@applicaster/quick-brick-player 15.1.13-alpha.1034774223 → 15.1.13
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/AudioPlayerWrapper.tsx +39 -17
- package/src/Player/AudioLayer/Layout/Controls/__tests__/utils.test.ts +4 -25
- package/src/Player/AudioLayer/Layout/Controls/index.tsx +8 -2
- package/src/Player/AudioLayer/Layout/Controls/utils.ts +0 -14
- package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +8 -69
- package/src/Player/AudioLayer/SleepTimerManager.ts +1 -5
- package/src/Player/AudioLayer/SpeedManager.ts +0 -4
- package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +66 -0
- package/src/Player/AudioLayer/components/SleepTimerModalHeader/index.ts +1 -0
- package/src/Player/AudioLayer/useSleepTimerModal.ts +57 -20
- package/src/Player/AudioLayer/Layout/TransportInfo/__tests__/index.test.tsx +0 -257
- package/src/Player/AudioLayer/__tests__/SleepTimerManager.test.ts +0 -78
- package/src/Player/AudioLayer/__tests__/SpeedManager.test.ts +0 -57
- package/src/Player/AudioLayer/__tests__/playerActions.test.ts +0 -369
- package/src/Player/AudioLayer/playerActions.ts +0 -294
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "15.1.13
|
|
3
|
+
"version": "15.1.13",
|
|
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": "15.1.
|
|
38
|
+
"@applicaster/quick-brick-mobile-transport-controls": "15.1.9",
|
|
39
39
|
"@applicaster/quick-brick-tv-transport-controls": "15.1.9",
|
|
40
|
-
"@applicaster/zapp-react-native-tvos-app": "15.1.13
|
|
41
|
-
"@applicaster/zapp-react-native-ui-components": "15.1.13
|
|
42
|
-
"@applicaster/zapp-react-native-utils": "15.1.13
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "15.1.13",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "15.1.13",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "15.1.13",
|
|
43
43
|
"query-string": "7.1.3",
|
|
44
44
|
"shaka-player": "4.3.5",
|
|
45
45
|
"typeface-montserrat": "^0.0.54",
|
|
@@ -12,18 +12,23 @@ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
|
12
12
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
13
13
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
14
14
|
import { formatSpeed } from "./utils";
|
|
15
|
+
import {
|
|
16
|
+
getBottomSheetModalDefaultItemIcon,
|
|
17
|
+
getBottomSheetModalIconProps,
|
|
18
|
+
getBottomSheetModalItemProps,
|
|
19
|
+
getBottomSheetModalLabelProps,
|
|
20
|
+
getBottomSheetModalSelectedItemIcon,
|
|
21
|
+
} from "../Utils";
|
|
15
22
|
|
|
16
23
|
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
24
|
+
|
|
17
25
|
import { DEFAULT_SPEED, PlaybackSpeed, SpeedController } from "./SpeedManager";
|
|
18
26
|
import {
|
|
19
27
|
dismissModal as dismissBottomSheetModal,
|
|
28
|
+
openBottomSheetModal,
|
|
20
29
|
useModalStoreState,
|
|
21
30
|
} from "@applicaster/zapp-react-native-utils/modalState";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
PLAYER_ACTION_IDENTIFIERS,
|
|
25
|
-
registerPlayerActions,
|
|
26
|
-
} from "./playerActions";
|
|
31
|
+
import { speedOptions } from "../Const/speedOptions";
|
|
27
32
|
|
|
28
33
|
const { log_debug } = createLogger({
|
|
29
34
|
subsystem: "UIComponent",
|
|
@@ -113,14 +118,6 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
113
118
|
setSpeedManager(player ? new SpeedController(player) : null);
|
|
114
119
|
}, [player]);
|
|
115
120
|
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
if (!speedManager || playerState.isLive) {
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return registerPlayerActions({ speedController: speedManager });
|
|
122
|
-
}, [speedManager, playerState.isLive]);
|
|
123
|
-
|
|
124
121
|
useEffect(() => {
|
|
125
122
|
if (!player) return;
|
|
126
123
|
|
|
@@ -219,11 +216,36 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
219
216
|
player?.forward(seekDuration);
|
|
220
217
|
}, [seekDuration, player]);
|
|
221
218
|
|
|
219
|
+
const onSpeedSelect = React.useCallback(
|
|
220
|
+
async (item) => {
|
|
221
|
+
await speedManager?.setPlaybackSpeed(item);
|
|
222
|
+
},
|
|
223
|
+
[speedManager]
|
|
224
|
+
);
|
|
225
|
+
|
|
222
226
|
const onSpeedButtonPress = React.useCallback(() => {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
+
openBottomSheetModal({
|
|
228
|
+
modalBottomSheetContentProps: {
|
|
229
|
+
items: speedOptions,
|
|
230
|
+
current_selection: playbackSpeed,
|
|
231
|
+
onPress: onSpeedSelect,
|
|
232
|
+
title: configuration.playback_speed_title,
|
|
233
|
+
itemProps: getBottomSheetModalItemProps,
|
|
234
|
+
iconProps: getBottomSheetModalIconProps,
|
|
235
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
236
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
237
|
+
getDefaultItemIcon: getBottomSheetModalDefaultItemIcon,
|
|
238
|
+
iconPlacement: "right",
|
|
239
|
+
},
|
|
240
|
+
options: {
|
|
241
|
+
supportedOrientations: [
|
|
242
|
+
"portrait",
|
|
243
|
+
"landscape",
|
|
244
|
+
"portrait-upside-down",
|
|
245
|
+
],
|
|
246
|
+
},
|
|
247
|
+
});
|
|
248
|
+
}, [playbackSpeed, onSpeedSelect, configuration.playback_speed_title]);
|
|
227
249
|
|
|
228
250
|
const onPlayerSeek = React.useCallback(
|
|
229
251
|
(targetTime: number) => {
|
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
controlsRowActionIdentifiers,
|
|
3
2
|
nextTrackButton,
|
|
4
3
|
previousTrackButton,
|
|
5
4
|
usesPlaylistControls,
|
|
6
5
|
} from "../utils";
|
|
7
|
-
import { PLAYER_ACTION_IDENTIFIERS } from "../../../playerActions";
|
|
8
|
-
|
|
9
|
-
const configuredAs = (layout?: unknown): GetValue =>
|
|
10
|
-
((key: string) =>
|
|
11
|
-
key === "player_controls_layout" ? layout : null) as unknown as GetValue;
|
|
12
6
|
|
|
13
7
|
describe("usesPlaylistControls", () => {
|
|
8
|
+
const configuredAs = (layout?: unknown): GetValue =>
|
|
9
|
+
((key: string) =>
|
|
10
|
+
key === "player_controls_layout" ? layout : null) as unknown as GetValue;
|
|
11
|
+
|
|
14
12
|
it("opts in only for the playlist controls value", () => {
|
|
15
13
|
expect(usesPlaylistControls(configuredAs("playlist_controls"))).toBe(true);
|
|
16
14
|
});
|
|
@@ -31,25 +29,6 @@ describe("usesPlaylistControls", () => {
|
|
|
31
29
|
});
|
|
32
30
|
});
|
|
33
31
|
|
|
34
|
-
describe("controlsRowActionIdentifiers", () => {
|
|
35
|
-
it("claims playback speed and sleep timer on the default layout", () => {
|
|
36
|
-
expect(
|
|
37
|
-
controlsRowActionIdentifiers(
|
|
38
|
-
configuredAs("playback_speed_and_sleep_timer")
|
|
39
|
-
)
|
|
40
|
-
).toEqual([
|
|
41
|
-
PLAYER_ACTION_IDENTIFIERS.PLAYBACK_SPEED,
|
|
42
|
-
PLAYER_ACTION_IDENTIFIERS.SLEEP_TIMER,
|
|
43
|
-
]);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it("claims nothing when the row shows playlist controls", () => {
|
|
47
|
-
expect(
|
|
48
|
-
controlsRowActionIdentifiers(configuredAs("playlist_controls"))
|
|
49
|
-
).toEqual([]);
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
|
|
53
32
|
describe("track control buttons", () => {
|
|
54
33
|
it("builds a previous button using the previous_track icon", () => {
|
|
55
34
|
const onPress = jest.fn();
|
|
@@ -2,7 +2,10 @@ import * as React from "react";
|
|
|
2
2
|
import { StyleSheet, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
useIsTablet,
|
|
7
|
+
useZStore,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
9
|
import {
|
|
7
10
|
Controls as MobileTransportControls,
|
|
8
11
|
ProgressBar,
|
|
@@ -97,8 +100,11 @@ export const Controls = (props: Props) => {
|
|
|
97
100
|
maxWidth = 320,
|
|
98
101
|
} = props;
|
|
99
102
|
|
|
103
|
+
const configuration = useZStore("playerConfiguration");
|
|
104
|
+
|
|
100
105
|
const { sleepTimerState, onSleepButtonPress } = useSleepTimerModal(
|
|
101
|
-
playerManager.getActivePlayer()
|
|
106
|
+
playerManager.getActivePlayer(),
|
|
107
|
+
configuration
|
|
102
108
|
);
|
|
103
109
|
|
|
104
110
|
const { hasNext, hasPrevious, goNext, goPrevious } = usePlaylistNavigation(
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { PLAYER_ACTION_IDENTIFIERS } from "../../playerActions";
|
|
2
|
-
|
|
3
1
|
const playbackButtonMargins = (
|
|
4
2
|
isTablet: boolean,
|
|
5
3
|
isLiveShowFullControls: boolean
|
|
@@ -111,18 +109,6 @@ export const sleepButton = (props: ButtonsProps): ControlsButton =>
|
|
|
111
109
|
export const usesPlaylistControls = (value: GetValue): boolean =>
|
|
112
110
|
value("player_controls_layout") === "playlist_controls";
|
|
113
111
|
|
|
114
|
-
/**
|
|
115
|
-
* Player actions this row renders as its own buttons. Consumers of the shared
|
|
116
|
-
* player action list have to filter these out to avoid showing them twice.
|
|
117
|
-
*/
|
|
118
|
-
export const controlsRowActionIdentifiers = (value: GetValue): string[] =>
|
|
119
|
-
usesPlaylistControls(value)
|
|
120
|
-
? []
|
|
121
|
-
: [
|
|
122
|
-
PLAYER_ACTION_IDENTIFIERS.PLAYBACK_SPEED,
|
|
123
|
-
PLAYER_ACTION_IDENTIFIERS.SLEEP_TIMER,
|
|
124
|
-
];
|
|
125
|
-
|
|
126
112
|
type TrackButtonProps = ButtonsProps & { disabled?: boolean };
|
|
127
113
|
|
|
128
114
|
const trackButtonByName = ({
|
|
@@ -3,8 +3,7 @@ import { LayoutChangeEvent, StyleSheet, View } from "react-native";
|
|
|
3
3
|
|
|
4
4
|
import { TransportInfo as MobileTransportInfo } from "@applicaster/quick-brick-mobile-transport-controls";
|
|
5
5
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
|
-
import {
|
|
7
|
-
import { useEntryActionsExpander } from "@applicaster/zapp-react-native-ui-components/Hooks/useEntryActionsExpander";
|
|
6
|
+
import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
|
|
8
7
|
|
|
9
8
|
import { toPositiveNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
10
9
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
@@ -13,22 +12,7 @@ import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "../const";
|
|
|
13
12
|
import { withDebug } from "../debug";
|
|
14
13
|
import { useSafeAreaFrame } from "react-native-safe-area-context";
|
|
15
14
|
import { isSmallTabletHeight } from "../utils";
|
|
16
|
-
import {
|
|
17
|
-
ActionButtonDescriptor,
|
|
18
|
-
resolvePlayerActions,
|
|
19
|
-
} from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
20
|
-
import {
|
|
21
|
-
RegisteredAction,
|
|
22
|
-
uiActionsRegistry,
|
|
23
|
-
} from "@applicaster/zapp-react-native-utils/uiActionsRegistrator";
|
|
24
|
-
|
|
25
|
-
import { PLAYER_ACTION_IDENTIFIERS } from "../../playerActions";
|
|
26
|
-
import { controlsRowActionIdentifiers } from "../Controls/utils";
|
|
27
|
-
|
|
28
|
-
/** Player-owned actions that join the shared action list of the overlay. */
|
|
29
|
-
const AUDIO_PLAYER_ACTION_IDENTIFIERS: string[] = Object.values(
|
|
30
|
-
PLAYER_ACTION_IDENTIFIERS
|
|
31
|
-
);
|
|
15
|
+
import { getPlayerActionButtons } from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
32
16
|
|
|
33
17
|
const styles = StyleSheet.create({
|
|
34
18
|
container: {
|
|
@@ -68,8 +52,7 @@ export const TransportInfo = ({
|
|
|
68
52
|
}: Props) => {
|
|
69
53
|
const isTablet = useIsTablet();
|
|
70
54
|
const safeAreaFrame = useSafeAreaFrame();
|
|
71
|
-
const
|
|
72
|
-
const expandEntryActions = useEntryActionsExpander();
|
|
55
|
+
const languageData = useLanguageData("audio-player");
|
|
73
56
|
|
|
74
57
|
const [marginBottom, setMarginBottom] = React.useState(0);
|
|
75
58
|
|
|
@@ -98,56 +81,11 @@ export const TransportInfo = ({
|
|
|
98
81
|
[onLayout]
|
|
99
82
|
);
|
|
100
83
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const overlayActionIdentifiers = React.useMemo(() => {
|
|
106
|
-
const renderedByControlsRow = controlsRowIdentifiersKey.split(",");
|
|
107
|
-
|
|
108
|
-
return AUDIO_PLAYER_ACTION_IDENTIFIERS.filter(
|
|
109
|
-
(identifier) => !renderedByControlsRow.includes(identifier)
|
|
110
|
-
);
|
|
111
|
-
}, [controlsRowIdentifiersKey]);
|
|
112
|
-
|
|
113
|
-
const readOwnPlayerActions = React.useCallback(
|
|
114
|
-
(): RegisteredAction[] =>
|
|
115
|
-
overlayActionIdentifiers.flatMap((identifier) =>
|
|
116
|
-
uiActionsRegistry.getActions(identifier, entry)
|
|
117
|
-
),
|
|
118
|
-
[entry, overlayActionIdentifiers]
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
// Playback speed and the sleep timer register in a later effect than our
|
|
122
|
-
// first render - speed waits for SpeedController state - so re-read whenever
|
|
123
|
-
// the registry changes instead of guessing when they will be there.
|
|
124
|
-
const playerActions = React.useMemo(
|
|
125
|
-
() => readOwnPlayerActions(),
|
|
126
|
-
// eslint-disable-next-line @wogns3623/better-exhaustive-deps/exhaustive-deps
|
|
127
|
-
[readOwnPlayerActions, registryRevision]
|
|
84
|
+
const actionButtons = React.useMemo(
|
|
85
|
+
() => getPlayerActionButtons(configuration),
|
|
86
|
+
[configuration]
|
|
128
87
|
);
|
|
129
88
|
|
|
130
|
-
const actionButtonDescriptors = React.useMemo<
|
|
131
|
-
ActionButtonDescriptor[]
|
|
132
|
-
>(() => {
|
|
133
|
-
const content = resolvePlayerActions({
|
|
134
|
-
configuration,
|
|
135
|
-
entry,
|
|
136
|
-
expandEntryActions,
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
const seen = new Set(content.map((action) => action.identifier));
|
|
140
|
-
|
|
141
|
-
const extras = playerActions.filter(
|
|
142
|
-
(action) => action?.identifier && !seen.has(action.identifier)
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
return [...content, ...extras].map((action) => ({
|
|
146
|
-
kind: "action" as const,
|
|
147
|
-
action,
|
|
148
|
-
}));
|
|
149
|
-
}, [configuration, entry, playerActions, expandEntryActions]);
|
|
150
|
-
|
|
151
89
|
return (
|
|
152
90
|
<View
|
|
153
91
|
style={[
|
|
@@ -168,8 +106,9 @@ export const TransportInfo = ({
|
|
|
168
106
|
content={entry}
|
|
169
107
|
value={value}
|
|
170
108
|
visible
|
|
109
|
+
languageData={languageData}
|
|
171
110
|
layoutState={layoutState}
|
|
172
|
-
|
|
111
|
+
actionButtons={actionButtons}
|
|
173
112
|
/>
|
|
174
113
|
</View>
|
|
175
114
|
</View>
|
|
@@ -41,10 +41,6 @@ export class SleepTimerController {
|
|
|
41
41
|
return this.sleepTimerStateSubject.asObservable();
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
get currentState(): SleepTimerState {
|
|
45
|
-
return this.sleepTimerStateSubject.getValue();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
44
|
private async scheduleSleep(sleepDate): Promise<boolean> {
|
|
49
45
|
log_debug(`Setting sleep interval to ${sleepDate}`);
|
|
50
46
|
|
|
@@ -122,7 +118,7 @@ export class SleepTimerController {
|
|
|
122
118
|
|
|
123
119
|
log_debug("Sleep state restored");
|
|
124
120
|
|
|
125
|
-
|
|
121
|
+
this.setSleepTimer(item as SleepTimer, futureSleepDate);
|
|
126
122
|
}
|
|
127
123
|
|
|
128
124
|
// Will be called if user closed the player explicitly.
|
|
@@ -33,10 +33,6 @@ export class SpeedController {
|
|
|
33
33
|
return this.playbackSpeedSubject.asObservable();
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
get currentSpeed(): PlaybackSpeed {
|
|
37
|
-
return this.playbackSpeedSubject.getValue();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
36
|
async loadSpeed() {
|
|
41
37
|
const speed = await localStorage.getItem(SPEED_PREFERENCE_KEY, NAMESPACE);
|
|
42
38
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ModalHeader } from "@applicaster/zapp-react-native-ui-components/Components/ModalComponent/Header";
|
|
3
|
+
import { isNil } from "@applicaster/zapp-react-native-utils/utils";
|
|
4
|
+
|
|
5
|
+
const formatTime = (milliseconds: number) => {
|
|
6
|
+
const totalSeconds = Math.floor(milliseconds / 1000);
|
|
7
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
8
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
9
|
+
const seconds = totalSeconds % 60;
|
|
10
|
+
|
|
11
|
+
if (milliseconds < 3600000) {
|
|
12
|
+
return `${minutes.toString().padStart(2, "0")}:${seconds
|
|
13
|
+
.toString()
|
|
14
|
+
.padStart(2, "0")}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return `${hours.toString().padStart(2, "0")}:${minutes
|
|
18
|
+
.toString()
|
|
19
|
+
.padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const SleepTimerModalHeader = ({
|
|
23
|
+
summary,
|
|
24
|
+
...props
|
|
25
|
+
}: {
|
|
26
|
+
summary?: string;
|
|
27
|
+
}) => {
|
|
28
|
+
const sleepTimerDate = +summary;
|
|
29
|
+
|
|
30
|
+
const [timeLeft, setTimeLeft] = React.useState(
|
|
31
|
+
sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const showCounter = React.useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
|
|
35
|
+
|
|
36
|
+
React.useLayoutEffect(() => {
|
|
37
|
+
if (showCounter && sleepTimerDate !== 0) {
|
|
38
|
+
setTimeLeft(sleepTimerDate - Date.now());
|
|
39
|
+
|
|
40
|
+
const intervalId = setInterval(() => {
|
|
41
|
+
setTimeLeft(() => {
|
|
42
|
+
const newTimeLeft = sleepTimerDate - Date.now();
|
|
43
|
+
|
|
44
|
+
if (newTimeLeft <= 0) {
|
|
45
|
+
clearInterval(intervalId);
|
|
46
|
+
|
|
47
|
+
return 0;
|
|
48
|
+
} else {
|
|
49
|
+
return newTimeLeft;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}, 1000);
|
|
53
|
+
|
|
54
|
+
return () => clearInterval(intervalId);
|
|
55
|
+
} else {
|
|
56
|
+
setTimeLeft(0);
|
|
57
|
+
}
|
|
58
|
+
}, [sleepTimerDate, showCounter]);
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<ModalHeader
|
|
62
|
+
summary={!isNil(summary) ? formatTime(timeLeft) : summary}
|
|
63
|
+
{...(props as any)}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./SleepTimerModalHeader";
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
2
|
-
import { uiActionsRegistry } from "@applicaster/zapp-react-native-utils/uiActionsRegistrator";
|
|
3
2
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
4
3
|
import {
|
|
5
4
|
SLEEP_TIMER_OFF,
|
|
6
5
|
SleepTimerController,
|
|
7
6
|
SleepTimerState,
|
|
8
7
|
} from "./SleepTimerManager";
|
|
8
|
+
|
|
9
|
+
import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
|
|
10
|
+
|
|
11
|
+
import { SleepTimerModalHeader } from "./components/SleepTimerModalHeader";
|
|
12
|
+
import { getSleepTimerOptions } from "../Const/sleepTimerOptions";
|
|
9
13
|
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
getBottomSheetModalLabelProps,
|
|
15
|
+
getBottomSheetModalIconProps,
|
|
16
|
+
getBottomSheetModalItemProps,
|
|
17
|
+
getBottomSheetModalSelectedItemIcon,
|
|
18
|
+
selectSleepTitle,
|
|
19
|
+
selectSleepOffLabel,
|
|
20
|
+
} from "../Utils";
|
|
13
21
|
|
|
14
|
-
export const useSleepTimerModal = (player) => {
|
|
22
|
+
export const useSleepTimerModal = (player, configuration) => {
|
|
15
23
|
const playerState = usePlayerState("audio-player-sleep-timer-modal");
|
|
16
24
|
|
|
25
|
+
const title = configuration(selectSleepTitle);
|
|
26
|
+
const offLabel = configuration(selectSleepOffLabel);
|
|
27
|
+
|
|
17
28
|
const [sleepTimerManager, setSleepTimerManager] =
|
|
18
29
|
useState<SleepTimerController | null>(null);
|
|
19
30
|
|
|
@@ -22,22 +33,19 @@ export const useSleepTimerModal = (player) => {
|
|
|
22
33
|
);
|
|
23
34
|
|
|
24
35
|
useEffect(() => {
|
|
25
|
-
|
|
36
|
+
if (player) {
|
|
37
|
+
setSleepTimerManager(new SleepTimerController(player));
|
|
38
|
+
} else {
|
|
39
|
+
setSleepTimerManager(null);
|
|
40
|
+
}
|
|
26
41
|
}, [player]);
|
|
27
42
|
|
|
28
43
|
useEffect(() => {
|
|
29
44
|
if (playerState?.isLive) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}, [playerState?.isLive, sleepTimerManager]);
|
|
33
|
-
|
|
34
|
-
useEffect(() => {
|
|
35
|
-
if (!sleepTimerManager || playerState.isLive) {
|
|
36
|
-
return;
|
|
45
|
+
// Resetting a sleep timer when audio content is live (Timer not supported on live video)
|
|
46
|
+
sleepTimerManager.setSleepTimer(SLEEP_TIMER_OFF).catch();
|
|
37
47
|
}
|
|
38
|
-
|
|
39
|
-
return registerPlayerActions({ sleepController: sleepTimerManager });
|
|
40
|
-
}, [sleepTimerManager, playerState.isLive]);
|
|
48
|
+
}, [playerState?.isLive]);
|
|
41
49
|
|
|
42
50
|
useEffect(() => {
|
|
43
51
|
if (!playerState.isReadyToPlay) {
|
|
@@ -56,11 +64,40 @@ export const useSleepTimerModal = (player) => {
|
|
|
56
64
|
};
|
|
57
65
|
}, [sleepTimerManager]);
|
|
58
66
|
|
|
67
|
+
const onSleepSelect = useCallback(
|
|
68
|
+
async (item) => {
|
|
69
|
+
await sleepTimerManager?.setSleepTimer(item);
|
|
70
|
+
},
|
|
71
|
+
[sleepTimerManager]
|
|
72
|
+
);
|
|
73
|
+
|
|
59
74
|
const onSleepButtonPress = useCallback(() => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
75
|
+
const timerDate = sleepTimerState.timerDate;
|
|
76
|
+
|
|
77
|
+
const timerRemaining =
|
|
78
|
+
timerDate !== 0 && +timerDate > Date.now() ? timerDate : null;
|
|
79
|
+
|
|
80
|
+
openBottomSheetModal({
|
|
81
|
+
modalBottomSheetContentProps: {
|
|
82
|
+
headerComponent: SleepTimerModalHeader,
|
|
83
|
+
items: getSleepTimerOptions(offLabel, timerRemaining),
|
|
84
|
+
onPress: onSleepSelect,
|
|
85
|
+
title,
|
|
86
|
+
summary: timerRemaining,
|
|
87
|
+
itemProps: getBottomSheetModalItemProps,
|
|
88
|
+
iconProps: getBottomSheetModalIconProps,
|
|
89
|
+
labelProps: getBottomSheetModalLabelProps,
|
|
90
|
+
getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
|
|
91
|
+
},
|
|
92
|
+
options: {
|
|
93
|
+
supportedOrientations: [
|
|
94
|
+
"portrait",
|
|
95
|
+
"landscape",
|
|
96
|
+
"portrait-upside-down",
|
|
97
|
+
],
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}, [sleepTimerState.timerDate, sleepTimerState.timer, title, onSleepSelect]);
|
|
64
101
|
|
|
65
102
|
return useMemo(
|
|
66
103
|
() => ({
|