@applicaster/zapp-react-native-ui-components 14.0.0-rc.9 → 15.0.0-rc.1

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 (163) hide show
  1. package/Components/AnimatedInOut/index.tsx +5 -3
  2. package/Components/AudioPlayer/index.tsx +15 -0
  3. package/Components/AudioPlayer/mobile/Layout.tsx +66 -0
  4. package/Components/AudioPlayer/{__tests__/__snapshots__/audioPlayer.test.js.snap → mobile/__tests__/__snapshots__/audioPlayerMobileLayout.test.js.snap} +2 -2
  5. package/Components/AudioPlayer/mobile/__tests__/audioPlayerMobileLayout.test.js +18 -0
  6. package/Components/AudioPlayer/mobile/index.tsx +18 -0
  7. package/Components/AudioPlayer/{Artwork.tsx → tv/Artwork.tsx} +3 -2
  8. package/Components/AudioPlayer/{Channel.tsx → tv/Channel.tsx} +7 -7
  9. package/Components/AudioPlayer/tv/Layout.tsx +168 -0
  10. package/Components/AudioPlayer/{Runtime.tsx → tv/Runtime.tsx} +7 -1
  11. package/Components/AudioPlayer/{Summary.tsx → tv/Summary.tsx} +6 -2
  12. package/Components/AudioPlayer/{Title.tsx → tv/Title.tsx} +6 -2
  13. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/Runtime.test.js.snap +2 -2
  14. package/Components/AudioPlayer/tv/__tests__/__snapshots__/audioPlayer.test.js.snap +164 -0
  15. package/Components/AudioPlayer/tv/__tests__/__snapshots__/channel.test.js.snap +19 -0
  16. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/summary.test.js.snap +1 -2
  17. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/title.test.js.snap +1 -2
  18. package/Components/AudioPlayer/{__tests__ → tv/__tests__}/audioPlayer.test.js +7 -3
  19. package/Components/AudioPlayer/{helpers.tsx → tv/helpers.tsx} +11 -5
  20. package/Components/AudioPlayer/{AudioPlayer.tsx → tv/index.tsx} +17 -58
  21. package/Components/AudioPlayer/types.ts +40 -0
  22. package/Components/BaseFocusable/index.tsx +23 -12
  23. package/Components/Cell/Cell.tsx +91 -64
  24. package/Components/Cell/CellWithFocusable.tsx +3 -0
  25. package/Components/Cell/__tests__/CellWIthFocusable.test.js +3 -2
  26. package/Components/Cell/index.js +7 -3
  27. package/Components/ComponentResolver/index.ts +1 -1
  28. package/Components/FeedLoader/FeedLoader.tsx +7 -16
  29. package/Components/FeedLoader/FeedLoaderHOC.tsx +21 -0
  30. package/Components/FeedLoader/index.js +2 -8
  31. package/Components/Focusable/Focusable.tsx +12 -3
  32. package/Components/Focusable/FocusableTvOS.tsx +5 -5
  33. package/Components/Focusable/FocusableiOS.tsx +2 -2
  34. package/Components/Focusable/Touchable.tsx +5 -3
  35. package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
  36. package/Components/Focusable/index.android.tsx +19 -11
  37. package/Components/Focusable/index.tsx +1 -1
  38. package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
  39. package/Components/FocusableList/FocusableItem.tsx +4 -3
  40. package/Components/FocusableList/FocusableListItemWrapper.tsx +2 -1
  41. package/Components/FocusableList/hooks/useCellState.android.ts +13 -3
  42. package/Components/FocusableList/index.tsx +20 -9
  43. package/Components/FreezeWithCallback/__tests__/index.test.tsx +67 -43
  44. package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +42 -59
  45. package/Components/GeneralContentScreen/utils/useCurationAPI.ts +13 -10
  46. package/Components/HandlePlayable/HandlePlayable.tsx +25 -9
  47. package/Components/HookRenderer/HookRenderer.tsx +5 -1
  48. package/Components/Layout/TV/LayoutBackground.tsx +1 -1
  49. package/Components/Layout/TV/__tests__/index.test.tsx +0 -1
  50. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +6 -2
  51. package/Components/MasterCell/DefaultComponents/Button.tsx +1 -1
  52. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -39
  53. package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +1 -1
  54. package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +1 -1
  55. package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +65 -17
  56. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +21 -3
  57. package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +6 -3
  58. package/Components/MasterCell/DefaultComponents/Text/index.tsx +26 -6
  59. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +10 -10
  60. package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +18 -18
  61. package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +10 -10
  62. package/Components/MasterCell/elementMapper.tsx +1 -2
  63. package/Components/MasterCell/index.tsx +1 -1
  64. package/Components/MasterCell/utils/behaviorProvider.ts +82 -14
  65. package/Components/MasterCell/utils/index.ts +11 -5
  66. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
  67. package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
  68. package/Components/OfflineHandler/__tests__/index.test.tsx +26 -35
  69. package/Components/PlayerContainer/ErrorDisplay/index.ts +1 -1
  70. package/Components/PlayerContainer/PlayerContainer.tsx +46 -33
  71. package/Components/PlayerContainer/ProgramInfo/index.tsx +1 -1
  72. package/Components/PlayerContainer/index.ts +1 -1
  73. package/Components/PlayerImageBackground/index.tsx +1 -1
  74. package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
  75. package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +378 -0
  76. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +2 -2
  77. package/Components/River/RefreshControl.tsx +11 -17
  78. package/Components/River/RiverItem.tsx +3 -0
  79. package/Components/River/TV/River.tsx +2 -17
  80. package/Components/River/TV/index.tsx +3 -1
  81. package/Components/River/TV/withPipesV1DataLoader.tsx +43 -0
  82. package/Components/River/TV/withRiverDataLoader.tsx +17 -0
  83. package/Components/River/TV/withTVEventHandler.tsx +1 -1
  84. package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
  85. package/Components/River/__tests__/river.test.js +12 -26
  86. package/Components/River/index.tsx +1 -1
  87. package/Components/Screen/__tests__/Screen.test.tsx +28 -29
  88. package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
  89. package/Components/Screen/navigationHandler.ts +20 -2
  90. package/Components/ScreenResolver/index.tsx +15 -0
  91. package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
  92. package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
  93. package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
  94. package/Components/ScreenRevealManager/index.ts +1 -0
  95. package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
  96. package/Components/Tabs/TV/Tabs.android.tsx +1 -3
  97. package/Components/Tabs/Tabs.tsx +2 -3
  98. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +13 -0
  99. package/Components/TextInputTv/index.tsx +11 -0
  100. package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
  101. package/Components/Touchable/__tests__/touchable.test.tsx +12 -17
  102. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
  103. package/Components/VideoLive/animationUtils.ts +3 -3
  104. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +3 -9
  105. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
  106. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
  107. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +73 -29
  108. package/Components/VideoModal/PlayerDetails.tsx +24 -2
  109. package/Components/VideoModal/PlayerWrapper.tsx +26 -142
  110. package/Components/VideoModal/VideoModal.tsx +3 -17
  111. package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +5 -5
  112. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
  113. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -240
  114. package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +9 -1
  115. package/Components/VideoModal/hooks/index.ts +0 -2
  116. package/Components/VideoModal/hooks/useDelayedPlayerDetails.ts +40 -15
  117. package/Components/VideoModal/hooks/useModalSize.ts +18 -2
  118. package/Components/VideoModal/hooks/utils/__tests__/showDetails.test.ts +2 -2
  119. package/Components/VideoModal/hooks/utils/index.ts +4 -0
  120. package/Components/VideoModal/utils.ts +6 -0
  121. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
  122. package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
  123. package/Components/Viewport/VisibilitySensor/VisibilitySensor.tsx +3 -3
  124. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/index.ts +3 -3
  125. package/Contexts/CellFocusedStateContext/index.tsx +27 -0
  126. package/Contexts/ConfigutaionContext/__tests__/ConfigurationProvider.test.tsx +3 -3
  127. package/Contexts/ScreenContext/index.tsx +46 -6
  128. package/Decorators/ConfigurationWrapper/__tests__/withConfigurationProvider.test.tsx +3 -3
  129. package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
  130. package/Decorators/RiverFeedLoader/__tests__/__snapshots__/riverFeedLoader.test.tsx.snap +221 -209
  131. package/Decorators/RiverFeedLoader/__tests__/riverFeedLoader.test.tsx +14 -16
  132. package/Decorators/RiverFeedLoader/__tests__/utils.test.ts +0 -20
  133. package/Decorators/RiverFeedLoader/index.tsx +22 -4
  134. package/Decorators/RiverFeedLoader/utils/index.ts +0 -18
  135. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +3 -6
  136. package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -0
  137. package/Decorators/ZappPipesDataConnector/__tests__/NullFeedResolver.test.tsx +78 -0
  138. package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +205 -0
  139. package/Decorators/ZappPipesDataConnector/__tests__/StaticFeedResolver.test.tsx +251 -0
  140. package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +368 -0
  141. package/Decorators/ZappPipesDataConnector/__tests__/utils.test.ts +39 -0
  142. package/Decorators/ZappPipesDataConnector/index.tsx +26 -293
  143. package/Decorators/ZappPipesDataConnector/resolvers/NullFeedResolver.tsx +25 -0
  144. package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +87 -0
  145. package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +266 -0
  146. package/Decorators/ZappPipesDataConnector/types.ts +29 -0
  147. package/Decorators/ZappPipesDataConnector/utils/mongoFilter.ts +738 -0
  148. package/Decorators/ZappPipesDataConnector/utils/useFilter.tsx +157 -0
  149. package/events/index.ts +3 -0
  150. package/package.json +5 -10
  151. package/Components/AudioPlayer/AudioPlayerLayout.tsx +0 -202
  152. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +0 -66
  153. package/Components/AudioPlayer/__tests__/__snapshots__/channel.test.js.snap +0 -28
  154. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +0 -26
  155. package/Components/AudioPlayer/index.ts +0 -1
  156. package/Components/River/__tests__/__snapshots__/river.test.js.snap +0 -27
  157. package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
  158. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/Runtime.test.js +0 -0
  159. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/__snapshots__/artWork.test.js.snap +0 -0
  160. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/artWork.test.js +0 -0
  161. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/channel.test.js +0 -0
  162. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/summary.test.js +0 -0
  163. /package/Components/AudioPlayer/{__tests__ → tv/__tests__}/title.test.js +0 -0
