@applicaster/zapp-react-native-ui-components 13.0.0-alpha.9946926334 → 13.0.0-rc.100

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 (172) hide show
  1. package/Components/AppContainer/__tests__/AppContainer.test.js +4 -6
  2. package/Components/AudioPlayer/AudioPlayer.tsx +7 -0
  3. package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
  4. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +54 -111
  5. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +36 -20
  6. package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
  7. package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
  8. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
  9. package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
  10. package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
  11. package/Components/AudioPlayer/__tests__/title.test.js +3 -5
  12. package/Components/AudioPlayer/helpers.tsx +1 -0
  13. package/Components/BaseFocusable/index.ios.ts +1 -1
  14. package/Components/BaseFocusable/index.tsx +2 -3
  15. package/Components/Cell/Cell.tsx +11 -16
  16. package/Components/Cell/CellWithFocusable.tsx +50 -59
  17. package/Components/Cell/CellWrapper.tsx +18 -0
  18. package/Components/Cell/TvOSCellComponent.tsx +20 -26
  19. package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
  20. package/Components/Cell/index.js +3 -1
  21. package/Components/Cell/styles.ts +17 -0
  22. package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +46 -48
  23. package/Components/CellRendererResolver/index.ts +2 -1
  24. package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
  25. package/Components/ComponentResolver/__tests__/componentResolver.test.js +16 -22
  26. package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
  27. package/Components/ErrorScreen/index.tsx +14 -6
  28. package/Components/Focusable/Focusable.tsx +1 -0
  29. package/Components/Focusable/FocusableTvOS.tsx +6 -2
  30. package/Components/Focusable/Touchable.tsx +19 -20
  31. package/Components/Focusable/index.android.tsx +10 -3
  32. package/Components/FocusableCell/index.tsx +1 -1
  33. package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
  34. package/Components/FocusableGroup/index.tsx +0 -3
  35. package/Components/FocusableList/index.tsx +26 -10
  36. package/Components/FocusableScrollView/index.tsx +43 -13
  37. package/Components/HandlePlayable/HandlePlayable.tsx +21 -27
  38. package/Components/Layout/TV/LayoutBackground.tsx +28 -0
  39. package/Components/Layout/TV/NavBarContainer.tsx +19 -23
  40. package/Components/Layout/TV/ScreenContainer.tsx +8 -2
  41. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
  42. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +2 -1
  43. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +3 -2
  44. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +3 -2
  45. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
  46. package/Components/Layout/TV/__tests__/index.test.tsx +8 -2
  47. package/Components/Layout/TV/index.tsx +6 -20
  48. package/Components/Layout/TV/index.web.tsx +4 -1
  49. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
  50. package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +66 -0
  51. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +4 -1
  52. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +10 -15
  53. package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
  54. package/Components/MasterCell/DefaultComponents/ImageBorderContainer/__tests__/index.test.ts +93 -0
  55. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
  56. package/Components/MasterCell/DefaultComponents/SecondaryImage/utils.ts +1 -1
  57. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  58. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
  59. package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
  60. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
  61. package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +4 -12
  62. package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +0 -229
  63. package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
  64. package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
  65. package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
  66. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +2 -2
  67. package/Components/MasterCell/utils/behaviorProvider.ts +136 -0
  68. package/Components/MasterCell/utils/index.ts +9 -135
  69. package/Components/ModalComponent/BottomSheetModalContent.tsx +45 -19
  70. package/Components/ModalComponent/Button/Item.tsx +6 -5
  71. package/Components/ModalComponent/Button/assets.ts +1 -1
  72. package/Components/ModalComponent/Button/index.tsx +30 -43
  73. package/Components/ModalComponent/Header/index.tsx +3 -3
  74. package/Components/ModalComponent/utils.ts +55 -7
  75. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
  76. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
  77. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
  78. package/Components/OfflineHandler/utils/index.ts +1 -1
  79. package/Components/PlayerContainer/PlayerContainer.tsx +43 -21
  80. package/Components/PlayerContainer/PlayerContainerContext.tsx +9 -0
  81. package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
  82. package/Components/PlayerImageBackground/index.tsx +1 -1
  83. package/Components/River/ComponentsMap/ComponentsMap.tsx +42 -65
  84. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
  85. package/Components/River/RiverFooter.tsx +39 -9
  86. package/Components/River/RiverItem.tsx +39 -3
  87. package/Components/River/TV/index.tsx +6 -1
  88. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +100 -31
  89. package/Components/River/__tests__/__snapshots__/river.test.js.snap +20 -82
  90. package/Components/River/__tests__/componentsMap.test.js +17 -5
  91. package/Components/River/__tests__/river.test.js +75 -40
  92. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +11 -4
  93. package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
  94. package/Components/RouteManager/__tests__/testId.test.js +8 -6
  95. package/Components/Screen/TV/index.web.tsx +5 -6
  96. package/Components/Screen/hooks.ts +53 -0
  97. package/Components/Screen/index.tsx +16 -42
  98. package/Components/ScreenResolver/__tests__/screenResolver.test.js +91 -70
  99. package/Components/Tabs/Tab.tsx +11 -9
  100. package/Components/TextInputTv/index.tsx +4 -3
  101. package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
  102. package/Components/TrackedView/index.tsx +1 -0
  103. package/Components/Transitioner/AnimationManager.js +15 -15
  104. package/Components/Transitioner/Scene.tsx +53 -24
  105. package/Components/Transitioner/Transitioner.tsx +3 -3
  106. package/Components/Transitioner/__tests__/Scene.test.js +25 -14
  107. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +9 -49
  108. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
  109. package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
  110. package/Components/Transitioner/index.js +8 -4
  111. package/Components/VideoLive/LiveImageManager.ts +27 -1
  112. package/Components/VideoLive/PlayerLiveImageComponent.tsx +36 -24
  113. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +51 -1
  114. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -5
  115. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
  116. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +51 -31
  117. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +8 -4
  118. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +48 -22
  119. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +12 -6
  120. package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
  121. package/Components/VideoModal/ModalAnimation/const.ts +5 -0
  122. package/Components/VideoModal/ModalAnimation/index.ts +2 -0
  123. package/Components/VideoModal/ModalAnimation/utils.ts +38 -2
  124. package/Components/VideoModal/OpaqueLayer.tsx +33 -0
  125. package/Components/VideoModal/PlayerDetails.tsx +18 -10
  126. package/Components/VideoModal/PlayerWrapper.tsx +43 -39
  127. package/Components/VideoModal/VideoModal.tsx +17 -11
  128. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -1
  129. package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
  130. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +0 -90
  131. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +89 -0
  132. package/Components/VideoModal/hooks/index.ts +7 -0
  133. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +49 -0
  134. package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +91 -0
  135. package/Components/VideoModal/hooks/utils/index.ts +33 -0
  136. package/Components/VideoModal/utils.ts +4 -5
  137. package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
  138. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
  139. package/Components/Viewport/__tests__/utils.test.js +5 -4
  140. package/Components/ZappUIComponent/Placeholder.tsx +3 -1
  141. package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
  142. package/Components/ZappUIComponent/index.tsx +4 -17
  143. package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
  144. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
  145. package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
  146. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
  147. package/Contexts/HeaderOffsetContext/index.tsx +4 -6
  148. package/Contexts/ScreenContext/index.tsx +6 -12
  149. package/Contexts/ScreenLayoutContext/index.tsx +5 -3
  150. package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
  151. package/Decorators/Navigator/index.tsx +1 -1
  152. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +18 -24
  153. package/Decorators/RiverResolver/index.tsx +6 -8
  154. package/Decorators/ZappPipesDataConnector/__tests__/Hero.js +1 -1
  155. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
  156. package/Decorators/ZappPipesDataConnector/index.tsx +6 -2
  157. package/package.json +7 -11
  158. package/tsconfig.json +2 -3
  159. package/.babelrc +0 -8
  160. package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
  161. package/Components/Cell/CellStyles/Hero/index.js +0 -111
  162. package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
  163. package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
  164. package/Components/Cell/CellStyles/colors.js +0 -40
  165. package/Components/Cell/CellStyles/index.js +0 -15
  166. package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
  167. package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
  168. package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
  169. package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
  170. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
  171. package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
  172. package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import { equals } from "ramda";
