@applicaster/zapp-react-native-ui-components 12.0.0-alpha.7855034103 → 12.0.0-alpha.8024419438
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Components/BaseFocusable/index.tsx +1 -1
- package/Components/Cell/Cell.tsx +5 -5
- package/Components/Cell/CellWithFocusable.tsx +17 -5
- package/Components/FocusableGroup/index.tsx +1 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +19 -75
- package/Components/Layout/TV/index.tsx +0 -2
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +6 -2
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
- package/Components/MasterCell/utils/index.ts +17 -30
- package/Components/Navigator/StackNavigator.tsx +48 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +8 -1
- package/Components/River/TV/River.tsx +0 -23
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +179 -0
- package/Components/Screen/__tests__/Screen.test.tsx +3 -0
- package/Components/Screen/index.tsx +29 -1
- package/Components/ScreenResolver/index.tsx +3 -1
- package/Components/Transitioner/Transitioner.tsx +15 -29
- package/Components/VideoLive/LiveImageManager.ts +15 -1
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +48 -38
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +40 -33
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +94 -71
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
- package/Components/VideoModal/PlayerWrapper.tsx +8 -8
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Components/VideoModal/utils.ts +5 -2
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Contexts/ScreenDataContext/index.ts +0 -3
|
@@ -7,14 +7,10 @@ import * as R from "ramda";
|
|
|
7
7
|
import {
|
|
8
8
|
useFeedLoader,
|
|
9
9
|
useLayoutVersion,
|
|
10
|
-
useNavigationPluginData,
|
|
11
10
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
11
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
13
12
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
14
13
|
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
15
|
-
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
16
|
-
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
17
|
-
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
14
|
import {
|
|
19
15
|
useNavbarState,
|
|
20
16
|
useSetNavbarState,
|
|
@@ -51,8 +47,6 @@ export const River = (props: Props) => {
|
|
|
51
47
|
const { setTitle: setScreenTitle, setSummary: setScreenSummary } =
|
|
52
48
|
useSetNavbarState();
|
|
53
49
|
|
|
54
|
-
const navigationPluginData = useNavigationPluginData();
|
|
55
|
-
|
|
56
50
|
const rivers = useRivers();
|
|
57
51
|
const isV2 = useLayoutVersion({ isV2: true });
|
|
58
52
|
|
|
@@ -99,23 +93,6 @@ export const River = (props: Props) => {
|
|
|
99
93
|
}
|
|
100
94
|
}, [feedData, screenData, screenTitle, screenSummary]);
|
|
101
95
|
|
|
102
|
-
React.useEffect(() => {
|
|
103
|
-
if (
|
|
104
|
-
isWeb() &&
|
|
105
|
-
toBooleanWithDefaultFalse(
|
|
106
|
-
navigationPluginData?.rules?.focus_on_content
|
|
107
|
-
) &&
|
|
108
|
-
river &&
|
|
109
|
-
river.type !== "general_content"
|
|
110
|
-
) {
|
|
111
|
-
const groupId = R.pathOr("river", ["groupId"], componentsMapExtraProps);
|
|
112
|
-
|
|
113
|
-
focusManager.setupInitialFocus(groupId, true);
|
|
114
|
-
focusManager.setInitialFocus();
|
|
115
|
-
focusManager.enableAutomaticFocus();
|
|
116
|
-
}
|
|
117
|
-
}, [river, componentsMapExtraProps]);
|
|
118
|
-
|
|
119
96
|
if (!river) {
|
|
120
97
|
utilsLogger.error({
|
|
121
98
|
message: `River ${screenData.id} not found!`,
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
useNavigationPluginData,
|
|
4
|
+
useIsNavBarVisible,
|
|
5
|
+
useRoute,
|
|
6
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
7
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
8
|
+
import {
|
|
9
|
+
setFocusOnContent,
|
|
10
|
+
setFocusOnMenu,
|
|
11
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux";
|
|
12
|
+
|
|
13
|
+
type Return =
|
|
14
|
+
| {
|
|
15
|
+
onContent: true;
|
|
16
|
+
onMenu: false;
|
|
17
|
+
}
|
|
18
|
+
| {
|
|
19
|
+
onContent: false;
|
|
20
|
+
onMenu: true;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getInitialFocus = (focusOnContent, isNavBarVisible): Return => {
|
|
24
|
+
if (focusOnContent) {
|
|
25
|
+
return {
|
|
26
|
+
onContent: true,
|
|
27
|
+
onMenu: false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!focusOnContent && isNavBarVisible) {
|
|
32
|
+
// put focus on navbar
|
|
33
|
+
return {
|
|
34
|
+
onContent: false,
|
|
35
|
+
onMenu: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// we don't have navbar, put focus on content anyway
|
|
40
|
+
return {
|
|
41
|
+
onContent: true,
|
|
42
|
+
onMenu: false,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const useInitialFocus = (): void => {
|
|
47
|
+
const navigationPluginData = useNavigationPluginData();
|
|
48
|
+
|
|
49
|
+
const focusOnContent = toBooleanWithDefaultFalse(
|
|
50
|
+
navigationPluginData?.rules?.focus_on_content
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const isNavBarVisible = useIsNavBarVisible();
|
|
54
|
+
|
|
55
|
+
const { pathname: currentRoute } = useRoute();
|
|
56
|
+
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
const initialFocus = getInitialFocus(focusOnContent, isNavBarVisible);
|
|
59
|
+
|
|
60
|
+
if (initialFocus.onContent) {
|
|
61
|
+
setFocusOnContent(currentRoute);
|
|
62
|
+
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (initialFocus.onMenu) {
|
|
67
|
+
setFocusOnMenu(currentRoute);
|
|
68
|
+
}
|
|
69
|
+
}, []);
|
|
70
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { isNil } from "ramda";
|
|
3
|
+
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
4
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
5
|
+
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
6
|
+
|
|
7
|
+
export const useRestoreFocus = (): void => {
|
|
8
|
+
const isScreenActive = useIsScreenActive();
|
|
9
|
+
const previousIsScreenActive = usePrevious(isScreenActive);
|
|
10
|
+
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
if (isNil(previousIsScreenActive)) {
|
|
13
|
+
// it's initial mounting of the screen, do nothing here
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!previousIsScreenActive && isScreenActive) {
|
|
18
|
+
// restore focus when we go back from next screen
|
|
19
|
+
focusManager.setInitialFocus();
|
|
20
|
+
}
|
|
21
|
+
}, [previousIsScreenActive, isScreenActive]);
|
|
22
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { last, pathOr } from "ramda";
|
|
3
|
+
import { View, StyleSheet } from "react-native";
|
|
4
|
+
import {
|
|
5
|
+
getNavigationProps,
|
|
6
|
+
getPathAttributes,
|
|
7
|
+
resolveNavigationPlugin,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
9
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
10
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
11
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
12
|
+
import { useScreenBackgroundColor } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
13
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
14
|
+
|
|
15
|
+
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
16
|
+
import { ScreenResolver } from "../../ScreenResolver";
|
|
17
|
+
import { useInitialFocus, useRestoreFocus } from "./hooks";
|
|
18
|
+
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
position: "absolute",
|
|
22
|
+
top: 0,
|
|
23
|
+
left: 0,
|
|
24
|
+
right: 0,
|
|
25
|
+
bottom: 0,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
type Components = {
|
|
30
|
+
NavBar: React.ComponentType<any>;
|
|
31
|
+
Background: React.ComponentType<any>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type Props = {
|
|
35
|
+
route: string;
|
|
36
|
+
Components: Components;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getPluginType = pathOr("unknown_plugin_type", [
|
|
40
|
+
"state",
|
|
41
|
+
"screen",
|
|
42
|
+
"plugin_type",
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const isPlayerPlugin = (routeState): boolean =>
|
|
46
|
+
getPluginType(routeState) === "player";
|
|
47
|
+
|
|
48
|
+
const isLoginPlugin = (routeState): boolean =>
|
|
49
|
+
getPluginType(routeState) === "login";
|
|
50
|
+
|
|
51
|
+
const getActiveRiver = ({
|
|
52
|
+
screenId,
|
|
53
|
+
screenType,
|
|
54
|
+
routeState,
|
|
55
|
+
rivers,
|
|
56
|
+
fallbackActiveRiver,
|
|
57
|
+
}) => {
|
|
58
|
+
if (rivers[screenId]) {
|
|
59
|
+
if (screenType === "hooks") {
|
|
60
|
+
const navigations = routeState?.state?.entry?.payload?.navigations;
|
|
61
|
+
|
|
62
|
+
if (navigations) {
|
|
63
|
+
return routeState.state.entry.payload;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return routeState?.state?.screen;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// screenId is not presented into rivers, use fallback instead
|
|
71
|
+
return fallbackActiveRiver;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const getNavigations = ({
|
|
75
|
+
screenId,
|
|
76
|
+
screenType,
|
|
77
|
+
routeState,
|
|
78
|
+
rivers,
|
|
79
|
+
fallbackNavigations,
|
|
80
|
+
}) => {
|
|
81
|
+
if (rivers[screenId]) {
|
|
82
|
+
// river presents
|
|
83
|
+
if (screenType === "hooks") {
|
|
84
|
+
const navigations = routeState?.state?.entry?.payload?.navigations;
|
|
85
|
+
|
|
86
|
+
if (navigations) {
|
|
87
|
+
return navigations;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return routeState?.state?.screen?.navigations;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// screenId is not presented into rivers, use fallback instead
|
|
95
|
+
return fallbackNavigations;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const Screen = ({ route, Components }: Props) => {
|
|
99
|
+
if (isNilOrEmpty(route)) {
|
|
100
|
+
throw Error("Required props: route is missing");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const navigator = useNavigation();
|
|
104
|
+
const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
|
|
105
|
+
|
|
106
|
+
const pathAttributes = getPathAttributes({ pathname: route });
|
|
107
|
+
const routeState = navigator.getStackForPathname(route);
|
|
108
|
+
|
|
109
|
+
const { screenType, screenId } = last(pathAttributes);
|
|
110
|
+
|
|
111
|
+
const backgroundColor = useScreenBackgroundColor(screenId);
|
|
112
|
+
|
|
113
|
+
useInitialFocus();
|
|
114
|
+
useRestoreFocus();
|
|
115
|
+
|
|
116
|
+
const activeRiver = getActiveRiver({
|
|
117
|
+
screenId,
|
|
118
|
+
screenType,
|
|
119
|
+
routeState,
|
|
120
|
+
rivers,
|
|
121
|
+
fallbackActiveRiver: navigator.activeRiver,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const navigationProps = getNavigationProps({
|
|
125
|
+
navigator: {
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
activeRiver,
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
screenTitle: routeState.state.entry?.title || routeState.screen?.name,
|
|
130
|
+
},
|
|
131
|
+
category: "menu",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const navigations = getNavigations({
|
|
135
|
+
screenId,
|
|
136
|
+
screenType,
|
|
137
|
+
routeState,
|
|
138
|
+
rivers,
|
|
139
|
+
fallbackNavigations: navigator.activeRiver.navigations,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const menuPlugin = resolveNavigationPlugin({
|
|
143
|
+
category: "menu",
|
|
144
|
+
navigations,
|
|
145
|
+
plugins,
|
|
146
|
+
}) as QuickBrickPlugin;
|
|
147
|
+
|
|
148
|
+
const NavBar = (Components.NavBar ||
|
|
149
|
+
menuPlugin.module) as React.ComponentType<any>;
|
|
150
|
+
|
|
151
|
+
const isPlayer = isPlayerPlugin(routeState);
|
|
152
|
+
const isLogin = isLoginPlugin(routeState);
|
|
153
|
+
|
|
154
|
+
const isNavBarVisible = !isPlayer && !isLogin;
|
|
155
|
+
|
|
156
|
+
const screenData =
|
|
157
|
+
screenType === "hooks" || isPlayer
|
|
158
|
+
? routeState?.state?.entry
|
|
159
|
+
: routeState?.state?.screen;
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<View style={[styles.container, { backgroundColor }]}>
|
|
163
|
+
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
164
|
+
<NavBar
|
|
165
|
+
groupId={route}
|
|
166
|
+
isVisible={isNavBarVisible}
|
|
167
|
+
menuPlugin={menuPlugin}
|
|
168
|
+
navigationProps={navigationProps}
|
|
169
|
+
/>
|
|
170
|
+
</NavBarContainer>
|
|
171
|
+
<ScreenResolver
|
|
172
|
+
screenType={screenType}
|
|
173
|
+
screenId={screenId}
|
|
174
|
+
screenData={screenData}
|
|
175
|
+
groupId={route}
|
|
176
|
+
/>
|
|
177
|
+
</View>
|
|
178
|
+
);
|
|
179
|
+
};
|
|
@@ -10,6 +10,8 @@ const mock_navBarVisibleFlag = true;
|
|
|
10
10
|
|
|
11
11
|
const mockIsNavBarVisible = jest.fn(() => mock_navBarVisibleFlag);
|
|
12
12
|
|
|
13
|
+
const mockIsOrientationCompatible = jest.fn(() => true);
|
|
14
|
+
|
|
13
15
|
jest.mock("react-native-safe-area-context", () => ({
|
|
14
16
|
useSafeAreaInsets: () => ({ top: 44 }),
|
|
15
17
|
}));
|
|
@@ -21,6 +23,7 @@ jest.mock("../../RouteManager", () => ({
|
|
|
21
23
|
jest.mock(
|
|
22
24
|
"@applicaster/zapp-react-native-utils/appUtils/orientationHelper",
|
|
23
25
|
() => ({
|
|
26
|
+
isOrientationCompatible: mockIsOrientationCompatible,
|
|
24
27
|
allowedOrientationsForScreen: jest.fn(),
|
|
25
28
|
getOrientation: jest.fn(),
|
|
26
29
|
getScreenOrientation: jest.fn(),
|
|
@@ -3,6 +3,10 @@ import React from "react";
|
|
|
3
3
|
import * as R from "ramda";
|
|
4
4
|
import { View } from "react-native";
|
|
5
5
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
6
|
+
import {
|
|
7
|
+
isOrientationCompatible,
|
|
8
|
+
useGetScreenOrientation,
|
|
9
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
6
10
|
|
|
7
11
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
8
12
|
import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
@@ -69,7 +73,11 @@ export function Screen(_props: Props) {
|
|
|
69
73
|
const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
|
|
70
74
|
const insets = useSafeAreaInsets();
|
|
71
75
|
|
|
72
|
-
const {
|
|
76
|
+
const {
|
|
77
|
+
width: screenWidth,
|
|
78
|
+
height,
|
|
79
|
+
deviceInfo,
|
|
80
|
+
} = useDimensions("screen", {
|
|
73
81
|
fullDimensions: true,
|
|
74
82
|
});
|
|
75
83
|
|
|
@@ -81,6 +89,13 @@ export function Screen(_props: Props) {
|
|
|
81
89
|
|
|
82
90
|
const { title } = useNavbarState();
|
|
83
91
|
|
|
92
|
+
const isTablet = deviceInfo?.isTablet;
|
|
93
|
+
|
|
94
|
+
const { appData } = usePickFromState(["appData"]);
|
|
95
|
+
const isTabletPortrait = appData?.isTabletPortrait;
|
|
96
|
+
|
|
97
|
+
const layoutData = { isTablet, isTabletPortrait, width: screenWidth, height };
|
|
98
|
+
|
|
84
99
|
const hasMenu =
|
|
85
100
|
resolveNavigationPlugin({
|
|
86
101
|
category: "menu",
|
|
@@ -143,6 +158,19 @@ export function Screen(_props: Props) {
|
|
|
143
158
|
|
|
144
159
|
useScreenOrientationHandler({ screenData: targetScreenData });
|
|
145
160
|
|
|
161
|
+
const orientation = useGetScreenOrientation(targetScreenData);
|
|
162
|
+
|
|
163
|
+
// We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
|
|
164
|
+
// This saves unnecessary re-renders and user will not see distorted aspect screen.
|
|
165
|
+
if (
|
|
166
|
+
!isOrientationCompatible({
|
|
167
|
+
orientation,
|
|
168
|
+
layoutData,
|
|
169
|
+
})
|
|
170
|
+
) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
|
|
146
174
|
return (
|
|
147
175
|
<ScreenContextProvider pathname={pathname}>
|
|
148
176
|
<View style={style}>
|
|
@@ -32,12 +32,13 @@ type Props = {
|
|
|
32
32
|
nextFocusLeft?: React.Ref<any>;
|
|
33
33
|
nextFocusUp?: React.Ref<any>;
|
|
34
34
|
};
|
|
35
|
+
groupId?: string;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
export function ScreenResolverComponent(props: Props) {
|
|
38
39
|
useScreenAnalytics(props);
|
|
39
40
|
|
|
40
|
-
const { screenType, screenId, screenData } = props;
|
|
41
|
+
const { screenType, screenId, screenData, groupId } = props;
|
|
41
42
|
|
|
42
43
|
const { hookPlugin } = screenData || {};
|
|
43
44
|
|
|
@@ -81,6 +82,7 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
81
82
|
item={screenData}
|
|
82
83
|
mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
|
|
83
84
|
isModal={false}
|
|
85
|
+
groupId={groupId}
|
|
84
86
|
/>
|
|
85
87
|
);
|
|
86
88
|
}
|
|
@@ -4,10 +4,7 @@ import * as R from "ramda";
|
|
|
4
4
|
|
|
5
5
|
import { AnimationManager } from "./AnimationManager";
|
|
6
6
|
import { Scene } from "./Scene";
|
|
7
|
-
|
|
8
|
-
getScreenOrientation,
|
|
9
|
-
isOrientationCompatible,
|
|
10
|
-
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
7
|
+
|
|
11
8
|
import {
|
|
12
9
|
getSceneByRoute,
|
|
13
10
|
shouldSkipAnimationForPreviousWebViewScene,
|
|
@@ -277,36 +274,25 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
277
274
|
// so only a single scene should be rendered,
|
|
278
275
|
// instead of dangerous nulls or duplicates.
|
|
279
276
|
renderSingleScene({ scenes, to }) {
|
|
280
|
-
const { contentStyle
|
|
277
|
+
const { contentStyle } = this.props;
|
|
281
278
|
const screenData = this.props.children.props.screenData;
|
|
282
279
|
const pathname = scenes[to.index].key;
|
|
283
280
|
|
|
284
|
-
const orientation = getScreenOrientation({
|
|
285
|
-
screenData,
|
|
286
|
-
layoutData,
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
// We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
|
|
290
|
-
// This saves unnecessary re-renders and user will not see distorted aspect screen.
|
|
291
281
|
return (
|
|
292
282
|
<View style={styles.container}>
|
|
293
|
-
{scenes[to.index] &&
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
>
|
|
307
|
-
{scenes[to.index].children}
|
|
308
|
-
</Scene>
|
|
309
|
-
)}
|
|
283
|
+
{scenes[to.index] && (
|
|
284
|
+
<Scene
|
|
285
|
+
{...{ style: to.style }}
|
|
286
|
+
pathname={pathname}
|
|
287
|
+
isActive={pathname === this.props.navigator.currentRoute}
|
|
288
|
+
contentStyle={contentStyle}
|
|
289
|
+
key={scenes[to.index].key}
|
|
290
|
+
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
291
|
+
screenData={screenData}
|
|
292
|
+
>
|
|
293
|
+
{scenes[to.index].children}
|
|
294
|
+
</Scene>
|
|
295
|
+
)}
|
|
310
296
|
</View>
|
|
311
297
|
);
|
|
312
298
|
}
|
|
@@ -10,7 +10,11 @@ import { Component } from "react";
|
|
|
10
10
|
|
|
11
11
|
const { log_debug, log_info, log_error } = loggerLiveImageManager;
|
|
12
12
|
|
|
13
|
-
export type LiveImageManagerEvent =
|
|
13
|
+
export type LiveImageManagerEvent =
|
|
14
|
+
| "onEnd"
|
|
15
|
+
| "onStart"
|
|
16
|
+
| "onError"
|
|
17
|
+
| "onDestroy";
|
|
14
18
|
|
|
15
19
|
export type LiveImageManagerListenerData = {
|
|
16
20
|
id: string;
|
|
@@ -102,6 +106,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
this.items = this.items.filter((i) => i !== item);
|
|
109
|
+
|
|
110
|
+
this.invokeListenersUpdate({
|
|
111
|
+
callbackName: "onDestroy",
|
|
112
|
+
event: {
|
|
113
|
+
item,
|
|
114
|
+
playerId: this.currentlyPlaying?.playerId,
|
|
115
|
+
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
116
|
+
entry: item.getPlayer().getEntry(),
|
|
117
|
+
},
|
|
118
|
+
});
|
|
105
119
|
};
|
|
106
120
|
|
|
107
121
|
public onViewportEnter = (item: LiveImage) => {
|
|
@@ -100,58 +100,68 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
100
100
|
{ useNativeDriver: true }
|
|
101
101
|
);
|
|
102
102
|
|
|
103
|
-
const onHandlerStateChange = (
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
const onHandlerStateChange = React.useCallback(
|
|
104
|
+
({ nativeEvent }) => {
|
|
105
|
+
if (
|
|
106
|
+
nativeEvent.oldState === State.ACTIVE &&
|
|
107
|
+
scrollPosition.current === 0
|
|
108
|
+
) {
|
|
109
|
+
// eslint-disable-next-line prefer-const
|
|
110
|
+
const { velocityY, translationY } = nativeEvent;
|
|
111
|
+
const dragToss = 0.05;
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
113
|
+
const preparedTranslationY =
|
|
114
|
+
Math.abs(translationY) - lastScrollYValue.current;
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
116
|
+
if (videoModalState.mode === "MAXIMIZED") {
|
|
117
|
+
const endOffsetY =
|
|
118
|
+
lastSnap + preparedTranslationY + dragToss * velocityY + 150;
|
|
115
119
|
|
|
116
|
-
|
|
120
|
+
let destSnapPoint = modalSnapPoints[0];
|
|
117
121
|
|
|
118
|
-
|
|
119
|
-
|
|
122
|
+
for (const snapPoint of modalSnapPoints) {
|
|
123
|
+
const distFromSnap = Math.abs(snapPoint - endOffsetY);
|
|
120
124
|
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
|
|
126
|
+
destSnapPoint = snapPoint;
|
|
127
|
+
}
|
|
123
128
|
}
|
|
124
|
-
}
|
|
125
129
|
|
|
126
|
-
|
|
130
|
+
setLastSnap(destSnapPoint);
|
|
127
131
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
if (destSnapPoint === modalSnapPoints[0]) {
|
|
133
|
+
translateYOffset.extractOffset();
|
|
134
|
+
translateYOffset.setValue(preparedTranslationY);
|
|
135
|
+
translateYOffset.flattenOffset();
|
|
136
|
+
dragScrollY.setValue(0);
|
|
133
137
|
|
|
134
|
-
|
|
138
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
139
|
+
} else {
|
|
140
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
|
|
141
|
+
}
|
|
135
142
|
} else {
|
|
136
|
-
|
|
143
|
+
if (translationY < 0) {
|
|
144
|
+
// from mini to full
|
|
145
|
+
setLastSnap(modalSnapPoints[0]);
|
|
146
|
+
|
|
147
|
+
translateYOffset.setValue(
|
|
148
|
+
modalSnapPoints[1] - preparedTranslationY
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
dragScrollY.setValue(0);
|
|
152
|
+
|
|
153
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
154
|
+
} else {
|
|
155
|
+
resetPlayerAnimationState();
|
|
156
|
+
}
|
|
137
157
|
}
|
|
138
158
|
} else {
|
|
139
|
-
|
|
140
|
-
// from mini to full
|
|
141
|
-
setLastSnap(modalSnapPoints[0]);
|
|
142
|
-
translateYOffset.setValue(modalSnapPoints[1] - preparedTranslationY);
|
|
143
|
-
dragScrollY.setValue(0);
|
|
144
|
-
|
|
145
|
-
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
146
|
-
} else {
|
|
159
|
+
playerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
|
|
147
160
|
resetPlayerAnimationState();
|
|
148
|
-
}
|
|
149
161
|
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
}
|
|
154
|
-
};
|
|
162
|
+
},
|
|
163
|
+
[lastSnap, modalSnapPoints, playerAnimationState, videoModalState.mode]
|
|
164
|
+
);
|
|
155
165
|
|
|
156
166
|
const onScroll = React.useCallback(({ nativeEvent }) => {
|
|
157
167
|
scrollPosition.current = nativeEvent.contentOffset.y;
|