@applicaster/zapp-react-native-utils 12.0.0-alpha.9262886003 → 12.0.0-alpha.9417984401

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 (100) hide show
  1. package/analyticsUtils/AnalyticPlayerListener.ts +141 -0
  2. package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
  3. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  4. package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
  5. package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
  6. package/analyticsUtils/analyticsPlugins.ts +25 -0
  7. package/analyticsUtils/events.ts +12 -0
  8. package/analyticsUtils/index.tsx +12 -0
  9. package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
  10. package/appUtils/HooksManager/index.js +3 -1
  11. package/appUtils/accessibilityManager/const.ts +50 -0
  12. package/appUtils/accessibilityManager/hooks.ts +40 -0
  13. package/appUtils/accessibilityManager/index.ts +166 -0
  14. package/appUtils/accessibilityManager/logger.ts +5 -0
  15. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
  16. package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
  17. package/appUtils/focusManager/__tests__/index.test.ts +2 -3
  18. package/appUtils/focusManager/index.ts +76 -57
  19. package/appUtils/focusManager/treeDataStructure/Utils/index.js +75 -44
  20. package/appUtils/focusManager/utils/index.ts +100 -0
  21. package/appUtils/focusManagerAux/index.ts +76 -0
  22. package/appUtils/focusManagerAux/utils/index.ts +100 -0
  23. package/appUtils/index.js +2 -0
  24. package/appUtils/keyCodes/keys.web.js +8 -0
  25. package/appUtils/keyCodes/keysByPlatform.js +11 -1
  26. package/appUtils/platform/const.ts +25 -0
  27. package/appUtils/platform/index.ts +3 -0
  28. package/appUtils/platform/platformUtils.ts +217 -0
  29. package/appUtils/playerManager/conts.ts +6 -0
  30. package/appUtils/playerManager/index.ts +20 -32
  31. package/appUtils/playerManager/nativePlayerManager.ts +12 -0
  32. package/appUtils/playerManager/player.ts +44 -3
  33. package/appUtils/playerManager/playerFactory.ts +13 -11
  34. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +57 -0
  35. package/appUtils/playerManager/playerNative.ts +15 -15
  36. package/appUtils/playerManager/usePlayerControllerSetup.tsx +8 -2
  37. package/appUtils/playerManager/usePlayerState.tsx +19 -34
  38. package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
  39. package/arrayUtils/index.ts +5 -0
  40. package/booleanUtils/index.ts +4 -4
  41. package/cellUtils/__tests__/cellUtils.test.ts +9 -20
  42. package/cellUtils/index.ts +48 -19
  43. package/dateUtils/index.ts +11 -0
  44. package/functionUtils/index.ts +38 -0
  45. package/headersUtils/index.ts +1 -0
  46. package/index.d.ts +15 -0
  47. package/inflatedUrlUtils/index.ts +4 -4
  48. package/keyboardState/index.ts +0 -0
  49. package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
  50. package/localizationUtils/index.ts +13 -22
  51. package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
  52. package/manifestUtils/defaultManifestConfigurations/player.js +123 -1
  53. package/manifestUtils/index.js +5 -1
  54. package/manifestUtils/keys.js +2 -1
  55. package/manifestUtils/secondaryImage/index.js +18 -15
  56. package/navigationUtils/index.ts +48 -0
  57. package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
  58. package/numberUtils/__tests__/toNumber.test.ts +2 -2
  59. package/numberUtils/index.ts +9 -18
  60. package/package.json +2 -2
  61. package/playerUtils/configurationGenerator.ts +123 -1
  62. package/playerUtils/imaScriptDom.ts +59 -0
  63. package/pluginUtils/index.ts +9 -0
  64. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
  65. package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
  66. package/reactHooks/cell-click/__tests__/index.test.js +10 -1
  67. package/reactHooks/cell-click/index.ts +12 -12
  68. package/reactHooks/debugging/__tests__/index.test.js +81 -11
  69. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
  70. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
  71. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  72. package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
  73. package/reactHooks/feed/useFeedRefresh.tsx +9 -7
  74. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  75. package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +44 -29
  76. package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
  77. package/reactHooks/layout/types/index.ts +2 -0
  78. package/reactHooks/layout/useDimensions/useDimensions.ts +15 -7
  79. package/reactHooks/navigation/__mocks__/index.ts +15 -0
  80. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  81. package/reactHooks/navigation/__tests__/index.test.tsx +11 -8
  82. package/reactHooks/navigation/index.ts +64 -21
  83. package/reactHooks/player/useAutoSeek.tsx +9 -7
  84. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
  85. package/reactHooks/resolvers/useCellResolver.ts +5 -1
  86. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
  87. package/reactHooks/screen/index.ts +2 -0
  88. package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
  89. package/reactHooks/screen/useScreenContext.ts +3 -3
  90. package/reactHooks/screen/useTargetScreenData.ts +7 -0
  91. package/reactHooks/useConfiguration.ts +2 -2
  92. package/reactUtils/index.ts +104 -0
  93. package/screenState/index.ts +0 -8
  94. package/stringUtils/index.ts +5 -0
  95. package/testUtils/getByTestId.ts +14 -0
  96. package/testUtils/index.tsx +24 -22
  97. package/types.ts +4 -0
  98. package/appUtils/focusManager/FocusableEvents.ts +0 -8
  99. package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
  100. package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
