@applicaster/quick-brick-player 14.0.0-rc.9 → 14.0.0-rc.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/package.json +6 -11
  2. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +44 -88
  3. package/src/Player/AudioLayer/Layout/Controls/index.tsx +8 -18
  4. package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +169 -161
  5. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +4 -42
  6. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +5 -9
  7. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +35 -83
  8. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +6 -1
  9. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +6 -66
  10. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +1 -39
  11. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +6 -18
  12. package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +1 -1
  13. package/src/Player/AudioLayer/utils.ts +1 -27
  14. package/src/Player/PlayerModal/GestureAnimatedScrollView.ts +7 -0
  15. package/src/Player/PlayerModal/PlayerModal.tsx +110 -0
  16. package/src/Player/PlayerModal/VideoPlayerModal.tsx +289 -0
  17. package/src/Player/PlayerModal/consts/index.ts +17 -0
  18. package/src/Player/PlayerModal/context/index.ts +6 -0
  19. package/src/Player/PlayerModal/hooks/index.ts +169 -0
  20. package/src/Player/PlayerModal/index.ts +3 -0
  21. package/src/Player/PlayerModal/index.web.ts +5 -0
  22. package/src/Player/PlayerModal/styles.ts +109 -0
  23. package/src/Player/PlayerModal/utils/index.ts +111 -0
  24. package/src/Player/PlayerView/GenericTVPlayerView.tsx +42 -0
  25. package/src/Player/PlayerView/TVPlayerView.tsx +26 -0
  26. package/src/Player/PlayerView/TvOSPlayerView.tsx +51 -0
  27. package/src/Player/PlayerView/types.ts +41 -0
  28. package/src/Player/index.tsx +575 -380
  29. package/src/QuickBrickPlayer.tsx +16 -10
  30. package/src/utils/dimensions.ts +29 -0
  31. package/src/utils/index.ts +12 -0
  32. package/src/utils/logger.ts +6 -0
  33. package/src/utils/playerHelpers.ts +11 -0
  34. package/src/utils/playerStyles.ts +50 -0
  35. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +0 -87
  36. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +0 -1
  37. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +0 -99
  38. /package/src/Player/AudioLayer/Layout/{Debug → DebugComponent}/index.tsx +0 -0
