@applicaster/zapp-react-native-utils 13.0.7-alpha.2991546311 → 13.0.7-alpha.7163853950

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.
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo } from "react";
1
+ import { useEffect, useMemo, useState } from "react";
2
2
  import { AccessibilityManager } from "./index";
3
3
 
4
4
  /**
@@ -38,3 +38,37 @@ export const useAccessibilityManager = (
38
38
 
39
39
  return accessibilityManager;
40
40
  };
41
+
42
+ export const useInitialAnnouncementReady = (
43
+ accessibilityManager: AccessibilityManager
44
+ ) => {
45
+ const [isReady, setIsReady] = useState(
46
+ accessibilityManager.isInitialPlayerAnnouncementReady
47
+ );
48
+
49
+ useEffect(() => {
50
+ const subscription = accessibilityManager
51
+ .getInitialAnnouncementReadyObservable()
52
+ .subscribe(setIsReady);
53
+
54
+ return () => subscription.unsubscribe();
55
+ }, [accessibilityManager]);
56
+
57
+ return isReady;
58
+ };
59
+
60
+ export const useAnnouncementActive = (
61
+ accessibilityManager: AccessibilityManager
62
+ ) => {
63
+ const [isActive, setIsActive] = useState(false);
64
+
65
+ useEffect(() => {
66
+ const subscription = accessibilityManager
67
+ .getTTSStateObservable()
68
+ .subscribe(setIsActive);
69
+
70
+ return () => subscription.unsubscribe();
71
+ }, [accessibilityManager]);
72
+
73
+ return isActive;
74
+ };
@@ -1,3 +1,4 @@
1
+ import * as R from "ramda";
1
2
  import { BehaviorSubject } from "rxjs";
2
3
  import { accessibilityManagerLogger as logger } from "./logger";
3
4
  import { TTSManager } from "../platform/platformUtils";
@@ -30,6 +31,9 @@ export class AccessibilityManager {
30
31
  private currentFocusId: string | null = null;
31
32
  private headingFocusMap: Map<string, string> = new Map();
32
33
  private pendingFocusId: string | null = null;
34
+ private isInitialPlayerAnnouncementReady$ = new BehaviorSubject<boolean>(
35
+ false
36
+ );
33
37
 
34
38
  private constructor() {}
35
39
 
@@ -41,6 +45,26 @@ export class AccessibilityManager {
41
45
  return AccessibilityManager._instance;
42
46
  }
43
47
 
48
+ public get isInitialPlayerAnnouncementReady(): boolean {
49
+ return this.isInitialPlayerAnnouncementReady$.getValue();
50
+ }
51
+
52
+ public setInitialPlayerAnnouncementReady(): void {
53
+ this.isInitialPlayerAnnouncementReady$.next(true);
54
+ }
55
+
56
+ public resetInitialPlayerAnnouncementReady(): void {
57
+ this.isInitialPlayerAnnouncementReady$.next(false);
58
+ }
59
+
60
+ public getInitialAnnouncementReadyObservable() {
61
+ return this.isInitialPlayerAnnouncementReady$.asObservable();
62
+ }
63
+
64
+ public getTTSStateObservable() {
65
+ return this.ttsManager.getStateAsObservable();
66
+ }
67
+
44
68
  /**
45
69
  * The method now accepts any object with localizations using a flattened structure
46
70
  *
@@ -51,7 +75,9 @@ export class AccessibilityManager {
51
75
  * i.e. localizations: [{ en: { accessibility_close_label: "Close", accessibility_close_hint: "Press here to close" } }]
52
76
  */
53
77
  public updateLocalizations(localizations: { [key: string]: string }) {
54
- this.localizations = localizations;
78
+ if (!R.isEmpty(localizations)) {
79
+ this.localizations = localizations;
80
+ }
55
81
  }
56
82
 
