@applicaster/zapp-react-native-ui-components 12.0.0-rc.14 → 12.0.0-rc.141

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 (171) 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 +40 -12
  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/Focusable/__tests__/index.android.test.tsx +72 -0
  11. package/Components/Focusable/index.android.tsx +15 -9
  12. package/Components/FocusableCell/index.tsx +7 -7
  13. package/Components/FocusableGroup/index.tsx +11 -2
  14. package/Components/FocusableList/FocusableChild.ts +26 -16
  15. package/Components/FocusableList/FocusableItem.tsx +1 -1
  16. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  17. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  18. package/Components/FocusableList/index.tsx +37 -37
  19. package/Components/FocusableScrollView/index.tsx +1 -1
  20. package/Components/FreezeWithCallback/Freeze.tsx +31 -0
  21. package/Components/FreezeWithCallback/LICENSE +21 -0
  22. package/Components/FreezeWithCallback/Suspender.tsx +17 -0
  23. package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
  24. package/Components/FreezeWithCallback/index.tsx +3 -0
  25. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  26. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  27. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  28. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  29. package/Components/HookRenderer/index.tsx +1 -6
  30. package/Components/Image/Image.android.tsx +4 -26
  31. package/Components/Image/Image.tsx +18 -2
  32. package/Components/Image/utils/index.ts +39 -0
  33. package/Components/Layout/TV/ScreenContainer.tsx +79 -5
  34. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  35. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
  36. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
  37. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  38. package/Components/Layout/TV/__tests__/index.test.tsx +20 -108
  39. package/Components/Layout/TV/index.tsx +15 -84
  40. package/Components/Layout/TV/index.web.tsx +33 -0
  41. package/Components/Layout/index.tsx +15 -11
  42. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +14 -7
  43. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -117
  44. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +27 -9
  45. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  46. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +16 -1
  47. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  48. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +3 -0
  49. package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +2 -2
  50. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  51. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +71 -0
  52. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  53. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +37 -2
  54. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  55. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  56. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  57. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  58. package/Components/MasterCell/DefaultComponents/index.ts +2 -0
  59. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  60. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
  61. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  62. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
  63. package/Components/MasterCell/dataAdapter.ts +21 -7
  64. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  65. package/Components/MasterCell/index.tsx +5 -3
  66. package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
  67. package/Components/MasterCell/utils/index.ts +31 -34
  68. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  69. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  70. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  71. package/Components/ModalComponent/Button/Item.tsx +82 -0
  72. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  73. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  74. package/Components/ModalComponent/Button/assets.ts +4 -0
  75. package/Components/ModalComponent/Button/index.tsx +111 -0
  76. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  77. package/Components/ModalComponent/Header/Title.tsx +70 -0
  78. package/Components/ModalComponent/Header/assets.ts +4 -0
  79. package/Components/ModalComponent/Header/index.tsx +71 -0
  80. package/Components/ModalComponent/Header/utils.ts +79 -0
  81. package/Components/ModalComponent/index.tsx +38 -0
  82. package/Components/ModalComponent/utils.ts +126 -0
  83. package/Components/Navigator/StackNavigator.tsx +57 -0
  84. package/Components/Navigator/index.ts +1 -0
  85. package/Components/PlayerContainer/PlayerContainer.tsx +80 -39
  86. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  87. package/Components/PlayerImageBackground/index.tsx +34 -8
  88. package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
  89. package/Components/River/RefreshControl.tsx +55 -1
  90. package/Components/River/TV/River.tsx +2 -25
  91. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  92. package/Components/River/__tests__/componentsMap.test.js +7 -0
  93. package/Components/River/useScreenConfiguration.ts +2 -2
  94. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  95. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  96. package/Components/RouteManager/index.tsx +4 -2
  97. package/Components/Screen/TV/hooks/index.ts +1 -0
  98. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  99. package/Components/Screen/TV/index.web.tsx +178 -0
  100. package/Components/Screen/__tests__/Screen.test.tsx +43 -75
  101. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  102. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  103. package/Components/Screen/index.tsx +104 -65
  104. package/Components/Screen/navigationHandler.ts +6 -85
  105. package/Components/Screen/orientationHandler.ts +18 -7
  106. package/Components/Screen/utils.ts +16 -0
  107. package/Components/ScreenResolver/index.tsx +10 -13
  108. package/Components/Tabs/TV/styles.ts +1 -1
  109. package/Components/TrackedView/index.tsx +6 -3
  110. package/Components/Transitioner/Scene.tsx +39 -26
  111. package/Components/Transitioner/Transitioner.tsx +56 -48
  112. package/Components/Transitioner/__tests__/Scene.test.js +7 -0
  113. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
  114. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
  115. package/Components/VideoLive/LiveImageManager.ts +65 -11
  116. package/Components/VideoLive/PlayerLiveImageComponent.tsx +132 -95
  117. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  118. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +24 -27
  119. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +60 -0
  120. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +401 -0
  121. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +172 -0
  122. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +475 -0
  123. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
  124. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  125. package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
  126. package/Components/VideoModal/PlayerDetails.tsx +21 -4
  127. package/Components/VideoModal/PlayerWrapper.tsx +115 -55
  128. package/Components/VideoModal/VideoModal.tsx +32 -43
  129. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +6 -1
  130. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
  131. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -0
  132. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +358 -166
  133. package/Components/VideoModal/hooks/useModalSize.ts +10 -12
  134. package/Components/VideoModal/utils.ts +8 -5
  135. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  136. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  137. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  138. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  139. package/Components/Viewport/utils.js +1 -1
  140. package/Components/ZappFrameworkComponents/BarView/BarView.tsx +7 -3
  141. package/Components/ZappFrameworkComponents/BarView/Buttons/BackButton.tsx +7 -2
  142. package/Components/ZappFrameworkComponents/BarView/Buttons/CloseButton.tsx +7 -2
  143. package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +87 -0
  144. package/Components/ZappFrameworkComponents/Buttons/ActionButton.tsx +9 -4
  145. package/Components/ZappUIComponent/index.tsx +22 -12
  146. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
  147. package/Components/index.js +2 -0
  148. package/Contexts/CachedDimensionsContext/index.ts +13 -9
  149. package/Contexts/ConfirmDialogState/index.ts +1 -1
  150. package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
  151. package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
  152. package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
  153. package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
  154. package/Contexts/FocusableGroupContext/index.ts +7 -0
  155. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
  156. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  157. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  158. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  159. package/Contexts/ScreenContext/index.tsx +101 -30
  160. package/Contexts/ScreenDataContext/index.tsx +20 -0
  161. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  162. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  163. package/const.ts +6 -0
  164. package/events/index.ts +1 -0
  165. package/index.js +3 -0
  166. package/package.json +5 -5
  167. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  168. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  169. /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
  170. /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
  171. /package/Contexts/{index.js → index.ts} +0 -0
