@applicaster/quick-brick-player 13.0.0-rc.12 → 13.0.0-rc.120

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 (44) hide show
  1. package/package.json +27 -14
  2. package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
  3. package/src/Player/AudioLayer/AudioDescription.tsx +107 -68
  4. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +205 -281
  5. package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +45 -0
  6. package/src/Player/AudioLayer/Layout/Controls/index.tsx +320 -0
  7. package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +7 -25
  8. package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
  9. package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +62 -83
  10. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +230 -0
  11. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +70 -0
  12. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +20 -0
  13. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +108 -0
  14. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +36 -0
  15. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +220 -0
  16. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +223 -0
  17. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +128 -0
  18. package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
  19. package/src/Player/AudioLayer/Layout/const.ts +26 -0
  20. package/src/Player/AudioLayer/Layout/debug.ts +6 -0
  21. package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
  22. package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
  23. package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
  24. package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
  25. package/src/Player/AudioLayer/Layout/index.tsx +21 -48
  26. package/src/Player/AudioLayer/Layout/types.ts +7 -0
  27. package/src/Player/AudioLayer/Layout/utils.ts +7 -0
  28. package/src/Player/AudioLayer/SleepTimerManager.ts +119 -0
  29. package/src/Player/AudioLayer/SpeedManager.ts +52 -0
  30. package/src/Player/AudioLayer/utils.ts +27 -0
  31. package/src/Player/Const/sleepTimerOptions.ts +39 -0
  32. package/src/Player/Const/speedOptions.ts +4 -0
  33. package/src/Player/Utils/Utils.ts +0 -5
  34. package/src/Player/Utils/index.tsx +117 -0
  35. package/src/Player/hooks/useIsCasting.tsx +57 -0
  36. package/src/Player/index.tsx +39 -22
  37. package/src/QuickBrickPlayer.tsx +3 -0
  38. package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
  39. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
  40. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
  41. package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
  42. package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
  43. package/src/Player/Helpers/VideoResizeMode.ts +0 -7
  44. package/src/utils/utils.ts +0 -25
