@applicaster/quick-brick-player 15.0.0-alpha.4069571733 → 15.0.0-alpha.4153840309
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 +5 -5
- package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +4 -3
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +25 -5
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +6 -1
- package/src/Player/PlayerModal/PlayerModal.tsx +10 -15
- package/src/Player/PlayerModal/VideoPlayerModal.tsx +127 -106
- package/src/Player/PlayerModal/hooks/index.ts +115 -147
- package/src/Player/PlayerModal/styles.ts +1 -0
- package/src/Player/PlayerModal/utils/index.ts +94 -12
- package/src/Player/index.tsx +23 -16
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "15.0.0-alpha.
|
|
3
|
+
"version": "15.0.0-alpha.4153840309",
|
|
4
4
|
"description": "Quick Brick Player",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@applicaster/quick-brick-mobile-transport-controls": "15.0.0-
|
|
38
|
+
"@applicaster/quick-brick-mobile-transport-controls": "15.0.0-rc.36",
|
|
39
39
|
"@applicaster/quick-brick-tv-transport-controls": "15.0.0-rc.15",
|
|
40
|
-
"@applicaster/zapp-react-native-tvos-app": "15.0.0-alpha.
|
|
41
|
-
"@applicaster/zapp-react-native-ui-components": "15.0.0-alpha.
|
|
42
|
-
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "15.0.0-alpha.4153840309",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "15.0.0-alpha.4153840309",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.4153840309",
|
|
43
43
|
"query-string": "7.1.3",
|
|
44
44
|
"shaka-player": "4.3.5",
|
|
45
45
|
"typeface-montserrat": "^0.0.54",
|
|
@@ -90,7 +90,8 @@ const styles = StyleSheet.create({
|
|
|
90
90
|
marginTop: { marginTop: PROGRESS_BAR_HEIGHT },
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
-
const getValue = (key: string, stylesObj:
|
|
93
|
+
const getValue = (key: string, stylesObj: Record<string, any>) =>
|
|
94
|
+
stylesObj?.[key] ?? null;
|
|
94
95
|
|
|
95
96
|
const controlButtons = (
|
|
96
97
|
live: boolean,
|
|
@@ -208,7 +209,7 @@ export const DockedControls = (props: Props) => {
|
|
|
208
209
|
|
|
209
210
|
const insets = useSafeAreaInsets();
|
|
210
211
|
|
|
211
|
-
const
|
|
212
|
+
const progressBarLayoutState = React.useMemo(
|
|
212
213
|
() => ({
|
|
213
214
|
inline: layoutState.inline,
|
|
214
215
|
docked: true,
|
|
@@ -275,7 +276,7 @@ export const DockedControls = (props: Props) => {
|
|
|
275
276
|
content={entry}
|
|
276
277
|
value={value}
|
|
277
278
|
visible
|
|
278
|
-
layoutState={
|
|
279
|
+
layoutState={progressBarLayoutState}
|
|
279
280
|
onPlayerSeek={onPlayerSeek}
|
|
280
281
|
playerState={playerState}
|
|
281
282
|
docked
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { LayoutChangeEvent, View } from "react-native";
|
|
2
|
+
import { Animated, LayoutChangeEvent, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
5
5
|
import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
@@ -8,6 +8,7 @@ import { FlexImage } from "./FlexImage";
|
|
|
8
8
|
|
|
9
9
|
import { styles } from "./styles";
|
|
10
10
|
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
11
|
+
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
11
12
|
|
|
12
13
|
type Props = {
|
|
13
14
|
entry: ZappEntry;
|
|
@@ -29,15 +30,34 @@ export const PlayerImage = (props: Props) => {
|
|
|
29
30
|
configuration.audio_player_artwork_border_radius
|
|
30
31
|
);
|
|
31
32
|
|
|
33
|
+
const { yTranslate } = useModalAnimationContext();
|
|
34
|
+
|
|
35
|
+
const isModalExpanded = yTranslate.current.interpolate({
|
|
36
|
+
inputRange: [0, 1], // this should be end with `1` only when it's in initial state ( 0pos), otherwise `0`
|
|
37
|
+
outputRange: [1, 0],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// do not use styles.shadow when isModalExpanded is 0
|
|
41
|
+
|
|
42
|
+
const animatedStyle = {
|
|
43
|
+
opacity: isModalExpanded,
|
|
44
|
+
};
|
|
45
|
+
|
|
32
46
|
return (
|
|
33
47
|
<View style={styles.alignItemsCenter}>
|
|
48
|
+
{/* Using an Animated.View to apply shadow to the image */}
|
|
49
|
+
<Animated.View
|
|
50
|
+
style={[
|
|
51
|
+
animatedStyle,
|
|
52
|
+
shouldShowShadow ? styles.shadow : undefined,
|
|
53
|
+
{ borderRadius },
|
|
54
|
+
]}
|
|
55
|
+
/>
|
|
34
56
|
<View
|
|
35
57
|
onLayout={onLayoutImage}
|
|
36
|
-
style={[
|
|
58
|
+
style={[styles.defaultImageWrapperView, { borderRadius }]}
|
|
37
59
|
>
|
|
38
|
-
<
|
|
39
|
-
<FlexImage entry={entry} style={styles.backgroundImageContainer} />
|
|
40
|
-
</View>
|
|
60
|
+
<FlexImage entry={entry} style={styles.backgroundImageContainer} />
|
|
41
61
|
</View>
|
|
42
62
|
</View>
|
|
43
63
|
);
|
|
@@ -23,7 +23,12 @@ export const styles = StyleSheet.create({
|
|
|
23
23
|
overflow: "hidden",
|
|
24
24
|
},
|
|
25
25
|
shadow: {
|
|
26
|
-
|
|
26
|
+
zIndex: 0,
|
|
27
|
+
position: "absolute",
|
|
28
|
+
top: 0,
|
|
29
|
+
left: 0,
|
|
30
|
+
right: 0,
|
|
31
|
+
bottom: 0,
|
|
27
32
|
shadowColor: SHADOW_COLOR,
|
|
28
33
|
shadowOffset: { width: 0, height: 24 },
|
|
29
34
|
shadowOpacity: platformSelect({
|
|
@@ -5,8 +5,8 @@ import { PanGestureHandler } from "react-native-gesture-handler";
|
|
|
5
5
|
import { useStyles } from "./styles";
|
|
6
6
|
import { useVideoModalState } from "./hooks";
|
|
7
7
|
import { MODAL_COLLAPSE_RATIO, MODAL_RADIUS } from "./consts";
|
|
8
|
-
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
9
8
|
import { getWindowHeight } from "./utils";
|
|
9
|
+
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
10
10
|
|
|
11
11
|
type AnimatedModalProps = {
|
|
12
12
|
content?: ReactElement;
|
|
@@ -17,22 +17,18 @@ export function AnimatedModal({
|
|
|
17
17
|
content,
|
|
18
18
|
collapsedContent,
|
|
19
19
|
}: AnimatedModalProps) {
|
|
20
|
-
const
|
|
20
|
+
const { translateY, collapsed, gestureHandlerProps, expand, offset } =
|
|
21
|
+
useVideoModalState();
|
|
21
22
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
collapsed,
|
|
25
|
-
collapsedHeight,
|
|
26
|
-
gestureHandlerProps,
|
|
27
|
-
expand,
|
|
28
|
-
} = useVideoModalState(translateYRef);
|
|
23
|
+
const frame = useSafeAreaFrame();
|
|
24
|
+
const collapsedHeight = frame.height - offset.current;
|
|
29
25
|
|
|
30
|
-
const
|
|
26
|
+
const height = getWindowHeight();
|
|
27
|
+
const heightAboveMinimised = height - collapsedHeight;
|
|
31
28
|
|
|
32
|
-
const
|
|
33
|
-
const heightAboveMinimised = WINDOW_HEIGHT - collapsedHeight;
|
|
29
|
+
const styles = useStyles({ height: collapsedHeight, type: "audio" });
|
|
34
30
|
|
|
35
|
-
const MODAL_COLLAPSE_START =
|
|
31
|
+
const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
|
|
36
32
|
|
|
37
33
|
// Interpolated opacities for smooth cross-fade
|
|
38
34
|
const collapsedOpacity = translateY.interpolate({
|
|
@@ -63,7 +59,7 @@ export function AnimatedModal({
|
|
|
63
59
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
64
60
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
65
61
|
transform: [{ translateY }],
|
|
66
|
-
height:
|
|
62
|
+
height: height,
|
|
67
63
|
},
|
|
68
64
|
]}
|
|
69
65
|
>
|
|
@@ -73,7 +69,6 @@ export function AnimatedModal({
|
|
|
73
69
|
{
|
|
74
70
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
75
71
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
76
|
-
height: WINDOW_HEIGHT,
|
|
77
72
|
},
|
|
78
73
|
]}
|
|
79
74
|
>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
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";
|
|
@@ -12,22 +12,25 @@ import {
|
|
|
12
12
|
VIDEO_TRANSITION_THRESHOLD,
|
|
13
13
|
} from "./consts";
|
|
14
14
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
15
|
-
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
16
|
-
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/useModalAnimationContext";
|
|
17
15
|
import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
|
|
18
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
SafeAreaView,
|
|
18
|
+
useSafeAreaFrame,
|
|
19
|
+
useSafeAreaInsets,
|
|
20
|
+
} from "react-native-safe-area-context";
|
|
19
21
|
import { GestureAnimatedScrollView } from "./GestureAnimatedScrollView";
|
|
20
22
|
import { PlayerDetailsWrapperHeightContext } from "./context";
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
import {
|
|
24
|
+
getInsetsOffset,
|
|
25
|
+
getWindowHeight,
|
|
26
|
+
getWindowWidth,
|
|
27
|
+
directionStyles,
|
|
28
|
+
getScaledPos,
|
|
29
|
+
getExtraContentPadding,
|
|
30
|
+
} from "./utils";
|
|
31
|
+
import { addOrientationChangeListener } from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
27
32
|
|
|
28
|
-
const
|
|
29
|
-
return isLandscape ? orientationStyles.landscape : orientationStyles.portrait;
|
|
30
|
-
};
|
|
33
|
+
const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
|
|
31
34
|
|
|
32
35
|
type AnimatedModalProps = {
|
|
33
36
|
pip?: boolean;
|
|
@@ -59,44 +62,61 @@ export function VideoPlayerModal({
|
|
|
59
62
|
const enabled = !!modal && !fullscreen;
|
|
60
63
|
const isTablet = useIsTablet();
|
|
61
64
|
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
+
// remember initial width, ignore rotation changes
|
|
66
|
+
const width = useMemo(
|
|
67
|
+
() =>
|
|
68
|
+
isTablet && !isTabletPortrait
|
|
69
|
+
? style.tabletLandscapeWidth
|
|
70
|
+
: getWindowWidth(isTablet, !isTabletPortrait),
|
|
71
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
+
[]
|
|
73
|
+
);
|
|
65
74
|
|
|
66
|
-
|
|
75
|
+
const height = useMemo(
|
|
76
|
+
() => getWindowHeight(isTablet, !isTabletPortrait),
|
|
77
|
+
[]
|
|
78
|
+
); // remember initial height, ignore rotation changes
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
width = style?.tabletLandscapeWidth || width;
|
|
70
|
-
}
|
|
80
|
+
const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
|
|
71
81
|
|
|
72
82
|
const { minimised_height: minimisedHeight } = useConfiguration();
|
|
73
83
|
const scrollViewRef = useRef<typeof Animated.ScrollView | null>(null);
|
|
74
84
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
const dummyRef = useRef(new Animated.Value(0));
|
|
85
|
+
const { translateY, collapsed, gestureHandlerProps, expand, offset } =
|
|
86
|
+
useVideoModalState();
|
|
78
87
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
collapsed,
|
|
82
|
-
collapsedHeight,
|
|
83
|
-
gestureHandlerProps,
|
|
84
|
-
expand,
|
|
85
|
-
} = useVideoModalState(modal ? translateYRef : dummyRef);
|
|
88
|
+
const frame = useSafeAreaFrame();
|
|
89
|
+
const collapsedHeight = frame.height - offset.current;
|
|
86
90
|
|
|
87
91
|
const heightAboveMinimised = height - collapsedHeight;
|
|
88
92
|
|
|
89
|
-
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
90
|
-
|
|
91
93
|
const styles = useStyles({ height: collapsedHeight });
|
|
92
94
|
|
|
93
95
|
const SCALE_FACTOR = 1 / (width / aspectRatio / minimisedHeight); // Scale factor for expanded content
|
|
94
96
|
|
|
95
97
|
const insets = useSafeAreaInsets();
|
|
96
98
|
|
|
97
|
-
const
|
|
99
|
+
const [isFullScreenMode, setFullScreenMode] = React.useState(
|
|
100
|
+
fullscreen || pip
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
React.useEffect(() => {
|
|
104
|
+
const listener = addOrientationChangeListener(({ toOrientation }) => {
|
|
105
|
+
/* ignored in collapsed mode non-PiP player */
|
|
106
|
+
if (collapsed && !pip) return;
|
|
107
|
+
setFullScreenMode(!(toOrientation === 1));
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return () => {
|
|
111
|
+
listener.remove();
|
|
112
|
+
};
|
|
113
|
+
}, [collapsed, pip]);
|
|
114
|
+
|
|
115
|
+
const isFullScreenOrPIP = isFullScreenMode;
|
|
116
|
+
|
|
117
|
+
const vidHeight = width / aspectRatio;
|
|
98
118
|
|
|
99
|
-
//
|
|
119
|
+
// animated opacity for smooth cross-fade of collapsed content
|
|
100
120
|
const collapsedOpacity = !isFullScreenOrPIP
|
|
101
121
|
? translateY.interpolate({
|
|
102
122
|
inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
|
|
@@ -105,6 +125,7 @@ export function VideoPlayerModal({
|
|
|
105
125
|
})
|
|
106
126
|
: new Animated.Value(0);
|
|
107
127
|
|
|
128
|
+
// animated opacity for extra content
|
|
108
129
|
const expandedOpacity = !isFullScreenOrPIP
|
|
109
130
|
? translateY.interpolate({
|
|
110
131
|
inputRange: [0, heightAboveMinimised],
|
|
@@ -113,6 +134,7 @@ export function VideoPlayerModal({
|
|
|
113
134
|
})
|
|
114
135
|
: new Animated.Value(1);
|
|
115
136
|
|
|
137
|
+
// animated x position for video content
|
|
116
138
|
const xPosition = !isFullScreenOrPIP
|
|
117
139
|
? translateY.interpolate({
|
|
118
140
|
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
@@ -121,27 +143,23 @@ export function VideoPlayerModal({
|
|
|
121
143
|
})
|
|
122
144
|
: new Animated.Value(0);
|
|
123
145
|
|
|
124
|
-
|
|
125
|
-
|
|
146
|
+
// animated y position for video content
|
|
126
147
|
const yPosition = !isFullScreenOrPIP
|
|
127
148
|
? translateY.interpolate({
|
|
128
149
|
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
129
150
|
outputRange: [
|
|
130
151
|
0,
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
(WINDOW_WIDTH / aspectRatio -
|
|
137
|
-
(WINDOW_WIDTH / aspectRatio) * SCALE_FACTOR) /
|
|
138
|
-
2
|
|
139
|
-
),
|
|
152
|
+
-(
|
|
153
|
+
PROGRESS_BAR_HEIGHT +
|
|
154
|
+
getInsetsOffset(insets, isTabletPortrait) +
|
|
155
|
+
getScaledPos(height, vidHeight, minimisedHeight, isTabletPortrait)
|
|
156
|
+
),
|
|
140
157
|
],
|
|
141
158
|
extrapolate: "clamp",
|
|
142
159
|
})
|
|
143
160
|
: new Animated.Value(0);
|
|
144
161
|
|
|
162
|
+
// animated position for video content
|
|
145
163
|
const scalePosition = !isFullScreenOrPIP
|
|
146
164
|
? translateY.interpolate({
|
|
147
165
|
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
@@ -152,7 +170,7 @@ export function VideoPlayerModal({
|
|
|
152
170
|
|
|
153
171
|
const borderTopRadiusAnimated = !isFullScreenOrPIP
|
|
154
172
|
? translateY.interpolate({
|
|
155
|
-
inputRange: [0,
|
|
173
|
+
inputRange: [0, heightAboveMinimised],
|
|
156
174
|
outputRange: [MODAL_RADIUS, 0],
|
|
157
175
|
extrapolate: "clamp",
|
|
158
176
|
})
|
|
@@ -176,93 +194,96 @@ export function VideoPlayerModal({
|
|
|
176
194
|
<PanGestureHandler
|
|
177
195
|
enabled={enabled}
|
|
178
196
|
waitFor={scrollViewRef}
|
|
197
|
+
activeOffsetY={[-25, 25]}
|
|
198
|
+
activeOffsetX={[-25, 25]}
|
|
179
199
|
{...gestureHandlerProps}
|
|
180
200
|
>
|
|
181
|
-
<
|
|
182
|
-
pointerEvents={"auto"}
|
|
183
|
-
style={[
|
|
184
|
-
styles.modalWrapper,
|
|
185
|
-
{
|
|
186
|
-
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
187
|
-
borderTopRightRadius: borderTopRadiusAnimated,
|
|
188
|
-
transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
|
|
189
|
-
height: height,
|
|
190
|
-
},
|
|
191
|
-
]}
|
|
192
|
-
>
|
|
201
|
+
<AnimatedSafeAreaView pointerEvents="box-none" edges={["bottom"]}>
|
|
193
202
|
<Animated.View
|
|
194
203
|
pointerEvents={"auto"}
|
|
195
204
|
style={[
|
|
196
|
-
styles.
|
|
197
|
-
collapsed ? styles.collapsedModalBg : null,
|
|
205
|
+
styles.modalWrapper,
|
|
198
206
|
{
|
|
199
207
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
200
208
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
201
|
-
|
|
209
|
+
transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
|
|
210
|
+
height: frame.height,
|
|
202
211
|
},
|
|
203
212
|
]}
|
|
204
213
|
>
|
|
205
214
|
<Animated.View
|
|
206
|
-
pointerEvents={
|
|
215
|
+
pointerEvents={"auto"}
|
|
207
216
|
style={[
|
|
208
|
-
|
|
209
|
-
|
|
217
|
+
styles.modal,
|
|
218
|
+
collapsed ? styles.collapsedModalBg : null,
|
|
219
|
+
{
|
|
220
|
+
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
221
|
+
borderTopRightRadius: borderTopRadiusAnimated,
|
|
222
|
+
},
|
|
210
223
|
]}
|
|
211
224
|
>
|
|
212
225
|
<Animated.View
|
|
226
|
+
pointerEvents={!collapsed ? "auto" : "none"}
|
|
213
227
|
style={[
|
|
214
|
-
styles.
|
|
215
|
-
|
|
216
|
-
transform: [
|
|
217
|
-
{ translateX: xPosition },
|
|
218
|
-
{ translateY: yPosition },
|
|
219
|
-
{ scale: scalePosition },
|
|
220
|
-
],
|
|
221
|
-
},
|
|
228
|
+
pip ? styles.modalContentPiP : styles.modalContent,
|
|
229
|
+
directionStyles(isTabletPortrait),
|
|
222
230
|
]}
|
|
223
231
|
>
|
|
224
|
-
|
|
232
|
+
<Animated.View
|
|
233
|
+
style={[
|
|
234
|
+
styles.expandedContentContainer,
|
|
235
|
+
{
|
|
236
|
+
transform: [
|
|
237
|
+
{ translateX: xPosition },
|
|
238
|
+
{ translateY: yPosition },
|
|
239
|
+
{ scale: scalePosition },
|
|
240
|
+
],
|
|
241
|
+
},
|
|
242
|
+
]}
|
|
243
|
+
>
|
|
244
|
+
{content}
|
|
245
|
+
</Animated.View>
|
|
246
|
+
{extraContent ? (
|
|
247
|
+
<GestureAnimatedScrollView
|
|
248
|
+
ref={scrollViewRef}
|
|
249
|
+
contentContainerStyle={getExtraContentPadding(insets)}
|
|
250
|
+
bounces={false}
|
|
251
|
+
overScrollMode="never"
|
|
252
|
+
onLayout={onScrollViewLayout}
|
|
253
|
+
style={[
|
|
254
|
+
styles.extraContentScrollView,
|
|
255
|
+
{ opacity: expandedOpacity },
|
|
256
|
+
]}
|
|
257
|
+
>
|
|
258
|
+
<PlayerDetailsWrapperHeightContext.Provider
|
|
259
|
+
value={playerDetailsWrapperHeight}
|
|
260
|
+
>
|
|
261
|
+
{extraContent}
|
|
262
|
+
</PlayerDetailsWrapperHeightContext.Provider>
|
|
263
|
+
</GestureAnimatedScrollView>
|
|
264
|
+
) : null}
|
|
225
265
|
</Animated.View>
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
paddingBottom: insets.bottom,
|
|
231
|
-
}}
|
|
232
|
-
onLayout={onScrollViewLayout}
|
|
266
|
+
|
|
267
|
+
{!isFullScreenOrPIP ? (
|
|
268
|
+
<Animated.View
|
|
269
|
+
pointerEvents={collapsed ? "box-none" : "none"}
|
|
233
270
|
style={[
|
|
234
|
-
styles.
|
|
235
|
-
{ opacity:
|
|
271
|
+
styles.collapsedBarContainer,
|
|
272
|
+
{ opacity: collapsedOpacity },
|
|
236
273
|
]}
|
|
237
274
|
>
|
|
238
|
-
<
|
|
239
|
-
|
|
275
|
+
<Pressable
|
|
276
|
+
testID="collapsedBarWrapper"
|
|
277
|
+
onPress={expand}
|
|
278
|
+
style={styles.collapsedBarWrapper}
|
|
240
279
|
>
|
|
241
|
-
{
|
|
242
|
-
</
|
|
243
|
-
</
|
|
280
|
+
{collapsedContent}
|
|
281
|
+
</Pressable>
|
|
282
|
+
</Animated.View>
|
|
244
283
|
) : null}
|
|
245
284
|
</Animated.View>
|
|
246
|
-
|
|
247
|
-
{!isFullScreenOrPIP ? (
|
|
248
|
-
<Animated.View
|
|
249
|
-
pointerEvents={collapsed ? "box-none" : "none"}
|
|
250
|
-
style={[
|
|
251
|
-
styles.collapsedBarContainer,
|
|
252
|
-
{ opacity: collapsedOpacity },
|
|
253
|
-
]}
|
|
254
|
-
>
|
|
255
|
-
<Pressable
|
|
256
|
-
testID="collapsedBarWrapper"
|
|
257
|
-
onPress={expand}
|
|
258
|
-
style={styles.collapsedBarWrapper}
|
|
259
|
-
>
|
|
260
|
-
{collapsedContent}
|
|
261
|
-
</Pressable>
|
|
262
|
-
</Animated.View>
|
|
263
|
-
) : null}
|
|
264
285
|
</Animated.View>
|
|
265
|
-
</
|
|
286
|
+
</AnimatedSafeAreaView>
|
|
266
287
|
</PanGestureHandler>
|
|
267
288
|
);
|
|
268
289
|
}
|
|
@@ -1,159 +1,132 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
import { State } from "react-native-gesture-handler";
|
|
4
|
-
import { Animated } from "react-native";
|
|
5
4
|
|
|
6
5
|
import { VideoModalMode } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
7
|
-
import {
|
|
8
|
-
import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
|
|
6
|
+
import { useAnimationStateStore } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
|
|
9
7
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
10
|
-
import { isMenuVisible } from "@applicaster/zapp-react-native-ui-components/Components/Screen/navigationHandler";
|
|
11
8
|
import {
|
|
12
9
|
ANIMATION_DURATION,
|
|
13
10
|
DRAG_TO_COLLAPSE,
|
|
14
11
|
DRAG_TO_EXPAND,
|
|
15
12
|
} from "../consts";
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { getWindowHeight } from "../utils";
|
|
19
|
-
|
|
20
|
-
const bottomTabBarHeight = getTabBarHeight();
|
|
21
|
-
|
|
22
|
-
export const useVideoModalState = (
|
|
23
|
-
translateYRef: React.MutableRefObject<Animated.Value>
|
|
24
|
-
) => {
|
|
25
|
-
const { minimised_height: minimisedHeight } = useConfiguration();
|
|
13
|
+
import { Animated } from "react-native";
|
|
14
|
+
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
26
15
|
|
|
27
|
-
|
|
16
|
+
const getAnimatedValue = (animatedValue: Animated.Value): number => {
|
|
17
|
+
return (animatedValue as any).__getValue() as number;
|
|
18
|
+
};
|
|
28
19
|
|
|
20
|
+
export const useVideoModalState = () => {
|
|
29
21
|
const {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} =
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
videoModalState.mode === VideoModalMode.MINIMIZED;
|
|
44
|
-
|
|
45
|
-
const { bottom } = useSafeAreaInsets();
|
|
46
|
-
|
|
47
|
-
const initialBottomOffset = useRef(bottom).current;
|
|
48
|
-
|
|
49
|
-
const collapsedHeight =
|
|
50
|
-
minimisedHeight +
|
|
51
|
-
initialBottomOffset +
|
|
52
|
-
(menuVisible ? bottomTabBarHeight : 0) +
|
|
53
|
-
PROGRESS_BAR_HEIGHT;
|
|
54
|
-
|
|
55
|
-
const heightAboveMinimised = WINDOW_HEIGHT - collapsedHeight;
|
|
56
|
-
|
|
57
|
-
const translateY = translateYRef.current;
|
|
58
|
-
|
|
59
|
-
const handleExpand = useCallback(
|
|
60
|
-
(toValue: number) => {
|
|
61
|
-
return Animated.timing(translateYRef.current, {
|
|
22
|
+
yTranslate,
|
|
23
|
+
offset,
|
|
24
|
+
heightAboveMinimised,
|
|
25
|
+
gestureTranslationRef,
|
|
26
|
+
offsetAnimatedValueRef,
|
|
27
|
+
} = useModalAnimationContext();
|
|
28
|
+
|
|
29
|
+
const modalAnimatedValue = offsetAnimatedValueRef.current;
|
|
30
|
+
const gestureTranslation = gestureTranslationRef.current;
|
|
31
|
+
|
|
32
|
+
const updateModalTranslation = useCallback(
|
|
33
|
+
(toValue: number, duration: number = ANIMATION_DURATION) =>
|
|
34
|
+
Animated.timing(modalAnimatedValue, {
|
|
62
35
|
toValue,
|
|
63
|
-
duration
|
|
36
|
+
duration,
|
|
64
37
|
useNativeDriver: true,
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
[translateYRef]
|
|
38
|
+
}),
|
|
39
|
+
[modalAnimatedValue]
|
|
68
40
|
);
|
|
69
41
|
|
|
70
|
-
const
|
|
71
|
-
(toValue: number) => {
|
|
72
|
-
return Animated.timing(translateYRef.current, {
|
|
73
|
-
toValue,
|
|
74
|
-
duration: ANIMATION_DURATION,
|
|
75
|
-
useNativeDriver: true,
|
|
76
|
-
});
|
|
77
|
-
},
|
|
78
|
-
[translateYRef]
|
|
79
|
-
);
|
|
42
|
+
const translateY = yTranslate.current;
|
|
80
43
|
|
|
81
|
-
const
|
|
44
|
+
const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
|
|
45
|
+
useNavigation();
|
|
82
46
|
|
|
83
|
-
|
|
84
|
-
const onGestureEvent = useCallback(
|
|
85
|
-
(event: any) => {
|
|
86
|
-
if (event.nativeEvent.state === State.ACTIVE) {
|
|
87
|
-
const y = event.nativeEvent.translationY;
|
|
88
|
-
let newY = offset.current + y;
|
|
89
|
-
if (newY < 0) newY = 0;
|
|
47
|
+
const videoModalMode = videoModalState.mode;
|
|
90
48
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
49
|
+
const prevModeStateRef = useRef(videoModalMode); // keep track of last non-PIP mode
|
|
50
|
+
const gestureStateRef = useRef<any>(State.UNDETERMINED); // keep track of gesture state
|
|
94
51
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
52
|
+
// Track last non-PIP mode
|
|
53
|
+
if (videoModalMode !== prevModeStateRef.current) {
|
|
54
|
+
if (["MAXIMIZED", "MINIMIZED"].includes(videoModalMode)) {
|
|
55
|
+
prevModeStateRef.current = videoModalMode;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const collapsed =
|
|
60
|
+
videoModalState.visible &&
|
|
61
|
+
((prevModeStateRef.current === "MINIMIZED" &&
|
|
62
|
+
videoModalState.mode === "PIP") || // If STILL in PIP mode, check if last non-PIP mode was MINIMIZED
|
|
63
|
+
videoModalState.mode === VideoModalMode.MINIMIZED); // Or if currently in MINIMIZED mode
|
|
64
|
+
|
|
65
|
+
// Gesture handler for modal
|
|
66
|
+
const onGestureEvent = useMemo(
|
|
67
|
+
() =>
|
|
68
|
+
Animated.event([{ nativeEvent: { translationY: gestureTranslation } }], {
|
|
69
|
+
useNativeDriver: true,
|
|
70
|
+
}),
|
|
71
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
72
|
+
[]
|
|
99
73
|
);
|
|
100
74
|
|
|
101
75
|
const onHandlerStateChange = useCallback(
|
|
102
76
|
(event: any) => {
|
|
103
|
-
|
|
104
|
-
const { translationY } = event.nativeEvent;
|
|
105
|
-
let newY = offset.current + translationY;
|
|
106
|
-
if (newY < 0) newY = 0;
|
|
77
|
+
const { state: newState, oldState, translationY } = event.nativeEvent;
|
|
107
78
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
79
|
+
if (newState === State.ACTIVE || oldState === State.ACTIVE) {
|
|
80
|
+
useAnimationStateStore.setState({
|
|
81
|
+
isAnimationInProgress: newState === State.ACTIVE,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
111
84
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
85
|
+
// Update gesture state tracking
|
|
86
|
+
gestureStateRef.current = newState;
|
|
87
|
+
|
|
88
|
+
if (translationY !== 0) {
|
|
89
|
+
if (newState === State.BEGAN) {
|
|
90
|
+
// clean up gesture translation
|
|
91
|
+
gestureTranslation.setValue(0);
|
|
92
|
+
} else if (
|
|
93
|
+
newState === State.END ||
|
|
94
|
+
newState === State.FAILED ||
|
|
95
|
+
newState === State.CANCELLED
|
|
96
|
+
) {
|
|
97
|
+
const newY = getAnimatedValue(gestureTranslation);
|
|
98
|
+
|
|
99
|
+
// clean up gesture translation
|
|
100
|
+
gestureTranslation.setValue(0);
|
|
101
|
+
|
|
102
|
+
const v = getAnimatedValue(modalAnimatedValue);
|
|
103
|
+
|
|
104
|
+
// store current offset
|
|
105
|
+
modalAnimatedValue.setValue(v + newY);
|
|
106
|
+
|
|
107
|
+
const shouldCollapse = newY > offset.current * DRAG_TO_COLLAPSE;
|
|
108
|
+
|
|
109
|
+
const shouldExpand = newY < offset.current * DRAG_TO_EXPAND;
|
|
110
|
+
|
|
111
|
+
if (!collapsed && shouldCollapse) {
|
|
112
|
+
// Collapse
|
|
113
|
+
updateModalTranslation(offset.current).start(() => {
|
|
114
|
+
minimiseVideoModal();
|
|
115
|
+
});
|
|
116
|
+
} else if (collapsed && shouldExpand) {
|
|
117
|
+
// Expand
|
|
118
|
+
updateModalTranslation(0).start(() => {
|
|
119
|
+
maximiseVideoModal();
|
|
120
|
+
});
|
|
121
|
+
} else {
|
|
122
|
+
// Snap back to current state
|
|
123
|
+
updateModalTranslation(collapsed ? offset.current : 0).start();
|
|
124
|
+
}
|
|
148
125
|
}
|
|
149
|
-
} else if (event.nativeEvent.state === State.BEGAN) {
|
|
150
|
-
// Gesture started, set offset
|
|
151
|
-
translateY.stopAnimation((value: number) => {
|
|
152
|
-
offset.current = value;
|
|
153
|
-
});
|
|
154
126
|
}
|
|
155
127
|
},
|
|
156
|
-
|
|
128
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
129
|
+
[collapsed]
|
|
157
130
|
);
|
|
158
131
|
|
|
159
132
|
const gestureHandlerProps = useMemo(() => {
|
|
@@ -163,39 +136,34 @@ export const useVideoModalState = (
|
|
|
163
136
|
};
|
|
164
137
|
}, [onGestureEvent, onHandlerStateChange]);
|
|
165
138
|
|
|
139
|
+
// Track video modal state changes & calling updateAnimatedPosition
|
|
166
140
|
useEffect(() => {
|
|
167
141
|
if (videoModalState.visible) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
142
|
+
const mode =
|
|
143
|
+
videoModalMode === "PIP" ? prevModeStateRef.current : videoModalMode;
|
|
144
|
+
|
|
145
|
+
// Prevent changes during active gesture states to avoid interference
|
|
146
|
+
if ([State.ACTIVE].includes(gestureStateRef.current)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (mode === VideoModalMode.MAXIMIZED) {
|
|
151
|
+
updateModalTranslation(0).start();
|
|
152
|
+
} else if (mode === VideoModalMode.MINIMIZED) {
|
|
153
|
+
updateModalTranslation(heightAboveMinimised).start();
|
|
180
154
|
}
|
|
181
155
|
}
|
|
182
|
-
|
|
156
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
157
|
+
}, [videoModalState.visible, videoModalState.mode, heightAboveMinimised]);
|
|
183
158
|
|
|
184
159
|
return useMemo(
|
|
185
160
|
() => ({
|
|
186
161
|
collapsed,
|
|
187
|
-
collapsedHeight,
|
|
188
162
|
offset,
|
|
189
163
|
gestureHandlerProps,
|
|
190
164
|
translateY,
|
|
191
165
|
expand: maximiseVideoModal,
|
|
192
166
|
}),
|
|
193
|
-
[
|
|
194
|
-
collapsed,
|
|
195
|
-
collapsedHeight,
|
|
196
|
-
gestureHandlerProps,
|
|
197
|
-
translateY,
|
|
198
|
-
maximiseVideoModal,
|
|
199
|
-
]
|
|
167
|
+
[collapsed, offset, gestureHandlerProps, translateY, maximiseVideoModal]
|
|
200
168
|
);
|
|
201
169
|
};
|
|
@@ -1,29 +1,111 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { StyleSheet, Dimensions, ViewStyle } from "react-native";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
isAndroidPlatform,
|
|
5
5
|
isAndroidVersionAtLeast,
|
|
6
|
+
isTV,
|
|
6
7
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
7
|
-
import {
|
|
8
|
+
import { useIsTablet as getIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const SAFE_AREA_BREAKING_API_VERSION = 35;
|
|
10
11
|
|
|
11
|
-
const isOldAndroidDevice =
|
|
12
|
+
export const isOldAndroidDevice =
|
|
12
13
|
isAndroidPlatform() &&
|
|
13
|
-
!isAndroidVersionAtLeast(
|
|
14
|
-
!isAndroidTablet();
|
|
14
|
+
!isAndroidVersionAtLeast(SAFE_AREA_BREAKING_API_VERSION);
|
|
15
15
|
|
|
16
|
-
export const getWindowHeight = (
|
|
16
|
+
export const getWindowHeight = (
|
|
17
|
+
isTablet: boolean,
|
|
18
|
+
landscape: boolean
|
|
19
|
+
): number => {
|
|
17
20
|
const windowDimensions = Dimensions.get("window");
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
windowDimensions.height
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
if (isTablet && landscape) {
|
|
23
|
+
return windowDimensions.height;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (windowDimensions.width > windowDimensions.height) {
|
|
27
|
+
return windowDimensions.width;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return windowDimensions.height;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const getScreenHeight = (): number => {
|
|
34
|
+
const screenDimensions = Dimensions.get("screen");
|
|
35
|
+
|
|
36
|
+
return screenDimensions.height;
|
|
23
37
|
};
|
|
24
38
|
|
|
25
|
-
export const getWindowWidth = (
|
|
39
|
+
export const getWindowWidth = (
|
|
40
|
+
isTablet: boolean,
|
|
41
|
+
landscape: boolean
|
|
42
|
+
): number => {
|
|
26
43
|
const windowDimensions = Dimensions.get("window");
|
|
27
44
|
|
|
45
|
+
if (isTablet && landscape) {
|
|
46
|
+
return windowDimensions.width;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (windowDimensions.width > windowDimensions.height) {
|
|
50
|
+
return windowDimensions.height;
|
|
51
|
+
}
|
|
52
|
+
|
|
28
53
|
return windowDimensions.width;
|
|
29
54
|
};
|
|
55
|
+
|
|
56
|
+
const getIsTabletLandscape = (isTabletPortrait: boolean): boolean => {
|
|
57
|
+
return !isTV() && getIsTablet() && !isTabletPortrait;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const getInsetsOffset = (
|
|
61
|
+
insets: { top: number; bottom: number },
|
|
62
|
+
isTabletPortrait: boolean
|
|
63
|
+
): number => {
|
|
64
|
+
const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
|
|
65
|
+
|
|
66
|
+
return getIsTablet() && isTabletLandscape
|
|
67
|
+
? isOldAndroidDevice
|
|
68
|
+
? insets.top / 2
|
|
69
|
+
: 0
|
|
70
|
+
: insets.top / 2;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const orientationStyles = StyleSheet.create({
|
|
74
|
+
landscape: { flexDirection: "row" },
|
|
75
|
+
portrait: { flexDirection: "column" },
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
export const directionStyles = (isTabletPortrait: boolean): ViewStyle => {
|
|
79
|
+
const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
|
|
80
|
+
|
|
81
|
+
return isTabletLandscape
|
|
82
|
+
? orientationStyles.landscape
|
|
83
|
+
: orientationStyles.portrait;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export const getScaledPos = (
|
|
87
|
+
height,
|
|
88
|
+
vidHeight,
|
|
89
|
+
minimisedHeight,
|
|
90
|
+
isTabletPortrait
|
|
91
|
+
) => {
|
|
92
|
+
const isTabletLandscape = getIsTabletLandscape(isTabletPortrait);
|
|
93
|
+
|
|
94
|
+
const SCALE_FACTOR = minimisedHeight / vidHeight; // Scale factor for expanded content
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
((isTabletLandscape ? height : vidHeight) - vidHeight * SCALE_FACTOR) / 2
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const getExtraContentPadding = (insets: {
|
|
102
|
+
top: number;
|
|
103
|
+
bottom: number;
|
|
104
|
+
}): ViewStyle => {
|
|
105
|
+
const isTablet = getIsTablet(); // not a hook, just a utility function
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
paddingTop: isTablet ? insets.top : 0,
|
|
109
|
+
paddingBottom: insets.bottom,
|
|
110
|
+
};
|
|
111
|
+
};
|
package/src/Player/index.tsx
CHANGED
|
@@ -835,25 +835,25 @@ export default class VideoPlayer extends React.Component<
|
|
|
835
835
|
: styles.playerContainerBlack;
|
|
836
836
|
|
|
837
837
|
private getBackgroundImageStyle = (
|
|
838
|
-
dimensions:
|
|
838
|
+
dimensions: ViewStyle,
|
|
839
839
|
isAudioItem: boolean
|
|
840
|
-
): ViewStyle =>
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
840
|
+
): ViewStyle[] => [
|
|
841
|
+
isAudioItem ? styles.audio : { position: "absolute" },
|
|
842
|
+
dimensions,
|
|
843
|
+
];
|
|
844
844
|
|
|
845
845
|
/* Returns player view style based on platform and content type (audio/video) */
|
|
846
846
|
private getPlayerViewStyle = (
|
|
847
847
|
dimensions: ViewStyle,
|
|
848
848
|
isAudioItem: boolean
|
|
849
|
-
): ViewStyle => {
|
|
850
|
-
const generalStyles = isAudioItem ? styles.audio :
|
|
849
|
+
): ViewStyle | ViewStyle[] => {
|
|
850
|
+
const generalStyles = isAudioItem ? styles.audio : undefined;
|
|
851
851
|
|
|
852
852
|
if (isAndroidPlatform() && isAudioItem) {
|
|
853
853
|
return generalStyles;
|
|
854
854
|
}
|
|
855
855
|
|
|
856
|
-
return
|
|
856
|
+
return [generalStyles, dimensions];
|
|
857
857
|
};
|
|
858
858
|
|
|
859
859
|
private renderAudioPlayer = (
|
|
@@ -876,7 +876,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
876
876
|
shouldRender: boolean,
|
|
877
877
|
imageKey: string,
|
|
878
878
|
entry: ZappEntry,
|
|
879
|
-
style: ViewStyle
|
|
879
|
+
style: ViewStyle | ViewStyle[]
|
|
880
880
|
) => {
|
|
881
881
|
if (!shouldRender) return null;
|
|
882
882
|
|
|
@@ -887,7 +887,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
887
887
|
|
|
888
888
|
private renderNativePlayer = (
|
|
889
889
|
shouldRender: boolean,
|
|
890
|
-
style: ViewStyle,
|
|
890
|
+
style: ViewStyle | ViewStyle[],
|
|
891
891
|
nativeEvents: ReturnType<typeof this.getNativeEvents>,
|
|
892
892
|
nativeProps: ReturnType<typeof this.getNativeProps>,
|
|
893
893
|
pluginConfiguration: Record<string, any>
|
|
@@ -1128,10 +1128,10 @@ export default class VideoPlayer extends React.Component<
|
|
|
1128
1128
|
isTV() && this.getPlayNextData() && !docked;
|
|
1129
1129
|
|
|
1130
1130
|
const needsToRender =
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
docked;
|
|
1131
|
+
!hideTransportControls &&
|
|
1132
|
+
!needToShowPlayNextOverlay &&
|
|
1133
|
+
this.props.mode !== "PIP" &&
|
|
1134
|
+
!docked;
|
|
1135
1135
|
|
|
1136
1136
|
const supportsNativeControls =
|
|
1137
1137
|
!!this.props.controller?.supportsNativeControls?.();
|
|
@@ -1265,13 +1265,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
1265
1265
|
</View>
|
|
1266
1266
|
}
|
|
1267
1267
|
/>
|
|
1268
|
-
) : (
|
|
1268
|
+
) : isModal ? (
|
|
1269
1269
|
<VideoPlayerModal
|
|
1270
1270
|
isTabletPortrait={isTabletPortrait}
|
|
1271
1271
|
aspectRatio={aspectRatio}
|
|
1272
1272
|
pip={piped}
|
|
1273
1273
|
fullscreen={fullscreen}
|
|
1274
|
-
modal
|
|
1274
|
+
modal
|
|
1275
1275
|
style={{
|
|
1276
1276
|
tabletLandscapeWidth: getTabletWidth(
|
|
1277
1277
|
this.getPluginConfiguration().tablet_landscape_sidebar_width,
|
|
@@ -1309,6 +1309,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
1309
1309
|
</View>
|
|
1310
1310
|
}
|
|
1311
1311
|
/>
|
|
1312
|
+
) : (
|
|
1313
|
+
<View style={style} testID={"player-view"}>
|
|
1314
|
+
<PlayerWrapper
|
|
1315
|
+
{...sharedWrapperViewProps}
|
|
1316
|
+
playerContent={this.renderPlayerContent}
|
|
1317
|
+
/>
|
|
1318
|
+
</View>
|
|
1312
1319
|
);
|
|
1313
1320
|
};
|
|
1314
1321
|
|