@applicaster/zapp-react-native-ui-components 12.0.0-rc.11 → 12.0.0-rc.111

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 (153) hide show
  1. package/Components/AudioPlayer/AudioPlayer.tsx +9 -1
  2. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
  3. package/Components/AudioPlayer/helpers.tsx +1 -0
  4. package/Components/BaseFocusable/index.tsx +3 -3
  5. package/Components/Cell/Cell.tsx +32 -11
  6. package/Components/Cell/CellWithFocusable.tsx +40 -19
  7. package/Components/Cell/TvOSCellComponent.tsx +5 -9
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/Focusable/Focusable.tsx +6 -1
  10. package/Components/FocusableCell/index.tsx +7 -7
  11. package/Components/FocusableGroup/index.tsx +11 -2
  12. package/Components/FocusableList/FocusableChild.ts +24 -14
  13. package/Components/FocusableList/FocusableItem.tsx +1 -1
  14. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  15. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  16. package/Components/FocusableList/index.tsx +26 -25
  17. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  18. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  19. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  20. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  21. package/Components/HookRenderer/index.tsx +1 -6
  22. package/Components/Image/Image.android.tsx +3 -26
  23. package/Components/Image/Image.tsx +18 -2
  24. package/Components/Image/utils/index.ts +39 -0
  25. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  26. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  27. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  28. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  29. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  30. package/Components/Layout/TV/__tests__/index.test.tsx +20 -108
  31. package/Components/Layout/TV/index.tsx +15 -84
  32. package/Components/Layout/TV/index.web.tsx +33 -0
  33. package/Components/Layout/index.tsx +15 -11
  34. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
  35. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -117
  36. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  37. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  38. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
  39. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  40. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  41. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  42. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +57 -0
  43. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  44. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +37 -2
  45. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  46. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  47. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  48. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  49. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  50. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  51. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  52. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  53. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  54. package/Components/MasterCell/dataAdapter.ts +21 -7
  55. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  56. package/Components/MasterCell/index.tsx +5 -3
  57. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  58. package/Components/MasterCell/utils/index.ts +33 -35
  59. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  60. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  61. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  62. package/Components/ModalComponent/Button/Item.tsx +82 -0
  63. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  64. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  65. package/Components/ModalComponent/Button/assets.ts +4 -0
  66. package/Components/ModalComponent/Button/index.tsx +111 -0
  67. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  68. package/Components/ModalComponent/Header/Title.tsx +70 -0
  69. package/Components/ModalComponent/Header/assets.ts +4 -0
  70. package/Components/ModalComponent/Header/index.tsx +71 -0
  71. package/Components/ModalComponent/Header/utils.ts +79 -0
  72. package/Components/ModalComponent/index.tsx +38 -0
  73. package/Components/ModalComponent/utils.ts +126 -0
  74. package/Components/Navigator/StackNavigator.tsx +57 -0
  75. package/Components/Navigator/index.ts +1 -0
  76. package/Components/PlayerContainer/PlayerContainer.tsx +66 -31
  77. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  78. package/Components/PlayerImageBackground/index.tsx +34 -8
  79. package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
  80. package/Components/River/RefreshControl.tsx +55 -1
  81. package/Components/River/River.tsx +8 -5
  82. package/Components/River/TV/River.tsx +2 -25
  83. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  84. package/Components/River/__tests__/componentsMap.test.js +7 -0
  85. package/Components/River/useScreenConfiguration.ts +2 -2
  86. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  87. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  88. package/Components/RouteManager/index.tsx +4 -2
  89. package/Components/Screen/TV/hooks/index.ts +3 -0
  90. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  91. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  92. package/Components/Screen/TV/index.web.tsx +165 -0
  93. package/Components/Screen/__tests__/Screen.test.tsx +91 -74
  94. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  95. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  96. package/Components/Screen/index.tsx +110 -54
  97. package/Components/Screen/navigationHandler.ts +5 -82
  98. package/Components/ScreenResolver/index.tsx +10 -13
  99. package/Components/Tabs/TV/styles.ts +1 -1
  100. package/Components/TrackedView/index.tsx +6 -3
  101. package/Components/Transitioner/Scene.tsx +32 -26
  102. package/Components/Transitioner/Transitioner.tsx +38 -43
  103. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  104. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  105. package/Components/VideoLive/LiveImageManager.ts +70 -14
  106. package/Components/VideoLive/PlayerLiveImageComponent.tsx +132 -95
  107. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  108. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +21 -29
  109. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +66 -0
  110. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +360 -0
  111. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
  112. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +456 -0
  113. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
  114. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  115. package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
  116. package/Components/VideoModal/PlayerDetails.tsx +6 -3
  117. package/Components/VideoModal/PlayerWrapper.tsx +81 -49
  118. package/Components/VideoModal/VideoModal.tsx +23 -40
  119. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  120. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
  121. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +312 -166
  122. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  123. package/Components/VideoModal/utils.ts +8 -5
  124. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  125. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  126. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  127. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  128. package/Components/Viewport/utils.js +1 -1
  129. package/Components/ZappUIComponent/index.tsx +22 -12
  130. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  131. package/Components/index.js +2 -0
  132. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  133. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  134. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  135. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  136. package/Contexts/FocusableGroupContext/index.ts +7 -0
  137. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  138. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  139. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  140. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  141. package/Contexts/ScreenContext/index.tsx +95 -29
  142. package/Contexts/ScreenDataContext/index.tsx +20 -0
  143. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  144. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  145. package/Decorators/RiverResolver/index.tsx +0 -4
  146. package/Decorators/index.tsx +0 -4
  147. package/events/index.ts +1 -0
  148. package/package.json +5 -6
  149. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  150. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  151. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  152. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  153. /package/Contexts/{index.js → index.ts} +0 -0