@@ -0,0 +1,289 @@
1
+ import React, { ReactElement, useMemo, useRef } from "react";
2
+
3
+ import { Animated, Pressable } from "react-native";
4
+ import { PanGestureHandler } from "react-native-gesture-handler";
5
+ import { useStyles } from "./styles";
6
+ import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
7
+ import { useVideoModalState } from "./hooks";
8
+ import {
9
+ DEFAULT_IMAGE_RATIO_VIDEO,
10
+ MODAL_COLLAPSE_RATIO,
11
+ MODAL_RADIUS,
12
+ VIDEO_TRANSITION_THRESHOLD,
13
+ } from "./consts";
14
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
15
+ import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
16
+ import {
17
+ SafeAreaView,
18
+ useSafeAreaFrame,
19
+ useSafeAreaInsets,
20
+ } from "react-native-safe-area-context";
21
+ import { GestureAnimatedScrollView } from "./GestureAnimatedScrollView";
22
+ import { PlayerDetailsWrapperHeightContext } from "./context";
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";
32
+
33
+ const AnimatedSafeAreaView = Animated.createAnimatedComponent(SafeAreaView);
34
+
35
+ type AnimatedModalProps = {
36
+ pip?: boolean;
37
+ fullscreen?: boolean;
38
+ modal?: boolean;
39
+ content?: ReactElement;
40
+ collapsedContent?: ReactElement;
41
+ extraContent?: ReactElement;
42
+ aspectRatio?: number;
43
+ isTabletPortrait?: boolean;
44
+ style?: {
45
+ tabletLandscapeWidth?: number;
46
+ width?: number;
47
+ height?: number;
48
+ };
49
+ };
50
+
51
+ export function VideoPlayerModal({
52
+ aspectRatio = DEFAULT_IMAGE_RATIO_VIDEO,
53
+ content,
54
+ extraContent,
55
+ collapsedContent,
56
+ isTabletPortrait,
57
+ style,
58
+ pip = false,
59
+ fullscreen = false,
60
+ modal = true,
61
+ }: AnimatedModalProps) {
62
+ const enabled = !!modal && !fullscreen;
63
+ const isTablet = useIsTablet();
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
+ );
74
+
75
+ const height = useMemo(
76
+ () => getWindowHeight(isTablet, !isTabletPortrait),
77
+ []
78
+ ); // remember initial height, ignore rotation changes
79
+
80
+ const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
81
+
82
+ const { minimised_height: minimisedHeight } = useConfiguration();
83
+ const scrollViewRef = useRef<typeof Animated.ScrollView | null>(null);
84
+
85
+ const { translateY, collapsed, gestureHandlerProps, expand, offset } =
86
+ useVideoModalState();
87
+
88
+ const frame = useSafeAreaFrame();
89
+ const collapsedHeight = frame.height - offset.current;
90
+
91
+ const heightAboveMinimised = height - collapsedHeight;
92
+
93
+ const styles = useStyles({ height: collapsedHeight });
94
+
95
+ const SCALE_FACTOR = 1 / (width / aspectRatio / minimisedHeight); // Scale factor for expanded content
96
+
97
+ const insets = useSafeAreaInsets();
98
+
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;
118
+
119
+ // animated opacity for smooth cross-fade of collapsed content
120
+ const collapsedOpacity = !isFullScreenOrPIP
121
+ ? translateY.interpolate({
122
+ inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
123
+ outputRange: [0, 1],
124
+ extrapolate: "clamp",
125
+ })
126
+ : new Animated.Value(0);
127
+
128
+ // animated opacity for extra content
129
+ const expandedOpacity = !isFullScreenOrPIP
130
+ ? translateY.interpolate({
131
+ inputRange: [0, heightAboveMinimised],
132
+ outputRange: [1, 0],
133
+ extrapolate: "clamp",
134
+ })
135
+ : new Animated.Value(1);
136
+
137
+ // animated x position for video content
138
+ const xPosition = !isFullScreenOrPIP
139
+ ? translateY.interpolate({
140
+ inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
141
+ outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
142
+ extrapolate: "clamp",
143
+ })
144
+ : new Animated.Value(0);
145
+
146
+ // animated y position for video content
147
+ const yPosition = !isFullScreenOrPIP
148
+ ? translateY.interpolate({
149
+ inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
150
+ outputRange: [
151
+ 0,
152
+ -(
153
+ PROGRESS_BAR_HEIGHT +
154
+ getInsetsOffset(insets, isTabletPortrait) +
155
+ getScaledPos(height, vidHeight, minimisedHeight, isTabletPortrait)
156
+ ),
157
+ ],
158
+ extrapolate: "clamp",
159
+ })
160
+ : new Animated.Value(0);
161
+
162
+ // animated position for video content
163
+ const scalePosition = !isFullScreenOrPIP
164
+ ? translateY.interpolate({
165
+ inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
166
+ outputRange: [1, SCALE_FACTOR],
167
+ extrapolate: "clamp",
168
+ })
169
+ : new Animated.Value(1);
170
+
171
+ const borderTopRadiusAnimated = !isFullScreenOrPIP
172
+ ? translateY.interpolate({
173
+ inputRange: [0, heightAboveMinimised],
174
+ outputRange: [MODAL_RADIUS, 0],
175
+ extrapolate: "clamp",
176
+ })
177
+ : new Animated.Value(0);
178
+
179
+ const [playerDetailsWrapperHeight, setPlayerDetailsWrapperHeight] =
180
+ React.useState(0);
181
+
182
+ const onScrollViewLayout = React.useCallback(
183
+ ({
184
+ nativeEvent: {
185
+ layout: { height },
186
+ },
187
+ }) => {
188
+ setPlayerDetailsWrapperHeight(height);
189
+ },
190
+ []
191
+ );
192
+
193
+ return (
194
+ <PanGestureHandler
195
+ enabled={enabled}
196
+ waitFor={scrollViewRef}
197
+ activeOffsetY={[-25, 25]}
198
+ activeOffsetX={[-25, 25]}
199
+ {...gestureHandlerProps}
200
+ >
201
+ <AnimatedSafeAreaView pointerEvents="box-none" edges={["bottom"]}>
202
+ <Animated.View
203
+ pointerEvents={"auto"}
204
+ style={[
205
+ styles.modalWrapper,
206
+ {
207
+ borderTopLeftRadius: borderTopRadiusAnimated,
208
+ borderTopRightRadius: borderTopRadiusAnimated,
209
+ transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
210
+ height: frame.height,
211
+ },
212
+ ]}
213
+ >
214
+ <Animated.View
215
+ pointerEvents={"auto"}
216
+ style={[
217
+ styles.modal,
218
+ collapsed ? styles.collapsedModalBg : null,
219
+ {
220
+ borderTopLeftRadius: borderTopRadiusAnimated,
221
+ borderTopRightRadius: borderTopRadiusAnimated,
222
+ },
223
+ ]}
224
+ >
225
+ <Animated.View
226
+ pointerEvents={!collapsed ? "auto" : "none"}
227
+ style={[
228
+ pip ? styles.modalContentPiP : styles.modalContent,
229
+ directionStyles(isTabletPortrait),
230
+ ]}
231
+ >
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}
265
+ </Animated.View>
266
+
267
+ {!isFullScreenOrPIP ? (
268
+ <Animated.View
269
+ pointerEvents={collapsed ? "box-none" : "none"}
270
+ style={[
271
+ styles.collapsedBarContainer,
272
+ { opacity: collapsedOpacity },
273
+ ]}
274
+ >
275
+ <Pressable
276
+ testID="collapsedBarWrapper"
277
+ onPress={expand}
278
+ style={styles.collapsedBarWrapper}
279
+ >
280
+ {collapsedContent}
281
+ </Pressable>
282
+ </Animated.View>
283
+ ) : null}
284
+ </Animated.View>
285
+ </Animated.View>
286
+ </AnimatedSafeAreaView>
287
+ </PanGestureHandler>
288
+ );
289
+ }
@@ -0,0 +1,17 @@
1
+ export const DOCKED_PROGRESSBAR_HEIGHT = 3; // Height of the docked progress bar plugins/mobile-transport-controls/src/ProgressBar/layouts/DockedLayout.tsx
2
+
3
+ export const VIDEO_TRANSITION_THRESHOLD = 0.5; // Threshold for video transition
4
+
5
+ export const DRAG_TO_COLLAPSE = 0.02; // 2% to collapse
6
+
7
+ export const DRAG_TO_EXPAND = 0.02; // 2% to expand
8
+
9
+ export const DEFAULT_IMAGE_RATIO_VIDEO = 16 / 9; // Default aspect ratio for video
10
+
11
+ export const DEFAULT_IMAGE_RATIO_AUDIO = 1; // Default aspect ratio for audio
12
+
13
+ export const ANIMATION_DURATION = 250; // Default animation duration in milliseconds
14
+
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
@@ -0,0 +1,6 @@
1
+ import React from "react";
2
+
3
+ export const PlayerDetailsWrapperHeightContext = React.createContext(null);
4
+
5
+ export const usePlayerDetailsWrapperHeight = () =>
6
+ React.useContext(PlayerDetailsWrapperHeightContext);
@@ -0,0 +1,169 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+
3
+ import { State } from "react-native-gesture-handler";
4
+
5
+ import { VideoModalMode } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
6
+ import { useAnimationStateStore } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
7
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
8
+ import {
9
+ ANIMATION_DURATION,
10
+ DRAG_TO_COLLAPSE,
11
+ DRAG_TO_EXPAND,
12
+ } from "../consts";
13
+ import { Animated } from "react-native";
14
+ import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
15
+
16
+ const getAnimatedValue = (animatedValue: Animated.Value): number => {
17
+ return (animatedValue as any).__getValue() as number;
18
+ };
19
+
20
+ export const useVideoModalState = () => {
21
+ const {
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, {
35
+ toValue,
36
+ duration,
37
+ useNativeDriver: true,
38
+ }),
39
+ [modalAnimatedValue]
40
+ );
41
+
42
+ const translateY = yTranslate.current;
43
+
44
+ const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
45
+ useNavigation();
46
+
47
+ const videoModalMode = videoModalState.mode;
48
+
49
+ const prevModeStateRef = useRef(videoModalMode); // keep track of last non-PIP mode
50
+ const gestureStateRef = useRef<any>(State.UNDETERMINED); // keep track of gesture state
51
+
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
+ []
73
+ );
74
+
75
+ const onHandlerStateChange = useCallback(
76
+ (event: any) => {
77
+ const { state: newState, oldState, translationY } = event.nativeEvent;
78
+
79
+ if (newState === State.ACTIVE || oldState === State.ACTIVE) {
80
+ useAnimationStateStore.setState({
81
+ isAnimationInProgress: newState === State.ACTIVE,
82
+ });
83
+ }
84
+
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
+ }
125
+ }
126
+ }
127
+ },
128
+ // eslint-disable-next-line react-hooks/exhaustive-deps
129
+ [collapsed]
130
+ );
131
+
132
+ const gestureHandlerProps = useMemo(() => {
133
+ return {
134
+ onGestureEvent,
135
+ onHandlerStateChange,
136
+ };
137
+ }, [onGestureEvent, onHandlerStateChange]);
138
+
139
+ // Track video modal state changes & calling updateAnimatedPosition
140
+ useEffect(() => {
141
+ if (videoModalState.visible) {
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();
154
+ }
155
+ }
156
+ // eslint-disable-next-line react-hooks/exhaustive-deps
157
+ }, [videoModalState.visible, videoModalState.mode, heightAboveMinimised]);
158
+
159
+ return useMemo(
160
+ () => ({
161
+ collapsed,
162
+ offset,
163
+ gestureHandlerProps,
164
+ translateY,
165
+ expand: maximiseVideoModal,
166
+ }),
167
+ [collapsed, offset, gestureHandlerProps, translateY, maximiseVideoModal]
168
+ );
169
+ };
@@ -0,0 +1,3 @@
1
+ export { AnimatedModal as default } from "./PlayerModal";
2
+
3
+ export { VideoPlayerModal } from "./VideoPlayerModal";
@@ -0,0 +1,5 @@
1
+ const View = require("react-native").View;
2
+
3
+ export const VideoPlayerModal = View;
4
+
5
+ export default View;
@@ -0,0 +1,109 @@
1
+ import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
2
+ import {
3
+ useIsTablet,
4
+ useNavigation,
5
+ } from "@applicaster/zapp-react-native-utils/reactHooks";
6
+ import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
7
+ import { useMemo } from "react";
8
+ import { StyleSheet } from "react-native";
9
+
10
+ export const useBackgroundColor = (): string => {
11
+ const {
12
+ modal_background_color: modalBackgroundColor,
13
+ tablet_landscape_player_container_background_color: tabletBackgroundColor,
14
+ } = useConfiguration();
15
+
16
+ const {
17
+ videoModalState: { mode },
18
+ } = useNavigation();
19
+
20
+ const isTablet = useIsTablet();
21
+
22
+ const theme = useTheme<BaseThemePropertiesMobile>();
23
+ const isFullscreen = mode === "FULLSCREEN";
24
+
25
+ /**
26
+ * For the new audio player, the background color setting work that way
27
+ * Layer 0 - modal_background_color
28
+ * Layer 1 - screen_background_color ( can be combined with layer 0 ), If the parameter is not set, it will be a solid black.
29
+ * audio_player_background_color is used only in the old player when the background image is not set
30
+ * modal_background_color is used as the background for player details, and in useBackgroundColor to set a background for a video modal.
31
+ * If it’s not set, theme?.status_background_color will be used instead
32
+ *
33
+ * This hook cover only case with layer 0: modal_background_color, layer 1: screen_background_color is used in the styles.expandedContentContainer
34
+ *
35
+ * For the video player, inline player will use tablet_landscape_player_container_background_color as background color, and transparent for fullscreen.
36
+ * Mobile player will use
37
+ * modal_background_color as background color.
38
+ */
39
+
40
+ return isTablet
41
+ ? !isFullscreen
42
+ ? tabletBackgroundColor
43
+ : "transparent"
44
+ : modalBackgroundColor || theme?.status_background_color;
45
+ };
46
+
47
+ export const useStyles = ({ height }: { height: number }) => {
48
+ const COLLAPSED_HEIGHT = height;
49
+
50
+ const backgroundColor = useBackgroundColor();
51
+
52
+ const BG_COLOR_DEFAULT_BLACK = "black";
53
+ const BG_COLOR_DEFAULT_TRANSPARENT = "transparent";
54
+
55
+ return useMemo(
56
+ () =>
57
+ StyleSheet.create({
58
+ modal: {
59
+ position: "absolute",
60
+ left: 0,
61
+ right: 0,
62
+ top: 0,
63
+ backgroundColor,
64
+ elevation: 10,
65
+ zIndex: 100,
66
+ height: "100%",
67
+ overflow: "hidden",
68
+ },
69
+ modalWrapper: {
70
+ backgroundColor: BG_COLOR_DEFAULT_BLACK,
71
+ },
72
+ collapsedModalBg: {
73
+ backgroundColor: BG_COLOR_DEFAULT_BLACK,
74
+ },
75
+ modalContent: {
76
+ flex: 1,
77
+ alignItems: "center",
78
+ },
79
+ modalContentPiP: {
80
+ flex: 1,
81
+ alignItems: "flex-start",
82
+ },
83
+ expandedContentContainer: {
84
+ justifyContent: "flex-start",
85
+ backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
86
+ zIndex: 1,
87
+ flex: 0,
88
+ },
89
+ extraContentScrollView: {
90
+ width: "100%",
91
+ backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
92
+ },
93
+ collapsedBarContainer: {
94
+ ...StyleSheet.absoluteFillObject,
95
+ height: COLLAPSED_HEIGHT,
96
+ zIndex: 90,
97
+ justifyContent: "flex-end",
98
+ },
99
+ collapsedBarWrapper: {
100
+ flex: 1,
101
+ },
102
+ flexNone: {
103
+ ...StyleSheet.absoluteFillObject,
104
+ flex: -1,
105
+ },
106
+ }),
107
+ [backgroundColor, COLLAPSED_HEIGHT]
108
+ );
109
+ };