@applicaster/quick-brick-player 13.0.0-rc.94 → 13.0.0-rc.96
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 +5 -5
- package/src/Player/AudioLayer/AudioDescription.tsx +4 -6
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +46 -68
- package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +27 -0
- package/src/Player/AudioLayer/Layout/Controls/index.tsx +305 -0
- package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +2 -12
- package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +28 -39
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +212 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +83 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +32 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +95 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +17 -0
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +214 -0
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +224 -0
- package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +102 -0
- package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
- package/src/Player/AudioLayer/Layout/const.ts +20 -0
- package/src/Player/AudioLayer/Layout/debug.ts +6 -0
- package/src/Player/AudioLayer/Layout/hooks/index.ts +3 -0
- package/src/Player/AudioLayer/Layout/hooks/useImageSize.ts +100 -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/utils.ts +6 -3
- package/src/Player/Const/sleepTimerOptions.ts +10 -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/AudioLayer/Layout/DefaultLayout.tsx +0 -495
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "13.0.0-rc.
|
|
3
|
+
"version": "13.0.0-rc.96",
|
|
4
4
|
"description": "Quick Brick Player",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
},
|
|
36
36
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.
|
|
38
|
+
"@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.95",
|
|
39
39
|
"@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
|
|
40
|
-
"@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.
|
|
41
|
-
"@applicaster/zapp-react-native-ui-components": "13.0.0-rc.
|
|
42
|
-
"@applicaster/zapp-react-native-utils": "13.0.0-rc.
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.96",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-rc.96",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-rc.96",
|
|
43
43
|
"query-string": "7.1.3",
|
|
44
44
|
"react-native-web-linear-gradient": "1.1.2",
|
|
45
45
|
"shaka-player": "4.3.5",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Text, TextStyle
|
|
2
|
+
import { Text, TextStyle } from "react-native";
|
|
3
3
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
4
|
|
|
5
5
|
type AudioDescriptionProps = {
|
|
@@ -13,8 +13,6 @@ type AudioDescriptionProps = {
|
|
|
13
13
|
value: GetValue;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const containerStyles = { paddingTop: 32, paddingBottom: 12 };
|
|
17
|
-
|
|
18
16
|
const titleStyles = (value: GetValue, prefix: string): TextStyle => ({
|
|
19
17
|
textAlign: "left",
|
|
20
18
|
color: value(`${prefix}title_color`),
|
|
@@ -83,13 +81,13 @@ export const AudioDescription = (props: AudioDescriptionProps) => {
|
|
|
83
81
|
const prefix = layoutState.docked ? "docked_player_" : "";
|
|
84
82
|
|
|
85
83
|
return (
|
|
86
|
-
|
|
84
|
+
<>
|
|
87
85
|
<Text style={titleStyles(value, prefix)} numberOfLines={1}>
|
|
88
86
|
{title}
|
|
89
87
|
</Text>
|
|
90
|
-
<Text style={summaryStyles(value, prefix)} numberOfLines={
|
|
88
|
+
<Text style={summaryStyles(value, prefix)} numberOfLines={1}>
|
|
91
89
|
{summary}
|
|
92
90
|
</Text>
|
|
93
|
-
|
|
91
|
+
</>
|
|
94
92
|
);
|
|
95
93
|
};
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
StyleSheet,
|
|
4
|
+
ViewStyle,
|
|
5
|
+
View,
|
|
6
|
+
Dimensions as ScreenDimensions,
|
|
7
|
+
} from "react-native";
|
|
3
8
|
|
|
4
9
|
import { SafeAreaView, Edge } from "react-native-safe-area-context";
|
|
5
10
|
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
@@ -18,16 +23,22 @@ import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
|
18
23
|
import { useEffect, useState } from "react";
|
|
19
24
|
import { MagicBG } from "./MagicBG";
|
|
20
25
|
import { formatSpeed } from "./utils";
|
|
21
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
addQueryParam,
|
|
28
|
+
getBottomSheetModalDefaultItemIcon,
|
|
29
|
+
getBottomSheetModalIconProps,
|
|
30
|
+
getBottomSheetModalItemProps,
|
|
31
|
+
getBottomSheetModalLabelProps,
|
|
32
|
+
getBottomSheetModalSelectedItemIcon,
|
|
33
|
+
} from "../Utils";
|
|
22
34
|
import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
|
|
23
35
|
import {
|
|
24
36
|
AnimationComponent,
|
|
25
37
|
ComponentAnimationType,
|
|
26
38
|
AnimatedScrollModal,
|
|
27
39
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
28
|
-
import { PADDING_HORIZONTAL } from "./Layout/
|
|
40
|
+
import { PADDING_HORIZONTAL } from "./Layout/const";
|
|
29
41
|
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
30
|
-
|
|
31
42
|
import {
|
|
32
43
|
SleepTimerController,
|
|
33
44
|
SleepTimerState,
|
|
@@ -37,6 +48,8 @@ import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
|
|
|
37
48
|
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
38
49
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
39
50
|
import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
|
|
51
|
+
import { sleepTimerOptions } from "../Const/sleepTimerOptions";
|
|
52
|
+
import { speedOptions } from "../Const/speedOptions";
|
|
40
53
|
|
|
41
54
|
const { log_debug } = createLogger({
|
|
42
55
|
subsystem: "UIComponent",
|
|
@@ -78,59 +91,17 @@ type Props = {
|
|
|
78
91
|
|
|
79
92
|
const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
|
|
80
93
|
|
|
81
|
-
const Styles = {
|
|
82
|
-
mainContainer: (style: ViewStyle) => {
|
|
83
|
-
const combinedStyle: ViewStyle = {
|
|
84
|
-
flex: 1,
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
return {
|
|
88
|
-
...combinedStyle,
|
|
89
|
-
...style,
|
|
90
|
-
};
|
|
91
|
-
},
|
|
94
|
+
const Styles = StyleSheet.create({
|
|
92
95
|
playerContainer: {
|
|
93
96
|
flex: 1,
|
|
94
97
|
},
|
|
95
98
|
paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
|
|
96
|
-
|
|
97
|
-
controlsMobile: {
|
|
98
|
-
height: 50,
|
|
99
|
-
marginHorizontal: 24,
|
|
100
|
-
},
|
|
101
|
-
controlsTablet: {
|
|
102
|
-
height: 96,
|
|
103
|
-
marginHorizontal: 24,
|
|
104
|
-
},
|
|
105
99
|
playerDetails: {
|
|
106
100
|
marginTop: 60,
|
|
107
101
|
alignSelf: "center",
|
|
108
102
|
width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
|
|
109
103
|
},
|
|
110
|
-
|
|
111
|
-
linearGradient: {
|
|
112
|
-
flex: 1,
|
|
113
|
-
},
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const sleeps = [
|
|
117
|
-
// { label: "End of episode", value: "episode" },
|
|
118
|
-
{ label: "5 minutes", value: 5 },
|
|
119
|
-
{ label: "10 minutes", value: 10 },
|
|
120
|
-
{ label: "15 minutes", value: 15 },
|
|
121
|
-
{ label: "30 minutes", value: 30 },
|
|
122
|
-
{ label: "45 minutes", value: 45 },
|
|
123
|
-
{ label: "1 hour", value: 60 },
|
|
124
|
-
{ label: "2 hours", value: 120 },
|
|
125
|
-
];
|
|
126
|
-
|
|
127
|
-
const speeds = [
|
|
128
|
-
{ label: "0.8x", value: 0.8 },
|
|
129
|
-
{ label: "1x", value: 1.0 },
|
|
130
|
-
{ label: "1.2x", value: 1.2 },
|
|
131
|
-
{ label: "1.5x", value: 1.5 },
|
|
132
|
-
{ label: "2x", value: 2.0 },
|
|
133
|
-
];
|
|
104
|
+
});
|
|
134
105
|
|
|
135
106
|
const edges: Edge[] = ["right", "left", "top"];
|
|
136
107
|
|
|
@@ -154,12 +125,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
154
125
|
|
|
155
126
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
156
127
|
|
|
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
128
|
const { title, summary } = useTitleSummaryOverlay(
|
|
162
|
-
feedUrl,
|
|
163
129
|
entry,
|
|
164
130
|
playerState?.isLive,
|
|
165
131
|
configuration?.audio_live_player_update_interval
|
|
@@ -288,21 +254,26 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
288
254
|
const onSpeedButtonPress = React.useCallback(() => {
|
|
289
255
|
openBottomSheetModal({
|
|
290
256
|
modalBottomSheetContentProps: {
|
|
291
|
-
items:
|
|
257
|
+
items: speedOptions,
|
|
292
258
|
current_selection: playbackSpeed,
|
|
293
259
|
onPress: onSpeedSelect,
|
|
294
260
|
title: configuration["playback_speed_title"],
|
|
261
|
+
itemProps: getBottomSheetModalItemProps,
|
|
262
|
+
iconProps: getBottomSheetModalIconProps,
|
|
263
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
264
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
265
|
+
getDefaultItemIcon: getBottomSheetModalDefaultItemIcon,
|
|
266
|
+
iconPlacement: "right",
|
|
295
267
|
},
|
|
296
268
|
options: {
|
|
297
|
-
supportedOrientations: [
|
|
269
|
+
supportedOrientations: [
|
|
270
|
+
"portrait",
|
|
271
|
+
"landscape",
|
|
272
|
+
"portrait-upside-down",
|
|
273
|
+
],
|
|
298
274
|
},
|
|
299
275
|
});
|
|
300
|
-
}, [
|
|
301
|
-
playbackSpeed,
|
|
302
|
-
setPlaybackSpeed,
|
|
303
|
-
onSpeedSelect,
|
|
304
|
-
configuration["playback_speed_title"],
|
|
305
|
-
]);
|
|
276
|
+
}, [playbackSpeed, onSpeedSelect, configuration["playback_speed_title"]]);
|
|
306
277
|
|
|
307
278
|
const onSleepButtonPress = React.useCallback(() => {
|
|
308
279
|
openBottomSheetModal({
|
|
@@ -312,13 +283,22 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
312
283
|
label: configuration["playback_sleep_off_label"],
|
|
313
284
|
value: 0,
|
|
314
285
|
},
|
|
315
|
-
].concat(
|
|
286
|
+
].concat(sleepTimerOptions),
|
|
316
287
|
current_selection: sleepTimerState.timer,
|
|
317
288
|
onPress: onSleepSelect,
|
|
318
289
|
title: configuration["playback_sleep_title"],
|
|
290
|
+
itemProps: getBottomSheetModalItemProps,
|
|
291
|
+
iconProps: getBottomSheetModalIconProps,
|
|
292
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
293
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
294
|
+
iconPlacement: "right",
|
|
319
295
|
},
|
|
320
296
|
options: {
|
|
321
|
-
supportedOrientations: [
|
|
297
|
+
supportedOrientations: [
|
|
298
|
+
"portrait",
|
|
299
|
+
"landscape",
|
|
300
|
+
"portrait-upside-down",
|
|
301
|
+
],
|
|
322
302
|
},
|
|
323
303
|
});
|
|
324
304
|
}, [
|
|
@@ -355,11 +335,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
355
335
|
player?.seekTo(0);
|
|
356
336
|
}, [player]);
|
|
357
337
|
|
|
358
|
-
const ContainerView = SafeAreaView;
|
|
359
|
-
|
|
360
338
|
const MainContent = React.useMemo(() => {
|
|
361
339
|
return (
|
|
362
|
-
<
|
|
340
|
+
<SafeAreaView style={[style, Styles.playerContainer]} edges={edges}>
|
|
363
341
|
<AnimationComponent
|
|
364
342
|
animationType={ComponentAnimationType.moveUpComponent}
|
|
365
343
|
additionalData={{ saveArea: true }}
|
|
@@ -403,18 +381,18 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
403
381
|
animationType={ComponentAnimationType.componentFade}
|
|
404
382
|
>
|
|
405
383
|
<PlayerDetails
|
|
384
|
+
isAudioPlayer
|
|
406
385
|
configuration={configuration}
|
|
407
386
|
style={Styles.playerDetails}
|
|
408
387
|
entry={entry}
|
|
409
388
|
isTabletLandscape={isTabletLandscape}
|
|
410
|
-
isAudioPlayer={true}
|
|
411
389
|
/>
|
|
412
390
|
</AnimationComponent>
|
|
413
391
|
</View>
|
|
414
392
|
</View>
|
|
415
393
|
</AnimatedScrollModal>
|
|
416
394
|
</AnimationComponent>
|
|
417
|
-
</
|
|
395
|
+
</SafeAreaView>
|
|
418
396
|
);
|
|
419
397
|
}, [
|
|
420
398
|
docked,
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { TABLET_VERTICAL_SEPARATOR_HEIGHT } from "../const";
|
|
7
|
+
|
|
8
|
+
import { withDebug } from "../debug";
|
|
9
|
+
|
|
10
|
+
const styles = StyleSheet.create({
|
|
11
|
+
flexingHeight: {
|
|
12
|
+
flex: 1,
|
|
13
|
+
|
|
14
|
+
...withDebug({ backgroundColor: "red" }),
|
|
15
|
+
},
|
|
16
|
+
fixedHeight: {
|
|
17
|
+
height: TABLET_VERTICAL_SEPARATOR_HEIGHT,
|
|
18
|
+
|
|
19
|
+
...withDebug({ backgroundColor: "red" }),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const VerticalGutter = () => {
|
|
24
|
+
const isTablet = useIsTablet();
|
|
25
|
+
|
|
26
|
+
return <View style={isTablet ? styles.fixedHeight : styles.flexingHeight} />;
|
|
27
|
+
};
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { StyleSheet } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
5
|
+
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
|
+
import {
|
|
7
|
+
Controls as MobileTransportControls,
|
|
8
|
+
CountDown,
|
|
9
|
+
ProgressBar,
|
|
10
|
+
} from "@applicaster/quick-brick-mobile-transport-controls";
|
|
11
|
+
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
AnimationComponent,
|
|
15
|
+
ComponentAnimationType,
|
|
16
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
17
|
+
|
|
18
|
+
import { AudioDescription } from "../../AudioDescription";
|
|
19
|
+
import { isValidDate } from "../../../Utils";
|
|
20
|
+
import { VerticalGutter } from "./VerticalGutter";
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
forwardButton,
|
|
24
|
+
playbackButton,
|
|
25
|
+
rewindButton,
|
|
26
|
+
skipToLiveButton,
|
|
27
|
+
skipToStartButton,
|
|
28
|
+
sleepButton,
|
|
29
|
+
speedButton,
|
|
30
|
+
} from "./utils";
|
|
31
|
+
|
|
32
|
+
const styles = StyleSheet.create({
|
|
33
|
+
flex: {
|
|
34
|
+
flex: 1,
|
|
35
|
+
},
|
|
36
|
+
nonFlex: {
|
|
37
|
+
flex: 0,
|
|
38
|
+
},
|
|
39
|
+
progressBar: {
|
|
40
|
+
flex: 0,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const controlsStyles = ({
|
|
45
|
+
isTablet,
|
|
46
|
+
isLiveShowFullControls,
|
|
47
|
+
}: {
|
|
48
|
+
isTablet: boolean;
|
|
49
|
+
isLiveShowFullControls: boolean;
|
|
50
|
+
}) => ({
|
|
51
|
+
height: isTablet ? undefined : 50,
|
|
52
|
+
marginHorizontal: isTablet ? undefined : 10,
|
|
53
|
+
justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
type Props = {
|
|
57
|
+
entry: ZappEntry;
|
|
58
|
+
layoutState: QuickBrickPlayer.LayoutState;
|
|
59
|
+
playerState: QuickBrickPlayer.PlayerState;
|
|
60
|
+
value: GetValue;
|
|
61
|
+
title: string | number;
|
|
62
|
+
summary: string | number;
|
|
63
|
+
sleepTimerDate: number;
|
|
64
|
+
cancelSleepTimer: Callback;
|
|
65
|
+
|
|
66
|
+
playbackSpeedName: string;
|
|
67
|
+
playbackSleepName: string;
|
|
68
|
+
|
|
69
|
+
onPlaybackButtonPress: Callback;
|
|
70
|
+
onRewindButtonPress: Callback;
|
|
71
|
+
onForwardButtonPress: Callback;
|
|
72
|
+
onPlayerSeek: (targetTime: number) => void;
|
|
73
|
+
onSkipStart: Callback;
|
|
74
|
+
onSkipLive: Callback;
|
|
75
|
+
onSpeedButtonPress: Callback;
|
|
76
|
+
onSleepButtonPress: Callback;
|
|
77
|
+
|
|
78
|
+
docked: boolean;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const Controls = (props: Props) => {
|
|
82
|
+
const {
|
|
83
|
+
entry,
|
|
84
|
+
layoutState,
|
|
85
|
+
playerState,
|
|
86
|
+
value,
|
|
87
|
+
title,
|
|
88
|
+
summary,
|
|
89
|
+
sleepTimerDate,
|
|
90
|
+
cancelSleepTimer,
|
|
91
|
+
|
|
92
|
+
playbackSpeedName,
|
|
93
|
+
playbackSleepName,
|
|
94
|
+
|
|
95
|
+
onPlaybackButtonPress,
|
|
96
|
+
onRewindButtonPress,
|
|
97
|
+
onForwardButtonPress,
|
|
98
|
+
onPlayerSeek,
|
|
99
|
+
onSkipStart,
|
|
100
|
+
onSkipLive,
|
|
101
|
+
onSpeedButtonPress,
|
|
102
|
+
onSleepButtonPress,
|
|
103
|
+
|
|
104
|
+
docked,
|
|
105
|
+
} = props;
|
|
106
|
+
|
|
107
|
+
const isTablet = useIsTablet();
|
|
108
|
+
const controller = playerManager.getActivePlayer();
|
|
109
|
+
let showFullControls = !controller?.isAd();
|
|
110
|
+
const liveButton = Boolean(value("live_badge_enabled"));
|
|
111
|
+
|
|
112
|
+
const isLiveContent = playerState.isLive;
|
|
113
|
+
|
|
114
|
+
if (isLiveContent) {
|
|
115
|
+
const seekEnabled = Boolean(value("liveSeekingEnabled"));
|
|
116
|
+
|
|
117
|
+
showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const sleepTitle = value("playback_sleep_countdown_label");
|
|
121
|
+
|
|
122
|
+
const [timeLeft, setTimeLeft] = React.useState(
|
|
123
|
+
sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
const showCounter = React.useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
|
|
127
|
+
|
|
128
|
+
React.useEffect(() => {
|
|
129
|
+
if (showCounter && sleepTimerDate !== 0) {
|
|
130
|
+
setTimeLeft(sleepTimerDate - Date.now());
|
|
131
|
+
|
|
132
|
+
const intervalId = setInterval(() => {
|
|
133
|
+
setTimeLeft(() => {
|
|
134
|
+
const newTimeLeft = sleepTimerDate - Date.now();
|
|
135
|
+
|
|
136
|
+
if (newTimeLeft <= 0) {
|
|
137
|
+
clearInterval(intervalId);
|
|
138
|
+
|
|
139
|
+
cancelSleepTimer();
|
|
140
|
+
|
|
141
|
+
return 0;
|
|
142
|
+
} else {
|
|
143
|
+
return newTimeLeft;
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}, 1000);
|
|
147
|
+
|
|
148
|
+
return () => clearInterval(intervalId);
|
|
149
|
+
} else {
|
|
150
|
+
setTimeLeft(0);
|
|
151
|
+
}
|
|
152
|
+
}, [sleepTimerDate, showCounter, cancelSleepTimer]);
|
|
153
|
+
|
|
154
|
+
const startTime = entry.extensions?.live?.start_time;
|
|
155
|
+
const endTime = entry.extensions?.live?.end_time;
|
|
156
|
+
|
|
157
|
+
const hasValidStartTime = isValidDate(startTime);
|
|
158
|
+
const hasValidEndTime = isValidDate(endTime);
|
|
159
|
+
|
|
160
|
+
const isDateBasedLiveContent =
|
|
161
|
+
isLiveContent && hasValidStartTime && hasValidEndTime;
|
|
162
|
+
|
|
163
|
+
const needsToShowProgressBar =
|
|
164
|
+
(isLiveContent &&
|
|
165
|
+
(Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
|
|
166
|
+
!isLiveContent;
|
|
167
|
+
|
|
168
|
+
const startTimestamp = hasValidStartTime
|
|
169
|
+
? dayjs.utc(startTime!).valueOf()
|
|
170
|
+
: undefined;
|
|
171
|
+
|
|
172
|
+
const endTimestamp = hasValidEndTime
|
|
173
|
+
? dayjs.utc(endTime!).valueOf()
|
|
174
|
+
: undefined;
|
|
175
|
+
|
|
176
|
+
const isLiveShowFullControls = showFullControls && isLiveContent;
|
|
177
|
+
|
|
178
|
+
const controlButtons = React.useCallback((): Array<ControlsButton> => {
|
|
179
|
+
const play = playbackButton({
|
|
180
|
+
playerState,
|
|
181
|
+
liveButton,
|
|
182
|
+
isTablet,
|
|
183
|
+
isLiveShowFullControls,
|
|
184
|
+
onPress: onPlaybackButtonPress,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
if (!showFullControls) {
|
|
188
|
+
return [play];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const rewind = rewindButton({
|
|
192
|
+
isTablet,
|
|
193
|
+
onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const forward = forwardButton({
|
|
197
|
+
isTablet,
|
|
198
|
+
onPress: controller?.hasSeekableDuration?.()
|
|
199
|
+
? onForwardButtonPress
|
|
200
|
+
: null,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
const speed = speedButton({
|
|
204
|
+
isTablet,
|
|
205
|
+
onPress: onSpeedButtonPress,
|
|
206
|
+
name: playbackSpeedName,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const sleep = sleepButton({
|
|
210
|
+
isTablet,
|
|
211
|
+
onPress: onSleepButtonPress,
|
|
212
|
+
name: playbackSleepName,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (isLiveContent) {
|
|
216
|
+
const skipToStart = skipToStartButton({
|
|
217
|
+
isTablet,
|
|
218
|
+
onPress: onSkipStart,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const skipToLive = skipToLiveButton({
|
|
222
|
+
isTablet,
|
|
223
|
+
onPress: onSkipLive,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
return [skipToStart, rewind, play, forward, skipToLive];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return [speed, rewind, play, forward, sleep];
|
|
230
|
+
}, [
|
|
231
|
+
playerState,
|
|
232
|
+
liveButton,
|
|
233
|
+
isTablet,
|
|
234
|
+
onPlaybackButtonPress,
|
|
235
|
+
onRewindButtonPress,
|
|
236
|
+
onForwardButtonPress,
|
|
237
|
+
onSpeedButtonPress,
|
|
238
|
+
showFullControls,
|
|
239
|
+
onSkipStart,
|
|
240
|
+
onSkipLive,
|
|
241
|
+
isLiveContent,
|
|
242
|
+
playbackSpeedName,
|
|
243
|
+
playbackSleepName,
|
|
244
|
+
controller,
|
|
245
|
+
isLiveShowFullControls,
|
|
246
|
+
]);
|
|
247
|
+
|
|
248
|
+
if (docked) {
|
|
249
|
+
return null;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return (
|
|
253
|
+
<AnimationComponent
|
|
254
|
+
animationType={ComponentAnimationType.componentFade}
|
|
255
|
+
style={isTablet ? styles.nonFlex : styles.flex}
|
|
256
|
+
>
|
|
257
|
+
<VerticalGutter />
|
|
258
|
+
|
|
259
|
+
<AudioDescription
|
|
260
|
+
title={title}
|
|
261
|
+
summary={summary}
|
|
262
|
+
value={value}
|
|
263
|
+
layoutState={layoutState}
|
|
264
|
+
/>
|
|
265
|
+
|
|
266
|
+
<VerticalGutter />
|
|
267
|
+
|
|
268
|
+
{needsToShowProgressBar ? (
|
|
269
|
+
<>
|
|
270
|
+
<ProgressBar
|
|
271
|
+
name={"audio-default-layout"}
|
|
272
|
+
content={entry}
|
|
273
|
+
value={value}
|
|
274
|
+
visible
|
|
275
|
+
layoutState={layoutState}
|
|
276
|
+
onPlayerSeek={onPlayerSeek}
|
|
277
|
+
playerState={playerState}
|
|
278
|
+
disableFullscreen
|
|
279
|
+
sliderStyle={2}
|
|
280
|
+
startTimestamp={startTimestamp}
|
|
281
|
+
endTimestamp={endTimestamp}
|
|
282
|
+
isDateBasedLiveContent={isDateBasedLiveContent}
|
|
283
|
+
onSkipLive={onSkipLive}
|
|
284
|
+
progressBarStyles={styles.progressBar}
|
|
285
|
+
/>
|
|
286
|
+
|
|
287
|
+
{showCounter && timeLeft >= 0 ? (
|
|
288
|
+
<CountDown timeLeft={timeLeft} value={value} title={sleepTitle} />
|
|
289
|
+
) : null}
|
|
290
|
+
|
|
291
|
+
<VerticalGutter />
|
|
292
|
+
</>
|
|
293
|
+
) : null}
|
|
294
|
+
|
|
295
|
+
<MobileTransportControls
|
|
296
|
+
value={value}
|
|
297
|
+
visible={true}
|
|
298
|
+
keepAlive={null}
|
|
299
|
+
buttons={controlButtons}
|
|
300
|
+
style={controlsStyles({ isTablet, isLiveShowFullControls })}
|
|
301
|
+
playerState={playerState}
|
|
302
|
+
/>
|
|
303
|
+
</AnimationComponent>
|
|
304
|
+
);
|
|
305
|
+
};
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
type PlayerState = {
|
|
2
|
-
currentTime: number;
|
|
3
|
-
duration: number;
|
|
4
|
-
seekableDuration: number;
|
|
5
|
-
isLive: boolean;
|
|
6
|
-
isPaused: boolean;
|
|
7
|
-
isBuffering: boolean;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
1
|
const rewindButtonSize = (isTablet: boolean): keyof ButtonSizeStyles =>
|
|
11
2
|
isTablet ? "big" : "smallMargins";
|
|
12
3
|
|
|
@@ -19,8 +10,6 @@ const playbackButtonMargins = (
|
|
|
19
10
|
): number =>
|
|
20
11
|
isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ? undefined : 40;
|
|
21
12
|
|
|
22
|
-
export const PADDING_HORIZONTAL = 15;
|
|
23
|
-
|
|
24
13
|
export const playbackButton = ({
|
|
25
14
|
playerState,
|
|
26
15
|
liveButton,
|
|
@@ -28,7 +17,7 @@ export const playbackButton = ({
|
|
|
28
17
|
isLiveShowFullControls,
|
|
29
18
|
onPress,
|
|
30
19
|
}: {
|
|
31
|
-
playerState: PlayerState;
|
|
20
|
+
playerState: QuickBrickPlayer.PlayerState;
|
|
32
21
|
liveButton: boolean;
|
|
33
22
|
isTablet: boolean;
|
|
34
23
|
isLiveShowFullControls: boolean;
|
|
@@ -57,6 +46,7 @@ type ButtonsProps = {
|
|
|
57
46
|
style?: any;
|
|
58
47
|
name?: string;
|
|
59
48
|
};
|
|
49
|
+
|
|
60
50
|
type ButtonsByNameProps = ButtonsProps & { name?: string };
|
|
61
51
|
|
|
62
52
|
const rewindButtonByName = ({
|