2
3
  import { Animated, ViewProps, ViewStyle } from "react-native";
3
4
  import { useSafeAreaFrame } from "react-native-safe-area-context";
4
5
 
@@ -8,6 +9,11 @@ import { PathnameContext } from "../../Contexts/PathnameContext";
8
9
  import { ScreenDataContext } from "../../Contexts/ScreenDataContext";
9
10
  import { ScreenContextProvider } from "../../Contexts/ScreenContext";
10
11
 
12
+ const fullWidthDimensions = {
13
+ height: "100%",
14
+ width: "100%",
15
+ };
16
+
11
17
  type Props = {
12
18
  children: any;
13
19
  style: any;
@@ -20,6 +26,47 @@ type Props = {
20
26
  screenData: NavigationScreenData;
21
27
  };
22
28
 
29
+ export function CurrentScreenContextProvider({
30
+ children,
31
+ ...props
32
+ }: {
33
+ children: any;
34
+ pathname: string;
35
+ isActive: boolean;
36
+ screenData: NavigationScreenData;
37
+ }) {
38
+ const { pathname, isActive = false, screenData } = props;
39
+
40
+ const [initialScreenData, setInitialScreenData] = React.useState(screenData);
41
+
42
+ React.useLayoutEffect(() => {
43
+ const screenDataChanged = !equals(initialScreenData, screenData);
44
+
45
+ if (isActive && screenDataChanged) {
46
+ setInitialScreenData(screenData);
47
+ }
48
+ }, [initialScreenData, screenData, isActive]);
49
+
50
+ return (
51
+ <ScreenDataContext.Provider value={initialScreenData}>
52
+ <PathnameContext.Provider value={pathname}>
53
+ <ScreenContextProvider pathname={pathname}>
54
+ {children}
55
+ </ScreenContextProvider>
56
+ </PathnameContext.Provider>
57
+ </ScreenDataContext.Provider>
58
+ );
59
+ }
60
+
61
+ const withCurrentScreenContext = (Component) =>
62
+ function SceneComponent(props: Props) {
63
+ return (
64
+ <CurrentScreenContextProvider {...props}>
65
+ <Component {...props} />
66
+ </CurrentScreenContextProvider>
67
+ );
68
+ };
69
+
23
70
  /**
24
71
  * Animated View container for any purpose.
25
72
  * Renders given children with given style object.
@@ -32,53 +79,35 @@ type Props = {
32
79
  * @param contentStyle
33
80
  * @param screenUniqueId
34
81
  */
35
- export function Scene({
82
+ function SceneComponent({
36
83
  children,
37
84
  style,
38
85
  pointerEvents = "auto",
39
86
  overlayStyle,
40
87
  animating,
41
88
  contentStyle,
42
- pathname,
43
89
  isActive = false,
44
90
  screenData,
45
91
  }: Props) {
46
- const [initialScreenData, setInitialScreenData] = React.useState(screenData);
47
-
48
92
  useScreenOrientationHandler({
49
93
  screenData,
50
94
  isActive,
51
95
  });
52
96
 
53
- React.useLayoutEffect(() => {
54
- if (isActive) {
55
- setInitialScreenData(screenData);
56
- }
57
- }, [screenData, isActive]);
58
-
59
97
  const frame = useSafeAreaFrame();
60
98
  const isAnimating = animating && overlayStyle;
61
99
 
62
- const dimensions = isAnimating
63
- ? {
64
- width: "100%",
65
- height: "100%",
66
- }
67
- : frame;
100
+ const dimensions = isAnimating ? fullWidthDimensions : frame;
68
101
 
69
102
  return (
70
103
  <Animated.View
71
104
  pointerEvents={pointerEvents}
72
105
  style={[style, contentStyle, dimensions]}
73
106
  >
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} />}
107
+ {children}
108
+ {isAnimating ? <Animated.View style={overlayStyle} /> : null}
82
109
  </Animated.View>
83
110
  );
84
111
  }
112
+
113
+ export const Scene = withCurrentScreenContext(SceneComponent);
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { update, compose, tail, append, take, identity, isNil } from "ramda";
3
+ import { append, compose, identity, isNil, tail, take, update } from "ramda";
4
4
 
5
5
  import { AnimationManager } from "./AnimationManager";
6
6
  import { Scene } from "./Scene";
@@ -289,7 +289,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
289
289
 
290
290
  return (
291
291
  <View style={styles.container}>
292
- {scenes[to.index] && (
292
+ {scenes[to.index] ? (
293
293
  <Scene
294
294
  {...{ style: to?.style || {} }}
295
295
  pathname={pathname}
@@ -301,7 +301,7 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
301
301
  >
302
302
  {scenes[to.index].children}
303
303
  </Scene>
304
- )}
304
+ ) : null}
305
305
  </View>
306
306
  );
307
307
  }
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
- import { shallow } from "enzyme";
3
- import { shallowToJson } from "enzyme-to-json";
2
+ import { render } from "@testing-library/react-native";
3
+
4
+ import { Scene } from "../Scene";
4
5
 
