@applicaster/zapp-react-native-ui-components 12.0.0-alpha.7855034103 → 12.0.0-alpha.7990242848

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.
Files changed (68) hide show
  1. package/Components/BaseFocusable/index.tsx +3 -3
  2. package/Components/Cell/Cell.tsx +30 -9
  3. package/Components/Cell/CellWithFocusable.tsx +23 -9
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +11 -2
  7. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  8. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  9. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  10. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  11. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  12. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  13. package/Components/Layout/TV/__tests__/index.test.tsx +20 -75
  14. package/Components/Layout/TV/index.tsx +11 -67
  15. package/Components/Layout/TV/index.web.tsx +33 -0
  16. package/Components/Layout/index.tsx +15 -11
  17. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
  18. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +7 -2
  19. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  20. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  21. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  22. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  23. package/Components/MasterCell/dataAdapter.ts +21 -7
  24. package/Components/MasterCell/index.tsx +3 -1
  25. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  26. package/Components/MasterCell/utils/index.ts +17 -30
  27. package/Components/Navigator/StackNavigator.tsx +57 -0
  28. package/Components/Navigator/index.ts +1 -0
  29. package/Components/PlayerContainer/PlayerContainer.tsx +5 -1
  30. package/Components/River/TV/River.tsx +0 -23
  31. package/Components/Screen/TV/hooks/index.ts +3 -0
  32. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  33. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  34. package/Components/Screen/TV/index.web.tsx +165 -0
  35. package/Components/Screen/__tests__/Screen.test.tsx +3 -0
  36. package/Components/Screen/index.tsx +55 -58
  37. package/Components/Screen/navigationHandler.ts +5 -0
  38. package/Components/ScreenResolver/index.tsx +9 -12
  39. package/Components/Transitioner/Scene.tsx +12 -11
  40. package/Components/Transitioner/Transitioner.tsx +15 -29
  41. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  42. package/Components/VideoLive/LiveImageManager.ts +25 -1
  43. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  44. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  45. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  46. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +56 -43
  47. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +42 -32
  48. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
  49. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
  50. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  51. package/Components/VideoModal/PlayerWrapper.tsx +10 -10
  52. package/Components/VideoModal/VideoModal.tsx +4 -4
  53. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
  54. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  55. package/Components/VideoModal/utils.ts +5 -2
  56. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  57. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  58. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  59. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  60. package/Contexts/FocusableGroupContext/index.ts +7 -0
  61. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  62. package/Contexts/ScreenDataContext/index.tsx +20 -0
  63. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  64. package/package.json +5 -5
  65. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  66. package/Contexts/ScreenDataContext/index.ts +0 -3
  67. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  68. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
@@ -68,6 +68,7 @@ type Props = {
68
68
  mode?: VideoModalMode;
69
69
  loadPipesData: (url: string, options: {}) => void;
70
70
  disableCastAction?: boolean;
71
+ groupId?: string;
71
72
  };
72
73
 