@@ -3,7 +3,6 @@ import * as R from "ramda";
3
3
  import { subscriber } from "../../functionUtils";
4
4
  import { utilsLogger, createLogger } from "../../logger";
5
5
  import { Player } from "./player";
6
- import { AnalyticsTracker } from "../../analyticsUtils/analyticsTracker";
7
6
  import {
8
7
  hasTizenAPIs,
9
8
  subscribeToDeviceNetworkChanges,
@@ -11,6 +10,7 @@ import {
11
10
  } from "@applicaster/quick-brick-core/App/NetworkStatusProvider/utils";
12
11
  import { setUserLanguagePreference } from "./userLanguagePreference";
13
12
  import { PlayerRole } from "./conts";
13
+ import { RNPlayerManager } from "./nativePlayerManager";
14
14
 
15
15
  const { log_error, log_debug, log_warning } = createLogger({
16
16
  category: "General",
@@ -36,7 +36,10 @@ export interface PlayerLifecycleListener {
36
36
  }
37
37
 
38
38
  type PlayersMap = {
39
- [id: string]: { player: Player; isInViewport: boolean };
39
+ [id: string]: {
40
+ player: Player;
41
+ isInViewport: boolean;
42
+ };
40
43
  };
41
44
 
42
45
  export class PlayerManager {
@@ -45,7 +48,6 @@ export class PlayerManager {
45
48
  private playersMap: PlayersMap = {};
46
49
  private manager = subscriber();
47
50
  private castingReceiver: Player;
48
- private analyticsTracker: AnalyticsTracker;
49
51
  private lifecycleListeners: PlayerLifecycleListener[] = [];
50
52
 
51
53
  public static getInstance() {
@@ -56,7 +58,7 @@ export class PlayerManager {
56
58
  return PlayerManager.instance;
57
59
  }
58
60
 
59
- public getActivePlayerId = (): String | null => {
61
+ public getActivePlayerId = (): string | null => {
60
62
  return this.activePlayerId;
61
63
  };
62
64
 
@@ -101,7 +103,10 @@ export class PlayerManager {
101
103
  }
102
104
 
103
105
  private addPlayer = (id: string, player: Player) => {
104
- this.playersMap[id] = { player: player, isInViewport: false };
106
+ this.playersMap[id] = {
107
+ player: player,
108
+ isInViewport: false,
109
+ };
105
110
  };
106
111
 
107
112
  public isPlayerRegistered = (id: string) => !!this.playersMap[id];
@@ -164,6 +169,10 @@ export class PlayerManager {
164
169
  this.addPlayer(id, playerController);
165
170
 
166
171
  if (playerController.playerRole === PlayerRole.Primary) {
172
+ if (playerController.playerPluginId !== "QuickBrickPlayerPlugin") {
173
+ RNPlayerManager?.["QuickBrickPlayerPlugin"]?.stopBackgroundPlayback?.();
174
+ }
175
+
167
176
  playerController.addListener({
168
177
  id: this.getPlayerListenerId(id),
169
178
  listener: {
@@ -246,28 +255,6 @@ export class PlayerManager {
246
255
  this.castingReceiver = null;
247
256
  }
248
257
 
249
- /**
250
- * Handles analytic events, generates a new analytics tracker and transmits events
251
- * Passes entry data, and playerState to the tracker for additional context
252
- * The end result is an event formatted and passed to AnalyticsBridge.postEvent
253
- * When we get the synthetic event we need to pull the data in the e object
254
- * e contains the return value from native
255
- */
256
- public handleAnalyticEvent(event, data = {}, entry: ZappEntry) {
257
- const playerState = this.getActivePlayer()?.getState();
258
-
259
- if (!this.analyticsTracker?.handleAnalyticEvent) {
260
- this.analyticsTracker = new AnalyticsTracker(entry);
261
- }
262
-
263
- this.analyticsTracker?.handleAnalyticEvent?.(
264
- event,
265
- data,
266
- entry,
267
- playerState
268
- );
269
- }
270
-
271
258
  /**
272
259
  * Method retrieves the instantiated player instance controller
273
260
  * Instance controller exposes methods like getContentDuration, getContentPosision
@@ -361,9 +348,9 @@ export class PlayerManager {
361
348
  // TODO: Remove
362
349
  if (this.castingReceiver) {
363
350
  this.castingReceiver.rewind(deltaTime);
351
+ } else {
352
+ this.getActivePlayer()?.rewind(deltaTime);
364
353
  }
365
-
366
- this.getActivePlayer()?.rewind(deltaTime);
367
354
  }
368
355
 
369
356
  public forward(deltaTime = null) {
@@ -371,9 +358,9 @@ export class PlayerManager {
371
358
 
372
359
  if (this.castingReceiver) {
373
360
  this.castingReceiver.forward(deltaTime);
361
+ } else {
362
+ this.getActivePlayer()?.forward(deltaTime);
374
363
  }
375
-
376
- this.getActivePlayer()?.forward(deltaTime);
377
364
  }
378
365
 
379
366
  public seeking(time) {
@@ -436,7 +423,7 @@ export class PlayerManager {
436
423
  }
437
424
 
438
425
  // Call method on player just in case
439
- return this.getActivePlayer()?.setLanguage(track);
426
+ return this.getActivePlayer()?.selectTrack(track);
440
427
  }
441
428
 
442
429
  public isRegistered() {
@@ -461,6 +448,7 @@ export class PlayerManager {
461
448
  if (this.castingReceiver) {
462
449
  this.castingReceiver.closeNativePlayer();
463
450
  } else {
451
+ this.getActivePlayer().closeNativePlayer();
464
452
  this.invokeHandler("close");
465
453
  }
466
454
  }
@@ -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,8 @@ export class Player {
693
730
  isFullScreenSupported(): boolean {
694
731
  return true;
695
732
  }
733
+
734
+ public supportsNativeControls = (): boolean => false;
735
+ public supportNativeCast = (): boolean => false;
736
+ public destroy = () => {};
696
737
  }
@@ -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) {
@@ -44,7 +46,7 @@ export const playerFactory = (config: PlayerFactoryProps): PlayerFactoryItem | n
44
46
 
45
47
  // TODO: Fix type:
46
48
  const playerProtocol: PlayerConstructor =
47
- playerPlugin?.module?.playerProtocol(config?.screenConfig);
49
+ playerPlugin?.module?.playerProtocol(config?.screenConfig, config?.entry);
48
50
 
49
51
  const playerView = (playerProtocol as any)?.Component || null;
50
52
 
@@ -0,0 +1,57 @@
1
+ import { useState, useEffect, useCallback } from "react";
2
+ import { Player } from "../player";
3
+ import { usePlayer } from "../usePlayer";
4
+ import { useThrottle } from "../../../functionUtils";
5
+
6
+ /**
7
+ *
8
+ * @param listenerId - A unique identifier for the listener.
9
+ * @param playerId - (Optional) The ID of the player to observe.
10
+ * @returns The current playback time in seconds.
11
+ */
12
+ export const usePlayerCurrentTime = (
13
+ listenerId: string,
14
+ playerId?: string
15
+ ): number | null => {
16
+ const [currentTime, setCurrentTime] = useState<number | null>(null);
17
+ const player: Player = usePlayer(playerId);
18
+
19
+ const updateCurrentTime = useCallback(() => {
20
+ if (player) {
21
+ const newCurrentTime = player.getContentPosition();
22
+
23
+ setCurrentTime((prevTime) =>
24
+ prevTime !== newCurrentTime ? newCurrentTime : prevTime
25
+ );
26
+ }
27
+ }, [player]);
28
+
29
+ const { throttledFunction: throttledUpdate, cancel } = useThrottle(
30
+ updateCurrentTime,
31
+ 1000
32
+ );
33
+
34
+ useEffect(() => {
35
+ if (player) {
36
+ throttledUpdate();
37
+
38
+ const listeners = {
39
+ onVideoProgress: throttledUpdate,
40
+ };
41
+
42
+ const id = `${listenerId}_player_current_time`;
43
+
44
+ player.addListener({
45
+ id: id,
46
+ listener: listeners,
47
+ });
48
+
49
+ return () => {
50
+ player.removeListener(id);
51
+ cancel();
52
+ };
53
+ }
54
+ }, [player, listenerId, throttledUpdate, cancel]);
55
+
56
+ return currentTime;
57
+ };
@@ -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",
@@ -69,7 +61,7 @@ export class PlayerNative extends Player {
69
61
  currentPlayerComponent = (): ReactComponent<PlayerProps> =>
70
62
  this.playerComponent?.current;
71
63
 
72
- getState = () => this.currentPlayerComponent()?.["getState"]?.() ?? {};
64
+ getState = () => this.playerState;
73
65
 
74
66
  // TODO: Try to add module interface
75
67
  invokeNativeFunction = (funcName: string, ...params: any[]): boolean => {
@@ -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,
@@ -45,7 +50,7 @@ export const usePlayerControllerSetup = ({
45
50
  });
46
51
 
47
52
  setPlayerController(newPlayerController);
48
- }, [playerId, entry?.id]);
53
+ }, [playerId, entry?.id, ref.current]);
49
54
 
50
55
  React.useEffect(() => {
51
56
  if (!playerController) {
@@ -67,6 +72,7 @@ export const usePlayerControllerSetup = ({
67
72
 
68
73
  return () => {
69
74
  playerManager.unregisterPlayer(playerId);
75
+ playerController.destroy?.();
70
76
  };
71
77
  }, [playerId, playerController]);
72
78
 
@@ -16,24 +16,28 @@ export const usePlayerState = (
16
16
  listenerId: string,
17
17
  playerId?: string
18
18
  ): PlayerState => {
19
- const [currentTime, setCurrentTime] = React.useState<number>(null);
20
- const [duration, setDuration] = React.useState<number>(null);
21
- const [seekableDuration, setSeekableDuration] = React.useState<number>(null);
22
- const [isLive, setIsLive] = React.useState<boolean>(null);
23
- const [isBuffering, setIsBuffering] = React.useState<boolean>(false);
24
- const [isReadyToPlay, setIsReadyToPlay] = React.useState<boolean>(false);
25
- const [isPaused, setIsPaused] = React.useState<boolean>(false);
19
+ const [state, setState] = React.useState<PlayerState>({
20
+ currentTime: null,
21
+ duration: null,
22
+ seekableDuration: null,
23
+ isLive: null,
24
+ isPaused: null,
25
+ isBuffering: false,
26
+ isReadyToPlay: false,
27
+ });
26
28
 
27
29
  const player: Player = usePlayer(playerId);
28
30
 
29
31
  const onPlayerChangeState = React.useCallback(() => {
30
- setIsBuffering(player.isBuffering());
31
- setIsReadyToPlay(player.isReadyToPlay);
32
- setCurrentTime(player.getContentPosition());
33
- setDuration(player.getDuration());
34
- setSeekableDuration(player.getSeekableDuration());
35
- setIsLive(player.isLive());
36
- setIsPaused(player.isPaused());
32
+ setState({
33
+ currentTime: player.getContentPosition(),
34
+ duration: player.getDuration(),
35
+ seekableDuration: player.getSeekableDuration(),
36
+ isLive: player.isLive(),
37
+ isPaused: player.isPaused(),
38
+ isBuffering: player.isBuffering(),
39
+ isReadyToPlay: player.isReadyToPlay(),
40
+ });
37
41
  }, [player]);
38
42
 
39
43
  React.useEffect(() => {
@@ -55,24 +59,5 @@ export const usePlayerState = (
55
59
  }
56
60
  }, [player]);
57
61
 
58
- return React.useMemo(
59
- () => ({
60
- currentTime,
61
- duration,
62
- seekableDuration,
63
- isLive,
64
- isPaused,
65
- isBuffering,
66
- isReadyToPlay,
67
- }),
68
- [
69
- currentTime,
70
- duration,
71
- seekableDuration,
72
- isLive,
73
- isPaused,
74
- isBuffering,
75
- isReadyToPlay,
76
- ]
77
- );
62
+ return state;
78
63
  };
@@ -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
 
@@ -24,7 +24,6 @@ import {
24
24
  EMPTY,
25
25
  FALLBACK,
26
26
  TRANSFORM,
27
- defaultColor,
28
27
  } from "./fixtures";
29
28
 
30
29
  describe("getKeyForLabel", () => {
@@ -395,9 +394,7 @@ describe("getColorFromData", () => {
395
394
  it("should return value directly if valid color", () => {
396
395
  const result = getColorFromData({
397
396
  data: entry,
398
- key: "background_color",
399
- getValue: getValue(componentStyle),
400
- defaultColor,
397
+ valueFromLayout: "#123456",
401
398
  });
402
399
 
403
400
  expect(result).toBe("#123456");
@@ -406,9 +403,7 @@ describe("getColorFromData", () => {
406
403
  it("should return valid rgba color name", () => {
407
404
  const result = getColorFromData({
408
405
  data: entry,
409
- key: "component_background_color",
410
- getValue: getValue(componentStyle),
411
- defaultColor,
406
+ valueFromLayout: "rgba(255, 255, 255, 0)",
412
407
  });
413
408
 
414
409
  expect(result).toBe("rgba(255, 255, 255, 0)");
@@ -417,33 +412,27 @@ describe("getColorFromData", () => {
417
412
  it("should return path value if path value is set and is valid color", () => {
418
413
  const result = getColorFromData({
419
414
  data: entry,
420
- key: VAL.colorKeyPath,
421
- getValue: getValue(componentStyle),
422
- defaultColor,
415
+ valueFromLayout: "background_color",
423
416
  });
424
417
 
425
418
  expect(result).toBe("#123456");
426
419
  });
427
420
 
428
- it("should return defaultColor if key value and path value are invalid", () => {
421
+ it("should return path value if path value is set, nested and is valid color", () => {
429
422
  const result = getColorFromData({
430
423
  data: entry,
431
- key: VAL.invalidColorKey,
432
- getValue: getValue(componentStyle),
433
- defaultColor,
424
+ valueFromLayout: "extensions.background_color",
434
425
  });
435
426
 
436
- expect(result).toBe(defaultColor);
427
+ expect(result).toBe("#123456");
437
428
  });
438
429
 
439
- it("should return defaultColor if path does not exist", () => {
430
+ it("should return valueFromLayout if path does not exist", () => {
440
431
  const result = getColorFromData({
441
432
  data: entry,
442
- key: VAL.invalidColorKeyPath,
443
- getValue: getValue(componentStyle),
444
- defaultColor,
433
+ valueFromLayout: "invalid_color",
445
434
  });
446
435
 
447
- expect(result).toBe(defaultColor);
436
+ expect(result).toBe("invalid_color");
448
437
  });
449
438
  });