5
6
  const overlayStyle = { opacity: 1 };
6
7
  const contentStyle = { paddingBottom: 49 };
@@ -23,28 +24,38 @@ jest.mock(
23
24
  })
24
25
  );
25
26
 
26
- const { Scene } = require("../Scene");
27
+ jest.mock("../../../Contexts/PathnameContext", () => ({
28
+ PathnameContext: jest.requireActual("react").createContext({ pathname: "" }),
29
+ }));
27
30
 
28
- const wrapper = shallow(
29
- <Scene
30
- style={style}
31
- overlayStyle={overlayStyle}
32
- contentStyle={contentStyle}
33
- />
34
- );
31
+ jest.mock("../../../Contexts/ScreenDataContext", () => ({
32
+ ScreenDataContext: jest.requireActual("react").createContext({}),
33
+ }));
34
+
35
+ jest.mock("../../../Contexts/ScreenContext", () => ({
36
+ ScreenContextProvider: jest.requireActual("react-native").View,
37
+ }));
35
38
 
36
39
  describe("<Scene />", () => {
40
+ const wrapper = render(
41
+ <Scene
42
+ style={style}
43
+ overlayStyle={overlayStyle}
44
+ contentStyle={contentStyle}
45
+ />
46
+ );
47
+
37
48
  it("renders correctly", () => {
38
- expect(shallowToJson(wrapper)).toMatchSnapshot();
49
+ expect(wrapper.toJSON()).toMatchSnapshot();
39
50
  });
40
51
 
41
52
  // skipped - this isn't a very useful test, and it doesn't work as it used to on the new version of RN
42
53
  it.skip("renders children surrounded by AnimatedComponent", () => {
43
- expect(shallowToJson(wrapper).type).toEqual("AnimatedComponent");
54
+ expect(wrapper.toJSON()).toEqual("AnimatedComponent");
44
55
  });
45
56
 
46
57
  it("renders the overlay while animating", () => {
47
- const wrapperWithOverlay = shallow(
58
+ const wrapperWithOverlay = render(
48
59
  <Scene
49
60
  style={style}
50
61
  overlayStyle={overlayStyle}
@@ -53,6 +64,6 @@ describe("<Scene />", () => {
53
64
  />
54
65
  );
55
66
 
56
- expect(shallowToJson(wrapperWithOverlay)).toMatchSnapshot();
67
+ expect(wrapperWithOverlay.toJSON).toMatchSnapshot();
57
68
  });
58
69
  });
@@ -1,63 +1,23 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`<Scene /> renders correctly 1`] = `
4
- <ForwardRef(AnimatedComponentWrapper)
5
- pointerEvents="auto"
6
- style={
7
- [
4
+ <View>
5
+ <View
6
+ collapsable={false}
7
+ pointerEvents="auto"
8
+ style={
8
9
  {
9
10
  "flex": 1,
10
- },
11
- {
12
- "paddingBottom": 49,
13
- },
14
- {
15
11
  "fontScale": 2,
16
12
  "height": 1334,
13
+ "paddingBottom": 49,
17
14
  "scale": 2,
18
15
  "statusBarHeight": null,
19
16
  "width": 750,
20
- },
21
- ]
22
- }
23
- >
24
- <ContextProvider>
25
- <ContextProvider>
26
- <ScreenContextProvider />
27
- </ContextProvider>
28
- </ContextProvider>
29
- </ForwardRef(AnimatedComponentWrapper)>
30
- `;
31
-
32
- exports[`<Scene /> renders the overlay while animating 1`] = `
33
- <ForwardRef(AnimatedComponentWrapper)
34
- pointerEvents="auto"
35
- style={
36
- [
37
- {
38
- "flex": 1,
39
- },
40
- {
41
- "paddingBottom": 49,
42
- },
43
- {
44
- "height": "100%",
45
- "width": "100%",
46
- },
47
- ]
48
- }
49
- >
50
- <ContextProvider>
51
- <ContextProvider>
52
- <ScreenContextProvider />
53
- </ContextProvider>
54
- </ContextProvider>
55
- <ForwardRef(AnimatedComponentWrapper)
56
- style={
57
- {
58
- "opacity": 1,
59
17
  }
60
18
  }
61
19
  />
62
- </ForwardRef(AnimatedComponentWrapper)>
20
+ </View>
63
21
  `;
22
+
23
+ exports[`<Scene /> renders the overlay while animating 1`] = `[Function]`;
@@ -9,7 +9,7 @@ exports[`<TransitionerComponent /> renders correctly 1`] = `
9
9
  }
10
10
  }
11
11
  >
12
- <Scene
12
+ <View
13
13
  isActive={true}
14
14
  screenUniqueId="mocked-uuid"
15
15
  style={{}}
@@ -23,6 +23,6 @@ exports[`<TransitionerComponent /> renders correctly 1`] = `
23
23
  children
24
24
  </Text>
25
25
  </View>
26
- </Scene>
26
+ </View>
27
27
  </View>
28
28
  `;
@@ -1,9 +1,18 @@
1
1
  import React from "react";
2
2
  import { Text, View } from "react-native";
3
- import { shallow } from "enzyme";
4
- import { shallowToJson } from "enzyme-to-json";
5
3
 
6
4
  import { TransitionerComponent } from "../Transitioner";
5
+ import { render } from "@testing-library/react-native";
6
+
7
+ jest.mock("../Scene", () => {
8
+ const View = jest.requireActual("react-native").View;
9
+
10
+ return {
11
+ Scene(props) {
12
+ return <View {...props} />;
13
+ },
14
+ };
15
+ });
7
16
 
8
17
  const children = (
9
18
  <View foo="bar">
@@ -33,12 +42,12 @@ jest.mock("uuid");
33
42
 
34
43
  describe("<TransitionerComponent />", () => {
35
44
  it("renders correctly", () => {
36
- const wrapper = shallow(
45
+ const wrapper = render(
37
46
  <TransitionerComponent {...transitionerComponentProps}>
38
47
  {children}
39
48
  </TransitionerComponent>
40
49
  );
41
50
 
42
- expect(shallowToJson(wrapper)).toMatchSnapshot();
51
+ expect(wrapper.toJSON()).toMatchSnapshot();
43
52
  });
44
53
  });
@@ -1,5 +1,4 @@
1
1
  import * as React from "react";
2
- import { useWindowDimensions } from "react-native";
3
2
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
4
3
  import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
5
4
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
@@ -7,10 +6,15 @@ import { TransitionerComponent } from "./Transitioner";
7
6
 
8
7
  export const Transitioner = (props) => {
9
8
  const navigator = useNavigation();
10
- const { height, width } = useWindowDimensions();
11
9
 
12
- const dimensions = useDimensions("window", { deviceInfo: true });
13
- const isTablet = dimensions?.deviceInfo?.isTablet;
10
+ const {
11
+ width,
12
+ height,
13
+ deviceInfo: { isTablet },
14
+ } = useDimensions("window", {
15
+ updateForInactiveScreens: false,
16
+ deviceInfo: true,
17
+ });
14
18
 
15
19
  const { appData } = usePickFromState(["appData"]);
16
20
  const isTabletPortrait = appData?.isTabletPortrait;
@@ -8,6 +8,8 @@ import { loggerLiveImageManager } from "./loggerHelper";
8
8
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
9
9
  import { Component } from "react";
10
10
 
11
+ const TIMEOUT_FOR_DELAY_CHECK_PLAYER_POSITION = 500; // ms
12
+
11
13
  const { log_debug, log_info, log_error } = loggerLiveImageManager;
12
14
 
13
15
  export type LiveImageManagerEvent =
@@ -62,6 +64,9 @@ export class LiveImageManager implements PlayerLifecycleListener {
62
64
  protected currentlyPlaying: LiveImage | null = null;
63
65
  protected primaryPlayer: Player | null = null;
64
66
 
67
+ private checkPlayerPositionTimeout: ReturnType<typeof setTimeout> | null =
68
+ null;
69
+
65
70
  protected listeners: Record<
66
71
  string,
67
72
  Record<LiveImageManagerEvent, (event?: Record<string, any>) => void>
@@ -118,6 +123,11 @@ export class LiveImageManager implements PlayerLifecycleListener {
118
123
  });
119
124
  };
120
125
 
126
+ private cancelCheckPlayerPositionTimeout = () => {
127
+ clearTimeout(this.checkPlayerPositionTimeout);
128
+ this.checkPlayerPositionTimeout = null;
129
+ };
130
+
121
131
  public onViewportEnter = (item: LiveImage) => {
122
132
  log_debug(
123
133
  `onViewportEnter: live-image ${playerInfo(
@@ -125,7 +135,21 @@ export class LiveImageManager implements PlayerLifecycleListener {
125
135
  )}, primary ${playerInfo(this.primaryPlayer)}`
126
136
  );
127
137
 
128
- this.checkPlayerPosition(item);
138
+ if (!isTV()) {
139
+ // mobile only
140
+ // we have to delay running checkPlayerPosition, because sometimes on fast scrolling we get wrong order onEnter, then onLeave.
141
+ // which could cause select wrong item to play
142
+
143
+ this.cancelCheckPlayerPositionTimeout();
144
+
145
+ this.checkPlayerPositionTimeout = setTimeout(() => {
146
+ this.cancelCheckPlayerPositionTimeout();
147
+
148
+ this.checkPlayerPosition(item);
149
+ }, TIMEOUT_FOR_DELAY_CHECK_PLAYER_POSITION);
150
+ } else {
151
+ this.checkPlayerPosition(item);
152
+ }
129
153
  };
130
154
 
131
155
  public onViewportLeave = (item: LiveImage) => {
@@ -246,6 +270,8 @@ export class LiveImageManager implements PlayerLifecycleListener {
246
270
  };
247
271
 
248
272
  public checkPlayerPosition = (item: LiveImage) => {
273
+ this.cancelCheckPlayerPositionTimeout();
274
+
249
275
  log_debug(
250
276
  `checkPlayerPosition: live-image playerId: ${playerInfo(
251
277
  item.player
@@ -1,6 +1,7 @@
1
1
  // /// <reference types="@applicaster/applicaster-types" />
2
2
  //
3
3
  import * as React from "react";
4
+ import { useEffect } from "react";
4
5
 
5
6
  import { AppState, AppStateStatus, View } from "react-native";
6
7
  import { TrackedView } from "../TrackedView";
@@ -25,13 +26,15 @@ import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/player
25
26
  import { getAutoplaySettings } from "./utils";
26
27
  import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
27
28
  import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
28
- import { useEffect } from "react";
29
29
 
30
30
  const { log_error, log_debug } = loggerLiveImageComponent;
31
31
 
32
32
  const isMeasurement = (item: ZappEntry) =>
33
33
  isString(item.id) && item.id.startsWith("pre-measurement-");
34
34
 
35
+ // Pixels by which the view can slightly extend outside the viewport and still be considered fully visible.
36
+ const CLIP_THRESHOLD = 10;
37
+
35
38
  type Props = {
36
39
  item: ZappEntry;
37
40
  style: Record<string, any>;
@@ -44,7 +47,10 @@ type Props = {
44
47
  };
45
48
 
46
49
  const PlayerLiveImageComponent = (props: Props) => {
47
- const dimensions = useDimensions("screen", { fullDimensions: true });
50
+ const dimensions = useDimensions("screen", {
51
+ fullDimensions: true,
52
+ updateForInactiveScreens: false,
53
+ });
48
54
 
49
55
  const { item, style, playerId } = props;
50
56
 
@@ -135,13 +141,16 @@ const PlayerLiveImageComponent = (props: Props) => {
135
141
  } else {
136
142
  throw new Error("Player factory item is null");
137
143
  }
138
- }, [playerId, item, playerPluginId, screenConfig]);
144
+ }, [playerId, item.id, playerPluginId, screenConfig]);
139
145
 
140
146
  React.useEffect(() => {
141
147
  liveImageItem.setMode = setModeDebounced;
142
148
  }, [setModeDebounced, liveImageItem]);
143
149
 
144
- const { start, end } = React.useMemo(() => getAutoplaySettings(item), [item]);
150
+ const { start, end } = React.useMemo(
151
+ () => getAutoplaySettings(item),
152
+ [item.id]
153
+ );
145
154
 
146
155
  const controller = liveImageItem.getPlayer();
147
156
  const player = usePlayer(playerId);
@@ -174,7 +183,7 @@ const PlayerLiveImageComponent = (props: Props) => {
174
183
 
175
184
  unregister();
176
185
  };
177
- }, [item, liveImageItem]);
186
+ }, [item.id, liveImageItem]);
178
187
 