73
74
  type ScreenStyles = ZappRiver["styles"] & {
@@ -123,6 +124,7 @@ const nativeStyles = {
123
124
  playerScreen: {
124
125
  flex: 1,
125
126
  backgroundColor: "black",
127
+ overflow: "hidden",
126
128
  },
127
129
  playerWrapper: {
128
130
  flex: 1,
@@ -200,6 +202,7 @@ const PlayerContainerComponent = (props: Props) => {
200
202
  style: videoStyle,
201
203
  mode = VideoModalMode.MAXIMIZED,
202
204
  disableCastAction = false,
205
+ groupId,
203
206
  } = props;
204
207
 
205
208
  // Hooks
@@ -249,8 +252,8 @@ const PlayerContainerComponent = (props: Props) => {
249
252
  return;
250
253
  }
251
254
 
252
- navigator.goBack();
253
255
  showNavBar(true);
256
+ navigator.goBack();
254
257
  }, [isModal, navigator.goBack, showNavBar]);
255
258
 
256
259
  const playEntry = (entry) => navigator.replaceTop(entry, { mode });
@@ -629,6 +632,7 @@ const PlayerContainerComponent = (props: Props) => {
629
632
  style={styles.focusableGroup}
630
633
  preferredFocus
631
634
  shouldUsePreferredFocus
635
+ groupId={groupId}
632
636
  >
633
637
  {/* Video player and components */}
634
638
  <View
@@ -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,3 @@
1
+ export { useInitialFocus } from "./useInitialFocus";
2
+
3
+ export { useRestoreFocus } from "./useRestoreFocus";
@@ -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,165 @@
1
+ import * as React from "react";
2
+ import { last } from "ramda";
3
+ import { View, StyleSheet } from "react-native";
4
+ import {
5
+ findMenuPlugin,
6
+ getNavigationProps,
7
+ getPathAttributes,
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 {
13
+ useNavbarState,
14
+ useScreenBackgroundColor,
15
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
16
+ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
17
+
18
+ import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
19
+ import { ScreenResolver } from "../../ScreenResolver";
20
+ import { useInitialFocus, useRestoreFocus } from "./hooks";
21
+ import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
22
+
23
+ const styles = StyleSheet.create({
24
+ container: {
25
+ position: "absolute",
26
+ top: 0,
27
+ left: 0,
28
+ right: 0,
29
+ bottom: 0,
30
+ },
31
+ });
32
+
33
+ type Components = {
34
+ NavBar: React.ComponentType<any>;
35
+ Background: React.ComponentType<any>;
36
+ };
37
+
38
+ type Props = {
39
+ route: string;
40
+ Components: Components;
41
+ };
42
+
43
+ const getActiveRiver = ({
44
+ screenId,
45
+ screenType,
46
+ routeState,
47
+ rivers,
48
+ fallbackActiveRiver,
49
+ }) => {
50
+ if (rivers[screenId]) {
51
+ if (screenType === "hooks") {
52
+ const navigations = routeState?.state?.entry?.payload?.navigations;
53
+
54
+ if (navigations) {
55
+ return routeState.state.entry.payload;
56
+ }
57
+ }
58
+
59
+ return routeState?.state?.screen;
60
+ }
61
+
62
+ // screenId is not presented into rivers, use fallback instead
63
+ return fallbackActiveRiver;
64
+ };
65
+
66
+ const getNavigations = ({
67
+ screenId,
68
+ screenType,
69
+ routeState,
70
+ rivers,
71
+ fallbackNavigations,
72
+ }) => {
73
+ if (rivers[screenId]) {
74
+ // river presents
75
+ if (screenType === "hooks") {
76
+ const navigations = routeState?.state?.entry?.payload?.navigations;
77
+
78
+ if (navigations) {
79
+ return navigations;
80
+ }
81
+ }
82
+
83
+ return routeState?.state?.screen?.navigations;
84
+ }
85
+
86
+ // screenId is not presented into rivers, use fallback instead
87
+ return fallbackNavigations;
88
+ };
89
+
90
+ export const Screen = ({ route, Components }: Props) => {
91
+ if (isNilOrEmpty(route)) {
92
+ throw Error("Required props: route is missing");
93
+ }
94
+
95
+ const navigator = useNavigation();
96
+ const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
97
+
98
+ const pathAttributes = getPathAttributes({ pathname: route });
99
+ const routeState = navigator.getStackForPathname(route);
100
+
101
+ const { screenType, screenId } = last(pathAttributes);
102
+
103
+ const backgroundColor = useScreenBackgroundColor(screenId);
104
+
105
+ useInitialFocus();
106
+ useRestoreFocus();
107
+
108
+ const activeRiver = getActiveRiver({
109
+ screenId,
110
+ screenType,
111
+ routeState,
112
+ rivers,
113
+ fallbackActiveRiver: navigator.activeRiver,
114
+ });
115
+
116
+ const navigationProps = getNavigationProps({
117
+ navigator: {
118
+ // @ts-ignore
119
+ activeRiver,
120
+ // @ts-ignore
121
+ screenTitle: routeState.state.entry?.title || routeState.screen?.name,
122
+ },
123
+ category: "menu",
124
+ });
125
+
126
+ const navigations = getNavigations({
127
+ screenId,
128
+ screenType,
129
+ routeState,
130
+ rivers,
131
+ fallbackNavigations: navigator.activeRiver.navigations,
132
+ });
133
+
134
+ const menuPlugin = findMenuPlugin(navigations, plugins);
135
+
136
+ const NavBar = (Components.NavBar ||
137
+ menuPlugin.module) as React.ComponentType<any>;
138
+
139
+ const isPlayer = isPlayerPlugin(routeState);
140
+
141
+ const { visible: isNavBarVisible } = useNavbarState();
142
+
143
+ const screenData =
144
+ screenType === "hooks" || isPlayer
145
+ ? routeState?.state?.entry
146
+ : routeState?.state?.screen;
147
+
148
+ return (
149
+ <View style={[styles.container, { backgroundColor }]}>
150
+ <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
151
+ <NavBar
152
+ isVisible={isNavBarVisible}
153
+ menuPlugin={menuPlugin}
154
+ navigationProps={navigationProps}
155
+ />
156
+ </NavBarContainer>
157
+ <ScreenResolver
158
+ screenType={screenType}
159
+ screenId={screenId}
160
+ screenData={screenData}
161
+ groupId={route}
162
+ />
163
+ </View>
164
+ );
165
+ };
@@ -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,14 +3,18 @@ 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";
9
13
  import {
10
- getNavigationPropsV2,
11
- resolveNavigationPlugin,
14
+ shouldNavBarDisplayMenu,
15
+ getNavBarProps,
16
+ getScreenId,
12
17
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
13
- import { useSafeAreaInsets } from "react-native-safe-area-context";
14
18
  import {
15
19
  useDimensions,
16
20
  useRoute,
@@ -21,20 +25,16 @@ import {
21
25
  } from "@applicaster/zapp-react-native-utils/reactHooks";
22
26
  import { getNavigationPluginModule } from "@applicaster/zapp-react-native-app/App/Layout/layoutHelpers";
23
27
 
24
- import { ScreenContextProvider } from "../../Contexts/ScreenContext";
25
28
  import { RouteManager } from "../RouteManager";
26
29
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
27
30
  import { useScreenOrientationHandler } from "./orientationHandler";
28
31
 
29
- const getScreenId = (
30
- screenData: LegacyNavigationScreenData,
31
- fallbackRiver: ZappRiver
32
- ) => {
33
- return screenData?.targetScreen
34
- ? screenData?.targetScreen?.id ?? fallbackRiver.id
35
- : "screen_id" in screenData
36
- ? screenData.screen_id
37
- : fallbackRiver.id;
32
+ const screenStyles = {
33
+ flex: 1,
34
+ paddingTop: 0,
35
+ // paddingBottom: insets.bottom, // Should be applied directly by UI plugin
36
+ // paddingLeft: insets.left, // Should be applied directly by UI plugin
37
+ // paddingRight: insets.right, // Should be applied directly by UI plugin
38
38
  };
39
39
 
40
40
  function colorIsNotTransparent(color) {
@@ -45,9 +45,7 @@ function colorIsNotTransparent(color) {
45
45
  R.replace("rgba(", "")
46
46
  )(color);
47
47
 
48
- const alpha = Number(layers?.[3]);
49
-
50
- return alpha > 0;
48
+ return Number(layers?.[3]) > 0;
51
49
  }
52
50
 
53
51
  function isValidColor(string) {
@@ -67,9 +65,12 @@ export function Screen(_props: Props) {
67
65
  // Gets the data for the current screen configuration
68
66
  const currentScreenData = useCurrentScreenData();
69
67
  const { backgroundColor } = useScreenConfiguration(currentScreenData.id);
70
- const insets = useSafeAreaInsets();
71
68
 
72
- const { width: screenWidth } = useDimensions("screen", {
69
+ const {
70
+ width: screenWidth,
71
+ height,
72
+ deviceInfo,
73
+ } = useDimensions("screen", {
73
74
  fullDimensions: true,
74
75
  });
75
76
 
@@ -81,30 +82,19 @@ export function Screen(_props: Props) {
81
82
 
82
83
  const { title } = useNavbarState();
83
84
 
84
- const hasMenu =
85
- resolveNavigationPlugin({
86
- category: "menu",
87
- navigations: currentRiver.navigations,
88
- plugins,
89
- })?.identifier === "quick_brick_side_menu";
90
-
91
- const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(() => {
92
- const props = getNavigationPropsV2({
93
- currentRiver,
94
- title,
95
- category: "nav_bar",
96
- });
97
-
98
- if (props) {
99
- return {
100
- ...props,
101
- id: pathname,
102
- pathname: pathname,
103
- };
104
- }
105
-
106
- return null;
107
- }, [currentRiver, pathname]);
85
+ const isTablet = deviceInfo?.isTablet;
86
+
87
+ const { appData } = usePickFromState(["appData"]);
88
+ const isTabletPortrait = appData?.isTabletPortrait;
89
+
90
+ const layoutData = { isTablet, isTabletPortrait, width: screenWidth, height };
91
+
92
+ const hasMenu = shouldNavBarDisplayMenu(currentRiver, plugins);
93
+
94
+ const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(
95
+ getNavBarProps(currentRiver, pathname, title),
96
+ [currentRiver, pathname]
97
+ );
108
98
 
109
99
  const NavBar = React.useMemo(
110
100
  () =>
@@ -126,16 +116,12 @@ export function Screen(_props: Props) {
126
116
 
127
117
  const style = React.useMemo(
128
118
  () => ({
129
- flex: 1,
119
+ ...screenStyles,
130
120
  backgroundColor: isValidColor(backgroundColor)
131
121
  ? backgroundColor
132
122
  : 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
123
  }),
138
- [insets, screenWidth, theme.app_background_color, backgroundColor]
124
+ [theme.app_background_color, backgroundColor]
139
125
  );
140
126
 
141
127
  const targetScreenData =
@@ -143,16 +129,27 @@ export function Screen(_props: Props) {
143
129
 
144
130
  useScreenOrientationHandler({ screenData: targetScreenData });
145
131
 
132
+ const orientation = useGetScreenOrientation(targetScreenData);
133
+
134
+ // We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
135
+ // This saves unnecessary re-renders and user will not see distorted aspect screen.
136
+ if (
137
+ !isOrientationCompatible({
138
+ orientation,
139
+ layoutData,
140
+ })
141
+ ) {
142
+ return <View style={style} />;
143
+ }
144
+
146
145
  return (
147
- <ScreenContextProvider pathname={pathname}>
148
- <View style={style}>
149
- {navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
150
-
151
- <OfflineFallbackScreen screenData={targetScreenData}>
152
- {/* @TODO RouteManager doesn't use props, can they be removed ? */}
153
- <RouteManager pathname={pathname} screenData={screenData} />
154
- </OfflineFallbackScreen>
155
- </View>
156
- </ScreenContextProvider>
146
+ <View style={style}>
147
+ {navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
148
+
149
+ <OfflineFallbackScreen screenData={targetScreenData}>
150
+ {/* @TODO RouteManager doesn't use props, can they be removed ? */}
151
+ <RouteManager pathname={pathname} screenData={screenData} />
152
+ </OfflineFallbackScreen>
153
+ </View>
157
154
  );
158
155
  }
@@ -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}
@@ -1,6 +1,5 @@
1
1
  import * as React from "react";
2
- import * as R from "ramda";
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
- R.path(["module", "Component"], ScreenPlugin) ||
102
- R.prop("module", ScreenPlugin) ||
103
- R.prop("Component", ScreenPlugin) ||
98
+ path(["module", "Component"], ScreenPlugin) ||
99
+ prop("module", ScreenPlugin) ||
100
+ prop("Component", ScreenPlugin) ||
104
101
  ScreenPlugin;
105
102
 
106
103
  const configuration =
107
- R.prop("configuration", ScreenPlugin) ||
108
- R.prop("__plugin_configuration", ScreenComponent);
104
+ prop("configuration", ScreenPlugin) ||
105
+ prop("__plugin_configuration", ScreenComponent);
109
106
 
110
107
  if (ScreenComponent) {
111
108
  return (
@@ -1,13 +1,9 @@
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";
9
4
  import { PathnameContext } from "../../Contexts/PathnameContext";
10
5
  import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
6
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
11
7
 
12
8
  type Props = {
13
9
  children: any;
@@ -53,12 +49,15 @@ export function Scene({
53
49
  }, [screenData, isActive]);
54
50
 
55
51
  const frame = useSafeAreaFrame();
56
- const { height, width } = useWindowDimensions();
57
52
 
58
- // Safe frame takes too long to update,
59
- // so we can not rely on it there, and use height and width instead.
60
53
  const isAnimating = animating && overlayStyle;
61
- const dimensions = isAnimating ? { height, width } : frame;
54
+
55
+ const dimensions = isAnimating
56
+ ? {
57
+ height: "100%",
58
+ width: "100%",
59
+ }
60
+ : frame;
62
61
 
63
62
  return (
64
63
  <Animated.View
@@ -67,7 +66,9 @@ export function Scene({
67
66
  >
68
67
  <ScreenDataContext.Provider value={initialScreenData}>
69
68
  <PathnameContext.Provider value={pathname}>
70
- {children}
69
+ <ScreenContextProvider pathname={pathname}>
70
+ {children}
71
+ </ScreenContextProvider>
71
72
  </PathnameContext.Provider>
72
73
  </ScreenDataContext.Provider>
73
74
  {isAnimating && <Animated.View style={overlayStyle} />}