@applicaster/zapp-react-native-ui-components 12.0.0-rc.13 → 12.0.0-rc.130

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 +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/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 -18
  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 +3 -25
  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 +4 -1
  43. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -117
  44. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  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 +33 -35
  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 +73 -34
  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 +70 -14
  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 +66 -0
  120. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +377 -0
  121. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
  122. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +481 -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,22 +1,20 @@
1
1
  // /// <reference types="@applicaster/applicaster-types" />
2
2
  //
3
3
  import * as React from "react";
4
- import * as R from "ramda";
5
4
 
6
- import { AppState, AppStateStatus } from "react-native";
5
+ import { AppState, AppStateStatus, View } from "react-native";
7
6
  import { TrackedView } from "../TrackedView";
8
7
  import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
9
8
 
10
9
  import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
11
10
 
12
- import { BufferAnimation } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/BufferAnimation";
13
11
  import {
14
12
  isApplePlatform,
15
13
  isTV,
16
14
  } from "@applicaster/zapp-react-native-utils/reactUtils";
17
15
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
18
16
  import { getUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
19
- import { PlayerImageBackground } from "../PlayerImageBackground";
17
+ import Image from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/Image";
20
18
  import { LiveImage, LiveImageManager, LiveImageType } from "./LiveImageManager";
21
19
 
22
20
  import { AnimatedInOut } from "@applicaster/zapp-react-native-ui-components/Components/AnimatedInOut";
@@ -25,12 +23,14 @@ import { loggerLiveImageComponent } from "./loggerHelper";
25
23
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
26
24
  import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
27
25
  import { getAutoplaySettings } from "./utils";
26
+ import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
27
+ import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
28
+ import { useEffect } from "react";
28
29
 
29
- const { log_error } = loggerLiveImageComponent;
30
+ const { log_error, log_debug } = loggerLiveImageComponent;
30
31
 
31
- const isMeasurement = (item) => {
32
- return item.id.startsWith("pre-measurement-");
33
- };
32
+ const isMeasurement = (item: ZappEntry) =>
33
+ isString(item.id) && item.id.startsWith("pre-measurement-");
34
34
 
35
35
  type Props = {
36
36
  item: ZappEntry;
@@ -40,12 +40,13 @@ type Props = {
40
40
  imageKey?: string;
41
41
  screenConfig: Record<string, any>;
42
42
  audioMutedByDefault?: boolean;
43
+ uri: string; // cover image url
43
44
  };
44
45
 
45
46
  const PlayerLiveImageComponent = (props: Props) => {
46
47
  const dimensions = useDimensions("screen", { fullDimensions: true });
47
48
 
48
- const { item, style, playerId, imageKey } = props;
49
+ const { item, style, playerId } = props;
49
50
 
50
51
  const timeoutRef = React.useRef<NodeJS.Timeout | null>(null);
51
52
  const [mode, setMode] = React.useState(LiveImageType.Image);
@@ -55,20 +56,18 @@ const PlayerLiveImageComponent = (props: Props) => {
55
56
  isTV() ? false : getUserCellPlayerMutedPreference(props.audioMutedByDefault)
56
57
  );
57
58
 
58
- const [PlayerViewComponent, setPlayerViewComponent] = React.useState(null);
59
- const Player: any = PlayerViewComponent || BufferAnimation;
60
-
61
59
  const ref = React.useRef(null);
62
-
63
- const liveImageItem: LiveImage = React.useMemo(() => {
64
- /**
65
- * Debounced setMode function.
66
- *
67
- * Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
68
- *
69
- * @param type video or image
70
- */
71
- const setModeDebounced = (type: LiveImageType) => {
60
+ const trackViewRef = React.useRef(null);
61
+
62
+ /**
63
+ * Debounced setMode function.
64
+ *
65
+ * Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
66
+ *
67
+ * @param type video or image
68
+ */
69
+ const setModeDebounced = React.useCallback(
70
+ (type: LiveImageType) => {
72
71
  if (type === LiveImageType.Video) {
73
72
  if (type === mode) {
74
73
  return;
@@ -80,45 +79,69 @@ const PlayerLiveImageComponent = (props: Props) => {
80
79
  } else {
81
80
  if (timeoutRef.current) {
82
81
  clearTimeout(timeoutRef.current);
82
+ timeoutRef.current = null;
83
83
  }
84
84
 
85
85
  setMode(type);
86
86
  }
87
- };
87
+ },
88
+ [mode]
89
+ );
90
+
91
+ const entryToViewIdMapping = React.useRef({});
92
+
93
+ useEffect(() => {
94
+ const nativeTag = trackViewRef.current?._nativeTag?.toString();
95
+
96
+ if (!nativeTag) {
97
+ return;
98
+ }
99
+
100
+ const prevValue = entryToViewIdMapping.current[nativeTag];
88
101
 
102
+ if (prevValue && prevValue.itemId !== item.id) {
103
+ if (mode === LiveImageType.Video) {
104
+ log_debug(
105
+ "Entry to view association changed, stopping current live image"
106
+ );
107
+
108
+ setMode(LiveImageType.Image);
109
+ }
110
+ }
111
+
112
+ entryToViewIdMapping.current[nativeTag] = { itemId: item.id };
113
+ }, [trackViewRef.current, item.id, mode]);
114
+
115
+ const { screenConfig, playerPluginId } = props;
116
+
117
+ const liveImageItem: LiveImage = React.useMemo(() => {
89
118
  const playerFactoryItem = playerFactory({
90
119
  player: ref,
91
- listener: props as Record<string, any>,
92
120
  playerId,
93
121
  autoplay: false,
94
122
  entry: item,
95
- muted,
96
- playerPluginId: props?.playerPluginId,
97
- screenConfig: props?.screenConfig,
123
+ muted, // Initial muted state, not needed in dependencies
124
+ playerPluginId: playerPluginId,
125
+ screenConfig: screenConfig,
98
126
  playerRole: PlayerRole.Cell,
99
127
  });
100
128
 
101
- const Component = playerFactoryItem?.Component;
102
-
103
- if (!R.isNil(Component) && Component !== PlayerViewComponent) {
104
- setPlayerViewComponent(Component);
105
- }
106
-
107
129
  if (playerFactoryItem) {
108
130
  return new LiveImage({
109
131
  playerId,
110
132
  player: playerFactoryItem.controller,
111
- setMode: setModeDebounced,
133
+ component: playerFactoryItem?.Component,
112
134
  });
113
135
  } else {
114
136
  throw new Error("Player factory item is null");
115
137
  }
116
- }, [playerId, item?.id]);
138
+ }, [playerId, item, playerPluginId, screenConfig]);
117
139
 
118
- const { start, end } = React.useMemo(
119
- () => getAutoplaySettings(item),
120
- [item?.id]
121
- );
140
+ React.useEffect(() => {
141
+ liveImageItem.setMode = setModeDebounced;
142
+ }, [setModeDebounced, liveImageItem]);
143
+
144
+ const { start, end } = React.useMemo(() => getAutoplaySettings(item), [item]);
122
145
 
123
146
  const controller = liveImageItem.getPlayer();
124
147
  const player = usePlayer(playerId);
@@ -127,6 +150,10 @@ const PlayerLiveImageComponent = (props: Props) => {
127
150
  ref.current = component;
128
151
  };
129
152
 
153
+ const onLiveImageCompleted = React.useCallback(() => {
154
+ LiveImageManager.instance.onLiveImageCompleted(liveImageItem);
155
+ }, [liveImageItem]);
156
+
130
157
  const onStop = React.useCallback(() => {
131
158
  LiveImageManager.instance.pauseLiveImage(liveImageItem);
132
159
  }, [liveImageItem]);
@@ -140,13 +167,14 @@ const PlayerLiveImageComponent = (props: Props) => {
140
167
  const unregister = LiveImageManager.instance.register(liveImageItem);
141
168
 
142
169
  return () => {
143
- unregister();
144
-
145
170
  if (timeoutRef.current) {
146
171
  clearTimeout(timeoutRef.current);
172
+ timeoutRef.current = null;
147
173
  }
174
+
175
+ unregister();
148
176
  };
149
- }, [liveImageItem, item]);
177
+ }, [item, liveImageItem]);
150
178
 
151
179
  React.useEffect(() => {
152
180
  if (!player) {
@@ -178,11 +206,12 @@ const PlayerLiveImageComponent = (props: Props) => {
178
206
  setMuted(false);
179
207
  },
180
208
  onPlayerClose: () => {
209
+ onLiveImageCompleted();
181
210
  setIsReady(false);
182
211
  },
183
212
  },
184
213
  });
185
- }, [player, onStop]);
214
+ }, [player, onStop, onLiveImageCompleted, start, end]);
186
215
 