@@ -0,0 +1,294 @@
1
+ import React from "react";
2
+ import { Animated, StyleSheet, View } from "react-native";
3
+
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+
6
+ import {
7
+ PlayerAnimationStateEnum,
8
+ useModalAnimationContext,
9
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
10
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
11
+ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
12
+
13
+ import {
14
+ resetScrollAnimatedValues,
15
+ setScrollModalAnimatedValue,
16
+ } from "./utils";
17
+
18
+ import { DURATION_TO_MINIMIZE } from "./const";
19
+
20
+ const getAnimatedConfig = (toValue) => {
21
+ return {
22
+ toValue,
23
+ duration: DURATION_TO_MINIMIZE,
24
+ useNativeDriver: true,
25
+ };
26
+ };
27
+
28
+ const generalStyles = StyleSheet.create({
29
+ container: {
30
+ flex: 1,
31
+ },
32
+ });
33
+
34
+ type Props = {
35
+ children: React.ReactNode;
36
+ };
37
+
38
+ export const AnimatedScrollModalComponent = ({ children }: Props) => {
39
+ const {
40
+ isActiveGesture,
41
+ playerAnimationState,
42
+ setPlayerAnimationState,
43
+ resetPlayerAnimationState,
44
+ animatedValues: {
45
+ lastScrollY,
46
+ dragScrollY,
47
+ dragVideoPlayerY,
48
+ translateYOffset,
49
+ },
50
+ lastScrollYValue,
51
+ scrollPosition,
52
+ modalSnapPoints,
53
+ setLastSnap,
54
+ setStartComponentsAnimation,
55
+ } = useModalAnimationContext();
56
+
57
+ const [enableGesture, setIEnableGesture] = React.useState<boolean>(true);
58
+
59
+ const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
60
+ useNavigation();
61
+
62
+ const {
63
+ mode: videoModalMode,
64
+ previousMode: previousVideoModalMode,
65
+ item: videoModalItem,
66
+ } = videoModalState;
67
+
68
+ const isMaximizedModal: boolean = videoModalMode === "MAXIMIZED";
69
+ const isMinimizedModal: boolean = videoModalMode === "MINIMIZED";
70
+ const previousItemId = usePrevious(videoModalItem?.id);
71
+
72
+ const isNotMinimizeMaximazeAnimation =
73
+ playerAnimationState !== PlayerAnimationStateEnum.minimize &&
74
+ playerAnimationState !== PlayerAnimationStateEnum.maximize;
75
+
76
+ const isAudioItem = React.useMemo(
77
+ () =>
78
+ videoModalItem?.content?.type?.includes?.("audio") ||
79
+ videoModalItem?.type?.value === "audio",
80
+ [videoModalItem]
81
+ );
82
+
83
+ const onRegisterLastScroll = Animated.event(
84
+ [{ nativeEvent: { contentOffset: { y: lastScrollY } } }],
85
+ { useNativeDriver: true }
86
+ );
87
+
88
+ const onScroll = React.useCallback(({ nativeEvent }) => {
89
+ scrollPosition.current = nativeEvent.contentOffset.y;
90
+ }, []);
91
+
92
+ // Workaround for onMomentumScrollEnd issue
93
+ // https://github.com/facebook/react-native/issues/32696#issuecomment-1104217223
94
+ const canMomentum = React.useRef(false);
95
+
96
+ const onMomentumScrollBegin = React.useCallback(() => {
97
+ canMomentum.current = true;
98
+ }, []);
99
+
100
+ const onMomentumScrollEnd = React.useCallback(
101
+ ({ nativeEvent }) => {
102
+ if (canMomentum.current && !isActiveGesture) {
103
+ if (nativeEvent.contentOffset.y === 0) {
104
+ resetScrollAnimatedValues(
105
+ lastScrollY,
106
+ lastScrollYValue,
107
+ dragScrollY,
108
+ dragVideoPlayerY
109
+ );
110
+
111
+ setIEnableGesture(true);
112
+ } else {
113
+ setIEnableGesture(false);
114
+ }
115
+
116
+ canMomentum.current = false;
117
+ }
118
+ },
119
+ [isActiveGesture]
120
+ );
121
+
122
+ React.useEffect(() => {
123
+ return () => {
124
+ scrollPosition.current = 0;
125
+
126
+ resetScrollAnimatedValues(
127
+ lastScrollY,
128
+ lastScrollYValue,
129
+ dragScrollY,
130
+ dragVideoPlayerY
131
+ );
132
+ };
133
+ }, []);
134
+
135
+ React.useEffect(() => {
136
+ if (
137
+ videoModalMode === "MAXIMIZED" &&
138
+ !enableGesture &&
139
+ scrollPosition.current === 0
140
+ ) {
141
+ setIEnableGesture(true);
142
+ }
143
+
144
+ if (
145
+ videoModalMode === "MINIMIZED" &&
146
+ previousVideoModalMode === "MAXIMIZED"
147
+ ) {
148
+ // set animation to the minimize values if moving from the player to another screen
149
+ if (playerAnimationState === null) {
150
+ setScrollModalAnimatedValue(
151
+ translateYOffset,
152
+ modalSnapPoints[1],
153
+ setLastSnap
154
+ );
155
+
156
+ resetScrollAnimatedValues(
157
+ lastScrollY,
158
+ lastScrollYValue,
159
+ dragScrollY,
160
+ dragVideoPlayerY
161
+ );
162
+ }
163
+ } else if (
164
+ playerAnimationState === null &&
165
+ ((previousItemId === videoModalItem?.id &&
166
+ videoModalMode === "MAXIMIZED" &&
167
+ (previousVideoModalMode === "MINIMIZED" ||
168
+ previousVideoModalMode === "MAXIMIZED")) ||
169
+ (previousItemId !== videoModalItem?.id &&
170
+ videoModalMode !== "FULLSCREEN"))
171
+ ) {
172
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximize);
173
+ }
174
+ }, [videoModalMode, previousVideoModalMode, videoModalItem]);
175
+
176
+ React.useEffect(() => {
177
+ if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
178
+ if (
179
+ (scrollPosition.current === 0 &&
180
+ (lastScrollY as any)._value !== 0 &&
181
+ (dragScrollY as any)._value === 0 &&
182
+ (dragVideoPlayerY as any)._value === 0) ||
183
+ (scrollPosition.current !== 0 &&
184
+ ((dragScrollY as any)._value !== 0 ||
185
+ (dragVideoPlayerY as any)._value !== 0))
186
+ ) {
187
+ resetScrollAnimatedValues(
188
+ lastScrollY,
189
+ lastScrollYValue,
190
+ dragScrollY,
191
+ dragVideoPlayerY
192
+ );
193
+ }
194
+
195
+ Animated.timing(
196
+ translateYOffset,
197
+ getAnimatedConfig(modalSnapPoints[1])
198
+ ).start(() => {
199
+ minimiseVideoModal();
200
+
201
+ setScrollModalAnimatedValue(
202
+ translateYOffset,
203
+ modalSnapPoints[1],
204
+ setLastSnap
205
+ );
206
+
207
+ resetScrollAnimatedValues(
208
+ lastScrollY,
209
+ lastScrollYValue,
210
+ dragScrollY,
211
+ dragVideoPlayerY
212
+ );
213
+
214
+ resetPlayerAnimationState();
215
+ });
216
+ } else if (playerAnimationState === PlayerAnimationStateEnum.maximize) {
217
+ Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
218
+ maximiseVideoModal();
219
+ setScrollModalAnimatedValue(translateYOffset, 0, setLastSnap);
220
+
221
+ resetScrollAnimatedValues(
222
+ lastScrollY,
223
+ lastScrollYValue,
224
+ dragScrollY,
225
+ dragVideoPlayerY
226
+ );
227
+
228
+ resetPlayerAnimationState();
229
+ });
230
+ }
231
+ }, [playerAnimationState]);
232
+
233
+ React.useEffect(() => {
234
+ const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
235
+ lastScrollYValue.current = value;
236
+ });
237
+
238
+ const dragListenerId = dragScrollY.addListener(({ value }) => {
239
+ const preparedValue =
240
+ isMinimizedModal && value >= 0
241
+ ? 0
242
+ : Math.round(isAudioItem ? Math.abs(value) : value);
243
+
244
+ if (
245
+ preparedValue > 0 &&
246
+ scrollPosition.current === 0 &&
247
+ playerAnimationState !== PlayerAnimationStateEnum.drag_player &&
248
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
249
+ ) {
250
+ isMinimizedModal && setStartComponentsAnimation(true);
251
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_scroll);
252
+ }
253
+ });
254
+
255
+ return () => {
256
+ lastScrollY.removeListener(lastScrollYListenerId);
257
+ dragScrollY.removeListener(dragListenerId);
258
+ };
259
+ }, [playerAnimationState, isAudioItem, isMinimizedModal]);
260
+
261
+ const scrollEnabled = isMaximizedModal && isNotMinimizeMaximazeAnimation;
262
+
263
+ return (
264
+ <View style={generalStyles.container}>
265
+ <View pointerEvents="box-none">
266
+ <Animated.View>
267
+ <Animated.ScrollView
268
+ scrollEnabled={scrollEnabled}
269
+ bounces={false}
270
+ onScrollBeginDrag={onRegisterLastScroll}
271
+ onScroll={onScroll}
272
+ onMomentumScrollBegin={onMomentumScrollBegin}
273
+ onMomentumScrollEnd={onMomentumScrollEnd}
274
+ scrollEventThrottle={1}
275
+ showsVerticalScrollIndicator={false}
276
+ >
277
+ {children}
278
+ </Animated.ScrollView>
279
+ </Animated.View>
280
+ </View>
281
+ </View>
282
+ );
283
+ };
284
+
285
+ export const AnimatedScrollModal = ({ children }: Props) => {
286
+ const {
287
+ videoModalState: { visible },
288
+ } = useNavigation();
289
+
290
+ const Component =
291
+ !isTV() && visible ? AnimatedScrollModalComponent : React.Fragment;
292
+
293
+ return <Component>{children}</Component>;
294
+ };
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import { Animated, StyleSheet } from "react-native";
3
+
4
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
5
+
6
+ import {
7
+ useModalAnimationContext,
8
+ PlayerAnimationStateEnum,
9
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
10
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
11
+
12
+ const generalStyles = StyleSheet.create({
13
+ container: {
14
+ flex: 1,
15
+ width: "100%",
16
+ position: "absolute",
17
+ zIndex: 201,
18
+ },
19
+ });
20
+
21
+ type Props = {
22
+ children: React.ReactNode;
23
+ };
24
+
25
+ export const AnimatedVideoPlayer = ({ children }: Props) => {
26
+ const {
27
+ playerAnimationState,
28
+ setPlayerAnimationState,
29
+ animatedValues: { translateYOffset, dragVideoPlayerY },
30
+ modalSnapPoints,
31
+ setStartComponentsAnimation,
32
+ } = useModalAnimationContext();
33
+
34
+ const {
35
+ videoModalState: { mode: videoModalMode },
36
+ } = useNavigation();
37
+
38
+ const isMaximazedModal = videoModalMode === "MAXIMIZED";
39
+ const isMinimizedModal = videoModalMode === "MINIMIZED";
40
+
41
+ React.useEffect(() => {
42
+ const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
43
+ ({ value }) => {
44
+ if (
45
+ (isMinimizedModal && value >= 0) ||
46
+ (isMaximazedModal && value <= 0)
47
+ ) {
48
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
49
+ translateYOffset.setValue(
50
+ modalSnapPoints[isMinimizedModal ? 1 : 0]
51
+ );
52
+ }
53
+ } else {
54
+ const preparedValue = Math.round(Math.abs(value));
55
+
56
+ if (
57
+ preparedValue > 0 &&
58
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
59
+ ) {
60
+ if (playerAnimationState !== PlayerAnimationStateEnum.drag_player) {
61
+ isMinimizedModal && setStartComponentsAnimation(true);
62
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_player);
63
+ }
64
+
65
+ translateYOffset.setValue(
66
+ isMaximazedModal
67
+ ? preparedValue
68
+ : modalSnapPoints[1] - preparedValue
69
+ );
70
+ }
71
+ }
72
+ }
73
+ );
74
+
75
+ return () => {
76
+ dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
77
+ };
78
+ }, [playerAnimationState, isMinimizedModal, isMaximazedModal]);
79
+
80
+ return (
81
+ <Animated.View style={generalStyles.container}>{children}</Animated.View>
82
+ );
83
+ };
84
+
85
+ export const AnimatedVideoPlayerComponent = ({ children }: Props) => {
86
+ const {
87
+ videoModalState: { visible },
88
+ } = useNavigation();
89
+
90
+ const Component = !isTV() && visible ? AnimatedVideoPlayer : React.Fragment;
91
+
92
+ return <Component>{children}</Component>;
93
+ };
@@ -1,5 +1,5 @@
1
- import React, { useEffect } from "react";
2
- import { Animated } from "react-native";
1
+ import React, { useEffect, useMemo } from "react";
2
+ import { Animated, Dimensions } from "react-native";
3
3
 
