@applicaster/zapp-react-dom-app 12.0.0-alpha.3977160850 → 12.0.0-alpha.4043183114

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.
@@ -31,14 +31,23 @@ import {
31
31
  import { PlayerContentContext } from "@applicaster/zapp-react-dom-ui-components/Contexts";
32
32
 
33
33
  import { withNavigator } from "@applicaster/zapp-react-native-ui-components/Decorators/Navigator";
34
- import { Platform } from "react-native";
35
34
  import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
36
35
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
37
36
  import { confirmationDialogStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ConfirmDialogState";
37
+ import {
38
+ isVizioPlatform,
39
+ isSamsungPlatform,
40
+ isLgPlatform,
41
+ } from "@applicaster/zapp-react-native-utils/reactUtils";
42
+
43
+ import { OnScreenKeyboard } from "@applicaster/zapp-react-dom-ui-components/Components/OnScreenKeyboard";
38
44
 
39
45
  const { withXray } = getXray();
40
46
  const globalAny: any = global;
41
47
 
48
+ const shouldUseOnScreenKeyboard = () =>
49
+ isVizioPlatform() || window.applicaster.useOnScreenKeyboard;
50
+
42
51
  type Props = {
43
52
  displayState: string;
44
53
  setDisplayState: (state: string) => void;
@@ -56,7 +65,7 @@ type Props = {
56
65
  };
57
66
  };
58
67
 
59
- type State = { isKeyboardVisible: boolean };
68
+ type State = { isKeyboardVisible: boolean; keyboardInput: string };
60
69
 
61
70
  type KeyCode = { code: string; keyCode: number | string };
62
71
 
@@ -76,6 +85,7 @@ export function withInteractionManager(Component: React.FC) {
76
85
  sequenceTimeout: NodeJS.Timeout | null; // timeoutID
77
86
  userSequence: number[] = [];
78
87
  confirmDialog: any;
88
+ isDismissing = false;
79
89
 
80
90
  constructor(props) {
81
91
  super(props);
@@ -84,6 +94,7 @@ export function withInteractionManager(Component: React.FC) {
84
94
 
85
95
  this.state = {
86
96
  isKeyboardVisible: false,
97
+ keyboardInput: "",
87
98
  };
88
99
 
89
100
  this.onMouseMoveListener = debounce({
@@ -116,6 +127,10 @@ export function withInteractionManager(Component: React.FC) {
116
127
  this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
117
128
  this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
118
129
  this.performExit = this.performExit.bind(this);
130
+ this.handleInputFocus = this.handleInputFocus.bind(this);
131
+ this.handleInputBlur = this.handleInputBlur.bind(this);
132
+ this.handleKeyboardInput = this.handleKeyboardInput.bind(this);
133
+ this.handleKeyboardDismiss = this.handleKeyboardDismiss.bind(this);
119
134
 
120
135
  this.confirmDialog.setConfirmAction(this.performExit);
121
136
  this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
@@ -138,6 +153,8 @@ export function withInteractionManager(Component: React.FC) {
138
153
  false
139
154
  );
140
155
 
156
+ document.addEventListener("focusin", this.handleInputFocus);
157
+
141
158
  document.addEventListener(
142
159
  "cursorStateChange",
143
160
  this.cursorVisibilityChange,
@@ -155,28 +172,31 @@ export function withInteractionManager(Component: React.FC) {
155
172
  this.cursorVisibilityChange
156
173
  );
157
174
 
158
- document.removeEventListener(
159
- "keyboardStateChange",
160
- this.onKeyboardStateChange
161
- );
175
+ document.removeEventListener("focusin", this.handleInputFocus);
162
176
 
163
177
  document.removeEventListener("mousedown", this.onMouseDownListener);
164
178
 
165
179
  if (this.timeout) {
166
180
  this.clearTimeout();
167
181
  }
182
+
183
+ this.isDismissing = false;
168
184
  }
169
185
 
170
186
  performExit() {
171
- if (Platform.OS === ("samsung_tv" as QuickBrickPlatforms)) {
187
+ if (isSamsungPlatform()) {
172
188
  this.onConfirmDialogClose();
173
189
  sendQuickBrickEvent(QUICK_BRICK_EVENTS.MOVE_APP_TO_BACKGROUND);
174
190
  }
175
191
 
176
- if (Platform.OS === ("lg_tv" as QuickBrickPlatforms)) {
192
+ if (isLgPlatform()) {
177
193
  // webOS recommend to use this method when implemention a custom exit
178
194
  globalAny.close();
179
195
  }
196
+
197
+ if (isVizioPlatform()) {
198
+ window?.VIZIO?.exitApplication();
199
+ }
180
200
  }
181
201
 
182
202
  handleWebOsBack() {
@@ -205,7 +225,7 @@ export function withInteractionManager(Component: React.FC) {
205
225
  platformBack() {
206
226
  try {
207
227
  // TODO: temporary hack until this code is refactored
208
- if (Platform.OS === ("samsung_tv" as QuickBrickPlatforms)) {
228
+ if (isSamsungPlatform() || isVizioPlatform()) {
209
229
  const { isDialogVisible } = confirmationDialogStore.getState();
210
230
 
211
231
  if (isDialogVisible) {
@@ -218,7 +238,7 @@ export function withInteractionManager(Component: React.FC) {
218
238
  cancelCompletion: this.onConfirmDialogClose,
219
239
  });
220
240
  }
221
- } else if (Platform.OS === ("lg_tv" as QuickBrickPlatforms)) {
241
+ } else if (isLgPlatform()) {
222
242
  this.handleWebOsBack();
223
243
  }
224
244
  } catch (e) {
@@ -441,6 +461,7 @@ export function withInteractionManager(Component: React.FC) {
441
461
 
442
462
  onKeyDown(event) {
443
463
  const { displayState, setDisplayState, navigator } = this.props;
464
+ const { isKeyboardVisible } = this.state;
444
465
 
445
466
  const { isDialogVisible } = confirmationDialogStore.getState();
446
467
 
@@ -451,6 +472,16 @@ export function withInteractionManager(Component: React.FC) {
451
472
  }, LONG_KEY_PRESS_TIMEOUT);
452
473
  }
453
474
 
475
+ if (isKeyboardVisible && shouldUseOnScreenKeyboard()) {
476
+ if (keyCode(event).matchesAny("Escape", "Back")) {
477
+ event.preventDefault();
478
+ event.stopPropagation();
479
+ this.handleKeyboardDismiss();
480
+
481
+ return;
482
+ }
483
+ }
484
+
454
485
  /**
455
486
  When the player is displayed, we listen to Native Play / Pause / Stop
456
487
  buttons. Any other key press will display the transport controls
@@ -567,7 +598,7 @@ export function withInteractionManager(Component: React.FC) {
567
598
  }
568
599
 
569
600
  if (keyCode(event).matches(KEYS.Exit)) {
570
- if (Platform.OS === ("samsung_tv" as QuickBrickPlatforms)) {
601
+ if (isSamsungPlatform() || shouldUseOnScreenKeyboard()) {
571
602
  this.performExit();
572
603
 
573
604
  return;
@@ -592,6 +623,12 @@ export function withInteractionManager(Component: React.FC) {
592
623
  focusManager.moveFocus(direction);
593
624
  }
594
625
 
626
+ if (!isDialogVisible) {
627
+ // run focus recovery on user interaction attempt
628
+ // probably we failed to set initial focus for some reason
629
+ focusManager.recoverFocus();
630
+ }
631
+
595
632
  if (
596
633
  displayState === DISPLAY_STATES.PLAYER ||
597
634
  displayState === DISPLAY_STATES.HUD
@@ -616,11 +653,9 @@ export function withInteractionManager(Component: React.FC) {
616
653
  };
617
654
 
618
655
  if (deltaY > 0) {
619
- DIRECTION.value =
620
- Platform.OS === ("lg_tv" as QuickBrickPlatforms) ? "down" : "up";
656
+ DIRECTION.value = isLgPlatform() ? "down" : "up";
621
657
  } else if (deltaY < 0) {
622
- DIRECTION.value =
623
- Platform.OS === ("lg_tv" as QuickBrickPlatforms) ? "up" : "down";
658
+ DIRECTION.value = isLgPlatform() ? "up" : "down";
624
659
  }
625
660
 
626
661
  if (
@@ -656,10 +691,76 @@ export function withInteractionManager(Component: React.FC) {
656
691
 
657
692
  onConfirmDialogClose() {
658
693
  this.confirmDialog.hideDialog();
694
+
695
+ // restore initial focus after closing dialog
696
+ focusManager.setInitialFocus();
697
+ }
698
+
699
+ handleInputFocus = (event: FocusEvent) => {
700
+ if (!shouldUseOnScreenKeyboard()) return;
701
+ const target = event.target as HTMLElement;
702
+
703
+ if (this.isDismissing) {
704
+ return;
705
+ }
706
+
707
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
708
+ this.setState({
709
+ isKeyboardVisible: true,
710
+ keyboardInput: (target as HTMLInputElement).value || "",
711
+ });
712
+ }
713
+ };
714
+
715
+ handleInputBlur(event: FocusEvent) {
716
+ if (!shouldUseOnScreenKeyboard()) return;
717
+
718
+ const target = event.target as HTMLElement;
719
+
720
+ if (target.tagName === "INPUT" || target.tagName === "TEXTAREA") {
721
+ const relatedTarget = event.relatedTarget as HTMLElement;
722
+
723
+ if (
724
+ !relatedTarget ||
725
+ (relatedTarget.tagName !== "INPUT" &&
726
+ relatedTarget.tagName !== "TEXTAREA")
727
+ ) {
728
+ this.setState({ isKeyboardVisible: false });
729
+ }
730
+ }
731
+ }
732
+
733
+ handleKeyboardDismiss = () => {
734
+ this.isDismissing = true;
735
+
736
+ this.setState(
737
+ {
738
+ isKeyboardVisible: false,
739
+ keyboardInput: "",
740
+ },
741
+ () => {
742
+ this.isDismissing = false;
743
+ }
744
+ );
745
+ };
746
+
747
+ handleKeyboardInput(value: string) {
748
+ this.setState({ keyboardInput: value });
659
749
  }
660
750
 
661
751
  render() {
662
- return <Component {...this.props} />;
752
+ return (
753
+ <>
754
+ <Component {...this.props} />
755
+ {shouldUseOnScreenKeyboard() && this.state.isKeyboardVisible && (
756
+ <OnScreenKeyboard
757
+ initialValue={this.state.keyboardInput}
758
+ onInput={this.handleKeyboardInput}
759
+ onDismiss={this.handleKeyboardDismiss}
760
+ />
761
+ )}
762
+ </>
763
+ );
663
764
  }
664
765
  }
665
766
 
@@ -1,7 +1,7 @@
1
- // @flow
2
1
  /* global tizen */
3
2
  import * as React from "react";
4
3
  import * as R from "ramda";
4
+ import PropTypes from "prop-types";
5
5
 
6
6
  import { connectToStore } from "@applicaster/zapp-react-native-redux";
7
7
  import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
@@ -9,17 +9,12 @@ import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickB
9
9
  import { QuickBrickEvents } from "../../Polyfills/QuickBrickCommunicationModule";
10
10
  import { Splash } from "../Splash";
11
11
 
12
- type Props = {
13
- appLaunched: boolean,
14
- children: any,
15
- };
16
-
17
12
  const getAppLaunched = R.compose(
18
13
  R.assoc("appLaunched", R.__, {}),
19
14
  R.path(["appState", "appLaunched"])
20
15
  );
21
16
 
22
- class SplashHandler extends React.Component<Props> {
17
+ class SplashHandler extends React.Component {
23
18
  constructor(props) {
24
19
  super(props);
25
20
 
@@ -76,6 +71,12 @@ class SplashHandler extends React.Component<Props> {
76
71
  }
77
72
  }
78
73
 
74
+ SplashHandler.propTypes = {
75
+ appLaunched: PropTypes.bool.isRequired,
76
+ children: PropTypes.node.isRequired,
77
+ };
78
+
79
+ SplashHandler.shouldShowSplash = true;
79
80
  SplashHandler.shouldShowSplash = true;
80
81
 
81
82
  export const SplashLoader = connectToStore(getAppLaunched)(SplashHandler);
@@ -8,11 +8,7 @@ export const appLoaderImpl =
8
8
  ) =>
9
9
  async (dispatch, getState) => {
10
10
  try {
11
- const {
12
- plugins,
13
- pluginConfigurations,
14
- remoteConfigurations: { localizations },
15
- } = getState();
11
+ const { plugins, pluginConfigurations } = getState();
16
12
 
17
13
  // Await crucial tasks
18
14
  await loadLocale();
@@ -20,7 +16,7 @@ export const appLoaderImpl =
20
16
  await loadAnalyticsPlugins(plugins, pluginConfigurations);
21
17
 
22
18
  // Remaining loaders
23
- const loaders = [loadDomPlugins(plugins), setUpRTL(localizations)];
19
+ const loaders = [loadDomPlugins(plugins), setUpRTL()];
24
20
 
25
21
  // Await for the remaining tasks and return when they are all complete
26
22
  await Promise.all(loaders);
@@ -1,4 +1,3 @@
1
- // @flow
2
1
  import * as R from "ramda";
3
2
  import { NativeModules } from "react-native";
4
3
  import uuidv4 from "uuid/v4";
@@ -1,7 +1,7 @@
1
- import { getIsRTLFromLocalizations } from "@applicaster/zapp-react-native-utils/localizationUtils";
1
+ import { getIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
2
2
  import { I18nManager } from "react-native";
3
3
 
4
- export async function setUpRTL(localizations) {
5
- const isRTL = getIsRTLFromLocalizations(localizations);
4
+ export async function setUpRTL() {
5
+ const isRTL = getIsRTL();
6
6
  I18nManager.forceRTL(isRTL);
7
7
  }
@@ -26,7 +26,6 @@ describe("getLanguageCode", () => {
26
26
 
27
27
  // verify
28
28
  expect(result).toEqual(locale);
29
- expect(setLanguageCodeToLocalStorage).toHaveBeenCalledWith(locale);
30
29
  });
31
30
 
32
31
  it("return value from local-storage", async () => {
@@ -62,6 +62,9 @@ export const PLATFORMS = {
62
62
  iphone: "iPhone",
63
63
  android: "Android",
64
64
  mobile: "Mobile",
65
+ vizio: "VIZIO",
66
+ smartcast: "SmartCast",
67
+ conjure: "Conjure",
65
68
  };
66
69
 
67
70
  /**
@@ -8,7 +8,7 @@ export const getLanguageCodeFromLocalStorage = () => {
8
8
  return NativeModules.LocalStorage.getItem(UI_LANGUAGE);
9
9
  };
10
10
 
11
- export const setLanguageCodeToLocalStorage = async (languageCode) => {
11
+ export const persistLanguageSelection = async (languageCode) => {
12
12
  await NativeModules.SessionStorage.setItem(UI_LANGUAGE, languageCode);
13
13
 
14
14
  return NativeModules.LocalStorage.setItem(UI_LANGUAGE, languageCode);
@@ -61,32 +61,34 @@ export const getLanguageCodeImpl =
61
61
  (
62
62
  GetLanguageCodeFromLocalStorage,
63
63
  GetAvailableAppLanguages,
64
- PickBestMatchedLanguage,
65
- SetLanguageCodeToLocalStorage
64
+ PickBestMatchedLanguage
66
65
  ) =>
67
66
  async (locale) => {
68
67
  const languageFromLocalStorage = await GetLanguageCodeFromLocalStorage();
69
68
 
70
69
  if (languageFromLocalStorage) {
71
70
  return languageFromLocalStorage;
72
- } else {
73
- const availableAppLanguages = GetAvailableAppLanguages();
71
+ }
74
72
 
75
- const pickedLanguage = PickBestMatchedLanguage(
76
- locale,
77
- availableAppLanguages
78
- );
73
+ const availableAppLanguages = GetAvailableAppLanguages();
79
74
 
80
- await SetLanguageCodeToLocalStorage(pickedLanguage);
75
+ const pickedLanguage = PickBestMatchedLanguage(
76
+ locale,
77
+ availableAppLanguages
78
+ );
81
79
 
82
- return pickedLanguage;
83
- }
80
+ return pickedLanguage;
84
81
  };
85
82
 
86
83
  /**
87
- * Supported platforms: [Samsung] TODO: LG
88
- * This function is adding languageLocale and countryLocale to the QuickBrickCommunicationModule
89
- * @return Promise
84
+ /**
85
+ * Loads and sets locale-related information in the QuickBrickCommunicationModule.
86
+ * This function adds uiLanguage, countryLocale, languageLocale, and languageCode to the module.
87
+ *
88
+ * @param {Function} GetLocale - Function to retrieve the current locale.
89
+ * @param {Function} GetLanguageCode - Function to determine the language code based on available languages.
90
+ * @param {Object} quickBrickCommunicationModule - The module to be updated with locale information.
91
+ * @returns {Promise<Function>} An async function that loads and sets the locale information.
90
92
  * Warning! This function mutates QuickBrickCommunicationModule
91
93
  */
92
94
  export const loadLocaleImpl =
@@ -101,14 +103,13 @@ export const loadLocaleImpl =
101
103
  quickBrickCommunicationModule.countryLocale = R.toUpper(countryLocale);
102
104
  }
103
105
 
104
- // setup languageCode
105
106
  const languageCode = await GetLanguageCode(locale);
106
107
  quickBrickCommunicationModule.languageCode = languageCode;
108
+ quickBrickCommunicationModule.uiLanguage = languageCode;
107
109
  };
108
110
 
109
111
  export const getLanguageCode = getLanguageCodeImpl(
110
112
  getLanguageCodeFromLocalStorage,
111
113
  getAvailableAppLanguages,
112
- pickBestMatchedLanguage,
113
- setLanguageCodeToLocalStorage
114
+ pickBestMatchedLanguage
114
115
  );
@@ -1,4 +1,3 @@
1
- // @flow
2
1
  /* global webOS */
3
2
  /* global tizen */
4
3
  /* eslint-disable no-console */
@@ -12,11 +11,28 @@ import {
12
11
  PLATFORMS,
13
12
  } from "./const";
14
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
+ */
15
23
  export const getUserAgent = () =>
16
24
  window?.navigator?.userAgent || global?.navigator?.userAgent;
17
25
 
26
+ /**
27
+ * Checks if the device is HD (1280 width).
28
+ * @returns {boolean} True if the device is HD, false otherwise.
29
+ */
18
30
  export const isHD = () => window.innerWidth === 1280;
19
31
 
32
+ /**
33
+ * Checks if the platform is LG.
34
+ * @returns {boolean} True if the platform is LG, false otherwise.
35
+ */
20
36
  export const isLgPlatform = () => {
21
37
  const userAgent = getUserAgent();
22
38
 
@@ -24,10 +40,13 @@ export const isLgPlatform = () => {
24
40
  return false;
25
41
  }
26
42
 
27
- // Note: LG uses the number 0 in their userAgent, possibly because of Palm WebOS
28
43
  return hasWebOS || userAgent.includes(PLATFORMS.webos);
29
44
  };
30
45
 
46
+ /**
47
+ * Checks if the platform is Samsung.
48
+ * @returns {boolean} True if the platform is Samsung, false otherwise.
49
+ */
31
50
  export const isSamsungPlatform = () => {
32
51
  const userAgent = getUserAgent();
33
52
 
@@ -43,12 +62,39 @@ export const isSamsungPlatform = () => {
43
62
  };
44
63
 
45
64
  /**
46
- * platformSelect can't be used, because Platform.OS is overriden
47
- * by overloadReactNativePlatform and don't support 'web' value
48
- * @returns {"tv" | "web" | "other"} value
65
+ * Checks if the platform is Vizio by using the user agent string.
66
+ * @returns {boolean} True if the platform is Vizio, false otherwise.
67
+ */
68
+ export const isVizioPlatform = () => {
69
+ const userAgent = getUserAgent();
70
+
71
+ return (
72
+ userAgent.includes(PLATFORMS.vizio) ||
73
+ userAgent.includes(PLATFORMS.smartcast) ||
74
+ userAgent.includes(PLATFORMS.conjure)
75
+ );
76
+ };
77
+
78
+ /**
79
+ * Checks if the Vizio APIs are available.
80
+ * @returns {boolean} True if the Vizio APIs are available, false otherwise.
81
+ */
82
+ export const hasVizioAPIs = () => {
83
+ return (
84
+ typeof window.VIZIO !== "undefined" &&
85
+ window?.applicaster?.vizioLibraryDidLoad
86
+ );
87
+ };
88
+
89
+ /**
90
+ * Determines the device type based on the platform.
91
+ * @returns {DeviceType} The device type ("tv", "web", or "other").
49
92
  */
50
93
  export const getDeviceType = () => {
51
- switch (Platform.OS) {
94
+ /** @type {CustomPlatformTypes} */
95
+ const platformOS = Platform.OS;
96
+
97
+ switch (platformOS) {
52
98
  case "samsung_tv":
53
99
  return isSamsungPlatform() ? "tv" : "web";
54
100
  case "lg_tv":
@@ -59,14 +105,15 @@ export const getDeviceType = () => {
59
105
  };
60
106
 
61
107
  /**
62
- * This function is used to rename keys
63
- * @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.
64
111
  */
65
112
  export const renameKeys = (key) => desiredKeysMap?.[key] || key;
66
113
 
67
114
  /**
68
- * This function is used to get the connection info from WebOS
69
- * 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.
70
117
  */
71
118
  export const getWebOSConnectionInfo = () => {
72
119
  return new Promise((resolve, reject) => {
@@ -79,7 +126,6 @@ export const getWebOSConnectionInfo = () => {
79
126
  webOS.service.request("luna://com.palm.connectionmanager", {
80
127
  method: "getStatus",
81
128
  parameters: { subscribe: false },
82
-
83
129
  onSuccess: (args) => {
84
130
  const types = Object.keys(args)
85
131
  .filter((key) => args[key].state === "connected")
@@ -87,7 +133,6 @@ export const getWebOSConnectionInfo = () => {
87
133
 
88
134
  resolve({ networkType: types });
89
135
  },
90
-
91
136
  onFailure: (error) => {
92
137
  console.error(
93
138
  "getWebOSConnectionInfo: There was an error getting connection info",
@@ -100,6 +145,10 @@ export const getWebOSConnectionInfo = () => {
100
145
  });
101
146
  };
102
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
+ */
103
152
  export const getTizenConnectionInfo = () => {
104
153
  return new Promise((resolve, reject) => {
105
154
  if (!isSamsungPlatform) {
@@ -253,6 +302,24 @@ export const getDeviceData = async () => {
253
302
  ...tizenConnectionInfo,
254
303
  device_type: getDeviceType(),
255
304
  };
305
+ } else if (isVizioPlatform()) {
306
+ deviceData = {
307
+ ...deviceData,
308
+ platform: "vizio",
309
+ deviceMake: "Vizio",
310
+ deviceType: "tv",
311
+ userAgent: getUserAgent(),
312
+ deviceWidth: window.innerWidth,
313
+ deviceHeight: window.innerHeight,
314
+ };
315
+
316
+ if (hasVizioAPIs()) {
317
+ window.VIZIO.getFirmwareVersion(function (firmwareVersion) {
318
+ deviceData.osVersion = firmwareVersion;
319
+ });
320
+
321
+ deviceData.deviceModel = window.VIZIO.deviceModel;
322
+ }
256
323
  }
257
324
 
258
325
  return deviceData;
@@ -1,18 +1,17 @@
1
- // @flow
2
-
3
1
  import React from "react";
2
+ import PropTypes from "prop-types";
4
3
 
5
4
  import { Router } from "react-router";
6
5
  import { createMemoryHistory } from "history";
7
6
 
8
- type Props = {
9
- children: any,
10
- };
11
-
12
7
  const history = createMemoryHistory();
13
8
 
14
- export const ZappDomRouter = ({ children, ...otherProps }: Props) => (
9
+ export const ZappDomRouter = ({ children, ...otherProps }) => (
15
10
  <Router history={history} {...otherProps}>
16
11
  {children}
17
12
  </Router>
18
13
  );
14
+
15
+ ZappDomRouter.propTypes = {
16
+ children: PropTypes.node.isRequired,
17
+ };
@@ -1,4 +1,3 @@
1
- // @flow
2
1
  import React from "react";
3
2
 
4
3
  import "./spinner-styles.css";
@@ -1,13 +1,10 @@
1
- // @flow
2
1
  import React from "react";
3
2
 
4
- import { verifyAssets } from "@applicaster/zapp-react-dom-ui-components/Helpers/protectHelper";
3
+ import PropTypes from "prop-types";
5
4
 
6
- type Props = {
7
- remoteConfigurations: any,
8
- };
5
+ import { verifyAssets } from "@applicaster/zapp-react-dom-ui-components/Helpers/protectHelper";
9
6
 
10
- export const SplashComponent = ({ remoteConfigurations }: Props) => {
7
+ export const SplashComponent = ({ remoteConfigurations }) => {
11
8
  const image = verifyAssets(remoteConfigurations.assets, [
12
9
  "universal",
13
10
  "splash",
@@ -19,3 +16,9 @@ export const SplashComponent = ({ remoteConfigurations }: Props) => {
19
16
  </div>
20
17
  );
21
18
  };
19
+
20
+ SplashComponent.propTypes = {
21
+ remoteConfigurations: PropTypes.shape({
22
+ assets: PropTypes.object.isRequired,
23
+ }).isRequired,
24
+ };
@@ -105,7 +105,11 @@ function isInvalidAnalyticsData(eventName, payload = null) {
105
105
 
106
106
  export const AnalyticsBridge = (function () {
107
107
  let registeredAnalyticPlugins: {
108
- module: { sendEvent: Function; initialize?: Function };
108
+ module: {
109
+ sendEvent: Function;
110
+ initialize?: Function;
111
+ getPlayerConfiguration?: Function;
112
+ };
109
113
  configuration?: any;
110
114
  }[] = [];
111
115
 
@@ -8,4 +8,5 @@ export enum STORAGE {
8
8
  export enum STORE_PLATFORM {
9
9
  lg = "lg_content_store",
10
10
  samsung = "samsung_app_store",
11
+ vizio = "vizio_app_store",
11
12
  }
@@ -0,0 +1,225 @@
1
+ const mockPersistLanguageSelection = jest.fn();
2
+
3
+ jest.mock("../../../App/Loader/utils", () => ({
4
+ persistLanguageSelection: mockPersistLanguageSelection,
5
+ }));
6
+
7
+ const mockGetAppData = jest.fn();
8
+
9
+ jest.mock("../../AppData", () => ({
10
+ getAppData: mockGetAppData,
11
+ }));
12
+
13
+ jest.mock("@applicaster/zapp-react-native-bridge/QuickBrick", () => ({
14
+ QUICK_BRICK_EVENTS: {
15
+ QUICK_BRICK_READY: "QUICK_BRICK_READY",
16
+ FORCE_APP_RELOAD: "FORCE_APP_RELOAD",
17
+ },
18
+ }));
19
+
20
+ const mocked_storage = {
21
+ "applicaster.v2_::_uiLanguage": "en-UK",
22
+ };
23
+
24
+ global.window.location = {
25
+ reload: jest.fn(),
26
+ };
27
+
28
+ global.window.localStorage = {
29
+ getItem: jest.fn((key) => mocked_storage[key] || null),
30
+ setItem: jest.fn((key, value) => {
31
+ mocked_storage[key] = value;
32
+ }),
33
+ removeItem: jest.fn((key) => {
34
+ delete mocked_storage[key];
35
+ }),
36
+ clear: jest.fn(),
37
+ length: 1,
38
+ key: jest.fn(),
39
+ };
40
+
41
+ const BASE_MOCK_APP_DATA = {
42
+ accountsAccountId: "abcid123",
43
+ appFamilyId: 1710,
44
+ appName: "App.TV",
45
+ buildVersion: 247,
46
+ bundleIdentifier: "com.bundleIdentifier",
47
+ deviceTarget: "samsung_tv",
48
+ languages: ["en", "en-US", "fr", "fr-FR"],
49
+ locale: "en",
50
+ quickBrickVersion: "11.1.13",
51
+ quickBrickEvent: () => {},
52
+ setAppLanguage: () => {},
53
+ initialProps: {},
54
+ riversConfigurationId: "riverid123",
55
+ sdkVersion: "1.0.0",
56
+ store: "samsung",
57
+ urlSchemePrefix: "app-tv",
58
+ versionId: "version1233",
59
+ versionName: "1.0.8",
60
+ bver: "1.0.8",
61
+ os_type: "web",
62
+ platform: "samsung_tv",
63
+ };
64
+
65
+ const getMockAppData = (overrides = {}) => ({
66
+ ...BASE_MOCK_APP_DATA,
67
+ ...overrides,
68
+ });
69
+
70
+ describe("QuickBrickCommunicationModule Polyfill", () => {
71
+ let originalWindow;
72
+ let QuickBrickModule;
73
+ let mockAppData;
74
+
75
+ beforeEach(() => {
76
+ jest.resetModules();
77
+ originalWindow = global.window;
78
+
79
+ // Get fresh mockAppData for each test
80
+ mockAppData = getMockAppData();
81
+ mockGetAppData.mockReturnValue(mockAppData);
82
+
83
+ window.localStorage.getItem.mockClear();
84
+ window.localStorage.setItem.mockClear();
85
+ window.localStorage.removeItem.mockClear();
86
+ window.localStorage.clear.mockClear();
87
+
88
+ QuickBrickModule = require("../index");
89
+ });
90
+
91
+ afterEach(() => {
92
+ global.window = originalWindow;
93
+ jest.clearAllMocks();
94
+ });
95
+
96
+ describe("getMatchingLanguageFromBuildData", () => {
97
+ it("should return default locale (en) if there are no languages listed in build time parameters", () => {
98
+ window.localStorage.getItem.mockReturnValue(undefined);
99
+ global.window.navigator.language = "ru-RU";
100
+ mockGetAppData.mockReturnValue(getMockAppData({ languages: null }));
101
+
102
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
103
+
104
+ expect(result).toEqual({
105
+ uiLanguage: "en",
106
+ languageCode: "en",
107
+ countryLocale: "",
108
+ languageLocale: "en",
109
+ });
110
+ });
111
+
112
+ it("should fallback to default language if browser / device locale (en-UK) does not match list of supported languages", () => {
113
+ // localizations: ["en", "en-US", "fr", "fr-FR"], device_language: en, device_region: UK -> ui: en, language: en, region: UK
114
+
115
+ global.window.navigator.language = "en-UK";
116
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
117
+
118
+ expect(result).toEqual({
119
+ uiLanguage: "en",
120
+ languageCode: "en",
121
+ countryLocale: "",
122
+ languageLocale: "en",
123
+ });
124
+ });
125
+
126
+ it("should use browser / device locale (en-US) when it matches one of the supported languages", () => {
127
+ // localizations: ["en", "en-US", "fr", "fr-FR"], device_language: en, device_region: US -> ui: en-US, language: en, region: US
128
+
129
+ global.window.navigator.language = "en-US";
130
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
131
+
132
+ expect(result).toEqual({
133
+ uiLanguage: "en-US",
134
+ languageCode: "en",
135
+ countryLocale: "US",
136
+ languageLocale: "en-US",
137
+ });
138
+ });
139
+
140
+ it("should fallback to default language if browser / device locale (ru-RU) does not match list of supported languages", () => {
141
+ // localizations: ["en", "en-US", "fr", "fr-FR"], device_language: ru, device_region: RU -> ui: en, language: en, region: ""
142
+ global.window.navigator.language = "ru-RU";
143
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
144
+
145
+ expect(result).toEqual({
146
+ uiLanguage: "en",
147
+ languageCode: "en",
148
+ countryLocale: "",
149
+ languageLocale: "en",
150
+ });
151
+ });
152
+
153
+ it("should use browser / device locale (fr-FR) when it matches one of the supported language", () => {
154
+ // localizations: ["en", "en-US", "fr", "fr-FR"], device_language: fr, device_region: FR -> ui: fr, language: fr, region: FR
155
+ global.window.navigator.language = "fr-FR";
156
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
157
+
158
+ expect(result).toEqual({
159
+ uiLanguage: "fr-FR",
160
+ languageCode: "fr",
161
+ countryLocale: "FR",
162
+ languageLocale: "fr-FR",
163
+ });
164
+ });
165
+
166
+ it("should use user-selected language (en-US) if it was persisted in local storage", () => {
167
+ window.localStorage.getItem.mockReturnValue("en-US");
168
+
169
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
170
+
171
+ expect(window.localStorage.getItem).toHaveBeenCalled();
172
+
173
+ expect(result).toEqual({
174
+ uiLanguage: "en-US",
175
+ languageCode: "en",
176
+ countryLocale: "US",
177
+ languageLocale: "en-US",
178
+ });
179
+ });
180
+
181
+ it("should use locale (fr-FR) from browser / device if no user selection is found in storage", () => {
182
+ window.localStorage.getItem.mockReturnValue(undefined);
183
+ global.window.navigator.language = "fr-FR";
184
+ const result = QuickBrickModule.getMatchingLanguageFromBuildData();
185
+
186
+ expect(result).toEqual({
187
+ uiLanguage: "fr-FR",
188
+ languageCode: "fr",
189
+ countryLocale: "FR",
190
+ languageLocale: "fr-FR",
191
+ });
192
+ });
193
+ });
194
+
195
+ describe("setAppLanguage", () => {
196
+ it("should persist language selection and reload the page", async () => {
197
+ await QuickBrickModule.setAppLanguage("fr-FR");
198
+
199
+ expect(mockPersistLanguageSelection).toHaveBeenCalledWith("fr-FR");
200
+ expect(window.location.reload).toHaveBeenCalled();
201
+ });
202
+ });
203
+
204
+ describe("QuickBrickCommunicationModule", () => {
205
+ it("should initialize with the required app data", () => {
206
+ expect(QuickBrickModule.QuickBrickCommunicationModule).toMatchObject({
207
+ ...mockAppData,
208
+ platform: mockAppData.deviceTarget,
209
+ setAppLanguage: expect.any(Function),
210
+ });
211
+ });
212
+
213
+ it("should include locale data after calling getMatchingLanguageBuildData", () => {
214
+ const localeData = QuickBrickModule.getMatchingLanguageFromBuildData();
215
+ const result = { ...mockAppData, ...localeData };
216
+
217
+ Object.entries(result).forEach(([key, value]) => {
218
+ expect(QuickBrickModule.QuickBrickCommunicationModule).toHaveProperty(
219
+ key,
220
+ typeof value === "function" ? expect.any(Function) : value
221
+ );
222
+ });
223
+ });
224
+ });
225
+ });
@@ -1,8 +1,15 @@
1
1
  import * as R from "ramda";
2
2
 
3
- import * as AppDataPolyfill from "../AppData";
4
- import { setLanguageCodeToLocalStorage } from "../../App/Loader/utils";
3
+ import { persistLanguageSelection } from "../../App/Loader/utils";
4
+
5
+ import { getAppData } from "../AppData";
5
6
  import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
7
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
8
+
9
+ const { log_error, log_debug, log_warning } = createLogger({
10
+ category: "QuickBrickCommunicationModule",
11
+ subsystem: "zapp-react-dom-app",
12
+ });
6
13
 
7
14
  const QuickBrickEventEmitter = {};
8
15
 
@@ -63,98 +70,154 @@ try {
63
70
  console.warn("cannot assign QuickBrickEvents to window", e.message);
64
71
  }
65
72
 
66
- function quickBrickEvent(eventName, payload) {
73
+ export function quickBrickEvent(eventName, payload) {
67
74
  QuickBrickEventEmitter.sendEvent(eventName, payload);
68
75
  }
69
76
 
70
77
  const initialProps = {}; // required for legacy plugins;
71
78
 
72
- function getBrowserLocale() {
79
+ /**
80
+ * Retrieves the browser locale, which represents the device locale for SmartTVs.
81
+ *
82
+ * @returns {string|undefined} The browser locale string (e.g., "en-US") or undefined if an error occurs.
83
+ *
84
+ * TODO: We can later get more accurate locale data with device APIs, if needed
85
+ */
86
+ export function getBrowserLocale() {
73
87
  try {
74
88
  return window.navigator.language;
75
89
  } catch (e) {
76
- // eslint-disable-next-line no-console
77
- console.error("Could not determine browser locale", e);
90
+ log_error("Could not determine locale", e);
78
91
  }
79
92
  }
80
93
 
81
- function formatLocale(locale) {
82
- return locale?.toLowerCase()?.split("-");
83
- }
84
-
85
- const browserLocale = getBrowserLocale();
86
- const [languageCode, countryLocale] = formatLocale(browserLocale) || ["", ""];
87
-
88
- const setAppLanguage = async (languageCode) => {
89
- await setLanguageCodeToLocalStorage(languageCode);
94
+ /**
95
+ * Updates the UI language, persists the selection, and reloads the application.
96
+ * This method is used by the QuickBrick Language Selector to change the app's language.
97
+ *
98
+ * @param {string} uiLanguage - en-UK, en-US, etc.
99
+ * @returns {Promise<void>}
100
+ *
101
+ * Usage: plugins/quick-brick-language-selector/src/utils/index.ts
102
+ */
103
+ export const setAppLanguage = async (uiLanguage) => {
104
+ await persistLanguageSelection(uiLanguage);
90
105
 
91
- // reload web page
92
106
  window.location.reload();
93
107
  };
94
108
 
95
- const buildTimeData = AppDataPolyfill.getAppData();
96
-
97
- // TODO - move to a better place
98
- const getMatchingLanguageFromBuildData = () => {
109
+ const buildTimeData = getAppData();
110
+
111
+ /**
112
+ * This method retrieves the all of the language data we need from the build data, and the browser locale.
113
+ * @returns localeData
114
+ * @returns localeData.uiLanguage - The language code to use for the app.
115
+ * @returns localeData.countryLocale - The country locale code.
116
+ * @returns localeData.languageLocale - The language locale code.
117
+ * @returns localeData.languageCode - The language code.
118
+ */
119
+ export const getMatchingLanguageFromBuildData = () => {
120
+ // Locale is a build time value we get from Zapp, so we can use it as a fallback
99
121
  const { locale, languages } = buildTimeData || {};
122
+ const browserLocale = getBrowserLocale();
123
+
124
+ if (!Array.isArray(languages)) {
125
+ log_error("Missing required 'languages' from the build time data.", {
126
+ buildTimeData,
127
+ });
128
+
129
+ return {
130
+ uiLanguage: locale,
131
+ languageCode: locale,
132
+ countryLocale: "",
133
+ languageLocale: locale,
134
+ };
135
+ }
100
136
 
101
- // TODO: refactor: tryAndResolve used in Storage is promise
102
137
  const userSelectedLanguage = window.localStorage.getItem(
103
138
  "applicaster.v2_::_uiLanguage"
104
139
  );
105
140
 
106
- if (!locale && !Array.isArray(languages)) {
107
- // eslint-disable-next-line no-console
108
- console.error("Missing required 'locale' and 'language' build time data.");
109
-
110
- // Default language
111
- return locale;
112
- }
113
-
114
141
  if (userSelectedLanguage) {
115
- if (languages.includes(userSelectedLanguage)) {
116
- return userSelectedLanguage;
142
+ if (languages.find((lang) => lang === userSelectedLanguage)) {
143
+ const [languageCode, countryLocale] = userSelectedLanguage.split("-");
144
+
145
+ return {
146
+ uiLanguage: userSelectedLanguage,
147
+ languageCode,
148
+ countryLocale: countryLocale || "",
149
+ languageLocale: userSelectedLanguage,
150
+ };
117
151
  }
118
152
 
119
- // eslint-disable-next-line no-console
120
- console.log(
121
- "User selected language is not present in available localizations, performing autoselect"
153
+ log_debug(
154
+ "User selected language is not present in available localizations, selecting language using browser or device locale",
155
+
156
+ { userSelectedLanguage, languages }
122
157
  );
123
158
  }
124
159
 
125
160
  if (!browserLocale) {
126
- // eslint-disable-next-line no-console
127
- console.error("Could not determine browser locale.");
161
+ log_warning(
162
+ "Could not use browser or device locale to determine language, falling back to default locale",
163
+ { browserLocale, locale }
164
+ );
128
165
 
129
- return locale;
166
+ return {
167
+ uiLanguage: locale,
168
+ languageCode: locale,
169
+ countryLocale: "",
170
+ languageLocale: locale,
171
+ };
130
172
  }
131
173
 
132
- // Match locale "en-UK"
133
- const localeMatch = languages.find((lang) => lang === browserLocale);
174
+ // Exact match
175
+ const [browserLanguageCode, browserCountryLocale] = browserLocale.split("-");
176
+ const browserLocaleMatch = languages.find((lang) => lang === browserLocale);
134
177
 
135
- if (localeMatch) {
136
- return localeMatch;
178
+ if (browserLocaleMatch) {
179
+ return {
180
+ uiLanguage: browserLocaleMatch,
181
+ languageCode: browserLanguageCode,
182
+ countryLocale: browserCountryLocale || "",
183
+ languageLocale: browserLocaleMatch,
184
+ };
137
185
  }
138
186
 
139
- // Match language "en"
140
- const languageMatch = languages.find((lang) => lang === languageCode);
187
+ // If there is no user-selected language, or the user-selected language is not found in the list of supported languages,
188
+ // and the browser locale is also not found in the list of supported languages,
189
+ // then fallback to the default language from the list of supported languages, while preserving the country locale from the browser.
190
+ const defaultLanguage = languages[0];
141
191
 
142
- if (languageMatch) {
143
- return languageMatch;
144
- }
192
+ if (defaultLanguage) {
193
+ const [languageCode, countryLocale] = defaultLanguage.split("-");
145
194
 
146
- // Default language
147
- return locale;
195
+ const defaultLocale = {
196
+ uiLanguage: defaultLanguage,
197
+ languageCode,
198
+ countryLocale: countryLocale || "",
199
+ languageLocale: defaultLanguage,
200
+ };
201
+
202
+ log_debug(
203
+ "Locale not found in the list of supported languages, falling back to the default language locale",
204
+ { defaultLocale, browserLocale, languages }
205
+ );
206
+
207
+ return defaultLocale;
208
+ }
148
209
  };
149
210
 
211
+ const localeData = getMatchingLanguageFromBuildData();
212
+
213
+ /**
214
+ * QuickBrickCommunicationModule object is a Polyfill that mimicks how we interface with the Native platforms
215
+ */
150
216
  export const QuickBrickCommunicationModule = {
151
217
  quickBrickEvent,
152
218
  initialProps,
153
219
  ...buildTimeData,
220
+ ...localeData,
154
221
  platform: buildTimeData.deviceTarget,
155
- languageLocale: languageCode,
156
- countryLocale,
157
222
  setAppLanguage,
158
- countryCode: countryLocale,
159
- uiLanguage: getMatchingLanguageFromBuildData(),
160
223
  };
@@ -1,4 +1,3 @@
1
- // @flow
2
1
  import * as R from "ramda";
3
2
 
4
3
  import {
@@ -7,11 +6,11 @@ import {
7
6
  } from "@applicaster/zapp-react-native-utils/functionUtils";
8
7
  import { mapKeys } from "@applicaster/zapp-react-native-utils/objectUtils";
9
8
 
10
- export type StorageI = {
11
- setItem: (string, string, ?string) => Promise<any>,
12
- getItem: (string, ?string) => Promise<any>,
13
- getAllItems: () => Promise<any>,
14
- };
9
+ // export type StorageI = {
10
+ // setItem: (string, string, ?string) => Promise<any>,
11
+ // getItem: (string, ?string) => Promise<any>,
12
+ // getAllItems: () => Promise<any>,
13
+ // };
15
14
 
16
15
  export const STORAGE_TYPES = ["localStorage", "sessionStorage"];
17
16
 
@@ -25,10 +24,7 @@ const NAMESPACE_SEPARATOR = "_::_";
25
24
  * @param {?String} namespace
26
25
  * @returns {String}
27
26
  */
28
- export function applyNamespaceToKeyName(
29
- key: string,
30
- namespace: ?string
31
- ): string {
27
+ export function applyNamespaceToKeyName(key, namespace) {
32
28
  return namespace ? `${namespace}${NAMESPACE_SEPARATOR}${key}` : key;
33
29
  }
34
30
 
@@ -40,7 +36,7 @@ export function applyNamespaceToKeyName(
40
36
  * @param {Function} fn function to run
41
37
  * @returns {Promise}
42
38
  */
43
- function tryAndResolve(fn: (any) => any): Promise<any> {
39
+ function tryAndResolve(fn) {
44
40
  try {
45
41
  return R.compose(
46
42
  (value) => Promise.resolve(value),
@@ -62,7 +58,7 @@ function tryAndResolve(fn: (any) => any): Promise<any> {
62
58
  * @returns {Function} storageObject.callMethod: invokes methods on the storage object
63
59
  * @returns {Function} storageObject.getKeys: returns all existing keys in the storage object
64
60
  */
65
- function getStorageObject(type: string): (any) => void | Promise<any> {
61
+ function getStorageObject(type) {
66
62
  const storage = R.prop(type, window);
67
63
 
68
64
  if (!R.includes(type, STORAGE_TYPES) || !storage) {
@@ -80,7 +76,7 @@ function getStorageObject(type: string): (any) => void | Promise<any> {
80
76
  * @param {Array} args array of arguments to use when invoking the method
81
77
  * @returns response of the method call
82
78
  */
83
- function callMethod(method: string, ...args: [any]): Promise<any> {
79
+ function callMethod(method, ...args) {
84
80
  return storage[method](...args);
85
81
  }
86
82
 
@@ -107,9 +103,9 @@ function getStorageObject(type: string): (any) => void | Promise<any> {
107
103
  /**
108
104
  * returns an object to interact with a storage module (localStorage or sessionStorage)
109
105
  * @param {String} type of storage
110
- * @returns {Object}
106
+ * @returns {StorageI}
111
107
  */
112
- export function getStorageModule(type: string): StorageI {
108
+ export function getStorageModule(type) {
113
109
  const Storage = getStorageObject(type);
114
110
 
115
111
  /**
@@ -120,11 +116,7 @@ export function getStorageModule(type: string): StorageI {
120
116
  * @param {?String} namespace
121
117
  * @returns {Promise<Boolean|Error>}
122
118
  */
123
- function setItem(
124
- key: string,
125
- value: string,
126
- namespace: ?string = DEFAULT_NAMESPACE
127
- ): Promise<boolean | Error> {
119
+ function setItem(key, value, namespace = DEFAULT_NAMESPACE) {
128
120
  const keyName = applyNamespaceToKeyName(
129
121
  key,
130
122
  namespace || DEFAULT_NAMESPACE
@@ -144,10 +136,7 @@ export function getStorageModule(type: string): StorageI {
144
136
  * @param {?String} namespace
145
137
  * @returns {Promise<Any|Error>}
146
138
  */
147
- function getItem(
148
- key: string,
149
- namespace: ?string = DEFAULT_NAMESPACE
150
- ): Promise<any> {
139
+ function getItem(key, namespace = DEFAULT_NAMESPACE) {
151
140
  const keyName = applyNamespaceToKeyName(
152
141
  key,
153
142
  namespace || DEFAULT_NAMESPACE
@@ -163,7 +152,7 @@ export function getStorageModule(type: string): StorageI {
163
152
  * @param {?String} namespace
164
153
  * @returns {Promise<Boolean|Error>}
165
154
  */
166
- function removeItem(key: string, namespace = DEFAULT_NAMESPACE) {
155
+ function removeItem(key, namespace = DEFAULT_NAMESPACE) {
167
156
  const keyName = applyNamespaceToKeyName(key, namespace);
168
157
 
169
158
  return tryAndResolve(() => Storage.callMethod("removeItem", keyName));
@@ -174,7 +163,7 @@ export function getStorageModule(type: string): StorageI {
174
163
  * @param {?String} namespace
175
164
  * @returns {Promise<Object|Error>}
176
165
  */
177
- function getAllItems(namespace: ?string = null): Promise<string> {
166
+ function getAllItems(namespace = null) {
178
167
  return tryAndResolve(() => {
179
168
  const keys = Storage.getKeys();
180
169
 
package/main.css CHANGED
@@ -10,8 +10,8 @@ body {
10
10
  }
11
11
 
12
12
  div#zapp_app_container {
13
- height: 100%;
14
- width: 100%;
13
+ height: 1080px;
14
+ width: 1920px;
15
15
  display: flex;
16
16
  flex: 1;
17
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-dom-app",
3
- "version": "12.0.0-alpha.3977160850",
3
+ "version": "12.0.0-alpha.4043183114",
4
4
  "description": "Zapp App Component for Applicaster's Quick Brick React Native App",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -22,11 +22,11 @@
22
22
  },
23
23
  "homepage": "https://github.com/applicaster/zapp-react-dom-app#readme",
24
24
  "dependencies": {
25
- "@applicaster/zapp-react-dom-ui-components": "12.0.0-alpha.3977160850",
26
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.3977160850",
27
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.3977160850",
28
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3977160850",
29
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3977160850",
25
+ "@applicaster/zapp-react-dom-ui-components": "12.0.0-alpha.4043183114",
26
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4043183114",
27
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.4043183114",
28
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4043183114",
29
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4043183114",
30
30
  "abortcontroller-polyfill": "^1.7.5",
31
31
  "history": "^4.7.2",
32
32
  "react-router-dom": "^5.1.2",
@@ -1,35 +0,0 @@
1
- import { getAvailableAppLanguagesImpl as getAvailableAppLanguages } from "..";
2
-
3
- describe("getAvailableAppLanguages", () => {
4
- it("return list of languages", () => {
5
- // setup
6
- const appStore = {
7
- get: () => ({
8
- localizations: {
9
- en: "en_value",
10
- de: "de_value",
11
- fr: "fr_value",
12
- "en-UK": "en-UK_value",
13
- "en-GB": "en-GB_value",
14
- },
15
- }),
16
- };
17
-
18
- // verify
19
- expect(getAvailableAppLanguages(appStore)).toEqual([
20
- "en",
21
- "de",
22
- "fr",
23
- "en-UK",
24
- "en-GB",
25
- ]);
26
- });
27
-
28
- it("return list of languages", () => {
29
- // setup
30
- const appStore = undefined;
31
-
32
- // verify
33
- expect(getAvailableAppLanguages(appStore)).toEqual([]);
34
- });
35
- });