@applicaster/quick-brick-player 13.0.0-alpha.1753452014 → 13.0.0-alpha.1756731121

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 (43) hide show
  1. package/package.json +5 -8
  2. package/src/Player/AudioLayer/AudioDescription.tsx +107 -68
  3. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +139 -198
  4. package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +45 -0
  5. package/src/Player/AudioLayer/Layout/Controls/index.tsx +320 -0
  6. package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +5 -23
  7. package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
  8. package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +62 -67
  9. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +230 -0
  10. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +87 -0
  11. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +20 -0
  12. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +1 -0
  13. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +79 -0
  14. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +112 -0
  15. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +36 -0
  16. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +220 -0
  17. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +223 -0
  18. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +128 -0
  19. package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
  20. package/src/Player/AudioLayer/Layout/const.ts +26 -0
  21. package/src/Player/AudioLayer/Layout/debug.ts +6 -0
  22. package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
  23. package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
  24. package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
  25. package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
  26. package/src/Player/AudioLayer/Layout/index.tsx +21 -48
  27. package/src/Player/AudioLayer/Layout/types.ts +7 -0
  28. package/src/Player/AudioLayer/Layout/utils.ts +7 -0
  29. package/src/Player/AudioLayer/utils.ts +27 -0
  30. package/src/Player/Const/sleepTimerOptions.ts +39 -0
  31. package/src/Player/Const/speedOptions.ts +4 -0
  32. package/src/Player/Utils/Utils.ts +0 -5
  33. package/src/Player/Utils/index.tsx +117 -0
  34. package/src/Player/hooks/useIsCasting.tsx +57 -0
  35. package/src/Player/index.tsx +22 -11
  36. package/src/QuickBrickPlayer.tsx +3 -0
  37. package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -454
  38. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
  39. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
  40. package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
  41. package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
  42. package/src/Player/Helpers/VideoResizeMode.ts +0 -7
  43. package/src/utils/utils.ts +0 -25
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@applicaster/quick-brick-player",
3
- "version": "13.0.0-alpha.1753452014",
3
+ "version": "13.0.0-alpha.1756731121",
4
4
  "description": "Quick Brick Player",
5
5
  "main": "./src/index.ts",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
8
- "test": "jest -w=2",
9
8
  "build": "echo 'skipping ts build for core packages'"
10
9
  },
11
10
  "files": [
@@ -36,12 +35,11 @@
36
35
  },
37
36
  "homepage": "https://github.com/applicaster/quickbrick#readme",
38
37
  "dependencies": {
39
- "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.55",
38
+ "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.120",
40
39
  "@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
41
- "@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.1753452014",
42
- "@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.1753452014",
43
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.1753452014",
44
- "keymirror": "^0.1.1",
40
+ "@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.1756731121",
41
+ "@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.1756731121",
42
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.1756731121",
45
43
  "query-string": "7.1.3",
46
44
  "react-native-web-linear-gradient": "1.1.2",
47
45
  "shaka-player": "4.3.5",
@@ -54,7 +52,6 @@
54
52
  "@applicaster/applicaster-types": "*",
55
53
  "@applicaster/blur": "*",
56
54
  "@applicaster/quick-brick-xray": "*",
57
- "@applicaster/react-native-color-thief": "*",
58
55
  "@applicaster/zapp-pipes-v2-client": "*",
59
56
  "@applicaster/zapp-react-dom-ui-components": "*",
60
57
  "@applicaster/zapp-react-native-redux": "*",
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Text, TextStyle, View } from "react-native";
2
+ import { StyleSheet, Text, TextStyle, View } from "react-native";
3
3
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
4
 
5
5
  type AudioDescriptionProps = {
@@ -10,86 +10,125 @@ type AudioDescriptionProps = {
10
10
  docked: boolean;
11
11
  isModal: boolean;
12
12
  };
13
+ maxWidth?: number;
13
14
  value: GetValue;
14
15
  };
15
16
 