@@ -1,12 +1,12 @@
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";
4
+
5
+ import { useScreenOrientationHandler } from "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler";
6
+
9
7
  import { PathnameContext } from "../../Contexts/PathnameContext";
8
+ import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
9
+ import { ScreenContextProvider } from "../../Contexts/ScreenContext";
10
10
 
11
11
  type Props = {
12
12
  children: any;
@@ -16,6 +16,8 @@ type Props = {
16
16
  animating: boolean;
17
17
  contentStyle: ViewStyle;
18
18
  pathname: string;
19
+ isActive: boolean;
20
+ screenData: NavigationScreenData;
19
21
  };
20
22
 
21
23
  /**
@@ -38,34 +40,45 @@ export function Scene({
38
40
  animating,
39
41
  contentStyle,
40
42
  pathname,
43
+ isActive = false,
44
+ screenData,
41
45
  }: Props) {
46
+ const [initialScreenData, setInitialScreenData] = React.useState(screenData);
47
+
48
+ useScreenOrientationHandler({
49
+ screenData,
50
+ isActive,
51
+ });
52
+
53
+ React.useLayoutEffect(() => {
54
+ if (isActive) {
55
+ setInitialScreenData(screenData);
56
+ }
57
+ }, [screenData, isActive]);
58
+
42
59
  const frame = useSafeAreaFrame();
43
- const { height, width } = useWindowDimensions();
60
+ const isAnimating = animating && overlayStyle;
44
61
 
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
- }
62
+ const dimensions = isAnimating
63
+ ? {
64
+ width: "100%",
65
+ height: "100%",
66
+ }
67
+ : frame;
60
68
 
61
69
  return (
62
70
  <Animated.View
63
71
  pointerEvents={pointerEvents}
64
- style={[style, contentStyle, frame]}
72
+ style={[style, contentStyle, dimensions]}
65
73
  >
66
- <PathnameContext.Provider value={pathname}>
67
- {children}
68
- </PathnameContext.Provider>
74
+ <ScreenDataContext.Provider value={initialScreenData}>
75
+ <PathnameContext.Provider value={pathname}>
76
+ <ScreenContextProvider pathname={pathname}>
77
+ {children}
78
+ </ScreenContextProvider>
79
+ </PathnameContext.Provider>
80
+ </ScreenDataContext.Provider>
81
+ {isAnimating && <Animated.View style={overlayStyle} />}
69
82
  </Animated.View>
70
83
  );
71
84
  }
@@ -1,13 +1,10 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import * as R from "ramda";
3
+ import { update, compose, tail, append, take, identity, isNil } 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,
@@ -49,10 +46,14 @@ function prepareScene(children) {
49
46
  */
50
47
  function scenesForBackTransition(props: SceneProps, { scenes }) {
51
48
  return scenes.length > 1
52
- ? R.identity(scenes)
49
+ ? identity(scenes)
53
50
  : [prepareScene(props.children), scenes[0]];
54
51
  }
55
52
 
53
+ const isModalClosed = (navigator) => {
54
+ return !!isNil(navigator?.modalData);
55
+ };
56
+
56
57
  type Props = {
57
58
  transitionConfig: any;
58
59
  children: React.ReactNode;
@@ -113,7 +114,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
113
114
  pushTransitionStart() {
114
115
  this.setState(
115
116
  {
116
- scenes: R.append(prepareScene(this.props.children), this.state.scenes),
117
+ scenes: append(prepareScene(this.props.children), this.state.scenes),
117
118
  ...this.animationManager.stateForAction(this.state, NAV_ACTION_PUSH),
118
119
  },
119
120
  () => {
@@ -169,21 +170,23 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
169
170
 
170
171
  transitionWithoutAnimation(resetState) {
171
172
  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
- };
173
+ const newScene = prepareScene(this.props.children);
174
+ const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
175
+
176
+ let newState;
177
+
178
+ if (resetState) {
179
+ newState = {
180
+ scenes: [newScene],
181
+ to: { index: 0 },
182
+ };
183
+ } else if (isLastSceneHook || scenes.length === 1) {
184
+ newState = { scenes: update(scenes.length - 1, newScene, scenes) };
185
+ } else {
186
+ newState = {
187
+ scenes: compose(tail, append(newScene))(scenes),
188
+ };
189
+ }
187
190
 
188
191
  this.setState(newState);
189
192
  }
@@ -226,7 +229,10 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
226
229
  this.shouldSkipAnimationForRoute(previousRoute) ||
227
230
  this.shouldSkipAnimationForRoute(currentRoute)
228
231
  ) {
229
- return this.transitionWithoutAnimation();
232
+ // we are going back, in this case we need to have only one scene using resetState
233
+ const resetState = isGoingBack ? true : undefined;
234
+
235
+ return this.transitionWithoutAnimation(resetState);
230
236
  }
231
237
 
232
238
  switch (this.props.navigator.previousAction) {
@@ -269,7 +275,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
269
275
  backTransitionEnd(stepsBack) {
270
276
  this.setState({
271
277
  animating: false,
272
- scenes: R.take(this.state.scenes.length - stepsBack, this.state.scenes),
278
+ scenes: take(this.state.scenes.length - stepsBack, this.state.scenes),
273
279
  });
274
280
  }
275
281
 
@@ -277,33 +283,25 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
277
283
  // so only a single scene should be rendered,
278
284
  // instead of dangerous nulls or duplicates.
279
285
  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
- });
286
+ const { contentStyle } = this.props;
287
+ const screenData = this.props.children.props.screenData;
288
+ const pathname = scenes[to.index].key;
287
289
 
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
290
  return (
291
291
  <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
- )}
292
+ {scenes[to.index] && (
293
+ <Scene
294
+ {...{ style: to?.style || {} }}
295
+ pathname={pathname}
296
+ isActive={pathname === this.props.navigator.currentRoute}
297
+ contentStyle={contentStyle}
298
+ key={scenes[to.index].key}
299
+ screenUniqueId={scenes[to.index].screenUniqueId}
300
+ screenData={screenData}
301
+ >
302
+ {scenes[to.index].children}
303
+ </Scene>
304
+ )}
307
305
  </View>
308
306
  );