57
83
  public getState(): AccessibilityState {
@@ -212,11 +212,16 @@ export class TTSManager {
212
212
  }
213
213
 
214
214
  readText(text: string) {
215
+ this.ttsState$.next(true);
216
+
215
217
  if (isSamsungPlatform() && window.speechSynthesis) {
216
218
  const utterance = new SpeechSynthesisUtterance(text);
217
219
 
218
220
  window.speechSynthesis.cancel(); // Cancel previous speech before speaking new text
219
221
  window.speechSynthesis.speak(utterance);
222
+
223
+ // Estimate reading time and set inactive when done
224
+ this.scheduleTTSComplete(text);
220
225
  }
221
226
 
222
227
  if (isLgPlatform() && window.webOS?.service) {
@@ -227,24 +232,47 @@ export class TTSManager {
227
232
  log_debug("There was a failure setting up webOS TTS service", {
228
233
  error,
229
234
  });
235
+
236
+ this.ttsState$.next(false);
230
237
  },
231
238
  onSuccess(response: any) {
232
239
  log_debug("webOS TTS service is configured successfully", {
233
240
  response,
234
241
  });
242
+
243
+ // Estimate reading time and set inactive when done
244
+ this.scheduleTTSComplete(text);
235
245
  },
236
246
  parameters: {
237
247
  text,
238
- clear: true, // Clear any pending speech before speaking new text
248
+ clear: true, // Clear any previous speech before speaking new text
239
249
  },
240
250
  });
241
251
  } catch (error) {
242
252
  log_debug("webOS TTS service error", { error });
253
+ this.ttsState$.next(false);
243
254
  }
244
255
  }
245
256
 
246
- if (!window.VIZIO?.Chromevox) return;
257
+ if (!window.VIZIO?.Chromevox) {
258
+ // For platforms without TTS, estimate reading time
259
+ this.scheduleTTSComplete(text);
260
+
261
+ return;
262
+ }
247
263
 
248
264
  window.VIZIO.Chromevox.play(text);
265
+ // Estimate reading time and set inactive when done
266
+ this.scheduleTTSComplete(text);
267
+ }
268
+
269
+ private scheduleTTSComplete(text: string) {
270
+ // Estimate reading time based on word count (160 words per minute)
271
+ const words = text.trim().split(/\s+/).length;
272
+ const readingTime = Math.max(500, (words / 160) * 60 * 1000) + 300;
273
+
274
+ setTimeout(() => {
275
+ this.ttsState$.next(false);
276
+ }, readingTime);
249
277
  }
250
278
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "13.0.7-alpha.2991546311",
3
+ "version": "13.0.7-alpha.7163853950",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "13.0.7-alpha.2991546311",
30
+ "@applicaster/applicaster-types": "13.0.7-alpha.7163853950",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -141,6 +141,7 @@ export class PlayerTTS {
141
141
  `${this.secondsToTime(timeRemaining, "standard")} remaining.`
142
142
  );
143
143
 
144
+ this.accessibilityManager.setInitialPlayerAnnouncementReady();
144
145
  this.isInitialPlayerOpen = false;
145
146
  }
146
147
  };
@@ -184,6 +185,19 @@ export class PlayerTTS {
184
185
  this.isSeeking = true;
185
186
  };
186
187
 
188
+ private handlePlayerClose = () => {
189
+ this.isInitialPlayerOpen = true;
190
+ this.accessibilityManager.resetInitialPlayerAnnouncementReady();
191
+ };
192
+
193
+ private announceAdBegin = (event: any) => {
194
+ if (event?.ad?.data?.duration) {
195
+ this.accessibilityManager.readText({
196
+ text: `Sponsored. Ends in ${this.secondsToTime(event.ad.data.duration, "standard")}`,
197
+ });
198
+ }
199
+ };
200
+
187
201
  public init(): () => void {
188
202
  if (!this.player) {
189
203
  return () => {};
@@ -199,6 +213,8 @@ export class PlayerTTS {
199
213
  onVideoProgress: this.handleVideoProgress,
200
214
  onPlayerSeekStart: this.handleSeekStart,
201
215
  onPlayerSeekComplete: this.handleSeekComplete,
216
+ onPlayerClose: this.handlePlayerClose,
217
+ onAdBegin: this.announceAdBegin,
202
218
  },
203
219
  });
204
220
  }
@@ -209,5 +225,6 @@ export class PlayerTTS {
209
225
  }
210
226
 
211
227
  this.seekStartPosition = null;
228
+ this.handlePlayerClose();
212
229
  }
213
230
  }