@applicaster/quick-brick-player 14.0.0-rc.7 → 14.0.0-rc.71

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 (28) hide show
  1. package/package.json +6 -11
  2. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +25 -81
  3. package/src/Player/AudioLayer/Layout/Controls/index.tsx +8 -18
  4. package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +119 -119
  5. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +5 -38
  6. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +3 -8
  7. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +5 -9
  8. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +22 -72
  9. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +1 -58
  10. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +0 -33
  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/PlayerModal/GestureAnimatedScrollView.ts +7 -0
  14. package/src/Player/PlayerModal/PlayerModal.tsx +109 -0
  15. package/src/Player/PlayerModal/VideoPlayerModal.tsx +271 -0
  16. package/src/Player/PlayerModal/consts/index.ts +34 -0
  17. package/src/Player/PlayerModal/context/index.ts +6 -0
  18. package/src/Player/PlayerModal/hooks/index.ts +193 -0
  19. package/src/Player/PlayerModal/index.ts +3 -0
  20. package/src/Player/PlayerModal/index.web.ts +5 -0
  21. package/src/Player/PlayerModal/styles.ts +104 -0
  22. package/src/Player/PlayerView/GenericTVPlayerView.tsx +42 -0
  23. package/src/Player/PlayerView/TVPlayerView.tsx +26 -0
  24. package/src/Player/PlayerView/TvOSPlayerView.tsx +51 -0
  25. package/src/Player/PlayerView/types.ts +42 -0
  26. package/src/Player/index.tsx +187 -190
  27. package/src/QuickBrickPlayer.tsx +16 -10
  28. /package/src/Player/AudioLayer/Layout/{Debug → DebugComponent}/index.tsx +0 -0
