@applicaster/zapp-react-dom-app 13.0.0-alpha.2635505531 → 13.0.0-alpha.2685746452

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.
@@ -23,8 +23,6 @@ import {
23
23
 
24
24
  import { showConfirmationDialog } from "@applicaster/zapp-react-native-utils/alertUtils";
25
25
 
26
- import { withUseSeek } from "@applicaster/zapp-react-native-utils/reactHooks/player";
27
-
28
26
  import {
29
27
  DISPLAY_STATES,
30
28
  DisplayStateContext,
@@ -33,7 +31,10 @@ import {
33
31
  import { PlayerContentContext } from "@applicaster/zapp-react-dom-ui-components/Contexts";
34
32
 
35
33
  import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator";
36
- import { getXray } from "@applicaster/zapp-react-native-utils/logger";
34
+ import {
35
+ getXray,
36
+ createLogger,
37
+ } from "@applicaster/zapp-react-native-utils/logger";
37
38
 
38
39
  import {
39
40
  confirmationDialogStore,
@@ -48,10 +49,16 @@ import {
48
49
 
49
50
  import { OnScreenKeyboard } from "@applicaster/zapp-react-dom-ui-components/Components/OnScreenKeyboard";
50
51
  import { KeyboardLongPressManager } from "@applicaster/zapp-react-dom-ui-components/Utils/KeyboardLongPressManager";
52
+ import { KeyInputHandler } from "@applicaster/zapp-react-native-utils/appUtils/keyInputHandler/KeyInputHandler";
51
53
 
52
54
  const { withXray } = getXray();
53
55
  const globalAny: any = global;
54
56
 
57
+ const { log_debug, log_warning } = createLogger({
58
+ category: "InteractionManager",
59
+ subsystem: "zapp-react-dom-app",
60
+ });
61
+
55
62
  const shouldUseOnScreenKeyboard = () =>
56
63
  isVizioPlatform() || window.applicaster.useOnScreenKeyboard;
57
64
 
@@ -62,14 +69,6 @@ type Props = {
62
69
  navigator: QuickBrickAppNavigator;
63
70
  rivers: {};
64
71
  xray: XRayContext;
65
- seekMethods: {
66
- onRewindPress: () => void;
67
- onRewindLongPress: () => void;
68
- onForwardPress: () => void;
69
- onForwardLongPress: () => void;
70
- onRewindPressOut: () => void;
71
- onForwardPressOut: () => void;
72
- };
73
72
  confirmDialog: typeof confirmationDialogStore;
74
73
  };
75
74
 
@@ -149,13 +148,16 @@ class InteractionManagerClass extends React.Component<Props, State> {
149
148
  this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
150
149
  this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
151
150
 
151
+ this.handlePhysicalKeyboardDismiss =
152
+ this.handlePhysicalKeyboardDismiss.bind(this);
153
+
152
154
  this.confirmDialog.setConfirmAction(this.performExit);
153
155
  this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
154
156
  this.longPressDetector = new KeyboardLongPressManager();
155
157
  }
156
158
 
157
159
  componentDidMount() {
158
- window.addEventListener("keydown", this.onKeyDownListener);
160
+ window.addEventListener("keydown", this.onKeyDownListener, true);
159
161
  window.addEventListener("keyup", this.onKeyUp);
160
162
  window.addEventListener("mousemove", this.onMouseMoveListener);
161
163
 
@@ -190,6 +192,11 @@ class InteractionManagerClass extends React.Component<Props, State> {
190
192
  "onLongPressRelease",
191
193
  this.handleLongPressRelease.bind(this)
192
194
  );
195
+
196
+ document.addEventListener(
197
+ "keyboardDismissedByPhysicalKeypress",
198
+ this.handlePhysicalKeyboardDismiss
199
+ );
193
200
  }
194
201
 
195
202
  componentWillUnmount() {
@@ -218,6 +225,11 @@ class InteractionManagerClass extends React.Component<Props, State> {
218
225
  "onLongPressRelease",
219
226
  this.handleLongPressRelease
220
227
  );
228
+
229
+ document.removeEventListener(
230
+ "keyboardDismissedByPhysicalKeypress",
231
+ this.handlePhysicalKeyboardDismiss
232
+ );
221
233
  }
222
234
 
223
235
  performExit() {
@@ -279,8 +291,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
279
291
  this.handleWebOsBack();
280
292
  }
281
293
  } catch (e) {
282
- // eslint-disable-next-line no-console
283
- console.warn("Failed to execute platformBack", e);
294
+ log_warning("Failed to execute platformBack", e);
284
295
  }
285
296
  }
286
297
 
@@ -344,36 +355,139 @@ class InteractionManagerClass extends React.Component<Props, State> {
344
355
  }
345
356
 
346
357
  onKeyUp(event: KeyboardEvent) {
358
+ const { setDisplayState } = this.props;
359
+
347
360
  if (this.keySupportsLongPress(event)) {
348
361
  this.longPressDetector.endKeyPressMonitoring(event.code);
349
362
  }
363
+
364
+ if (
365
+ keyCode(event).matches(KEYS.Enter) ||
366
+ (__DEV__ && keyCode(event).matches(KEYS.X))
367
+ ) {
368
+ focusManager.pressOut();
369
+ }
370
+
371
+ if (
372
+ keyCode(event).matches(KEYS.Forward) ||
373
+ (__DEV__ && keyCode(event).matches(KEYS.C))
374
+ ) {
375
+ setDisplayState(DISPLAY_STATES.HUD);
376
+ KeyInputHandler.getInstance().onForwardPressOut();
377
+ }
378
+
379
+ if (
380
+ keyCode(event).matches(KEYS.Rewind) ||
381
+ (__DEV__ && keyCode(event).matches(KEYS.Z))
382
+ ) {
383
+ setDisplayState(DISPLAY_STATES.HUD);
384
+ KeyInputHandler.getInstance().onRewindPressOut();
385
+ }
350
386
  }
351
387
 
352
- onKeyDown(event) {
353
- // console.log("Anton: event", event);
354
- // debugger;
388
+ /**
389
+ When pressing escape or the Native "Back" button:
390
+ if on the transport controls: we show the player
391
+ if on the player : we show the UI
392
+ if on the UI : we exit the app
393
+ note: backspace affects the keyboard input, so it behaves differently
394
+ */
395
+ onBackPress(event) {
355
396
  const { displayState, setDisplayState, navigator } = this.props;
397
+ const { isDialogVisible } = confirmationDialogStore.getState();
356
398
  const { isKeyboardVisible } = this.state;
357
399
 
358
- const { isDialogVisible } = confirmationDialogStore.getState();
400
+ log_debug("onBackPress", {
401
+ eventCode: event.code,
402
+ displayState,
403
+ isDialogVisible,
404
+ isKeyboardVisible,
405
+ });
359
406
 
360
407
  if (isKeyboardVisible && shouldUseOnScreenKeyboard()) {
361
- if (keyCode(event).matchesAny("Escape", "Back")) {
362
- this.handleKeyboardDismiss();
363
- }
364
-
408
+ this.handleKeyboardDismiss();
365
409
  event.preventDefault();
366
410
  event.stopPropagation();
367
411
 
368
412
  return;
369
413
  }
370
414
 
415
+ switch (displayState) {
416
+ case DISPLAY_STATES.DEFAULT:
417
+ case DISPLAY_STATES.PLAYER:
418
+ if (isDialogVisible) {
419
+ this.onConfirmDialogClose();
420
+ } else if (navigator.canGoBack()) {
421
+ navigator.goBack();
422
+ } else if (this.isHomeScreen()) {
423
+ this.platformBack();
424
+ } else if (navigator.currentRoute.includes("hook")) {
425
+ // If code reaches this block navigator cant go back, it is not home,
426
+ // and this is a login plugin that was pushed on top of the home
427
+ // Treat it like a home screen and run platformBack()
428
+ const entryData = navigator?.data?.entry;
429
+ const isHookInHomescreen = entryData?.payload?.home;
430
+
431
+ const isHookFlowBlocker =
432
+ typeof entryData?.hookPlugin?.module?.isFlowBlocker === "function"
433
+ ? entryData?.hookPlugin?.module?.isFlowBlocker()
434
+ : entryData?.hookPlugin?.module?.isFlowBlocker;
435
+
436
+ if (isHookInHomescreen && isHookFlowBlocker) {
437
+ this.platformBack();
438
+ } else {
439
+ navigator.goBack(false, true);
440
+ }
441
+ } else {
442
+ this.goToHome();
443
+ }
444
+
445
+ break;
446
+ case DISPLAY_STATES.HUD:
447
+ // IF transport controls are open, close them instead of closing player
448
+ setDisplayState(DISPLAY_STATES.PLAYER);
449
+ break;
450
+ default:
451
+ setDisplayState(DISPLAY_STATES.PLAYER);
452
+ break;
453
+ }
454
+ }
455
+
456
+ onBackspacePress(event) {
457
+ const isInputFocused =
458
+ document.activeElement instanceof HTMLInputElement ||
459
+ document.activeElement instanceof HTMLTextAreaElement;
460
+
461
+ // Don't handle backspace if input is focused
462
+ if (isInputFocused) {
463
+ return;
464
+ }
465
+
466
+ this.onBackPress(event);
467
+ }
468
+
469
+ onKeyDown(event) {
470
+ const { displayState, setDisplayState, navigator } = this.props;
471
+ const { isDialogVisible } = confirmationDialogStore.getState();
472
+
473
+ if (keyCode(event).matches("Backspace")) {
474
+ this.onBackspacePress(event);
475
+
476
+ return;
477
+ }
478
+
479
+ if (keyCode(event).matchesAny(KEYS.Back, KEYS.Escape, KEYS.EscapeDevice)) {
480
+ this.onBackPress(event);
481
+
482
+ return;
483
+ }
484
+
371
485
  if (this.keySupportsLongPress(event)) {
372
486
  this.longPressDetector.monitorKeyPress(event.code, event);
373
487
  }
374
488
 
375
- // None of the logic below should be executed for repeated keys
376
- if (event.repeat) return;
489
+ // Only handle repeat events for arrow keys
490
+ if (event.repeat && !keyCode(event).matchesAny(...ARROW_KEYS)) return;
377
491
 
378
492
  /**
379
493
  When the player is displayed, we listen to Native Play / Pause / Stop
@@ -414,83 +528,33 @@ class InteractionManagerClass extends React.Component<Props, State> {
414
528
 
415
529
  if (
416
530
  keyCode(event).matches(KEYS.Forward) ||
417
- keyCode(event).matches(KEYS.C)
531
+ (__DEV__ && keyCode(event).matches(KEYS.C))
418
532
  ) {
419
533
  setDisplayState(DISPLAY_STATES.HUD);
420
- this.props.seekMethods.onForwardPress();
534
+ KeyInputHandler.getInstance().onForwardPress();
421
535
 
422
536
  return;
423
537
  }
424
538
 
425
539
  if (
426
540
  keyCode(event).matches(KEYS.Rewind) ||
427
- keyCode(event).matches(KEYS.Z)
541
+ (__DEV__ && keyCode(event).matches(KEYS.Z))
428
542
  ) {
429
543
  setDisplayState(DISPLAY_STATES.HUD);
430
- this.props.seekMethods.onRewindPress();
544
+ KeyInputHandler.getInstance().onRewindPress();
431
545
 
432
546
  return;
433
547
  }
434
548
  }
435
549
 
436
- /**
437
- When pressing backspace or the Native "Back" button:
438
- if on the transport controls: we show the player
439
- if on the player : we show the UI
440
- if on the UI : we exit the app
441
- */
442
-
443
550
  if (
444
- keyCode(event).matchesAny(
445
- KEYS.Back,
446
- KEYS.Escape,
447
- KEYS.EscapeDevice,
448
- KEYS.Backspace
449
- )
551
+ keyCode(event).matches(KEYS.Enter) ||
552
+ (__DEV__ && keyCode(event).matches(KEYS.X))
450
553
  ) {
451
- switch (displayState) {
452
- case DISPLAY_STATES.DEFAULT:
453
- case DISPLAY_STATES.PLAYER:
454
- if (isDialogVisible) {
455
- this.onConfirmDialogClose();
456
- } else if (navigator.canGoBack()) {
457
- navigator.goBack();
458
- } else if (this.isHomeScreen()) {
459
- this.platformBack();
460
- } else if (navigator.currentRoute.includes("hook")) {
461
- // If code reaches this block navigator cant go back, it is not home,
462
- // and this is a login plugin that was pushed on top of the home
463
- // Treat it like a home screen and run platformBack()
464
- const entryData = navigator?.data?.entry;
465
- const isHookInHomescreen = entryData?.payload?.home;
466
-
467
- const isHookFlowBlocker =
468
- entryData?.hookPlugin?.module?.isFlowBlocker();
469
-
470
- if (isHookInHomescreen && isHookFlowBlocker) {
471
- this.platformBack();
472
- } else {
473
- navigator.goBack(false, true);
474
- }
475
- } else {
476
- this.goToHome();
477
- }
478
-
479
- break;
480
- case DISPLAY_STATES.HUD:
481
- // IF transport controls are open, close them instead of closing player
482
- setDisplayState(DISPLAY_STATES.PLAYER);
483
- break;
484
- default:
485
- setDisplayState(DISPLAY_STATES.PLAYER);
486
- break;
487
- }
488
- }
489
-
490
- if (keyCode(event).matches(KEYS.Enter) || keyCode(event).matches(KEYS.X)) {
491
554
  if (displayState === DISPLAY_STATES.PLAYER) {
492
555
  setDisplayState(DISPLAY_STATES.HUD);
493
556
  } else {
557
+ focusManager.pressIn();
494
558
  focusManager.press();
495
559
  }
496
560
 
@@ -507,10 +571,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
507
571
  this.platformBack();
508
572
  }
509
573
 
510
- if (
511
- keyCode(event).matchesAny(...ARROW_KEYS) &&
512
- !this.state.isKeyboardVisible
513
- ) {
574
+ if (keyCode(event).matchesAny(...ARROW_KEYS)) {
514
575
  if (displayState === DISPLAY_STATES.PLAYER) {
515
576
  setDisplayState(DISPLAY_STATES.HUD);
516
577
  }
@@ -604,6 +665,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
604
665
 
605
666
  if (
606
667
  (target.tagName === "INPUT" && target.type === "text") ||
668
+ (target.tagName === "INPUT" && target.type === "password") ||
607
669
  target.tagName === "TEXTAREA"
608
670
  ) {
609
671
  this.setState({
@@ -632,7 +694,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
632
694
  }
633
695
  }
634
696
 
635
- handleKeyboardDismiss = () => {
697
+ handleKeyboardDismiss() {
636
698
  this.isDismissing = true;
637
699
 
638
700
  this.setState(
@@ -643,9 +705,10 @@ class InteractionManagerClass extends React.Component<Props, State> {
643
705
  },
644
706
  () => {
645
707
  this.isDismissing = false;
708
+ focusManager.recoverFocus();
646
709
  }
647
710
  );
648
- };
711
+ }
649
712
 
650
713
  handleKeyboardInput = (value: string) => {
651
714
  const { activeInputRef } = this.state;
@@ -702,26 +765,13 @@ class InteractionManagerClass extends React.Component<Props, State> {
702
765
  }, SEQUENCE_ENTRY_TIME);
703
766
  }
704
767
 
768
+ // TODO: Delete it on next PR if not needed
705
769
  private handleLongPress = (event: CustomEvent) => {
706
770
  const { keyCode } = event.detail;
707
- const { displayState } = this.props;
708
- const playerState = displayState === DISPLAY_STATES.PLAYER;
709
- const hudState = displayState === DISPLAY_STATES.HUD;
710
- const playbackState = playerState || hudState;
711
771
  this.longPressActive = true;
712
772
  this.cancelHudTimeout();
713
773
 
714
774
  switch (keyCode) {
715
- case KEYS.Forward.code:
716
- case KEYS.C.code:
717
- playbackState && this.props.seekMethods.onForwardLongPress();
718
- break;
719
-
720
- case KEYS.Rewind.code:
721
- case KEYS.Z.code:
722
- playbackState && this.props.seekMethods.onRewindLongPress();
723
- break;
724
-
725
775
  case KEYS.Enter.code:
726
776
  case KEYS.X.code:
727
777
  focusManager.longPress();
@@ -729,26 +779,16 @@ class InteractionManagerClass extends React.Component<Props, State> {
729
779
  }
730
780
  };
731
781
 
782
+ // TODO: Delete it on next PR if not needed
732
783
  private handleLongPressRelease = (event: CustomEvent) => {
733
784
  const { keyCode } = event.detail;
734
785
  this.longPressActive = false;
735
786
  this.resetHudTimeout();
736
- // debugger;
737
787
 
738
788
  switch (keyCode) {
739
- case KEYS.Forward.code:
740
- case KEYS.C.code:
741
- this.props.seekMethods.onForwardPressOut();
742
- break;
743
-
744
- case KEYS.Rewind.code:
745
- case KEYS.Z.code:
746
- this.props.seekMethods.onRewindPressOut();
747
- break;
748
-
749
789
  case KEYS.Enter.code:
750
790
  case KEYS.X.code:
751
- focusManager.pressOut();
791
+ // focusManager.pressOut();
752
792
  break;
753
793
  }
754
794
  };
@@ -764,6 +804,35 @@ class InteractionManagerClass extends React.Component<Props, State> {
764
804
  ].includes(event.code);
765
805
  }
766
806
 
807
+ handlePhysicalKeyboardDismiss(event: CustomEvent) {
808
+ const { value, position, inputElement } = event.detail;
809
+
810
+ this.isDismissing = true;
811
+
812
+ this.setState(
813
+ {
814
+ isKeyboardVisible: false,
815
+ keyboardInput: "",
816
+ activeInputRef: null,
817
+ },
818
+ () => {
819
+ if (inputElement) {
820
+ inputElement.value = value;
821
+ inputElement.focus();
822
+ inputElement.setSelectionRange(position, position);
823
+
824
+ const keyboardEvent = new CustomEvent("keyboardUpdate", {
825
+ detail: { value },
826
+ });
827
+
828
+ document.dispatchEvent(keyboardEvent);
829
+ }
830
+
831
+ this.isDismissing = false;
832
+ }
833
+ );
834
+ }
835
+
767
836
  render() {
768
837
  return (
769
838
  (shouldUseOnScreenKeyboard() && this.state.isKeyboardVisible && (
@@ -780,7 +849,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
780
849
 
781
850
  export const InteractionManager = R.compose(
782
851
  withNavigator,
783
- withUseSeek,
784
852
  withXray,
785
853
  connectToStore(R.pick(["rivers"])),
786
854
  PlayerContentContext.withConsumer,
@@ -1,15 +1,15 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`loadDomPlugins when there are plugins requiring to write to the dom skips plugins without init method 1`] = `
4
- Array [
5
- Array [
4
+ [
5
+ [
6
6
  "could not initialize plugin Plugin with Dom node & no init method - it doesn't have an init method",
7
- Object {
8
- "plugin": Object {
9
- "configuration": Object {
7
+ {
8
+ "plugin": {
9
+ "configuration": {
10
10
  "foo": "bar",
11
11
  },
12
- "module": Object {
12
+ "module": {
13
13
  "requiresAppendingDomNode": true,
14
14
  },
15
15
  "name": "Plugin with Dom node & no init method",
@@ -3,11 +3,6 @@ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils"
3
3
  import { QuickBrickCommunicationModule } from "../../Polyfills/QuickBrickCommunicationModule";
4
4
  import { loadLocaleImpl, getLanguageCode } from "./utils";
5
5
 
6
- type Locale = {
7
- language: string,
8
- country: string,
9
- };
10
-
11
6
  async function getBrowserLocale() {
12
7
  return navigator.language;
13
8
  }
@@ -19,7 +14,7 @@ async function getSamsungLocale() {
19
14
  }
20
15
 
21
16
  try {
22
- tizen.systeminfo.getPropertyValue("LOCALE", (locale: Locale) => {
17
+ tizen.systeminfo.getPropertyValue("LOCALE", (locale) => {
23
18
  resolve(locale.language);
24
19
  });
25
20
  } catch (e) {
@@ -11,11 +11,28 @@ import {
11
11
  PLATFORMS,
12
12
  } from "./const";
13
13
 
14
+ /**
15
+ * @typedef {"tv" | "web" | "other"} DeviceType
16
+ * @typedef {"samsung_tv" | "lg_tv" | unknown} CustomPlatformTypes
17
+ */
18
+
19
+ /**
20
+ * Retrieves the user agent string from the browser or global navigator.
21
+ * @returns {string} The user agent string.
22
+ */
14
23
  export const getUserAgent = () =>
15
24
  window?.navigator?.userAgent || global?.navigator?.userAgent;
16
25
 
26
+ /**
27
+ * Checks if the device is HD (1280 width).
28
+ * @returns {boolean} True if the device is HD, false otherwise.
29
+ */
17
30
  export const isHD = () => window.innerWidth === 1280;
18
31
 
32
+ /**
33
+ * Checks if the platform is LG.
34
+ * @returns {boolean} True if the platform is LG, false otherwise.
35
+ */
19
36
  export const isLgPlatform = () => {
20
37
  const userAgent = getUserAgent();
21
38
 
@@ -23,10 +40,13 @@ export const isLgPlatform = () => {
23
40
  return false;
24
41
  }
25
42
 
26
- // Note: LG uses the number 0 in their userAgent, possibly because of Palm WebOS
27
43
  return hasWebOS || userAgent.includes(PLATFORMS.webos);
28
44
  };
29
45
 
46
+ /**
47
+ * Checks if the platform is Samsung.
48
+ * @returns {boolean} True if the platform is Samsung, false otherwise.
49
+ */
30
50
  export const isSamsungPlatform = () => {
31
51
  const userAgent = getUserAgent();
32
52
 
@@ -42,42 +62,39 @@ export const isSamsungPlatform = () => {
42
62
  };
43
63
 
44
64
  /**
45
- * Checks if we are on the Vizio platform by using the userAgent string
46
- *
47
- * Use this method when you need to identify the platform on runtime
48
- * before the VIZIO Companion Library has loaded
65
+ * Checks if the platform is Vizio by using the user agent string.
66
+ * @returns {boolean} True if the platform is Vizio, false otherwise.
49
67
  */
50
68
  export const isVizioPlatform = () => {
51
69
  const userAgent = getUserAgent();
52
70
 
53
- const isVizioAgent =
71
+ return (
54
72
  userAgent.includes(PLATFORMS.vizio) ||
55
73
  userAgent.includes(PLATFORMS.smartcast) ||
56
- userAgent.includes(PLATFORMS.conjure);
57
-
58
- return isVizioAgent;
74
+ userAgent.includes(PLATFORMS.conjure)
75
+ );
59
76
  };
60
77
 
61
78
  /**
62
- * Checks if we are on the Vizio platform by checking for the global VIZIO object
63
- * and the VIZIO Companion Library. This method does not use the userAgent string,
64
- * because it mainly checks whether we have access to apis, which may not be available yet
79
+ * Checks if the Vizio APIs are available.
80
+ * @returns {boolean} True if the Vizio APIs are available, false otherwise.
65
81
  */
66
82
  export const hasVizioAPIs = () => {
67
- const hasAPIs =
83
+ return (
68
84
  typeof window.VIZIO !== "undefined" &&
69
- window?.applicaster?.vizioLibraryDidLoad;
70
-
71
- return hasAPIs;
85
+ window?.applicaster?.vizioLibraryDidLoad
86
+ );
72
87
  };
73
88
 
74
89
  /**
75
- * platformSelect can't be used, because Platform.OS is overriden
76
- * by overloadReactNativePlatform and don't support 'web' value
77
- * @returns {"tv" | "web" | "other"} value
90
+ * Determines the device type based on the platform.
91
+ * @returns {DeviceType} The device type ("tv", "web", or "other").
78
92
  */
79
93
  export const getDeviceType = () => {
80
- switch (Platform.OS) {
94
+ /** @type {CustomPlatformTypes} */
95
+ const platformOS = Platform.OS;
96
+
97
+ switch (platformOS) {
81
98
  case "samsung_tv":
82
99
  return isSamsungPlatform() ? "tv" : "web";
83
100
  case "lg_tv":
@@ -88,14 +105,15 @@ export const getDeviceType = () => {
88
105
  };
89
106
 
90
107
  /**
91
- * This function is used to rename keys
92
- * @param {string} key - key you would like to rename
108
+ * Renames keys based on a predefined map.
109
+ * @param {string} key - The key to rename.
110
+ * @returns {string} The renamed key.
93
111
  */
94
112
  export const renameKeys = (key) => desiredKeysMap?.[key] || key;
95
113
 
96
114
  /**
97
- * This function is used to get the connection info from WebOS
98
- * TODO: move to connection hook
115
+ * Retrieves the connection info from WebOS.
116
+ * @returns {Promise<{networkType: string} | null>} A promise that resolves with the connection info or null.
99
117
  */
100
118
  export const getWebOSConnectionInfo = () => {
101
119
  return new Promise((resolve, reject) => {
@@ -108,7 +126,6 @@ export const getWebOSConnectionInfo = () => {
108
126
  webOS.service.request("luna://com.palm.connectionmanager", {
109
127
  method: "getStatus",
110
128
  parameters: { subscribe: false },
111
-
112
129
  onSuccess: (args) => {
113
130
  const types = Object.keys(args)
114
131
  .filter((key) => args[key].state === "connected")
@@ -116,7 +133,6 @@ export const getWebOSConnectionInfo = () => {
116
133
 
117
134
  resolve({ networkType: types });
118
135
  },
119
-
120
136
  onFailure: (error) => {
121
137
  console.error(
122
138
  "getWebOSConnectionInfo: There was an error getting connection info",
@@ -129,6 +145,10 @@ export const getWebOSConnectionInfo = () => {
129
145
  });
130
146
  };
131
147
 
148
+ /**
149
+ * Retrieves the connection info from Tizen.
150
+ * @returns {Promise<{networkType: string} | null>} A promise that resolves with the connection info or null.
151
+ */
132
152
  export const getTizenConnectionInfo = () => {
133
153
  return new Promise((resolve, reject) => {
134
154
  if (!isSamsungPlatform) {
@@ -1,7 +1,7 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`storageObject when the requested storage exists getAllItems returns all keys 1`] = `
4
- Object {
4
+ {
5
5
  "baz_::_foo": "baz",
6
6
  "baz_::_otherKey": "otherValue",
7
7
  "foo": "bar",
@@ -10,7 +10,7 @@ Object {
10
10
  `;
11
11
 
12
12
  exports[`storageObject when the requested storage exists getAllItems returns all keys 2`] = `
13
- Object {
13
+ {
14
14
  "baz_::_foo": "baz",
15
15
  "baz_::_otherKey": "otherValue",
16
16
  "foo": "bar",
@@ -19,43 +19,15 @@ Object {
19
19
  `;
20
20
 
21
21
  exports[`storageObject when the requested storage exists getAllItems returns all keys in the namespace if provided 1`] = `
22
- Object {
22
+ {
23
23
  "foo": "baz",
24
24
  "otherKey": "otherValue",
25
25
  }
26
26
  `;
27
27
 
28
28
  exports[`storageObject when the requested storage exists getAllItems returns all keys in the namespace if provided 2`] = `
29
- Object {
29
+ {
30
30
  "foo": "baz",
31
31
  "otherKey": "otherValue",
32
32
  }
33
33
  `;
34
-
35
- exports[`storageObject when the requested storage exists getItem gets properties from the storage 1`] = `"bar"`;
36
-
37
- exports[`storageObject when the requested storage exists getItem gets properties from the storage 2`] = `"bar"`;
38
-
39
- exports[`storageObject when the requested storage exists getItem gets properties from the storage 3`] = `"bar"`;
40
-
41
- exports[`storageObject when the requested storage exists getItem gets properties from the storage 4`] = `"bar"`;
42
-
43
- exports[`storageObject when the requested storage exists getItem gets properties from the storage with a namespace 1`] = `"baz"`;
44
-
45
- exports[`storageObject when the requested storage exists getItem gets properties from the storage with a namespace 2`] = `"baz"`;
46
-
47
- exports[`storageObject when the requested storage exists getItem rejects if the property cannot be retrieved 1`] = `[Error: Could not retrieve item applicaster.v2_::_fail_key]`;
48
-
49
- exports[`storageObject when the requested storage exists getItem rejects if the property cannot be retrieved 2`] = `[Error: Could not retrieve item applicaster.v2_::_fail_key]`;
50
-
51
- exports[`storageObject when the requested storage exists removeItem removes an item 1`] = `true`;
52
-
53
- exports[`storageObject when the requested storage exists removeItem removes an item 2`] = `true`;
54
-
55
- exports[`storageObject when the requested storage exists removeItem removes an item 3`] = `true`;
56
-
57
- exports[`storageObject when the requested storage exists removeItem removes an item 4`] = `true`;
58
-
59
- exports[`storageObject when the requested storage exists setItem will reject a promise if it the setting of the data fails 1`] = `[Error: Could not set item applicaster.v2_::_fail_key]`;
60
-
61
- exports[`storageObject when the requested storage exists setItem will reject a promise if it the setting of the data fails 2`] = `[Error: Could not set item applicaster.v2_::_fail_key]`;
@@ -4,7 +4,8 @@ import {
4
4
  applyNamespaceToKeyName,
5
5
  STORAGE_TYPES,
6
6
  DEFAULT_NAMESPACE,
7
- } from "../index";
7
+ } from "../";
8
+
8
9
  import { StorageMock } from "./StorageMocks";
9
10
 
10
11
  import * as functionUtils from "@applicaster/zapp-react-native-utils/functionUtils";
@@ -26,14 +27,7 @@ function clearStorage() {
26
27
  R.forEach((storage) => global.window[storage].clear(), STORAGE_TYPES);
27
28
  }
28
29
 
29
- async function testStorage(expectations) {
30
- await Promise.all(
31
- R.map((storage) => {
32
- const Storage = getStorageModule(storage);
33
- expectations(Storage);
34
- }, STORAGE_TYPES)
35
- );
36
- }
30
+ const storages = R.map((storage) => getStorageModule(storage), STORAGE_TYPES);
37
31
 
38
32
  describe("storageObject", () => {
39
33
  beforeEach(resetMocks);
@@ -48,143 +42,119 @@ describe("storageObject", () => {
48
42
 
49
43
  beforeEach(clearStorage);
50
44
 
51
- it("returns an object with 3 methods", () => {
52
- expect.assertions(6);
53
-
54
- testStorage((Storage) => {
55
- expect(Storage).toHaveProperty("setItem");
56
- expect(Storage).toHaveProperty("getItem");
57
- expect(Storage).toHaveProperty("getAllItems");
58
- });
45
+ it.each(storages)("returns an object with 3 methods", (storage) => {
46
+ expect(storage).toHaveProperty("setItem");
47
+ expect(storage).toHaveProperty("getItem");
48
+ expect(storage).toHaveProperty("getAllItems");
59
49
  });
60
50
 
61
51
  describe("setItem", () => {
62
52
  beforeEach(clearStorage);
63
53
 
64
- it("sets a property in the storage", async () => {
65
- expect.assertions(4);
54
+ it.each(storages)("sets a property in the storage", async (storage) => {
55
+ const result = await storage.setItem(key, value, null);
66
56
 
67
- await testStorage(async (Storage) => {
68
- const result = await Storage.setItem(key, value, null);
57
+ const keyWithDefaultNameSpace = applyNamespaceToKeyName(
58
+ key,
59
+ DEFAULT_NAMESPACE
60
+ );
69
61
 
70
- const keyWithDefaultNameSpace = applyNamespaceToKeyName(
71
- key,
72
- DEFAULT_NAMESPACE
73
- );
62
+ expect(result).toBe(true);
74
63
 
75
- expect(result).toBe(true);
76
- expect(Storage[keyWithDefaultNameSpace]).toEqual(value);
77
- });
64
+ expect(storage.getItem(keyWithDefaultNameSpace)).resolves.toEqual(
65
+ value
66
+ );
78
67
  });
79
68
 
80
- it("sets a property in the storage with a namespace", async () => {
81
- expect.assertions(4);
82
-
83
- await testStorage(async (Storage) => {
84
- const result = await Storage.setItem(key, namespaceValue, namespace);
69
+ it.each(storages)(
70
+ "sets a property in the storage with a namespace",
71
+ async (storage) => {
72
+ const result = await storage.setItem(key, namespaceValue, namespace);
85
73
 
86
74
  expect(result).toBe(true);
87
- expect(Storage[keyName]).toEqual(namespaceValue);
88
- });
89
- });
90
75
 
91
- it("will reject a promise if it the setting of the data fails", async () => {
92
- expect.assertions(2);
76
+ expect(storage.getItem(keyName)).resolves.toEqual(namespaceValue);
77
+ }
78
+ );
93
79
 
94
- await testStorage(async (Storage) => {
95
- await expect(
96
- Storage.setItem(failKey, value)
97
- ).rejects.toMatchSnapshot();
98
- });
99
- });
80
+ it.each(storages)(
81
+ "will reject a promise if it the setting of the data fails",
82
+ async (storage) => {
83
+ await expect(storage.setItem(failKey, value)).rejects.toThrow(
84
+ "Could not set item applicaster.v2_::_fail_key"
85
+ );
86
+ }
87
+ );
100
88
  });
101
89
 
102
90
  describe("getItem", () => {
103
91
  beforeEach(async () => {
104
92
  clearStorage();
105
93
 
106
- await testStorage(async (Storage) => {
94
+ storages.forEach((Storage) => {
107
95
  Storage.setItem(key, value, null);
108
96
  Storage.setItem(key, namespaceValue, namespace);
109
97
  });
110
98
  });
111
99
 
112
- it("gets properties from the storage", async () => {
113
- expect.assertions(8);
114
-
115
- await testStorage(async (Storage) => {
116
- await expect(Storage.getItem(key)).resolves.toEqual(value);
117
- await expect(Storage.getItem(key)).resolves.toMatchSnapshot();
118
- await expect(Storage.getItem(key, null)).resolves.toEqual(value);
119
- await expect(Storage.getItem(key, null)).resolves.toMatchSnapshot();
120
- });
100
+ it.each(storages)("gets properties from the storage", async (storage) => {
101
+ const result = await storage.getItem(key);
102
+ const resultWithNull = await storage.getItem(key, null);
103
+ expect(result).toEqual(value);
104
+ expect(resultWithNull).toEqual(value);
121
105
  });
122
106
 
123
- it("gets properties from the storage with a namespace", async () => {
124
- expect.assertions(4);
125
-
126
- await testStorage(async (Storage) => {
127
- await expect(Storage.getItem(key, namespace)).resolves.toEqual(
128
- namespaceValue
107
+ it.each(storages)(
108
+ "gets properties from the storage with a namespace",
109
+ (storage) => {
110
+ expect(storage.getItem(key, namespace)).resolves.toEqual(
111
+ "namespaceValue"
129
112
  );
113
+ }
114
+ );
130
115
 
131
- await expect(
132
- Storage.getItem(key, namespace)
133
- ).resolves.toMatchSnapshot();
134
- });
135
- });
136
-
137
- it("rejects if the property cannot be retrieved", async () => {
138
- expect.assertions(2);
139
-
140
- await testStorage(async (Storage) => {
141
- await expect(Storage.getItem(failKey)).rejects.toMatchSnapshot();
142
- });
143
- });
116
+ it.each(storages)(
117
+ "rejects if the property cannot be retrieved",
118
+ async (storage) => {
119
+ await expect(storage.getItem(failKey)).rejects.toThrow(
120
+ "Could not retrieve item applicaster.v2_::_fail_key"
121
+ );
122
+ }
123
+ );
144
124
  });
145
125
 
146
126
  describe("getAllItems", () => {
147
127
  beforeEach(async () => {
148
128
  clearStorage();
149
129
 
150
- await testStorage(async (Storage) => {
151
- await Storage.setItem(key, value);
152
- await Storage.setItem(key, namespaceValue, namespace);
153
- await Storage.setItem("otherKey", "otherValue");
154
- await Storage.setItem("otherKey", "otherValue", namespace);
130
+ storages.forEach((Storage) => {
131
+ Storage.setItem(key, value);
132
+ Storage.setItem(key, namespaceValue, namespace);
133
+ Storage.setItem("otherKey", "otherValue");
134
+ Storage.setItem("otherKey", "otherValue", namespace);
155
135
  });
156
136
  });
157
137
 
158
- it("returns all keys", async () => {
159
- expect.assertions(2);
160
-
161
- await testStorage(async (Storage) => {
162
- await expect(Storage.getAllItems()).resolves.toMatchSnapshot();
163
- });
138
+ it.each(storages)("returns all keys", async (Storage) => {
139
+ const res = await Storage.getAllItems();
140
+ expect(res).toMatchSnapshot();
164
141
  });
165
142
 
166
- it("returns all keys in the namespace if provided", async () => {
167
- expect.assertions(2);
168
-
169
- await testStorage(async (Storage) => {
143
+ it.each(storages)(
144
+ "returns all keys in the namespace if provided",
145
+ async (Storage) => {
170
146
  await expect(
171
147
  Storage.getAllItems(namespace)
172
148
  ).resolves.toMatchSnapshot();
173
- });
174
- });
149
+ }
150
+ );
175
151
  });
176
152
 
177
153
  describe("removeItem", () => {
178
- it("removes an item", async () => {
179
- expect.assertions(4);
180
-
181
- await testStorage(async (Storage) => {
182
- await expect(Storage.removeItem(key)).resolves.toMatchSnapshot();
154
+ it.each(storages)("removes an item", async (Storage) => {
155
+ await expect(Storage.removeItem(key)).resolves.toBeTruthy();
183
156
 
184
- await expect(
185
- Storage.removeItem(key, namespace)
186
- ).resolves.toMatchSnapshot();
187
- });
157
+ await expect(Storage.removeItem(key, namespace)).resolves.toBeTruthy();
188
158
  });
189
159
  });
190
160
  });
package/index.js CHANGED
@@ -1,13 +1,11 @@
1
1
  /// <reference types="@applicaster/applicaster-types" />
2
2
  import * as R from "ramda";
3
- import { useHistory, useLocation } from "react-router-dom";
4
3
 
5
4
  import { createQuickBrickApp } from "@applicaster/quick-brick-core";
6
5
  import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
7
6
  import * as Contexts from "@applicaster/zapp-react-native-ui-components/Contexts";
8
7
  import { OfflineHandler } from "@applicaster/zapp-react-native-ui-components/Components/OfflineHandler";
9
8
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
10
- import { ZappDomRouter } from "./App/Router";
11
9
  import { Layout } from "./App/Layout";
12
10
  import { SplashLoader } from "./App/Loader/SplashLoader";
13
11
  import { appLoader } from "./App/Loader";
@@ -24,11 +22,6 @@ const contextProviders = R.map(R.prop("withProvider"), R.values(Contexts));
24
22
  if (withXray) contextProviders.push(withXray);
25
23
 
26
24
  export const ZappApp = createQuickBrickApp({
27
- navigations: {
28
- Router: ZappDomRouter,
29
- useLocation,
30
- useHistory,
31
- },
32
25
  QuickBrickManager,
33
26
  Layout,
34
27
  OfflineHandler,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-dom-app",
3
- "version": "13.0.0-alpha.2635505531",
3
+ "version": "13.0.0-alpha.2685746452",
4
4
  "description": "Zapp App Component for Applicaster's Quick Brick React Native App",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,13 +22,12 @@
22
22
  },
23
23
  "homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
24
24
  "dependencies": {
25
- "@applicaster/zapp-react-dom-ui-components": "13.0.0-alpha.2635505531",
26
- "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.2635505531",
27
- "@applicaster/zapp-react-native-redux": "13.0.0-alpha.2635505531",
28
- "@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.2635505531",
29
- "@applicaster/zapp-react-native-utils": "13.0.0-alpha.2635505531",
25
+ "@applicaster/zapp-react-dom-ui-components": "13.0.0-alpha.2685746452",
26
+ "@applicaster/zapp-react-native-bridge": "13.0.0-alpha.2685746452",
27
+ "@applicaster/zapp-react-native-redux": "13.0.0-alpha.2685746452",
28
+ "@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.2685746452",
29
+ "@applicaster/zapp-react-native-utils": "13.0.0-alpha.2685746452",
30
30
  "abortcontroller-polyfill": "^1.7.5",
31
- "history": "^4.7.2",
32
31
  "react-router-dom": "^5.1.2",
33
32
  "typeface-montserrat": "^0.0.54",
34
33
  "video.js": "7.14.3",
@@ -36,9 +35,18 @@
36
35
  "videojs-contrib-quality-levels": "3.0.0"
37
36
  },
38
37
  "peerDependencies": {
38
+ "@applicaster/zapp-pipes-v2-client": "*",
39
+ "@react-native-community/netinfo": "*",
39
40
  "core-js": "3.29.1",
40
- "react": "17.0.2",
41
- "react-dom": "17.0.2",
42
- "react-native-web": "0.18.11"
41
+ "immer": "*",
42
+ "react": "*",
43
+ "react-dom": "*",
44
+ "react-native": "*",
45
+ "react-native-safe-area-context": "*",
46
+ "react-native-svg": "*",
47
+ "react-native-web": "*",
48
+ "uglify-js": "*",
49
+ "validate-color": "*",
50
+ "zustand": "*"
43
51
  }
44
52
  }
@@ -1,17 +0,0 @@
1
- import React from "react";
2
- import PropTypes from "prop-types";
3
-
4
- import { Router } from "react-router";
5
- import { createMemoryHistory } from "history";
6
-
7
- const history = createMemoryHistory();
8
-
9
- export const ZappDomRouter = ({ children, ...otherProps }) => (
10
- <Router history={history} {...otherProps}>
11
- {children}
12
- </Router>
13
- );
14
-
15
- ZappDomRouter.propTypes = {
16
- children: PropTypes.node.isRequired,
17
- };
@@ -1,30 +0,0 @@
1
- import React from "react";
2
-
3
- import "./spinner-styles.css";
4
-
5
- export const Spinner = (color) => {
6
- const spinnerColor = {
7
- background: color.color,
8
- };
9
-
10
- return (
11
- <div>
12
- <div id="progress">
13
- <div className="spinner">
14
- <div style={spinnerColor} className="bar1" />
15
- <div style={spinnerColor} className="bar2" />
16
- <div style={spinnerColor} className="bar3" />
17
- <div style={spinnerColor} className="bar4" />
18
- <div style={spinnerColor} className="bar5" />
19
- <div style={spinnerColor} className="bar6" />
20
- <div style={spinnerColor} className="bar7" />
21
- <div style={spinnerColor} className="bar8" />
22
- <div style={spinnerColor} className="bar9" />
23
- <div style={spinnerColor} className="bar10" />
24
- <div style={spinnerColor} className="bar11" />
25
- <div style={spinnerColor} className="bar12" />
26
- </div>
27
- </div>
28
- </div>
29
- );
30
- };
@@ -1,81 +0,0 @@
1
- div.spinner {
2
- position: absolute;
3
- width: 100px;
4
- height: 100px;
5
- display: inline-block;
6
- top: 50%;
7
- left: 50%;
8
- margin: -60px 0 0 -70px;
9
- }
10
-
11
- div.spinner div {
12
- width: 6%;
13
- height: 16%;
14
- position: absolute;
15
- left: 49%;
16
- top: 43%;
17
- opacity: 0;
18
- -webkit-border-radius: 50px;
19
- -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
20
- -webkit-animation: fade 1s linear infinite;
21
- }
22
-
23
- @-webkit-keyframes fade {
24
- from {
25
- opacity: 1;
26
- }
27
- to {
28
- opacity: 0.25;
29
- }
30
- }
31
-
32
- div.spinner div.bar1 {
33
- -webkit-transform: rotate(0deg) translate(0, -130%);
34
- -webkit-animation-delay: 0s;
35
- }
36
-
37
- div.spinner div.bar2 {
38
- -webkit-transform: rotate(30deg) translate(0, -130%);
39
- -webkit-animation-delay: -0.9167s;
40
- }
41
-
42
- div.spinner div.bar3 {
43
- -webkit-transform: rotate(60deg) translate(0, -130%);
44
- -webkit-animation-delay: -0.833s;
45
- }
46
- div.spinner div.bar4 {
47
- -webkit-transform: rotate(90deg) translate(0, -130%);
48
- -webkit-animation-delay: -0.7497s;
49
- }
50
- div.spinner div.bar5 {
51
- -webkit-transform: rotate(120deg) translate(0, -130%);
52
- -webkit-animation-delay: -0.667s;
53
- }
54
- div.spinner div.bar6 {
55
- -webkit-transform: rotate(150deg) translate(0, -130%);
56
- -webkit-animation-delay: -0.5837s;
57
- }
58
- div.spinner div.bar7 {
59
- -webkit-transform: rotate(180deg) translate(0, -130%);
60
- -webkit-animation-delay: -0.5s;
61
- }
62
- div.spinner div.bar8 {
63
- -webkit-transform: rotate(210deg) translate(0, -130%);
64
- -webkit-animation-delay: -0.4167s;
65
- }
66
- div.spinner div.bar9 {
67
- -webkit-transform: rotate(240deg) translate(0, -130%);
68
- -webkit-animation-delay: -0.333s;
69
- }
70
- div.spinner div.bar10 {
71
- -webkit-transform: rotate(270deg) translate(0, -130%);
72
- -webkit-animation-delay: -0.2497s;
73
- }
74
- div.spinner div.bar11 {
75
- -webkit-transform: rotate(300deg) translate(0, -130%);
76
- -webkit-animation-delay: -0.167s;
77
- }
78
- div.spinner div.bar12 {
79
- -webkit-transform: rotate(330deg) translate(0, -130%);
80
- -webkit-animation-delay: -0.0833s;
81
- }