179
188
  React.useEffect(() => {
180
189
  if (!player) {
@@ -244,25 +253,27 @@ const PlayerLiveImageComponent = (props: Props) => {
244
253
  }, [item.id]);
245
254
 
246
255
  React.useEffect(() => {
247
- if (playerManager) {
248
- const isPlayerRegistered = playerManager.isPlayerRegistered(playerId);
256
+ if (isMeasurement(item) || !playerManager) {
257
+ return;
258
+ }
249
259
 
250
- if (isPlayerRegistered) {
251
- log_error(
252
- `PlayerLiveImageComponent: player ${playerId} already registered`
253
- );
254
- } else {
255
- playerManager.registerPlayer({
256
- id: playerId,
257
- playerController: controller,
258
- });
260
+ const isPlayerRegistered = playerManager.isPlayerRegistered(playerId);
259
261
 
260
- return () => {
261
- playerManager.unregisterPlayer(playerId);
262
- };
263
- }
262
+ if (isPlayerRegistered) {
263
+ log_error(
264
+ `PlayerLiveImageComponent: player ${playerId} already registered`
265
+ );
266
+ } else {
267
+ playerManager.registerPlayer({
268
+ id: playerId,
269
+ playerController: controller,
270
+ });
271
+
272
+ return () => {
273
+ playerManager.unregisterPlayer(playerId);
274
+ };
264
275
  }
265
- }, [liveImageItem, playerId, controller]);
276
+ }, [liveImageItem, playerId, controller, item.id]);
266
277
 
267
278
  const onPositionUpdated = React.useCallback(
268
279
  (data) => {
@@ -302,7 +313,7 @@ const PlayerLiveImageComponent = (props: Props) => {
302
313
  LiveImageManager.instance.checkPlayerPosition(liveImageItem);
303
314
  }
304
315
  },
305
- [liveImageItem, dimensions]
316
+ [liveImageItem, dimensions.height, dimensions.width]
306
317
  );
307
318
 
308
319
  const platformSpecificProps = isApplePlatform()
@@ -320,9 +331,10 @@ const PlayerLiveImageComponent = (props: Props) => {
320
331
  <TrackedView
321
332
  testId={`tracked-view-${playerId}-${item.title}`}
322
333
  onPositionUpdated={onPositionUpdated}
334
+ clipThreshold={CLIP_THRESHOLD}
323
335
  >
324
336
  <View ref={trackViewRef}>
325
- {isVideoMode && (
337
+ {isVideoMode ? (
326
338
  <Player
327
339
  autoplay={false}
328
340
  ref={_assignRoot}
@@ -334,7 +346,7 @@ const PlayerLiveImageComponent = (props: Props) => {
334
346
  resizeMode={"cover"}
335
347
  {...platformSpecificProps}
336
348
  />
337
- )}
349
+ ) : null}
338
350
  {
339
351
  <AnimatedInOut
340
352
  visible={isBackgroundImageVisible}
@@ -4,6 +4,7 @@ import { render } from "@testing-library/react-native";
4
4
  import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
5
5
  import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
6
6
  import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
+ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
7
8
 
8
9
  import { PlayerLiveImage } from "../PlayerLiveImageComponent";
9
10
  import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
@@ -32,7 +33,7 @@ const mockStore = configureStore();
32
33
 
33
34
  const store = mockStore({ appData: {} });
34
35
 
35
- const Wrapper = ({ children }: { children: React.ReactChildren }) => (
36
+ const Wrapper = ({ children }: { children: React.ReactNode }) => (
36
37
  /* @ts-ignore */
37
38
  <Provider store={store}>
38
39
  <ThemeContext.Provider
@@ -118,4 +119,53 @@ describe("PlayerLiveImageComponent", () => {
118
119
 
119
120
  // TODO: implement this test
120
121
  });
122
+
123
+ it("should register the player for normal item", () => {
124
+ render(
125
+ <Wrapper>
126
+ <PlayerLiveImage {...defaultProps} />
127
+ </Wrapper>
128
+ );
129
+
130
+ const isPlayerRegistered = playerManager.isPlayerRegistered(
131
+ defaultProps.playerId
132
+ );
133
+
134
+ expect(isPlayerRegistered).toBe(true);
135
+ });
136
+
137
+ it("should unregister the player for normal item", () => {
138
+ const component = render(
139
+ <Wrapper>
140
+ <PlayerLiveImage {...defaultProps} />
141
+ </Wrapper>
142
+ );
143
+
144
+ component.unmount();
145
+
146
+ const isPlayerRegistered = playerManager.isPlayerRegistered(
147
+ defaultProps.playerId
148
+ );
149
+
150
+ expect(isPlayerRegistered).toBe(false);
151
+ });
152
+
153
+ it("should not register the player for 'pre-measurement' item", () => {
154
+ const props = {
155
+ ...defaultProps,
156
+ item: {
157
+ ...defaultProps.item,
158
+ id: "pre-measurement-1",
159
+ },
160
+ };
161
+
162
+ render(
163
+ <Wrapper>
164
+ <PlayerLiveImage {...props} />
165
+ </Wrapper>
166
+ );
167
+
168
+ const isPlayerRegistered = playerManager.isPlayerRegistered(props.playerId);
169
+ expect(isPlayerRegistered).toBe(false);
170
+ });
121
171
  });
@@ -2,6 +2,7 @@
2
2
 
3
3
  exports[`PlayerLiveImageComponent should render correctly with default props 1`] = `
4
4
  <TrackedView
5
+ clipThreshold={10}
5
6
  onPositionUpdated={[Function]}
6
7
  testId="tracked-view-player1-Test"
7
8
  >
@@ -31,11 +32,6 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
31
32
  playerId="player1"
32
33
  resizeMode="cover"
33
34
  screenConfig={{}}
34
- source={
35
- {
36
- "uri": "",
37
- }
38
- }
39
35
  style={{}}
40
36
  />
41
37
  </View>
@@ -46,7 +46,7 @@ export const AnimatedPlayerModalWrapper = (props: Props) => {
46
46
 
47
47
  React.useEffect(() => {
48
48
  (playerAnimationState === PlayerAnimationStateEnum.minimize ||
49
- playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
49
+ playerAnimationState === PlayerAnimationStateEnum.maximize) &&
50
50
  setStartComponentsAnimation(true);
51
51
  }, [playerAnimationState]);
52
52