@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
@@ -0,0 +1,401 @@
1
+ import React from "react";
2
+ import { Animated, StyleSheet, View, Platform } from "react-native";
3
+
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+ import {
6
+ NativeViewGestureHandler,
7
+ PanGestureHandler,
8
+ State,
9
+ TapGestureHandler,
10
+ GestureHandlerRootView,
11
+ } from "react-native-gesture-handler";
12
+
13
+ import { PlayerContainerContext } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainerContext";
14
+ import {
15
+ useModalAnimationContext,
16
+ PlayerAnimationStateEnum,
17
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
18
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
19
+ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
20
+
21
+ import {
22
+ setScrollModalAnimatedValue,
23
+ resetScrollAnimatedValues,
24
+ } from "./utils";
25
+
26
+ const getAnimatedConfig = (toValue) => {
27
+ return {
28
+ toValue,
29
+ duration: 200,
30
+ useNativeDriver: true,
31
+ };
32
+ };
33
+
34
+ const generalStyles = StyleSheet.create({
35
+ container: {
36
+ flex: 1,
37
+ },
38
+ });
39
+
40
+ type Props = {
41
+ children: React.ReactNode;
42
+ };
43
+
44
+ export const AnimatedScrollModalComponent = ({ children }: Props) => {
45
+ const {
46
+ isActiveGesture,
47
+ playerAnimationState,
48
+ setPlayerAnimationState,
49
+ resetPlayerAnimationState,
50
+ animatedValues: {
51
+ lastScrollY,
52
+ dragScrollY,
53
+ dragVideoPlayerY,
54
+ translateYOffset,
55
+ },
56
+ lastScrollYValue,
57
+ scrollPosition,
58
+ modalSnapPoints,
59
+ lastSnap,
60
+ setLastSnap,
61
+ setStartComponentsAnimation,
62
+ } = useModalAnimationContext();
63
+
64
+ const [enableGesture, setIEnableGesture] = React.useState<boolean>(true);
65
+ const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
66
+
67
+ const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
68
+ useNavigation();
69
+
70
+ const { mode: videoModalMode, item: videoModalItem } = videoModalState;
71
+ const isMaximazedModal = videoModalMode === "MAXIMIZED";
72
+ const isMinimizedModal = videoModalMode === "MINIMIZED";
73
+ const previousItemId = usePrevious(videoModalItem?.id);
74
+
75
+ const isNotMinimizeMaximazeAnimation =
76
+ playerAnimationState !== PlayerAnimationStateEnum.minimize &&
77
+ playerAnimationState !== PlayerAnimationStateEnum.maximaze;
78
+
79
+ const isEnablePanGesture =
80
+ enableGesture &&
81
+ !isLanguageOverlayVisible &&
82
+ isNotMinimizeMaximazeAnimation &&
83
+ (isMaximazedModal || isMinimizedModal);
84
+
85
+ const isAudioItem = React.useMemo(
86
+ () =>
87
+ videoModalItem?.content?.type?.includes?.("audio") ||
88
+ videoModalItem?.type?.value === "audio",
89
+ [videoModalItem]
90
+ );
91
+
92
+ // Refs for components
93
+ const scrollRef = React.useRef(null);
94
+ const tapHandlerRef = React.useRef(null);
95
+ const panHandlerRef = React.useRef(null);
96
+
97
+ const onRegisterLastScroll = Animated.event(
98
+ [{ nativeEvent: { contentOffset: { y: lastScrollY } } }],
99
+ { useNativeDriver: true }
100
+ );
101
+
102
+ const onGestureEvent = Animated.event(
103
+ [{ nativeEvent: { translationY: dragScrollY } }],
104
+ { useNativeDriver: true }
105
+ );
106
+
107
+ const onHandlerStateChange = React.useCallback(
108
+ ({ nativeEvent }) => {
109
+ if (
110
+ nativeEvent.oldState === State.ACTIVE &&
111
+ scrollPosition.current === 0
112
+ ) {
113
+ // eslint-disable-next-line prefer-const
114
+ const { velocityY, translationY } = nativeEvent;
115
+ const dragToss = 0.05;
116
+
117
+ const preparedTranslationY =
118
+ Math.abs(translationY) - lastScrollYValue.current;
119
+
120
+ if (videoModalMode === "MAXIMIZED") {
121
+ const endOffsetY =
122
+ lastSnap + preparedTranslationY + dragToss * velocityY + 150;
123
+
124
+ let destSnapPoint = modalSnapPoints[0];
125
+
126
+ for (const snapPoint of modalSnapPoints) {
127
+ const distFromSnap = Math.abs(snapPoint - endOffsetY);
128
+
129
+ if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
130
+ destSnapPoint = snapPoint;
131
+ }
132
+ }
133
+
134
+ setLastSnap(destSnapPoint);
135
+
136
+ if (destSnapPoint === modalSnapPoints[0]) {
137
+ translateYOffset.extractOffset();
138
+ translateYOffset.setValue(preparedTranslationY);
139
+ translateYOffset.flattenOffset();
140
+ dragScrollY.setValue(0);
141
+
142
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
143
+ } else {
144
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
145
+ }
146
+ } else {
147
+ if (translationY < 0) {
148
+ // from mini to full
149
+ setLastSnap(modalSnapPoints[0]);
150
+
151
+ translateYOffset.setValue(
152
+ modalSnapPoints[1] - preparedTranslationY
153
+ );
154
+
155
+ dragScrollY.setValue(0);
156
+
157
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
158
+ } else {
159
+ resetPlayerAnimationState();
160
+ }
161
+ }
162
+ } else {
163
+ playerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
164
+ resetPlayerAnimationState();
165
+ }
166
+ },
167
+ [lastSnap, modalSnapPoints, playerAnimationState, videoModalMode]
168
+ );
169
+
170
+ const onScroll = React.useCallback(({ nativeEvent }) => {
171
+ scrollPosition.current = nativeEvent.contentOffset.y;
172
+ }, []);
173
+
174
+ // Workaround for onMomentumScrollEnd issue
175
+ // https://github.com/facebook/react-native/issues/32696#issuecomment-1104217223
176
+ const canMomentum = React.useRef(false);
177
+
178
+ const onMomentumScrollBegin = React.useCallback(() => {
179
+ canMomentum.current = true;
180
+ }, []);
181
+
182
+ const onMomentumScrollEnd = React.useCallback(
183
+ ({ nativeEvent }) => {
184
+ if (canMomentum.current && !isActiveGesture) {
185
+ if (nativeEvent.contentOffset.y === 0) {
186
+ resetScrollAnimatedValues(
187
+ lastScrollY,
188
+ lastScrollYValue,
189
+ dragScrollY,
190
+ dragVideoPlayerY
191
+ );
192
+
193
+ setIEnableGesture(true);
194
+ } else {
195
+ setIEnableGesture(false);
196
+ }
197
+
198
+ canMomentum.current = false;
199
+ }
200
+ },
201
+ [isActiveGesture]
202
+ );
203
+
204
+ React.useEffect(() => {
205
+ return () => {
206
+ scrollPosition.current = 0;
207
+
208
+ resetScrollAnimatedValues(
209
+ lastScrollY,
210
+ lastScrollYValue,
211
+ dragScrollY,
212
+ dragVideoPlayerY
213
+ );
214
+ };
215
+ }, []);
216
+
217
+ React.useEffect(() => {
218
+ const { mode, previousMode, item } = videoModalState;
219
+
220
+ if (
221
+ mode === "MAXIMIZED" &&
222
+ !enableGesture &&
223
+ scrollPosition.current === 0
224
+ ) {
225
+ setIEnableGesture(true);
226
+ }
227
+
228
+ if (mode === "MINIMIZED" && previousMode === "MAXIMIZED") {
229
+ // set animation to the minimize values if moving from the player to another screen
230
+ if (playerAnimationState === null) {
231
+ setScrollModalAnimatedValue(
232
+ translateYOffset,
233
+ modalSnapPoints[1],
234
+ setLastSnap
235
+ );
236
+
237
+ resetScrollAnimatedValues(
238
+ lastScrollY,
239
+ lastScrollYValue,
240
+ dragScrollY,
241
+ dragVideoPlayerY
242
+ );
243
+ }
244
+ } else if (
245
+ playerAnimationState === null &&
246
+ ((previousItemId === item?.id &&
247
+ mode === "MAXIMIZED" &&
248
+ (previousMode === "MINIMIZED" || previousMode === "MAXIMIZED")) ||
249
+ (previousItemId !== item?.id && mode !== "FULLSCREEN"))
250
+ ) {
251
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
252
+ }
253
+ }, [videoModalState]);
254
+
255
+ React.useEffect(() => {
256
+ if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
257
+ if (
258
+ (scrollPosition.current === 0 &&
259
+ (lastScrollY as any)._value !== 0 &&
260
+ (dragScrollY as any)._value === 0 &&
261
+ (dragVideoPlayerY as any)._value === 0) ||
262
+ (scrollPosition.current !== 0 &&
263
+ ((dragScrollY as any)._value !== 0 ||
264
+ (dragVideoPlayerY as any)._value !== 0))
265
+ ) {
266
+ resetScrollAnimatedValues(
267
+ lastScrollY,
268
+ lastScrollYValue,
269
+ dragScrollY,
270
+ dragVideoPlayerY
271
+ );
272
+ }
273
+
274
+ Animated.timing(
275
+ translateYOffset,
276
+ getAnimatedConfig(modalSnapPoints[1])
277
+ ).start(() => {
278
+ minimiseVideoModal();
279
+
280
+ setScrollModalAnimatedValue(
281
+ translateYOffset,
282
+ modalSnapPoints[1],
283
+ setLastSnap
284
+ );
285
+
286
+ resetScrollAnimatedValues(
287
+ lastScrollY,
288
+ lastScrollYValue,
289
+ dragScrollY,
290
+ dragVideoPlayerY
291
+ );
292
+
293
+ resetPlayerAnimationState();
294
+ });
295
+ } else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
296
+ Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
297
+ maximiseVideoModal();
298
+ setScrollModalAnimatedValue(translateYOffset, 0, setLastSnap);
299
+
300
+ resetScrollAnimatedValues(
301
+ lastScrollY,
302
+ lastScrollYValue,
303
+ dragScrollY,
304
+ dragVideoPlayerY
305
+ );
306
+
307
+ resetPlayerAnimationState();
308
+ });
309
+ }
310
+ }, [playerAnimationState]);
311
+
312
+ React.useEffect(() => {
313
+ const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
314
+ lastScrollYValue.current = value;
315
+ });
316
+
317
+ const dragListenerId = dragScrollY.addListener(({ value }) => {
318
+ const preparedValue =
319
+ isMinimizedModal && value >= 0
320
+ ? 0
321
+ : Math.round(isAudioItem ? Math.abs(value) : value);
322
+
323
+ if (
324
+ preparedValue > 0 &&
325
+ scrollPosition.current === 0 &&
326
+ playerAnimationState !== PlayerAnimationStateEnum.drag_player &&
327
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
328
+ ) {
329
+ isMinimizedModal && setStartComponentsAnimation(true);
330
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_scroll);
331
+ }
332
+ });
333
+
334
+ return () => {
335
+ lastScrollY.removeListener(lastScrollYListenerId);
336
+ dragScrollY.removeListener(dragListenerId);
337
+ };
338
+ }, [playerAnimationState, isAudioItem, isMinimizedModal]);
339
+
340
+ const Wrapper = React.useMemo(
341
+ () => (Platform.OS === "android" ? GestureHandlerRootView : View),
342
+ []
343
+ );
344
+
345
+ return (
346
+ <Wrapper style={generalStyles.container}>
347
+ <TapGestureHandler
348
+ maxDurationMs={100000}
349
+ ref={tapHandlerRef}
350
+ maxDeltaY={lastSnap - modalSnapPoints[0]}
351
+ numberOfTaps={1}
352
+ >
353
+ <View pointerEvents="box-none">
354
+ <PanGestureHandler
355
+ enabled={isEnablePanGesture}
356
+ ref={panHandlerRef}
357
+ simultaneousHandlers={[scrollRef, tapHandlerRef]}
358
+ shouldCancelWhenOutside={isMaximazedModal}
359
+ onGestureEvent={onGestureEvent}
360
+ onHandlerStateChange={onHandlerStateChange}
361
+ activeOffsetY={[-5, 5]}
362
+ >
363
+ <Animated.View>
364
+ <NativeViewGestureHandler
365
+ ref={scrollRef}
366
+ waitFor={tapHandlerRef}
367
+ simultaneousHandlers={panHandlerRef}
368
+ >
369
+ <Animated.ScrollView
370
+ scrollEnabled={
371
+ isMaximazedModal && isNotMinimizeMaximazeAnimation
372
+ }
373
+ bounces={false}
374
+ onScrollBeginDrag={onRegisterLastScroll}
375
+ onScroll={onScroll}
376
+ onMomentumScrollBegin={onMomentumScrollBegin}
377
+ onMomentumScrollEnd={onMomentumScrollEnd}
378
+ scrollEventThrottle={1}
379
+ showsVerticalScrollIndicator={false}
380
+ >
381
+ {children}
382
+ </Animated.ScrollView>
383
+ </NativeViewGestureHandler>
384
+ </Animated.View>
385
+ </PanGestureHandler>
386
+ </View>
387
+ </TapGestureHandler>
388
+ </Wrapper>
389
+ );
390
+ };
391
+
392
+ export const AnimatedScrollModal = ({ children }: Props) => {
393
+ const {
394
+ videoModalState: { visible },
395
+ } = useNavigation();
396
+
397
+ const Component =
398
+ !isTV() && visible ? AnimatedScrollModalComponent : React.Fragment;
399
+
400
+ return <Component>{children}</Component>;
401
+ };
@@ -0,0 +1,172 @@
1
+ import React from "react";
2
+ import { Animated, StyleSheet } from "react-native";
3
+
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+ import { PanGestureHandler, State } from "react-native-gesture-handler";
6
+
7
+ import { PlayerContainerContext } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainerContext";
8
+ import {
9
+ useModalAnimationContext,
10
+ PlayerAnimationStateEnum,
11
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
12
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
13
+
14
+ const generalStyles = StyleSheet.create({
15
+ container: {
16
+ flex: 1,
17
+ width: "100%",
18
+ position: "absolute",
19
+ zIndex: 201,
20
+ },
21
+ });
22
+
23
+ type Props = {
24
+ children: React.ReactNode;
25
+ };
26
+
27
+ export const AnimatedVideoPlayer = ({ children }: Props) => {
28
+ const {
29
+ playerAnimationState,
30
+ setPlayerAnimationState,
31
+ animatedValues: { translateYOffset, dragVideoPlayerY, lastScrollY },
32
+ lastScrollYValue,
33
+ modalSnapPoints,
34
+ lastSnap,
35
+ setLastSnap,
36
+ resetPlayerAnimationState,
37
+ setStartComponentsAnimation,
38
+ } = useModalAnimationContext();
39
+
40
+ const {
41
+ videoModalState: { mode: videoModalMode },
42
+ } = useNavigation();
43
+
44
+ const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
45
+ const isMaximazedModal = videoModalMode === "MAXIMIZED";
46
+ const isMinimizedModal = videoModalMode === "MINIMIZED";
47
+
48
+ const isNotMinimizeMaximazeAnimation =
49
+ playerAnimationState !== PlayerAnimationStateEnum.minimize &&
50
+ playerAnimationState !== PlayerAnimationStateEnum.maximaze;
51
+
52
+ const isEnablePanGesture =
53
+ !isLanguageOverlayVisible &&
54
+ isNotMinimizeMaximazeAnimation &&
55
+ (isMaximazedModal || isMinimizedModal);
56
+
57
+ const onGestureEvent = Animated.event(
58
+ [{ nativeEvent: { translationY: dragVideoPlayerY } }],
59
+ { useNativeDriver: true }
60
+ );
61
+
62
+ const onHandlerStateChange = React.useCallback(
63
+ ({ nativeEvent }) => {
64
+ if (nativeEvent.oldState === State.ACTIVE) {
65
+ // eslint-disable-next-line prefer-const
66
+ const { velocityY, translationY } = nativeEvent;
67
+ const preparedTranslationY = Math.abs(translationY);
68
+ const dragToss = 0.05;
69
+
70
+ if (videoModalMode === "MAXIMIZED") {
71
+ if (translationY > 0) {
72
+ const endOffsetY =
73
+ lastSnap + preparedTranslationY + dragToss * velocityY + 200;
74
+
75
+ let destSnapPoint = modalSnapPoints[0];
76
+
77
+ for (const snapPoint of modalSnapPoints) {
78
+ const distFromSnap = Math.abs(snapPoint - endOffsetY);
79
+
80
+ if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
81
+ destSnapPoint = snapPoint;
82
+ }
83
+ }
84
+
85
+ setLastSnap(destSnapPoint);
86
+
87
+ if (destSnapPoint === modalSnapPoints[0]) {
88
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
89
+ } else {
90
+ lastScrollY.setValue(0);
91
+ lastScrollYValue.current = 0;
92
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
93
+ }
94
+ }
95
+ } else if (videoModalMode === "MINIMIZED") {
96
+ if (translationY < 0) {
97
+ // from mini to full
98
+ setLastSnap(modalSnapPoints[0]);
99
+
100
+ translateYOffset.setValue(
101
+ modalSnapPoints[1] - preparedTranslationY
102
+ );
103
+
104
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
105
+ } else {
106
+ resetPlayerAnimationState();
107
+ }
108
+ }
109
+ }
110
+ },
111
+ [lastSnap, modalSnapPoints, videoModalMode]
112
+ );
113
+
114
+ React.useEffect(() => {
115
+ const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
116
+ ({ value }) => {
117
+ if (
118
+ (isMinimizedModal && value >= 0) ||
119
+ (isMaximazedModal && value <= 0)
120
+ ) {
121
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
122
+ translateYOffset.setValue(
123
+ modalSnapPoints[isMinimizedModal ? 1 : 0]
124
+ );
125
+ }
126
+ } else {
127
+ const preparedValue = Math.round(Math.abs(value));
128
+
129
+ if (
130
+ preparedValue > 0 &&
131
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
132
+ ) {
133
+ if (playerAnimationState !== PlayerAnimationStateEnum.drag_player) {
134
+ isMinimizedModal && setStartComponentsAnimation(true);
135
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_player);
136
+ }
137
+
138
+ translateYOffset.setValue(
139
+ isMaximazedModal
140
+ ? preparedValue
141
+ : modalSnapPoints[1] - preparedValue
142
+ );
143
+ }
144
+ }
145
+ }
146
+ );
147
+
148
+ return () => {
149
+ dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
150
+ };
151
+ }, [playerAnimationState, isMinimizedModal, isMaximazedModal]);
152
+
153
+ return (
154
+ <PanGestureHandler
155
+ enabled={isEnablePanGesture}
156
+ onGestureEvent={onGestureEvent}
157
+ onHandlerStateChange={onHandlerStateChange}
158
+ >
159
+ <Animated.View style={generalStyles.container}>{children}</Animated.View>
160
+ </PanGestureHandler>
161
+ );
162
+ };
163
+
164
+ export const AnimatedVideoPlayerComponent = ({ children }: Props) => {
165
+ const {
166
+ videoModalState: { visible },
167
+ } = useNavigation();
168
+
169
+ const Component = !isTV() && visible ? AnimatedVideoPlayer : React.Fragment;
170
+
171
+ return <Component>{children}</Component>;
172
+ };