@applicaster/zapp-react-native-ui-components 12.0.0-rc.47 → 12.0.0-rc.49

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.
@@ -0,0 +1,144 @@
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
+ 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, lastScrollY },
30
+ lastScrollYValue,
31
+ modalSnapPoints,
32
+ lastSnap,
33
+ setLastSnap,
34
+ resetPlayerAnimationState,
35
+ } = useModalAnimationContext();
36
+
37
+ const { videoModalState } = useNavigation();
38
+ const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
39
+ const isMinimizedModal = videoModalState.mode === "MINIMIZED";
40
+
41
+ const onGestureEvent = Animated.event(
42
+ [{ nativeEvent: { translationY: dragVideoPlayerY } }],
43
+ { useNativeDriver: true }
44
+ );
45
+
46
+ const onHandlerStateChange = ({ nativeEvent }) => {
47
+ if (nativeEvent.oldState === State.ACTIVE) {
48
+ // eslint-disable-next-line prefer-const
49
+ const { velocityY, translationY } = nativeEvent;
50
+ const preparedTranslationY = Math.abs(translationY);
51
+ const dragToss = 0.05;
52
+
53
+ if (videoModalState.mode === "MAXIMIZED") {
54
+ if (translationY > 0) {
55
+ const endOffsetY =
56
+ lastSnap + preparedTranslationY + dragToss * velocityY + 150;
57
+
58
+ let destSnapPoint = modalSnapPoints[0];
59
+
60
+ for (const snapPoint of modalSnapPoints) {
61
+ const distFromSnap = Math.abs(snapPoint - endOffsetY);
62
+
63
+ if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
64
+ destSnapPoint = snapPoint;
65
+ }
66
+ }
67
+
68
+ setLastSnap(destSnapPoint);
69
+
70
+ if (destSnapPoint === modalSnapPoints[0]) {
71
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
72
+ } else {
73
+ lastScrollY.setValue(0);
74
+ lastScrollYValue.current = 0;
75
+ setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
76
+ }
77
+ }
78
+ } else if (videoModalState.mode === "MINIMIZED") {
79
+ if (translationY < 0) {
80
+ // from mini to full
81
+ setLastSnap(modalSnapPoints[0]);
82
+ translateYOffset.setValue(modalSnapPoints[1] - preparedTranslationY);
83
+ setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
84
+ } else {
85
+ resetPlayerAnimationState();
86
+ }
87
+ }
88
+ }
89
+ };
90
+
91
+ React.useEffect(() => {
92
+ const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
93
+ ({ value }) => {
94
+ if (
95
+ (isMinimizedModal && value >= 0) ||
96
+ (isMaximazedModal && value <= 0)
97
+ ) {
98
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
99
+ translateYOffset.setValue(
100
+ modalSnapPoints[isMinimizedModal ? 1 : 0]
101
+ );
102
+ }
103
+ } else {
104
+ const preparedValue = Math.round(Math.abs(value));
105
+
106
+ if (
107
+ preparedValue > 0 &&
108
+ playerAnimationState !== PlayerAnimationStateEnum.drag_scroll
109
+ ) {
110
+ playerAnimationState !== PlayerAnimationStateEnum.drag_player &&
111
+ setPlayerAnimationState(PlayerAnimationStateEnum.drag_player);
112
+
113
+ translateYOffset.setValue(
114
+ isMaximazedModal
115
+ ? preparedValue
116
+ : modalSnapPoints[1] - preparedValue
117
+ );
118
+ }
119
+ }
120
+ }
121
+ );
122
+
123
+ return () => {
124
+ dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
125
+ };
126
+ }, [playerAnimationState, isMinimizedModal, isMaximazedModal]);
127
+
128
+ return (
129
+ <PanGestureHandler
130
+ enabled={isMaximazedModal || isMinimizedModal}
131
+ shouldCancelWhenOutside={isMaximazedModal}
132
+ onGestureEvent={onGestureEvent}
133
+ onHandlerStateChange={onHandlerStateChange}
134
+ >
135
+ <Animated.View style={generalStyles.container}>{children}</Animated.View>
136
+ </PanGestureHandler>
137
+ );
138
+ };
139
+
140
+ export const AnimatedVideoPlayerComponent = ({ children }: Props) => {
141
+ const Component = !isTV() ? AnimatedVideoPlayer : React.Fragment;
142
+
143
+ return <Component>{children}</Component>;
144
+ };
@@ -0,0 +1,438 @@
1
+ import React, { useRef, useState } from "react";
2
+ import { Animated, View, StyleSheet } from "react-native";
3
+
4
+ import {
5
+ useSafeAreaInsets,
6
+ useSafeAreaFrame,
7
+ } from "react-native-safe-area-context";
8
+
9
+ import {
10
+ useModalAnimationContext,
11
+ PlayerAnimationStateEnum,
12
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
13
+
14
+ import {
15
+ useGetBottomTabBarHeight,
16
+ useNavigation,
17
+ useDimensions,
18
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
19
+ import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
20
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
21
+
22
+ import {
23
+ gestureListenerHelper,
24
+ getAnimationStyle,
25
+ defaultAspectRatioWidth,
26
+ getAnimationDefaultValue,
27
+ ComponentAnimationType,
28
+ AUDIO_PLAYER_HORIZONTAL_PADDING,
29
+ } from "./utils";
30
+
31
+ type Props = {
32
+ animationType: string;
33
+ children: React.ReactNode;
34
+ style?: Record<string, any>;
35
+ additionalData?: { [key: string]: any };
36
+ };
37
+
38
+ const styles = StyleSheet.create({
39
+ flex: { flex: 1 },
40
+ });
41
+
42
+ export const AnimationView = ({
43
+ animationType,
44
+ style,
45
+ children,
46
+ additionalData = {},
47
+ }: Props) => {
48
+ const {
49
+ startComponentsAnimation,
50
+ setStartComponentsAnimation,
51
+ playerAnimationState,
52
+ minimisedHeight,
53
+ animatedValues: { dragScrollY, dragVideoPlayerY },
54
+ lastScrollYValue,
55
+ scrollPosition,
56
+ tabletLandscapePlayerTopPosition,
57
+ setTabletLandscapePlayerTopPosition,
58
+ modalSnapPoints,
59
+ } = useModalAnimationContext();
60
+
61
+ const isRTL = useIsRTL();
62
+
63
+ const {
64
+ height: screenHeight,
65
+ deviceInfo: { isTablet, isTabletLandscape },
66
+ } = useDimensions("screen", { deviceInfo: true });
67
+
68
+ const startAnimationDistance = Math.round((screenHeight * 60) / 100);
69
+ const { videoModalState } = useNavigation();
70
+ const bottomTabBarHeight = useGetBottomTabBarHeight();
71
+ const minimisedWidth = defaultAspectRatioWidth(minimisedHeight);
72
+ const insets = useSafeAreaInsets();
73
+ const { width: screenWidth } = useSafeAreaFrame();
74
+ const animationComponentRef = useRef(null);
75
+
76
+ // retrieving top position of the player for tablet landscape mode
77
+ const measureView = React.useCallback(() => {
78
+ if (isTabletLandscape && tabletLandscapePlayerTopPosition === 0) {
79
+ animationComponentRef.current.measure(
80
+ (x, y, width, height, pageX, pageY) => {
81
+ setTabletLandscapePlayerTopPosition(pageY - 20);
82
+ }
83
+ );
84
+ }
85
+ }, [tabletLandscapePlayerTopPosition]);
86
+
87
+ const [defaultValue, setDefaultValue] = useState<any>(
88
+ getAnimationDefaultValue(animationType, bottomTabBarHeight)
89
+ );
90
+
91
+ const animationValueType: string =
92
+ animationType === ComponentAnimationType.player ? "ValueXY" : "Value";
93
+
94
+ const animatedValue = useRef(
95
+ new Animated[animationValueType](defaultValue)
96
+ ).current;
97
+
98
+ const isAudioItem = React.useMemo(
99
+ () =>
100
+ videoModalState.item?.content?.type?.includes?.("audio") ||
101
+ videoModalState.item?.type?.value === "audio",
102
+ [videoModalState.item]
103
+ );
104
+
105
+ const inlineAudioPlayer = additionalData.inlineAudioPlayer;
106
+
107
+ const moveUpValue = additionalData.saveArea
108
+ ? -insets.top
109
+ : isTablet
110
+ ? isTabletLandscape && (!isAudioItem || (isAudioItem && inlineAudioPlayer))
111
+ ? -tabletLandscapePlayerTopPosition
112
+ : -130
113
+ : -50;
114
+
115
+ const moveComponentHorizontalValue = additionalData.moveValue
116
+ ? isRTL
117
+ ? additionalData.moveValue
118
+ : -additionalData.moveValue
119
+ : 0;
120
+
121
+ const calculationData = React.useMemo(
122
+ () => ({
123
+ isAudioItem,
124
+ bottomTabBarHeight,
125
+ minimisedHeight,
126
+ minimisedWidth,
127
+ defaultValue,
128
+ moveUpValue,
129
+ moveComponentHorizontalValue,
130
+ isTablet,
131
+ isTabletLandscape,
132
+ isRTL,
133
+ fromMiniPlayer: videoModalState.mode === "MINIMIZED",
134
+ inlineAudioPlayer,
135
+ }),
136
+ [
137
+ bottomTabBarHeight,
138
+ minimisedHeight,
139
+ minimisedWidth,
140
+ defaultValue,
141
+ moveUpValue,
142
+ moveComponentHorizontalValue,
143
+ videoModalState.mode,
144
+ ]
145
+ );
146
+
147
+ React.useEffect(() => {
148
+ if (additionalData.resetAnimationValue) {
149
+ animatedValue.setValue(0);
150
+ }
151
+ }, [additionalData.resetAnimationValue]);
152
+
153
+ React.useEffect(() => {
154
+ if (animationType === ComponentAnimationType.player) {
155
+ let width, height;
156
+
157
+ if (additionalData.aspectRatio) {
158
+ width = isTabletLandscape ? additionalData.width : screenWidth;
159
+
160
+ height =
161
+ (isTabletLandscape ? additionalData.width : screenWidth) /
162
+ additionalData.aspectRatio;
163
+ } else {
164
+ width =
165
+ typeof additionalData.width === "number" && additionalData.width;
166
+
167
+ height =
168
+ typeof additionalData.height === "number" && additionalData.height;
169
+ }
170
+
171
+ if (defaultValue.x === 0 && width && height) {
172
+ const value = { x: width, y: height };
173
+ setDefaultValue(value);
174
+ animatedValue.setValue(value);
175
+ }
176
+ }
177
+ }, [additionalData, screenWidth]);
178
+
179
+ const getAnimationValue = React.useCallback(
180
+ (animationType, state) => {
181
+ const defaultConfig = {
182
+ toValue: 0,
183
+ duration: state === PlayerAnimationStateEnum.minimize ? 150 : 100,
184
+ useNativeDriver: true,
185
+ };
186
+
187
+ switch (animationType) {
188
+ case ComponentAnimationType.bottomBar: {
189
+ if (state === PlayerAnimationStateEnum.minimize) {
190
+ return defaultConfig;
191
+ }
192
+
193
+ defaultConfig.toValue = defaultValue;
194
+
195
+ return defaultConfig;
196
+ }
197
+
198
+ case ComponentAnimationType.player: {
199
+ if (state === PlayerAnimationStateEnum.minimize) {
200
+ const minWidth =
201
+ isAudioItem && !inlineAudioPlayer
202
+ ? minimisedHeight
203
+ : minimisedWidth;
204
+
205
+ return {
206
+ ...defaultConfig,
207
+ toValue: { x: minWidth, y: minimisedHeight },
208
+ useNativeDriver: false,
209
+ };
210
+ }
211
+
212
+ return {
213
+ ...defaultConfig,
214
+ toValue: defaultValue,
215
+ useNativeDriver: false,
216
+ };
217
+ }
218
+
219
+ case ComponentAnimationType.componentFade: {
220
+ if (state === PlayerAnimationStateEnum.minimize) {
221
+ defaultConfig.toValue = 0;
222
+
223
+ return defaultConfig;
224
+ }
225
+
226
+ defaultConfig.toValue = defaultValue;
227
+
228
+ return defaultConfig;
229
+ }
230
+
231
+ case ComponentAnimationType.componentAppears: {
232
+ if (state === PlayerAnimationStateEnum.minimize) {
233
+ defaultConfig.toValue = 1;
234
+
235
+ return defaultConfig;
236
+ }
237
+
238
+ defaultConfig.toValue = defaultValue;
239
+
240
+ return defaultConfig;
241
+ }
242
+
243
+ case ComponentAnimationType.moveUpComponent: {
244
+ if (state === PlayerAnimationStateEnum.minimize) {
245
+ defaultConfig.toValue = moveUpValue;
246
+
247
+ return defaultConfig;
248
+ }
249
+
250
+ defaultConfig.toValue = defaultValue;
251
+
252
+ return defaultConfig;
253
+ }
254
+
255
+ case ComponentAnimationType.moveComponentHorizontal: {
256
+ if (state === PlayerAnimationStateEnum.minimize) {
257
+ defaultConfig.toValue = moveComponentHorizontalValue;
258
+
259
+ return defaultConfig;
260
+ }
261
+
262
+ defaultConfig.toValue = defaultValue;
263
+
264
+ return defaultConfig;
265
+ }
266
+
267
+ case ComponentAnimationType.audioPlayerPaddingHorizontal: {
268
+ if (state === PlayerAnimationStateEnum.minimize) {
269
+ defaultConfig.toValue = isRTL
270
+ ? AUDIO_PLAYER_HORIZONTAL_PADDING
271
+ : -AUDIO_PLAYER_HORIZONTAL_PADDING;
272
+
273
+ return defaultConfig;
274
+ }
275
+
276
+ defaultConfig.toValue = 0;
277
+
278
+ return defaultConfig;
279
+ }
280
+
281
+ default:
282
+ return defaultConfig;
283
+ }
284
+ },
285
+ [
286
+ defaultValue,
287
+ minimisedWidth,
288
+ minimisedHeight,
289
+ isAudioItem,
290
+ moveUpValue,
291
+ moveComponentHorizontalValue,
292
+ ]
293
+ );
294
+
295
+ React.useEffect(() => {
296
+ if (
297
+ playerAnimationState === PlayerAnimationStateEnum.minimize &&
298
+ startComponentsAnimation &&
299
+ videoModalState.mode === "MAXIMIZED"
300
+ ) {
301
+ Animated.timing(
302
+ animatedValue,
303
+ getAnimationValue(animationType, playerAnimationState)
304
+ ).start();
305
+ } else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
306
+ animatedValue.setValue(defaultValue);
307
+ }
308
+ }, [
309
+ playerAnimationState,
310
+ startComponentsAnimation,
311
+ videoModalState.mode,
312
+ defaultValue,
313
+ ]);
314
+
315
+ React.useEffect(() => {
316
+ const dragVideoPlayerYListenerId = dragVideoPlayerY.addListener(
317
+ ({ value }) => {
318
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
319
+ const preparedValue = Math.round(Math.abs(value));
320
+
321
+ gestureListenerHelper({
322
+ listenerValue: value,
323
+ preparedValue,
324
+ animationType,
325
+ animatedValue,
326
+ calculationData,
327
+ modalSnapPoint: modalSnapPoints[1],
328
+ startAnimationDistance,
329
+ startComponentsAnimation,
330
+ setStartComponentsAnimation,
331
+ getAnimationValue,
332
+ });
333
+ }
334
+ }
335
+ );
336
+
337
+ const dragListenerId = dragScrollY.addListener(({ value }) => {
338
+ if (
339
+ scrollPosition.current === 0 &&
340
+ playerAnimationState === PlayerAnimationStateEnum.drag_scroll
341
+ ) {
342
+ const preparedValue = Math.round(
343
+ Math.abs(value) - lastScrollYValue.current
344
+ );
345
+
346
+ gestureListenerHelper({
347
+ listenerValue: value,
348
+ preparedValue,
349
+ animationType,
350
+ animatedValue,
351
+ calculationData,
352
+ modalSnapPoint: modalSnapPoints[1],
353
+ startAnimationDistance,
354
+ startComponentsAnimation,
355
+ setStartComponentsAnimation,
356
+ getAnimationValue,
357
+ });
358
+ }
359
+ });
360
+
361
+ return () => {
362
+ dragScrollY.removeListener(dragListenerId);
363
+ dragVideoPlayerY.removeListener(dragVideoPlayerYListenerId);
364
+ };
365
+ }, [playerAnimationState, calculationData, startComponentsAnimation]);
366
+
367
+ const preparedStyles = Array.isArray(style) ? style : [style];
368
+
369
+ return (
370
+ <Animated.View
371
+ onLayout={additionalData.useLayoutMeasure && measureView}
372
+ ref={animationComponentRef}
373
+ style={[
374
+ ...preparedStyles,
375
+ additionalData.saveArea ? styles.flex : null,
376
+ (videoModalState.mode === "MAXIMIZED" ||
377
+ videoModalState.mode === "MINIMIZED") &&
378
+ getAnimationStyle(animationType, animatedValue),
379
+ ]}
380
+ >
381
+ {children}
382
+ </Animated.View>
383
+ );
384
+ };
385
+
386
+ export const AnimationComponent = (props: Props) => {
387
+ const { additionalData = {}, style } = props;
388
+
389
+ const {
390
+ videoModalState: { visible },
391
+ } = useNavigation();
392
+
393
+ const useAnimation =
394
+ visible && !additionalData.disableAnimatedComponent && !isTV();
395
+
396
+ const isReactFragment = !useAnimation && !style;
397
+
398
+ const Component = useAnimation
399
+ ? AnimationView
400
+ : style
401
+ ? View
402
+ : React.Fragment;
403
+
404
+ if (
405
+ additionalData.extraAnimation &&
406
+ typeof additionalData.extraAnimation === "object" &&
407
+ !Array.isArray(additionalData.extraAnimation) &&
408
+ !!Object.keys(additionalData.extraAnimation).length
409
+ ) {
410
+ const animationType = Object.keys(additionalData.extraAnimation)[0];
411
+ const animationProps = additionalData.extraAnimation[animationType] || {};
412
+ delete additionalData.extraAnimation[animationType];
413
+
414
+ return (
415
+ <Component {...(isReactFragment ? null : props)}>
416
+ <AnimationComponent
417
+ {...animationProps}
418
+ animationType={animationType}
419
+ additionalData={{
420
+ ...animationProps.additionalData,
421
+ extraAnimation:
422
+ !!Object.keys(additionalData.extraAnimation).length &&
423
+ additionalData.extraAnimation,
424
+ }}
425
+ >
426
+ {props.children}
427
+ </AnimationComponent>
428
+ </Component>
429
+ );
430
+ }
431
+
432
+ if (isReactFragment) {
433
+ // @ts-ignore
434
+ return <Component>{props.children}</Component>;
435
+ }
436
+
437
+ return <Component {...props}>{props.children}</Component>;
438
+ };