@applicaster/quick-brick-player 13.0.0-alpha.2569962250 → 13.0.0-alpha.2614386581
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 +8 -12
- package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
- package/src/Player/AudioLayer/AudioDescription.tsx +4 -6
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +33 -29
- 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} +3 -13
- package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +43 -67
- 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 +91 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +17 -0
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +207 -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 +5 -0
- package/src/Player/AudioLayer/MagicBG/index.tsx +1 -1
- package/src/Player/AudioLayer/utils.ts +24 -0
- package/src/Player/index.tsx +29 -17
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
package/package.json
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "13.0.0-alpha.
|
|
3
|
+
"version": "13.0.0-alpha.2614386581",
|
|
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,11 +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-
|
|
40
|
-
"@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.
|
|
41
|
-
"@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.
|
|
42
|
-
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.
|
|
43
|
-
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.
|
|
38
|
+
"@applicaster/quick-brick-mobile-transport-controls": "13.0.0-alpha.2614386581",
|
|
39
|
+
"@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.2614386581",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.2614386581",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.2614386581",
|
|
44
43
|
"keymirror": "^0.1.1",
|
|
45
44
|
"query-string": "7.1.3",
|
|
46
45
|
"react-native-web-linear-gradient": "1.1.2",
|
|
@@ -61,12 +60,9 @@
|
|
|
61
60
|
"@applicaster/zapp-react-native-tvos-ui-components": "*",
|
|
62
61
|
"@babel/runtime": "*",
|
|
63
62
|
"@react-native-community/netinfo": "*",
|
|
64
|
-
"@types/node": "*",
|
|
65
|
-
"@types/react-native": "0.69.6",
|
|
66
63
|
"immer": "*",
|
|
67
|
-
"react": "
|
|
68
|
-
"react-
|
|
69
|
-
"react-native": "0.68.6",
|
|
64
|
+
"react": "*",
|
|
65
|
+
"react-native": "*",
|
|
70
66
|
"react-native-fs": "*",
|
|
71
67
|
"react-native-gesture-handler": "*",
|
|
72
68
|
"react-native-linear-gradient": "*",
|
|
@@ -55,6 +55,11 @@ const useMuteUnmuteListeners = (playerId, player, asset, setImageUri) =>
|
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// initial state setup - show correct mute/unmute icon based on current state
|
|
59
|
+
if (player?.playerState?.isReadyToPlay) {
|
|
60
|
+
setImageUri(player.getIsMuted() ? asset.active : asset.inactive);
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
// active action = muted, inactive = unmuted
|
|
59
64
|
return player.addListener({
|
|
60
65
|
id: liveImageButtonsListenerKey,
|
|
@@ -73,10 +78,17 @@ const useMuteUnmuteListeners = (playerId, player, asset, setImageUri) =>
|
|
|
73
78
|
setImageUri(player?.getIsMuted() ? asset.active : asset.inactive);
|
|
74
79
|
},
|
|
75
80
|
onPlayerClose: () => {
|
|
76
|
-
|
|
81
|
+
if (isCurrentPlayer(playerId)) {
|
|
82
|
+
setImageUri(null);
|
|
83
|
+
}
|
|
77
84
|
},
|
|
78
85
|
onVideoEnd: () => {
|
|
79
|
-
|
|
86
|
+
if (isCurrentPlayer(playerId)) {
|
|
87
|
+
setImageUri(null);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
onPlayerResume: () => {
|
|
91
|
+
setImageUri(player?.getIsMuted() ? asset.active : asset.inactive);
|
|
80
92
|
},
|
|
81
93
|
},
|
|
82
94
|
});
|
|
@@ -93,7 +105,7 @@ const styles = StyleSheet.create({
|
|
|
93
105
|
},
|
|
94
106
|
});
|
|
95
107
|
|
|
96
|
-
|
|
108
|
+
function AssetImage(props: CellActionAssetComponentProps) {
|
|
97
109
|
const { cellUUID: playerId, asset } = props;
|
|
98
110
|
const [imageUri, setImageUri] = useState<Asset>(null);
|
|
99
111
|
|
|
@@ -108,3 +120,5 @@ export function AssetComponent(props: CellActionAssetComponentProps) {
|
|
|
108
120
|
|
|
109
121
|
return <View />;
|
|
110
122
|
}
|
|
123
|
+
|
|
124
|
+
export const AssetComponent = React.memo(AssetImage);
|
|
@@ -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,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { ViewStyle, View } from "react-native";
|
|
2
|
+
import { ViewStyle, View, Dimensions as ScreenDimensions } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { SafeAreaView, Edge } from "react-native-safe-area-context";
|
|
5
5
|
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
@@ -25,21 +25,17 @@ import {
|
|
|
25
25
|
ComponentAnimationType,
|
|
26
26
|
AnimatedScrollModal,
|
|
27
27
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
28
|
-
import { PADDING_HORIZONTAL } from "./Layout/
|
|
28
|
+
import { PADDING_HORIZONTAL } from "./Layout/const";
|
|
29
29
|
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
30
|
-
|
|
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";
|
|
30
|
+
|
|
37
31
|
import {
|
|
38
32
|
SleepTimerController,
|
|
39
33
|
SleepTimerState,
|
|
40
34
|
SLEEP_TIMER_OFF,
|
|
41
35
|
} from "./SleepTimerManager";
|
|
42
36
|
import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
|
|
37
|
+
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
38
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
43
39
|
|
|
44
40
|
const { log_debug } = createLogger({
|
|
45
41
|
subsystem: "UIComponent",
|
|
@@ -57,6 +53,7 @@ type Configuration = {
|
|
|
57
53
|
[key: string]: any;
|
|
58
54
|
magic_background?: boolean;
|
|
59
55
|
audio_player_background_image_query?: string;
|
|
56
|
+
audio_player_background_image_default_color?: string;
|
|
60
57
|
tablet_landscape_sidebar_width?: string;
|
|
61
58
|
tablet_landscape_player_container_background_color?: string;
|
|
62
59
|
};
|
|
@@ -78,8 +75,7 @@ type Props = {
|
|
|
78
75
|
isTabletPortrait?: boolean;
|
|
79
76
|
};
|
|
80
77
|
|
|
81
|
-
|
|
82
|
-
(height / 9) * 16;
|
|
78
|
+
const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
|
|
83
79
|
|
|
84
80
|
const Styles = {
|
|
85
81
|
mainContainer: (style: ViewStyle) => {
|
|
@@ -105,7 +101,11 @@ const Styles = {
|
|
|
105
101
|
height: 96,
|
|
106
102
|
marginHorizontal: 24,
|
|
107
103
|
},
|
|
108
|
-
playerDetails: {
|
|
104
|
+
playerDetails: {
|
|
105
|
+
marginTop: 60,
|
|
106
|
+
alignSelf: "center",
|
|
107
|
+
width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
|
|
108
|
+
},
|
|
109
109
|
|
|
110
110
|
linearGradient: {
|
|
111
111
|
flex: 1,
|
|
@@ -123,9 +123,20 @@ const sleeps = [
|
|
|
123
123
|
{ label: "2 hours", value: 120 },
|
|
124
124
|
];
|
|
125
125
|
|
|
126
|
+
const speeds = [
|
|
127
|
+
{ label: "0.8x", value: 0.8 },
|
|
128
|
+
{ label: "1x", value: 1.0 },
|
|
129
|
+
{ label: "1.2x", value: 1.2 },
|
|
130
|
+
{ label: "1.5x", value: 1.5 },
|
|
131
|
+
{ label: "2x", value: 2.0 },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const edges: Edge[] = ["right", "left", "top"];
|
|
135
|
+
|
|
126
136
|
export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
127
137
|
const player = usePlayer();
|
|
128
138
|
const playerState = usePlayerState("audio-player-wrapper");
|
|
139
|
+
const theme = useTheme();
|
|
129
140
|
|
|
130
141
|
const {
|
|
131
142
|
docked,
|
|
@@ -138,14 +149,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
138
149
|
isTabletPortrait,
|
|
139
150
|
} = props;
|
|
140
151
|
|
|
141
|
-
const speeds = [
|
|
142
|
-
{ asset: configuration["speed_0_8"] || speed_0_8, value: 0.8 },
|
|
143
|
-
{ asset: configuration["speed_1"] || speed_1, value: 1.0 },
|
|
144
|
-
{ asset: configuration["speed_1_2"] || speed_1_2, value: 1.2 },
|
|
145
|
-
{ asset: configuration["speed_1_5"] || speed_1_5, value: 1.5 },
|
|
146
|
-
{ asset: configuration["speed_2"] || speed_2, value: 2.0 },
|
|
147
|
-
];
|
|
148
|
-
|
|
149
152
|
const isTablet = useIsTablet();
|
|
150
153
|
|
|
151
154
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
@@ -355,13 +358,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
355
358
|
player?.seekTo(0);
|
|
356
359
|
}, [player]);
|
|
357
360
|
|
|
358
|
-
const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
|
|
359
|
-
|
|
360
|
-
const ContainerView = SafeAreaView;
|
|
361
|
-
|
|
362
361
|
const MainContent = React.useMemo(() => {
|
|
363
362
|
return (
|
|
364
|
-
<
|
|
363
|
+
<SafeAreaView style={Styles.mainContainer(style)} edges={edges}>
|
|
365
364
|
<AnimationComponent
|
|
366
365
|
animationType={ComponentAnimationType.moveUpComponent}
|
|
367
366
|
additionalData={{ saveArea: true }}
|
|
@@ -416,7 +415,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
416
415
|
</View>
|
|
417
416
|
</AnimatedScrollModal>
|
|
418
417
|
</AnimationComponent>
|
|
419
|
-
</
|
|
418
|
+
</SafeAreaView>
|
|
420
419
|
);
|
|
421
420
|
}, [
|
|
422
421
|
docked,
|
|
@@ -442,21 +441,26 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
442
441
|
]);
|
|
443
442
|
|
|
444
443
|
if (configuration.magic_background) {
|
|
445
|
-
const baseUrl = entry
|
|
444
|
+
const baseUrl = imageSrcFromMediaItem(entry, null);
|
|
446
445
|
|
|
447
446
|
const queryParamName =
|
|
448
447
|
configuration.audio_player_background_image_query || "width";
|
|
449
448
|
|
|
449
|
+
const defaultBackgroundColor =
|
|
450
|
+
configuration.audio_player_background_image_default_color ||
|
|
451
|
+
theme?.app_background_color;
|
|
452
|
+
|
|
450
453
|
const queryParamValue = 15;
|
|
451
454
|
|
|
452
|
-
const url =
|
|
455
|
+
const url =
|
|
456
|
+
baseUrl && addQueryParam(baseUrl, queryParamName, queryParamValue);
|
|
453
457
|
|
|
454
458
|
return (
|
|
455
459
|
<MagicBG
|
|
456
460
|
image={url}
|
|
457
461
|
fallbackUrl={baseUrl}
|
|
458
462
|
colors={entry?.extensions?.backgroundColors}
|
|
459
|
-
defaultColor=
|
|
463
|
+
defaultColor={defaultBackgroundColor}
|
|
460
464
|
>
|
|
461
465
|
{MainContent}
|
|
462
466
|
</MagicBG>
|
|
@@ -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
|
|
|
@@ -17,9 +8,7 @@ const playbackButtonMargins = (
|
|
|
17
8
|
isTablet: boolean,
|
|
18
9
|
isLiveShowFullControls: boolean
|
|
19
10
|
): number =>
|
|
20
|
-
isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ?
|
|
21
|
-
|
|
22
|
-
export const PADDING_HORIZONTAL = 15;
|
|
11
|
+
isLiveShowFullControls ? (isTablet ? 65 : 10) : isTablet ? undefined : 40;
|
|
23
12
|
|
|
24
13
|
export const playbackButton = ({
|
|
25
14
|
playerState,
|
|
@@ -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 = ({
|