@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4201443043 → 12.0.0-alpha.4220424021

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 (74) hide show
  1. package/Components/BaseFocusable/index.tsx +2 -2
  2. package/Components/Cell/Cell.tsx +26 -5
  3. package/Components/Cell/CellWithFocusable.tsx +6 -4
  4. package/Components/Cell/TvOSCellComponent.tsx +3 -7
  5. package/Components/Focusable/Focusable.tsx +6 -1
  6. package/Components/FocusableGroup/index.tsx +10 -2
  7. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  8. package/Components/FreezeWithCallback/LICENSE +21 -0
  9. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  10. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  11. package/Components/FreezeWithCallback/index.tsx +3 -0
  12. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  13. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  14. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  15. package/Components/Layout/TV/__tests__/index.test.tsx +3 -2
  16. package/Components/Layout/TV/index.tsx +52 -9
  17. package/Components/Layout/TV/index.web.tsx +33 -0
  18. package/Components/Layout/index.tsx +15 -11
  19. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -1
  20. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
  21. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  22. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  23. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  24. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  25. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +6 -1
  26. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  27. package/Components/MasterCell/dataAdapter.ts +21 -7
  28. package/Components/MasterCell/index.tsx +5 -3
  29. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  30. package/Components/MasterCell/utils/index.ts +17 -30
  31. package/Components/Navigator/StackNavigator.tsx +14 -5
  32. package/Components/PlayerContainer/PlayerContainer.tsx +2 -0
  33. package/Components/Screen/TV/hooks/index.ts +0 -2
  34. package/Components/Screen/TV/index.web.tsx +40 -41
  35. package/Components/Screen/__tests__/Screen.test.tsx +3 -49
  36. package/Components/Screen/index.tsx +55 -76
  37. package/Components/Screen/navigationHandler.ts +6 -3
  38. package/Components/Screen/orientationHandler.ts +18 -7
  39. package/Components/Screen/utils.ts +16 -0
  40. package/Components/ScreenResolver/index.tsx +6 -11
  41. package/Components/Transitioner/Scene.tsx +20 -12
  42. package/Components/Transitioner/Transitioner.tsx +40 -49
  43. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  44. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  45. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  46. package/Components/VideoLive/LiveImageManager.ts +10 -0
  47. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  48. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  49. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  50. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +79 -45
  51. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +47 -33
  52. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +121 -86
  53. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
  54. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  55. package/Components/VideoModal/PlayerDetails.tsx +3 -3
  56. package/Components/VideoModal/PlayerWrapper.tsx +10 -10
  57. package/Components/VideoModal/VideoModal.tsx +4 -4
  58. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +80 -14
  59. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  60. package/Components/VideoModal/utils.ts +5 -2
  61. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
  62. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  63. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  64. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  65. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  66. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  67. package/Contexts/FocusableGroupContext/index.ts +7 -0
  68. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  69. package/Contexts/ScreenDataContext/index.tsx +20 -0
  70. package/package.json +5 -5
  71. package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
  72. package/Contexts/ScreenDataContext/index.ts +0 -3
  73. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  74. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
@@ -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,
@@ -7,6 +7,10 @@ import type {
7
7
  ContainerProps,
8
8
  ContainerChildren,
9
9
  } from "./types";
10
+ import {
11
+ useIsRTL,
12
+ applyRTLStylesIfNeeded,
13
+ } from "@applicaster/zapp-react-native-utils/localizationUtils";
10
14
 
11
15
  const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
12
16
  <View style={{ width }} />
