@applicaster/zapp-react-native-utils 12.0.0-alpha.5471145113 → 12.0.0-alpha.5522474195

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.
@@ -206,7 +206,7 @@ export function getTargetInDirection(
206
206
  const overrideTarget = currentNode?.component?.props[overridePropName];
207
207
 
208
208
  if (overrideTarget) {
209
- const target = targetNodes.find((n) => n.id === overrideTarget);
209
+ const target = targetNodes.find((n) => n?.id === overrideTarget);
210
210
 
211
211
  if (target) return target;
212
212
  }
@@ -16,3 +16,10 @@ export const PLATFORMS = {
16
16
  smartcast: "SmartCast",
17
17
  conjure: "Conjure",
18
18
  };
19
+
20
+ /**
21
+ * Keys used to store the platform / device state in the session storage
22
+ */
23
+ export const PLATFORM_KEYS = {
24
+ deviceClosedCaptioningEnabled: "device_closed_captioning_enabled",
25
+ };
@@ -1 +1,3 @@
1
1
  export * from "./platformUtils";
2
+
3
+ export * from "./const";
@@ -1 +1,223 @@
1
- export {};
1
+ import { BehaviorSubject } from "rxjs";
2
+
3
+ import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
4
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
5
+ import { PlayerWebController } from "@applicaster/zapp-react-native-default-player/src/playerFactory/players/playerWebController";
6
+
7
+ import { PLATFORM_KEYS, PLATFORMS } from "./const";
8
+ import { createLogger, utilsLogger } from "../../logger";
9
+
10
+ declare global {
11
+ interface Window {
12
+ VIZIO?: {
13
+ exitApplication: () => void;
14
+ setClosedCaptionHandler: (
15
+ callback: (isCCEnabled: boolean) => void
16
+ ) => void;
17
+ };
18
+ }
19
+ }
20
+
21
+ const { log_debug, log_error } = createLogger({
22
+ category: "General",
23
+ subsystem: "PlatformUtils",
24
+ parent: utilsLogger,
25
+ });
26
+
27
+ export const getUserAgent = () =>
28
+ window?.navigator?.userAgent || global?.navigator?.userAgent;
29
+
30
+ /** VIZIO UTILS */
31
+
32
+ /**
33
+ * Checks if we are on the Vizio platform by using the userAgent string
34
+ *
35
+ * Use this method when you need to identify the platform on runtime
36
+ * before the VIZIO Companion Library has loaded
37
+ */
38
+ export const isVizioPlatform = () => {
39
+ const userAgent = getUserAgent();
40
+
41
+ const isVizioAgent =
42
+ userAgent.includes(PLATFORMS.vizio) ||
43
+ userAgent.includes(PLATFORMS.smartcast) ||
44
+ userAgent.includes(PLATFORMS.conjure);
45
+
46
+ return isVizioAgent;
47
+ };
48
+
49
+ /**
50
+ * Checks if we are on the Vizio platform by checking for the global VIZIO object
51
+ * and the VIZIO Companion Library. This method does not use the userAgent string,
52
+ * because it mainly checks whether we have access to apis, which may not be available yet
53
+ */
54
+ export const hasVizioAPIs = () => {
55
+ const hasAPIs =
56
+ typeof window.VIZIO !== "undefined" &&
57
+ window?.applicaster?.vizioLibraryDidLoad;
58
+
59
+ return hasAPIs;
60
+ };
61
+
62
+ /**
63
+ * Manages device based closed captioning state
64
+ * Returns an observable that emits the current state and updates whenever it changes
65
+ */
66
+ class ClosedCaptioningManager {
67
+ private ccState$ = new BehaviorSubject<boolean>(false);
68
+ private static ccManagerInstance: ClosedCaptioningManager;
69
+
70
+ private constructor() {
71
+ this.initialize();
72
+ }
73
+
74
+ static getInstance(): ClosedCaptioningManager {
75
+ if (!ClosedCaptioningManager.ccManagerInstance) {
76
+ ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
77
+ }
78
+
79
+ return ClosedCaptioningManager.ccManagerInstance;
80
+ }
81
+
82
+ async initialize() {
83
+ const existingState = await sessionStorage.getItem(
84
+ PLATFORM_KEYS.deviceClosedCaptioningEnabled
85
+ );
86
+
87
+ log_debug("Initializing closed captioning manager", { existingState });
88
+
89
+ if (existingState !== null) {
90
+ this.ccState$.next(existingState === "true" || existingState === true);
91
+ }
92
+
93
+ if (hasVizioAPIs()) {
94
+ window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
95
+ log_debug("CC state changed", { isCCEnabled });
96
+
97
+ sessionStorage.setItem(
98
+ PLATFORM_KEYS.deviceClosedCaptioningEnabled,
99
+ isCCEnabled
100
+ );
101
+
102
+ this.ccState$.next(isCCEnabled);
103
+ });
104
+ }
105
+ }
106
+
107
+ getCurrentState(): boolean {
108
+ return this.ccState$.getValue();
109
+ }
110
+
111
+ getStateAsObservable() {
112
+ return this.ccState$.asObservable();
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Subscribe to closed captioning state changes
118
+ * @returns Observable<boolean>
119
+ * @example
120
+ * const subscription = getClosedCaptionState().subscribe(
121
+ * isEnabled => setClosedCaptionState(isEnabled)
122
+ * );
123
+ * subscription.unsubscribe(), []);
124
+ */
125
+ export const getClosedCaptionState = () => {
126
+ const ccManager = ClosedCaptioningManager.getInstance();
127
+
128
+ return ccManager.getStateAsObservable();
129
+ };
130
+
131
+ export class TextTrackManager {
132
+ private controller?: PlayerWebController;
133
+ private static instance: TextTrackManager;
134
+
135
+ private constructor() {}
136
+
137
+ static getInstance(): TextTrackManager {
138
+ if (!TextTrackManager.instance) {
139
+ TextTrackManager.instance = new TextTrackManager();
140
+ }
141
+
142
+ return TextTrackManager.instance;
143
+ }
144
+
145
+ initialize(controller: PlayerWebController) {
146
+ if (!controller) {
147
+ throw new Error(
148
+ "Controller is required for TextTrackManager initialization"
149
+ );
150
+ }
151
+
152
+ this.controller = controller;
153
+ }
154
+
155
+ async setTextTrackBasedOnCaptions(closedCaptionsState: boolean) {
156
+ if (!this.controller) {
157
+ log_error("Controller is not initialized");
158
+
159
+ return;
160
+ }
161
+
162
+ if (closedCaptionsState) {
163
+ const textTracks = this.controller.getTracksState().textTracks;
164
+ const preferredTextTrack = await this.getPreferredTextTrack(textTracks);
165
+
166
+ if (preferredTextTrack) {
167
+ this.controller.selectTrack(preferredTextTrack);
168
+ }
169
+ } else {
170
+ this.controller.selectTrack(null);
171
+ }
172
+ }
173
+
174
+ async getPreferredTextTrack(
175
+ textTracks: QuickBrickPlayer.TextTrack[]
176
+ ): Promise<QuickBrickPlayer.TextTrack | undefined> {
177
+ if (!this.controller) return;
178
+
179
+ const userPreferredTextLanguageLocalStorage = await localStorage.getItem(
180
+ "preferred_text_language",
181
+ "user_preferences"
182
+ );
183
+
184
+ let userPreferredTextLanguage;
185
+
186
+ if (userPreferredTextLanguageLocalStorage) {
187
+ userPreferredTextLanguage = textTracks.find(
188
+ (track) => track.language === userPreferredTextLanguageLocalStorage
189
+ );
190
+ }
191
+
192
+ if (userPreferredTextLanguage?.id) {
193
+ return userPreferredTextLanguage;
194
+ }
195
+
196
+ const enableAutoTextTrackSelection =
197
+ this.controller.getPluginConfiguration()
198
+ ?.enable_auto_text_track_selection ||
199
+ this.controller.getTracksState().textTracks.length > 0;
200
+
201
+ if (enableAutoTextTrackSelection) {
202
+ const languageCode = await sessionStorage.getItem("languageCode");
203
+
204
+ if (languageCode) {
205
+ const chosenTextTrackBySystemLanguage = textTracks.find(
206
+ (track) => track.language === languageCode
207
+ );
208
+
209
+ if (chosenTextTrackBySystemLanguage?.id) {
210
+ return chosenTextTrackBySystemLanguage;
211
+ }
212
+ }
213
+ }
214
+
215
+ return textTracks?.[0];
216
+ }
217
+
218
+ isTextTrackEnabled(): boolean {
219
+ if (!this.controller) return false;
220
+
221
+ return this.controller.getTracksState().textTrackId !== null;
222
+ }
223
+ }
@@ -7,6 +7,7 @@ export enum SharedPlayerCallBacksKeys {
7
7
  OnPlayerPause = "onPlayerPause",
8
8
  OnLoad = "onLoad",
9
9
  OnError = "onError",
10
+ OnVideoError = "onVideoError",
10
11
  OnVideoEnd = "onVideoEnd",
11
12
  OnPlaybackRateChange = "onPlaybackRateChange",
12
13
  OnVideoLoad = "onVideoLoad",
@@ -366,9 +366,9 @@ export class PlayerManager {
366
366
  // TODO: Remove
367
367
  if (this.castingReceiver) {
368
368
  this.castingReceiver.rewind(deltaTime);
369
+ } else {
370
+ this.getActivePlayer()?.rewind(deltaTime);
369
371
  }
370
-
371
- this.getActivePlayer()?.rewind(deltaTime);
372
372
  }
373
373
 
374
374
  public forward(deltaTime = null) {
@@ -376,9 +376,9 @@ export class PlayerManager {
376
376
 
377
377
  if (this.castingReceiver) {
378
378
  this.castingReceiver.forward(deltaTime);
379
+ } else {
380
+ this.getActivePlayer()?.forward(deltaTime);
379
381
  }
380
-
381
- this.getActivePlayer()?.forward(deltaTime);
382
382
  }
383
383
 
384
384
  public seeking(time) {
@@ -441,7 +441,7 @@ export class PlayerManager {
441
441
  }
442
442
 
443
443
  // Call method on player just in case
444
- return this.getActivePlayer()?.setLanguage(track);
444
+ return this.getActivePlayer()?.selectTrack(track);
445
445
  }
446
446
 
447
447
  public isRegistered() {
@@ -359,6 +359,13 @@ export class Player {
359
359
  });
360
360
  };
361
361
 
362
+ onVideoError = (error: Error) => {
363
+ this.invokeListenersUpdate({
364
+ callbackName: SharedPlayerCallBacksKeys.OnVideoError,
365
+ event: error,
366
+ });
367
+ };
368
+
362
369
  onError = (error: Error) => {
363
370
  this.invokeListenersUpdate({
364
371
  callbackName: SharedPlayerCallBacksKeys.OnError,
@@ -650,6 +657,7 @@ export class Player {
650
657
  onPlayerSeekComplete: this.onSeekComplete,
651
658
  onVideoEnd: this.onVideoEnd,
652
659
  onError: this.onError,
660
+ onVideoError: this.onVideoError,
653
661
  onLoad: this.onLoad,
654
662
  onPlayerPause: this.onPlayerPause,
655
663
  onPlayerResume: this.onPlayerResume,
@@ -684,9 +692,6 @@ export class Player {
684
692
  play = () => {};
685
693
  pause = () => {};
686
694
  disableBufferAnimation = (): boolean => true;
687
- setLanguage = (
688
- _selected?: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
689
- ) => {};
690
695
 
691
696
  setPlaybackRate = (_rate) => {};
692
697
  startSleepTimer = (_timestamp) => {};
@@ -188,10 +188,10 @@ export class PlayerNative extends Player {
188
188
 
189
189
  disableBufferAnimation = (): boolean => false;
190
190
 
191
- setLanguage = (
191
+ selectTrack = (
192
192
  selected: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
193
193
  ) => {
194
- this.currentPlayerComponent()?.["setLanguage"]?.(selected);
194
+ this.currentPlayerComponent()?.["selectTrack"]?.(selected);
195
195
  };
196
196
 
197
197
  setPlaybackRate = (rate: number) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "12.0.0-alpha.5471145113",
3
+ "version": "12.0.0-alpha.5522474195",
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.5471145113",
31
+ "@applicaster/applicaster-types": "12.0.0-alpha.5522474195",
32
32
  "buffer": "^5.2.1",
33
33
  "camelize": "^1.0.0",
34
34
  "create-react-context": "^0.2.3",
@@ -1,8 +0,0 @@
1
- export const FOCUSABLE_EVENTS = {
2
- IS_REGISTERED: "isRegistered",
3
- WILL_RECEIVE_FOCUS: "willReceiveFocus",
4
- HAS_RECEIVED_FOCUS: "hasReceivedFocus",
5
- WILL_LOSE_FOCUS: "willLoseFocus",
6
- HAS_LOST_FOCUS: "hasLostFocus",
7
- WILL_UNREGISTER: "willUnregister",
8
- };