@applicaster/zapp-react-native-ui-components 12.0.0-rc.8 → 12.0.0-rc.80

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 (135) 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 +1 -1
  5. package/Components/Cell/Cell.tsx +7 -7
  6. package/Components/Cell/CellWithFocusable.tsx +38 -19
  7. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  8. package/Components/ErrorScreen/index.tsx +1 -1
  9. package/Components/FocusableCell/index.tsx +7 -7
  10. package/Components/FocusableGroup/index.tsx +1 -0
  11. package/Components/FocusableList/FocusableChild.ts +24 -14
  12. package/Components/FocusableList/FocusableItem.tsx +1 -1
  13. package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
  14. package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
  15. package/Components/FocusableList/index.tsx +26 -25
  16. package/Components/GeneralContentScreen/GeneralContentScreen.tsx +11 -8
  17. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
  18. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
  19. package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
  20. package/Components/HookRenderer/index.tsx +1 -6
  21. package/Components/Image/Image.android.tsx +3 -26
  22. package/Components/Image/Image.tsx +18 -2
  23. package/Components/Image/utils/index.ts +39 -0
  24. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  25. package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
  26. package/Components/Layout/TV/__tests__/index.test.tsx +19 -108
  27. package/Components/Layout/TV/index.tsx +28 -43
  28. package/Components/Layout/TV/index.web.tsx +33 -0
  29. package/Components/Layout/index.tsx +15 -11
  30. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
  31. package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +80 -110
  32. package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
  33. package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
  34. package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
  35. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  36. package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
  37. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
  38. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -2
  39. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
  40. package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
  41. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  42. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  43. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
  44. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
  45. package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
  46. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
  47. package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
  48. package/Components/MasterCell/utils/index.ts +33 -35
  49. package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
  50. package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
  51. package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
  52. package/Components/ModalComponent/Button/Item.tsx +82 -0
  53. package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
  54. package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
  55. package/Components/ModalComponent/Button/assets.ts +4 -0
  56. package/Components/ModalComponent/Button/index.tsx +111 -0
  57. package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
  58. package/Components/ModalComponent/Header/Title.tsx +70 -0
  59. package/Components/ModalComponent/Header/assets.ts +4 -0
  60. package/Components/ModalComponent/Header/index.tsx +71 -0
  61. package/Components/ModalComponent/Header/utils.ts +79 -0
  62. package/Components/ModalComponent/index.tsx +38 -0
  63. package/Components/ModalComponent/utils.ts +126 -0
  64. package/Components/Navigator/StackNavigator.tsx +48 -0
  65. package/Components/Navigator/index.ts +1 -0
  66. package/Components/PlayerContainer/PlayerContainer.tsx +69 -31
  67. package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
  68. package/Components/PlayerImageBackground/index.tsx +34 -8
  69. package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
  70. package/Components/River/RefreshControl.tsx +55 -1
  71. package/Components/River/River.tsx +8 -5
  72. package/Components/River/TV/River.tsx +2 -25
  73. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
  74. package/Components/River/__tests__/componentsMap.test.js +7 -0
  75. package/Components/River/useScreenConfiguration.ts +5 -6
  76. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
  77. package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
  78. package/Components/RouteManager/index.tsx +4 -2
  79. package/Components/Screen/TV/hooks/index.ts +3 -0
  80. package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
  81. package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
  82. package/Components/Screen/TV/index.web.tsx +179 -0
  83. package/Components/Screen/__tests__/Screen.test.tsx +51 -36
  84. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
  85. package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
  86. package/Components/Screen/index.tsx +131 -44
  87. package/Components/Screen/navigationHandler.ts +0 -82
  88. package/Components/Screen/orientationHandler.ts +1 -1
  89. package/Components/ScreenResolver/index.tsx +4 -2
  90. package/Components/Tabs/TV/styles.ts +1 -1
  91. package/Components/TrackedView/index.tsx +6 -3
  92. package/Components/Transitioner/Scene.tsx +24 -19
  93. package/Components/Transitioner/Transitioner.tsx +21 -28
  94. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
  95. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
  96. package/Components/VideoLive/LiveImageManager.ts +60 -14
  97. package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
  98. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
  99. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
  100. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  101. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +352 -0
  102. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +158 -0
  103. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +461 -0
  104. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
  105. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  106. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  107. package/Components/VideoModal/PlayerDetails.tsx +6 -3
  108. package/Components/VideoModal/PlayerWrapper.tsx +82 -50
  109. package/Components/VideoModal/VideoModal.tsx +23 -40
  110. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
  111. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
  112. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +246 -166
  113. package/Components/VideoModal/hooks/useModalSize.ts +13 -4
  114. package/Components/VideoModal/utils.ts +8 -5
  115. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
  116. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
  117. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
  118. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  119. package/Components/Viewport/utils.js +1 -1
  120. package/Components/ZappUIComponent/index.tsx +22 -12
  121. package/Components/index.js +2 -0
  122. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  123. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  124. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  125. package/Contexts/ScreenContext/index.tsx +95 -29
  126. package/Contexts/ScreenDataContext/index.tsx +20 -0
  127. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  128. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  129. package/Decorators/RiverResolver/index.tsx +0 -4
  130. package/Decorators/index.tsx +0 -4
  131. package/events/index.ts +1 -0
  132. package/package.json +5 -6
  133. package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
  134. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  135. /package/Contexts/{index.js → index.ts} +0 -0
