@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4802689107 → 12.0.0-alpha.5031512294
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.
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +14 -1
- package/Components/MasterCell/utils/index.ts +16 -5
- package/Components/PlayerContainer/PlayerContainer.tsx +10 -1
- package/Components/PlayerImageBackground/index.tsx +34 -8
- package/Components/River/__tests__/componentsMap.test.js +6 -0
- package/Components/Screen/index.tsx +1 -1
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +20 -5
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +335 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +144 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
- package/Components/VideoModal/PlayerWrapper.tsx +64 -41
- package/Components/VideoModal/VideoModal.tsx +8 -25
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +6 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +151 -119
- package/Components/VideoModal/utils.ts +3 -3
- package/package.json +5 -5
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
|
@@ -177,10 +177,23 @@ const getPlayerConfig = (player_screen_id, actionIdentifier) => {
|
|
|
177
177
|
const positionAbsolute: ViewStyle = { position: "absolute" };
|
|
178
178
|
|
|
179
179
|
const LiveImageComponent = (props: LiveImageProps) => {
|
|
180
|
-
const {
|
|
180
|
+
const {
|
|
181
|
+
item,
|
|
182
|
+
style: componentStyle,
|
|
183
|
+
cellUUID,
|
|
184
|
+
imageKey,
|
|
185
|
+
actionIdentifier,
|
|
186
|
+
state,
|
|
187
|
+
} = props;
|
|
181
188
|
|
|
182
189
|
const component = useUIComponentContext();
|
|
183
190
|
|
|
191
|
+
// Fix for blinking on state change
|
|
192
|
+
const style = React.useMemo(
|
|
193
|
+
() => ({ ...componentStyle, backgroundColor: "transparent" }),
|
|
194
|
+
[componentStyle]
|
|
195
|
+
);
|
|
196
|
+
|
|
184
197
|
const componentType = React.useMemo(
|
|
185
198
|
() => getPropComponentType(component),
|
|
186
199
|
[component?.id]
|
|
@@ -125,13 +125,24 @@ export const useFilterChildren = <
|
|
|
125
125
|
|
|
126
126
|
const filteredChildren = children.filter((child) => {
|
|
127
127
|
const item = child.props.item;
|
|
128
|
-
const
|
|
128
|
+
const actionIdentifier = child.props.pluginIdentifier;
|
|
129
|
+
const action = actions.actions[actionIdentifier];
|
|
130
|
+
|
|
129
131
|
// context value of specific plugin
|
|
130
|
-
|
|
132
|
+
if (action?.module && action.module.context) {
|
|
133
|
+
const currentValue = action.module.context._currentValue;
|
|
134
|
+
|
|
135
|
+
return currentValue?.isActionAvailable
|
|
136
|
+
? currentValue.isActionAvailable(item)
|
|
137
|
+
: true;
|
|
138
|
+
}
|
|
131
139
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
:
|
|
140
|
+
masterCellLogger.error({
|
|
141
|
+
message: `Action plugin for ${actionIdentifier} could not be found, check the configuration of your action button`,
|
|
142
|
+
data: { item, action: child.props.pluginIdentifier },
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
return false;
|
|
135
146
|
});
|
|
136
147
|
|
|
137
148
|
return filteredChildren;
|
|
@@ -54,6 +54,8 @@ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
|
54
54
|
import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayNextOverlay";
|
|
55
55
|
import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
|
|
56
56
|
|
|
57
|
+
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
58
|
+
|
|
57
59
|
type Props = {
|
|
58
60
|
Player: React.ComponentType<any>;
|
|
59
61
|
PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
|
|
@@ -598,6 +600,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
598
600
|
pluginConfiguration,
|
|
599
601
|
};
|
|
600
602
|
|
|
603
|
+
const { isActiveGesture, startComponentsAnimation } =
|
|
604
|
+
useModalAnimationContext();
|
|
605
|
+
|
|
601
606
|
return (
|
|
602
607
|
<PlayerStateContext.Provider value={value}>
|
|
603
608
|
<PlayerContainerContextProvider
|
|
@@ -641,7 +646,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
641
646
|
autoplay={true}
|
|
642
647
|
controls={false}
|
|
643
648
|
disableCastAction={disableCastAction}
|
|
644
|
-
docked={
|
|
649
|
+
docked={
|
|
650
|
+
navigator.isVideoModalDocked() &&
|
|
651
|
+
!startComponentsAnimation &&
|
|
652
|
+
!isActiveGesture
|
|
653
|
+
}
|
|
645
654
|
entry={item}
|
|
646
655
|
fullscreen={mode === VideoModalMode.FULLSCREEN}
|
|
647
656
|
inline={inline}
|
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
import React, { PropsWithChildren } from "react";
|
|
2
|
-
import { ImageBackground } from "react-native";
|
|
2
|
+
import { ImageBackground, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
5
|
+
import {
|
|
6
|
+
AnimationComponent,
|
|
7
|
+
ComponentAnimationType,
|
|
8
|
+
useModalAnimationContext,
|
|
9
|
+
PlayerAnimationStateEnum,
|
|
10
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
5
11
|
|
|
6
12
|
type Props = PropsWithChildren<{
|
|
7
13
|
entry: ZappEntry;
|
|
8
14
|
style?: { [K: string]: any };
|
|
9
15
|
imageStyle?: { [K: string]: any };
|
|
10
16
|
imageKey?: string;
|
|
17
|
+
defaultImageDimensions?: { [K: string]: any };
|
|
11
18
|
}>;
|
|
12
19
|
|
|
20
|
+
const imageSize = { width: "100%", height: "100%" };
|
|
21
|
+
|
|
13
22
|
const PlayerImageBackgroundComponent = ({
|
|
14
23
|
entry,
|
|
15
24
|
children,
|
|
16
25
|
style,
|
|
17
26
|
imageStyle,
|
|
18
27
|
imageKey,
|
|
28
|
+
defaultImageDimensions,
|
|
19
29
|
}: Props) => {
|
|
20
30
|
const source = React.useMemo(
|
|
21
31
|
() => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
|
|
22
32
|
[imageKey, entry]
|
|
23
33
|
);
|
|
24
34
|
|
|
35
|
+
const { playerAnimationState } = useModalAnimationContext();
|
|
36
|
+
|
|
25
37
|
if (!source) return <>{children}</>;
|
|
26
38
|
|
|
27
39
|
return (
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
40
|
+
<View
|
|
41
|
+
style={
|
|
42
|
+
playerAnimationState === PlayerAnimationStateEnum.maximaze
|
|
43
|
+
? defaultImageDimensions
|
|
44
|
+
: style
|
|
45
|
+
}
|
|
33
46
|
>
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
<AnimationComponent
|
|
48
|
+
style={style}
|
|
49
|
+
animationType={ComponentAnimationType.player}
|
|
50
|
+
additionalData={defaultImageDimensions}
|
|
51
|
+
>
|
|
52
|
+
<ImageBackground
|
|
53
|
+
resizeMode="cover"
|
|
54
|
+
style={imageSize}
|
|
55
|
+
imageStyle={imageStyle}
|
|
56
|
+
source={source}
|
|
57
|
+
>
|
|
58
|
+
{children}
|
|
59
|
+
</ImageBackground>
|
|
60
|
+
</AnimationComponent>
|
|
61
|
+
</View>
|
|
36
62
|
);
|
|
37
63
|
};
|
|
38
64
|
|
|
@@ -6,6 +6,12 @@ import configureStore from "redux-mock-store";
|
|
|
6
6
|
|
|
7
7
|
import * as themeUtils from "@applicaster/zapp-react-native-utils/theme";
|
|
8
8
|
|
|
9
|
+
// silences the errors related to React-native-gesture-handler in tests
|
|
10
|
+
jest.mock(
|
|
11
|
+
"@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation",
|
|
12
|
+
() => () => null
|
|
13
|
+
);
|
|
14
|
+
|
|
9
15
|
jest.mock("react-native-safe-area-context", () => ({
|
|
10
16
|
useSafeAreaInsets: () => ({ top: 50 }),
|
|
11
17
|
}));
|
|
@@ -137,7 +137,7 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
137
137
|
{...{ ...(navBarProps as MobileNavBarPluginProps), id: pathname }}
|
|
138
138
|
/>
|
|
139
139
|
|
|
140
|
-
<OfflineFallbackScreen screenData={
|
|
140
|
+
<OfflineFallbackScreen screenData={targetScreenData}>
|
|
141
141
|
{/* @TODO RouteManager doesn't use props, can they be removed ? */}
|
|
142
142
|
<RouteManager pathname={pathname} screenData={screenData} />
|
|
143
143
|
</OfflineFallbackScreen>
|
|
@@ -7,6 +7,10 @@ import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
|
|
|
7
7
|
import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
8
8
|
|
|
9
9
|
import { PlayerLiveImage } from "../PlayerLiveImageComponent";
|
|
10
|
+
import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
11
|
+
|
|
12
|
+
import { Provider } from "react-redux";
|
|
13
|
+
import configureStore from "redux-mock-store";
|
|
10
14
|
|
|
11
15
|
const seekTo = jest.fn();
|
|
12
16
|
|
|
@@ -19,14 +23,25 @@ jest.mock(
|
|
|
19
23
|
})
|
|
20
24
|
);
|
|
21
25
|
|
|
26
|
+
jest
|
|
27
|
+
.spyOn(useNavigationHooks, "useNavigation")
|
|
28
|
+
.mockImplementation(() => ({ videoModalState: { visible: false } }));
|
|
29
|
+
|
|
22
30
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
|
|
23
31
|
|
|
32
|
+
const mockStore = configureStore();
|
|
33
|
+
|
|
34
|
+
const store = mockStore({ appData: {} });
|
|
35
|
+
|
|
24
36
|
const Wrapper = ({ children }: { children: React.ReactChildren }) => (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
/* @ts-ignore */
|
|
38
|
+
<Provider store={store}>
|
|
39
|
+
<ThemeContext.Provider
|
|
40
|
+
value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
|
|
41
|
+
>
|
|
42
|
+
{children}
|
|
43
|
+
</ThemeContext.Provider>
|
|
44
|
+
</Provider>
|
|
30
45
|
);
|
|
31
46
|
|
|
32
47
|
describe("PlayerLiveImageComponent", () => {
|
|
@@ -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,335 @@
|
|
|
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
|
+
import {
|
|
13
|
+
useModalAnimationContext,
|
|
14
|
+
PlayerAnimationStateEnum,
|
|
15
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
16
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
17
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
setScrollModalAnimatedValue,
|
|
21
|
+
resetScrollAnimatedValues,
|
|
22
|
+
} from "./utils";
|
|
23
|
+
|
|
24
|
+
const getAnimatedConfig = (toValue) => {
|
|
25
|
+
return {
|
|
26
|
+
toValue,
|
|
27
|
+
duration: 200,
|
|
28
|
+
useNativeDriver: true,
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const generalStyles = StyleSheet.create({
|
|
33
|
+
container: {
|
|
34
|
+
flex: 1,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
type Props = {
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
43
|
+
const {
|
|
44
|
+
isActiveGesture,
|
|
45
|
+
playerAnimationState,
|
|
46
|
+
setPlayerAnimationState,
|
|
47
|
+
resetPlayerAnimationState,
|
|
48
|
+
animatedValues: {
|
|
49
|
+
lastScrollY,
|
|
50
|
+
dragScrollY,
|
|
51
|
+
dragVideoPlayerY,
|
|
52
|
+
translateYOffset,
|
|
53
|
+
},
|
|
54
|
+
lastScrollYValue,
|
|
55
|
+
scrollPosition,
|
|
56
|
+
modalSnapPoints,
|
|
57
|
+
lastSnap,
|
|
58
|
+
setLastSnap,
|
|
59
|
+
} = useModalAnimationContext();
|
|
60
|
+
|
|
61
|
+
const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
|
|
62
|
+
useNavigation();
|
|
63
|
+
|
|
64
|
+
const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
|
|
65
|
+
const isMinimizedModal = videoModalState.mode === "MINIMIZED";
|
|
66
|
+
const previousItemId = usePrevious(videoModalState.item?.id);
|
|
67
|
+
|
|
68
|
+
const isNotMinimizeMaximazeAnimation =
|
|
69
|
+
playerAnimationState !== PlayerAnimationStateEnum.minimize &&
|
|
70
|
+
playerAnimationState !== PlayerAnimationStateEnum.maximaze;
|
|
71
|
+
|
|
72
|
+
const isAudioItem = React.useMemo(
|
|
73
|
+
() =>
|
|
74
|
+
videoModalState.item?.content?.type?.includes?.("audio") ||
|
|
75
|
+
videoModalState.item?.type?.value === "audio",
|
|
76
|
+
[videoModalState.item]
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Refs for components
|
|
80
|
+
const scrollRef = React.useRef(null);
|
|
81
|
+
const tapHandlerRef = React.useRef(null);
|
|
82
|
+
const panHandlerRef = React.useRef(null);
|
|
83
|
+
|
|
84
|
+
const onRegisterLastScroll = Animated.event(
|
|
85
|
+
[{ nativeEvent: { contentOffset: { y: lastScrollY } } }],
|
|
86
|
+
{ useNativeDriver: true }
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const onGestureEvent = Animated.event(
|
|
90
|
+
[{ nativeEvent: { translationY: dragScrollY } }],
|
|
91
|
+
{ useNativeDriver: true }
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
const onHandlerStateChange = ({ nativeEvent }) => {
|
|
95
|
+
if (nativeEvent.oldState === State.ACTIVE && scrollPosition.current === 0) {
|
|
96
|
+
// eslint-disable-next-line prefer-const
|
|
97
|
+
const { velocityY, translationY } = nativeEvent;
|
|
98
|
+
const dragToss = 0.05;
|
|
99
|
+
|
|
100
|
+
const preparedTranslationY =
|
|
101
|
+
Math.abs(translationY) - lastScrollYValue.current;
|
|
102
|
+
|
|
103
|
+
if (videoModalState.mode === "MAXIMIZED") {
|
|
104
|
+
const endOffsetY =
|
|
105
|
+
lastSnap + preparedTranslationY + dragToss * velocityY + 150;
|
|
106
|
+
|
|
107
|
+
let destSnapPoint = modalSnapPoints[0];
|
|
108
|
+
|
|
109
|
+
for (const snapPoint of modalSnapPoints) {
|
|
110
|
+
const distFromSnap = Math.abs(snapPoint - endOffsetY);
|
|
111
|
+
|
|
112
|
+
if (distFromSnap < Math.abs(destSnapPoint - endOffsetY)) {
|
|
113
|
+
destSnapPoint = snapPoint;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
setLastSnap(destSnapPoint);
|
|
118
|
+
|
|
119
|
+
if (destSnapPoint === modalSnapPoints[0]) {
|
|
120
|
+
translateYOffset.extractOffset();
|
|
121
|
+
translateYOffset.setValue(preparedTranslationY);
|
|
122
|
+
translateYOffset.flattenOffset();
|
|
123
|
+
dragScrollY.setValue(0);
|
|
124
|
+
|
|
125
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
126
|
+
} else {
|
|
127
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
if (translationY < 0) {
|
|
131
|
+
// from mini to full
|
|
132
|
+
setLastSnap(modalSnapPoints[0]);
|
|
133
|
+
translateYOffset.setValue(modalSnapPoints[1] - preparedTranslationY);
|
|
134
|
+
dragScrollY.setValue(0);
|
|
135
|
+
|
|
136
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
137
|
+
} else {
|
|
138
|
+
resetPlayerAnimationState();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
playerAnimationState === PlayerAnimationStateEnum.drag_scroll &&
|
|
143
|
+
resetPlayerAnimationState();
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const onScroll = React.useCallback(({ nativeEvent }) => {
|
|
148
|
+
scrollPosition.current = nativeEvent.contentOffset.y;
|
|
149
|
+
}, []);
|
|
150
|
+
|
|
151
|
+
const onMomentumScrollEnd = React.useCallback(
|
|
152
|
+
({ nativeEvent }) => {
|
|
153
|
+
if (nativeEvent.contentOffset.y === 0 && !isActiveGesture) {
|
|
154
|
+
resetScrollAnimatedValues(
|
|
155
|
+
lastScrollY,
|
|
156
|
+
lastScrollYValue,
|
|
157
|
+
dragScrollY,
|
|
158
|
+
dragVideoPlayerY
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
[isActiveGesture]
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
React.useEffect(() => {
|
|
166
|
+
return () => {
|
|
167
|
+
scrollPosition.current = 0;
|
|
168
|
+
|
|
169
|
+
resetScrollAnimatedValues(
|
|
170
|
+
lastScrollY,
|
|
171
|
+
lastScrollYValue,
|
|
172
|
+
dragScrollY,
|
|
173
|
+
dragVideoPlayerY
|
|
174
|
+
);
|
|
175
|
+
};
|
|
176
|
+
}, []);
|
|
177
|
+
|
|
178
|
+
React.useEffect(() => {
|
|
179
|
+
if (
|
|
180
|
+
videoModalState.mode === "MINIMIZED" &&
|
|
181
|
+
videoModalState.previousMode === "MAXIMIZED"
|
|
182
|
+
) {
|
|
183
|
+
resetPlayerAnimationState();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
(videoModalState.mode === "MAXIMIZED" &&
|
|
188
|
+
videoModalState.previousMode === "MAXIMIZED") ||
|
|
189
|
+
previousItemId !== videoModalState.item?.id
|
|
190
|
+
) {
|
|
191
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.maximaze);
|
|
192
|
+
setTimeout(() => resetPlayerAnimationState());
|
|
193
|
+
}
|
|
194
|
+
}, [videoModalState, previousItemId]);
|
|
195
|
+
|
|
196
|
+
React.useEffect(() => {
|
|
197
|
+
if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
|
|
198
|
+
if (
|
|
199
|
+
(scrollPosition.current === 0 &&
|
|
200
|
+
(lastScrollY as any)._value !== 0 &&
|
|
201
|
+
(dragScrollY as any)._value === 0 &&
|
|
202
|
+
(dragVideoPlayerY as any)._value === 0) ||
|
|
203
|
+
(scrollPosition.current !== 0 &&
|
|
204
|
+
((dragScrollY as any)._value !== 0 ||
|
|
205
|
+
(dragVideoPlayerY as any)._value !== 0))
|
|
206
|
+
) {
|
|
207
|
+
resetScrollAnimatedValues(
|
|
208
|
+
lastScrollY,
|
|
209
|
+
lastScrollYValue,
|
|
210
|
+
dragScrollY,
|
|
211
|
+
dragVideoPlayerY
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
Animated.timing(
|
|
216
|
+
translateYOffset,
|
|
217
|
+
getAnimatedConfig(modalSnapPoints[1])
|
|
218
|
+
).start(() => {
|
|
219
|
+
setTimeout(() => {
|
|
220
|
+
minimiseVideoModal();
|
|
221
|
+
|
|
222
|
+
setScrollModalAnimatedValue(
|
|
223
|
+
translateYOffset,
|
|
224
|
+
modalSnapPoints[1],
|
|
225
|
+
setLastSnap
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
resetScrollAnimatedValues(
|
|
229
|
+
lastScrollY,
|
|
230
|
+
lastScrollYValue,
|
|
231
|
+
dragScrollY,
|
|
232
|
+
dragVideoPlayerY
|
|
233
|
+
);
|
|
234
|
+
}, 150);
|
|
235
|
+
});
|
|
236
|
+
} else if (playerAnimationState === PlayerAnimationStateEnum.maximaze) {
|
|
237
|
+
Animated.timing(translateYOffset, getAnimatedConfig(0)).start(() => {
|
|
238
|
+
maximiseVideoModal();
|
|
239
|
+
setScrollModalAnimatedValue(translateYOffset, 0, setLastSnap);
|
|
240
|
+
|
|
241
|
+
resetScrollAnimatedValues(
|
|
242
|
+
lastScrollY,
|
|
243
|
+
lastScrollYValue,
|
|
244
|
+
dragScrollY,
|
|
245
|
+
dragVideoPlayerY
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
resetPlayerAnimationState();
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const lastScrollYListenerId = lastScrollY.addListener(({ value }) => {
|
|
253
|
+
lastScrollYValue.current = value;
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const dragListenerId = dragScrollY.addListener(({ value }) => {
|
|
257
|
+
const preparedValue =
|
|
258
|
+
isMinimizedModal && value >= 0
|
|
259
|
+
? 0
|
|
260
|
+
: Math.round(isAudioItem ? Math.abs(value) : value);
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
preparedValue > 0 &&
|
|
264
|
+
scrollPosition.current === 0 &&
|
|
265
|
+
playerAnimationState !== PlayerAnimationStateEnum.drag_player
|
|
266
|
+
) {
|
|
267
|
+
playerAnimationState !== PlayerAnimationStateEnum.drag_scroll &&
|
|
268
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.drag_scroll);
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return () => {
|
|
273
|
+
lastScrollY.removeListener(lastScrollYListenerId);
|
|
274
|
+
dragScrollY.removeListener(dragListenerId);
|
|
275
|
+
};
|
|
276
|
+
}, [playerAnimationState, isAudioItem, modalSnapPoints]);
|
|
277
|
+
|
|
278
|
+
const Wrapper = React.useMemo(
|
|
279
|
+
() => (Platform.OS === "android" ? GestureHandlerRootView : View),
|
|
280
|
+
[]
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
return (
|
|
284
|
+
<Wrapper style={generalStyles.container}>
|
|
285
|
+
<TapGestureHandler
|
|
286
|
+
maxDurationMs={100000}
|
|
287
|
+
ref={tapHandlerRef}
|
|
288
|
+
maxDeltaY={lastSnap - modalSnapPoints[0]}
|
|
289
|
+
numberOfTaps={1}
|
|
290
|
+
>
|
|
291
|
+
<View pointerEvents="box-none">
|
|
292
|
+
<PanGestureHandler
|
|
293
|
+
enabled={
|
|
294
|
+
(isMaximazedModal || isMinimizedModal) &&
|
|
295
|
+
isNotMinimizeMaximazeAnimation
|
|
296
|
+
}
|
|
297
|
+
ref={panHandlerRef}
|
|
298
|
+
simultaneousHandlers={[scrollRef, tapHandlerRef]}
|
|
299
|
+
shouldCancelWhenOutside={isMaximazedModal}
|
|
300
|
+
onGestureEvent={onGestureEvent}
|
|
301
|
+
onHandlerStateChange={onHandlerStateChange}
|
|
302
|
+
>
|
|
303
|
+
<Animated.View>
|
|
304
|
+
<NativeViewGestureHandler
|
|
305
|
+
ref={scrollRef}
|
|
306
|
+
waitFor={tapHandlerRef}
|
|
307
|
+
simultaneousHandlers={panHandlerRef}
|
|
308
|
+
>
|
|
309
|
+
<Animated.ScrollView
|
|
310
|
+
scrollEnabled={
|
|
311
|
+
isMaximazedModal && isNotMinimizeMaximazeAnimation
|
|
312
|
+
}
|
|
313
|
+
bounces={false}
|
|
314
|
+
onScrollBeginDrag={onRegisterLastScroll}
|
|
315
|
+
onScroll={onScroll}
|
|
316
|
+
onMomentumScrollEnd={onMomentumScrollEnd}
|
|
317
|
+
scrollEventThrottle={1}
|
|
318
|
+
showsVerticalScrollIndicator={false}
|
|
319
|
+
>
|
|
320
|
+
{children}
|
|
321
|
+
</Animated.ScrollView>
|
|
322
|
+
</NativeViewGestureHandler>
|
|
323
|
+
</Animated.View>
|
|
324
|
+
</PanGestureHandler>
|
|
325
|
+
</View>
|
|
326
|
+
</TapGestureHandler>
|
|
327
|
+
</Wrapper>
|
|
328
|
+
);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
export const AnimatedScrollModal = ({ children }: Props) => {
|
|
332
|
+
const Component = !isTV() ? AnimatedScrollModalComponent : React.Fragment;
|
|
333
|
+
|
|
334
|
+
return <Component>{children}</Component>;
|
|
335
|
+
};
|