@applicaster/zapp-react-native-utils 12.0.0-alpha.5882013252 → 12.0.0-alpha.9151207838
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/actionsExecutor/ActionExecutorContext.tsx +5 -5
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +53 -0
- package/appUtils/playerManager/player.ts +12 -4
- package/appUtils/playerManager/playerNative.ts +26 -0
- package/appUtils/playerManager/usePlayerState.tsx +13 -1
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +50 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +8 -0
- package/modalState/index.ts +57 -0
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +8 -0
|
@@ -11,9 +11,7 @@ import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickB
|
|
|
11
11
|
import { showConfirmationDialog } from "../alertUtils";
|
|
12
12
|
import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
|
|
13
13
|
import { createLogger } from "../logger";
|
|
14
|
-
import {
|
|
15
|
-
StorageMultiSelectProvider
|
|
16
|
-
} from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
14
|
+
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
17
15
|
|
|
18
16
|
const { log_error, log_debug, log_info } = createLogger({
|
|
19
17
|
subsystem: "ActionExecutorContext",
|
|
@@ -110,7 +108,8 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
110
108
|
const tag = entry?.extensions?.tag;
|
|
111
109
|
|
|
112
110
|
if (keyNamespace && tag) {
|
|
113
|
-
const multiSelectProvider =
|
|
111
|
+
const multiSelectProvider =
|
|
112
|
+
StorageMultiSelectProvider.getProvider(keyNamespace);
|
|
114
113
|
|
|
115
114
|
const selectedItems = await multiSelectProvider.getSelectedAsync();
|
|
116
115
|
const isTagInSelectedItems = selectedItems.includes(tag);
|
|
@@ -128,7 +127,8 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
return ActionResult.Success;
|
|
131
|
-
}
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
132
|
};
|
|
133
133
|
|
|
134
134
|
export const ActionExecutorContext =
|
|
@@ -41,6 +41,11 @@ export type ChapterMarkerEvent = {
|
|
|
41
41
|
actions: ActionChapter[];
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
+
export type TitleSummaryEvent = {
|
|
45
|
+
title: string | number;
|
|
46
|
+
summary: string | number;
|
|
47
|
+
};
|
|
48
|
+
|
|
44
49
|
type ChapterMarkersObserverProps = {
|
|
45
50
|
player: Player;
|
|
46
51
|
};
|
|
@@ -60,6 +65,11 @@ export type PlayNextState = PlayNextConfig & {
|
|
|
60
65
|
export class OverlaysObserver {
|
|
61
66
|
readonly chapterSubject: BehaviorSubject<ChapterMarkerEvent>;
|
|
62
67
|
private playNextSubject: BehaviorSubject<PlayNextState>;
|
|
68
|
+
private titleSummarySubject: BehaviorSubject<TitleSummaryEvent>;
|
|
69
|
+
private feedUrl: string;
|
|
70
|
+
private reloadData: () => void;
|
|
71
|
+
private updateTitleAndDescription: (data: any) => void;
|
|
72
|
+
private feedDataInterval: any;
|
|
63
73
|
private releasePlayerObserver?: () => void;
|
|
64
74
|
readonly entry: ZappEntry;
|
|
65
75
|
private chapterMarkerEvents: ChapterMarkerEvent[];
|
|
@@ -70,14 +80,55 @@ export class OverlaysObserver {
|
|
|
70
80
|
constructor({ player }: ChapterMarkersObserverProps) {
|
|
71
81
|
this.chapterSubject = new BehaviorSubject(null);
|
|
72
82
|
this.playNextSubject = new BehaviorSubject(null);
|
|
83
|
+
|
|
84
|
+
this.titleSummarySubject = new BehaviorSubject<TitleSummaryEvent>({
|
|
85
|
+
title: player.getEntry()?.title || "",
|
|
86
|
+
summary: player.getEntry()?.summary || "",
|
|
87
|
+
});
|
|
88
|
+
|
|
73
89
|
this.entry = player.getEntry();
|
|
74
90
|
this.player = player;
|
|
75
91
|
|
|
76
92
|
this.chapterMarkerEvents = this.prepareChapterMarkers();
|
|
77
93
|
this.releasePlayerObserver = this.subscribeToPlayerEvents();
|
|
94
|
+
this.feedUrl = "";
|
|
95
|
+
this.reloadData = () => {};
|
|
96
|
+
this.updateTitleAndDescription = () => {};
|
|
97
|
+
this.feedDataInterval = null;
|
|
78
98
|
void this.preparePlayNext();
|
|
79
99
|
}
|
|
80
100
|
|
|
101
|
+
private setupFeedDataInterval(interval: number) {
|
|
102
|
+
if (this.feedUrl && this.reloadData && this.updateTitleAndDescription) {
|
|
103
|
+
this.feedDataInterval = setInterval(() => {
|
|
104
|
+
this.reloadData();
|
|
105
|
+
}, interval * 1000);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public clearFeedDataInterval() {
|
|
110
|
+
if (this.feedDataInterval) {
|
|
111
|
+
clearInterval(this.feedDataInterval);
|
|
112
|
+
this.feedDataInterval = null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public setFeedDataHandlers(
|
|
117
|
+
feedUrl: string,
|
|
118
|
+
reloadData: () => void,
|
|
119
|
+
interval: number,
|
|
120
|
+
updateTitleAndDescription: (data: any) => void
|
|
121
|
+
) {
|
|
122
|
+
this.feedUrl = feedUrl;
|
|
123
|
+
this.reloadData = reloadData;
|
|
124
|
+
this.updateTitleAndDescription = updateTitleAndDescription;
|
|
125
|
+
this.setupFeedDataInterval(interval);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public getTitleSummaryObservable(): Observable<TitleSummaryEvent> {
|
|
129
|
+
return this.titleSummarySubject.asObservable().pipe(distinctUntilChanged());
|
|
130
|
+
}
|
|
131
|
+
|
|
81
132
|
handleUserCancelPlayNext = () => {
|
|
82
133
|
this.isCanceledByUser = true;
|
|
83
134
|
this.playNextSubject.next(null);
|
|
@@ -281,7 +332,9 @@ export class OverlaysObserver {
|
|
|
281
332
|
onPlayerClose = () => {
|
|
282
333
|
this.chapterSubject.complete();
|
|
283
334
|
this.playNextSubject.complete();
|
|
335
|
+
this.titleSummarySubject.complete();
|
|
284
336
|
this.releasePlayerObserver?.();
|
|
337
|
+
this.clearFeedDataInterval();
|
|
285
338
|
this.releasePlayerObserver = null;
|
|
286
339
|
};
|
|
287
340
|
|
|
@@ -42,7 +42,7 @@ export class Player {
|
|
|
42
42
|
|
|
43
43
|
protected startPosition?: number | null;
|
|
44
44
|
readonly playerRole: PlayerRole = PlayerRole.Unspecified;
|
|
45
|
-
private
|
|
45
|
+
private overlaysObserver?: OverlaysObserver | null;
|
|
46
46
|
private entryObservable?: BehaviorSubject<ZappEntry> | null;
|
|
47
47
|
|
|
48
48
|
protected listeners: {
|
|
@@ -95,11 +95,11 @@ export class Player {
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
getOverlayObservable = () => {
|
|
98
|
-
if (!this.
|
|
99
|
-
this.
|
|
98
|
+
if (!this.overlaysObserver) {
|
|
99
|
+
this.overlaysObserver = new OverlaysObserver({ player: this });
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
return this.
|
|
102
|
+
return this.overlaysObserver;
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
getEntryObservable = (): BehaviorSubject<ZappEntry | null> => {
|
|
@@ -278,6 +278,10 @@ export class Player {
|
|
|
278
278
|
return this.playerState.isBuffering;
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
+
isReadyToPlay = (): boolean => {
|
|
282
|
+
return this.playerState.isReadyToPlay;
|
|
283
|
+
};
|
|
284
|
+
|
|
281
285
|
// Methods to call actions on the player
|
|
282
286
|
seekTo = (_position: number) => {};
|
|
283
287
|
|
|
@@ -652,6 +656,10 @@ export class Player {
|
|
|
652
656
|
_selected?: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
|
|
653
657
|
) => {};
|
|
654
658
|
|
|
659
|
+
setPlaybackRate = (_rate) => {};
|
|
660
|
+
startSleepTimer = (_timestamp) => {};
|
|
661
|
+
cancelSleepTimer = () => {};
|
|
662
|
+
|
|
655
663
|
getPluginConfiguration = () => null;
|
|
656
664
|
appStateChange = (_appState, _previousAppState) => {};
|
|
657
665
|
|
|
@@ -41,6 +41,9 @@ const PlayerModuleFuncNames = {
|
|
|
41
41
|
rewind: "rewind",
|
|
42
42
|
play: "play",
|
|
43
43
|
pause: "pause",
|
|
44
|
+
startSleepTimer: "startSleepTimer",
|
|
45
|
+
cancelSleepTimer: "cancelSleepTimer",
|
|
46
|
+
getSleepTimerEnd: "getSleepTimerEnd",
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
export class PlayerNative extends Player {
|
|
@@ -172,6 +175,25 @@ export class PlayerNative extends Player {
|
|
|
172
175
|
}
|
|
173
176
|
};
|
|
174
177
|
|
|
178
|
+
startSleepTimer = (sleepTimestamp: number) => {
|
|
179
|
+
if (
|
|
180
|
+
!this.invokeNativeFunction(
|
|
181
|
+
PlayerModuleFuncNames.startSleepTimer,
|
|
182
|
+
sleepTimestamp
|
|
183
|
+
)
|
|
184
|
+
) {
|
|
185
|
+
this.currentPlayerComponent()?.["startSleepTimer"](sleepTimestamp);
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
cancelSleepTimer = () => {
|
|
190
|
+
if (!this.invokeNativeFunction(PlayerModuleFuncNames.cancelSleepTimer)) {
|
|
191
|
+
this.currentPlayerComponent()?.[
|
|
192
|
+
PlayerModuleFuncNames.cancelSleepTimer
|
|
193
|
+
]?.();
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
175
197
|
disableBufferAnimation = (): boolean => false;
|
|
176
198
|
|
|
177
199
|
setLanguage = (
|
|
@@ -180,6 +202,10 @@ export class PlayerNative extends Player {
|
|
|
180
202
|
this.currentPlayerComponent()?.["setLanguage"]?.(selected);
|
|
181
203
|
};
|
|
182
204
|
|
|
205
|
+
setPlaybackRate = (rate: number) => {
|
|
206
|
+
this.currentPlayerComponent()?.["setPlaybackRate"]?.(rate);
|
|
207
|
+
};
|
|
208
|
+
|
|
183
209
|
getPluginConfiguration = () => {
|
|
184
210
|
return (this.currentPlayerComponent() as any)?.props?.pluginConfiguration;
|
|
185
211
|
};
|
|
@@ -9,6 +9,7 @@ type PlayerState = {
|
|
|
9
9
|
isLive: boolean;
|
|
10
10
|
isPaused: boolean;
|
|
11
11
|
isBuffering: boolean;
|
|
12
|
+
isReadyToPlay: boolean;
|
|
12
13
|
};
|
|
13
14
|
|
|
14
15
|
export const usePlayerState = (
|
|
@@ -20,12 +21,14 @@ export const usePlayerState = (
|
|
|
20
21
|
const [seekableDuration, setSeekableDuration] = React.useState<number>(null);
|
|
21
22
|
const [isLive, setIsLive] = React.useState<boolean>(null);
|
|
22
23
|
const [isBuffering, setIsBuffering] = React.useState<boolean>(false);
|
|
24
|
+
const [isReadyToPlay, setIsReadyToPlay] = React.useState<boolean>(false);
|
|
23
25
|
const [isPaused, setIsPaused] = React.useState<boolean>(false);
|
|
24
26
|
|
|
25
27
|
const player: Player = usePlayer(playerId);
|
|
26
28
|
|
|
27
29
|
const onPlayerChangeState = React.useCallback(() => {
|
|
28
30
|
setIsBuffering(player.isBuffering());
|
|
31
|
+
setIsReadyToPlay(player.isReadyToPlay);
|
|
29
32
|
setCurrentTime(player.getContentPosition());
|
|
30
33
|
setDuration(player.getDuration());
|
|
31
34
|
setSeekableDuration(player.getSeekableDuration());
|
|
@@ -60,7 +63,16 @@ export const usePlayerState = (
|
|
|
60
63
|
isLive,
|
|
61
64
|
isPaused,
|
|
62
65
|
isBuffering,
|
|
66
|
+
isReadyToPlay,
|
|
63
67
|
}),
|
|
64
|
-
[
|
|
68
|
+
[
|
|
69
|
+
currentTime,
|
|
70
|
+
duration,
|
|
71
|
+
seekableDuration,
|
|
72
|
+
isLive,
|
|
73
|
+
isPaused,
|
|
74
|
+
isBuffering,
|
|
75
|
+
isReadyToPlay,
|
|
76
|
+
]
|
|
65
77
|
);
|
|
66
78
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { OverlaysObserver } from "./OverlayObserver/OverlaysObserver";
|
|
3
|
+
import { useFeedLoader } from "../../reactHooks";
|
|
4
|
+
import { usePlayer } from "./usePlayer";
|
|
5
|
+
|
|
6
|
+
export const useTitleSummaryOverlay = (
|
|
7
|
+
feedUrl,
|
|
8
|
+
entry,
|
|
9
|
+
isLive = false,
|
|
10
|
+
interval: number
|
|
11
|
+
) => {
|
|
12
|
+
const player = usePlayer();
|
|
13
|
+
const [title, setTitle] = useState<string | number>(entry?.title || "");
|
|
14
|
+
const [summary, setSummary] = useState<string | number>(entry?.summary || "");
|
|
15
|
+
|
|
16
|
+
// Hook to load feed data
|
|
17
|
+
const { data: feedData, reloadData } = useFeedLoader({ feedUrl });
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (player && feedUrl && isLive) {
|
|
21
|
+
const observer = new OverlaysObserver({ player });
|
|
22
|
+
|
|
23
|
+
observer.setFeedDataHandlers(feedUrl, reloadData, interval, (entry) => {
|
|
24
|
+
setTitle(entry?.title || "");
|
|
25
|
+
setSummary(entry?.summary || "");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const subscription = observer
|
|
29
|
+
.getTitleSummaryObservable()
|
|
30
|
+
.subscribe(({ title, summary }) => {
|
|
31
|
+
setTitle(title);
|
|
32
|
+
setSummary(summary);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
return () => {
|
|
36
|
+
subscription.unsubscribe();
|
|
37
|
+
observer.clearFeedDataInterval();
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}, [player, feedUrl, reloadData, isLive]);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (isLive && feedData?.entry?.[0]) {
|
|
44
|
+
setTitle(feedData.entry[0].title || "");
|
|
45
|
+
setSummary(feedData.entry[0].summary || "");
|
|
46
|
+
}
|
|
47
|
+
}, [feedData]);
|
|
48
|
+
|
|
49
|
+
return { title, summary };
|
|
50
|
+
};
|
|
@@ -41,6 +41,14 @@ function getPlayerConfiguration({ platform }) {
|
|
|
41
41
|
label_tooltip:
|
|
42
42
|
"Enable if you want to have adaptive background gradient based on audio background image.",
|
|
43
43
|
},
|
|
44
|
+
{
|
|
45
|
+
key: "audio_player_background_image_query",
|
|
46
|
+
label: "Audio Player Image Query",
|
|
47
|
+
initial_value: "",
|
|
48
|
+
type: "text_input",
|
|
49
|
+
label_tooltip:
|
|
50
|
+
"Set the query params which control the size of the image e.g width, height. This will help to optimize the loading time, when magic background is enabled.",
|
|
51
|
+
},
|
|
44
52
|
],
|
|
45
53
|
};
|
|
46
54
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { create } from "zustand";
|
|
2
|
+
|
|
3
|
+
interface ModalState {
|
|
4
|
+
visible: boolean;
|
|
5
|
+
screen: any;
|
|
6
|
+
options: Record<string, unknown>;
|
|
7
|
+
props: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface ModalStore {
|
|
11
|
+
modalState: ModalState;
|
|
12
|
+
setModalState: (newState: Partial<ModalState>) => void;
|
|
13
|
+
openModal: (
|
|
14
|
+
item: any,
|
|
15
|
+
options?: Record<string, unknown>,
|
|
16
|
+
props?: Record<string, unknown>
|
|
17
|
+
) => void;
|
|
18
|
+
dismissModal: () => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const initialModalState: ModalState = {
|
|
22
|
+
visible: false,
|
|
23
|
+
screen: null,
|
|
24
|
+
options: {},
|
|
25
|
+
props: {},
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const useModalStore = create<ModalStore>((set) => ({
|
|
29
|
+
modalState: initialModalState,
|
|
30
|
+
setModalState: (newState) =>
|
|
31
|
+
set((state) => ({
|
|
32
|
+
modalState: { ...state.modalState, ...newState },
|
|
33
|
+
})),
|
|
34
|
+
openModal: ({
|
|
35
|
+
item,
|
|
36
|
+
options = {},
|
|
37
|
+
props = { screenData: {} },
|
|
38
|
+
}: OpenModalArg) =>
|
|
39
|
+
set({
|
|
40
|
+
modalState: {
|
|
41
|
+
visible: true,
|
|
42
|
+
screen: item,
|
|
43
|
+
options: {
|
|
44
|
+
animated: true,
|
|
45
|
+
animationType: "slide",
|
|
46
|
+
onShow: () => {},
|
|
47
|
+
presentationStyle: "overFullScreen",
|
|
48
|
+
transparent: true,
|
|
49
|
+
...options,
|
|
50
|
+
onDismiss: () => set({ modalState: initialModalState }),
|
|
51
|
+
onRequestClose: () => set({ modalState: initialModalState }),
|
|
52
|
+
},
|
|
53
|
+
props,
|
|
54
|
+
},
|
|
55
|
+
}),
|
|
56
|
+
dismissModal: () => set(() => ({ modalState: initialModalState })),
|
|
57
|
+
}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.9151207838",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.9151207838",
|
|
32
32
|
"buffer": "^5.2.1",
|
|
33
33
|
"camelize": "^1.0.0",
|
|
34
34
|
"create-react-context": "^0.2.3",
|
|
@@ -46,6 +46,14 @@ function getPlayerConfiguration({ platform }) {
|
|
|
46
46
|
label_tooltip:
|
|
47
47
|
"Enable if you want to have adaptive background gradient based on audio background image.",
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
key: "audio_player_background_image_query",
|
|
51
|
+
label: "Audio Player Image Query",
|
|
52
|
+
initial_value: "",
|
|
53
|
+
type: "text_input",
|
|
54
|
+
label_tooltip:
|
|
55
|
+
"Set the query params which control the size of the image e.g width, height. This will help to optimize the loading time, when magic background is enabled.",
|
|
56
|
+
},
|
|
49
57
|
],
|
|
50
58
|
};
|
|
51
59
|
|