@@ -13,35 +13,25 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
13
13
  }
14
14
  }
15
15
  >
16
- <View
17
- accessibilityIgnoresInvertColors={true}
18
- style={Object {}}
19
- >
20
- <Image
21
- resizeMode="cover"
22
- source={
23
- Object {
24
- "uri": undefined,
25
- }
26
- }
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
- ]
16
+ <Image
17
+ applyMaxSize={true}
18
+ audioMutedByDefault={false}
19
+ imageKey="image1"
20
+ item={
21
+ Object {
22
+ "id": "1",
23
+ "title": "Test",
24
+ "type": Object {
25
+ "value": "",
26
+ },
42
27
  }
43
- />
44
- </View>
28
+ }
29
+ onError={[Function]}
30
+ playerId="player1"
31
+ resizeMode="cover"
32
+ screenConfig={Object {}}
33
+ style={Object {}}
34
+ />
45
35
  </View>
46
36
  </TrackedView>
47
37
  `;
@@ -0,0 +1,78 @@
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
+ import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+
10
+ type Props = {
11
+ style: ViewStyle[];
12
+ children: React.ReactNode;
13
+ };
14
+
15
+ export const AnimatedPlayerModalWrapper = (props: Props) => {
16
+ const {
17
+ playerAnimationState,
18
+ animatedValues: { lastScrollY, dragScrollY, translateYOffset },
19
+ modalSnapPoints,
20
+ setStartComponentsAnimation,
21
+ lastScrollYValue,
22
+ } = useModalAnimationContext();
23
+
24
+ const { height: screenHeight } = useDimensions("screen", {
25
+ deviceInfo: true,
26
+ });
27
+
28
+ const interpolateConfig: Animated.InterpolationConfigType = React.useMemo(
29
+ () => ({
30
+ inputRange: modalSnapPoints,
31
+ outputRange: modalSnapPoints,
32
+ extrapolate: "clamp",
33
+ }),
34
+ [modalSnapPoints]
35
+ );
36
+
37
+ let translateY;
38
+
39
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
40
+ translateY = translateYOffset.interpolate(interpolateConfig);
41
+ } else {
42
+ const reverseLastScrollY = Animated.multiply(
43
+ new Animated.Value(-1),
44
+ lastScrollY
45
+ );
46
+
47
+ translateY = Animated.add(
48
+ translateYOffset,
49
+ Animated.add(dragScrollY, reverseLastScrollY)
50
+ ).interpolate(interpolateConfig);
51
+ }
52
+
53
+ React.useEffect(() => {
54
+ const translateYListener = translateY.addListener(({ value }) => {
55
+ const preparedValue = Math.round(
56
+ Math.abs(value) - lastScrollYValue.current
57
+ );
58
+
59
+ (playerAnimationState === PlayerAnimationStateEnum.minimize ||
60
+ playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
61
+ setStartComponentsAnimation(
62
+ preparedValue >= Math.round((screenHeight * 10) / 100)
63
+ );
64
+ });
65
+
66
+ return () => {
67
+ translateYListener && translateY.removeListener(translateYListener);
68
+ };
69
+ }, [playerAnimationState]);
70
+
71
+ return (
72
+ <Animated.View
73
+ style={[props.style, { transform: [{ translateY: translateY }] }]}
74
+ >
75
+ {props.children}
76
+ </Animated.View>
77
+ );
78
+ };
@@ -0,0 +1,352 @@
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
+ } = useModalAnimationContext();
62
+
63
+ const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
64
+
65
+ const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
66
+ useNavigation();
67
+
68
+ const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
69
+ const isMinimizedModal = videoModalState.mode === "MINIMIZED";
70
+ const previousItemId = usePrevious(videoModalState.item?.id);
71
+
72
+ const isNotMinimizeMaximazeAnimation =
73
+ playerAnimationState !== PlayerAnimationStateEnum.minimize &&
74
+ playerAnimationState !== PlayerAnimationStateEnum.maximaze;
75
+
76
+ const isEnablePanGesture =
77
+ !isLanguageOverlayVisible &&
78
+ isNotMinimizeMaximazeAnimation &&
79
+ (isMaximazedModal || isMinimizedModal);
80
+
81
+ const isAudioItem = React.useMemo(
82
+ () =>
83
+ videoModalState.item?.content?.type?.includes?.("audio") ||
84
+ videoModalState.item?.type?.value === "audio",
85
+ [videoModalState.item]
86
+ );
87
+
88
+ // Refs for components
89
+ const scrollRef = React.useRef(null);
90
+ const tapHandlerRef = React.useRef(null);
91
+ const panHandlerRef = React.useRef(null);
92
+
93
+ const onRegisterLastScroll = Animated.event(
94
+ [{ nativeEvent: { contentOffset: { y: lastScrollY } } }],
95
+ { useNativeDriver: true }
96
+ );
97
+
98
+ const onGestureEvent = Animated.event(
99
+ [{ nativeEvent: { translationY: dragScrollY } }],
100
+ { useNativeDriver: true }
101
+ );
102
+
103
+ const onHandlerStateChange = React.useCallback(
104
+ ({ nativeEvent }) => {
105
+ if (
106
+ nativeEvent.oldState === State.ACTIVE &&
107
+ scrollPosition.current === 0
108
+ ) {
109
+ // eslint-disable-next-line prefer-const
110
+ const { velocityY, translationY } = nativeEvent;
111
+ const dragToss = 0.05;
112
+
113
+ const preparedTranslationY =
114
+ Math.abs(translationY) - lastScrollYValue.current;
115
+
116
+ if (videoModalState.mode === "MAXIMIZED") {
117
+ const endOffsetY =
118
+ lastSnap + preparedTranslationY + dragToss * velocityY + 150;
119
+
120
+ let destSnapPoint = modalSnapPoints[0];
121
+
122
+ for (const snapPoint of modalSnapPoints) {
123
+ const distFromSnap = Math.abs(snapPoint - endOffsetY);
124
+
125
+ if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
126
+ destSnapPoint = snapPoint;
127
+ }
128
+ }
129
+
130
+ setLastSnap(destSnapPoint);
131
+
132
+ if (destSnapPoint === modalSnapPoints[0]) {
133
+ translateYOffset.extractOffset();
134
+ translateYOffset.setValue(preparedTranslationY);
135
+ translateYOffset.flattenOffset();
136
+ dragScrollY.setValue(0);
137
+
138
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
139
+ } else {
140
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
141
+ }
142
+ } else {
143
+ if (translationY < 0) {
144
+ // from mini to full
145
+ setLastSnap(modalSnapPoints[0]);
146
+
147
+ translateYOffset.setValue(
148
+ modalSnapPoints[1] - preparedTranslationY
149
+ );
150
+
151
+ dragScrollY.setValue(0);
152
+
153
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
154
+ } else {
155
+ resetPlayerAnimationState();
156
+ }
157
+ }
158
+ } else {
159
+ playerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
160
+ resetPlayerAnimationState();
161
+ }
162
+ },
163
+ [lastSnap, modalSnapPoints, playerAnimationState, videoModalState.mode]
164
+ );
165
+
166
+ const onScroll = React.useCallback(({ nativeEvent }) => {
167
+ scrollPosition.current = nativeEvent.contentOffset.y;
168
+ }, []);
169
+
170
+ const onMomentumScrollEnd = React.useCallback(
171
+ ({ nativeEvent }) => {
172
+ if (nativeEvent.contentOffset.y === 0 && !isActiveGesture) {
173
+ resetScrollAnimatedValues(
174
+ lastScrollY,
175
+ lastScrollYValue,
176
+ dragScrollY,
177
+ dragVideoPlayerY
178
+ );
179
+ }
180
+ },
181
+ [isActiveGesture]
182
+ );
183
+
184
+ React.useEffect(() => {
185
+ return () => {
186
+ scrollPosition.current = 0;
187
+
188
+ resetScrollAnimatedValues(
189
+ lastScrollY,
190
+ lastScrollYValue,
191
+ dragScrollY,
192
+ dragVideoPlayerY
193
+ );
194
+ };
195
+ }, []);
196
+
197
+ React.useEffect(() => {
198
+ if (
199
+ videoModalState.mode === "MINIMIZED" &&
200
+ videoModalState.previousMode === "MAXIMIZED"
201
+ ) {
202
+ resetPlayerAnimationState();
203
+ }
204
+
205
+ if (
206
+ (videoModalState.mode === "MAXIMIZED" &&
207
+ videoModalState.previousMode === "MAXIMIZED") ||
208
+ previousItemId !== videoModalState.item?.id
209
+ ) {
210
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
211
+ setTimeout(() => resetPlayerAnimationState());
212
+ }
213
+ }, [videoModalState, previousItemId]);
214
+
215
+ React.useEffect(() => {
216
+ if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
217
+ if (
218
+ (scrollPosition.current === 0 &&
219
+ (lastScrollY as any)._value !== 0 &&
220
+ (dragScrollY as any)._value === 0 &&
221
+ (dragVideoPlayerY as any)._value === 0) ||
222
+ (scrollPosition.current !== 0 &&
223
+ ((dragScrollY as any)._value !== 0 ||
224
+ (dragVideoPlayerY as any)._value !== 0))
225
+ ) {
226
+ resetScrollAnimatedValues(
227
+ lastScrollY,
228
+ lastScrollYValue,
229
+ dragScrollY,
230
+ dragVideoPlayerY
231
+ );
232
+ }
233
+
234
+ Animated.timing(
235
+ translateYOffset,
236
+ getAnimatedConfig(modalSnapPoints[1])
237
+ ).start(() => {
238
+ setTimeout(() => {
239
+ minimiseVideoModal();
240
+
241
+ setScrollModalAnimatedValue(
242
+ translateYOffset,
243
+ modalSnapPoints[1],
244
+ setLastSnap
245
+ );
246
+
247
+ resetScrollAnimatedValues(
248
+ lastScrollY,
249
+ lastScrollYValue,
250
+ dragScrollY,
251
+ dragVideoPlayerY
252
+ );
253
+ }, 150);
254
+ });
255
+ } else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
256
+ Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
257
+ maximiseVideoModal();
258
+ setScrollModalAnimatedValue(translateYOffset, 0, setLastSnap);
259
+
260
+ resetScrollAnimatedValues(
261
+ lastScrollY,
262
+ lastScrollYValue,
263
+ dragScrollY,
264
+ dragVideoPlayerY
265
+ );
266
+
267
+ resetPlayerAnimationState();
268
+ });
269
+ }
270
+
271
+ const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
272
+ lastScrollYValue.current = value;
273
+ });
274
+
275
+ const dragListenerId = dragScrollY.addListener(({ value }) => {
276
+ const preparedValue =
277
+ isMinimizedModal && value >= 0
278
+ ? 0
279
+ : Math.round(isAudioItem ? Math.abs(value) : value);
280
+
281
+ if (
282
+ preparedValue > 0 &&
283
+ scrollPosition.current === 0 &&
284
+ playerAnimationState !== PlayerAnimationStateEnum.drag_player
285
+ ) {
286
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll &&
287
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_scroll);
288
+ }
289
+ });
290
+
291
+ return () => {
292
+ lastScrollY.removeListener(lastScrollYListenerId);
293
+ dragScrollY.removeListener(dragListenerId);
294
+ };
295
+ }, [playerAnimationState, isAudioItem, modalSnapPoints]);
296
+
297
+ const Wrapper = React.useMemo(
298
+ () => (Platform.OS === "android" ? GestureHandlerRootView : View),
299
+ []
300
+ );
301
+
302
+ return (
303
+ <Wrapper style={generalStyles.container}>
304
+ <TapGestureHandler
305
+ maxDurationMs={100000}
306
+ ref={tapHandlerRef}
307
+ maxDeltaY={lastSnap - modalSnapPoints[0]}
308
+ numberOfTaps={1}
309
+ >
310
+ <View pointerEvents="box-none">
311
+ <PanGestureHandler
312
+ enabled={isEnablePanGesture}
313
+ ref={panHandlerRef}
314
+ simultaneousHandlers={[scrollRef, tapHandlerRef]}
315
+ shouldCancelWhenOutside={isMaximazedModal}
316
+ onGestureEvent={onGestureEvent}
317
+ onHandlerStateChange={onHandlerStateChange}
318
+ activeOffsetY={[-5, 5]}
319
+ >
320
+ <Animated.View>
321
+ <NativeViewGestureHandler
322
+ ref={scrollRef}
323
+ waitFor={tapHandlerRef}
324
+ simultaneousHandlers={panHandlerRef}
325
+ >
326
+ <Animated.ScrollView
327
+ scrollEnabled={
328
+ isMaximazedModal && isNotMinimizeMaximazeAnimation
329
+ }
330
+ bounces={false}
331
+ onScrollBeginDrag={onRegisterLastScroll}
332
+ onScroll={onScroll}
333
+ onMomentumScrollEnd={onMomentumScrollEnd}
334
+ scrollEventThrottle={1}
335
+ showsVerticalScrollIndicator={false}
336
+ >
337
+ {children}
338
+ </Animated.ScrollView>
339
+ </NativeViewGestureHandler>
340
+ </Animated.View>
341
+ </PanGestureHandler>
342
+ </View>
343
+ </TapGestureHandler>
344
+ </Wrapper>
345
+ );
346
+ };
347
+
348
+ export const AnimatedScrollModal = ({ children }: Props) => {
349
+ const Component = !isTV() ? AnimatedScrollModalComponent : React.Fragment;
350
+
351
+ return <Component>{children}</Component>;
352
+ };
@@ -0,0 +1,158 @@
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
+ } = useModalAnimationContext();
38
+
39
+ const { videoModalState } = useNavigation();
40
+ const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
41
+
42
+ const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
43
+ const isMinimizedModal = videoModalState.mode === "MINIMIZED";
44
+
45
+ const isEnablePanGesture =
46
+ !isLanguageOverlayVisible && (isMaximazedModal || isMinimizedModal);
47
+
48
+ const onGestureEvent = Animated.event(
49
+ [{ nativeEvent: { translationY: dragVideoPlayerY } }],
50
+ { useNativeDriver: true }
51
+ );
52
+
53
+ const onHandlerStateChange = React.useCallback(
54
+ ({ nativeEvent }) => {
55
+ if (nativeEvent.oldState === State.ACTIVE) {
56
+ // eslint-disable-next-line prefer-const
57
+ const { velocityY, translationY } = nativeEvent;
58
+ const preparedTranslationY = Math.abs(translationY);
59
+ const dragToss = 0.05;
60
+
61
+ if (videoModalState.mode === "MAXIMIZED") {
62
+ if (translationY > 0) {
63
+ const endOffsetY =
64
+ lastSnap + preparedTranslationY + dragToss * velocityY + 200;
65
+
66
+ let destSnapPoint = modalSnapPoints[0];
67
+
68
+ for (const snapPoint of modalSnapPoints) {
69
+ const distFromSnap = Math.abs(snapPoint - endOffsetY);
70
+
71
+ if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
72
+ destSnapPoint = snapPoint;
73
+ }
74
+ }
75
+
76
+ setLastSnap(destSnapPoint);
77
+
78
+ if (destSnapPoint === modalSnapPoints[0]) {
79
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
80
+ } else {
81
+ lastScrollY.setValue(0);
82
+ lastScrollYValue.current = 0;
83
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
84
+ }
85
+ }
86
+ } else if (videoModalState.mode === "MINIMIZED") {
87
+ if (translationY < 0) {
88
+ // from mini to full
89
+ setLastSnap(modalSnapPoints[0]);
90
+
91
+ translateYOffset.setValue(
92
+ modalSnapPoints[1] - preparedTranslationY
93
+ );
94
+
95
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
96
+ } else {
97
+ resetPlayerAnimationState();
98
+ }
99
+ }
100
+ }
101
+ },
102
+ [lastSnap, modalSnapPoints, videoModalState.mode]
103
+ );
104
+
105
+ React.useEffect(() => {
106
+ const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
107
+ ({ value }) => {
108
+ if (
109
+ (isMinimizedModal && value >= 0) ||
110
+ (isMaximazedModal && value <= 0)
111
+ ) {
112
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
113
+ translateYOffset.setValue(
114
+ modalSnapPoints[isMinimizedModal ? 1 : 0]
115
+ );
116
+ }
117
+ } else {
118
+ const preparedValue = Math.round(Math.abs(value));
119
+
120
+ if (
121
+ preparedValue > 0 &&
122
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
123
+ ) {
124
+ playerAnimationState !== PlayerAnimationStateEnum.drag_player &&
125
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_player);
126
+
127
+ translateYOffset.setValue(
128
+ isMaximazedModal
129
+ ? preparedValue
130
+ : modalSnapPoints[1] - preparedValue
131
+ );
132
+ }
133
+ }
134
+ }
135
+ );
136
+
137
+ return () => {
138
+ dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
139
+ };
140
+ }, [playerAnimationState, isMinimizedModal, isMaximazedModal]);
141
+
142
+ return (
143
+ <PanGestureHandler
144
+ enabled={isEnablePanGesture}
145
+ shouldCancelWhenOutside={isMaximazedModal}
146
+ onGestureEvent={onGestureEvent}
147
+ onHandlerStateChange={onHandlerStateChange}
148
+ >
149
+ <Animated.View style={generalStyles.container}>{children}</Animated.View>
150
+ </PanGestureHandler>
151
+ );
152
+ };
153
+
154
+ export const AnimatedVideoPlayerComponent = ({ children }: Props) => {
155
+ const Component = !isTV() ? AnimatedVideoPlayer : React.Fragment;
156
+
157
+ return <Component>{children}</Component>;
158
+ };