187
216
  React.useEffect(() => {
188
217
  const subscription = AppState.addEventListener(
@@ -233,40 +262,48 @@ const PlayerLiveImageComponent = (props: Props) => {
233
262
  };
234
263
  }
235
264
  }
236
- }, [liveImageItem]);
237
-
238
- const onPositionUpdated = (data) => {
239
- const normalizedRect = (rect) => {
240
- if (!rect) {
241
- return null;
242
- }
265
+ }, [liveImageItem, playerId, controller]);
266
+
267
+ const onPositionUpdated = React.useCallback(
268
+ (data) => {
269
+ const normalizedRect = (rect: {
270
+ left: number;
271
+ right: number;
272
+ top: number;
273
+ bottom: number;
274
+ }) => {
275
+ if (!rect) {
276
+ return null;
277
+ }
243
278
 
244
- const { left, right, top, bottom } = rect;
279
+ const { left, right, top, bottom } = rect;
245
280
 
246
- return {
247
- left: left / dimensions.width,
248
- right: right / dimensions.width,
249
- top: top / dimensions.height,
250
- bottom: bottom / dimensions.height,
251
- centerX: (left + right) / 2 / dimensions.width,
252
- centerY: (top + bottom) / 2 / dimensions.height,
281
+ return {
282
+ left: left / dimensions.width,
283
+ right: right / dimensions.width,
284
+ top: top / dimensions.height,
285
+ bottom: bottom / dimensions.height,
286
+ centerX: (left + right) / 2 / dimensions.width,
287
+ centerY: (top + bottom) / 2 / dimensions.height,
288
+ };
253
289
  };
254
- };
255
290
 
256
- liveImageItem.position = normalizedRect(data.rect);
291
+ liveImageItem.position = normalizedRect(data.rect);
257
292
 
258
- const newIsFullyVisible = !!data.rect;
293
+ const newIsFullyVisible = !!data.rect;
259
294
 
260
- if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
261
- liveImageItem.isFullyVisible = newIsFullyVisible;
295
+ if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
296
+ liveImageItem.isFullyVisible = newIsFullyVisible;
262
297
 
263
- liveImageItem.isFullyVisible
264
- ? LiveImageManager.instance.onViewportEnter(liveImageItem)
265
- : LiveImageManager.instance.onViewportLeave(liveImageItem);
266
- } else {
267
- LiveImageManager.instance.checkPlayerPosition(liveImageItem);
268
- }
269
- };
298
+ liveImageItem.isFullyVisible
299
+ ? LiveImageManager.instance.onViewportEnter(liveImageItem)
300
+ : LiveImageManager.instance.onViewportLeave(liveImageItem);
301
+ } else {
302
+ LiveImageManager.instance.checkPlayerPosition(liveImageItem);
303
+ }
304
+ },
305
+ [liveImageItem, dimensions]
306
+ );
270
307
 