16
- const containerStyles = { paddingTop: 32, paddingBottom: 12 };
17
+ const TITLE_PADDING_BOTTOM = 5;
18
+ const TITLE_LINES = 2;
19
+ const SUBTITLE_LINES = 1;
17
20
 
18
- const titleStyles = (value: GetValue, prefix: string): TextStyle => ({
19
- textAlign: "left",
20
- color: value(`${prefix}title_color`),
21
- alignSelf: "center",
22
- paddingBottom: 5,
23
- lineHeight:
24
- Number(
25
- platformSelect({
26
- ios: value(`${prefix}title_lineheight_ios`),
27
- android: value(`${prefix}title_lineheight_android`),
28
- })
29
- ) || 18,
30
- letterSpacing:
31
- Number(
32
- platformSelect({
33
- ios: value(`${prefix}title_letterspacing_ios`),
34
- android: value(`${prefix}title_letterspacing_android`),
35
- })
36
- ) || 0,
37
- fontSize:
38
- Number(
39
- platformSelect({
40
- ios: value(`${prefix}title_fontsize_ios`),
41
- android: value(`${prefix}title_fontsize_android`),
42
- })
43
- ) || 16,
44
- fontFamily: platformSelect({
45
- ios: value(`${prefix}title_font_ios`),
46
- android: value(`${prefix}title_font_android`),
47
- }),
21
+ const styles = StyleSheet.create({
22
+ wrapper: {
23
+ width: "100%",
24
+ alignSelf: "center",
25
+ alignItems: "center",
26
+ justifyContent: "center",
27
+ },
28
+ titleText: {
29
+ textAlign: "center",
30
+ alignSelf: "center",
31
+ paddingBottom: TITLE_PADDING_BOTTOM,
32
+ },
33
+ summaryText: {
34
+ textAlign: "left",
35
+ alignSelf: "center",
36
+ },
48
37
  });
49
38
 
50
- const summaryStyles = (value: GetValue, prefix: string): TextStyle => ({
51
- textAlign: "left",
52
- color: value(`${prefix}subtitle_color`),
53
- alignSelf: "center",
54
- lineHeight:
55
- Number(
56
- platformSelect({
57
- ios: value(`${prefix}subtitle_lineheight_ios`),
58
- android: value(`${prefix}subtitle_lineheight_android`),
59
- })
60
- ) || 18,
61
- letterSpacing:
62
- Number(
63
- platformSelect({
64
- ios: value(`${prefix}subtitle_letterspacing_ios`),
65
- android: value(`${prefix}subtitle_letterspacing_android`),
66
- })
67
- ) || 0,
68
- fontSize:
69
- Number(
70
- platformSelect({
71
- ios: value(`${prefix}subtitle_fontsize_ios`),
72
- android: value(`${prefix}subtitle_fontsize_android`),
73
- })
74
- ) || 13,
75
- fontFamily: platformSelect({
76
- ios: value(`${prefix}subtitle_font_ios`),
77
- android: value(`${prefix}subtitle_font_android`),
78
- }),
79
- });
39
+ const getTitleStyles = (value: GetValue, prefix: string) =>
40
+ ({
41
+ color: value(`${prefix}title_color`),
42
+ lineHeight:
43
+ Number(
44
+ platformSelect({
45
+ ios: value(`${prefix}title_lineheight_ios`),
46
+ android: value(`${prefix}title_lineheight_android`),
47
+ })
48
+ ) || 18,
49
+ letterSpacing:
50
+ Number(
51
+ platformSelect({
52
+ ios: value(`${prefix}title_letterspacing_ios`),
53
+ android: value(`${prefix}title_letterspacing_android`),
54
+ })
55
+ ) || 0,
56
+ fontSize:
57
+ Number(
58
+ platformSelect({
59
+ ios: value(`${prefix}title_fontsize_ios`),
60
+ android: value(`${prefix}title_fontsize_android`),
61
+ })
62
+ ) || 16,
63
+ fontFamily: platformSelect({
64
+ ios: value(`${prefix}title_font_ios`),
65
+ android: value(`${prefix}title_font_android`),
66
+ }),
67
+ }) as const;
68
+
69
+ const getSummaryStyles = (value: GetValue, prefix: string): TextStyle =>
70
+ ({
71
+ color: value(`${prefix}subtitle_color`),
72
+ lineHeight:
73
+ Number(
74
+ platformSelect({
75
+ ios: value(`${prefix}subtitle_lineheight_ios`),
76
+ android: value(`${prefix}subtitle_lineheight_android`),
77
+ })
78
+ ) || 18,
79
+ letterSpacing:
80
+ Number(
81
+ platformSelect({
82
+ ios: value(`${prefix}subtitle_letterspacing_ios`),
83
+ android: value(`${prefix}subtitle_letterspacing_android`),
84
+ })
85
+ ) || 0,
86
+ fontSize:
87
+ Number(
88
+ platformSelect({
89
+ ios: value(`${prefix}subtitle_fontsize_ios`),
90
+ android: value(`${prefix}subtitle_fontsize_android`),
91
+ })
92
+ ) || 13,
93
+ fontFamily: platformSelect({
94
+ ios: value(`${prefix}subtitle_font_ios`),
95
+ android: value(`${prefix}subtitle_font_android`),
96
+ }),
97
+ }) as const;
98
+
99
+ const getHeight = (titleLineHeight: number, subtitleLineHeight) =>
100
+ titleLineHeight * TITLE_LINES + subtitleLineHeight + TITLE_PADDING_BOTTOM;
80
101
 
81
102
  export const AudioDescription = (props: AudioDescriptionProps) => {
82
- const { title, summary, layoutState, value } = props;
103
+ const { title, summary, layoutState, value, maxWidth } = props;
83
104
  const prefix = layoutState.docked ? "docked_player_" : "";
84
105
 
106
+ const summaryStyles = getSummaryStyles(value, prefix);
107
+ const titleStyles = getTitleStyles(value, prefix);
108
+
109
+ const height = getHeight(titleStyles.lineHeight, summaryStyles.lineHeight);
110
+
85
111
  return (
86
- <View style={containerStyles}>
87
- <Text style={titleStyles(value, prefix)} numberOfLines={1}>
112
+ <View
113
+ style={[
114
+ styles.wrapper,
115
+ {
116
+ maxWidth: Math.max(maxWidth, 320),
117
+ height,
118
+ },
119
+ ]}
120
+ >
121
+ <Text style={[styles.titleText, titleStyles]} numberOfLines={TITLE_LINES}>
88
122
  {title}
89
123
  </Text>
90
- <Text style={summaryStyles(value, prefix)} numberOfLines={2}>
91
- {summary}
92
- </Text>
124
+ {summary ? (
125
+ <Text
126
+ style={[styles.summaryText, summaryStyles]}
127
+ numberOfLines={SUBTITLE_LINES}
128
+ >
129
+ {summary}
130
+ </Text>
131
+ ) : null}
93
132
  </View>
94
133
  );
95
134
  };
@@ -1,7 +1,13 @@
1
1
  import * as React from "react";
2
- import { ViewStyle, View, Dimensions as ScreenDimensions } from "react-native";
2
+ import { useEffect, useState } from "react";
3
+ import {
4
+ Dimensions as ScreenDimensions,
5
+ StyleSheet,
6
+ View,
7
+ ViewStyle,
8
+ } from "react-native";
3
9
 
4
- import { SafeAreaView, Edge } from "react-native-safe-area-context";
10
+ import { Edge, SafeAreaView } from "react-native-safe-area-context";
5
11
  import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
6
12
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
7
13
  import * as R from "ramda";
@@ -15,32 +21,35 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
15
21
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
16
22
  import { PlayerDetails } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/PlayerDetails";
17
23
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
18
- import { useEffect, useState } from "react";
19
- import { MagicBG } from "./MagicBG";
20
24
  import { formatSpeed } from "./utils";
21
- import { addQueryParam, getLiveUrl } from "../Utils";
25
+ import {
26
+ getBottomSheetModalDefaultItemIcon,
27
+ getBottomSheetModalIconProps,
28
+ getBottomSheetModalItemProps,
29
+ getBottomSheetModalLabelProps,
30
+ getBottomSheetModalSelectedItemIcon,
31
+ } from "../Utils";
22
32
  import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
23
33
  import {
34
+ AnimatedScrollModal,
24
35
  AnimationComponent,
25
36
  ComponentAnimationType,
26
- AnimatedScrollModal,
27
37
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
28
- import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
38
+ import { PADDING_HORIZONTAL } from "./Layout/const";
29
39
  import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
30
40
  import {
31
- speed_0_8,
32
- speed_1,
33
- speed_1_2,
34
- speed_1_5,
35
- speed_2,
36
- } from "@applicaster/quick-brick-mobile-transport-controls";
37
- import {
41
+ SLEEP_TIMER_OFF,
38
42
  SleepTimerController,
39
43
  SleepTimerState,
40
- SLEEP_TIMER_OFF,
41
44
  } from "./SleepTimerManager";
42
- import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
43
- import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
45
+ import { DEFAULT_SPEED, PlaybackSpeed, SpeedController } from "./SpeedManager";
46
+ import {
47
+ dismissModal as dismissBottomSheetModal,
48
+ openBottomSheetModal,
49
+ useModalStoreState,
50
+ } from "@applicaster/zapp-react-native-utils/modalState";
51
+ import { getSleepTimerOptions } from "../Const/sleepTimerOptions";
52
+ import { speedOptions } from "../Const/speedOptions";
44
53
 
45
54
  const { log_debug } = createLogger({
46
55
  subsystem: "UIComponent",
@@ -56,8 +65,7 @@ type Dimensions = {
56
65
 
57
66
  type Configuration = {
58
67
  [key: string]: any;
59
- magic_background?: boolean;
60
- audio_player_background_image_query?: string;
68
+ audio_player_background_image_default_color?: string;
61
69
  tablet_landscape_sidebar_width?: string;
62
70
  tablet_landscape_player_container_background_color?: string;
63
71
  };
@@ -65,7 +73,6 @@ type Configuration = {
65
73
  type Props = {
66
74
  children: React.ReactNode;
67
75
  inline?: boolean;
68
- docked?: boolean;
69
76
  configuration: Configuration;
70
77
  style: ViewStyle & Dimensions;
71
78
  entry: ZappEntry;
@@ -81,58 +88,27 @@ type Props = {
81
88
 
82
89
  const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
83
90
 
84
- const Styles = {
85
- mainContainer: (style: ViewStyle) => {
86
- const combinedStyle: ViewStyle = {
87
- flex: 1,
88
- };
89
-
90
- return {
91
- ...combinedStyle,
92
- ...style,
93
- };
94
- },
91
+ const Styles = StyleSheet.create({
95
92
  playerContainer: {
96
93
  flex: 1,
97
94
  },
98
95
  paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
99
-
100
- controlsMobile: {
101
- height: 50,
102
- marginHorizontal: 24,
103
- },
104
- controlsTablet: {
105
- height: 96,
106
- marginHorizontal: 24,
107
- },
108
96
  playerDetails: {
109
97
  marginTop: 60,
110
98
  alignSelf: "center",
111
99
  width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
112
100
  },
101
+ });
113
102
 
114
- linearGradient: {
115
- flex: 1,
116
- },
117
- };
118
-
119
- const sleeps = [
120
- // { label: "End of episode", value: "episode" },
121
- { label: "5 minutes", value: 5 },
122
- { label: "10 minutes", value: 10 },
123
- { label: "15 minutes", value: 15 },
124
- { label: "30 minutes", value: 30 },
125
- { label: "45 minutes", value: 45 },
126
- { label: "1 hour", value: 60 },
127
- { label: "2 hours", value: 120 },
128
- ];
103
+ const edges: Edge[] = ["right", "left", "top"];
129
104
 
130
105
  export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
131
106
  const player = usePlayer();
132
107
  const playerState = usePlayerState("audio-player-wrapper");
133
108
 
109
+ const modalBottomSheetState = useModalStoreState();
110
+
134
111
  const {
135
- docked,
136
112
  configuration,
137
113
  style,
138
114
  entry,
@@ -142,24 +118,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
142
118
  isTabletPortrait,
143
119
  } = props;
144
120
 
145
- const speeds = [
146
- { asset: configuration["speed_0_8"] || speed_0_8, value: 0.8 },
147
- { asset: configuration["speed_1"] || speed_1, value: 1.0 },
148
- { asset: configuration["speed_1_2"] || speed_1_2, value: 1.2 },
149
- { asset: configuration["speed_1_5"] || speed_1_5, value: 1.5 },
150
- { asset: configuration["speed_2"] || speed_2, value: 2.0 },
151
- ];
152
-
153
121
  const isTablet = useIsTablet();
154
122
 
155
123
  const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
156
124
 
157
- // TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
158
-
159
- const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
160
-
161
125
  const { title, summary } = useTitleSummaryOverlay(
162
- feedUrl,
163
126
  entry,
164
127
  playerState?.isLive,
165
128
  configuration?.audio_live_player_update_interval
@@ -182,6 +145,31 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
182
145
  }
183
146
  }, [player]);
184
147
 
148
+ useEffect(() => {
149
+ if (!player) return;
150
+
151
+ const unsubscribe = player.addListener({
152
+ id: "audio-player-wrapper-bottom-sheet-modal",
153
+ listener: {
154
+ onVideoEnd: () => {
155
+ // Dismiss the bottom sheet modal when the video ends to avoid audio breaks and app freeze
156
+ if (modalBottomSheetState.visible) {
157
+ dismissBottomSheetModal();
158
+ }
159
+ },
160
+ },
161
+ });
162
+
163
+ return () => unsubscribe?.();
164
+ }, [player, modalBottomSheetState.visible, sleepTimerManager]);
165
+
166
+ React.useEffect(() => {
167
+ if (playerState?.isLive) {
168
+ // Resetting a sleep timer when audio content is live (Timer not supported on live video)
169
+ sleepTimerManager.setSleepTimer(SLEEP_TIMER_OFF).catch();
170
+ }
171
+ }, [playerState?.isLive]);
172
+
185
173
  const [playbackSpeed, setPlaybackSpeed] =
186
174
  useState<PlaybackSpeed>(DEFAULT_SPEED);
187
175
 
@@ -197,8 +185,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
197
185
  height: 0,
198
186
  });
199
187
 
200
- const navigator = useNavigation();
201
-
202
188
  const { maximiseVideoModal } = useNavigation();
203
189
 
204
190
  const onLayout = (event: any) => {
@@ -288,44 +274,51 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
288
274
  );
289
275
 
290
276
  const onSpeedButtonPress = React.useCallback(() => {
291
- navigator.openModalBottomSheet({
277
+ openBottomSheetModal({
292
278
  modalBottomSheetContentProps: {
293
- items: speeds,
279
+ items: speedOptions,
294
280
  current_selection: playbackSpeed,
295
281
  onPress: onSpeedSelect,
296
282
  title: configuration["playback_speed_title"],
283
+ itemProps: getBottomSheetModalItemProps,
284
+ iconProps: getBottomSheetModalIconProps,
285
+ labelProps: getBottomSheetModalLabelProps,
286
+ getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
287
+ getDefaultItemIcon: getBottomSheetModalDefaultItemIcon,
288
+ iconPlacement: "right",
297
289
  },
298
290
  options: {
299
- supportedOrientations: ["portrait"],
291
+ supportedOrientations: [
292
+ "portrait",
293
+ "landscape",
294
+ "portrait-upside-down",
295
+ ],
300
296
  },
301
297
  });
302
- }, [
303
- playbackSpeed,
304
- setPlaybackSpeed,
305
- navigator,
306
- onSpeedSelect,
307
- configuration["playback_speed_title"],
308
- ]);
298
+ }, [playbackSpeed, onSpeedSelect, configuration["playback_speed_title"]]);
309
299
 
310
300
  const onSleepButtonPress = React.useCallback(() => {
311
- navigator.openModalBottomSheet({
301
+ openBottomSheetModal({
312
302
  modalBottomSheetContentProps: {
313
- items: [
314
- {
315
- label: configuration["playback_sleep_off_label"],
316
- value: 0,
317
- },
318
- ].concat(sleeps),
303
+ items: getSleepTimerOptions(configuration),
319
304
  current_selection: sleepTimerState.timer,
320
305
  onPress: onSleepSelect,
321
306
  title: configuration["playback_sleep_title"],
307
+ itemProps: getBottomSheetModalItemProps,
308
+ iconProps: getBottomSheetModalIconProps,
309
+ labelProps: getBottomSheetModalLabelProps,
310
+ getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
311
+ iconPlacement: "right",
322
312
  },
323
313
  options: {
324
- supportedOrientations: ["portrait"],
314
+ supportedOrientations: [
315
+ "portrait",
316
+ "landscape",
317
+ "portrait-upside-down",
318
+ ],
325
319
  },
326
320
  });
327
321
  }, [
328
- navigator,
329
322
  sleepTimerState.timer,
330
323
  configuration["playback_sleep_title"],
331
324
  configuration["playback_sleep_off_label"],
@@ -359,113 +352,61 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
359
352
  player?.seekTo(0);
360
353
  }, [player]);
361
354
 
362
- const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
363
-
364
- const ContainerView = SafeAreaView;
365
-
366
- const MainContent = React.useMemo(() => {
367
- return (
368
- <ContainerView style={Styles.mainContainer(style)} edges={edges}>
369
- <AnimationComponent
370
- animationType={ComponentAnimationType.moveUpComponent}
371
- additionalData={{ saveArea: true }}
372
- style={Styles.playerContainer}
373
- >
374
- <AnimatedScrollModal>
375
- <View style={Styles.playerContainer} onLayout={onLayout}>
376
- <Layout
377
- entry={entry}
378
- playerState={playerState}
379
- layoutState={layoutState}
380
- value={value}
381
- onPlaybackButtonPress={onPlaybackButtonPress}
382
- onRewindButtonPress={onRewindButtonPress}
383
- onForwardButtonPress={onForwardButtonPress}
384
- onPlayerSeek={onPlayerSeek}
385
- onSkipStart={onSkipStart}
386
- onSpeedButtonPress={onSpeedButtonPress}
387
- onSleepButtonPress={onSleepButtonPress}
388
- playbackSpeedName={formatSpeed(playbackSpeed.value)}
389
- playbackSleepName={
390
- sleepTimerState.timer.value === 0
391
- ? "sleep_timer"
392
- : "sleep_timer_active"
393
- }
394
- sleepTimerDate={sleepTimerState.timerDate}
395
- cancelSleepTimer={cancelSleepTimer}
396
- onSkipLive={onSkipLive}
397
- onCloseVideoModal={onCloseVideoModal}
398
- maximiseVideoModal={maximiseVideoModal}
399
- configuration={configuration}
400
- dimensions={dimensions}
401
- playNextData={playNextData}
402
- title={title}
403
- summary={summary}
404
- defaultDimensions={defaultDimensions}
405
- />
406
- <View style={Styles.paddingHorizontal}>
407
- {children}
408
- <AnimationComponent
409
- animationType={ComponentAnimationType.componentFade}
410
- >
411
- <PlayerDetails
412
- configuration={configuration}
413
- style={Styles.playerDetails}
414
- entry={entry}
415
- isTabletLandscape={isTabletLandscape}
416
- isAudioPlayer={true}
417
- />
418
- </AnimationComponent>
419
- </View>
420
- </View>
421
- </AnimatedScrollModal>
422
- </AnimationComponent>
423
- </ContainerView>
424
- );
425
- }, [
426
- docked,
427
- style,
428
- entry,
429
- playerState,
430
- layoutState,
431
- value,
432
- onPlaybackButtonPress,
433
- onRewindButtonPress,
434
- onForwardButtonPress,
435
- onPlayerSeek,
436
- onCloseVideoModal,
437
- maximiseVideoModal,
438
- configuration,
439
- dimensions,
440
- children,
441
- playNextData,
442
- onSkipStart,
443
- onSkipLive,
444
- sleepTimerState.timer.value,
445
- sleepTimerState.timerDate,
446
- ]);
447
-
448
- if (configuration.magic_background) {
449
- const baseUrl = imageSrcFromMediaItem(entry, null);
450
-
451
- const queryParamName =
452
- configuration.audio_player_background_image_query || "width";
453
-
454
- const queryParamValue = 15;
455
-
456
- const url = addQueryParam(baseUrl, queryParamName, queryParamValue);
457
-
458
- return (
459
- <MagicBG
460
- image={url}
461
- fallbackUrl={baseUrl}
462
- colors={entry?.extensions?.backgroundColors}
463
- defaultColor="#000000"
355
+ return (
356
+ <SafeAreaView style={[style, Styles.playerContainer]} edges={edges}>
357
+ <AnimationComponent
358
+ animationType={ComponentAnimationType.moveUpComponent}
359
+ additionalData={{ saveArea: true }}
360
+ style={Styles.playerContainer}
464
361
  >
465
- {MainContent}
466
- </MagicBG>
467
- );
468
- }
469
-
470
- return MainContent;
362
+ <AnimatedScrollModal>
363
+ <View style={Styles.playerContainer} onLayout={onLayout}>
364
+ <Layout
365
+ entry={entry}
366
+ playerState={playerState}
367
+ layoutState={layoutState}
368
+ value={value}
369
+ onPlaybackButtonPress={onPlaybackButtonPress}
370
+ onRewindButtonPress={onRewindButtonPress}
371
+ onForwardButtonPress={onForwardButtonPress}
372
+ onPlayerSeek={onPlayerSeek}
373
+ onSkipStart={onSkipStart}
374
+ onSpeedButtonPress={onSpeedButtonPress}
375
+ onSleepButtonPress={onSleepButtonPress}
376
+ playbackSpeedName={formatSpeed(playbackSpeed.value)}
377
+ playbackSleepName={
378
+ sleepTimerState.timer.value === 0
379
+ ? "sleep_timer"
380
+ : "sleep_timer_active"
381
+ }
382
+ sleepTimerDate={sleepTimerState.timerDate}
383
+ cancelSleepTimer={cancelSleepTimer}
384
+ onSkipLive={onSkipLive}
385
+ onCloseVideoModal={onCloseVideoModal}
386
+ maximiseVideoModal={maximiseVideoModal}
387
+ configuration={configuration}
388
+ dimensions={dimensions}
389
+ playNextData={playNextData}
390
+ title={title}
391
+ summary={summary}
392
+ />
393
+ <View style={Styles.paddingHorizontal}>
394
+ {children}
395
+ <AnimationComponent
396
+ animationType={ComponentAnimationType.componentFade}
397
+ >
398
+ <PlayerDetails
399
+ isAudioPlayer
400
+ configuration={configuration}
401
+ style={Styles.playerDetails}
402
+ entry={entry}
403
+ isTabletLandscape={isTabletLandscape}
404
+ />
405
+ </AnimationComponent>
406
+ </View>
407
+ </View>
408
+ </AnimatedScrollModal>
409
+ </AnimationComponent>
410
+ </SafeAreaView>
411
+ );
471
412
  };