@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5895113034 → 12.0.0-alpha.5933014273
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 +3 -3
- package/Components/Cell/Cell.tsx +30 -9
- package/Components/Cell/CellWithFocusable.tsx +23 -9
- package/Components/Cell/TvOSCellComponent.tsx +3 -7
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +11 -2
- package/Components/FreezeWithCallback/Freeze.tsx +31 -0
- package/Components/FreezeWithCallback/LICENSE +21 -0
- package/Components/FreezeWithCallback/Suspender.tsx +17 -0
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
- package/Components/FreezeWithCallback/index.tsx +3 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
- package/Components/Layout/TV/index.tsx +11 -67
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +8 -9
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +17 -1
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
- package/Components/MasterCell/DefaultComponents/index.ts +2 -0
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
- package/Components/MasterCell/dataAdapter.ts +21 -7
- package/Components/MasterCell/index.tsx +5 -3
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +17 -30
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +5 -1
- package/Components/River/TV/River.tsx +0 -23
- package/Components/Screen/TV/hooks/index.ts +1 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/index.web.tsx +178 -0
- package/Components/Screen/__tests__/Screen.test.tsx +3 -49
- package/Components/Screen/index.tsx +55 -76
- package/Components/Screen/navigationHandler.ts +6 -3
- package/Components/Screen/orientationHandler.ts +18 -7
- package/Components/Screen/utils.ts +16 -0
- package/Components/ScreenResolver/index.tsx +9 -12
- package/Components/Transitioner/Scene.tsx +20 -12
- package/Components/Transitioner/Transitioner.tsx +40 -49
- package/Components/Transitioner/__tests__/Scene.test.js +7 -0
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +25 -1
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +79 -45
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +47 -33
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +121 -86
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
- package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
- package/Components/VideoModal/PlayerWrapper.tsx +10 -10
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +80 -14
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +5 -2
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/const.ts +6 -0
- package/index.js +3 -0
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Contexts/ScreenDataContext/index.ts +0 -3
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { last } from "ramda";
|
|
3
|
+
import { StyleSheet, View } from "react-native";
|
|
4
|
+
import {
|
|
5
|
+
findMenuPlugin,
|
|
6
|
+
getNavigationProps,
|
|
7
|
+
getPathAttributes,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
9
|
+
import {
|
|
10
|
+
useIsScreenActive,
|
|
11
|
+
useNavigation,
|
|
12
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
14
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
15
|
+
import {
|
|
16
|
+
useNavbarState,
|
|
17
|
+
useScreenBackgroundColor,
|
|
18
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
19
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
20
|
+
|
|
21
|
+
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
22
|
+
import { ScreenResolver } from "../../ScreenResolver";
|
|
23
|
+
import { useInitialFocus } from "./hooks";
|
|
24
|
+
import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
25
|
+
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
26
|
+
import { FreezeWithCallback } from "../../FreezeWithCallback";
|
|
27
|
+
|
|
28
|
+
const styles = StyleSheet.create({
|
|
29
|
+
container: {
|
|
30
|
+
position: "absolute",
|
|
31
|
+
top: 0,
|
|
32
|
+
left: 0,
|
|
33
|
+
right: 0,
|
|
34
|
+
bottom: 0,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
type Components = {
|
|
39
|
+
NavBar: React.ComponentType<any>;
|
|
40
|
+
Background: React.ComponentType<any>;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
type Props = {
|
|
44
|
+
route: string;
|
|
45
|
+
Components: Components;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const getActiveRiver = ({
|
|
49
|
+
screenId,
|
|
50
|
+
screenType,
|
|
51
|
+
routeState,
|
|
52
|
+
rivers,
|
|
53
|
+
fallbackActiveRiver,
|
|
54
|
+
}) => {
|
|
55
|
+
if (rivers[screenId]) {
|
|
56
|
+
if (screenType === "hooks") {
|
|
57
|
+
const navigations = routeState?.state?.entry?.payload?.navigations;
|
|
58
|
+
|
|
59
|
+
if (navigations) {
|
|
60
|
+
return routeState.state.entry.payload;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return routeState?.state?.screen;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// screenId is not presented into rivers, use fallback instead
|
|
68
|
+
return fallbackActiveRiver;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const getNavigations = ({
|
|
72
|
+
screenId,
|
|
73
|
+
screenType,
|
|
74
|
+
routeState,
|
|
75
|
+
rivers,
|
|
76
|
+
fallbackNavigations,
|
|
77
|
+
}) => {
|
|
78
|
+
if (rivers[screenId]) {
|
|
79
|
+
// river presents
|
|
80
|
+
if (screenType === "hooks") {
|
|
81
|
+
const navigations = routeState?.state?.entry?.payload?.navigations;
|
|
82
|
+
|
|
83
|
+
if (navigations) {
|
|
84
|
+
return navigations;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return routeState?.state?.screen?.navigations;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// screenId is not presented into rivers, use fallback instead
|
|
92
|
+
return fallbackNavigations;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const Screen = ({ route, Components }: Props) => {
|
|
96
|
+
if (isNilOrEmpty(route)) {
|
|
97
|
+
throw Error("Required props: route is missing");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const navigator = useNavigation();
|
|
101
|
+
const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
|
|
102
|
+
|
|
103
|
+
const pathAttributes = getPathAttributes({ pathname: route });
|
|
104
|
+
const routeState = navigator.getStackForPathname(route);
|
|
105
|
+
|
|
106
|
+
const { screenType, screenId } = last(pathAttributes);
|
|
107
|
+
|
|
108
|
+
const backgroundColor = useScreenBackgroundColor(screenId);
|
|
109
|
+
|
|
110
|
+
useInitialFocus();
|
|
111
|
+
|
|
112
|
+
const activeRiver = getActiveRiver({
|
|
113
|
+
screenId,
|
|
114
|
+
screenType,
|
|
115
|
+
routeState,
|
|
116
|
+
rivers,
|
|
117
|
+
fallbackActiveRiver: navigator.activeRiver,
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const navigationProps = getNavigationProps({
|
|
121
|
+
navigator: {
|
|
122
|
+
// @ts-ignore
|
|
123
|
+
activeRiver,
|
|
124
|
+
// @ts-ignore
|
|
125
|
+
screenTitle: routeState.state.entry?.title || routeState.screen?.name,
|
|
126
|
+
},
|
|
127
|
+
category: "menu",
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
const navigations = getNavigations({
|
|
131
|
+
screenId,
|
|
132
|
+
screenType,
|
|
133
|
+
routeState,
|
|
134
|
+
rivers,
|
|
135
|
+
fallbackNavigations: navigator.activeRiver.navigations,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const menuPlugin = findMenuPlugin(navigations, plugins);
|
|
139
|
+
|
|
140
|
+
const NavBar = (Components.NavBar ||
|
|
141
|
+
menuPlugin.module) as React.ComponentType<any>;
|
|
142
|
+
|
|
143
|
+
const isPlayer = isPlayerPlugin(routeState);
|
|
144
|
+
|
|
145
|
+
const { visible: isNavBarVisible } = useNavbarState();
|
|
146
|
+
|
|
147
|
+
const screenData =
|
|
148
|
+
screenType === "hooks" || isPlayer
|
|
149
|
+
? routeState?.state?.entry
|
|
150
|
+
: routeState?.state?.screen;
|
|
151
|
+
|
|
152
|
+
const isScreenActive = useIsScreenActive();
|
|
153
|
+
|
|
154
|
+
return (
|
|
155
|
+
<FreezeWithCallback
|
|
156
|
+
freeze={!isScreenActive}
|
|
157
|
+
onRelease={() => {
|
|
158
|
+
focusManager.setInitialFocus();
|
|
159
|
+
}}
|
|
160
|
+
>
|
|
161
|
+
<View style={[styles.container, { backgroundColor }]}>
|
|
162
|
+
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
163
|
+
<NavBar
|
|
164
|
+
isVisible={isNavBarVisible}
|
|
165
|
+
menuPlugin={menuPlugin}
|
|
166
|
+
navigationProps={navigationProps}
|
|
167
|
+
/>
|
|
168
|
+
</NavBarContainer>
|
|
169
|
+
<ScreenResolver
|
|
170
|
+
screenType={screenType}
|
|
171
|
+
screenId={screenId}
|
|
172
|
+
screenData={screenData}
|
|
173
|
+
groupId={route}
|
|
174
|
+
/>
|
|
175
|
+
</View>
|
|
176
|
+
</FreezeWithCallback>
|
|
177
|
+
);
|
|
178
|
+
};
|
|
@@ -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(),
|
|
@@ -96,14 +99,6 @@ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
|
|
|
96
99
|
}),
|
|
97
100
|
}));
|
|
98
101
|
|
|
99
|
-
const {
|
|
100
|
-
ORIENTATIONS,
|
|
101
|
-
} = require("@applicaster/zapp-react-native-utils/appUtils/orientationHelper");
|
|
102
|
-
|
|
103
|
-
const {
|
|
104
|
-
useCurrentScreenData,
|
|
105
|
-
} = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
|
|
106
|
-
|
|
107
102
|
const {
|
|
108
103
|
allowedOrientationsForScreen,
|
|
109
104
|
getOrientation,
|
|
@@ -155,45 +150,4 @@ describe("<Screen Component />", () => {
|
|
|
155
150
|
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
156
151
|
});
|
|
157
152
|
});
|
|
158
|
-
|
|
159
|
-
it("invokes the orientation hook when the route changes", () => {
|
|
160
|
-
act(() => {
|
|
161
|
-
wrapper = create(<Screen {...screenProps} />);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// @ts-ignore
|
|
165
|
-
useCurrentScreenData.mockReturnValue({
|
|
166
|
-
id: "player-testId",
|
|
167
|
-
general: { screen_orientation: ORIENTATIONS.landscapeSensor },
|
|
168
|
-
plugin_type: "player",
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
act(() => {
|
|
172
|
-
wrapper.update(
|
|
173
|
-
<Screen
|
|
174
|
-
{...screenProps}
|
|
175
|
-
pathname="/playable"
|
|
176
|
-
screenData={{
|
|
177
|
-
id: "player-testId",
|
|
178
|
-
general: { screen_orientation: ORIENTATIONS.landscapeSensor },
|
|
179
|
-
plugin_type: "player",
|
|
180
|
-
}}
|
|
181
|
-
/>
|
|
182
|
-
);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
useCurrentScreenData.mockReturnValue({
|
|
186
|
-
id: "player-testId",
|
|
187
|
-
general: { screen_orientation: ORIENTATIONS.landscapeSensor },
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
act(() => {
|
|
191
|
-
wrapper.update(<Screen {...screenProps} />);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
expect(allowedOrientationsForScreen).toHaveBeenNthCalledWith(
|
|
195
|
-
1,
|
|
196
|
-
ORIENTATIONS.landscapeSensor
|
|
197
|
-
);
|
|
198
|
-
});
|
|
199
153
|
});
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
/// <reference types="@applicaster/applicaster-types" />
|
|
2
2
|
import React from "react";
|
|
3
|
-
import * as R from "ramda";
|
|
4
3
|
import { View } from "react-native";
|
|
5
4
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
5
|
+
import {
|
|
6
|
+
isOrientationCompatible,
|
|
7
|
+
useGetScreenOrientation,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
6
9
|
|
|
7
10
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
8
11
|
import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
9
12
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
13
|
+
shouldNavBarDisplayMenu,
|
|
14
|
+
getNavBarProps,
|
|
15
|
+
getScreenId,
|
|
12
16
|
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
13
|
-
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
14
17
|
import {
|
|
15
18
|
useDimensions,
|
|
16
19
|
useRoute,
|
|
@@ -21,39 +24,18 @@ import {
|
|
|
21
24
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
22
25
|
import { getNavigationPluginModule } from "@applicaster/zapp-react-native-app/App/Layout/layoutHelpers";
|
|
23
26
|
|
|
24
|
-
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
25
27
|
import { RouteManager } from "../RouteManager";
|
|
26
28
|
import { useScreenConfiguration } from "../River/useScreenConfiguration";
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
: "screen_id" in screenData
|
|
36
|
-
? screenData.screen_id
|
|
37
|
-
: fallbackRiver.id;
|
|
29
|
+
import { isValidColor } from "./utils";
|
|
30
|
+
|
|
31
|
+
const screenStyles = {
|
|
32
|
+
flex: 1,
|
|
33
|
+
paddingTop: 0,
|
|
34
|
+
// paddingBottom: insets.bottom, // Should be applied directly by UI plugin
|
|
35
|
+
// paddingLeft: insets.left, // Should be applied directly by UI plugin
|
|
36
|
+
// paddingRight: insets.right, // Should be applied directly by UI plugin
|
|
38
37
|
};
|
|
39
38
|
|
|
40
|
-
function colorIsNotTransparent(color) {
|
|
41
|
-
const layers = R.compose(
|
|
42
|
-
R.map(R.trim),
|
|
43
|
-
R.split(","),
|
|
44
|
-
R.replace(")", ""),
|
|
45
|
-
R.replace("rgba(", "")
|
|
46
|
-
)(color);
|
|
47
|
-
|
|
48
|
-
const alpha = Number(layers?.[3]);
|
|
49
|
-
|
|
50
|
-
return alpha > 0;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function isValidColor(string) {
|
|
54
|
-
return string && string !== "transparent" && colorIsNotTransparent(string);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
39
|
type Props = {
|
|
58
40
|
pathname: unknown;
|
|
59
41
|
screenData: unknown;
|
|
@@ -67,9 +49,12 @@ export function Screen(_props: Props) {
|
|
|
67
49
|
// Gets the data for the current screen configuration
|
|
68
50
|
const currentScreenData = useCurrentScreenData();
|
|
69
51
|
const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
|
|
70
|
-
const insets = useSafeAreaInsets();
|
|
71
52
|
|
|
72
|
-
const {
|
|
53
|
+
const {
|
|
54
|
+
width: screenWidth,
|
|
55
|
+
height,
|
|
56
|
+
deviceInfo,
|
|
57
|
+
} = useDimensions("screen", {
|
|
73
58
|
fullDimensions: true,
|
|
74
59
|
});
|
|
75
60
|
|
|
@@ -81,30 +66,19 @@ export function Screen(_props: Props) {
|
|
|
81
66
|
|
|
82
67
|
const { title } = useNavbarState();
|
|
83
68
|
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (props) {
|
|
99
|
-
return {
|
|
100
|
-
...props,
|
|
101
|
-
id: pathname,
|
|
102
|
-
pathname: pathname,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return null;
|
|
107
|
-
}, [currentRiver, pathname]);
|
|
69
|
+
const isTablet = deviceInfo?.isTablet;
|
|
70
|
+
|
|
71
|
+
const { appData } = usePickFromState(["appData"]);
|
|
72
|
+
const isTabletPortrait = appData?.isTabletPortrait;
|
|
73
|
+
|
|
74
|
+
const layoutData = { isTablet, isTabletPortrait, width: screenWidth, height };
|
|
75
|
+
|
|
76
|
+
const hasMenu = shouldNavBarDisplayMenu(currentRiver, plugins);
|
|
77
|
+
|
|
78
|
+
const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(
|
|
79
|
+
getNavBarProps(currentRiver, pathname, title),
|
|
80
|
+
[currentRiver, pathname]
|
|
81
|
+
);
|
|
108
82
|
|
|
109
83
|
const NavBar = React.useMemo(
|
|
110
84
|
() =>
|
|
@@ -126,33 +100,38 @@ export function Screen(_props: Props) {
|
|
|
126
100
|
|
|
127
101
|
const style = React.useMemo(
|
|
128
102
|
() => ({
|
|
129
|
-
|
|
103
|
+
...screenStyles,
|
|
130
104
|
backgroundColor: isValidColor(backgroundColor)
|
|
131
105
|
? backgroundColor
|
|
132
106
|
: theme.app_background_color,
|
|
133
|
-
paddingTop: 0,
|
|
134
|
-
// paddingBottom: insets.bottom, // Should be applied directly by UI plugin
|
|
135
|
-
// paddingLeft: insets.left, // Should be applied directly by UI plugin
|
|
136
|
-
// paddingRight: insets.right, // Should be applied directly by UI plugin
|
|
137
107
|
}),
|
|
138
|
-
[
|
|
108
|
+
[theme.app_background_color, backgroundColor]
|
|
139
109
|
);
|
|
140
110
|
|
|
141
111
|
const targetScreenData =
|
|
142
112
|
currentScreenData || (screenData as any)?.targetScreen || screenData;
|
|
143
113
|
|
|
144
|
-
|
|
114
|
+
const orientation = useGetScreenOrientation(targetScreenData);
|
|
115
|
+
|
|
116
|
+
// We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
|
|
117
|
+
// This saves unnecessary re-renders and user will not see distorted aspect screen.
|
|
118
|
+
if (
|
|
119
|
+
!isOrientationCompatible({
|
|
120
|
+
orientation,
|
|
121
|
+
layoutData,
|
|
122
|
+
})
|
|
123
|
+
) {
|
|
124
|
+
return <View style={style} />;
|
|
125
|
+
}
|
|
145
126
|
|
|
146
127
|
return (
|
|
147
|
-
<
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
</View>
|
|
156
|
-
</ScreenContextProvider>
|
|
128
|
+
<View style={style}>
|
|
129
|
+
{navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
|
|
130
|
+
|
|
131
|
+
<OfflineFallbackScreen screenData={targetScreenData}>
|
|
132
|
+
{/* @TODO RouteManager doesn't use props, can they be removed ? */}
|
|
133
|
+
<RouteManager pathname={pathname} screenData={screenData} />
|
|
134
|
+
</OfflineFallbackScreen>
|
|
135
|
+
</View>
|
|
157
136
|
);
|
|
158
137
|
}
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* is similar to the navbar, except that it covers scenarios where only the navbar (and not)
|
|
6
6
|
* the menu, will be hidden
|
|
7
7
|
*
|
|
8
|
+
* - playable screens
|
|
9
|
+
* - qb_search_screen
|
|
10
|
+
* - screen hooks that specify showNavBar or presentFullScreen
|
|
11
|
+
* - screens or nested screens that have allow_screen_plugin_presentation set to true
|
|
12
|
+
*
|
|
8
13
|
* @param {String} route current route of the screen
|
|
9
14
|
* @param {Object} screenData payload associated with the currently presented screen
|
|
10
15
|
* @returns {Boolean}
|
|
@@ -21,9 +26,7 @@ export function isMenuVisible(route, screenData) {
|
|
|
21
26
|
if (screenData?.hookPlugin) {
|
|
22
27
|
const hookPlugin = screenData?.hookPlugin?.module;
|
|
23
28
|
|
|
24
|
-
return
|
|
25
|
-
hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true || false
|
|
26
|
-
);
|
|
29
|
+
return hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
if (
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import React, { useLayoutEffect } from "react";
|
|
2
|
+
|
|
2
3
|
import {
|
|
3
4
|
allowedOrientationsForScreen,
|
|
4
5
|
ORIENTATIONS,
|
|
5
6
|
getOrientation,
|
|
6
7
|
useGetScreenOrientation,
|
|
7
8
|
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
8
|
-
|
|
9
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
9
10
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
10
11
|
import { findPluginByType } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
11
12
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
|
+
|
|
12
14
|
import { ZappHookModalContext } from "../../Contexts";
|
|
13
15
|
import { HookModalContextT } from "../../Contexts/ZappHookModalContext";
|
|
14
16
|
|
|
@@ -79,14 +81,23 @@ export function useNewOrientationForScreenData({
|
|
|
79
81
|
screenOrientation;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
|
-
|
|
83
|
-
screenData
|
|
84
|
-
|
|
84
|
+
type Props = {
|
|
85
|
+
screenData: {
|
|
86
|
+
screen: {};
|
|
87
|
+
};
|
|
88
|
+
isActive: boolean;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export function useScreenOrientationHandler({ screenData, isActive }: Props) {
|
|
85
92
|
const { isHooksExecutionInProgress } = React.useContext<HookModalContextT>(
|
|
86
93
|
ZappHookModalContext.ReactContext
|
|
87
94
|
);
|
|
88
95
|
|
|
89
|
-
const
|
|
96
|
+
const prevIsActive = usePrevious(isActive);
|
|
97
|
+
|
|
98
|
+
const newOrientation = useNewOrientationForScreenData({
|
|
99
|
+
screenData: screenData.screen,
|
|
100
|
+
});
|
|
90
101
|
|
|
91
102
|
useLayoutEffect(() => {
|
|
92
103
|
// Null means screen does not have orientation preference, so we can skip rotate
|
|
@@ -100,12 +111,12 @@ export function useScreenOrientationHandler({
|
|
|
100
111
|
return;
|
|
101
112
|
}
|
|
102
113
|
|
|
103
|
-
if (newOrientation !== current) {
|
|
114
|
+
if (!prevIsActive && isActive && newOrientation !== current) {
|
|
104
115
|
current = newOrientation;
|
|
105
116
|
|
|
106
117
|
setOrientation(newOrientation);
|
|
107
118
|
}
|
|
108
|
-
}, [newOrientation, isHooksExecutionInProgress]);
|
|
119
|
+
}, [newOrientation, isHooksExecutionInProgress, prevIsActive, isActive]);
|
|
109
120
|
}
|
|
110
121
|
|
|
111
122
|
export function useOrientationHandler({ screenData }: OrientationHookArgs) {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { map, split, replace, compose, trim } from "ramda";
|
|
2
|
+
|
|
3
|
+
function colorIsNotTransparent(color) {
|
|
4
|
+
const layers = compose(
|
|
5
|
+
map(trim),
|
|
6
|
+
split(","),
|
|
7
|
+
replace(")", ""),
|
|
8
|
+
replace("rgba(", "")
|
|
9
|
+
)(color);
|
|
10
|
+
|
|
11
|
+
return Number(layers?.[3]) > 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function isValidColor(string) {
|
|
15
|
+
return string && string !== "transparent" && colorIsNotTransparent(string);
|
|
16
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
3
|
-
import { useDispatch } from "react-redux";
|
|
2
|
+
import { path, prop } from "ramda";
|
|
4
3
|
import {
|
|
5
4
|
findPluginByType,
|
|
6
5
|
findPluginByIdentifier,
|
|
@@ -15,7 +14,6 @@ import { componentsLogger } from "../../Helpers/logger";
|
|
|
15
14
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
16
15
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
17
16
|
import { useScreenAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
|
|
18
|
-
import { setAppStateHasFinishedTransitioning } from "@applicaster/zapp-react-native-redux/appState";
|
|
19
17
|
|
|
20
18
|
const logger = componentsLogger.addSubsystem("ScreenResolver");
|
|
21
19
|
|
|
@@ -32,12 +30,13 @@ type Props = {
|
|
|
32
30
|
nextFocusLeft?: React.Ref<any>;
|
|
33
31
|
nextFocusUp?: React.Ref<any>;
|
|
34
32
|
};
|
|
33
|
+
groupId?: string;
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
export function ScreenResolverComponent(props: Props) {
|
|
38
37
|
useScreenAnalytics(props);
|
|
39
38
|
|
|
40
|
-
const { screenType, screenId, screenData } = props;
|
|
39
|
+
const { screenType, screenId, screenData, groupId } = props;
|
|
41
40
|
|
|
42
41
|
const { hookPlugin } = screenData || {};
|
|
43
42
|
|
|
@@ -53,11 +52,8 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
53
52
|
|
|
54
53
|
const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
55
54
|
|
|
56
|
-
const dispatch = useDispatch();
|
|
57
|
-
|
|
58
55
|
React.useEffect(() => {
|
|
59
56
|
setScreenContext(rivers[screenId]);
|
|
60
|
-
dispatch(setAppStateHasFinishedTransitioning());
|
|
61
57
|
}, [screenId]);
|
|
62
58
|
|
|
63
59
|
const ScreenPlugin =
|
|
@@ -81,6 +77,7 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
81
77
|
item={screenData}
|
|
82
78
|
mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
|
|
83
79
|
isModal={false}
|
|
80
|
+
groupId={groupId}
|
|
84
81
|
/>
|
|
85
82
|
);
|
|
86
83
|
}
|
|
@@ -98,14 +95,14 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
const ScreenComponent =
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
path(["module", "Component"], ScreenPlugin) ||
|
|
99
|
+
prop("module", ScreenPlugin) ||
|
|
100
|
+
prop("Component", ScreenPlugin) ||
|
|
104
101
|
ScreenPlugin;
|
|
105
102
|
|
|
106
103
|
const configuration =
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
prop("configuration", ScreenPlugin) ||
|
|
105
|
+
prop("__plugin_configuration", ScreenComponent);
|
|
109
106
|
|
|
110
107
|
if (ScreenComponent) {
|
|
111
108
|
return (
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import {
|
|
3
|
-
Animated,
|
|
4
|
-
useWindowDimensions,
|
|
5
|
-
ViewProps,
|
|
6
|
-
ViewStyle,
|
|
7
|
-
} from "react-native";
|
|
2
|
+
import { Animated, ViewProps, ViewStyle } from "react-native";
|
|
8
3
|
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
4
|
+
|
|
5
|
+
import { useScreenOrientationHandler } from "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler";
|
|
6
|
+
|
|
9
7
|
import { PathnameContext } from "../../Contexts/PathnameContext";
|
|
10
8
|
import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
|
|
9
|
+
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
11
10
|
|
|
12
11
|
type Props = {
|
|
13
12
|
children: any;
|
|
@@ -46,6 +45,11 @@ export function Scene({
|
|
|
46
45
|
}: Props) {
|
|
47
46
|
const [initialScreenData, setInitialScreenData] = React.useState(screenData);
|
|
48
47
|
|
|
48
|
+
useScreenOrientationHandler({
|
|
49
|
+
screenData,
|
|
50
|
+
isActive,
|
|
51
|
+
});
|
|
52
|
+
|
|
49
53
|
React.useLayoutEffect(() => {
|
|
50
54
|
if (isActive) {
|
|
51
55
|
setInitialScreenData(screenData);
|
|
@@ -53,12 +57,14 @@ export function Scene({
|
|
|
53
57
|
}, [screenData, isActive]);
|
|
54
58
|
|
|
55
59
|
const frame = useSafeAreaFrame();
|
|
56
|
-
const { height, width } = useWindowDimensions();
|
|
57
|
-
|
|
58
|
-
// Safe frame takes too long to update,
|
|
59
|
-
// so we can not rely on it there, and use height and width instead.
|
|
60
60
|
const isAnimating = animating && overlayStyle;
|
|
61
|
-
|
|
61
|
+
|
|
62
|
+
const dimensions = isAnimating
|
|
63
|
+
? {
|
|
64
|
+
width: "100%",
|
|
65
|
+
height: "100%",
|
|
66
|
+
}
|
|
67
|
+
: frame;
|
|
62
68
|
|
|
63
69
|
return (
|
|
64
70
|
<Animated.View
|
|
@@ -67,7 +73,9 @@ export function Scene({
|
|
|
67
73
|
>
|
|
68
74
|
<ScreenDataContext.Provider value={initialScreenData}>
|
|
69
75
|
<PathnameContext.Provider value={pathname}>
|
|
70
|
-
{
|
|
76
|
+
<ScreenContextProvider pathname={pathname}>
|
|
77
|
+
{children}
|
|
78
|
+
</ScreenContextProvider>
|
|
71
79
|
</PathnameContext.Provider>
|
|
72
80
|
</ScreenDataContext.Provider>
|
|
73
81
|
{isAnimating && <Animated.View style={overlayStyle} />}
|