271
308
  const platformSpecificProps = isApplePlatform()
272
309
  ? { hideNativeControls: true, controls: false }
@@ -276,38 +313,38 @@ const PlayerLiveImageComponent = (props: Props) => {
276
313
  const isVideoMode = mode === LiveImageType.Video;
277
314
  const isBackgroundImageVisible = isImageMode || !isReadyToPlay;
278
315
  const videoStyles = { ...style, position: "absolute", zIndex: -100 };
316
+ const Player: any = liveImageItem.component || BufferAnimation;
279
317
 
318
+ // TODO: nice to have - resolve imageKey when imageUrl is not provided
280
319
  return (
281
320
  <TrackedView
282
321
  testId={`tracked-view-${playerId}-${item.title}`}
283
322
  onPositionUpdated={onPositionUpdated}
284
323
  >
285
- {isVideoMode && (
286
- <Player
287
- autoplay={false}
288
- ref={_assignRoot}
289
- entry={item} // Must be passed first in list
290
- style={videoStyles}
291
- playerId={playerId}
292
- muted={muted}
293
- listener={controller?.getListener()}
294
- resizeMode={"cover"}
295
- {...platformSpecificProps}
296
- />
297
- )}
298
- {
299
- <AnimatedInOut
300
- visible={isBackgroundImageVisible}
301
- animationConfig={overlayFadeIn}
302
- staticStyles={style}
303
- >
304
- <PlayerImageBackground
305
- entry={item}
306
- style={style}
307
- imageKey={imageKey}
324
+ <View ref={trackViewRef}>
325
+ {isVideoMode && (
326
+ <Player
327
+ autoplay={false}
328
+ ref={_assignRoot}
329
+ entry={item} // Must be passed first in list
330
+ style={videoStyles}
331
+ playerId={playerId}
332
+ muted={muted}
333
+ listener={controller?.getListener()}
334
+ resizeMode={"cover"}
335
+ {...platformSpecificProps}
308
336
  />
309
- </AnimatedInOut>
310
- }
337
+ )}
338
+ {
339
+ <AnimatedInOut
340
+ visible={isBackgroundImageVisible}
341
+ animationConfig={overlayFadeIn}
342
+ staticStyles={style}
343
+ >
344
+ <Image {...props} resizeMode="cover" style={style} applyMaxSize />
345
+ </AnimatedInOut>
346
+ }
347
+ </View>
311
348
  </TrackedView>
312
349
  );
313
350
  };
