@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5522474195 → 12.0.0-alpha.5545254270

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 (49) hide show
  1. package/Components/Cell/Cell.tsx +26 -5
  2. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  3. package/Components/FreezeWithCallback/LICENSE +21 -0
  4. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  5. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  6. package/Components/FreezeWithCallback/index.tsx +3 -0
  7. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  8. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  9. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  10. package/Components/Layout/TV/__tests__/index.test.tsx +2 -1
  11. package/Components/Layout/TV/index.tsx +11 -65
  12. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
  13. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +1 -7
  14. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  15. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  16. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  17. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  18. package/Components/MasterCell/dataAdapter.ts +21 -7
  19. package/Components/MasterCell/index.tsx +5 -3
  20. package/Components/Navigator/StackNavigator.tsx +14 -5
  21. package/Components/PlayerContainer/PlayerContainer.tsx +2 -5
  22. package/Components/Screen/TV/hooks/index.ts +0 -2
  23. package/Components/Screen/TV/index.web.tsx +41 -49
  24. package/Components/Screen/__tests__/Screen.test.tsx +0 -49
  25. package/Components/Screen/index.tsx +28 -77
  26. package/Components/Screen/navigationHandler.ts +6 -3
  27. package/Components/Screen/orientationHandler.ts +18 -7
  28. package/Components/Screen/utils.ts +16 -0
  29. package/Components/ScreenResolver/index.tsx +6 -11
  30. package/Components/Transitioner/Scene.tsx +20 -12
  31. package/Components/Transitioner/Transitioner.tsx +26 -21
  32. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  33. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  34. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  35. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  36. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  37. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  38. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +31 -7
  39. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +9 -2
  40. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +23 -5
  41. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +28 -8
  42. package/Components/VideoModal/ModalAnimation/utils.ts +1 -0
  43. package/Components/VideoModal/PlayerWrapper.tsx +1 -1
  44. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +48 -2
  45. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  46. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  47. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  48. package/package.json +5 -5
  49. package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
@@ -4,22 +4,14 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
4
4
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
5
5
  import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
6
6
 
7
- import {
8
- getNavigationProps,
9
- resolveNavigationPlugin,
10
- routeIsPlayerScreen,
11
- } from "@applicaster/zapp-react-native-utils/navigationUtils";
12
-
13
7
  import { getBackgroundImageUrl } from "../utils";
14
8
  import { LayoutContainer } from "./LayoutContainer";
15
- import { NavBarContainer } from "./NavBarContainer";
16
9
  import { ScreenContainer } from "./ScreenContainer";
17
10
 
18
11
  import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
19
- import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
20
12
  import { PathnameContext } from "../../../Contexts/PathnameContext";
21
- import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
22
13
  import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
14
+ import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
23
15
 