@@ -0,0 +1,230 @@
1
+ import * as React from "react";
2
+ import { StyleSheet, View, ViewStyle } from "react-native";
3
+ import {
4
+ useSafeAreaFrame,
5
+ useSafeAreaInsets,
6
+ } from "react-native-safe-area-context";
7
+ import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
+
9
+ import { MOBILE, NAVBAR_HEIGHT } from "./const";
10
+ import { TransportInfo } from "./TransportInfo";
11
+ import { PlayerImage } from "./PlayerImage";
12
+ import { Controls } from "./Controls";
13
+
14
+ import { useMobileLayoutImageSize, useTransportInfoHeight } from "./hooks";
15
+ import { DockedControls } from "./DockedControls";
16
+ import { DEBUG, withDebug } from "./debug";
17
+ import {
18
+ BottomDebugSquare,
19
+ LeftDebugSquare,
20
+ RightDebugSquare,
21
+ } from "./Debug/index";
22
+
23
+ import { Props } from "./types";
24
+
25
+ const styles = StyleSheet.create({
26
+ container: {
27
+ flex: 1,
28
+ },
29
+
30
+ flex: {
31
+ flex: 1,
32
+ },
33
+
34
+ audioPlayerContainer: {
35
+ flex: 1,
36
+ justifyContent: "flex-start",
37
+
38
+ minHeight: MOBILE.MIN_HEIGHT,
39
+
40
+ marginLeft: MOBILE.MARGIN_HORIZONTAL,
41
+ marginRight: MOBILE.MARGIN_HORIZONTAL,
42
+
43
+ marginTop: MOBILE.MARGIN_TOP,
44
+
45
+ ...withDebug({
46
+ borderWidth: 2,
47
+ borderColor: "blue",
48
+ }),
49
+ },
50
+ });
51
+
52
+ const mobileStyles = ({
53
+ screenHeight,
54
+ topInset,
55
+ bottomInset,
56
+ imageSize,
57
+ }): ViewStyle => ({
58
+ height: screenHeight - topInset - bottomInset,
59
+
60
+ opacity: imageSize ? 1 : 0, // hide content until imageSize is calculated
61
+
62
+ ...withDebug({
63
+ borderWidth: 2,
64
+ borderColor: "magenta",
65
+ }),
66
+ });
67
+
68
+ export function MobileLayout({
69
+ entry,
70
+ layoutState,
71
+ playerState,
72
+ value,
73
+ onPlaybackButtonPress,
74
+ onRewindButtonPress,
75
+ onForwardButtonPress,
76
+ onPlayerSeek,
77
+ onSkipStart,
78
+ onSkipLive,
79
+ onSpeedButtonPress,
80
+ onSleepButtonPress,
81
+ onCloseVideoModal,
82
+ playbackSpeedName,
83
+ playbackSleepName,
84
+ configuration,
85
+ dimensions,
86
+ playNextData,
87
+ cancelSleepTimer,
88
+ sleepTimerDate,
89
+ title,
90
+ summary,
91
+ }: Props) {
92
+ const { docked } = layoutState;
93
+
94
+ const { bottom: bottomInset, top: topInset } = useSafeAreaInsets();
95
+ const { height: screenHeight } = useSafeAreaFrame();
96
+ const { progressBarHeight } = useModalAnimationContext();
97
+
98
+ const { imageSize } = useMobileLayoutImageSize();
99
+
100
+ const { height: transportInfoHeight, onLayout: onTransportInfoLayout } =
101
+ useTransportInfoHeight();
102
+
103
+ const controlsContainerHeight = React.useMemo(() => {
104
+ return (
105
+ screenHeight -
106
+ topInset -
107
+ imageSize -
108
+ NAVBAR_HEIGHT -
109
+ MOBILE.MARGIN_BOTTOM -
110
+ MOBILE.MARGIN_TOP -
111
+ bottomInset
112
+ );
113
+ }, [screenHeight, topInset, imageSize, bottomInset]);
114
+
115
+ const verticalOffsetForImage = React.useMemo(() => {
116
+ return transportInfoHeight + MOBILE.MARGIN_TOP - progressBarHeight;
117
+ }, [transportInfoHeight, progressBarHeight]);
118
+
119
+ return (
120
+ <View
121
+ style={[
122
+ styles.container,
123
+ mobileStyles({
124
+ screenHeight,
125
+ topInset,
126
+ bottomInset,
127
+ imageSize,
128
+ }),
129
+ ]}
130
+ >
131
+ {DEBUG ? <LeftDebugSquare /> : null}
132
+ {DEBUG ? <RightDebugSquare /> : null}
133
+ {DEBUG ? <BottomDebugSquare /> : null}
134
+
135
+ {/* TransportInfo */}
136
+ <TransportInfo
137
+ entry={entry}
138
+ layoutState={layoutState}
139
+ value={value}
140
+ configuration={configuration}
141
+ onLayout={onTransportInfoLayout}
142
+ />
143
+
144
+ {/* TransportInfo */}
145
+
146
+ <View
147
+ style={[
148
+ styles.audioPlayerContainer,
149
+ {
150
+ width: imageSize,
151
+ },
152
+ ]}
153
+ >
154
+ {/* PlayerImage */}
155
+ <View
156
+ style={[
157
+ styles.flex,
158
+ {
159
+ maxHeight: imageSize,
160
+
161
+ ...withDebug({
162
+ borderWidth: 2,
163
+ borderColor: "yellow",
164
+ }),
165
+ },
166
+ ]}
167
+ >
168
+ <PlayerImage
169
+ entry={entry}
170
+ layoutState={layoutState}
171
+ playerState={playerState}
172
+ value={value}
173
+ configuration={configuration}
174
+ onPlayerSeek={onPlayerSeek}
175
+ onCloseVideoModal={onCloseVideoModal}
176
+ dimensions={dimensions}
177
+ playNextData={playNextData}
178
+ title={title}
179
+ summary={summary}
180
+ docked={docked}
181
+ imageWidth={imageSize}
182
+ verticalOffset={verticalOffsetForImage}
183
+ />
184
+ </View>
185
+ {/* PlayerImage */}
186
+
187
+ <View
188
+ style={{
189
+ height: controlsContainerHeight,
190
+ }}
191
+ >
192
+ <Controls
193
+ entry={entry}
194
+ layoutState={layoutState}
195
+ playerState={playerState}
196
+ value={value}
197
+ title={title}
198
+ summary={summary}
199
+ sleepTimerDate={sleepTimerDate}
200
+ cancelSleepTimer={cancelSleepTimer}
201
+ playbackSpeedName={playbackSpeedName}
202
+ playbackSleepName={playbackSleepName}
203
+ onPlaybackButtonPress={onPlaybackButtonPress}
204
+ onRewindButtonPress={onRewindButtonPress}
205
+ onForwardButtonPress={onForwardButtonPress}
206
+ onPlayerSeek={onPlayerSeek}
207
+ onSkipStart={onSkipStart}
208
+ onSkipLive={onSkipLive}
209
+ onSpeedButtonPress={onSpeedButtonPress}
210
+ onSleepButtonPress={onSleepButtonPress}
211
+ docked={docked}
212
+ />
213
+ </View>
214
+ </View>
215
+
216
+ <DockedControls
217
+ entry={entry}
218
+ layoutState={layoutState}
219
+ playerState={playerState}
220
+ value={value}
221
+ dimensions={dimensions}
222
+ onCloseVideoModal={onCloseVideoModal}
223
+ onPlayerSeek={onPlayerSeek}
224
+ playNextData={playNextData}
225
+ title={title}
226
+ summary={summary}
227
+ />
228
+ </View>
229
+ );
230
+ }
@@ -0,0 +1,70 @@
1
+ import React, { PropsWithChildren } from "react";
2
+ import { Image, Animated, StyleSheet, ImageStyle } from "react-native";
3
+
4
+ import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
+ import {
6
+ useModalAnimationContext,
7
+ PlayerAnimationStateEnum,
8
+ DURATION_TO_MINIMIZE,
9
+ DURATION_TO_MAXIMIZE,
10
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
11
+
12
+ const styles = StyleSheet.create({
13
+ container: {
14
+ // we have to specify flex:0 and dimensions to make animation work
15
+ flex: 0,
16
+ aspectRatio: 1,
17
+ },
18
+ });
19
+
20
+ type Props = PropsWithChildren<{
21
+ entry: ZappEntry;
22
+ style?: ImageStyle | ImageStyle[];
23
+ imageWidth: number;
24
+ }>;
25
+
26
+ export const AnimatedImage = ({ entry, style, imageWidth }: Props) => {
27
+ const heightAnim = React.useRef(new Animated.Value(imageWidth)).current;
28
+
29
+ const source = React.useMemo(
30
+ () => ({ uri: imageSrcFromMediaItem(entry, undefined) }),
31
+ [entry]
32
+ );
33
+
34
+ const { playerAnimationState, minimisedHeight } = useModalAnimationContext();
35
+
36
+ React.useEffect(() => {
37
+ if (playerAnimationState === PlayerAnimationStateEnum.minimize) {
38
+ Animated.timing(heightAnim, {
39
+ toValue: minimisedHeight,
40
+ duration: DURATION_TO_MINIMIZE,
41
+ useNativeDriver: false, // width/height can't use native driver
42
+ }).start();
43
+
44
+ return;
45
+ }
46
+
47
+ if (playerAnimationState === PlayerAnimationStateEnum.maximize) {
48
+ Animated.timing(heightAnim, {
49
+ toValue: imageWidth,
50
+ duration: DURATION_TO_MAXIMIZE,
51
+ useNativeDriver: false, // width/height can't use native driver
52
+ }).start();
53
+ }
54
+ }, [playerAnimationState, imageWidth]);
55
+
56
+ if (!source) return null;
57
+
58
+ return (
59
+ <Animated.View
60
+ style={[
61
+ styles.container,
62
+ {
63
+ width: heightAnim,
64
+ },
65
+ ]}
66
+ >
67
+ <Image resizeMode="cover" style={style} source={source} />
68
+ </Animated.View>
69
+ );
70
+ };
@@ -0,0 +1,20 @@
1
+ import * as React from "react";
2
+ import { Image, ImageStyle } from "react-native";
3
+
4
+ import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
+
6
+ type Props = {
7
+ entry: ZappEntry;
8
+ style?: ImageStyle;
9
+ };
10
+
11
+ export const FlexImage = ({ entry, style }: Props) => {
12
+ const source = React.useMemo(
13
+ () => ({ uri: imageSrcFromMediaItem(entry, undefined) }),
14
+ [entry]
15
+ );
16
+
17
+ if (!source) return null;
18
+
19
+ return <Image resizeMode="cover" style={style} source={source} />;
20
+ };
@@ -0,0 +1,108 @@
1
+ import * as React from "react";
2
+
3
+ import {
4
+ AnimationComponent,
5
+ ComponentAnimationType,
6
+ useModalAnimationContext,
7
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
+
9
+ import { AnimatedImage } from "./AnimatedImage";
10
+ import { FlexImage } from "./FlexImage";
11
+
12
+ import { styles } from "./styles";
13
+ import { calculateBorderRadius } from "../../utils";
14
+ import { PlayNextData } from "../types";
15
+ import { LayoutChangeEvent, View } from "react-native";
16
+
17
+ type Props = {
18
+ entry: ZappEntry;
19
+ layoutState: QuickBrickPlayer.LayoutState;
20
+ playerState: QuickBrickPlayer.PlayerState;
21
+ value: GetValue;
22
+ configuration: QuickBrickPlayer.AudioPlayerProps["configuration"];
23
+ dimensions: QuickBrickPlayer.AudioPlayerProps["dimensions"];
24
+ onCloseVideoModal: Callback;
25
+ onPlayerSeek: (targetTime: number) => void;
26
+ playNextData: PlayNextData;
27
+ title: string | number;
28
+ summary: string | number;
29
+ docked: boolean;
30
+ imageWidth?: Option<number>;
31
+ verticalOffset: number;
32
+ onLayoutImage: (event: LayoutChangeEvent) => void;
33
+ };
34
+
35
+ export const PlayerImage = (props: Props) => {
36
+ const {
37
+ entry,
38
+ dimensions,
39
+ docked,
40
+ verticalOffset,
41
+ imageWidth,
42
+ configuration,
43
+ onLayoutImage,
44
+ } = props;
45
+
46
+ const {
47
+ isActiveGesture,
48
+ startComponentsAnimation,
49
+ playerAnimationState,
50
+ minimisedHeight,
51
+ } = useModalAnimationContext();
52
+
53
+ const isShadowEnabled =
54
+ configuration?.audio_player_artwork_shadow_enabled ?? true;
55
+
56
+ const shouldShowShadow = !docked && isShadowEnabled;
57
+
58
+ const borderRadius = calculateBorderRadius(
59
+ docked,
60
+ startComponentsAnimation,
61
+ isActiveGesture,
62
+ playerAnimationState,
63
+ configuration
64
+ );
65
+
66
+ return (
67
+ <AnimationComponent
68
+ animationType={ComponentAnimationType.moveUpComponent}
69
+ additionalData={{
70
+ marginTop: verticalOffset,
71
+ }}
72
+ style={styles.flex}
73
+ >
74
+ <AnimationComponent
75
+ animationType={ComponentAnimationType.moveComponentHorizontal}
76
+ additionalData={{
77
+ // we move image horiontally to this value due artwork is centered
78
+ moveValue: (dimensions.width - minimisedHeight) / 2,
79
+ }}
80
+ style={styles.alignItemsCenter}
81
+ >
82
+ <View
83
+ onLayout={onLayoutImage}
84
+ style={[
85
+ shouldShowShadow ? styles.shadow : undefined,
86
+ { borderRadius },
87
+ ]}
88
+ >
89
+ {!imageWidth ? (
90
+ <View style={[styles.defaultImageWrapperView, { borderRadius }]}>
91
+ <FlexImage
92
+ entry={entry}
93
+ style={styles.backgroundImageContainer}
94
+ />
95
+ </View>
96
+ ) : (
97
+ // we have imageSize here and now we could animate resizing of this image
98
+ <AnimatedImage
99
+ entry={entry}
100
+ style={[styles.backgroundImageContainer, { borderRadius }]}
101
+ imageWidth={imageWidth}
102
+ />
103
+ )}
104
+ </View>
105
+ </AnimationComponent>
106
+ </AnimationComponent>
107
+ );
108
+ };
@@ -0,0 +1,36 @@
1
+ /* eslint-disable react-native/no-color-literals */
2
+ import { StyleSheet } from "react-native";
3
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
+
5
+ const SHADOW_COLOR = "rgba(0, 0, 0, 1)";
6
+
7
+ export const styles = StyleSheet.create({
8
+ backgroundImageContainer: {
9
+ flex: 1,
10
+ aspectRatio: 1,
11
+ overflow: "hidden",
12
+ },
13
+
14
+ alignItemsCenter: {
15
+ flex: 1,
16
+ alignItems: "center",
17
+ },
18
+
19
+ flex: {
20
+ flex: 1,
21
+ },
22
+ defaultImageWrapperView: {
23
+ overflow: "hidden",
24
+ },
25
+ shadow: {
26
+ borderColor: "transparent",
27
+ shadowColor: SHADOW_COLOR,
28
+ shadowOffset: { width: 0, height: 24 },
29
+ shadowOpacity: platformSelect({
30
+ ios: 0.35,
31
+ default: 0.2,
32
+ }),
33
+ shadowRadius: 32,
34
+ elevation: 12,
35
+ },
36
+ });
@@ -0,0 +1,220 @@
1
+ import * as React from "react";
2
+ import { StyleSheet, View } from "react-native";
3
+ import {
4
+ useSafeAreaFrame,
5
+ useSafeAreaInsets,
6
+ } from "react-native-safe-area-context";
7
+ import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
+ import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
9
+
10
+ import { TransportInfo } from "./TransportInfo";
11
+ import { PlayerImage } from "./PlayerImage";
12
+ import { Controls } from "./Controls";
13
+
14
+ import { DockedControls } from "./DockedControls";
15
+ import { withDebug } from "./debug";
16
+
17
+ import { Props } from "./types";
18
+ import { isSmallTabletHeight as getIsSmallTabletHeight } from "./utils";
19
+ import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "./const";
20
+ import { FlexImage } from "./PlayerImage/FlexImage";
21
+
22
+ const isIOS = isApplePlatform();
23
+
24
+ const MIN_WIDTH = TABLET_LANDSCAPE.MIN_WIDTH; // Minimum width for the audio player container
25
+ const MAX_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL; // Maximum spacing for the audio player container
26
+ const MIN_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL_S; // Minimum spacing for the audio player container
27
+ const transportInfoHeight = NAVBAR_HEIGHT;
28
+
29
+ const styles = StyleSheet.create({
30
+ container: {
31
+ flex: 1,
32
+ alignItems: "center",
33
+ height: "100%",
34
+ ...withDebug({
35
+ borderWidth: 2,
36
+ borderColor: "magenta",
37
+ }),
38
+ },
39
+ flex: {
40
+ flex: 1,
41
+ },
42
+ audioPlayerContainer: {
43
+ flexDirection: "column",
44
+ alignItems: "center",
45
+ justifyContent: "center",
46
+ minWidth: MIN_WIDTH,
47
+
48
+ ...withDebug({
49
+ borderWidth: 2,
50
+ borderColor: "blue",
51
+ }),
52
+ },
53
+ audioPlayerContainerHeightLimit: {
54
+ maxHeight: 750,
55
+ },
56
+ audioPlayerContainerPaddings: {
57
+ paddingBottom: MAX_SPACING,
58
+ paddingTop: MAX_SPACING,
59
+ },
60
+ // For small screens, we reduce the padding to fit better
61
+ audioPlayerContainerPaddingsSmall: {
62
+ paddingBottom: MIN_SPACING,
63
+ paddingTop: MIN_SPACING,
64
+ },
65
+ controlsContainer: { flexGrow: 0, alignSelf: "stretch" },
66
+ // eslint-disable-next-line react-native/no-color-literals
67
+ debugYellow: {
68
+ borderWidth: 2,
69
+ borderColor: "yellow",
70
+ },
71
+ });
72
+
73
+ const isTabletWithHomeButton = (bottomInset: number): boolean =>
74
+ bottomInset === 0;
75
+
76
+ const withAdditionalOffset = ({ progressBarHeight, bottomInset }) => {
77
+ if (isIOS && isTabletWithHomeButton(bottomInset)) {
78
+ return progressBarHeight === 0 ? 8 : progressBarHeight + 2;
79
+ }
80
+
81
+ if (isIOS && !isTabletWithHomeButton(bottomInset)) {
82
+ return progressBarHeight === 0 ? 4 : 1;
83
+ }
84
+
85
+ // android
86
+ return progressBarHeight === 0 ? 4 : 0.5;
87
+ };
88
+
89
+ export function TabletLandscapeLayout({
90
+ entry,
91
+ layoutState,
92
+ playerState,
93
+ value,
94
+ onPlaybackButtonPress,
95
+ onRewindButtonPress,
96
+ onForwardButtonPress,
97
+ onPlayerSeek,
98
+ onSkipStart,
99
+ onSkipLive,
100
+ onSpeedButtonPress,
101
+ onSleepButtonPress,
102
+ onCloseVideoModal,
103
+ playbackSpeedName,
104
+ playbackSleepName,
105
+ configuration,
106
+ dimensions,
107
+ playNextData,
108
+ cancelSleepTimer,
109
+ sleepTimerDate,
110
+ title,
111
+ summary,
112
+ }: Props) {
113
+ const [imageWidth, setImageWidth] = React.useState(0);
114
+ const { docked } = layoutState;
115
+
116
+ const { bottom: bottomInset } = useSafeAreaInsets();
117
+ const { height: screenHeight } = useSafeAreaFrame();
118
+ const isSmallScreen = getIsSmallTabletHeight(screenHeight);
119
+ const { progressBarHeight } = useModalAnimationContext();
120
+
121
+ const onLayoutImage = React.useCallback((e) => {
122
+ setImageWidth(e.nativeEvent.layout.width);
123
+ }, []);
124
+
125
+ return (
126
+ <View style={styles.container}>
127
+ {/* TransportInfo */}
128
+ <TransportInfo
129
+ entry={entry}
130
+ layoutState={layoutState}
131
+ value={value}
132
+ configuration={configuration}
133
+ />
134
+
135
+ {/* TransportInfo */}
136
+
137
+ <View
138
+ style={[
139
+ styles.audioPlayerContainer,
140
+ {
141
+ marginTop: isSmallScreen
142
+ ? -TABLET_LANDSCAPE.MARGIN_VERTICAL_S
143
+ : -TABLET_LANDSCAPE.MARGIN_VERTICAL,
144
+ height: screenHeight - transportInfoHeight,
145
+ },
146
+ isSmallScreen
147
+ ? styles.audioPlayerContainerPaddingsSmall
148
+ : styles.audioPlayerContainerPaddings,
149
+ ]}
150
+ >
151
+ <View style={[styles.flex, styles.audioPlayerContainerHeightLimit]}>
152
+ {/* PlayerImage non-docked */}
153
+ <View style={[styles.flex, withDebug(styles.debugYellow)]}>
154
+ {!docked ? (
155
+ <PlayerImage
156
+ docked={false}
157
+ entry={entry}
158
+ layoutState={layoutState}
159
+ playerState={playerState}
160
+ value={value}
161
+ configuration={configuration}
162
+ onPlayerSeek={onPlayerSeek}
163
+ onCloseVideoModal={onCloseVideoModal}
164
+ dimensions={dimensions}
165
+ playNextData={playNextData}
166
+ title={title}
167
+ summary={summary}
168
+ verticalOffset={withAdditionalOffset({
169
+ progressBarHeight,
170
+ bottomInset,
171
+ })}
172
+ onLayoutImage={onLayoutImage}
173
+ />
174
+ ) : null}
175
+ </View>
176
+ {/* PlayerImage */}
177
+
178
+ <View style={styles.controlsContainer}>
179
+ <Controls
180
+ maxWidth={imageWidth}
181
+ entry={entry}
182
+ layoutState={layoutState}
183
+ playerState={playerState}
184
+ value={value}
185
+ title={title}
186
+ summary={summary}
187
+ sleepTimerDate={sleepTimerDate}
188
+ cancelSleepTimer={cancelSleepTimer}
189
+ playbackSpeedName={playbackSpeedName}
190
+ playbackSleepName={playbackSleepName}
191
+ onPlaybackButtonPress={onPlaybackButtonPress}
192
+ onRewindButtonPress={onRewindButtonPress}
193
+ onForwardButtonPress={onForwardButtonPress}
194
+ onPlayerSeek={onPlayerSeek}
195
+ onSkipStart={onSkipStart}
196
+ onSkipLive={onSkipLive}
197
+ onSpeedButtonPress={onSpeedButtonPress}
198
+ onSleepButtonPress={onSleepButtonPress}
199
+ docked={docked}
200
+ />
201
+ </View>
202
+ </View>
203
+ </View>
204
+
205
+ <DockedControls
206
+ ImageComponent={<FlexImage entry={entry} style={styles.flex} />}
207
+ entry={entry}
208
+ layoutState={layoutState}
209
+ playerState={playerState}
210
+ value={value}
211
+ dimensions={dimensions}
212
+ onCloseVideoModal={onCloseVideoModal}
213
+ onPlayerSeek={onPlayerSeek}
214
+ playNextData={playNextData}
215
+ title={title}
216
+ summary={summary}
217
+ />
218
+ </View>
219
+ );
220
+ }