@@ -3,7 +3,14 @@ import * as React from "react";
3
3
  import { render } from "@testing-library/react-native";
4
4
  import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
5
5
  import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
6
+ import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
7
+ import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
+
6
9
  import { PlayerLiveImage } from "../PlayerLiveImageComponent";
10
+ import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
11
+
12
+ import { Provider } from "react-redux";
13
+ import configureStore from "redux-mock-store";
7
14
 
8
15
  const seekTo = jest.fn();
9
16
 
@@ -16,6 +23,27 @@ jest.mock(
16
23
  })
17
24
  );
18
25
 
26
+ jest
27
+ .spyOn(useNavigationHooks, "useNavigation")
28
+ .mockImplementation(() => ({ videoModalState: { visible: false } }));
29
+
30
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
31
+
32
+ const mockStore = configureStore();
33
+
34
+ const store = mockStore({ appData: {} });
35
+
36
+ const Wrapper = ({ children }: { children: React.ReactChildren }) => (
37
+ /* @ts-ignore */
38
+ <Provider store={store}>
39
+ <ThemeContext.Provider
40
+ value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
41
+ >
42
+ {children}
43
+ </ThemeContext.Provider>
44
+ </Provider>
45
+ );
46
+
19
47
  describe("PlayerLiveImageComponent", () => {
20
48
  const defaultProps = {
21
49
  item: { id: "1", title: "Test", type: { value: "" } },
@@ -36,10 +64,16 @@ describe("PlayerLiveImageComponent", () => {
36
64
  controller: new Player({}),
37
65
  Component: () => null,
38
66
  }));
67
+
68
+ jest.spyOn(navigationHooks, "useIsScreenActive").mockReturnValue(true);
39
69
  });
40
70
 
41
71
  it("should render correctly with default props", () => {
42
- const component = render(<PlayerLiveImage {...defaultProps} />);
72
+ const component = render(
73
+ <Wrapper>
74
+ <PlayerLiveImage {...defaultProps} />
75
+ </Wrapper>
76
+ );
43
77
 
44
78
  expect(component.toJSON()).toMatchSnapshot();
45
79
  });
@@ -53,7 +87,11 @@ describe("PlayerLiveImageComponent", () => {
53
87
  },
54
88
  };
55
89
 
56
- render(<PlayerLiveImage {...props} />);
90
+ render(
91
+ <Wrapper>
92
+ <PlayerLiveImage {...props} />
93
+ </Wrapper>
94
+ );
57
95
 
58
96
  // TODO: implement this test
