@applicaster/quick-brick-player 13.0.0-rc.12 → 13.0.0-rc.121
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +27 -14
- package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
- package/src/Player/AudioLayer/AudioDescription.tsx +107 -68
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +205 -281
- package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +45 -0
- package/src/Player/AudioLayer/Layout/Controls/index.tsx +320 -0
- package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +7 -25
- package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
- package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +77 -81
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +230 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +70 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +20 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +108 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +36 -0
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +220 -0
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +223 -0
- package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +128 -0
- package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
- package/src/Player/AudioLayer/Layout/const.ts +26 -0
- package/src/Player/AudioLayer/Layout/debug.ts +6 -0
- package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
- package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
- package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
- package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
- package/src/Player/AudioLayer/Layout/index.tsx +21 -48
- package/src/Player/AudioLayer/Layout/types.ts +7 -0
- package/src/Player/AudioLayer/Layout/utils.ts +7 -0
- package/src/Player/AudioLayer/SleepTimerManager.ts +119 -0
- package/src/Player/AudioLayer/SpeedManager.ts +52 -0
- package/src/Player/AudioLayer/utils.ts +27 -0
- package/src/Player/Const/sleepTimerOptions.ts +39 -0
- package/src/Player/Const/speedOptions.ts +4 -0
- package/src/Player/Utils/Utils.ts +0 -5
- package/src/Player/Utils/index.tsx +117 -0
- package/src/Player/hooks/useIsCasting.tsx +57 -0
- package/src/Player/index.tsx +39 -22
- package/src/QuickBrickPlayer.tsx +3 -0
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
- package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
- package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
- package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
- package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
- package/src/Player/Helpers/VideoResizeMode.ts +0 -7
- package/src/utils/utils.ts +0 -25
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
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 {
|
|
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,24 +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 {
|
|
19
|
-
import { MagicBG } from "./MagicBG";
|
|
24
|
+
import { formatSpeed } from "./utils";
|
|
20
25
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
import { addQueryParam, getLiveUrl } from "../Utils";
|
|
26
|
+
getBottomSheetModalDefaultItemIcon,
|
|
27
|
+
getBottomSheetModalIconProps,
|
|
28
|
+
getBottomSheetModalItemProps,
|
|
29
|
+
getBottomSheetModalLabelProps,
|
|
30
|
+
getBottomSheetModalSelectedItemIcon,
|
|
31
|
+
} from "../Utils";
|
|
28
32
|
import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
|
|
29
33
|
import {
|
|
34
|
+
AnimatedScrollModal,
|
|
30
35
|
AnimationComponent,
|
|
31
36
|
ComponentAnimationType,
|
|
32
|
-
AnimatedScrollModal,
|
|
33
37
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
34
|
-
import { PADDING_HORIZONTAL } from "./Layout/
|
|
38
|
+
import { PADDING_HORIZONTAL } from "./Layout/const";
|
|
35
39
|
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
40
|
+
import {
|
|
41
|
+
SLEEP_TIMER_OFF,
|
|
42
|
+
SleepTimerController,
|
|
43
|
+
SleepTimerState,
|
|
44
|
+
} from "./SleepTimerManager";
|
|
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";
|
|
36
53
|
|
|
37
54
|
const { log_debug } = createLogger({
|
|
38
55
|
subsystem: "UIComponent",
|
|
@@ -48,8 +65,7 @@ type Dimensions = {
|
|
|
48
65
|
|
|
49
66
|
type Configuration = {
|
|
50
67
|
[key: string]: any;
|
|
51
|
-
|
|
52
|
-
audio_player_background_image_query?: string;
|
|
68
|
+
audio_player_background_image_default_color?: string;
|
|
53
69
|
tablet_landscape_sidebar_width?: string;
|
|
54
70
|
tablet_landscape_player_container_background_color?: string;
|
|
55
71
|
};
|
|
@@ -57,7 +73,6 @@ type Configuration = {
|
|
|
57
73
|
type Props = {
|
|
58
74
|
children: React.ReactNode;
|
|
59
75
|
inline?: boolean;
|
|
60
|
-
docked?: boolean;
|
|
61
76
|
configuration: Configuration;
|
|
62
77
|
style: ViewStyle & Dimensions;
|
|
63
78
|
entry: ZappEntry;
|
|
@@ -71,57 +86,29 @@ type Props = {
|
|
|
71
86
|
isTabletPortrait?: boolean;
|
|
72
87
|
};
|
|
73
88
|
|
|
74
|
-
|
|
75
|
-
(height / 9) * 16;
|
|
76
|
-
|
|
77
|
-
const Styles = {
|
|
78
|
-
mainContainer: (style: ViewStyle) => {
|
|
79
|
-
const combinedStyle: ViewStyle = {
|
|
80
|
-
flex: 1,
|
|
81
|
-
};
|
|
89
|
+
const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
|
|
82
90
|
|
|
83
|
-
|
|
84
|
-
...combinedStyle,
|
|
85
|
-
...style,
|
|
86
|
-
};
|
|
87
|
-
},
|
|
91
|
+
const Styles = StyleSheet.create({
|
|
88
92
|
playerContainer: {
|
|
89
93
|
flex: 1,
|
|
90
94
|
},
|
|
91
95
|
paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
},
|
|
97
|
-
controlsTablet: {
|
|
98
|
-
height: 96,
|
|
99
|
-
marginHorizontal: 24,
|
|
100
|
-
},
|
|
101
|
-
playerDetails: { marginTop: 60 },
|
|
102
|
-
|
|
103
|
-
linearGradient: {
|
|
104
|
-
flex: 1,
|
|
96
|
+
playerDetails: {
|
|
97
|
+
marginTop: 60,
|
|
98
|
+
alignSelf: "center",
|
|
99
|
+
width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
|
|
105
100
|
},
|
|
106
|
-
};
|
|
101
|
+
});
|
|
107
102
|
|
|
108
|
-
const
|
|
109
|
-
// { label: "End of episode", value: "episode" },
|
|
110
|
-
{ label: "5 minutes", value: 5 },
|
|
111
|
-
{ label: "10 minutes", value: 10 },
|
|
112
|
-
{ label: "15 minutes", value: 15 },
|
|
113
|
-
{ label: "30 minutes", value: 30 },
|
|
114
|
-
{ label: "45 minutes", value: 45 },
|
|
115
|
-
{ label: "1 hour", value: 60 },
|
|
116
|
-
{ label: "2 hours", value: 120 },
|
|
117
|
-
];
|
|
103
|
+
const edges: Edge[] = ["right", "left", "top"];
|
|
118
104
|
|
|
119
105
|
export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
120
106
|
const player = usePlayer();
|
|
121
107
|
const playerState = usePlayerState("audio-player-wrapper");
|
|
122
108
|
|
|
109
|
+
const modalBottomSheetState = useModalStoreState();
|
|
110
|
+
|
|
123
111
|
const {
|
|
124
|
-
docked,
|
|
125
112
|
configuration,
|
|
126
113
|
style,
|
|
127
114
|
entry,
|
|
@@ -131,40 +118,64 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
131
118
|
isTabletPortrait,
|
|
132
119
|
} = props;
|
|
133
120
|
|
|
134
|
-
const speeds = [
|
|
135
|
-
{ asset: configuration["speed_0_8"], value: 0.8 },
|
|
136
|
-
{ asset: configuration["speed_1"], value: 1.0 },
|
|
137
|
-
{ asset: configuration["speed_1_2"], value: 1.2 },
|
|
138
|
-
{ asset: configuration["speed_1_5"], value: 1.5 },
|
|
139
|
-
{ asset: configuration["speed_2"], value: 2.0 },
|
|
140
|
-
];
|
|
141
|
-
|
|
142
121
|
const isTablet = useIsTablet();
|
|
143
122
|
|
|
144
123
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
145
124
|
|
|
146
|
-
// TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
|
|
147
|
-
|
|
148
|
-
const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
|
|
149
|
-
|
|
150
125
|
const { title, summary } = useTitleSummaryOverlay(
|
|
151
|
-
feedUrl,
|
|
152
126
|
entry,
|
|
153
127
|
playerState?.isLive,
|
|
154
128
|
configuration?.audio_live_player_update_interval
|
|
155
129
|
);
|
|
156
130
|
|
|
157
|
-
const [
|
|
158
|
-
|
|
159
|
-
value: 1.0,
|
|
160
|
-
});
|
|
131
|
+
const [sleepTimerManager, setSleepTimerManager] =
|
|
132
|
+
useState<SleepTimerController | null>(null);
|
|
161
133
|
|
|
162
|
-
const [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
134
|
+
const [speedManager, setSpeedManager] = useState<SpeedController | null>(
|
|
135
|
+
null
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
useEffect(() => {
|
|
139
|
+
if (player) {
|
|
140
|
+
setSleepTimerManager(new SleepTimerController(player));
|
|
141
|
+
setSpeedManager(new SpeedController(player));
|
|
142
|
+
} else {
|
|
143
|
+
setSleepTimerManager(null);
|
|
144
|
+
setSpeedManager(null);
|
|
145
|
+
}
|
|
146
|
+
}, [player]);
|
|
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
|
+
});
|
|
166
162
|
|
|
167
|
-
|
|
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
|
+
|
|
173
|
+
const [playbackSpeed, setPlaybackSpeed] =
|
|
174
|
+
useState<PlaybackSpeed>(DEFAULT_SPEED);
|
|
175
|
+
|
|
176
|
+
const [sleepTimerState, setSleepTimerState] = useState<SleepTimerState>(
|
|
177
|
+
new SleepTimerState(SLEEP_TIMER_OFF, 0)
|
|
178
|
+
);
|
|
168
179
|
|
|
169
180
|
const [defaultDimensions, setDefaultDimensions] =
|
|
170
181
|
React.useState<Dimensions>(undefined);
|
|
@@ -174,8 +185,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
174
185
|
height: 0,
|
|
175
186
|
});
|
|
176
187
|
|
|
177
|
-
const navigator = useNavigation();
|
|
178
|
-
|
|
179
188
|
const { maximiseVideoModal } = useNavigation();
|
|
180
189
|
|
|
181
190
|
const onLayout = (event: any) => {
|
|
@@ -189,82 +198,27 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
189
198
|
if (!defaultDimensions) setDefaultDimensions({ width, height });
|
|
190
199
|
};
|
|
191
200
|
|
|
192
|
-
const cancelSleepTimer = async () => {
|
|
193
|
-
player?.cancelSleepTimer();
|
|
194
|
-
|
|
195
|
-
setSleepTimer({
|
|
196
|
-
label: "playback_sleep_off_label",
|
|
197
|
-
value: 0,
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
setSleepTimerDate(0);
|
|
201
|
-
|
|
202
|
-
await localStorage.removeItem("sleep", NAMESPACE);
|
|
203
|
-
};
|
|
204
|
-
|
|
205
|
-
const startSleepTimer = (timerValue: number) => {
|
|
206
|
-
try {
|
|
207
|
-
const currentDate = new Date();
|
|
208
|
-
const futureDate = new Date(currentDate.getTime() + timerValue * 60000);
|
|
209
|
-
const futureSleepDate = futureDate.getTime();
|
|
210
|
-
|
|
211
|
-
player?.cancelSleepTimer();
|
|
212
|
-
|
|
213
|
-
player?.startSleepTimer(futureSleepDate);
|
|
214
|
-
|
|
215
|
-
return futureSleepDate;
|
|
216
|
-
} catch (e) {
|
|
217
|
-
return 0;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
const handleSleep = async (
|
|
222
|
-
timerValue: number,
|
|
223
|
-
currentFutureSleepDate = null
|
|
224
|
-
) => {
|
|
225
|
-
if (currentFutureSleepDate) {
|
|
226
|
-
if (hasDatePassed(currentFutureSleepDate)) {
|
|
227
|
-
await cancelSleepTimer();
|
|
228
|
-
|
|
229
|
-
return 0;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return currentFutureSleepDate;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (timerValue === 0) {
|
|
236
|
-
await cancelSleepTimer();
|
|
237
|
-
|
|
238
|
-
return timerValue;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return startSleepTimer(timerValue);
|
|
242
|
-
};
|
|
243
|
-
|
|
244
201
|
useEffect(() => {
|
|
245
|
-
const
|
|
246
|
-
|
|
202
|
+
const sleepSubscription =
|
|
203
|
+
sleepTimerManager?.sleepTimerState$.subscribe(setSleepTimerState);
|
|
247
204
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
player?.setPlaybackRate(speed.value);
|
|
251
|
-
}
|
|
252
|
-
};
|
|
253
|
-
|
|
254
|
-
const loadSleep = async () => {
|
|
255
|
-
const sleep = await loadItemsFromStorage("sleep");
|
|
205
|
+
const speedSubscription =
|
|
206
|
+
speedManager?.playbackSpeed$.subscribe(setPlaybackSpeed);
|
|
256
207
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const sleepTimerDate = await handleSleep(sleep.value, futureSleepDate);
|
|
261
|
-
setSleepTimerDate(sleepTimerDate);
|
|
262
|
-
}
|
|
208
|
+
return () => {
|
|
209
|
+
sleepSubscription?.unsubscribe();
|
|
210
|
+
speedSubscription?.unsubscribe();
|
|
263
211
|
};
|
|
212
|
+
}, [sleepTimerManager, speedManager]);
|
|
213
|
+
|
|
214
|
+
useEffect(() => {
|
|
215
|
+
if (!playerState.isReadyToPlay) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
264
218
|
|
|
265
|
-
loadSpeed()
|
|
266
|
-
loadSleep()
|
|
267
|
-
}, [playerState.isReadyToPlay]);
|
|
219
|
+
void speedManager?.loadSpeed();
|
|
220
|
+
void sleepTimerManager?.loadSleep();
|
|
221
|
+
}, [playerState.isReadyToPlay, speedManager, sleepTimerManager]);
|
|
268
222
|
|
|
269
223
|
const getValue = (key: string, stylesObj: {}) =>
|
|
270
224
|
R.propOr(null, key, stylesObj);
|
|
@@ -292,7 +246,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
292
246
|
|
|
293
247
|
const onPlaybackButtonPress = React.useCallback(() => {
|
|
294
248
|
if (playerState.isBuffering) return;
|
|
295
|
-
playerState.isPaused ? player?.play() : player
|
|
249
|
+
playerState.isPaused ? player?.play() : player?.pause();
|
|
296
250
|
}, [playerState, player]);
|
|
297
251
|
|
|
298
252
|
const seekDuration = toNumberWithDefault(10, value("seek_duration"));
|
|
@@ -307,57 +261,77 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
307
261
|
|
|
308
262
|
const onSpeedSelect = React.useCallback(
|
|
309
263
|
async (item) => {
|
|
310
|
-
setPlaybackSpeed(item);
|
|
311
|
-
player.setPlaybackRate(item.value);
|
|
312
|
-
await localStorage.setItem("speed", item, NAMESPACE);
|
|
264
|
+
await speedManager?.setPlaybackSpeed(item);
|
|
313
265
|
},
|
|
314
|
-
[
|
|
266
|
+
[speedManager]
|
|
315
267
|
);
|
|
316
268
|
|
|
317
269
|
const onSleepSelect = React.useCallback(
|
|
318
270
|
async (item) => {
|
|
319
|
-
setSleepTimer(item);
|
|
320
|
-
const futureSleepDate = await handleSleep(item.value);
|
|
321
|
-
setSleepTimerDate(futureSleepDate);
|
|
322
|
-
|
|
323
|
-
await localStorage.setItem(
|
|
324
|
-
"sleep",
|
|
325
|
-
{ ...item, futureSleepDate },
|
|
326
|
-
NAMESPACE
|
|
327
|
-
);
|
|
271
|
+
await sleepTimerManager?.setSleepTimer(item);
|
|
328
272
|
},
|
|
329
|
-
[
|
|
273
|
+
[sleepTimerManager]
|
|
330
274
|
);
|
|
331
275
|
|
|
332
276
|
const onSpeedButtonPress = React.useCallback(() => {
|
|
333
|
-
|
|
277
|
+
openBottomSheetModal({
|
|
334
278
|
modalBottomSheetContentProps: {
|
|
335
|
-
items:
|
|
279
|
+
items: speedOptions,
|
|
336
280
|
current_selection: playbackSpeed,
|
|
337
281
|
onPress: onSpeedSelect,
|
|
338
282
|
title: configuration["playback_speed_title"],
|
|
283
|
+
itemProps: getBottomSheetModalItemProps,
|
|
284
|
+
iconProps: getBottomSheetModalIconProps,
|
|
285
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
286
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
287
|
+
getDefaultItemIcon: getBottomSheetModalDefaultItemIcon,
|
|
288
|
+
iconPlacement: "right",
|
|
339
289
|
},
|
|
340
290
|
options: {
|
|
341
|
-
supportedOrientations: [
|
|
291
|
+
supportedOrientations: [
|
|
292
|
+
"portrait",
|
|
293
|
+
"landscape",
|
|
294
|
+
"portrait-upside-down",
|
|
295
|
+
],
|
|
342
296
|
},
|
|
343
297
|
});
|
|
344
|
-
}, [playbackSpeed,
|
|
298
|
+
}, [playbackSpeed, onSpeedSelect, configuration["playback_speed_title"]]);
|
|
345
299
|
|
|
346
300
|
const onSleepButtonPress = React.useCallback(() => {
|
|
347
|
-
|
|
301
|
+
openBottomSheetModal({
|
|
348
302
|
modalBottomSheetContentProps: {
|
|
349
|
-
items:
|
|
350
|
-
|
|
351
|
-
].concat(sleeps),
|
|
352
|
-
current_selection: sleepTimer,
|
|
303
|
+
items: getSleepTimerOptions(configuration),
|
|
304
|
+
current_selection: sleepTimerState.timer,
|
|
353
305
|
onPress: onSleepSelect,
|
|
354
306
|
title: configuration["playback_sleep_title"],
|
|
307
|
+
itemProps: getBottomSheetModalItemProps,
|
|
308
|
+
iconProps: getBottomSheetModalIconProps,
|
|
309
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
310
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
311
|
+
iconPlacement: "right",
|
|
355
312
|
},
|
|
356
313
|
options: {
|
|
357
|
-
supportedOrientations: [
|
|
314
|
+
supportedOrientations: [
|
|
315
|
+
"portrait",
|
|
316
|
+
"landscape",
|
|
317
|
+
"portrait-upside-down",
|
|
318
|
+
],
|
|
358
319
|
},
|
|
359
320
|
});
|
|
360
|
-
}, [
|
|
321
|
+
}, [
|
|
322
|
+
sleepTimerState.timer,
|
|
323
|
+
configuration["playback_sleep_title"],
|
|
324
|
+
configuration["playback_sleep_off_label"],
|
|
325
|
+
onSleepSelect,
|
|
326
|
+
]);
|
|
327
|
+
|
|
328
|
+
// This method does not actually cancel the sleep timer
|
|
329
|
+
// (and should not to avoid race condition),
|
|
330
|
+
// it just performs the cleanup when timer expires
|
|
331
|
+
// TODO: rename it in code above
|
|
332
|
+
const cancelSleepTimer = React.useCallback(() => {
|
|
333
|
+
sleepTimerManager?.onTimerExpired();
|
|
334
|
+
}, [sleepTimerManager]);
|
|
361
335
|
|
|
362
336
|
const onCloseVideoModal = React.useCallback(() => {
|
|
363
337
|
playerManager.close();
|
|
@@ -378,111 +352,61 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
378
352
|
player?.seekTo(0);
|
|
379
353
|
}, [player]);
|
|
380
354
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
<ContainerView style={Styles.mainContainer(style)} edges={edges}>
|
|
388
|
-
<AnimationComponent
|
|
389
|
-
animationType={ComponentAnimationType.moveUpComponent}
|
|
390
|
-
additionalData={{ saveArea: true }}
|
|
391
|
-
style={Styles.playerContainer}
|
|
392
|
-
>
|
|
393
|
-
<AnimatedScrollModal>
|
|
394
|
-
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
395
|
-
<Layout
|
|
396
|
-
entry={entry}
|
|
397
|
-
playerState={playerState}
|
|
398
|
-
layoutState={layoutState}
|
|
399
|
-
value={value}
|
|
400
|
-
onPlaybackButtonPress={onPlaybackButtonPress}
|
|
401
|
-
onRewindButtonPress={onRewindButtonPress}
|
|
402
|
-
onForwardButtonPress={onForwardButtonPress}
|
|
403
|
-
onPlayerSeek={onPlayerSeek}
|
|
404
|
-
onSkipStart={onSkipStart}
|
|
405
|
-
onSpeedButtonPress={onSpeedButtonPress}
|
|
406
|
-
onSleepButtonPress={onSleepButtonPress}
|
|
407
|
-
playbackSpeedName={formatSpeed(playbackSpeed.value)}
|
|
408
|
-
playbackSleepName={
|
|
409
|
-
sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
|
|
410
|
-
}
|
|
411
|
-
sleepTimerDate={sleepTimerDate}
|
|
412
|
-
cancelSleepTimer={cancelSleepTimer}
|
|
413
|
-
onSkipLive={onSkipLive}
|
|
414
|
-
onCloseVideoModal={onCloseVideoModal}
|
|
415
|
-
maximiseVideoModal={maximiseVideoModal}
|
|
416
|
-
configuration={configuration}
|
|
417
|
-
dimensions={dimensions}
|
|
418
|
-
playNextData={playNextData}
|
|
419
|
-
title={title}
|
|
420
|
-
summary={summary}
|
|
421
|
-
defaultDimensions={defaultDimensions}
|
|
422
|
-
/>
|
|
423
|
-
<View style={Styles.paddingHorizontal}>
|
|
424
|
-
{children}
|
|
425
|
-
<AnimationComponent
|
|
426
|
-
animationType={ComponentAnimationType.componentFade}
|
|
427
|
-
>
|
|
428
|
-
<PlayerDetails
|
|
429
|
-
configuration={configuration}
|
|
430
|
-
style={Styles.playerDetails}
|
|
431
|
-
entry={entry}
|
|
432
|
-
isTabletLandscape={isTabletLandscape}
|
|
433
|
-
isAudioPlayer={true}
|
|
434
|
-
/>
|
|
435
|
-
</AnimationComponent>
|
|
436
|
-
</View>
|
|
437
|
-
</View>
|
|
438
|
-
</AnimatedScrollModal>
|
|
439
|
-
</AnimationComponent>
|
|
440
|
-
</ContainerView>
|
|
441
|
-
);
|
|
442
|
-
}, [
|
|
443
|
-
docked,
|
|
444
|
-
style,
|
|
445
|
-
entry,
|
|
446
|
-
playerState,
|
|
447
|
-
layoutState,
|
|
448
|
-
value,
|
|
449
|
-
onPlaybackButtonPress,
|
|
450
|
-
onRewindButtonPress,
|
|
451
|
-
onForwardButtonPress,
|
|
452
|
-
onPlayerSeek,
|
|
453
|
-
onCloseVideoModal,
|
|
454
|
-
maximiseVideoModal,
|
|
455
|
-
configuration,
|
|
456
|
-
dimensions,
|
|
457
|
-
children,
|
|
458
|
-
playNextData,
|
|
459
|
-
onSkipStart,
|
|
460
|
-
onSkipLive,
|
|
461
|
-
sleepTimer.value,
|
|
462
|
-
sleepTimerDate,
|
|
463
|
-
]);
|
|
464
|
-
|
|
465
|
-
if (configuration.magic_background) {
|
|
466
|
-
const baseUrl = entry?.extensions?.audio_player_background_image ?? "";
|
|
467
|
-
|
|
468
|
-
const queryParamName =
|
|
469
|
-
configuration.audio_player_background_image_query || "width";
|
|
470
|
-
|
|
471
|
-
const queryParamValue = 15;
|
|
472
|
-
|
|
473
|
-
const url = addQueryParam(baseUrl, queryParamName, queryParamValue);
|
|
474
|
-
|
|
475
|
-
return (
|
|
476
|
-
<MagicBG
|
|
477
|
-
image={url}
|
|
478
|
-
fallbackUrl={baseUrl}
|
|
479
|
-
colors={entry?.extensions?.backgroundColors}
|
|
480
|
-
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}
|
|
481
361
|
>
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
+
);
|
|
488
412
|
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
TABLET_VERTICAL_SEPARATOR_HEIGHT,
|
|
8
|
+
TABLET_VERTICAL_SEPARATOR_HEIGHT_S,
|
|
9
|
+
} from "../const";
|
|
10
|
+
|
|
11
|
+
import { withDebug } from "../debug";
|
|
12
|
+
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
13
|
+
import { isSmallTabletHeight } from "../utils";
|
|
14
|
+
|
|
15
|
+
const styles = StyleSheet.create({
|
|
16
|
+
flexingHeight: {
|
|
17
|
+
flex: 1,
|
|
18
|
+
...withDebug({ backgroundColor: "red" }),
|
|
19
|
+
},
|
|
20
|
+
fixedHeight: {
|
|
21
|
+
height: TABLET_VERTICAL_SEPARATOR_HEIGHT,
|
|
22
|
+
...withDebug({ backgroundColor: "red" }),
|
|
23
|
+
},
|
|
24
|
+
fixedHeightSmall: {
|
|
25
|
+
height: TABLET_VERTICAL_SEPARATOR_HEIGHT_S,
|
|
26
|
+
...withDebug({ backgroundColor: "red" }),
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export const VerticalGutter = () => {
|
|
31
|
+
const isTablet = useIsTablet();
|
|
32
|
+
const { height } = useSafeAreaFrame();
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<View
|
|
36
|
+
style={
|
|
37
|
+
isTablet
|
|
38
|
+
? isSmallTabletHeight(height)
|
|
39
|
+
? styles.fixedHeightSmall
|
|
40
|
+
: styles.fixedHeight
|
|
41
|
+
: styles.flexingHeight
|
|
42
|
+
}
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
};
|