@applicaster/quick-brick-player 15.0.0-rc.3 → 15.0.0-rc.30
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/package.json +6 -6
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +20 -8
- package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +71 -63
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +1 -6
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +5 -23
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +5 -8
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +1 -6
- package/src/Player/AudioLayer/utils.ts +1 -27
- package/src/Player/PlayerModal/PlayerModal.tsx +11 -6
- package/src/Player/PlayerModal/VideoPlayerModal.tsx +107 -106
- package/src/Player/PlayerModal/consts/index.ts +2 -19
- package/src/Player/PlayerModal/hooks/index.ts +44 -31
- package/src/Player/PlayerModal/styles.ts +5 -0
- package/src/Player/PlayerModal/utils/index.ts +92 -0
- package/src/Player/PlayerView/types.ts +1 -2
- package/src/Player/index.tsx +559 -357
- package/src/utils/dimensions.ts +29 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/logger.ts +6 -0
- package/src/utils/playerHelpers.ts +11 -0
- package/src/utils/playerStyles.ts +50 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +0 -82
- package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +0 -1
- package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +0 -99
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import React, { ReactElement, useRef } from "react";
|
|
1
|
+
import React, { ReactElement, useMemo, useRef } from "react";
|
|
2
2
|
|
|
3
|
-
import { Animated, Pressable
|
|
3
|
+
import { Animated, Pressable } from "react-native";
|
|
4
4
|
import { PanGestureHandler } from "react-native-gesture-handler";
|
|
5
5
|
import { useStyles } from "./styles";
|
|
6
6
|
import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
|
|
7
7
|
import { useVideoModalState } from "./hooks";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_IMAGE_RATIO_VIDEO,
|
|
10
|
-
|
|
10
|
+
MODAL_COLLAPSE_RATIO,
|
|
11
11
|
MODAL_RADIUS,
|
|
12
|
-
SCREEN_HEIGHT,
|
|
13
|
-
SCREEN_WIDTH,
|
|
14
12
|
VIDEO_TRANSITION_THRESHOLD,
|
|
15
13
|
} from "./consts";
|
|
16
14
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
17
|
-
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
15
|
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/useModalAnimationContext";
|
|
19
16
|
import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
|
|
20
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
SafeAreaView,
|
|
19
|
+
useSafeAreaFrame,
|
|
20
|
+
useSafeAreaInsets,
|
|
21
|
+
} from "react-native-safe-area-context";
|
|
21
22
|
import { GestureAnimatedScrollView } from "./GestureAnimatedScrollView";
|
|
22
23
|
import { PlayerDetailsWrapperHeightContext } from "./context";
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
24
|
+
import {
|
|
25
|
+
getInsetsOffset,
|
|
26
|
+
getWindowHeight,
|
|
27
|
+
getWindowWidth,
|
|
28
|
+
directionStyles,
|
|
29
|
+
getScaledPos,
|
|
30
|
+
getExtraContentPadding,
|
|
31
|
+
} from "./utils";
|
|
32
32
|
|
|
33
33
|
type AnimatedModalProps = {
|
|
34
34
|
pip?: boolean;
|
|
@@ -46,8 +46,6 @@ type AnimatedModalProps = {
|
|
|
46
46
|
};
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
const height = SCREEN_HEIGHT;
|
|
50
|
-
|
|
51
49
|
export function VideoPlayerModal({
|
|
52
50
|
aspectRatio = DEFAULT_IMAGE_RATIO_VIDEO,
|
|
53
51
|
content,
|
|
@@ -62,11 +60,18 @@ export function VideoPlayerModal({
|
|
|
62
60
|
const enabled = !!modal && !fullscreen;
|
|
63
61
|
const isTablet = useIsTablet();
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
// remember initial width, ignore rotation changes
|
|
64
|
+
const width = useMemo(
|
|
65
|
+
() =>
|
|
66
|
+
isTablet && !isTabletPortrait
|
|
67
|
+
? style.tabletLandscapeWidth
|
|
68
|
+
: getWindowWidth(),
|
|
69
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
70
|
+
[]
|
|
71
|
+
);
|
|
66
72
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
73
|
+
const height = useMemo(() => getWindowHeight(), []); // remember initial height, ignore rotation changes
|
|
74
|
+
const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
|
|
70
75
|
|
|
71
76
|
const { minimised_height: minimisedHeight } = useConfiguration();
|
|
72
77
|
const scrollViewRef = useRef<typeof Animated.ScrollView | null>(null);
|
|
@@ -83,7 +88,9 @@ export function VideoPlayerModal({
|
|
|
83
88
|
expand,
|
|
84
89
|
} = useVideoModalState(modal ? translateYRef : dummyRef);
|
|
85
90
|
|
|
86
|
-
const
|
|
91
|
+
const frame = useSafeAreaFrame();
|
|
92
|
+
|
|
93
|
+
const heightAboveMinimised = height - collapsedHeight;
|
|
87
94
|
|
|
88
95
|
const styles = useStyles({ height: collapsedHeight });
|
|
89
96
|
|
|
@@ -96,7 +103,7 @@ export function VideoPlayerModal({
|
|
|
96
103
|
// Interpolated opacities for smooth cross-fade
|
|
97
104
|
const collapsedOpacity = !isFullScreenOrPIP
|
|
98
105
|
? translateY.interpolate({
|
|
99
|
-
inputRange: [MODAL_COLLAPSE_START,
|
|
106
|
+
inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
|
|
100
107
|
outputRange: [0, 1],
|
|
101
108
|
extrapolate: "clamp",
|
|
102
109
|
})
|
|
@@ -104,18 +111,16 @@ export function VideoPlayerModal({
|
|
|
104
111
|
|
|
105
112
|
const expandedOpacity = !isFullScreenOrPIP
|
|
106
113
|
? translateY.interpolate({
|
|
107
|
-
inputRange: [0,
|
|
114
|
+
inputRange: [0, heightAboveMinimised],
|
|
108
115
|
outputRange: [1, 0],
|
|
109
116
|
extrapolate: "clamp",
|
|
110
117
|
})
|
|
111
118
|
: new Animated.Value(1);
|
|
112
119
|
|
|
120
|
+
// animated position for video content during modal transition
|
|
113
121
|
const xPosition = !isFullScreenOrPIP
|
|
114
122
|
? translateY.interpolate({
|
|
115
|
-
inputRange: [
|
|
116
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
117
|
-
height - collapsedHeight,
|
|
118
|
-
],
|
|
123
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
119
124
|
outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
|
|
120
125
|
extrapolate: "clamp",
|
|
121
126
|
})
|
|
@@ -123,34 +128,26 @@ export function VideoPlayerModal({
|
|
|
123
128
|
|
|
124
129
|
const vidHeight = width / aspectRatio;
|
|
125
130
|
|
|
131
|
+
// animated position for video content during modal transition
|
|
126
132
|
const yPosition = !isFullScreenOrPIP
|
|
127
133
|
? translateY.interpolate({
|
|
128
|
-
inputRange: [
|
|
129
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
130
|
-
height - collapsedHeight,
|
|
131
|
-
],
|
|
134
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
132
135
|
outputRange: [
|
|
133
136
|
0,
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
(SCREEN_WIDTH / aspectRatio -
|
|
140
|
-
(SCREEN_WIDTH / aspectRatio) * SCALE_FACTOR) /
|
|
141
|
-
2
|
|
142
|
-
),
|
|
137
|
+
-(
|
|
138
|
+
PROGRESS_BAR_HEIGHT +
|
|
139
|
+
getInsetsOffset(insets, isTabletPortrait) +
|
|
140
|
+
getScaledPos(height, vidHeight, minimisedHeight, isTabletPortrait)
|
|
141
|
+
),
|
|
143
142
|
],
|
|
144
143
|
extrapolate: "clamp",
|
|
145
144
|
})
|
|
146
145
|
: new Animated.Value(0);
|
|
147
146
|
|
|
147
|
+
// animated position for video content during modal transition
|
|
148
148
|
const scalePosition = !isFullScreenOrPIP
|
|
149
149
|
? translateY.interpolate({
|
|
150
|
-
inputRange: [
|
|
151
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
152
|
-
height - collapsedHeight,
|
|
153
|
-
],
|
|
150
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
154
151
|
outputRange: [1, SCALE_FACTOR],
|
|
155
152
|
extrapolate: "clamp",
|
|
156
153
|
})
|
|
@@ -158,7 +155,7 @@ export function VideoPlayerModal({
|
|
|
158
155
|
|
|
159
156
|
const borderTopRadiusAnimated = !isFullScreenOrPIP
|
|
160
157
|
? translateY.interpolate({
|
|
161
|
-
inputRange: [0,
|
|
158
|
+
inputRange: [0, heightAboveMinimised],
|
|
162
159
|
outputRange: [MODAL_RADIUS, 0],
|
|
163
160
|
extrapolate: "clamp",
|
|
164
161
|
})
|
|
@@ -184,88 +181,92 @@ export function VideoPlayerModal({
|
|
|
184
181
|
waitFor={scrollViewRef}
|
|
185
182
|
{...gestureHandlerProps}
|
|
186
183
|
>
|
|
187
|
-
<
|
|
188
|
-
pointerEvents={"auto"}
|
|
189
|
-
style={[
|
|
190
|
-
styles.modalWrapper,
|
|
191
|
-
{
|
|
192
|
-
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
193
|
-
borderTopRightRadius: borderTopRadiusAnimated,
|
|
194
|
-
transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
|
|
195
|
-
height: height,
|
|
196
|
-
},
|
|
197
|
-
]}
|
|
198
|
-
>
|
|
184
|
+
<SafeAreaView pointerEvents="box-none" edges={["bottom"]}>
|
|
199
185
|
<Animated.View
|
|
200
186
|
pointerEvents={"auto"}
|
|
201
187
|
style={[
|
|
202
|
-
styles.
|
|
203
|
-
collapsed ? styles.collapsedModalBg : null,
|
|
188
|
+
styles.modalWrapper,
|
|
204
189
|
{
|
|
205
190
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
206
191
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
207
|
-
|
|
192
|
+
transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
|
|
193
|
+
height: frame.height,
|
|
208
194
|
},
|
|
209
195
|
]}
|
|
210
196
|
>
|
|
211
197
|
<Animated.View
|
|
212
|
-
pointerEvents={
|
|
213
|
-
style={[
|
|
198
|
+
pointerEvents={"auto"}
|
|
199
|
+
style={[
|
|
200
|
+
styles.modal,
|
|
201
|
+
collapsed ? styles.collapsedModalBg : null,
|
|
202
|
+
{
|
|
203
|
+
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
204
|
+
borderTopRightRadius: borderTopRadiusAnimated,
|
|
205
|
+
},
|
|
206
|
+
]}
|
|
214
207
|
>
|
|
215
208
|
<Animated.View
|
|
209
|
+
pointerEvents={!collapsed ? "auto" : "none"}
|
|
216
210
|
style={[
|
|
217
|
-
styles.
|
|
218
|
-
|
|
219
|
-
transform: [
|
|
220
|
-
{ translateX: xPosition },
|
|
221
|
-
{ translateY: yPosition },
|
|
222
|
-
{ scale: scalePosition },
|
|
223
|
-
],
|
|
224
|
-
},
|
|
211
|
+
pip ? styles.modalContentPiP : styles.modalContent,
|
|
212
|
+
directionStyles(isTabletPortrait),
|
|
225
213
|
]}
|
|
226
214
|
>
|
|
227
|
-
|
|
215
|
+
<Animated.View
|
|
216
|
+
style={[
|
|
217
|
+
styles.expandedContentContainer,
|
|
218
|
+
{
|
|
219
|
+
transform: [
|
|
220
|
+
{ translateX: xPosition },
|
|
221
|
+
{ translateY: yPosition },
|
|
222
|
+
{ scale: scalePosition },
|
|
223
|
+
],
|
|
224
|
+
},
|
|
225
|
+
]}
|
|
226
|
+
>
|
|
227
|
+
{content}
|
|
228
|
+
</Animated.View>
|
|
229
|
+
{extraContent ? (
|
|
230
|
+
<GestureAnimatedScrollView
|
|
231
|
+
ref={scrollViewRef}
|
|
232
|
+
contentContainerStyle={getExtraContentPadding(insets)}
|
|
233
|
+
bounces={false}
|
|
234
|
+
overScrollMode="never"
|
|
235
|
+
onLayout={onScrollViewLayout}
|
|
236
|
+
style={[
|
|
237
|
+
styles.extraContentScrollView,
|
|
238
|
+
{ opacity: expandedOpacity },
|
|
239
|
+
]}
|
|
240
|
+
>
|
|
241
|
+
<PlayerDetailsWrapperHeightContext.Provider
|
|
242
|
+
value={playerDetailsWrapperHeight}
|
|
243
|
+
>
|
|
244
|
+
{extraContent}
|
|
245
|
+
</PlayerDetailsWrapperHeightContext.Provider>
|
|
246
|
+
</GestureAnimatedScrollView>
|
|
247
|
+
) : null}
|
|
228
248
|
</Animated.View>
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
paddingBottom: insets.bottom,
|
|
234
|
-
}}
|
|
235
|
-
onLayout={onScrollViewLayout}
|
|
249
|
+
|
|
250
|
+
{!isFullScreenOrPIP ? (
|
|
251
|
+
<Animated.View
|
|
252
|
+
pointerEvents={collapsed ? "box-none" : "none"}
|
|
236
253
|
style={[
|
|
237
|
-
styles.
|
|
238
|
-
{ opacity:
|
|
254
|
+
styles.collapsedBarContainer,
|
|
255
|
+
{ opacity: collapsedOpacity },
|
|
239
256
|
]}
|
|
240
257
|
>
|
|
241
|
-
<
|
|
242
|
-
|
|
258
|
+
<Pressable
|
|
259
|
+
testID="collapsedBarWrapper"
|
|
260
|
+
onPress={expand}
|
|
261
|
+
style={styles.collapsedBarWrapper}
|
|
243
262
|
>
|
|
244
|
-
{
|
|
245
|
-
</
|
|
246
|
-
</
|
|
263
|
+
{collapsedContent}
|
|
264
|
+
</Pressable>
|
|
265
|
+
</Animated.View>
|
|
247
266
|
) : null}
|
|
248
267
|
</Animated.View>
|
|
249
|
-
|
|
250
|
-
{!isFullScreenOrPIP ? (
|
|
251
|
-
<Animated.View
|
|
252
|
-
pointerEvents={collapsed ? "box-none" : "none"}
|
|
253
|
-
style={[
|
|
254
|
-
styles.collapsedBarContainer,
|
|
255
|
-
{ opacity: collapsedOpacity },
|
|
256
|
-
]}
|
|
257
|
-
>
|
|
258
|
-
<Pressable
|
|
259
|
-
testID="collapsedBarWrapper"
|
|
260
|
-
onPress={expand}
|
|
261
|
-
style={styles.collapsedBarWrapper}
|
|
262
|
-
>
|
|
263
|
-
{collapsedContent}
|
|
264
|
-
</Pressable>
|
|
265
|
-
</Animated.View>
|
|
266
|
-
) : null}
|
|
267
268
|
</Animated.View>
|
|
268
|
-
</
|
|
269
|
+
</SafeAreaView>
|
|
269
270
|
</PanGestureHandler>
|
|
270
271
|
);
|
|
271
272
|
}
|
|
@@ -1,26 +1,7 @@
|
|
|
1
|
-
import { isAndroidTablet } from "@applicaster/zapp-react-native-utils/reactHooks/layout/isTablet";
|
|
2
|
-
import {
|
|
3
|
-
isAndroidPlatform,
|
|
4
|
-
isAndroidVersionAtLeast,
|
|
5
|
-
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
6
|
-
import { Dimensions, StatusBar } from "react-native";
|
|
7
|
-
|
|
8
1
|
export const DOCKED_PROGRESSBAR_HEIGHT = 3; // Height of the docked progress bar plugins/mobile-transport-controls/src/ProgressBar/layouts/DockedLayout.tsx
|
|
9
2
|
|
|
10
3
|
export const VIDEO_TRANSITION_THRESHOLD = 0.5; // Threshold for video transition
|
|
11
4
|
|
|
12
|
-
const windowDimensions = Dimensions.get("window");
|
|
13
|
-
|
|
14
|
-
const isOldAndroidDevice =
|
|
15
|
-
isAndroidPlatform() && !isAndroidVersionAtLeast(34) && !isAndroidTablet();
|
|
16
|
-
|
|
17
|
-
export const SCREEN_WIDTH = windowDimensions.width;
|
|
18
|
-
|
|
19
|
-
export const SCREEN_HEIGHT =
|
|
20
|
-
windowDimensions.height + (isOldAndroidDevice ? StatusBar.currentHeight : 0);
|
|
21
|
-
|
|
22
|
-
export const MODAL_COLLAPSE_START = SCREEN_HEIGHT * 0.7; // 70% of screen height
|
|
23
|
-
|
|
24
5
|
export const DRAG_TO_COLLAPSE = 0.02; // 2% to collapse
|
|
25
6
|
|
|
26
7
|
export const DRAG_TO_EXPAND = 0.02; // 2% to expand
|
|
@@ -32,3 +13,5 @@ export const DEFAULT_IMAGE_RATIO_AUDIO = 1; // Default aspect ratio for audio
|
|
|
32
13
|
export const ANIMATION_DURATION = 250; // Default animation duration in milliseconds
|
|
33
14
|
|
|
34
15
|
export const MODAL_RADIUS = 16; // Default border radius for modal
|
|
16
|
+
|
|
17
|
+
export const MODAL_COLLAPSE_RATIO = 0.7; // 70% of the screen height
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
useSafeAreaFrame,
|
|
4
|
+
useSafeAreaInsets,
|
|
5
|
+
} from "react-native-safe-area-context";
|
|
3
6
|
import { State } from "react-native-gesture-handler";
|
|
4
7
|
import { Animated } from "react-native";
|
|
5
8
|
|
|
@@ -12,10 +15,10 @@ import {
|
|
|
12
15
|
ANIMATION_DURATION,
|
|
13
16
|
DRAG_TO_COLLAPSE,
|
|
14
17
|
DRAG_TO_EXPAND,
|
|
15
|
-
SCREEN_HEIGHT,
|
|
16
18
|
} from "../consts";
|
|
17
19
|
import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
|
|
18
20
|
import { usePlugins } from "@applicaster/zapp-react-native-redux";
|
|
21
|
+
import { isOldAndroidDevice } from "../utils";
|
|
19
22
|
|
|
20
23
|
const bottomTabBarHeight = getTabBarHeight();
|
|
21
24
|
|
|
@@ -36,18 +39,21 @@ export const useVideoModalState = (
|
|
|
36
39
|
|
|
37
40
|
const menuVisible = isMenuVisible(currentRoute, screenData, plugins);
|
|
38
41
|
|
|
39
|
-
const collapsed =
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
const collapsed =
|
|
43
|
+
videoModalState.visible &&
|
|
44
|
+
videoModalState.mode === VideoModalMode.MINIMIZED;
|
|
42
45
|
|
|
43
|
-
const
|
|
46
|
+
const frame = useSafeAreaFrame();
|
|
47
|
+
const insets = useSafeAreaInsets();
|
|
44
48
|
|
|
45
49
|
const collapsedHeight =
|
|
46
50
|
minimisedHeight +
|
|
47
|
-
initialBottomOffset +
|
|
48
51
|
(menuVisible ? bottomTabBarHeight : 0) +
|
|
52
|
+
(isOldAndroidDevice ? 0 : insets.bottom) + // insets.bottom is added to properly display docked modal
|
|
49
53
|
PROGRESS_BAR_HEIGHT;
|
|
50
54
|
|
|
55
|
+
const heightAboveMinimised = frame.height - collapsedHeight;
|
|
56
|
+
|
|
51
57
|
const translateY = translateYRef.current;
|
|
52
58
|
|
|
53
59
|
const handleExpand = useCallback(
|
|
@@ -72,7 +78,7 @@ export const useVideoModalState = (
|
|
|
72
78
|
[translateYRef]
|
|
73
79
|
);
|
|
74
80
|
|
|
75
|
-
const offset = useRef(
|
|
81
|
+
const offset = useRef(heightAboveMinimised);
|
|
76
82
|
|
|
77
83
|
// Gesture handler for modal
|
|
78
84
|
const onGestureEvent = useCallback(
|
|
@@ -82,8 +88,8 @@ export const useVideoModalState = (
|
|
|
82
88
|
let newY = offset.current + y;
|
|
83
89
|
if (newY < 0) newY = 0;
|
|
84
90
|
|
|
85
|
-
if (newY >
|
|
86
|
-
newY =
|
|
91
|
+
if (newY > heightAboveMinimised) {
|
|
92
|
+
newY = heightAboveMinimised;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
translateY.setValue(newY);
|
|
@@ -99,25 +105,25 @@ export const useVideoModalState = (
|
|
|
99
105
|
let newY = offset.current + translationY;
|
|
100
106
|
if (newY < 0) newY = 0;
|
|
101
107
|
|
|
102
|
-
if (newY >
|
|
103
|
-
newY =
|
|
108
|
+
if (newY > heightAboveMinimised) {
|
|
109
|
+
newY = heightAboveMinimised;
|
|
104
110
|
}
|
|
105
111
|
|
|
106
112
|
const shouldCollapse =
|
|
107
|
-
translationY >
|
|
113
|
+
translationY > heightAboveMinimised * DRAG_TO_COLLAPSE;
|
|
108
114
|
|
|
109
115
|
const shouldExpand =
|
|
110
|
-
translationY < -
|
|
116
|
+
translationY < -heightAboveMinimised * DRAG_TO_EXPAND;
|
|
111
117
|
|
|
112
118
|
if (!collapsed && shouldCollapse) {
|
|
113
119
|
// Collapse
|
|
114
120
|
Animated.timing(translateY, {
|
|
115
|
-
toValue:
|
|
121
|
+
toValue: heightAboveMinimised,
|
|
116
122
|
duration: ANIMATION_DURATION,
|
|
117
123
|
useNativeDriver: true,
|
|
118
124
|
}).start(() => {
|
|
119
125
|
minimiseVideoModal();
|
|
120
|
-
offset.current =
|
|
126
|
+
offset.current = heightAboveMinimised;
|
|
121
127
|
});
|
|
122
128
|
} else if (collapsed && shouldExpand) {
|
|
123
129
|
// Expand
|
|
@@ -133,10 +139,10 @@ export const useVideoModalState = (
|
|
|
133
139
|
} else {
|
|
134
140
|
// Snap back to current state
|
|
135
141
|
Animated.spring(translateY, {
|
|
136
|
-
toValue: collapsed ?
|
|
142
|
+
toValue: collapsed ? heightAboveMinimised : 0,
|
|
137
143
|
useNativeDriver: true,
|
|
138
144
|
}).start(() => {
|
|
139
|
-
offset.current = collapsed ?
|
|
145
|
+
offset.current = collapsed ? heightAboveMinimised : 0;
|
|
140
146
|
translateY.setValue(offset.current);
|
|
141
147
|
});
|
|
142
148
|
}
|
|
@@ -158,20 +164,27 @@ export const useVideoModalState = (
|
|
|
158
164
|
}, [onGestureEvent, onHandlerStateChange]);
|
|
159
165
|
|
|
160
166
|
useEffect(() => {
|
|
161
|
-
if (videoModalState.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
167
|
+
if (videoModalState.visible) {
|
|
168
|
+
if (videoModalState.mode === VideoModalMode.MAXIMIZED) {
|
|
169
|
+
handleExpand(0).start(() => {
|
|
170
|
+
maximiseVideoModal();
|
|
171
|
+
offset.current = 0;
|
|
172
|
+
translateY.setValue(0);
|
|
173
|
+
});
|
|
174
|
+
} else if (videoModalState.mode === VideoModalMode.MINIMIZED) {
|
|
175
|
+
handleCollapse(heightAboveMinimised).start(() => {
|
|
176
|
+
minimiseVideoModal();
|
|
177
|
+
offset.current = heightAboveMinimised;
|
|
178
|
+
translateY.setValue(heightAboveMinimised);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
173
181
|
}
|
|
174
|
-
}, [
|
|
182
|
+
}, [
|
|
183
|
+
videoModalState.visible,
|
|
184
|
+
videoModalState.mode,
|
|
185
|
+
collapsedHeight,
|
|
186
|
+
heightAboveMinimised,
|
|
187
|
+
]);
|
|
175
188
|
|
|
176
189
|
return useMemo(
|
|
177
190
|
() => ({
|
|
@@ -63,6 +63,7 @@ export const useStyles = ({ height }: { height: number }) => {
|
|
|
63
63
|
backgroundColor,
|
|
64
64
|
elevation: 10,
|
|
65
65
|
zIndex: 100,
|
|
66
|
+
height: "100%",
|
|
66
67
|
overflow: "hidden",
|
|
67
68
|
},
|
|
68
69
|
modalWrapper: {
|
|
@@ -75,6 +76,10 @@ export const useStyles = ({ height }: { height: number }) => {
|
|
|
75
76
|
flex: 1,
|
|
76
77
|
alignItems: "center",
|
|
77
78
|
},
|
|
79
|
+
modalContentPiP: {
|
|
80
|
+
flex: 1,
|
|
81
|
+
alignItems: "flex-start",
|
|
82
|
+
},
|
|
78
83
|
expandedContentContainer: {
|
|
79
84
|
justifyContent: "flex-start",
|
|
80
85
|
backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { StyleSheet, Dimensions, ViewStyle } from "react-native";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
isAndroidPlatform,
|
|
5
|
+
isAndroidVersionAtLeast,
|
|
6
|
+
isTV,
|
|
7
|
+
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
8
|
+
import {
|
|
9
|
+
isTablet,
|
|
10
|
+
useIsTablet as getIsTablet,
|
|
11
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
|
+
|
|
13
|
+
const SAFE_AREA_BREAKING_API_VERSION = 35;
|
|
14
|
+
|
|
15
|
+
export const isOldAndroidDevice =
|
|
16
|
+
isAndroidPlatform() &&
|
|
17
|
+
!isAndroidVersionAtLeast(SAFE_AREA_BREAKING_API_VERSION);
|
|
18
|
+
|
|
19
|
+
export const getWindowHeight = (): number => {
|
|
20
|
+
const windowDimensions = Dimensions.get("window");
|
|
21
|
+
|
|
22
|
+
return windowDimensions.height;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const getScreenHeight = (): number => {
|
|
26
|
+
const screenDimensions = Dimensions.get("screen");
|
|
27
|
+
|
|
28
|
+
return screenDimensions.height;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const getWindowWidth = (): number => {
|
|
32
|
+
const windowDimensions = Dimensions.get("window");
|
|
33
|
+
|
|
34
|
+
return windowDimensions.width;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const getIsTabletLandscape = (isTabletPortrait: boolean): boolean => {
|
|
38
|
+
return !isTV() && isTablet() && !isTabletPortrait;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const getInsetsOffset = (
|
|
42
|
+
insets: { top: number; bottom: number },
|
|
43
|
+
isTabletPortrait: boolean
|
|
44
|
+
): number => {
|
|
45
|
+
const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
|
|
46
|
+
|
|
47
|
+
return isTablet() && isTabletLandscape
|
|
48
|
+
? isOldAndroidDevice
|
|
49
|
+
? insets.top / 2
|
|
50
|
+
: 0
|
|
51
|
+
: insets.top / 2;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const orientationStyles = StyleSheet.create({
|
|
55
|
+
landscape: { flexDirection: "row" },
|
|
56
|
+
portrait: { flexDirection: "column" },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const directionStyles = (isTabletPortrait: boolean): ViewStyle => {
|
|
60
|
+
const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
|
|
61
|
+
|
|
62
|
+
return isTabletLandscape
|
|
63
|
+
? orientationStyles.landscape
|
|
64
|
+
: orientationStyles.portrait;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const getScaledPos = (
|
|
68
|
+
height,
|
|
69
|
+
vidHeight,
|
|
70
|
+
minimisedHeight,
|
|
71
|
+
isTabletPortrait
|
|
72
|
+
) => {
|
|
73
|
+
const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
|
|
74
|
+
|
|
75
|
+
const SCALE_FACTOR = minimisedHeight / vidHeight; // Scale factor for expanded content
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
((isTabletLandscape ? height : vidHeight) - vidHeight * SCALE_FACTOR) / 2
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const getExtraContentPadding = (insets: {
|
|
83
|
+
top: number;
|
|
84
|
+
bottom: number;
|
|
85
|
+
}): ViewStyle => {
|
|
86
|
+
const isTablet = getIsTablet(); // not a hook, just a utility function
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
paddingTop: isTablet ? insets.top : 0,
|
|
90
|
+
paddingBottom: insets.bottom,
|
|
91
|
+
};
|
|
92
|
+
};
|