4
4
  import {
5
5
  useSafeAreaInsets,
@@ -11,6 +11,7 @@ import { isLive } from "@applicaster/zapp-react-native-utils/playerUtils";
11
11
 
12
12
  import { PROGRESS_BAR_HEIGHT } from "./utils";
13
13
  import { useConfiguration } from "../utils";
14
+ import { useIsTabletLandscape } from "@applicaster/zapp-react-native-utils/reactHooks/device/useMemoizedIsTablet";
14
15
 
15
16
  export enum PlayerAnimationStateEnum {
16
17
  minimize = "minimize",
@@ -23,6 +24,7 @@ export enum PlayerAnimationStateEnum {
23
24
  export type PlayerAnimationStateT = number | PlayerAnimationStateEnum | null;
24
25
 
25
26
  export type ModalAnimationContextT = {
27
+ yTranslate: React.MutableRefObject<Animated.Value | null>;
26
28
  isActiveGesture: boolean;
27
29
  playerAnimationState: PlayerAnimationStateT;
28
30
  setPlayerAnimationState: (value: PlayerAnimationStateT) => void;
@@ -48,6 +50,7 @@ export type ModalAnimationContextT = {
48
50
  };
49
51
 
50
52
  export const ReactContext = React.createContext<ModalAnimationContextT>({
53
+ yTranslate: React.createRef<Animated.Value | null>(),
51
54
  isActiveGesture: false,
52
55
  playerAnimationState: null,
53
56
  setPlayerAnimationState: () => null,
@@ -73,6 +76,10 @@ export const ReactContext = React.createContext<ModalAnimationContextT>({
73
76
  });
74
77
 
75
78
  const Provider = ({ children }: { children: React.ReactNode }) => {
79
+ const yTranslate = React.useRef(
80
+ new Animated.Value(Dimensions.get("window").height)
81
+ );
82
+
76
83
  const [playerAnimationState, setPlayerAnimationState] =
77
84
  React.useState<PlayerAnimationStateT>(null);
78
85
 
@@ -96,13 +103,6 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
96
103
  setStartComponentsAnimation(false);
97
104
  }, []);
98
105
 
99
- useEffect(() => {
100
- // Reset player animation state when video modal is closed
101
- if (!visible) {
102
- resetPlayerAnimationState();
103
- }
104
- }, [visible, resetPlayerAnimationState]);
105
-
106
106
  // Animated values
107
107
  const lastScrollY = React.useRef(new Animated.Value(0)).current;
108
108
  const dragScrollY = React.useRef(new Animated.Value(0)).current;
@@ -115,6 +115,29 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
115
115
  const { bottom: bottomSafeArea } = useSafeAreaInsets();
116
116
  const bottomTabBarHeight = useGetBottomTabBarHeight();
117
117
  const startComponentsAnimationDistance = Math.round((height * 60) / 100);
118
+ const isTabletLandscape = useIsTabletLandscape();
119
+ const windowDimensions = Dimensions.get("window");
120
+
121
+ useEffect(() => {
122
+ // Reset player animation state when video modal is closed
123
+ if (!visible) {
124
+ resetPlayerAnimationState();
125
+
126
+ if (!isTabletLandscape) {
127
+ // restore to portrait ( in portrait mode height is bigger)
128
+ if (windowDimensions.height > windowDimensions.width) {
129
+ yTranslate.current?.setValue(windowDimensions.height);
130
+ }
131
+ } else {
132
+ yTranslate.current?.setValue(windowDimensions.height);
133
+ }
134
+ }
135
+ }, [
136
+ visible,
137
+ resetPlayerAnimationState,
138
+ windowDimensions.height,
139
+ isTabletLandscape,
140
+ ]);
118
141
 
119
142
  React.useEffect(() => {
120
143
  if (visible && mode === "MAXIMIZED" && height !== safeAreaFrameHeight) {
@@ -140,30 +163,51 @@ const Provider = ({ children }: { children: React.ReactNode }) => {
140
163
 
141
164
  return (
142
165
  <ReactContext.Provider
143
- value={{
144
- startComponentsAnimation,
145
- setStartComponentsAnimation,
146
- isActiveGesture: playerAnimationState !== null,
147
- playerAnimationState,
148
- setPlayerAnimationState,
149
- resetPlayerAnimationState,
150
- minimisedHeight,
151
- animatedValues: {
166
+ value={useMemo(
167
+ () => ({
168
+ yTranslate,
169
+ startComponentsAnimation,
170
+ setStartComponentsAnimation,
171
+ isActiveGesture: playerAnimationState !== null,
172
+ playerAnimationState,
173
+ setPlayerAnimationState,
174
+ resetPlayerAnimationState,
175
+ minimisedHeight,
176
+ animatedValues: {
177
+ lastScrollY,
178
+ dragScrollY,
179
+ dragVideoPlayerY,
180
+ translateYOffset,
181
+ },
182
+ lastScrollYValue,
183
+ scrollPosition,
184
+ modalSnapPoints,
185
+ lastSnap,
186
+ setLastSnap,
187
+ tabletLandscapePlayerTopPosition,
188
+ setTabletLandscapePlayerTopPosition,
189
+ startComponentsAnimationDistance,
190
+ progressBarHeight,
191
+ }),
192
+ // eslint-disable-next-line react-hooks/exhaustive-deps
193
+ [
194
+ startComponentsAnimation,
195
+ playerAnimationState,
196
+ minimisedHeight,
152
197
  lastScrollY,
153
198
  dragScrollY,
154
199
  dragVideoPlayerY,
155
200
  translateYOffset,
156
- },
157
- lastScrollYValue,
158
- scrollPosition,
159
- modalSnapPoints,
160
- lastSnap,
161
- setLastSnap,
162
- tabletLandscapePlayerTopPosition,
163
- setTabletLandscapePlayerTopPosition,
164
- startComponentsAnimationDistance,
165
- progressBarHeight,
166
- }}
201
+ lastSnap,
202
+ modalSnapPoints,
203
+ lastScrollYValue,
204
+ scrollPosition,
205
+ tabletLandscapePlayerTopPosition,
206
+ startComponentsAnimationDistance,
207
+ progressBarHeight,
208
+ isLiveItem,
209
+ ]
210
+ )}
167
211
  >
168
212
  {children}
169
213
  </ReactContext.Provider>
@@ -11,6 +11,8 @@ import { useTargetScreenData } from "@applicaster/zapp-react-native-utils/reactH
11
11
  import { ComponentsMap } from "@applicaster/zapp-react-native-ui-components/Components/River/ComponentsMap";
12
12
  import { useSafeAreaInsets } from "react-native-safe-area-context";
13
13
  import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
14
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
15
+ import { useDelayedPlayerDetails } from "./hooks";
14
16
 
15
17
  const { width: SCREEN_WIDTH } = Dimensions.get("screen");
16
18
 
@@ -26,6 +28,10 @@ type Props = {
26
28
  isTabletLandscape?: boolean;
27
29
  isAudioPlayer?: boolean;
28
30
  isTablet?: boolean;
31
+ inline?: any;
32
+ docked?: boolean;
33
+ isModal?: boolean;
34
+ pip?: boolean;
29
35
  };
30
36
 
31
37
  const containerStyle = ({
@@ -42,8 +48,24 @@ export const PlayerDetails = ({
42
48
  configuration,
43
49
  isTabletLandscape = false,
44
50
  isAudioPlayer,
45
- isTablet = false,
51
+ inline,
52
+ docked,
53
+ isModal,
54
+ pip,
46
55
  }: Props) => {
56
+ const isInlineModal = inline && isModal;
57
+
58
+ // Mounting the PlayerDetails component is a resource-intensive process.
59
+ // Therefore, for performance reasons, we mount it with a delay to make the rotation process as smooth as possible.
60
+ // The flow is as follows: the rotation occurs first, and then, after a short delay, we mount the PlayerDetails component.
61
+ // This helps to avoid blocking the rotation and any animations related to the rotation.
62
+ const isShowPlayerDetails = useDelayedPlayerDetails({
63
+ isInline: isInlineModal,
64
+ isDocked: docked,
65
+ isPip: pip,
66
+ });
67
+
68
+ const isTablet = useIsTablet();
47
69
  const screenData = useTargetScreenData(entry);
48
70
  const insets = useSafeAreaInsets();
49
71
 
@@ -79,7 +101,7 @@ export const PlayerDetails = ({
79
101
  }
80
102
  }, [isAudioPlayer]);
81
103
 
82
- if (isNilOrEmpty(screenData?.ui_components)) {
104
+ if (isNilOrEmpty(screenData?.ui_components) || !isShowPlayerDetails) {
83
105
  return null;
84
106
  }
85
107