@applicaster/zapp-react-native-utils 12.0.0-alpha.3977160850 → 12.0.0-alpha.4195481103

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.
Files changed (90) hide show
  1. package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
  2. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  3. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  4. package/analyticsUtils/analyticsPlugins.ts +25 -0
  5. package/analyticsUtils/events.ts +12 -0
  6. package/analyticsUtils/index.tsx +12 -0
  7. package/appUtils/HooksManager/index.js +3 -1
  8. package/appUtils/accessibilityManager/const.ts +50 -0
  9. package/appUtils/accessibilityManager/hooks.ts +31 -0
  10. package/appUtils/accessibilityManager/index.ts +150 -0
  11. package/appUtils/accessibilityManager/logger.ts +5 -0
  12. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  13. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  14. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  15. package/appUtils/focusManager/index.ts +76 -57
  16. package/appUtils/focusManager/treeDataStructure/Utils/index.js +75 -35
  17. package/appUtils/focusManager/utils/index.ts +100 -0
  18. package/appUtils/focusManagerAux/index.ts +76 -0
  19. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  20. package/appUtils/index.js +2 -0
  21. package/appUtils/keyCodes/keys.web.js +8 -0
  22. package/appUtils/keyCodes/keysByPlatform.js +11 -1
  23. package/appUtils/platform/const.ts +25 -0
  24. package/appUtils/platform/index.ts +3 -0
  25. package/appUtils/platform/platformUtils.ts +281 -0
  26. package/appUtils/playerManager/conts.ts +6 -0
  27. package/appUtils/playerManager/index.ts +11 -5
  28. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  29. package/appUtils/playerManager/player.ts +43 -3
  30. package/appUtils/playerManager/playerFactory.ts +12 -10
  31. package/appUtils/playerManager/playerNative.ts +14 -14
  32. package/appUtils/playerManager/usePlayerControllerSetup.tsx +6 -1
  33. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  34. package/arrayUtils/index.ts +5 -0
  35. package/booleanUtils/index.ts +4 -4
  36. package/cellUtils/__tests__/cellUtils.test.ts +9 -20
  37. package/cellUtils/index.ts +10 -14
  38. package/dateUtils/index.ts +11 -0
  39. package/headersUtils/index.ts +1 -0
  40. package/inflatedUrlUtils/index.ts +4 -4
  41. package/keyboardState/index.ts +0 -0
  42. package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
  43. package/localizationUtils/index.ts +13 -22
  44. package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
  45. package/manifestUtils/defaultManifestConfigurations/player.js +2 -1
  46. package/manifestUtils/index.js +5 -1
  47. package/manifestUtils/secondaryImage/index.js +18 -15
  48. package/navigationUtils/index.ts +8 -4
  49. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  50. package/numberUtils/index.ts +9 -18
  51. package/package.json +2 -2
  52. package/playerUtils/configurationGenerator.ts +3 -1
  53. package/pluginUtils/index.ts +9 -0
  54. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
  55. package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
  56. package/reactHooks/cell-click/__tests__/index.test.js +10 -1
  57. package/reactHooks/cell-click/index.ts +12 -12
  58. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  59. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  60. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  61. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  62. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  63. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  64. package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +44 -29
  65. package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
  66. package/reactHooks/layout/types/index.ts +2 -0
  67. package/reactHooks/layout/useDimensions/useDimensions.ts +13 -7
  68. package/reactHooks/navigation/__mocks__/index.ts +15 -0
  69. package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
  70. package/reactHooks/navigation/__tests__/index.test.tsx +26 -8
  71. package/reactHooks/navigation/index.ts +64 -21
  72. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
  73. package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
  74. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  75. package/reactHooks/screen/index.ts +2 -0
  76. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  77. package/reactHooks/screen/useScreenContext.ts +4 -4
  78. package/reactHooks/screen/useScreenData.ts +1 -1
  79. package/reactHooks/screen/useTargetScreenData.ts +7 -0
  80. package/reactHooks/useListenEventBusEvent.ts +1 -4
  81. package/reactHooks/videoModal/index.ts +0 -3
  82. package/reactUtils/index.ts +105 -0
  83. package/screenState/index.ts +0 -8
  84. package/stringUtils/index.ts +5 -0
  85. package/testUtils/getByTestId.ts +14 -0
  86. package/testUtils/index.tsx +38 -23
  87. package/types.ts +4 -0
  88. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  89. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  90. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
