@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.
@@ -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 = StorageMultiSelectProvider.getProvider(keyNamespace);
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 chaptersObserver?: OverlaysObserver | null;
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.chaptersObserver) {
99
- this.chaptersObserver = new OverlaysObserver({ player: this });
98
+ if (!this.overlaysObserver) {
99
+ this.overlaysObserver = new OverlaysObserver({ player: this });
100
100
  }
101
101
 
102
- return this.chaptersObserver;
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
- [currentTime, duration, seekableDuration, isLive, isPaused, isBuffering]
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.5882013252",
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.5882013252",
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