@@ -0,0 +1,271 @@
1
+ import React, { ReactElement, useRef } from "react";
2
+
3
+ import { Animated, Pressable, StyleSheet, ViewStyle } 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_START,
11
+ MODAL_RADIUS,
12
+ SCREEN_HEIGHT,
13
+ SCREEN_WIDTH,
14
+ VIDEO_TRANSITION_THRESHOLD,
15
+ } from "./consts";
16
+ import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
17
+ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
18
+ import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/useModalAnimationContext";
19
+ import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
20
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
21
+ import { GestureAnimatedScrollView } from "./GestureAnimatedScrollView";
22
+ import { PlayerDetailsWrapperHeightContext } from "./context";
23
+
24
+ const orientationStyles = StyleSheet.create({
25
+ landscape: { flexDirection: "row" },
26
+ portrait: { flexDirection: "column" },
27
+ });
28
+
29
+ const directionStyles = (isLandscape: boolean): ViewStyle => {
30
+ return isLandscape ? orientationStyles.landscape : orientationStyles.portrait;
31
+ };
32
+
33
+ type AnimatedModalProps = {
34
+ pip?: boolean;
35
+ fullscreen?: boolean;
36
+ modal?: boolean;
37
+ content?: ReactElement;
38
+ collapsedContent?: ReactElement;
39
+ extraContent?: ReactElement;
40
+ aspectRatio?: number;
41
+ isTabletPortrait?: boolean;
42
+ style?: {
43
+ tabletLandscapeWidth?: number;
44
+ width?: number;
45
+ height?: number;
46
+ };
47
+ };
48
+
49
+ const height = SCREEN_HEIGHT;
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
+ let width = SCREEN_WIDTH;
66
+
67
+ if (isTablet && !isTabletPortrait) {
68
+ width = style?.tabletLandscapeWidth || width;
69
+ }
70
+
71
+ const { minimised_height: minimisedHeight } = useConfiguration();
72
+ const scrollViewRef = useRef<typeof Animated.ScrollView | null>(null);
73
+
74
+ const translateYRef = useModalAnimationContext().yTranslate;
75
+ // used when modal is false, should not be used in animation
76
+ const dummyRef = useRef(new Animated.Value(0));
77
+
78
+ const {
79
+ translateY,
80
+ collapsed,
81
+ collapsedHeight,
82
+ gestureHandlerProps,
83
+ expand,
84
+ } = useVideoModalState(modal ? translateYRef : dummyRef);
85
+
86
+ const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
87
+
88
+ const styles = useStyles({ height: collapsedHeight });
89
+
90
+ const SCALE_FACTOR = 1 / (width / aspectRatio / minimisedHeight); // Scale factor for expanded content
91
+
92
+ const insets = useSafeAreaInsets();
93
+
94
+ const isFullScreenOrPIP = fullscreen || pip;
95
+
96
+ // Interpolated opacities for smooth cross-fade
97
+ const collapsedOpacity = !isFullScreenOrPIP
98
+ ? translateY.interpolate({
99
+ inputRange: [MODAL_COLLAPSE_START, height - collapsedHeight],
100
+ outputRange: [0, 1],
101
+ extrapolate: "clamp",
102
+ })
103
+ : new Animated.Value(0);
104
+
105
+ const expandedOpacity = !isFullScreenOrPIP
106
+ ? translateY.interpolate({
107
+ inputRange: [0, height - collapsedHeight],
108
+ outputRange: [1, 0],
109
+ extrapolate: "clamp",
110
+ })
111
+ : new Animated.Value(1);
112
+
113
+ const xPosition = !isFullScreenOrPIP
114
+ ? translateY.interpolate({
115
+ inputRange: [
116
+ height * VIDEO_TRANSITION_THRESHOLD,
117
+ height - collapsedHeight,
118
+ ],
119
+ outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
120
+ extrapolate: "clamp",
121
+ })
122
+ : new Animated.Value(0);
123
+
124
+ const vidHeight = width / aspectRatio;
125
+
126
+ const yPosition = !isFullScreenOrPIP
127
+ ? translateY.interpolate({
128
+ inputRange: [
129
+ height * VIDEO_TRANSITION_THRESHOLD,
130
+ height - collapsedHeight,
131
+ ],
132
+ outputRange: [
133
+ 0,
134
+ isTablet && isTabletLandscape
135
+ ? -((-PROGRESS_BAR_HEIGHT + height - vidHeight * SCALE_FACTOR) / 2)
136
+ : -(
137
+ PROGRESS_BAR_HEIGHT +
138
+ insets.top / 2 +
139
+ (SCREEN_WIDTH / aspectRatio -
140
+ (SCREEN_WIDTH / aspectRatio) * SCALE_FACTOR) /
141
+ 2
142
+ ),
143
+ ],
144
+ extrapolate: "clamp",
145
+ })
146
+ : new Animated.Value(0);
147
+
148
+ const scalePosition = !isFullScreenOrPIP
149
+ ? translateY.interpolate({
150
+ inputRange: [
151
+ height * VIDEO_TRANSITION_THRESHOLD,
152
+ height - collapsedHeight,
153
+ ],
154
+ outputRange: [1, SCALE_FACTOR],
155
+ extrapolate: "clamp",
156
+ })
157
+ : new Animated.Value(1);
158
+
159
+ const borderTopRadiusAnimated = !isFullScreenOrPIP
160
+ ? translateY.interpolate({
161
+ inputRange: [0, height - collapsedHeight],
162
+ outputRange: [MODAL_RADIUS, 0],
163
+ extrapolate: "clamp",
164
+ })
165
+ : new Animated.Value(0);
166
+
167
+ const [playerDetailsWrapperHeight, setPlayerDetailsWrapperHeight] =
168
+ React.useState(0);
169
+
170
+ const onScrollViewLayout = React.useCallback(
171
+ ({
172
+ nativeEvent: {
173
+ layout: { height },
174
+ },
175
+ }) => {
176
+ setPlayerDetailsWrapperHeight(height);
177
+ },
178
+ []
179
+ );
180
+
181
+ return (
182
+ <PanGestureHandler
183
+ enabled={enabled}
184
+ waitFor={scrollViewRef}
185
+ {...gestureHandlerProps}
186
+ >
187
+ <Animated.View
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
+ >
199
+ <Animated.View
200
+ pointerEvents={"auto"}
201
+ style={[
202
+ styles.modal,
203
+ collapsed ? styles.collapsedModalBg : null,
204
+ {
205
+ borderTopLeftRadius: borderTopRadiusAnimated,
206
+ borderTopRightRadius: borderTopRadiusAnimated,
207
+ height: height,
208
+ },
209
+ ]}
210
+ >
211
+ <Animated.View
212
+ pointerEvents={!collapsed ? "auto" : "none"}
213
+ style={[styles.modalContent, directionStyles(isTabletLandscape)]}
214
+ >
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={{
233
+ paddingBottom: insets.bottom,
234
+ }}
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}
248
+ </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
+ </Animated.View>
268
+ </Animated.View>
269
+ </PanGestureHandler>
270
+ );
271
+ }
@@ -0,0 +1,34 @@
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
+ export const DOCKED_PROGRESSBAR_HEIGHT = 3; // Height of the docked progress bar plugins/mobile-transport-controls/src/ProgressBar/layouts/DockedLayout.tsx
9
+
10
+ export const VIDEO_TRANSITION_THRESHOLD = 0.5; // Threshold for video transition
11
+
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
+ export const DRAG_TO_COLLAPSE = 0.02; // 2% to collapse
25
+
26
+ export const DRAG_TO_EXPAND = 0.02; // 2% to expand
27
+
28
+ export const DEFAULT_IMAGE_RATIO_VIDEO = 16 / 9; // Default aspect ratio for video
29
+
30
+ export const DEFAULT_IMAGE_RATIO_AUDIO = 1; // Default aspect ratio for audio
31
+
32
+ export const ANIMATION_DURATION = 250; // Default animation duration in milliseconds
33
+
34
+ export const MODAL_RADIUS = 16; // Default border radius for modal
@@ -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,193 @@
1
+ import { useCallback, useEffect, useMemo, useRef } from "react";
2
+ import { useSafeAreaInsets } from "react-native-safe-area-context";
3
+ import { State } from "react-native-gesture-handler";
4
+ import { Animated } from "react-native";
5
+
6
+ import { VideoModalMode } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
7
+ import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
8
+ import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
9
+ 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
+ import {
12
+ ANIMATION_DURATION,
13
+ DRAG_TO_COLLAPSE,
14
+ DRAG_TO_EXPAND,
15
+ SCREEN_HEIGHT,
16
+ } from "../consts";
17
+ import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
18
+ import { usePlugins } from "@applicaster/zapp-react-native-redux";
19
+
20
+ const bottomTabBarHeight = getTabBarHeight();
21
+
22
+ export const useVideoModalState = (
23
+ translateYRef: React.MutableRefObject<Animated.Value>
24
+ ) => {
25
+ const { minimised_height: minimisedHeight } = useConfiguration();
26
+
27
+ const {
28
+ maximiseVideoModal,
29
+ minimiseVideoModal,
30
+ videoModalState,
31
+ currentRoute,
32
+ screenData,
33
+ } = useNavigation();
34
+
35
+ const plugins = usePlugins();
36
+
37
+ const menuVisible = isMenuVisible(currentRoute, screenData, plugins);
38
+
39
+ const collapsed = videoModalState.mode === VideoModalMode.MINIMIZED;
40
+
41
+ const { bottom } = useSafeAreaInsets();
42
+
43
+ const initialBottomOffset = useRef(bottom).current;
44
+
45
+ const collapsedHeight =
46
+ minimisedHeight +
47
+ initialBottomOffset +
48
+ (menuVisible ? bottomTabBarHeight : 0) +
49
+ PROGRESS_BAR_HEIGHT;
50
+
51
+ const translateY = translateYRef.current;
52
+
53
+ const handleExpand = useCallback(
54
+ (toValue: number) => {
55
+ return Animated.timing(translateYRef.current, {
56
+ toValue,
57
+ duration: ANIMATION_DURATION,
58
+ useNativeDriver: true,
59
+ });
60
+ },
61
+ [translateYRef]
62
+ );
63
+
64
+ const handleCollapse = useCallback(
65
+ (toValue: number) => {
66
+ return Animated.timing(translateYRef.current, {
67
+ toValue,
68
+ duration: ANIMATION_DURATION,
69
+ useNativeDriver: true,
70
+ });
71
+ },
72
+ [translateYRef]
73
+ );
74
+
75
+ const offset = useRef(SCREEN_HEIGHT - collapsedHeight);
76
+
77
+ // Gesture handler for modal
78
+ const onGestureEvent = useCallback(
79
+ (event: any) => {
80
+ if (event.nativeEvent.state === State.ACTIVE) {
81
+ const y = event.nativeEvent.translationY;
82
+ let newY = offset.current + y;
83
+ if (newY < 0) newY = 0;
84
+
85
+ if (newY > SCREEN_HEIGHT - collapsedHeight) {
86
+ newY = SCREEN_HEIGHT - collapsedHeight;
87
+ }
88
+
89
+ translateY.setValue(newY);
90
+ }
91
+ },
92
+ [collapsedHeight, translateY]
93
+ );
94
+
95
+ const onHandlerStateChange = useCallback(
96
+ (event: any) => {
97
+ if (event.nativeEvent.oldState === State.ACTIVE) {
98
+ const { translationY } = event.nativeEvent;
99
+ let newY = offset.current + translationY;
100
+ if (newY < 0) newY = 0;
101
+
102
+ if (newY > SCREEN_HEIGHT - collapsedHeight) {
103
+ newY = SCREEN_HEIGHT - collapsedHeight;
104
+ }
105
+
106
+ const shouldCollapse =
107
+ translationY > (SCREEN_HEIGHT - collapsedHeight) * DRAG_TO_COLLAPSE;
108
+
109
+ const shouldExpand =
110
+ translationY < -(SCREEN_HEIGHT - collapsedHeight) * DRAG_TO_EXPAND;
111
+
112
+ if (!collapsed && shouldCollapse) {
113
+ // Collapse
114
+ Animated.timing(translateY, {
115
+ toValue: SCREEN_HEIGHT - collapsedHeight,
116
+ duration: ANIMATION_DURATION,
117
+ useNativeDriver: true,
118
+ }).start(() => {
119
+ minimiseVideoModal();
120
+ offset.current = SCREEN_HEIGHT - collapsedHeight;
121
+ });
122
+ } else if (collapsed && shouldExpand) {
123
+ // Expand
124
+ Animated.timing(translateY, {
125
+ toValue: 0,
126
+ duration: ANIMATION_DURATION,
127
+ useNativeDriver: true,
128
+ }).start(() => {
129
+ maximiseVideoModal();
130
+ offset.current = 0;
131
+ translateY.setValue(0);
132
+ });
133
+ } else {
134
+ // Snap back to current state
135
+ Animated.spring(translateY, {
136
+ toValue: collapsed ? SCREEN_HEIGHT - collapsedHeight : 0,
137
+ useNativeDriver: true,
138
+ }).start(() => {
139
+ offset.current = collapsed ? SCREEN_HEIGHT - collapsedHeight : 0;
140
+ translateY.setValue(offset.current);
141
+ });
142
+ }
143
+ } else if (event.nativeEvent.state === State.BEGAN) {
144
+ // Gesture started, set offset
145
+ translateY.stopAnimation((value: number) => {
146
+ offset.current = value;
147
+ });
148
+ }
149
+ },
150
+ [collapsedHeight, translateY, collapsed, videoModalState]
151
+ );
152
+
153
+ const gestureHandlerProps = useMemo(() => {
154
+ return {
155
+ onGestureEvent,
156
+ onHandlerStateChange,
157
+ };
158
+ }, [onGestureEvent, onHandlerStateChange]);
159
+
160
+ useEffect(() => {
161
+ if (videoModalState.mode === VideoModalMode.MAXIMIZED) {
162
+ handleExpand(0).start(() => {
163
+ maximiseVideoModal();
164
+ offset.current = 0;
165
+ translateY.setValue(0);
166
+ });
167
+ } else if (videoModalState.mode === VideoModalMode.MINIMIZED) {
168
+ handleCollapse(SCREEN_HEIGHT - collapsedHeight).start(() => {
169
+ minimiseVideoModal();
170
+ offset.current = SCREEN_HEIGHT - collapsedHeight;
171
+ translateY.setValue(SCREEN_HEIGHT - collapsedHeight);
172
+ });
173
+ }
174
+ }, [videoModalState.visible, videoModalState.mode, collapsedHeight]);
175
+
176
+ return useMemo(
177
+ () => ({
178
+ collapsed,
179
+ collapsedHeight,
180
+ offset,
181
+ gestureHandlerProps,
182
+ translateY,
183
+ expand: maximiseVideoModal,
184
+ }),
185
+ [
186
+ collapsed,
187
+ collapsedHeight,
188
+ gestureHandlerProps,
189
+ translateY,
190
+ maximiseVideoModal,
191
+ ]
192
+ );
193
+ };
@@ -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,104 @@
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
+ overflow: "hidden",
67
+ },
68
+ modalWrapper: {
69
+ backgroundColor: BG_COLOR_DEFAULT_BLACK,
70
+ },
71
+ collapsedModalBg: {
72
+ backgroundColor: BG_COLOR_DEFAULT_BLACK,
73
+ },
74
+ modalContent: {
75
+ flex: 1,
76
+ alignItems: "center",
77
+ },
78
+ expandedContentContainer: {
79
+ justifyContent: "flex-start",
80
+ backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
81
+ zIndex: 1,
82
+ flex: 0,
83
+ },
84
+ extraContentScrollView: {
85
+ width: "100%",
86
+ backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
87
+ },
88
+ collapsedBarContainer: {
89
+ ...StyleSheet.absoluteFillObject,
90
+ height: COLLAPSED_HEIGHT,
91
+ zIndex: 90,
92
+ justifyContent: "flex-end",
93
+ },
94
+ collapsedBarWrapper: {
95
+ flex: 1,
96
+ },
97
+ flexNone: {
98
+ ...StyleSheet.absoluteFillObject,
99
+ flex: -1,
100
+ },
101
+ }),
102
+ [backgroundColor, COLLAPSED_HEIGHT]
103
+ );
104
+ };
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import { PlayNextOverlay } from "../PlayNextOverlay";
3
+ import { GenericTVPlayerViewProps } from "./types";
4
+ import { AudioPlayer } from "@applicaster/zapp-react-native-ui-components/Components/AudioPlayer";
5
+
6
+ export const GenericTVPlayerView: React.FC<GenericTVPlayerViewProps> = ({
7
+ children,
8
+ type,
9
+ PlayerComponent,
10
+ pluginConfiguration,
11
+ playerProps,
12
+ playNextProps,
13
+ audioPlayerProps,
14
+ transportControls,
15
+ entry,
16
+ }) => {
17
+ return (
18
+ <>
19
+ {type === "audio" ? (
20
+ <AudioPlayer
21
+ audio_item={entry}
22
+ plugin_configuration={pluginConfiguration}
23
+ {...audioPlayerProps}
24
+ />
25
+ ) : null}
26
+ <PlayerComponent
27
+ pluginConfiguration={pluginConfiguration}
28
+ {...playerProps}
29
+ >
30
+ {children}
31
+ </PlayerComponent>
32
+ {transportControls}
33
+ {playNextProps.playNextData ? (
34
+ <PlayNextOverlay
35
+ item={entry}
36
+ pluginConfiguration={pluginConfiguration}
37
+ {...playNextProps}
38
+ />
39
+ ) : null}
40
+ </>
41
+ );
42
+ };
@@ -0,0 +1,26 @@
1
+ import React from "react";
2
+ import { isTvOSPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
3
+ import { TvOSPlayerView } from "./TvOSPlayerView";
4
+ import { GenericTVPlayerView } from "./GenericTVPlayerView";
5
+ import {
6
+ GenericTVPlayerViewProps,
7
+ TvOSPlayerViewProps,
8
+ TVPlayerViewProps,
9
+ } from "./types";
10
+
11
+ const isTvOS = isTvOSPlatform();
12
+
13
+ const shouldRenderTvOSPlayerView = (
14
+ isTvOS: boolean,
15
+ inline: boolean
16
+ ): boolean => {
17
+ return isTvOS && !inline;
18
+ };
19
+
20
+ export const TVPlayerView: React.FC<TVPlayerViewProps> = (props) => {
21
+ return shouldRenderTvOSPlayerView(isTvOS, props.inline) ? (
22
+ <TvOSPlayerView {...(props as TvOSPlayerViewProps)} />
23
+ ) : (
24
+ <GenericTVPlayerView {...(props as GenericTVPlayerViewProps)} />
25
+ );
26
+ };