@@ -17,6 +21,7 @@ export function ButtonContainerView({
17
21
  children,
18
22
  ...otherProps
19
23
  }: ContainerProps) {
24
+ const isRTL = useIsRTL();
20
25
  const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
21
26
 
22
27
  const filteredChildren = useFilterChildren<ContainerChildren>(children);
@@ -26,7 +31,7 @@ export function ButtonContainerView({
26
31
  }
27
32
 
28
33
  return (
29
- <View style={style}>
34
+ <View style={applyRTLStylesIfNeeded(style, isRTL)}>
30
35
  {insertBetween(
31
36
  (index) => (
32
37
  <HorizontalSeparator
@@ -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);
@@ -9,4 +9,13 @@ describe("insertBetween", () => {
9
9
 
10
10
  expect(result).toEqual([1, "|", 2, "|", 3]);
11
11
  });
12
+
13
+ it("insertBetween", () => {
14
+ const separator = (index) => `separator:${index}`;
15
+ const items = [1, 2, 3];
16
+
17
+ const result = insertBetween(separator, items);
18
+
19
+ expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
20
+ });
12
21
  });
@@ -1,5 +1,6 @@
1
1
  import React, { useEffect, useMemo } from "react";
2
2
  import * as R from "ramda";
3
+ import validateColor from "validate-color";
3
4
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
6
 
@@ -9,6 +10,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
9
10
  import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
10
11
  import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
11
12
  import { getCellState } from "../../Cell/utils";
13
+ import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
12
14
 
13
15
  const hasElementSpecificViewType = (viewType) => (element) => {
14
16
  if (R.isNil(element)) {
@@ -47,44 +49,29 @@ export const hasElementsSpecificViewType = (viewType) => (elements) => {
47
49
  return R.any(hasElementSpecificViewType(viewType))(elements);
48
50
  };
49
51
 
50
- const isColorOrEmpty = (value) =>
51
- value === null ||
52
- value === undefined ||
53
- value === "" ||
54
- value.startsWith("#") ||
55
- value.startsWith("rgba") ||
56
- value === "transparent";
57
-
58
52
  function resolveColorForProp(entry, style, colorProp) {
59
- const colorValue = style[colorProp];
60
-
61
- if (isColorOrEmpty(colorValue)) {
62
- return style;
53
+ const colorFromProp = style[colorProp];
54
+ const nestedEntryValue = R.path(colorFromProp.split("."), entry);
55
+
56
+ if (
57
+ nestedEntryValue === undefined &&
58
+ !validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
59
+ ) {
60
+ logWarning(colorFromProp, style, entry, nestedEntryValue);
63
61
  }
64
62
 
65
- const pathParts = colorValue.split(".");
66
- let nestedEntryValue = entry;
67
-
68
- for (const part of pathParts) {
69
- if (nestedEntryValue === null || typeof nestedEntryValue !== "object") {
70
- logWarning(colorValue, style, entry, nestedEntryValue);
71
-
72
- return style;
73
- }
74
-
75
- nestedEntryValue = nestedEntryValue[part];
76
- }
63
+ const colorValue = getColorFromData({
64
+ data: entry,
65
+ valueFromLayout: colorFromProp,
66
+ });
77
67
 
78
- if (nestedEntryValue === undefined) {
79
- logWarning(colorValue, style, entry, nestedEntryValue);
68
+ if (!colorValue) {
69
+ logWarning(colorProp, style, entry, colorValue);
80
70
 
81
71
  return style;
82
72
  }
83
73
 
84
- // After successful traversal, set the value.
85
- style[colorProp] = nestedEntryValue;
86
-
87
- return style;
74
+ return { ...style, [colorProp]: colorValue };
88
75
  }
89
76
 
90
77
  export function resolveColor(entry, style) {
@@ -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,6 +253,7 @@ const PlayerContainerComponent = (props: Props) => {
252
253
  }
253
254
 
254
255
  showNavBar(true);
256
+ navigator.goBack();
255
257
  }, [isModal, navigator.goBack, showNavBar]);
256
258
 
257
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,18 +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
- const isPlayerPlugin = (routeState): boolean =>
46
- getPluginType(routeState) === "player";
47
-
48
- const isLoginPlugin = (routeState): boolean =>
49
- getPluginType(routeState) === "login";
50
-
51
48
  const getActiveRiver = ({
52
49
  screenId,
53
50
  screenType,
@@ -111,7 +108,6 @@ export const Screen = ({ route, Components }: Props) => {
111
108
  const backgroundColor = useScreenBackgroundColor(screenId);
112
109
 
113
110
  useInitialFocus();
114
- useRestoreFocus();
115
111
 
116
112
  const activeRiver = getActiveRiver({
117
113
  screenId,
@@ -139,41 +135,44 @@ export const Screen = ({ route, Components }: Props) => {
139
135
  fallbackNavigations: navigator.activeRiver.navigations,
140
136
  });
141
137
 
142
- const menuPlugin = resolveNavigationPlugin({
143
- category: "menu",
144
- navigations,
145
- plugins,
146
- }) as QuickBrickPlugin;
138
+ const menuPlugin = findMenuPlugin(navigations, plugins);
147
139
 
148
140
  const NavBar = (Components.NavBar ||
149
141
  menuPlugin.module) as React.ComponentType<any>;
150
142
 
151
143
  const isPlayer = isPlayerPlugin(routeState);
152
- const isLogin = isLoginPlugin(routeState);
153
144
 
154
- const isNavBarVisible = !isPlayer && !isLogin;
145
+ const { visible: isNavBarVisible } = useNavbarState();
155
146
 
156
147
  const screenData =
157
148
  screenType === "hooks" || isPlayer
158
149
  ? routeState?.state?.entry
159
150
  : routeState?.state?.screen;
160
151
 
152
+ const isScreenActive = useIsScreenActive();
153
+
161
154
  return (
162
- <View style={[styles.container, { backgroundColor }]}>
163
- <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
164
- <NavBar
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}
165
173
  groupId={route}
166
- isVisible={isNavBarVisible}
167
- menuPlugin={menuPlugin}
168
- navigationProps={navigationProps}
169
174
  />
170
- </NavBarContainer>
171
- <ScreenResolver
172
- screenType={screenType}
173
- screenId={screenId}
174
- screenData={screenData}
175
- groupId={route}
176
- />
177
- </View>
175
+ </View>
176
+ </FreezeWithCallback>
178
177
  );
179
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
  });