59
97
  });
@@ -67,7 +105,11 @@ describe("PlayerLiveImageComponent", () => {
67
105
  },
68
106
  };
69
107
 
70
- render(<PlayerLiveImage {...props} />);
108
+ render(
109
+ <Wrapper>
110
+ <PlayerLiveImage {...props} />
111
+ </Wrapper>
112
+ );
71
113
 
72
114
  // TODO: implement this test
73
115
  });
@@ -5,41 +5,38 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
5
5
  onPositionUpdated={[Function]}
6
6
  testId="tracked-view-player1-Test"
7
7
  >
8
- <View
9
- collapsable={false}
10
- style={
11
- Object {
12
- "opacity": 1,
13
- }
14
- }
15
- >
8
+ <View>
16
9
  <View
17
- accessibilityIgnoresInvertColors={true}
18
- style={Object {}}
10
+ collapsable={false}
11
+ style={
12
+ Object {
13
+ "opacity": 1,
14
+ }
15
+ }
19
16
  >
20
17
  <Image
18
+ applyMaxSize={true}
19
+ audioMutedByDefault={false}
20
+ imageKey="image1"
21
+ item={
22
+ Object {
23
+ "id": "1",
24
+ "title": "Test",
25
+ "type": Object {
26
+ "value": "",
27
+ },
28
+ }
29
+ }
30
+ onError={[Function]}
31
+ playerId="player1"
21
32
  resizeMode="cover"
33
+ screenConfig={Object {}}
22
34
  source={
23
35
  Object {
24
- "uri": undefined,
36
+ "uri": "",
25
37
  }
26
38
  }
27
- style={
28
- Array [
29
- Object {
30
- "bottom": 0,
31
- "left": 0,
32
- "position": "absolute",
33
- "right": 0,
34
- "top": 0,
35
- },
36
- Object {
37
- "height": undefined,
38
- "width": undefined,
39
- },
40
- undefined,
41
- ]
42
- }
39
+ style={Object {}}
43
40
  />
44
41
  </View>
45
42
  </View>
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ import { Animated, ViewStyle } from "react-native";
3
+
4
+ import {
5
+ useModalAnimationContext,
6
+ PlayerAnimationStateEnum,
7
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
+
9
+ type Props = {
10
+ style: ViewStyle[];
11
+ children: React.ReactNode;
12
+ };
13
+
14
+ export const AnimatedPlayerModalWrapper = (props: Props) => {
15
+ const {
16
+ playerAnimationState,
17
+ animatedValues: { lastScrollY, dragScrollY, translateYOffset },
18
+ modalSnapPoints,
19
+ setStartComponentsAnimation,
20
+ } = useModalAnimationContext();
21
+
22
+ const interpolateConfig: Animated.InterpolationConfigType = React.useMemo(
23
+ () => ({
24
+ inputRange: modalSnapPoints,
25
+ outputRange: modalSnapPoints,
26
+ extrapolate: "clamp",
27
+ }),
28
+ [modalSnapPoints]
29
+ );
30
+
31
+ let translateY;
32
+
33
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
34
+ translateY = translateYOffset.interpolate(interpolateConfig);
35
+ } else {
36
+ const reverseLastScrollY = Animated.multiply(
37
+ new Animated.Value(-1),
38
+ lastScrollY
39
+ );
40
+
41
+ translateY = Animated.add(
42
+ translateYOffset,
43
+ Animated.add(dragScrollY, reverseLastScrollY)
44
+ ).interpolate(interpolateConfig);
45
+ }
46
+
47
+ React.useEffect(() => {
48
+ const translateYListener = translateY.addListener(() => {
49
+ (playerAnimationState === PlayerAnimationStateEnum.minimize ||
50
+ playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
51
+ setStartComponentsAnimation(true);
52
+ });
53
+
54
+ return () => {
55
+ translateYListener && translateY.removeListener(translateYListener);
56
+ };
57
+ }, [playerAnimationState]);
58
+
59
+ return (
60
+ <Animated.View
61
+ style={[props.style, { transform: [{ translateY: translateY }] }]}
62
+ >
63
+ {props.children}
64
+ </Animated.View>
65
+ );
66
+ };