@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4757075613 → 12.0.0-alpha.4796013211
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/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- 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 +14 -67
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +16 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -1
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
- 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/CollapsibleTextContainer/index.ts +1 -3
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
- package/Components/MasterCell/dataAdapter.ts +21 -7
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- package/Components/MasterCell/index.tsx +5 -3
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +33 -35
- package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +20 -3
- package/Components/PlayerImageBackground/index.tsx +34 -8
- package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
- package/Components/River/RefreshControl.tsx +55 -1
- package/Components/River/TV/River.tsx +0 -23
- package/Components/River/__tests__/componentsMap.test.js +6 -0
- package/Components/RouteManager/index.tsx +2 -2
- 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/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
- package/Components/Screen/index.tsx +62 -72
- 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 +39 -26
- package/Components/Transitioner/Transitioner.tsx +46 -48
- package/Components/Transitioner/__tests__/Scene.test.js +7 -0
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
- package/Components/VideoLive/LiveImageManager.ts +28 -1
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +20 -5
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +25 -28
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +66 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +376 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +473 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
- package/Components/VideoModal/PlayerDetails.tsx +3 -3
- package/Components/VideoModal/PlayerWrapper.tsx +77 -47
- package/Components/VideoModal/VideoModal.tsx +23 -40
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +13 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +203 -105
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +8 -5
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Components/Viewport/ViewportTracker/index.tsx +1 -0
- package/Components/Viewport/utils.js +1 -1
- 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/MenuToggleContext/{index.js → index.ts} +16 -0
- package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
- package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
- package/Contexts/ScreenContext/index.tsx +94 -25
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/const.ts +6 -0
- package/events/index.ts +1 -0
- package/index.js +3 -0
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
- /package/Contexts/{index.js → index.ts} +0 -0
|
@@ -1,13 +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
|
-
import {
|
|
10
|
-
|
|
12
|
+
import {
|
|
13
|
+
shouldNavBarDisplayMenu,
|
|
14
|
+
getNavBarProps,
|
|
15
|
+
getScreenId,
|
|
16
|
+
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
11
17
|
import {
|
|
12
18
|
useDimensions,
|
|
13
19
|
useRoute,
|
|
@@ -18,45 +24,24 @@ import {
|
|
|
18
24
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
19
25
|
import { getNavigationPluginModule } from "@applicaster/zapp-react-native-app/App/Layout/layoutHelpers";
|
|
20
26
|
|
|
21
|
-
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
22
27
|
import { RouteManager } from "../RouteManager";
|
|
23
28
|
import { useScreenConfiguration } from "../River/useScreenConfiguration";
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
: "screen_id" in screenData
|
|
33
|
-
? screenData.screen_id
|
|
34
|
-
: 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
|
|
35
37
|
};
|
|
36
38
|
|
|
37
|
-
function colorIsNotTransparent(color) {
|
|
38
|
-
const layers = R.compose(
|
|
39
|
-
R.map(R.trim),
|
|
40
|
-
R.split(","),
|
|
41
|
-
R.replace(")", ""),
|
|
42
|
-
R.replace("rgba(", "")
|
|
43
|
-
)(color);
|
|
44
|
-
|
|
45
|
-
const alpha = Number(layers?.[3]);
|
|
46
|
-
|
|
47
|
-
return alpha > 0;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function isValidColor(string) {
|
|
51
|
-
return string && string !== "transparent" && colorIsNotTransparent(string);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
39
|
type Props = {
|
|
55
|
-
|
|
56
|
-
|
|
40
|
+
pathname: unknown;
|
|
41
|
+
screenData: unknown;
|
|
57
42
|
};
|
|
58
43
|
|
|
59
|
-
export function Screen(
|
|
44
|
+
export function Screen(_props: Props) {
|
|
60
45
|
const theme = useTheme<BaseThemePropertiesMobile>();
|
|
61
46
|
const navigation = useNavigation();
|
|
62
47
|
const { plugins } = usePickFromState(["plugins"]);
|
|
@@ -64,31 +49,35 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
64
49
|
// Gets the data for the current screen configuration
|
|
65
50
|
const currentScreenData = useCurrentScreenData();
|
|
66
51
|
const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
|
|
67
|
-
const insets = useSafeAreaInsets();
|
|
68
52
|
|
|
69
|
-
const {
|
|
53
|
+
const {
|
|
54
|
+
width: screenWidth,
|
|
55
|
+
height,
|
|
56
|
+
deviceInfo,
|
|
57
|
+
} = useDimensions("screen", {
|
|
70
58
|
fullDimensions: true,
|
|
71
59
|
});
|
|
72
60
|
|
|
73
|
-
const
|
|
61
|
+
const { screenData, pathname } = useRoute();
|
|
74
62
|
|
|
75
63
|
const currentRiver = useScreenData(
|
|
76
|
-
getScreenId(
|
|
64
|
+
getScreenId(screenData, navigation.activeRiver)
|
|
77
65
|
);
|
|
78
66
|
|
|
79
67
|
const { title } = useNavbarState();
|
|
80
68
|
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
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]
|
|
92
81
|
);
|
|
93
82
|
|
|
94
83
|
const NavBar = React.useMemo(
|
|
@@ -97,12 +86,10 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
97
86
|
"nav_bar",
|
|
98
87
|
currentRiver,
|
|
99
88
|
plugins
|
|
100
|
-
) as React.ComponentType<MobileNavBarPluginProps>,
|
|
89
|
+
) as React.ComponentType<MobileNavBarPluginProps & { hasMenu: boolean }>,
|
|
101
90
|
[]
|
|
102
91
|
);
|
|
103
92
|
|
|
104
|
-
const { screenData, pathname } = routeData;
|
|
105
|
-
|
|
106
93
|
const offlinePlugin = getComponentModule({
|
|
107
94
|
plugins,
|
|
108
95
|
components: {},
|
|
@@ -113,35 +100,38 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
113
100
|
|
|
114
101
|
const style = React.useMemo(
|
|
115
102
|
() => ({
|
|
116
|
-
|
|
103
|
+
...screenStyles,
|
|
117
104
|
backgroundColor: isValidColor(backgroundColor)
|
|
118
105
|
? backgroundColor
|
|
119
106
|
: theme.app_background_color,
|
|
120
|
-
paddingTop: 0,
|
|
121
|
-
// paddingBottom: insets.bottom, // Should be applied directly by UI plugin
|
|
122
|
-
// paddingLeft: insets.left, // Should be applied directly by UI plugin
|
|
123
|
-
// paddingRight: insets.right, // Should be applied directly by UI plugin
|
|
124
107
|
}),
|
|
125
|
-
[
|
|
108
|
+
[theme.app_background_color, backgroundColor]
|
|
126
109
|
);
|
|
127
110
|
|
|
128
111
|
const targetScreenData =
|
|
129
112
|
currentScreenData || (screenData as any)?.targetScreen || screenData;
|
|
130
113
|
|
|
131
|
-
|
|
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
|
+
}
|
|
132
126
|
|
|
133
127
|
return (
|
|
134
|
-
<
|
|
135
|
-
<
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
<RouteManager pathname={pathname} screenData={screenData} />
|
|
143
|
-
</OfflineFallbackScreen>
|
|
144
|
-
</View>
|
|
145
|
-
</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>
|
|
146
136
|
);
|
|
147
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,12 +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";
|
|
8
|
+
import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
|
|
9
|
+
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
10
10
|
|
|
11
11
|
type Props = {
|
|
12
12
|
children: any;
|
|
@@ -16,6 +16,8 @@ type Props = {
|
|
|
16
16
|
animating: boolean;
|
|
17
17
|
contentStyle: ViewStyle;
|
|
18
18
|
pathname: string;
|
|
19
|
+
isActive: boolean;
|
|
20
|
+
screenData: NavigationScreenData;
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -38,34 +40,45 @@ export function Scene({
|
|
|
38
40
|
animating,
|
|
39
41
|
contentStyle,
|
|
40
42
|
pathname,
|
|
43
|
+
isActive = false,
|
|
44
|
+
screenData,
|
|
41
45
|
}: Props) {
|
|
46
|
+
const [initialScreenData, setInitialScreenData] = React.useState(screenData);
|
|
47
|
+
|
|
48
|
+
useScreenOrientationHandler({
|
|
49
|
+
screenData,
|
|
50
|
+
isActive,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
React.useLayoutEffect(() => {
|
|
54
|
+
if (isActive) {
|
|
55
|
+
setInitialScreenData(screenData);
|
|
56
|
+
}
|
|
57
|
+
}, [screenData, isActive]);
|
|
58
|
+
|
|
42
59
|
const frame = useSafeAreaFrame();
|
|
43
|
-
const
|
|
60
|
+
const isAnimating = animating && overlayStyle;
|
|
44
61
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
style={[style, contentStyle, { height, width }]}
|
|
52
|
-
>
|
|
53
|
-
<PathnameContext.Provider value={pathname}>
|
|
54
|
-
{children}
|
|
55
|
-
</PathnameContext.Provider>
|
|
56
|
-
<Animated.View style={overlayStyle} />
|
|
57
|
-
</Animated.View>
|
|
58
|
-
);
|
|
59
|
-
}
|
|
62
|
+
const dimensions = isAnimating
|
|
63
|
+
? {
|
|
64
|
+
width: "100%",
|
|
65
|
+
height: "100%",
|
|
66
|
+
}
|
|
67
|
+
: frame;
|
|
60
68
|
|
|
61
69
|
return (
|
|
62
70
|
<Animated.View
|
|
63
71
|
pointerEvents={pointerEvents}
|
|
64
|
-
style={[style, contentStyle,
|
|
72
|
+
style={[style, contentStyle, dimensions]}
|
|
65
73
|
>
|
|
66
|
-
<
|
|
67
|
-
{
|
|
68
|
-
|
|
74
|
+
<ScreenDataContext.Provider value={initialScreenData}>
|
|
75
|
+
<PathnameContext.Provider value={pathname}>
|
|
76
|
+
<ScreenContextProvider pathname={pathname}>
|
|
77
|
+
{children}
|
|
78
|
+
</ScreenContextProvider>
|
|
79
|
+
</PathnameContext.Provider>
|
|
80
|
+
</ScreenDataContext.Provider>
|
|
81
|
+
{isAnimating && <Animated.View style={overlayStyle} />}
|
|
69
82
|
</Animated.View>
|
|
70
83
|
);
|
|
71
84
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import
|
|
3
|
+
import { update, compose, tail, append, take, identity } 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,
|
|
@@ -49,7 +46,7 @@ function prepareScene(children) {
|
|
|
49
46
|
*/
|
|
50
47
|
function scenesForBackTransition(props: SceneProps, { scenes }) {
|
|
51
48
|
return scenes.length > 1
|
|
52
|
-
?
|
|
49
|
+
? identity(scenes)
|
|
53
50
|
: [prepareScene(props.children), scenes[0]];
|
|
54
51
|
}
|
|
55
52
|
|
|
@@ -113,7 +110,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
113
110
|
pushTransitionStart() {
|
|
114
111
|
this.setState(
|
|
115
112
|
{
|
|
116
|
-
scenes:
|
|
113
|
+
scenes: append(prepareScene(this.props.children), this.state.scenes),
|
|
117
114
|
...this.animationManager.stateForAction(this.state, NAV_ACTION_PUSH),
|
|
118
115
|
},
|
|
119
116
|
() => {
|
|
@@ -169,21 +166,23 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
169
166
|
|
|
170
167
|
transitionWithoutAnimation(resetState) {
|
|
171
168
|
const { scenes } = this.state;
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
169
|
+
const newScene = prepareScene(this.props.children);
|
|
170
|
+
const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
|
|
171
|
+
|
|
172
|
+
let newState;
|
|
173
|
+
|
|
174
|
+
if (resetState) {
|
|
175
|
+
newState = {
|
|
176
|
+
scenes: [newScene],
|
|
177
|
+
to: { index: 0 },
|
|
178
|
+
};
|
|
179
|
+
} else if (isLastSceneHook || scenes.length === 1) {
|
|
180
|
+
newState = { scenes: update(scenes.length - 1, newScene, scenes) };
|
|
181
|
+
} else {
|
|
182
|
+
newState = {
|
|
183
|
+
scenes: compose(tail, append(newScene))(scenes),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
187
186
|
|
|
188
187
|
this.setState(newState);
|
|
189
188
|
}
|
|
@@ -226,7 +225,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
226
225
|
this.shouldSkipAnimationForRoute(previousRoute) ||
|
|
227
226
|
this.shouldSkipAnimationForRoute(currentRoute)
|
|
228
227
|
) {
|
|
229
|
-
|
|
228
|
+
// we are going back, in this case we need to have only one scene using resetState
|
|
229
|
+
const resetState = isGoingBack ? true : undefined;
|
|
230
|
+
|
|
231
|
+
return this.transitionWithoutAnimation(resetState);
|
|
230
232
|
}
|
|
231
233
|
|
|
232
234
|
switch (this.props.navigator.previousAction) {
|
|
@@ -269,7 +271,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
269
271
|
backTransitionEnd(stepsBack) {
|
|
270
272
|
this.setState({
|
|
271
273
|
animating: false,
|
|
272
|
-
scenes:
|
|
274
|
+
scenes: take(this.state.scenes.length - stepsBack, this.state.scenes),
|
|
273
275
|
});
|
|
274
276
|
}
|
|
275
277
|
|
|
@@ -277,33 +279,25 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
277
279
|
// so only a single scene should be rendered,
|
|
278
280
|
// instead of dangerous nulls or duplicates.
|
|
279
281
|
renderSingleScene({ scenes, to }) {
|
|
280
|
-
const { contentStyle
|
|
281
|
-
const screenData =
|
|
282
|
-
|
|
283
|
-
const orientation = getScreenOrientation({
|
|
284
|
-
screenData,
|
|
285
|
-
layoutData,
|
|
286
|
-
});
|
|
282
|
+
const { contentStyle } = this.props;
|
|
283
|
+
const screenData = this.props.children.props.screenData;
|
|
284
|
+
const pathname = scenes[to.index].key;
|
|
287
285
|
|
|
288
|
-
// We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
|
|
289
|
-
// This saves unnecessary re-renders and user will not see distorted aspect screen.
|
|
290
286
|
return (
|
|
291
287
|
<View style={styles.container}>
|
|
292
|
-
{scenes[to.index] &&
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
</Scene>
|
|
306
|
-
)}
|
|
288
|
+
{scenes[to.index] && (
|
|
289
|
+
<Scene
|
|
290
|
+
{...{ style: to?.style || {} }}
|
|
291
|
+
pathname={pathname}
|
|
292
|
+
isActive={pathname === this.props.navigator.currentRoute}
|
|
293
|
+
contentStyle={contentStyle}
|
|
294
|
+
key={scenes[to.index].key}
|
|
295
|
+
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
296
|
+
screenData={screenData}
|
|
297
|
+
>
|
|
298
|
+
{scenes[to.index].children}
|
|
299
|
+
</Scene>
|
|
300
|
+
)}
|
|
307
301
|
</View>
|
|
308
302
|
);
|
|
309
303
|
}
|
|
@@ -319,12 +313,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
319
313
|
<Scene
|
|
320
314
|
key={scenes[from.index].key}
|
|
321
315
|
pathname={scenes[from.index].key}
|
|
316
|
+
isActive={scenes[from.index].key === this.props.navigator.currentRoute}
|
|
322
317
|
style={from.style}
|
|
323
318
|
pointerEvents="none"
|
|
324
319
|
overlayStyle={from.overlayStyle}
|
|
325
320
|
animating={this.state.animating}
|
|
326
321
|
contentStyle={contentStyle}
|
|
327
322
|
screenUniqueId={scenes[from.index].screenUniqueId}
|
|
323
|
+
screenData={scenes[from.index].children.props.screenData}
|
|
328
324
|
>
|
|
329
325
|
{scenes[from.index].children}
|
|
330
326
|
</Scene>
|
|
@@ -333,12 +329,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
333
329
|
const toScene = scenes[to.index] && (
|
|
334
330
|
<Scene
|
|
335
331
|
pathname={scenes[to.index].key}
|
|
332
|
+
isActive={scenes[to.index].key === this.props.navigator.currentRoute}
|
|
336
333
|
key={scenes[to.index].key}
|
|
337
334
|
style={to.style}
|
|
338
335
|
overlayStyle={to.overlayStyle}
|
|
339
336
|
animating={this.state.animating}
|
|
340
337
|
contentStyle={contentStyle}
|
|
341
338
|
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
339
|
+
screenData={this.props.children.props.screenData}
|
|
342
340
|
>
|
|
343
341
|
{scenes[to.index].children}
|
|
344
342
|
</Scene>
|
|
@@ -16,6 +16,13 @@ jest.mock("react-native-safe-area-context", () => ({
|
|
|
16
16
|
})),
|
|
17
17
|
}));
|
|
18
18
|
|
|
19
|
+
jest.mock(
|
|
20
|
+
"@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler",
|
|
21
|
+
() => ({
|
|
22
|
+
useScreenOrientationHandler: jest.fn(),
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
|
|
19
26
|
const { Scene } = require("../Scene");
|
|
20
27
|
|
|
21
28
|
const wrapper = shallow(
|