309
307
  }
@@ -319,12 +317,17 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
319
317
  <Scene
320
318
  key={scenes[from.index].key}
321
319
  pathname={scenes[from.index].key}
320
+ isActive={
321
+ scenes[from.index].key === this.props.navigator.currentRoute &&
322
+ isModalClosed(this.props.navigator)
323
+ }
322
324
  style={from.style}
323
325
  pointerEvents="none"
324
326
  overlayStyle={from.overlayStyle}
325
327
  animating={this.state.animating}
326
328
  contentStyle={contentStyle}
327
329
  screenUniqueId={scenes[from.index].screenUniqueId}
330
+ screenData={scenes[from.index].children.props.screenData}
328
331
  >
329
332
  {scenes[from.index].children}
330
333
  </Scene>
@@ -333,12 +336,17 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
333
336
  const toScene = scenes[to.index] && (
334
337
  <Scene
335
338
  pathname={scenes[to.index].key}
339
+ isActive={
340
+ scenes[to.index].key === this.props.navigator.currentRoute &&
341
+ isModalClosed(this.props.navigator)
342
+ }
336
343
  key={scenes[to.index].key}
337
344
  style={to.style}
338
345
  overlayStyle={to.overlayStyle}
339
346
  animating={this.state.animating}
340
347
  contentStyle={contentStyle}
341
348
  screenUniqueId={scenes[to.index].screenUniqueId}
349
+ screenData={this.props.children.props.screenData}
342
350
  >
343
351
  {scenes[to.index].children}
344
352
  </Scene>
@@ -16,6 +16,13 @@ jest.mock("react-native-safe-area-context", () => ({
16
16
  })),
17
17
  }));