@@ -0,0 +1,3 @@
1
+ export * from "./platformUtils";
2
+
3
+ export * from "./const";
@@ -0,0 +1,281 @@
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
+ Chromevox: {
15
+ play: (text: string) => void;
16
+ };
17
+ setClosedCaptionHandler: (
18
+ callback: (isCCEnabled: boolean) => void
19
+ ) => void;
20
+ };
21
+ }
22
+ }
23
+
24
+ const { log_debug, log_error } = createLogger({
25
+ category: "General",
26
+ subsystem: "PlatformUtils",
27
+ parent: utilsLogger,
28
+ });
29
+
30
+ export const getUserAgent = () =>
31
+ window?.navigator?.userAgent || global?.navigator?.userAgent;
32
+
33
+ /** VIZIO UTILS */
34
+
35
+ /**
36
+ * Checks if we are on the Vizio platform by using the userAgent string
37
+ *
38
+ * Use this method when you need to identify the platform on runtime
39
+ * before the VIZIO Companion Library has loaded
40
+ */
41
+ export const isVizioPlatform = () => {
42
+ const userAgent = getUserAgent();
43
+
44
+ const isVizioAgent =
45
+ userAgent.includes(PLATFORMS.vizio) ||
46
+ userAgent.includes(PLATFORMS.smartcast) ||
47
+ userAgent.includes(PLATFORMS.conjure);
48
+
49
+ return isVizioAgent;
50
+ };
51
+
52
+ /**
53
+ * Checks if we are on the Vizio platform by checking for the global VIZIO object
54
+ * and the VIZIO Companion Library. This method does not use the userAgent string,
55
+ * because it mainly checks whether we have access to apis, which may not be available yet
56
+ */
57
+ export const hasVizioAPIs = () => {
58
+ const hasAPIs =
59
+ typeof window.VIZIO !== "undefined" &&
60
+ window?.applicaster?.vizioLibraryDidLoad;
61
+
62
+ return hasAPIs;
63
+ };
64
+
65
+ /**
66
+ * Manages device based closed captioning state
67
+ * Returns an observable that emits the current state and updates whenever it changes
68
+ */
69
+ export class ClosedCaptioningManager {
70
+ private ccState$ = new BehaviorSubject<boolean>(false);
71
+ private static ccManagerInstance: ClosedCaptioningManager;
72
+
73
+ private constructor() {
74
+ this.initialize();
75
+ }
76
+
77
+ static getInstance(): ClosedCaptioningManager {
78
+ if (!ClosedCaptioningManager.ccManagerInstance) {
79
+ ClosedCaptioningManager.ccManagerInstance = new ClosedCaptioningManager();
80
+ }
81
+
82
+ return ClosedCaptioningManager.ccManagerInstance;
83
+ }
84
+
85
+ async initialize() {
86
+ const existingState = await sessionStorage.getItem(
87
+ PLATFORM_KEYS.deviceClosedCaptioningEnabled
88
+ );
89
+
90
+ log_debug("Initializing closed captioning manager", { existingState });
91
+
92
+ if (existingState !== null) {
93
+ this.ccState$.next(existingState === "true" || existingState === true);
94
+ }
95
+
96
+ if (hasVizioAPIs()) {
97
+ window.VIZIO!.setClosedCaptionHandler((isCCEnabled) => {
98
+ log_debug("CC state changed", { isCCEnabled });
99
+
100
+ sessionStorage.setItem(
101
+ PLATFORM_KEYS.deviceClosedCaptioningEnabled,
102
+ isCCEnabled
103
+ );
104
+
105
+ this.ccState$.next(isCCEnabled);
106
+ });
107
+ }
108
+ }
109
+
110
+ getCurrentState(): boolean {
111
+ return this.ccState$.getValue();
112
+ }
113
+
114
+ getStateAsObservable() {
115
+ return this.ccState$.asObservable();
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Subscribe to closed captioning state changes
121
+ * @returns Observable<boolean>
122
+ * @example
123
+ * const subscription = getClosedCaptionState().subscribe(
124
+ * isEnabled => setClosedCaptionState(isEnabled)
125
+ * );
126
+ * subscription.unsubscribe(), []);
127
+ */
128
+ export const getClosedCaptionState = () => {
129
+ const ccManager = ClosedCaptioningManager.getInstance();
130
+
131
+ return ccManager.getStateAsObservable();
132
+ };
133
+
134
+ export class TextTrackManager {
135
+ private controller?: PlayerWebController;
136
+ private static instance: TextTrackManager;
137
+
138
+ private constructor() {}
139
+
140
+ static getInstance(): TextTrackManager {
141
+ if (!TextTrackManager.instance) {
142
+ TextTrackManager.instance = new TextTrackManager();
143
+ }
144
+
145
+ return TextTrackManager.instance;
146
+ }
147
+
148
+ initialize(controller: PlayerWebController) {
149
+ if (!controller) {
150
+ throw new Error(
151
+ "Controller is required for TextTrackManager initialization"
152
+ );
153
+ }
154
+
155
+ this.controller = controller;
156
+ }
157
+
158
+ async setTextTrackBasedOnCaptions(closedCaptionsState: boolean) {
159
+ if (!this.controller) {
160
+ log_error("Controller is not initialized");
161
+
162
+ return;
163
+ }
164
+
165
+ if (closedCaptionsState) {
166
+ const textTracks = this.controller.getTracksState().textTracks;
167
+ const preferredTextTrack = await this.getPreferredTextTrack(textTracks);
168
+
169
+ if (preferredTextTrack) {
170
+ this.controller.selectTrack(preferredTextTrack);
171
+ }
172
+ } else {
173
+ this.controller.selectTrack(null);
174
+ }
175
+ }
176
+
177
+ async getPreferredTextTrack(
178
+ textTracks: QuickBrickPlayer.TextTrack[]
179
+ ): Promise<QuickBrickPlayer.TextTrack | undefined> {
180
+ if (!this.controller) return;
181
+
182
+ const userPreferredTextLanguageLocalStorage = await localStorage.getItem(
183
+ "preferred_text_language",
184
+ "user_preferences"
185
+ );
186
+
187
+ let userPreferredTextLanguage;
188
+
189
+ if (userPreferredTextLanguageLocalStorage) {
190
+ userPreferredTextLanguage = textTracks.find(
191
+ (track) => track.language === userPreferredTextLanguageLocalStorage
192
+ );
193
+ }
194
+
195
+ if (userPreferredTextLanguage?.id) {
196
+ return userPreferredTextLanguage;
197
+ }
198
+
199
+ const enableAutoTextTrackSelection =
200
+ this.controller.getPluginConfiguration()
201
+ ?.enable_auto_text_track_selection ||
202
+ this.controller.getTracksState().textTracks.length > 0;
203
+
204
+ if (enableAutoTextTrackSelection) {
205
+ const languageCode = await sessionStorage.getItem("languageCode");
206
+
207
+ if (languageCode) {
208
+ const chosenTextTrackBySystemLanguage = textTracks.find(
209
+ (track) => track.language === languageCode
210
+ );
211
+
212
+ if (chosenTextTrackBySystemLanguage?.id) {
213
+ return chosenTextTrackBySystemLanguage;
214
+ }
215
+ }
216
+ }
217
+
218
+ return textTracks?.[0];
219
+ }
220
+
221
+ isTextTrackEnabled(): boolean {
222
+ if (!this.controller) return false;
223
+
224
+ return this.controller.getTracksState().textTrackId !== null;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Manages device based closed captioning state
230
+ * Returns an observable that emits the current state and updates whenever it changes
231
+ */
232
+ export class TTSManager {
233
+ private ttsState$ = new BehaviorSubject<boolean>(false);
234
+ private static ttsManagerInstance: TTSManager;
235
+
236
+ private constructor() {
237
+ this.initialize();
238
+ }
239
+
240
+ static getInstance(): TTSManager {
241
+ if (!TTSManager.ttsManagerInstance) {
242
+ TTSManager.ttsManagerInstance = new TTSManager();
243
+ }
244
+
245
+ return TTSManager.ttsManagerInstance;
246
+ }
247
+
248
+ async initialize() {
249
+ if (!isVizioPlatform()) return;
250
+
251
+ document.addEventListener(
252
+ "VIZIO_TTS_ENABLED",
253
+ () => {
254
+ this.ttsState$.next(true);
255
+ },
256
+ false
257
+ );
258
+
259
+ document.addEventListener(
260
+ "VIZIO_TTS_DISABLED",
261
+ () => {
262
+ this.ttsState$.next(false);
263
+ },
264
+ false
265
+ );
266
+ }
267
+
268
+ getCurrentState(): boolean {
269
+ return this.ttsState$.getValue();
270
+ }
271
+
272
+ getStateAsObservable() {
273
+ return this.ttsState$.asObservable();
274
+ }
275
+
276
+ readText(text: string) {
277
+ if (!window.VIZIO?.Chromevox) return;
278
+
279
+ window.VIZIO.Chromevox.play(text);
280
+ }
281
+ }
@@ -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",
@@ -20,6 +21,11 @@ export enum SharedPlayerCallBacksKeys {
20
21
  OnPlayerMute = "onPlayerMute",
21
22
  OnPlayerUnmute = "onPlayerUnmute",
22
23
 
24
+ onVideoFullscreenPlayerDidDismiss = "onVideoFullscreenPlayerDidDismiss",
25
+ onVideoFullscreenPlayerDidPresent = "onVideoFullscreenPlayerDidPresent",
26
+ onVideoFullscreenPlayerWillDismiss = "onVideoFullscreenPlayerWillDismiss",
27
+ onVideoFullscreenPlayerWillPresent = "onVideoFullscreenPlayerWillPresent",
28
+
23
29
  OnAdBegin = "onAdBegin",
24
30
  OnAdBreakBegin = "onAdBreakBegin",
25
31
  OnAdBreakEnd = "onAdBreakEnd",
@@ -11,6 +11,7 @@ import {
11
11
  } from "@applicaster/quick-brick-core/App/NetworkStatusProvider/utils";
12
12
  import { setUserLanguagePreference } from "./userLanguagePreference";
13
13
  import { PlayerRole } from "./conts";
14
+ import { RNPlayerManager } from "./nativePlayerManager";
14
15
 
15
16
  const { log_error, log_debug, log_warning } = createLogger({
16
17
  category: "General",
@@ -164,6 +165,10 @@ export class PlayerManager {
164
165
  this.addPlayer(id, playerController);
165
166
 
166
167
  if (playerController.playerRole === PlayerRole.Primary) {
168
+ if (playerController.playerPluginId !== "QuickBrickPlayerPlugin") {
169
+ RNPlayerManager?.["QuickBrickPlayerPlugin"]?.stopBackgroundPlayback?.();
170
+ }
171
+
167
172
  playerController.addListener({
168
173
  id: this.getPlayerListenerId(id),
169
174
  listener: {
@@ -361,9 +366,9 @@ export class PlayerManager {
361
366
  // TODO: Remove
362
367
  if (this.castingReceiver) {
363
368
  this.castingReceiver.rewind(deltaTime);
369
+ } else {
370
+ this.getActivePlayer()?.rewind(deltaTime);
364
371
  }
365
-
366
- this.getActivePlayer()?.rewind(deltaTime);
367
372
  }
368
373
 
369
374
  public forward(deltaTime = null) {
@@ -371,9 +376,9 @@ export class PlayerManager {
371
376
 
372
377
  if (this.castingReceiver) {
373
378
  this.castingReceiver.forward(deltaTime);
379
+ } else {
380
+ this.getActivePlayer()?.forward(deltaTime);
374
381
  }
375
-
376
- this.getActivePlayer()?.forward(deltaTime);
377
382
  }
378
383
 
379
384
  public seeking(time) {
@@ -436,7 +441,7 @@ export class PlayerManager {
436
441
  }
437
442
 
438
443
  // Call method on player just in case
439
- return this.getActivePlayer()?.setLanguage(track);
444
+ return this.getActivePlayer()?.selectTrack(track);
440
445
  }
441
446
 
442
447
  public isRegistered() {
@@ -461,6 +466,7 @@ export class PlayerManager {
461
466
  if (this.castingReceiver) {
462
467
  this.castingReceiver.closeNativePlayer();
463
468
  } else {
469
+ this.getActivePlayer().closeNativePlayer();
464
470
  this.invokeHandler("close");
465
471
  }
466
472
  }
@@ -0,0 +1,12 @@
1
+ import { NativeModules } from "react-native";
2
+ import { isApplePlatform } from "../../reactUtils";
3
+
4
+ export const RNPlayerManager = {
5
+ QuickBrickPlayerPlugin: isApplePlatform()
6
+ ? NativeModules.PlayerModule
7
+ : NativeModules.QuickBrickDefaultPlayerModule,
8
+ KalturaPlayerPlugin: isApplePlatform()
9
+ ? NativeModules.KalturaPlayerModule
10
+ : NativeModules.QBKalturaPlayerModule,
11
+ "quick-brick-player-brightcove": NativeModules.BrightcovePlayerModule,
12
+ };
@@ -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,
@@ -414,6 +421,32 @@ export class Player {
414
421
  });
415
422
  };
416
423
 
424
+ onVideoFullscreenPlayerWillDismiss = () => {
425
+ this.invokeListenersUpdate({
426
+ callbackName:
427
+ SharedPlayerCallBacksKeys.onVideoFullscreenPlayerWillDismiss,
428
+ });
429
+ };
430
+
431
+ onVideoFullscreenPlayerDidDismiss = () => {
432
+ this.invokeListenersUpdate({
433
+ callbackName: SharedPlayerCallBacksKeys.onVideoFullscreenPlayerDidDismiss,
434
+ });
435
+ };
436
+
437
+ onVideoFullscreenPlayerWillPresent = () => {
438
+ this.invokeListenersUpdate({
439
+ callbackName:
440
+ SharedPlayerCallBacksKeys.onVideoFullscreenPlayerWillPresent,
441
+ });
442
+ };
443
+
444
+ onVideoFullscreenPlayerDidPresent = () => {
445
+ this.invokeListenersUpdate({
446
+ callbackName: SharedPlayerCallBacksKeys.onVideoFullscreenPlayerDidPresent,
447
+ });
448
+ };
449
+
417
450
  public invokeListenersUpdate = ({
418
451
  callbackName,
419
452
  event = {},
@@ -624,6 +657,7 @@ export class Player {
624
657
  onPlayerSeekComplete: this.onSeekComplete,
625
658
  onVideoEnd: this.onVideoEnd,
626
659
  onError: this.onError,
660
+ onVideoError: this.onVideoError,
627
661
  onLoad: this.onLoad,
628
662
  onPlayerPause: this.onPlayerPause,
629
663
  onPlayerResume: this.onPlayerResume,
@@ -634,6 +668,12 @@ export class Player {
634
668
  onBufferStart: this.onBufferStart,
635
669
  onBufferComplete: this.onBufferComplete,
636
670
 
671
+ onPlayerClose: this.onPlayerClose,
672
+ onVideoFullscreenPlayerWillPresent: this.onVideoFullscreenPlayerWillPresent,
673
+ onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
674
+ onVideoFullscreenPlayerWillDismiss: this.onVideoFullscreenPlayerWillDismiss,
675
+ onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
676
+
637
677
  // Ads Callbacks:
638
678
  onAdBegin: this.onAdBegin,
639
679
  onAdBreakBegin: this.onAdBreakBegin,
@@ -652,9 +692,6 @@ export class Player {
652
692
  play = () => {};
653
693
  pause = () => {};
654
694
  disableBufferAnimation = (): boolean => true;
655
- setLanguage = (
656
- _selected?: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
657
- ) => {};
658
695
 
659
696
  setPlaybackRate = (_rate) => {};
660
697
  startSleepTimer = (_timestamp) => {};
@@ -693,4 +730,7 @@ export class Player {
693
730
  isFullScreenSupported(): boolean {
694
731
  return true;
695
732
  }
733
+
734
+ public supportsNativeControls = (): boolean => false;
735
+ public supportNativeCast = (): boolean => false;
696
736
  }
@@ -9,21 +9,23 @@ type PlayerFactoryItem = {
9
9
  };
10
10
 
11
11
  type PlayerFactoryProps = {
12
- player: any,
13
- playerId: string,
14
- autoplay: boolean,
15
- entry: ZappEntry,
16
- muted: boolean,
17
- playerPluginId: string,
18
- screenConfig: Record<string, any>,
19
- playerRole: PlayerRole,
20
- }
12
+ player: any;
13
+ playerId: string;
14
+ autoplay: boolean;
15
+ entry: ZappEntry;
16
+ muted: boolean;
17
+ playerPluginId: string;
18
+ screenConfig: Record<string, any>;
19
+ playerRole: PlayerRole;
20
+ };
21
21
 
22
22
  interface PlayerConstructor {
23
23
  new (params: any): Player;
24
24
  }
25
25
 
26
- export const playerFactory = (config: PlayerFactoryProps): PlayerFactoryItem | null => {
26
+ export const playerFactory = (
27
+ config: PlayerFactoryProps
28
+ ): PlayerFactoryItem | null => {
27
29
  const IDENTIFIER = config?.playerPluginId;
28
30
 
29
31
  if (!IDENTIFIER) {
@@ -2,18 +2,10 @@ import * as R from "ramda";
2
2
  import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
3
3
  import { createLogger, utilsLogger } from "../../logger";
4
4
  import { Player } from "./player";
5
- import { findNodeHandle, NativeModules } from "react-native";
6
- import { isApplePlatform } from "../../reactUtils";
5
+ import { findNodeHandle } from "react-native";
7
6
  import { PlayerRole } from "./conts";
8
-
9
- const RNPlayerManager = {
10
- QuickBrickPlayerPlugin: isApplePlatform()
11
- ? NativeModules.PlayerModule
12
- : NativeModules.QuickBrickDefaultPlayerModule,
13
- KalturaPlayerPlugin: isApplePlatform()
14
- ? NativeModules.KalturaPlayerModule
15
- : NativeModules.QBKalturaPlayerModule,
16
- };
7
+ import { toBooleanWithDefaultFalse } from "../../booleanUtils";
8
+ import { RNPlayerManager } from "./nativePlayerManager";
17
9
 
18
10
  const logger = createLogger({
19
11
  category: "PlayerNativeController",
@@ -110,7 +102,7 @@ export class PlayerNative extends Player {
110
102
  return;
111
103
  }
112
104
 
113
- const newPosition = R.clamp(0, position, this.playerState.seekableDuration);
105
+ const newPosition = R.clamp(0, this.playerState.seekableDuration, position);
114
106
 
115
107
  if (
116
108
  !this.invokeNativeFunction(
@@ -196,10 +188,10 @@ export class PlayerNative extends Player {
196
188
 
197
189
  disableBufferAnimation = (): boolean => false;
198
190
 
199
- setLanguage = (
191
+ selectTrack = (
200
192
  selected: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
201
193
  ) => {
202
- this.currentPlayerComponent()?.["setLanguage"]?.(selected);
194
+ this.currentPlayerComponent()?.["selectTrack"]?.(selected);
203
195
  };
204
196
 
205
197
  setPlaybackRate = (rate: number) => {
@@ -291,4 +283,12 @@ export class PlayerNative extends Player {
291
283
 
292
284
  return !(isFullScreenAudioPlayer && this.isAudioItem());
293
285
  };
286
+
287
+ supportsNativeControls = (): boolean =>
288
+ toBooleanWithDefaultFalse(this.getConfig()?.["supports_native_controls"]);
289
+
290
+ supportNativeCast = (): boolean =>
291
+ toBooleanWithDefaultFalse(
292
+ this.playerPluginId === "quick-brick-player-brightcove"
293
+ );
294
294
  }
@@ -4,6 +4,7 @@ import { useEffect } from "react";
4
4
  import { playerManager } from "./index";
5
5
  import { useValidatePlayerConfig } from "../../playerUtils/useValidatePlayerConfig";
6
6
  import { PlayerRole } from "./conts";
7
+ import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
7
8
 
8
9
  // TODO: Rename to ControllerType
9
10
  export const usePlayerControllerSetup = ({
@@ -34,10 +35,14 @@ export const usePlayerControllerSetup = ({
34
35
  useValidatePlayerConfig(config);
35
36
 
36
37
  useEffect(() => {
38
+ const newConfig = isAppleTV()
39
+ ? { supports_native_controls: true, ...config }
40
+ : config;
41
+
37
42
  const newPlayerController = new ControllerType({
38
43
  player: ref,
39
44
  listener: props as any,
40
- config,
45
+ config: newConfig,
41
46
  playerId,
42
47
  entry,
43
48
  playerPluginId: pluginId,
@@ -0,0 +1,63 @@
1
+ import { isFilledArray } from "..";
2
+
3
+ describe("isFilledArray", () => {
4
+ it("non-empty array is not empty", () => {
5
+ const value = [1, 2, 3];
6
+
7
+ expect(isFilledArray(value)).toBe(true);
8
+ });
9
+
10
+ it("empty array is empty", () => {
11
+ const value = [];
12
+
13
+ expect(isFilledArray(value)).toBe(false);
14
+ });
15
+
16
+ it("number is not array", () => {
17
+ const value = 123;
18
+
19
+ expect(isFilledArray(value)).toBe(false);
20
+ });
21
+
22
+ it("string is not array", () => {
23
+ const value = "vfnjdk";
24
+
25
+ expect(isFilledArray(value)).toBe(false);
26
+ });
27
+
28
+ it("empty string is not array", () => {
29
+ const value = "";
30
+
31
+ expect(isFilledArray(value)).toBe(false);
32
+ });
33
+
34
+ it("NaN is not array", () => {
35
+ const value = "";
36
+
37
+ expect(isFilledArray(value)).toBe(false);
38
+ });
39
+
40
+ it("object is not array", () => {
41
+ const value = { test: 1 };
42
+
43
+ expect(isFilledArray(value)).toBe(false);
44
+ });
45
+
46
+ it("empty object is not array", () => {
47
+ const value = {};
48
+
49
+ expect(isFilledArray(value)).toBe(false);
50
+ });
51
+
52
+ it("undefined is not array", () => {
53
+ const value = undefined;
54
+
55
+ expect(isFilledArray(value)).toBe(false);
56
+ });
57
+
58
+ it("null is not array", () => {
59
+ const value = null;
60
+
61
+ expect(isFilledArray(value)).toBe(false);
62
+ });
63
+ });
@@ -95,3 +95,8 @@ export const makeListOfIndexes = (size: number): number[] =>
95
95
  export const makeListOf = (value: unknown, size: number): number[] => {
96
96
  return Array(size).fill(value);
97
97
  };
98
+
99
+ /** Checks if a value is a non-empty array */
100
+ export function isFilledArray(value: unknown): boolean {
101
+ return R.is(Array, value) && R.length(value) > 0;
102
+ }
@@ -1,7 +1,7 @@
1
- import * as R from "ramda";
1
+ import { is, toLower } from "ramda";
2
2
 
3
3
  export const toBoolean = (value: any): boolean | undefined => {
4
- if (R.is(Boolean, value)) {
4
+ if (is(Boolean, value)) {
5
5
  return value;
6
6
  }
7
7
 
@@ -17,12 +17,12 @@ export const toBooleanWithDefaultTrue = toBooleanWithDefault(true);
17
17
 
18
18
  export const toBooleanWithDefaultFalse = toBooleanWithDefault(false);
19
19
 
20
- export const isTrue = (value: any): boolean => {
20
+ export const isTrue = (value: unknown): boolean => {
21
21
  if (value === true) {
22
22
  return true;
23
23
  }
24
24
 
25
- if (R.is(String, value) && value.toLowerCase() === "true") {
25
+ if (is(String, value) && toLower(value) === "true") {
26
26
  return true;
27
27
  }
28
28