24
16
  type Components = {
25
17
  NavBar: React.ComponentType<any>;
@@ -40,20 +32,9 @@ type Props = {
40
32
  const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
41
33
  const navigator = useNavigation();
42
34
  const theme = useTheme();
43
- const { title, visible } = useNavbarState();
44
- const { activeRiver, currentRoute } = navigator;
45
-
46
- const {
47
- appState: { appReady = false } = {},
48
- remoteConfigurations,
49
- plugins = [],
50
- } = usePickFromState(["appState", "remoteConfigurations", "plugins"]);
51
35
 
52
- const navigationProps = getNavigationProps({
53
- navigator,
54
- title,
55
- category: "menu",
56
- });
36
+ const { appState: { appReady = false } = {}, remoteConfigurations } =
37
+ usePickFromState(["appState", "remoteConfigurations", "plugins"]);
57
38
 
58
39
  const backgroundColor = React.useMemo(() => theme.app_background_color, []);
59
40
 
@@ -62,37 +43,6 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
62
43
  [remoteConfigurations]
63
44
  );
64
45
 
65
- const menuPlugin = React.useMemo(
66
- () =>
67
- resolveNavigationPlugin({
68
- category: "menu",
69
- navigations: activeRiver?.navigations,
70
- plugins,
71
- }) as QuickBrickPlugin,
72
- []
73
- );
74
-
75
- const NavBar = React.useMemo(
76
- () => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
77
- []
78
- );
79
-
80
- const [navBarReady, setNavBarReady] = React.useState(false);
81
-
82
- const navBarContainer = (
83
- <NavBarContainer isVisible={visible} onReady={setNavBarReady}>
84
- <NavBar
85
- ref={ComponentsExtraProps?.NavBar?.ref}
86
- isVisible={visible && !routeIsPlayerScreen(currentRoute)}
87
- menuPlugin={menuPlugin}
88
- navigationProps={navigationProps}
89
- {...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
90
- />
91
- </NavBarContainer>
92
- );
93
-
94
- const isTVOS = isApplePlatform();
95
-
96
46
  if (!appReady) {
97
47
  return null;
98
48
  }
@@ -107,18 +57,14 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
107
57
  >
108
58
  <ScreenDataContext.Provider value={navigator.data}>
109
59
  <PathnameContext.Provider value={navigator.currentRoute}>
110
- {!isTVOS ? navBarContainer : null}
111
- {navBarReady ? (
112
- /**
113
- Need to re-mount this component on each navigation event
114
- It's a hack to work around the fact that we don't support
115
- correct screen rendering in our navigator (shared currentRoute state)
116
- **/
117
- <ScreenContainer>{children}</ScreenContainer>
118
- ) : null}
119
- {/** Render NavBarContainer over ScreenContainer to let tvOS native
120
- focus manager works correctly to focus nav bar items first **/}
121
- {isTVOS ? navBarContainer : null}
60
+ <ScreenContextProvider pathname={navigator.currentRoute}>
61
+ <ScreenContainer
62
+ ComponentsExtraProps={ComponentsExtraProps}
63
+ NavBar={Components.NavBar}
64
+ >
65
+ {children}
66
+ </ScreenContainer>
67
+ </ScreenContextProvider>
122
68
  </PathnameContext.Provider>
123
69
  </ScreenDataContext.Provider>
124
70
  </Components.Background>
@@ -53,6 +53,7 @@ export function ActionButton(props: Props) {
53
53
  const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
54
54
  const actionContext = useActions(action?.identifier);
55
55
 
56
+ // TODO: add subscription API for action availability
56
57
  const actionDisabled =
57
58
  typeof actionContext?.isActionAvailable === "function" &&
58
59
  !actionContext.isActionAvailable(item);
@@ -68,7 +69,7 @@ export function ActionButton(props: Props) {
68
69
  if (actionDisabled || !actionContext) return;
69
70
 
70
71
  setActionState(actionContext.initialEntryState(item));
71
- }, [actionDisabled, item?.id]);
72
+ }, [actionDisabled, item?.id, actionContext]);
72
73
 