18
18
 
19
+ jest.mock(
20
+ "@applicaster/zapp-react-native-ui-components/Components/Screen/orientationHandler",
21
+ () => ({
22
+ useScreenOrientationHandler: jest.fn(),
23
+ })
24
+ );
25
+
19
26
  const { Scene } = require("../Scene");
20
27
 
21
28
  const wrapper = shallow(
@@ -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,7 +10,9 @@ exports[`<TransitionerComponent /> renders correctly 1`] = `
10
10
  }
11
11
  >
12
12
  <Scene
13
+ isActive={true}
13
14
  screenUniqueId="mocked-uuid"
15
+ style={Object {}}
14
16
  >
15
17
  <View
16
18
  foo="bar"
@@ -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,17 +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
411
  const currentItem = this.currentlyPlaying;
383
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
+
384
421
  if (currentItem === item) {
385
422
  this.currentlyPlaying = null;
423
+
424
+ log_debug(
425
+ `onLiveImageError: currentitem: ${currentItem.playerId} was removed`
426
+ );
427
+
386
428
  // TODO: ...Maybe player some other item
387
429
  }
388
430
 
@@ -393,6 +435,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
393
435
  error,
394
436
  playerId: currentItem?.playerId,
395
437
  primaryPlayerId: currentItem?.playerId,
438
+ entry: item.getPlayer().getEntry(),
396
439
  },
397
440
  });
398
441
  };
@@ -448,12 +491,13 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
448
491
  };
449
492
 
450
493
  readonly playerId: string;
494
+ readonly component: Component;
451
495
 
452
496
  constructor(props: LiveImageProps) {
453
497
  this.player = props.player;
454
498
  this.setMode = props.setMode;
455
499
  this.playerId = this.player.playerId;
456
-
500
+ this.component = props.component;
457
501
  this.player.addListener({ id: "live-image", listener: this });
458
502
  }
459
503
 
@@ -481,6 +525,16 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
481
525
  LiveImageManager.instance.onLiveImageError(this, error);
482
526
  };
483
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
+
484
538
  onVideoEnd = (_event) => {
485
539
  log_info(
486
540
  `onVideoEnd: live-image, video completed, switching back to image, ${playerInfo(