@@ -1,85 +1,3 @@
1
- import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
2
-
3
- /**
4
- * This function helps to decide wether the navbar should be presented on the screen
5
- * based on route and / or screen Data
6
- *
7
- * Currently the scenarios include
8
- * - players => false
9
- * - search screen plugin => false
10
- * - hooks with `showNavBar: true` or `presentFullScreen` not set to true, defaults to no navbar for hook screens
11
- * - screens with `allow_screen_plugin_presentation` in general property => false
12
- *
13
- * @param {String} route current route of the screen
14
- * @param {Object} screenData payload associated with the currently presented screen
15
- * @returns {Boolean}
16
- */
17
- export function isNavBarVisible(
18
- route,
19
- screenData,
20
- showNavBar,
21
- canGoBack,
22
- videoModalState: QuickBrickVideoModalState | null = null
23
- ) {
24
- /* screenData is not actual navigator.data
25
- * or navigator.screenData,
26
- * but navigator.data.screen */
27
- if (route.includes("playable")) {
28
- return false;
29
- }
30
-
31
- if (
32
- videoModalState?.mode === "FULLSCREEN" &&
33
- videoModalState?.visible === true
34
- ) {
35
- return false;
36
- }
37
-
38
- if (screenData?.type === "qb_search_screen" && !isTV()) {
39
- return false;
40
- }
41
-
42
- /* Match if screen is Hook */
43
- if (route.startsWith("/hooks/")) {
44
- const module = screenData?.module;
45
-
46
- if (module?.presentFullScreen) {
47
- return false;
48
- }
49
-
50
- return module?.showNavBar ?? false;
51
- }
52
-
53
- if (screenData?.hookPlugin) {
54
- const hookPlugin = screenData?.hookPlugin?.module;
55
-
56
- return (
57
- hookPlugin?.showNavBar || hookPlugin?.presentFullScreen !== true || false
58
- );
59
- }
60
-
61
- if (
62
- screenData?.general?.allow_screen_plugin_presentation ||
63
- screenData?.general?.hide_app_nav_bar
64
- ) {
65
- return false;
66
- }
67
-
68
- const hideSecondaryLevel = screenData?.navigations?.some(
69
- (navigation) => navigation.styles?.hide_secondary_level_menu
70
- );
71
-
72
- if (canGoBack && hideSecondaryLevel) {
73
- return false;
74
- }
75
-
76
- if (typeof showNavBar === "boolean" && !showNavBar) {
77
- return false;
78
- }
79
-
80
- return true;
81
- }
82
-
83
1
  /**
84
2
  * This function helps to decide wether the menu should be presented on the screen
85
3
  * based on route and / or screen Data
@@ -87,6 +5,11 @@ export function isNavBarVisible(
87
5
  * is similar to the navbar, except that it covers scenarios where only the navbar (and not)
88
6
  * the menu, will be hidden
89
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
+ *
90
13
  * @param {String} route current route of the screen
91
14
  * @param {Object} screenData payload associated with the currently presented screen
92
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
  }
@@ -91,21 +88,21 @@ export function ScreenResolverComponent(props: Props) {
91
88
  <HookRenderer
92
89
  screenData={screenData}
93
90
  focused={props.focused}
94
- parentFocus={props.parentFocus}
91
+ parentFocus={props.parentFocus as ParentFocus}
95
92
  />
96
93
  )
97
94
  );
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 (
@@ -78,7 +78,7 @@ export const getStyles = (config): Partial<TVTabsStyles> => {
78
78
  },
79
79
  tvos: {
80
80
  marginTop: -1,
81
- }
81
+ },
82
82
  }),
83
83
  },
84
84
  tabsBackground: {
@@ -17,9 +17,12 @@ type TrackedViewProps = {
17
17
  export const TrackedView = memo(function TrackedView(props: TrackedViewProps) {
18
18
  const children = props.children;
19
19
 
20
- const onPositionUpdated = useCallback((event: TrackedViewNativeProps) => {
21
- props?.onPositionUpdated(event.nativeEvent);
22
- }, []);
20
+ const onPositionUpdated = useCallback(
21
+ (event: TrackedViewNativeProps) => {
22
+ props.onPositionUpdated(event.nativeEvent);
23
+ },
24
+ [props.onPositionUpdated]
25
+ );
23
26
 
24
27
  if (isTV()) {
25
28
  return <View {...(props as any)}>{children}</View>;
@@ -1,12 +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";
5
+ import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
6
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
10
7
 
11
8
  type Props = {
12
9
  children: any;
@@ -16,6 +13,8 @@ type Props = {
16
13
  animating: boolean;
17
14
  contentStyle: ViewStyle;
18
15
  pathname: string;
16
+ isActive: boolean;
17
+ screenData: NavigationScreenData;
19
18
  };
20
19
 
21
20
  /**
@@ -38,34 +37,41 @@ export function Scene({
38
37
  animating,
39
38
  contentStyle,
40
39
  pathname,
40
+ isActive = false,
41
+ screenData,
41
42
  }: Props) {
43
+ const [initialScreenData, setInitialScreenData] = React.useState(screenData);
44
+
45
+ React.useLayoutEffect(() => {
46
+ if (isActive) {
47
+ setInitialScreenData(screenData);
48
+ }
49
+ }, [screenData, isActive]);
50
+
42
51
  const frame = useSafeAreaFrame();
43
- const { height, width } = useWindowDimensions();
44
52
 
45
- if (overlayStyle && animating) {
46
- // Safe frame takes too long to update,
47
- // so we can not rely on it there, and use height and width instead.
48
- return (
49
- <Animated.View
50
- pointerEvents={pointerEvents}
51
- style={[style, contentStyle, { height, width }]}
52
- >
53
- <PathnameContext.Provider value={pathname}>
54
- {children}
55
- </PathnameContext.Provider>
56
- <Animated.View style={overlayStyle} />
57
- </Animated.View>
58
- );
59
- }
53
+ const isAnimating = animating && overlayStyle;
54
+
55
+ const dimensions = isAnimating
56
+ ? {
57
+ height: "100%",
58
+ width: "100%",
59
+ }
60
+ : frame;
60
61
 
61
62
  return (
62
63
  <Animated.View
63
64
  pointerEvents={pointerEvents}
64
- style={[style, contentStyle, frame]}
65
+ style={[style, contentStyle, dimensions]}
65
66
  >
66
- <PathnameContext.Provider value={pathname}>
67
- {children}
68
- </PathnameContext.Provider>
67
+ <ScreenDataContext.Provider value={initialScreenData}>
68
+ <PathnameContext.Provider value={pathname}>
69
+ <ScreenContextProvider pathname={pathname}>
70
+ {children}
71
+ </ScreenContextProvider>
72
+ </PathnameContext.Provider>
73
+ </ScreenDataContext.Provider>
74
+ {isAnimating && <Animated.View style={overlayStyle} />}
69
75
  </Animated.View>
70
76
  );
71
77
  }
@@ -4,10 +4,7 @@ import * as R from "ramda";
4
4
 
5
5
  import { AnimationManager } from "./AnimationManager";
6
6
  import { Scene } from "./Scene";
7
- import {
8
- getScreenOrientation,
9
- isOrientationCompatible,
10
- } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
7
+
11
8
  import {
12
9
  getSceneByRoute,
13
10
  shouldSkipAnimationForPreviousWebViewScene,
@@ -169,21 +166,23 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
169
166
 
170
167
  transitionWithoutAnimation(resetState) {
171
168
  const { scenes } = this.state;
172
-
173
- const newState = resetState
174
- ? {
175
- scenes: [prepareScene(this.props.children)],
176
- to: {
177
- index: 0,
178
- },
179
- }
180
- : {
181
- scenes: R.update(
182
- scenes.length - 1,
183
- prepareScene(this.props.children),
184
- scenes
185
- ),
186
- };
169
+ const newScene = prepareScene(this.props.children);
170
+ const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
171
+
172
+ let newState;
173
+
174
+ if (resetState) {
175
+ newState = {
176
+ scenes: [newScene],
177
+ to: { index: 0 },
178
+ };
179
+ } else if (isLastSceneHook || scenes.length === 1) {
180
+ newState = { scenes: R.update(scenes.length - 1, newScene, scenes) };
181
+ } else {
182
+ newState = {
183
+ scenes: R.compose(R.tail, R.append(newScene))(scenes),
184
+ };
185
+ }
187
186
 
188
187
  this.setState(newState);
189
188
  }
@@ -277,33 +276,25 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
277
276
  // so only a single scene should be rendered,
278
277
  // instead of dangerous nulls or duplicates.
279
278
  renderSingleScene({ scenes, to }) {
280
- const { contentStyle, layoutData } = this.props;
281
- const screenData = scenes[to.index]?.children?.props?.screenData;
282
-
283
- const orientation = getScreenOrientation({
284
- screenData,
285
- layoutData,
286
- });
279
+ const { contentStyle } = this.props;
280
+ const screenData = this.props.children.props.screenData;
281
+ const pathname = scenes[to.index].key;
287
282
 
288
- // We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
289
- // This saves unnecessary re-renders and user will not see distorted aspect screen.
290
283
  return (
291
284
  <View style={styles.container}>
292
- {scenes[to.index] &&
293
- isOrientationCompatible({
294
- orientation,
295
- layoutData,
296
- }) && (
297
- <Scene
298
- {...{ style: to.style }}
299
- pathname={scenes[to.index].key}
300
- contentStyle={contentStyle}
301
- key={scenes[to.index].key}
302
- screenUniqueId={scenes[to.index].screenUniqueId}
303
- >
304
- {scenes[to.index].children}
305
- </Scene>
306
- )}
285
+ {scenes[to.index] && (
286
+ <Scene
287
+ {...{ style: to.style }}
288
+ pathname={pathname}
289
+ isActive={pathname === this.props.navigator.currentRoute}
290
+ contentStyle={contentStyle}
291
+ key={scenes[to.index].key}
292
+ screenUniqueId={scenes[to.index].screenUniqueId}
293
+ screenData={screenData}
294
+ >
295
+ {scenes[to.index].children}
296
+ </Scene>
297
+ )}
307
298
  </View>
308
299
  );
309
300
  }
@@ -319,12 +310,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
319
310
  <Scene
320
311
  key={scenes[from.index].key}
321
312
  pathname={scenes[from.index].key}
313
+ isActive={scenes[from.index].key === this.props.navigator.currentRoute}
322
314
  style={from.style}
323
315
  pointerEvents="none"
324
316
  overlayStyle={from.overlayStyle}
325
317
  animating={this.state.animating}
326
318
  contentStyle={contentStyle}
327
319
  screenUniqueId={scenes[from.index].screenUniqueId}
320
+ screenData={scenes[from.index].children.props.screenData}
328
321
  >
329
322
  {scenes[from.index].children}
330
323
  </Scene>
@@ -333,12 +326,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
333
326
  const toScene = scenes[to.index] && (
334
327
  <Scene
335
328
  pathname={scenes[to.index].key}
329
+ isActive={scenes[to.index].key === this.props.navigator.currentRoute}
336
330
  key={scenes[to.index].key}
337
331
  style={to.style}
338
332
  overlayStyle={to.overlayStyle}
339
333
  animating={this.state.animating}
340
334
  contentStyle={contentStyle}
341
335
  screenUniqueId={scenes[to.index].screenUniqueId}
336
+ screenData={this.props.children.props.screenData}
342
337
  >
343
338
  {scenes[to.index].children}
344
339
  </Scene>
@@ -21,7 +21,11 @@ exports[`<Scene /> renders correctly 1`] = `
21
21
  ]
22
22
  }
23
23
  >
24
- <ContextProvider />
24
+ <ContextProvider>
25
+ <ContextProvider>
26
+ <ScreenContextProvider />
27
+ </ContextProvider>
28
+ </ContextProvider>
25
29
  </ForwardRef(AnimatedComponentWrapper)>
26
30
  `;
27
31
 
@@ -37,13 +41,17 @@ exports[`<Scene /> renders the overlay while animating 1`] = `
37
41
  "paddingBottom": 49,
38
42
  },
39
43
  Object {
40
- "height": 1334,
41
- "width": 750,
44
+ "height": "100%",
45
+ "width": "100%",
42
46
  },
43
47
  ]
44
48
  }
45
49
  >
46
- <ContextProvider />
50
+ <ContextProvider>
51
+ <ContextProvider>
52
+ <ScreenContextProvider />
53
+ </ContextProvider>
54
+ </ContextProvider>
47
55
  <ForwardRef(AnimatedComponentWrapper)
48
56
  style={
49
57
  Object {
@@ -10,6 +10,7 @@ exports[`<TransitionerComponent /> renders correctly 1`] = `
10
10
  }
11
11
  >
12
12
  <Scene
13
+ isActive={true}
13
14
  screenUniqueId="mocked-uuid"
14
15
  >
15
16
  <View
@@ -6,10 +6,15 @@ import {
6
6
  import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
7
7
  import { loggerLiveImageManager } from "./loggerHelper";
8
8
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
9
+ import { Component } from "react";
9
10
 
10
11
  const { log_debug, log_info, log_error } = loggerLiveImageManager;
11
12
 
12
- export type LiveImageManagerEvent = "onEnd" | "onStart" | "onError";
13
+ export type LiveImageManagerEvent =
14
+ | "onEnd"
15
+ | "onStart"
16
+ | "onError"
17
+ | "onDestroy";
13
18
 
14
19
  export type LiveImageManagerListenerData = {
15
20
  id: string;
@@ -36,7 +41,8 @@ type Position = {
36
41
  type LiveImageProps = {
37
42
  player: Player;
38
43
  playerId: string;
39
- setMode: (type: LiveImageType) => void;
44
+ setMode?: (type: LiveImageType) => void;
45
+ component: Component;
40
46
  // TODO: ...primary, powerCell, tvGallery, etc.
41
47
  // type: string;
42
48
  };
@@ -100,6 +106,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
100
106
  }
101
107
 
102
108
  this.items = this.items.filter((i) => i !== item);
109
+
110
+ this.invokeListenersUpdate({
111
+ callbackName: "onDestroy",
112
+ event: {
113
+ item,
114
+ playerId: this.currentlyPlaying?.playerId,
115
+ primaryPlayerId: this.primaryPlayer?.playerId,
116
+ entry: item.getPlayer().getEntry(),
117
+ },
118
+ });
103
119
  };
104
120
 
105
121
  public onViewportEnter = (item: LiveImage) => {
@@ -164,7 +180,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
164
180
 
165
181
  // Fake close event, because we unmount native view
166
182
  item.player?.onPlayerClose();
167
- item.setMode(LiveImageType.Image);
183
+ item.setMode?.(LiveImageType.Image);
168
184
 
169
185
  if (item === this.currentlyPlaying) {
170
186
  this.currentlyPlaying = null;
@@ -191,8 +207,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
191
207
  }
192
208
 
193
209
  this.currentlyPlaying = item;
194
-
195
- item.setMode(LiveImageType.Video);
210
+ item.setMode?.(LiveImageType.Video);
196
211
 
197
212
  if (item.player.playerState.isReadyToPlay) {
198
213
  item.player.play();
@@ -209,6 +224,11 @@ export class LiveImageManager implements PlayerLifecycleListener {
209
224
  this.pauseItem(item);
210
225
  };
211
226
 
227
+ public onLiveImageCompleted = (_item: LiveImage) => {
228
+ // TODO: Notify listeners that player has died
229
+ // Do not try look for new playable, otherwise you will restart video finish to play
230
+ };
231
+
212
232
  public muteAll = () => {
213
233
  log_debug("muteAll");
214
234
 
@@ -235,6 +255,14 @@ export class LiveImageManager implements PlayerLifecycleListener {
235
255
  const playerItem = this.findNextPlayableItem();
236
256
 
237
257
  if (playerItem) {
258
+ if (!playerItem.isFullyVisible) {
259
+ log_error(
260
+ `checkPlayerPosition: trying to start playback currently invisible item: ${playerInfo(
261
+ playerItem.player
262
+ )}`
263
+ );
264
+ }
265
+
238
266
  // Will also check if it's item that already playing
239
267
  this.playLiveImage(playerItem);
240
268
  }
@@ -242,7 +270,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
242
270
 
243
271
  onPrimaryPlayerClosed = () => {
244
272
  const playerItem = this.findNextPlayableItem();
245
-
246
273
  log_info("onPrimaryPlayerClosed: starting to play visible live-image");
247
274
 
248
275
  this.currentlyPlaying = null;
@@ -338,6 +365,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
338
365
  item,
339
366
  playerId: this.currentlyPlaying?.playerId,
340
367
  primaryPlayerId: this.primaryPlayer?.playerId,
368
+ entry: item.getPlayer().getEntry(),
341
369
  },
342
370
  });
343
371
  };
@@ -356,12 +384,12 @@ export class LiveImageManager implements PlayerLifecycleListener {
356
384
  // TODO: This branch was used when we had play button to toggle replay.
357
385
  // Now we mute button instead but we keep it just in case.
358
386
  if (IS_ALLOWED_REPLAY && !isTV() && isCurrentItemEnded) {
359
- this.currentlyPlaying.player.seekTo(0);
360
- this.currentlyPlaying.player.pause();
387
+ this.currentlyPlaying?.player.seekTo(0);
388
+ this.currentlyPlaying?.player.pause();
361
389
 
362
390
  // TODO: ...Maybe player some other item
363
391
  } else {
364
- item.setMode(LiveImageType.Image);
392
+ item.setMode?.(LiveImageType.Image);
365
393
  }
366
394
 
367
395
  // Prevent receiving onEnd event from both `close` and `end` player events
@@ -372,15 +400,31 @@ export class LiveImageManager implements PlayerLifecycleListener {
372
400
  item,
373
401
  playerId: this.currentlyPlaying?.playerId,
374
402
  primaryPlayerId: this.primaryPlayer?.playerId,
403
+ entry: item.getPlayer().getEntry(),
375
404
  },
376
405
  });
377
406
  };
378
407
 
379
408
  onLiveImageError = (item: LiveImage, error: Error) => {
380
- item.setMode(LiveImageType.Image);
409
+ item.setMode?.(LiveImageType.Image);
381
410
 
382
- if (this.currentlyPlaying === item) {
411
+ const currentItem = this.currentlyPlaying;
412
+
413
+ log_debug(
414
+ `onLiveImageError: error: ${error.message}, live-image ${playerInfo(
415
+ item.player
416
+ )}, currentPlayingId: ${
417
+ this.currentlyPlaying?.playerId
418
+ }, primaryPlayerId: ${this.primaryPlayer?.playerId}`
419
+ );
420
+
421
+ if (currentItem === item) {
383
422
  this.currentlyPlaying = null;
423
+
424
+ log_debug(
425
+ `onLiveImageError: currentitem: ${currentItem.playerId} was removed`
426
+ );
427
+
384
428
  // TODO: ...Maybe player some other item
385
429
  }
386
430
 
@@ -389,8 +433,9 @@ export class LiveImageManager implements PlayerLifecycleListener {
389
433
  event: {
390
434
  item,
391
435
  error,
392
- playerId: this.currentlyPlaying?.playerId,
393
- primaryPlayerId: this.primaryPlayer?.playerId,
436
+ playerId: currentItem?.playerId,
437
+ primaryPlayerId: currentItem?.playerId,
438
+ entry: item.getPlayer().getEntry(),
394
439
  },
395
440
  });
396
441
  };
@@ -446,12 +491,13 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
446
491
  };
447
492
 
448
493
  readonly playerId: string;
494
+ readonly component: Component;
449
495
 
450
496
  constructor(props: LiveImageProps) {
451
497
  this.player = props.player;
452
498
  this.setMode = props.setMode;
453
499
  this.playerId = this.player.playerId;
454
-
500
+ this.component = props.component;
455
501
  this.player.addListener({ id: "live-image", listener: this });
456
502
  }
457
503
 
@@ -479,6 +525,16 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
479
525
  LiveImageManager.instance.onLiveImageError(this, error);
480
526
  };
481
527
 
528
+ onVideoError = (error: Error) => {
529
+ log_error(
530
+ `onVideoError: live-image, fail to play, switching back to image. error: ${
531
+ error?.message
532
+ }, ${playerInfo(this.player)}`
533
+ );
534
+
535
+ LiveImageManager.instance.onLiveImageError(this, error);
536
+ };
537
+
482
538
  onVideoEnd = (_event) => {
483
539
  log_info(
484
540
  `onVideoEnd: live-image, video completed, switching back to image, ${playerInfo(