@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4536343143 → 12.0.0-alpha.4584840011

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 (54) 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/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 +7 -2
  14. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  15. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +20 -0
  16. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +6 -1
  17. package/Components/MasterCell/dataAdapter.ts +21 -7
  18. package/Components/MasterCell/index.tsx +5 -3
  19. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  20. package/Components/MasterCell/utils/index.ts +17 -30
  21. package/Components/Navigator/StackNavigator.tsx +14 -5
  22. package/Components/PlayerContainer/PlayerContainer.tsx +2 -0
  23. package/Components/Screen/TV/index.web.tsx +9 -23
  24. package/Components/Screen/__tests__/Screen.test.tsx +3 -0
  25. package/Components/Screen/index.tsx +55 -58
  26. package/Components/Screen/navigationHandler.ts +5 -0
  27. package/Components/ScreenResolver/index.tsx +6 -11
  28. package/Components/Transitioner/Scene.tsx +12 -11
  29. package/Components/Transitioner/Transitioner.tsx +32 -44
  30. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +8 -4
  31. package/Components/VideoLive/LiveImageManager.ts +10 -0
  32. package/Components/VideoLive/PlayerLiveImageComponent.tsx +52 -24
  33. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +26 -24
  34. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +2 -14
  35. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +56 -43
  36. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +42 -32
  37. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +104 -86
  38. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +32 -4
  39. package/Components/VideoModal/ModalAnimation/utils.ts +7 -4
  40. package/Components/VideoModal/PlayerWrapper.tsx +2 -2
  41. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
  42. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  43. package/Components/VideoModal/utils.ts +5 -2
  44. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  45. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  46. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  47. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  48. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  49. package/Contexts/FocusableGroupContext/index.ts +7 -0
  50. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  51. package/Contexts/ScreenContext/index.tsx +0 -6
  52. package/package.json +5 -5
  53. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  54. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
@@ -4,6 +4,7 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
4
4
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
5
5
  import * as R from "ramda";
6
6
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
7
+ import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
7
8
 
8
9
  const { Logger } = getXray();
9
10
 
@@ -35,7 +36,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
35
36
 
36
37
  const focusableId = getFocusableId(prefixId, suffixId);
37
38
 
38
- const focused = focusableId === focusedButtonId;
39
+ const focused =
40
+ focusableId === focusedButtonId ||
41
+ toBooleanWithDefaultFalse(otherProps.focused);
39
42
 
40
43
  const additionalStyles = focused ? focusedStyles : normalStyles;
41
44
 
@@ -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) {
@@ -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
@@ -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,20 +1,24 @@
1
1
  import * as React from "react";
2
- import { last, pathOr } from "ramda";
2
+ import { last } from "ramda";
3
3
  import { View, StyleSheet } 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
9
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
10
10
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
11
11
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
12
- import { useScreenBackgroundColor } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
12
+ import {
13
+ useNavbarState,
14
+ useScreenBackgroundColor,
15
+ } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
13
16
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
17
 
15
18
  import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
16
19
  import { ScreenResolver } from "../../ScreenResolver";
17
20
  import { useInitialFocus, useRestoreFocus } from "./hooks";
21
+ import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
18
22
 
19
23
  const styles = StyleSheet.create({
20
24
  container: {
@@ -36,18 +40,6 @@ type Props = {
36
40
  Components: Components;
37
41
  };
38
42
 
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
43
  const getActiveRiver = ({
52
44
  screenId,
53
45
  screenType,
@@ -139,19 +131,14 @@ export const Screen = ({ route, Components }: Props) => {
139
131
  fallbackNavigations: navigator.activeRiver.navigations,
140
132
  });
141
133
 
142
- const menuPlugin = resolveNavigationPlugin({
143
- category: "menu",
144
- navigations,
145
- plugins,
146
- }) as QuickBrickPlugin;
134
+ const menuPlugin = findMenuPlugin(navigations, plugins);
147
135
 
148
136
  const NavBar = (Components.NavBar ||
149
137
  menuPlugin.module) as React.ComponentType<any>;
150
138
 
151
139
  const isPlayer = isPlayerPlugin(routeState);
152
- const isLogin = isLoginPlugin(routeState);
153
140
 
154
- const isNavBarVisible = !isPlayer && !isLogin;
141
+ const { visible: isNavBarVisible } = useNavbarState();
155
142
 
156
143
  const screenData =
157
144
  screenType === "hooks" || isPlayer
@@ -162,7 +149,6 @@ export const Screen = ({ route, Components }: Props) => {
162
149
  <View style={[styles.container, { backgroundColor }]}>
163
150
  <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
164
151
  <NavBar
165
- groupId={route}
166
152
  isVisible={isNavBarVisible}
167
153
  menuPlugin={menuPlugin}
168
154
  navigationProps={navigationProps}
@@ -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
 
@@ -54,11 +52,8 @@ export function ScreenResolverComponent(props: Props) {
54
52
 
55
53
  const [, setScreenContext] = ZappPipesScreenContext.useZappPipesContext();
56
54
 
57
- const dispatch = useDispatch();
58
-
59
55
  React.useEffect(() => {
60
56
  setScreenContext(rivers[screenId]);
61
- dispatch(setAppStateHasFinishedTransitioning());
62
57
  }, [screenId]);
63
58
 
64
59
  const ScreenPlugin =
@@ -100,14 +95,14 @@ export function ScreenResolverComponent(props: Props) {
100
95
  }
101
96
 
102
97
  const ScreenComponent =
103
- R.path(["module", "Component"], ScreenPlugin) ||
104
- R.prop("module", ScreenPlugin) ||
105
- R.prop("Component", ScreenPlugin) ||
98
+ path(["module", "Component"], ScreenPlugin) ||
99
+ prop("module", ScreenPlugin) ||
100
+ prop("Component", ScreenPlugin) ||
106
101
  ScreenPlugin;
107
102
 
108
103
  const configuration =
109
- R.prop("configuration", ScreenPlugin) ||
110
- R.prop("__plugin_configuration", ScreenComponent);
104
+ prop("configuration", ScreenPlugin) ||
105
+ prop("__plugin_configuration", ScreenComponent);
111
106
 
112
107
  if (ScreenComponent) {
113
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} />}