@applicaster/quick-brick-player 13.0.0-alpha.1338463240 → 13.0.0-alpha.1354246175
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 -12
- package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +128 -174
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +85 -42
- package/src/Player/AudioLayer/Layout/DockedLayout.tsx +19 -31
- package/src/Player/AudioLayer/Layout/defaultLayoutsConts.ts +3 -3
- package/src/Player/AudioLayer/MagicBG/index.tsx +1 -1
- package/src/Player/AudioLayer/SleepTimerManager.ts +119 -0
- package/src/Player/AudioLayer/SpeedManager.ts +52 -0
- package/src/Player/AudioLayer/utils.ts +24 -0
- 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/index.tsx +31 -19
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.1354246175",
|
|
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-rc.
|
|
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-rc.88",
|
|
39
|
+
"@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "13.0.0-alpha.1354246175",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.1354246175",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.1354246175",
|
|
44
43
|
"keymirror": "^0.1.1",
|
|
45
44
|
"query-string": "7.1.3",
|
|
46
45
|
"react-native-web-linear-gradient": "1.1.2",
|
|
@@ -51,12 +50,28 @@
|
|
|
51
50
|
"videojs-contrib-quality-levels": "3.0.0"
|
|
52
51
|
},
|
|
53
52
|
"peerDependencies": {
|
|
53
|
+
"@applicaster/applicaster-types": "*",
|
|
54
|
+
"@applicaster/blur": "*",
|
|
54
55
|
"@applicaster/quick-brick-xray": "*",
|
|
55
56
|
"@applicaster/react-native-color-thief": "*",
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"react": "
|
|
59
|
-
"react-native": "
|
|
60
|
-
"
|
|
57
|
+
"@applicaster/zapp-pipes-v2-client": "*",
|
|
58
|
+
"@applicaster/zapp-react-dom-ui-components": "*",
|
|
59
|
+
"@applicaster/zapp-react-native-redux": "*",
|
|
60
|
+
"@applicaster/zapp-react-native-tvos-ui-components": "*",
|
|
61
|
+
"@babel/runtime": "*",
|
|
62
|
+
"@react-native-community/netinfo": "*",
|
|
63
|
+
"immer": "*",
|
|
64
|
+
"react": "*",
|
|
65
|
+
"react-native": "*",
|
|
66
|
+
"react-native-fs": "*",
|
|
67
|
+
"react-native-gesture-handler": "*",
|
|
68
|
+
"react-native-linear-gradient": "*",
|
|
69
|
+
"react-native-safe-area-context": "*",
|
|
70
|
+
"react-native-svg": "*",
|
|
71
|
+
"react-native-web": "*",
|
|
72
|
+
"react-native-webview": "*",
|
|
73
|
+
"uglify-js": "*",
|
|
74
|
+
"validate-color": "*",
|
|
75
|
+
"zustand": "*"
|
|
61
76
|
}
|
|
62
77
|
}
|
|
@@ -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,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";
|
|
@@ -17,14 +22,15 @@ import { PlayerDetails } from "@applicaster/zapp-react-native-ui-components/Comp
|
|
|
17
22
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
23
|
import { useEffect, useState } from "react";
|
|
19
24
|
import { MagicBG } from "./MagicBG";
|
|
25
|
+
import { formatSpeed } from "./utils";
|
|
20
26
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
addQueryParam,
|
|
28
|
+
getBottomSheetModalDefaultItemIcon,
|
|
29
|
+
getBottomSheetModalIconProps,
|
|
30
|
+
getBottomSheetModalItemProps,
|
|
31
|
+
getBottomSheetModalLabelProps,
|
|
32
|
+
getBottomSheetModalSelectedItemIcon,
|
|
33
|
+
} from "../Utils";
|
|
28
34
|
import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
|
|
29
35
|
import {
|
|
30
36
|
AnimationComponent,
|
|
@@ -33,6 +39,17 @@ import {
|
|
|
33
39
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
34
40
|
import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
|
|
35
41
|
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
42
|
+
import {
|
|
43
|
+
SleepTimerController,
|
|
44
|
+
SleepTimerState,
|
|
45
|
+
SLEEP_TIMER_OFF,
|
|
46
|
+
} from "./SleepTimerManager";
|
|
47
|
+
import { SpeedController, PlaybackSpeed, DEFAULT_SPEED } from "./SpeedManager";
|
|
48
|
+
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
49
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
50
|
+
import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
|
|
51
|
+
import { sleepTimerOptions } from "../Const/sleepTimerOptions";
|
|
52
|
+
import { speedOptions } from "../Const/speedOptions";
|
|
36
53
|
|
|
37
54
|
const { log_debug } = createLogger({
|
|
38
55
|
subsystem: "UIComponent",
|
|
@@ -50,6 +67,7 @@ type Configuration = {
|
|
|
50
67
|
[key: string]: any;
|
|
51
68
|
magic_background?: boolean;
|
|
52
69
|
audio_player_background_image_query?: string;
|
|
70
|
+
audio_player_background_image_default_color?: string;
|
|
53
71
|
tablet_landscape_sidebar_width?: string;
|
|
54
72
|
tablet_landscape_player_container_background_color?: string;
|
|
55
73
|
};
|
|
@@ -71,54 +89,26 @@ type Props = {
|
|
|
71
89
|
isTabletPortrait?: boolean;
|
|
72
90
|
};
|
|
73
91
|
|
|
74
|
-
|
|
75
|
-
(height / 9) * 16;
|
|
76
|
-
|
|
77
|
-
const Styles = {
|
|
78
|
-
mainContainer: (style: ViewStyle) => {
|
|
79
|
-
const combinedStyle: ViewStyle = {
|
|
80
|
-
flex: 1,
|
|
81
|
-
};
|
|
92
|
+
const { width: SCREEN_WIDTH } = ScreenDimensions.get("screen");
|
|
82
93
|
|
|
83
|
-
|
|
84
|
-
...combinedStyle,
|
|
85
|
-
...style,
|
|
86
|
-
};
|
|
87
|
-
},
|
|
94
|
+
const Styles = StyleSheet.create({
|
|
88
95
|
playerContainer: {
|
|
89
96
|
flex: 1,
|
|
90
97
|
},
|
|
91
98
|
paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
},
|
|
97
|
-
controlsTablet: {
|
|
98
|
-
height: 96,
|
|
99
|
-
marginHorizontal: 24,
|
|
99
|
+
playerDetails: {
|
|
100
|
+
marginTop: 60,
|
|
101
|
+
alignSelf: "center",
|
|
102
|
+
width: SCREEN_WIDTH - PADDING_HORIZONTAL * 2,
|
|
100
103
|
},
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
linearGradient: {
|
|
104
|
-
flex: 1,
|
|
105
|
-
},
|
|
106
|
-
};
|
|
104
|
+
});
|
|
107
105
|
|
|
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
|
-
];
|
|
106
|
+
const edges: Edge[] = ["right", "left", "top"];
|
|
118
107
|
|
|
119
108
|
export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
120
109
|
const player = usePlayer();
|
|
121
110
|
const playerState = usePlayerState("audio-player-wrapper");
|
|
111
|
+
const theme = useTheme();
|
|
122
112
|
|
|
123
113
|
const {
|
|
124
114
|
docked,
|
|
@@ -131,40 +121,39 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
131
121
|
isTabletPortrait,
|
|
132
122
|
} = props;
|
|
133
123
|
|
|
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
124
|
const isTablet = useIsTablet();
|
|
143
125
|
|
|
144
126
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
145
127
|
|
|
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
128
|
const { title, summary } = useTitleSummaryOverlay(
|
|
151
|
-
feedUrl,
|
|
152
129
|
entry,
|
|
153
130
|
playerState?.isLive,
|
|
154
131
|
configuration?.audio_live_player_update_interval
|
|
155
132
|
);
|
|
156
133
|
|
|
157
|
-
const [
|
|
158
|
-
|
|
159
|
-
value: 1.0,
|
|
160
|
-
});
|
|
134
|
+
const [sleepTimerManager, setSleepTimerManager] =
|
|
135
|
+
useState<SleepTimerController | null>(null);
|
|
161
136
|
|
|
162
|
-
const [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
137
|
+
const [speedManager, setSpeedManager] = useState<SpeedController | null>(
|
|
138
|
+
null
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
if (player) {
|
|
143
|
+
setSleepTimerManager(new SleepTimerController(player));
|
|
144
|
+
setSpeedManager(new SpeedController(player));
|
|
145
|
+
} else {
|
|
146
|
+
setSleepTimerManager(null);
|
|
147
|
+
setSpeedManager(null);
|
|
148
|
+
}
|
|
149
|
+
}, [player]);
|
|
166
150
|
|
|
167
|
-
const [
|
|
151
|
+
const [playbackSpeed, setPlaybackSpeed] =
|
|
152
|
+
useState<PlaybackSpeed>(DEFAULT_SPEED);
|
|
153
|
+
|
|
154
|
+
const [sleepTimerState, setSleepTimerState] = useState<SleepTimerState>(
|
|
155
|
+
new SleepTimerState(SLEEP_TIMER_OFF, 0)
|
|
156
|
+
);
|
|
168
157
|
|
|
169
158
|
const [defaultDimensions, setDefaultDimensions] =
|
|
170
159
|
React.useState<Dimensions>(undefined);
|
|
@@ -174,8 +163,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
174
163
|
height: 0,
|
|
175
164
|
});
|
|
176
165
|
|
|
177
|
-
const navigator = useNavigation();
|
|
178
|
-
|
|
179
166
|
const { maximiseVideoModal } = useNavigation();
|
|
180
167
|
|
|
181
168
|
const onLayout = (event: any) => {
|
|
@@ -189,82 +176,27 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
189
176
|
if (!defaultDimensions) setDefaultDimensions({ width, height });
|
|
190
177
|
};
|
|
191
178
|
|
|
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
179
|
useEffect(() => {
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
if (playerState.isReadyToPlay && speed) {
|
|
249
|
-
setPlaybackSpeed(speed);
|
|
250
|
-
player?.setPlaybackRate(speed.value);
|
|
251
|
-
}
|
|
252
|
-
};
|
|
180
|
+
const sleepSubscription =
|
|
181
|
+
sleepTimerManager?.sleepTimerState$.subscribe(setSleepTimerState);
|
|
253
182
|
|
|
254
|
-
const
|
|
255
|
-
|
|
183
|
+
const speedSubscription =
|
|
184
|
+
speedManager?.playbackSpeed$.subscribe(setPlaybackSpeed);
|
|
256
185
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const sleepTimerDate = await handleSleep(sleep.value, futureSleepDate);
|
|
261
|
-
setSleepTimerDate(sleepTimerDate);
|
|
262
|
-
}
|
|
186
|
+
return () => {
|
|
187
|
+
sleepSubscription?.unsubscribe();
|
|
188
|
+
speedSubscription?.unsubscribe();
|
|
263
189
|
};
|
|
190
|
+
}, [sleepTimerManager, speedManager]);
|
|
264
191
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (!playerState.isReadyToPlay) {
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
void speedManager?.loadSpeed();
|
|
198
|
+
void sleepTimerManager?.loadSleep();
|
|
199
|
+
}, [playerState.isReadyToPlay, speedManager, sleepTimerManager]);
|
|
268
200
|
|
|
269
201
|
const getValue = (key: string, stylesObj: {}) =>
|
|
270
202
|
R.propOr(null, key, stylesObj);
|
|
@@ -292,7 +224,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
292
224
|
|
|
293
225
|
const onPlaybackButtonPress = React.useCallback(() => {
|
|
294
226
|
if (playerState.isBuffering) return;
|
|
295
|
-
playerState.isPaused ? player?.play() : player
|
|
227
|
+
playerState.isPaused ? player?.play() : player?.pause();
|
|
296
228
|
}, [playerState, player]);
|
|
297
229
|
|
|
298
230
|
const seekDuration = toNumberWithDefault(10, value("seek_duration"));
|
|
@@ -307,57 +239,74 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
307
239
|
|
|
308
240
|
const onSpeedSelect = React.useCallback(
|
|
309
241
|
async (item) => {
|
|
310
|
-
setPlaybackSpeed(item);
|
|
311
|
-
player.setPlaybackRate(item.value);
|
|
312
|
-
await localStorage.setItem("speed", item, NAMESPACE);
|
|
242
|
+
await speedManager?.setPlaybackSpeed(item);
|
|
313
243
|
},
|
|
314
|
-
[
|
|
244
|
+
[speedManager]
|
|
315
245
|
);
|
|
316
246
|
|
|
317
247
|
const onSleepSelect = React.useCallback(
|
|
318
248
|
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
|
-
);
|
|
249
|
+
await sleepTimerManager?.setSleepTimer(item);
|
|
328
250
|
},
|
|
329
|
-
[
|
|
251
|
+
[sleepTimerManager]
|
|
330
252
|
);
|
|
331
253
|
|
|
332
254
|
const onSpeedButtonPress = React.useCallback(() => {
|
|
333
|
-
|
|
255
|
+
openBottomSheetModal({
|
|
334
256
|
modalBottomSheetContentProps: {
|
|
335
|
-
items:
|
|
257
|
+
items: speedOptions,
|
|
336
258
|
current_selection: playbackSpeed,
|
|
337
259
|
onPress: onSpeedSelect,
|
|
338
260
|
title: configuration["playback_speed_title"],
|
|
261
|
+
itemProps: getBottomSheetModalItemProps,
|
|
262
|
+
iconProps: getBottomSheetModalIconProps,
|
|
263
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
264
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
265
|
+
getDefaultItemIcon: getBottomSheetModalDefaultItemIcon,
|
|
266
|
+
iconPlacement: "right",
|
|
339
267
|
},
|
|
340
268
|
options: {
|
|
341
269
|
supportedOrientations: ["portrait"],
|
|
342
270
|
},
|
|
343
271
|
});
|
|
344
|
-
}, [playbackSpeed,
|
|
272
|
+
}, [playbackSpeed, onSpeedSelect, configuration["playback_speed_title"]]);
|
|
345
273
|
|
|
346
274
|
const onSleepButtonPress = React.useCallback(() => {
|
|
347
|
-
|
|
275
|
+
openBottomSheetModal({
|
|
348
276
|
modalBottomSheetContentProps: {
|
|
349
277
|
items: [
|
|
350
|
-
{
|
|
351
|
-
|
|
352
|
-
|
|
278
|
+
{
|
|
279
|
+
label: configuration["playback_sleep_off_label"],
|
|
280
|
+
value: 0,
|
|
281
|
+
},
|
|
282
|
+
].concat(sleepTimerOptions),
|
|
283
|
+
current_selection: sleepTimerState.timer,
|
|
353
284
|
onPress: onSleepSelect,
|
|
354
285
|
title: configuration["playback_sleep_title"],
|
|
286
|
+
itemProps: getBottomSheetModalItemProps,
|
|
287
|
+
iconProps: getBottomSheetModalIconProps,
|
|
288
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
289
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
290
|
+
iconPlacement: "right",
|
|
355
291
|
},
|
|
356
292
|
options: {
|
|
357
293
|
supportedOrientations: ["portrait"],
|
|
358
294
|
},
|
|
359
295
|
});
|
|
360
|
-
}, [
|
|
296
|
+
}, [
|
|
297
|
+
sleepTimerState.timer,
|
|
298
|
+
configuration["playback_sleep_title"],
|
|
299
|
+
configuration["playback_sleep_off_label"],
|
|
300
|
+
onSleepSelect,
|
|
301
|
+
]);
|
|
302
|
+
|
|
303
|
+
// This method does not actually cancel the sleep timer
|
|
304
|
+
// (and should not to avoid race condition),
|
|
305
|
+
// it just performs the cleanup when timer expires
|
|
306
|
+
// TODO: rename it in code above
|
|
307
|
+
const cancelSleepTimer = React.useCallback(() => {
|
|
308
|
+
sleepTimerManager?.onTimerExpired();
|
|
309
|
+
}, [sleepTimerManager]);
|
|
361
310
|
|
|
362
311
|
const onCloseVideoModal = React.useCallback(() => {
|
|
363
312
|
playerManager.close();
|
|
@@ -378,13 +327,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
378
327
|
player?.seekTo(0);
|
|
379
328
|
}, [player]);
|
|
380
329
|
|
|
381
|
-
const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
|
|
382
|
-
|
|
383
330
|
const ContainerView = SafeAreaView;
|
|
384
331
|
|
|
385
332
|
const MainContent = React.useMemo(() => {
|
|
386
333
|
return (
|
|
387
|
-
<ContainerView style={Styles.
|
|
334
|
+
<ContainerView style={[style, Styles.playerContainer]} edges={edges}>
|
|
388
335
|
<AnimationComponent
|
|
389
336
|
animationType={ComponentAnimationType.moveUpComponent}
|
|
390
337
|
additionalData={{ saveArea: true }}
|
|
@@ -406,9 +353,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
406
353
|
onSleepButtonPress={onSleepButtonPress}
|
|
407
354
|
playbackSpeedName={formatSpeed(playbackSpeed.value)}
|
|
408
355
|
playbackSleepName={
|
|
409
|
-
|
|
356
|
+
sleepTimerState.timer.value === 0
|
|
357
|
+
? "sleep_timer"
|
|
358
|
+
: "sleep_timer_active"
|
|
410
359
|
}
|
|
411
|
-
sleepTimerDate={
|
|
360
|
+
sleepTimerDate={sleepTimerState.timerDate}
|
|
412
361
|
cancelSleepTimer={cancelSleepTimer}
|
|
413
362
|
onSkipLive={onSkipLive}
|
|
414
363
|
onCloseVideoModal={onCloseVideoModal}
|
|
@@ -426,11 +375,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
426
375
|
animationType={ComponentAnimationType.componentFade}
|
|
427
376
|
>
|
|
428
377
|
<PlayerDetails
|
|
378
|
+
isAudioPlayer
|
|
429
379
|
configuration={configuration}
|
|
430
380
|
style={Styles.playerDetails}
|
|
431
381
|
entry={entry}
|
|
432
382
|
isTabletLandscape={isTabletLandscape}
|
|
433
|
-
isAudioPlayer={true}
|
|
434
383
|
/>
|
|
435
384
|
</AnimationComponent>
|
|
436
385
|
</View>
|
|
@@ -458,26 +407,31 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
458
407
|
playNextData,
|
|
459
408
|
onSkipStart,
|
|
460
409
|
onSkipLive,
|
|
461
|
-
|
|
462
|
-
|
|
410
|
+
sleepTimerState.timer.value,
|
|
411
|
+
sleepTimerState.timerDate,
|
|
463
412
|
]);
|
|
464
413
|
|
|
465
414
|
if (configuration.magic_background) {
|
|
466
|
-
const baseUrl = entry
|
|
415
|
+
const baseUrl = imageSrcFromMediaItem(entry, null);
|
|
467
416
|
|
|
468
417
|
const queryParamName =
|
|
469
418
|
configuration.audio_player_background_image_query || "width";
|
|
470
419
|
|
|
420
|
+
const defaultBackgroundColor =
|
|
421
|
+
configuration.audio_player_background_image_default_color ||
|
|
422
|
+
theme?.app_background_color;
|
|
423
|
+
|
|
471
424
|
const queryParamValue = 15;
|
|
472
425
|
|
|
473
|
-
const url =
|
|
426
|
+
const url =
|
|
427
|
+
baseUrl && addQueryParam(baseUrl, queryParamName, queryParamValue);
|
|
474
428
|
|
|
475
429
|
return (
|
|
476
430
|
<MagicBG
|
|
477
431
|
image={url}
|
|
478
432
|
fallbackUrl={baseUrl}
|
|
479
433
|
colors={entry?.extensions?.backgroundColors}
|
|
480
|
-
defaultColor=
|
|
434
|
+
defaultColor={defaultBackgroundColor}
|
|
481
435
|
>
|
|
482
436
|
{MainContent}
|
|
483
437
|
</MagicBG>
|