73
74
  const onPress = useCallback(() => {
74
75
  actionContext.invokeAction(item, {
@@ -117,9 +117,6 @@ export const BorderContainerView = (props: Props) => {
117
117
  children,
118
118
  } = props;
119
119
 
120
- const borderStyleForMissingBorder =
121
- style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
122
-
123
120
  const padding =
124
121
  borderPosition === "outside"
125
122
  ? {
@@ -131,10 +128,7 @@ export const BorderContainerView = (props: Props) => {
131
128
  : {};
132
129
 
133
130
  return (
134
- <View
135
- {...props}
136
- style={[style, styles.container, borderStyleForMissingBorder]}
137
- >
131
+ <View pointerEvents="box-none" {...props} style={[style, styles.container]}>
138
132
  <Border style={style} padding={padding} borderPosition={borderPosition} />
139
133
  {children}
140
134
  </View>
@@ -0,0 +1,71 @@
1
+ import { ImageStyle } from "react-native";
2
+
3
+ import {
4
+ getImageContainerMarginStyles,
5
+ ifElseFocusedSelected,
6
+ } from "@applicaster/zapp-react-native-utils/cellUtils";
7
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
8
+
9
+ export const ImageBorderContainer = ({
10
+ value,
11
+ state,
12
+ imageStyles,
13
+ }: {
14
+ value: (key: string) => string;
15
+ state: CellState;
16
+ imageStyles: ImageStyle;
17
+ }) => {
18
+ const imageMargins = getImageContainerMarginStyles({ value });
19
+
20
+ return {
21
+ type: "BorderContainerView",
22
+ style: {
23
+ position: "absolute",
24
+ // Image border now separated from the image, so cell padding affects the border position
25
+ marginTop:
26
+ toNumberWithDefaultZero(imageMargins.marginTop) +
27
+ toNumberWithDefaultZero(value("cell_padding_top")),
28
+ marginLeft:
29
+ toNumberWithDefaultZero(imageMargins.marginLeft) +
30
+ toNumberWithDefaultZero(value("cell_padding_left")),
31
+ marginRight:
32
+ toNumberWithDefaultZero(imageMargins.marginRight) +
33
+ toNumberWithDefaultZero(value("cell_padding_right")),
34
+ marginBottom:
35
+ toNumberWithDefaultZero(imageMargins.marginBottom) +
36
+ toNumberWithDefaultZero(value("cell_padding_bottom")),
37
+ zIndex: 1,
38
+ borderWidth: value("image_border_size"),
39
+ borderColor: ifElseFocusedSelected(
40
+ state,
41
+ value("image_focused_border_color"),
42
+ value("image_selected_border_color"),
43
+ value("image_focused_selected_border_color"),
44
+ value("image_border_color")
45
+ ),
46
+ borderRadius: toNumberWithDefaultZero(value("image_corner_radius")),
47
+ },
48
+ additionalProps: {
49
+ pointerEvents: "none",
50
+ borderPosition: value("image_border_position"),
51
+ borderPaddingTop: toNumberWithDefaultZero(
52
+ value("image_border_padding_top")
53
+ ),
54
+ borderPaddingRight: toNumberWithDefaultZero(
55
+ value("image_border_padding_right")
56
+ ),
57
+ borderPaddingBottom: toNumberWithDefaultZero(
58
+ value("image_border_padding_bottom")
59
+ ),
60
+ borderPaddingLeft: toNumberWithDefaultZero(
61
+ value("image_border_padding_left")
62
+ ),
63
+ },
64
+ elements: [
65
+ {
66
+ type: "View",
67
+ style: imageStyles,
68
+ },
69
+ ],
70
+ };
71
+ };
@@ -108,6 +108,26 @@ const prepareEntry = (entry) => {
108
108
  };
109
109
  }
110
110
 
111
+ const previewPlayback =
112
+ entry.extensions?.["brightcove"]?.["preview_playback"];
113
+
114
+ if (previewPlayback) {
115
+ return {
116
+ ...entry,
117
+ extensions: {
118
+ ...entry.extensions,
119
+ brightcove: {
120
+ ...entry?.extensions?.["brightcove"],
121
+ video_id: previewPlayback,
122
+ },
123
+ },
124
+ };
125
+ }
126
+
127
+ if (entry.extensions?.["brightcove"]?.["video_id"]) {
128
+ return entry;
129
+ }
130
+
111
131
  const src = entry.content?.src;
112
132
 
113
133
  if (!src) {
@@ -15,6 +15,7 @@ import { BorderContainerView } from "./BorderContainerView";
15
15
  import { CellBadge } from "./CellBadge";
16
16
  import { TvActionButtons } from "./tv/TvActionButtons";
17
17
  import { ButtonContainerView } from "./tv/ButtonContainerView";
18
+ import { ImageBorderContainer } from "./ImageBorderContainer";
18
19
 
19
20
  export const defaultComponents = {
20
21
  View,
@@ -28,6 +29,7 @@ export const defaultComponents = {
28
29
  ProgressBar,
29
30
  Toggle,
30
31
  LiveImage,
32
+ ImageBorderContainer,
31
33
  BorderContainerView,
32
34
  DynamicBadge,
33
35
  SecondaryImage,
@@ -5,6 +5,7 @@ import * as R from "ramda";
5
5
 
6
6
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
7
7
  import { normalizeProgressValue } from "./utils";
8
+ import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
8
9
 
9
10
  const ACTION_NAME = "continue-watching";
10
11
  const DEFAULT_FILL = 0;
@@ -27,6 +28,7 @@ const getProgressValue = (
27
28
 
28
29
  export const useFillInPercent = (entry: ZappEntry): number => {
29
30
  const action = useActions(ACTION_NAME);
31
+ const isActive = useIsScreenActive();
30
32
 
31
33
  const [fillInPercent, setFillInPercent] =
32
34
  React.useState<number>(DEFAULT_FILL);
@@ -39,6 +41,10 @@ export const useFillInPercent = (entry: ZappEntry): number => {
39
41
  }, []);
40
42
 
41
43
  React.useEffect(() => {
44
+ if (!isActive) {
45
+ return;
46
+ }
47
+
42
48
  // refresh progress in UI when it was changed in CW
43
49
  const unsubscribe = action?.addDataSourceListener?.(() => {
44
50
  getProgressValue(action, entry, (progress) => {
@@ -49,7 +55,7 @@ export const useFillInPercent = (entry: ZappEntry): number => {
49
55
  return () => {
50
56
  unsubscribe?.();
51
57
  };
52
- }, []);
58
+ }, [isActive]);
53
59
 
54
60
  return fillInPercent;
55
61
  };
@@ -37,14 +37,28 @@ function retrieveData(entry, func, args) {
37
37
  */
38
38
 
39
39
  export function configInflater(
40
- entry,
41
- { type, style, additionalProps = {}, data = [], elements }
40
+ entry: any,
41
+ {
42
+ type,
43
+ style,
44
+ additionalProps = {},
45
+ data = [],
46
+ elements,
47
+ }: {
48
+ type: any;
49
+ style: any;
50
+ additionalProps?: Record<string, any>;
51
+ data?: Array<{ propName: string; func: Function; args: any[] }>;
52
+ elements?: any[];
53
+ }
42
54
  ) {
43
- const props = R.reduce(
44
- (acc, curr) =>
45
- R.assoc(curr.propName, retrieveData(entry, curr.func, curr.args), acc),
46
- additionalProps,
47
- data
55
+ const props = data.reduce(
56
+ (acc, curr) => {
57
+ acc[curr.propName] = retrieveData(entry, curr.func, curr.args);
58
+
59
+ return acc;
60
+ },
61
+ { ...additionalProps }
48
62
  );
49
63
 
50
64
  let adjustedElements;
@@ -52,6 +52,8 @@ export function masterCellBuilder({
52
52
  const { View } = componentsMap;
53
53
  const elementsBuilder = dataAdapter(cellConfiguration);
54
54
 
55
+ // This is very expensive operation
56
+ // Keep calls to minimum
55
57
  const hasFocusableInside = hasFocusableInsideBuilder(elementsBuilder);
56
58
 
57
59
  /**
@@ -74,8 +76,8 @@ export function masterCellBuilder({
74
76
  const selectedState = screen?.selectedEntry;
75
77
 
76
78
  const entryIsSelected = React.useMemo(
77
- () => selectedState?.id === item?.id,
78
- [selectedState?.id]
79
+ () => !!(selectedState?.id && selectedState?.id === item?.id),
80
+ [selectedState?.id, item?.id]
79
81
  );
80
82
 
81
83
  const elements = React.useMemo(
@@ -84,7 +86,7 @@ export function masterCellBuilder({
84
86
  entry: item,
85
87
  state: getEntryState(state, entryIsSelected),
86
88
  }),
87
- [state, item, entryIsSelected]
89
+ [state, item?.id, entryIsSelected] // Assuming that item won't mutate
88
90
  );
89
91
 
90
92
  const wrapperRef = React.useRef(null);
@@ -8,6 +8,8 @@ import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/
8
8
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
9
9
 
10
10
  import { Screen } from "../Screen/TV/index.web";
11
+ import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
12
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
11
13
 
12
14
  type Components = {
13
15
  NavBar: React.ComponentType<any>;
@@ -19,25 +21,32 @@ type Props = {
19
21
  };
20
22
 
21
23
  export const StackNavigator = ({ Components }: Props) => {
22
- const { mainStack, currentRoute } = useNavigation();
24
+ const { mainStack } = useNavigation();
23
25
 
24
- const renderScreen = ({ route, state }) => {
26
+ const renderScreen = ({ route, state }, index) => {
25
27
  const pathAttributes = getPathAttributes({ pathname: route });
26
28
 
27
29
  if (isEmpty(pathAttributes)) {
28
30
  return null;
29
31
  }
30
32
 
33
+ // HACK: Adding index to route to avoid conflicts in the navigator.
34
+ // Startup hooks are all using PUSH navigation action to navigate, but their routes are always like root routes.
35
+ // This means some hooks can have the same routes, e.g., ["hooks/context-setter", "/hooks/login-plug", "hooks/context-setter"].
36
+ const routeId = `${route}--${index}`;
37
+
31
38
  return (
32
39
  <FocusableGroup
33
40
  id={route}
34
- preferredFocus={route === currentRoute}
41
+ preferredFocus={isLast(index, mainStack.length)}
35
42
  excludeFromFocusSearching
36
- key={route}
43
+ key={routeId}
37
44
  >
38
45
  <ScreenDataContext.Provider value={state}>
39
46
  <PathnameContext.Provider value={route}>
40
- <Screen route={route} Components={Components} />
47
+ <ScreenContextProvider pathname={route}>
48
+ <Screen route={route} Components={Components} />
49
+ </ScreenContextProvider>
41
50
  </PathnameContext.Provider>
42
51
  </ScreenDataContext.Provider>
43
52
  </FocusableGroup>
@@ -124,6 +124,7 @@ const nativeStyles = {
124
124
  playerScreen: {
125
125
  flex: 1,
126
126
  backgroundColor: "black",
127
+ overflow: "hidden",
127
128
  },
128
129
  playerWrapper: {
129
130
  flex: 1,
@@ -252,11 +253,7 @@ const PlayerContainerComponent = (props: Props) => {
252
253
  }
253
254
 
254
255
  showNavBar(true);
255
-
256
- // Hack to close player screen on mobile only (tv handles that in InteractionManager)
257
- if (!isTV()) {
258
- navigator.goBack();
259
- }
256
+ navigator.goBack();
260
257
  }, [isModal, navigator.goBack, showNavBar]);
261
258
 
262
259
  const playEntry = (entry) => navigator.replaceTop(entry, { mode });
@@ -1,3 +1 @@
1
1
  export { useInitialFocus } from "./useInitialFocus";
2
-
3
- export { useRestoreFocus } from "./useRestoreFocus";
@@ -1,20 +1,29 @@
1
- import * as React from "react";
2
- import { last, pathOr } from "ramda";
3
- import { View, StyleSheet } from "react-native";
1
+ import React from "react";
2
+ import { last } from "ramda";
3
+ import { StyleSheet, View } from "react-native";
4
4
  import {
5
+ findMenuPlugin,
5
6
  getNavigationProps,
6
7
  getPathAttributes,
7
- resolveNavigationPlugin,
8
8
  } from "@applicaster/zapp-react-native-utils/navigationUtils";
9
- import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+ import {
10
+ useIsScreenActive,
11
+ useNavigation,
12
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
10
13
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
14
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
- import { useScreenBackgroundColor } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
15
+ import {
16
+ useNavbarState,
17
+ useScreenBackgroundColor,
18
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
13
19
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
20
 
15
21
  import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
16
22
  import { ScreenResolver } from "../../ScreenResolver";
17
- import { useInitialFocus, useRestoreFocus } from "./hooks";
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";
18
27
 
19
28
  const styles = StyleSheet.create({
20
29
  container: {
@@ -36,25 +45,6 @@ type Props = {
36
45
  Components: Components;
37
46
  };
38
47
 
39
- const getPluginType = pathOr("unknown_plugin_type", [
40
- "state",
41
- "screen",
42
- "plugin_type",
43
- ]);
44
-
45
- export const isPresentFullScreen = pathOr(false, [
46
- "state",
47
- "screen",
48
- "module",
49
- "presentFullScreen",
50
- ]);
51
-
52
- const isPlayerPlugin = (routeState): boolean =>
53
- getPluginType(routeState) === "player";
54
-
55
- const isLoginPlugin = (routeState): boolean =>
56
- getPluginType(routeState) === "login";
57
-
58
48
  const getActiveRiver = ({
59
49
  screenId,
60
50
  screenType,
@@ -118,7 +108,6 @@ export const Screen = ({ route, Components }: Props) => {
118
108
  const backgroundColor = useScreenBackgroundColor(screenId);
119
109
 
120
110
  useInitialFocus();
121
- useRestoreFocus();
122
111
 
123
112
  const activeRiver = getActiveRiver({
124
113
  screenId,
@@ -146,41 +135,44 @@ export const Screen = ({ route, Components }: Props) => {
146
135
  fallbackNavigations: navigator.activeRiver.navigations,
147
136
  });
148
137
 
149
- const menuPlugin = resolveNavigationPlugin({
150
- category: "menu",
151
- navigations,
152
- plugins,
153
- }) as QuickBrickPlugin;
138
+ const menuPlugin = findMenuPlugin(navigations, plugins);
154
139
 
155
140
  const NavBar = (Components.NavBar ||
156
141
  menuPlugin.module) as React.ComponentType<any>;
157
142
 
158
143
  const isPlayer = isPlayerPlugin(routeState);
159
- const isLogin = isLoginPlugin(routeState);
160
- const isFullScreen = isPresentFullScreen(routeState);
161
144
 
162
- const isNavBarVisible = !isPlayer && !isLogin && !isFullScreen;
145
+ const { visible: isNavBarVisible } = useNavbarState();
163
146
 
164
147
  const screenData =
165
148
  screenType === "hooks" || isPlayer
166
149
  ? routeState?.state?.entry
167
150
  : routeState?.state?.screen;
168
151
 
152
+ const isScreenActive = useIsScreenActive();
153
+
169
154
  return (
170
- <View style={[styles.container, { backgroundColor }]}>
171
- <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
172
- <NavBar
173
- isVisible={isNavBarVisible}
174
- menuPlugin={menuPlugin}
175
- navigationProps={navigationProps}
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}
176
174
  />
177
- </NavBarContainer>
178
- <ScreenResolver
179
- screenType={screenType}
180
- screenId={screenId}
181
- screenData={screenData}
182
- groupId={route}
183
- />
184
- </View>
175
+ </View>
176
+ </FreezeWithCallback>
185
177
  );
186
178
  };
@@ -99,14 +99,6 @@ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
99
99
  }),
100
100
  }));
101
101
 
102
- const {
103
- ORIENTATIONS,
104
- } = require("@applicaster/zapp-react-native-utils/appUtils/orientationHelper");
105
-
106
- const {
107
- useCurrentScreenData,
108
- } = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
109
-
110
102
  const {
111
103
  allowedOrientationsForScreen,
112
104
  getOrientation,
@@ -158,45 +150,4 @@ describe("<Screen Component />", () => {
158
150
  expect(wrapper.toJSON()).toMatchSnapshot();
159
151
  });
160
152
  });
161
-
162
- it("invokes the orientation hook when the route changes", () => {
163
- act(() => {
164
- wrapper = create(<Screen {...screenProps} />);
165
- });
166
-
167
- // @ts-ignore
168
- useCurrentScreenData.mockReturnValue({
169
- id: "player-testId",
170
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
171
- plugin_type: "player",
172
- });
173
-
174
- act(() => {
175
- wrapper.update(
176
- <Screen
177
- {...screenProps}
178
- pathname="/playable"
179
- screenData={{
180
- id: "player-testId",
181
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
182
- plugin_type: "player",
183
- }}
184
- />
185
- );
186
- });
187
-
188
- useCurrentScreenData.mockReturnValue({
189
- id: "player-testId",
190
- general: { screen_orientation: ORIENTATIONS.landscapeSensor },
191
- });
192
-
193
- act(() => {
194
- wrapper.update(<Screen {...screenProps} />);
195
- });
196
-
197
- expect(allowedOrientationsForScreen).toHaveBeenNthCalledWith(
198
- 1,
199
- ORIENTATIONS.landscapeSensor
200
- );
201
- });
202
153
  });