@applicaster/zapp-react-dom-app 12.0.0-alpha.4400210593 → 12.0.0-alpha.4510795609

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
 
@@ -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,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
  }
@@ -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
  /**
@@ -1,7 +1,6 @@
1
1
  import * as R from "ramda";
2
2
  import { appStore as AppStore } from "@applicaster/zapp-react-native-redux/AppStore";
3
3
  import { NativeModules } from "react-native";
4
- import { getAppData } from "../../../Polyfills/AppData";
5
4
 
6
5
  export const UI_LANGUAGE = "uiLanguage";
7
6
 
@@ -15,11 +14,11 @@ export const persistLanguageSelection = async (languageCode) => {
15
14
  return NativeModules.LocalStorage.setItem(UI_LANGUAGE, languageCode);
16
15
  };
17
16
 
18
- export const getAvailableAppLanguagesImpl = () => {
17
+ export const getAvailableAppLanguagesImpl = (appStore) => {
19
18
  try {
20
- const { languages } = getAppData();
19
+ const remoteConfigurations = appStore.get("remoteConfigurations");
21
20
 
22
- return languages;
21
+ return R.keys(remoteConfigurations.localizations);
23
22
  } catch (e) {
24
23
  return [];
25
24
  }
@@ -42,6 +42,36 @@ export const isSamsungPlatform = () => {
42
42
  );
43
43
  };
44
44
 
45
+ /**
46
+ * Checks if we are on the Vizio platform by using the userAgent string
47
+ *
48
+ * Use this method when you need to identify the platform on runtime
49
+ * before the VIZIO Companion Library has loaded
50
+ */
51
+ export const isVizioPlatform = () => {
52
+ const userAgent = getUserAgent();
53
+
54
+ const isVizioAgent =
55
+ userAgent.includes(PLATFORMS.vizio) ||
56
+ userAgent.includes(PLATFORMS.smartcast) ||
57
+ userAgent.includes(PLATFORMS.conjure);
58
+
59
+ return isVizioAgent;
60
+ };
61
+
62
+ /**
63
+ * Checks if we are on the Vizio platform by checking for the global VIZIO object
64
+ * and the VIZIO Companion Library. This method does not use the userAgent string,
65
+ * because it mainly checks whether we have access to apis, which may not be available yet
66
+ */
67
+ export const hasVizioAPIs = () => {
68
+ const hasAPIs =
69
+ typeof window.VIZIO !== "undefined" &&
70
+ window?.applicaster?.vizioLibraryDidLoad;
71
+
72
+ return hasAPIs;
73
+ };
74
+
45
75
  /**
46
76
  * platformSelect can't be used, because Platform.OS is overriden
47
77
  * by overloadReactNativePlatform and don't support 'web' value
@@ -253,6 +283,24 @@ export const getDeviceData = async () => {
253
283
  ...tizenConnectionInfo,
254
284
  device_type: getDeviceType(),
255
285
  };
286
+ } else if (isVizioPlatform()) {
287
+ deviceData = {
288
+ ...deviceData,
289
+ platform: "vizio",
290
+ deviceMake: "Vizio",
291
+ deviceType: "tv",
292
+ userAgent: getUserAgent(),
293
+ deviceWidth: window.innerWidth,
294
+ deviceHeight: window.innerHeight,
295
+ };
296
+
297
+ if (hasVizioAPIs()) {
298
+ window.VIZIO.getFirmwareVersion(function (firmwareVersion) {
299
+ deviceData.osVersion = firmwareVersion;
300
+ });
301
+
302
+ deviceData.deviceModel = window.VIZIO.deviceModel;
303
+ }
256
304
  }
257
305
 
258
306
  return deviceData;
@@ -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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-dom-app",
3
- "version": "12.0.0-alpha.4400210593",
3
+ "version": "12.0.0-alpha.4510795609",
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.4400210593",
26
- "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4400210593",
27
- "@applicaster/zapp-react-native-redux": "12.0.0-alpha.4400210593",
28
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4400210593",
29
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4400210593",
25
+ "@applicaster/zapp-react-dom-ui-components": "12.0.0-alpha.4510795609",
26
+ "@applicaster/zapp-react-native-bridge": "12.0.0-alpha.4510795609",
27
+ "@applicaster/zapp-react-native-redux": "12.0.0-alpha.4510795609",
28
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4510795609",
29
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.4510795609",
30
30
  "abortcontroller-polyfill": "^1.7.5",
31
31
  "history": "^4.7.2",
32
32
  "react-router-dom": "^5.1.2",
@@ -1,22 +0,0 @@
1
- jest.mock("../../../../Polyfills/AppData", () => ({
2
- getAppData: jest.fn(),
3
- }));
4
-
5
- describe("getAvailableAppLanguages", () => {
6
- const { getAppData } = require("../../../../Polyfills/AppData");
7
- const { getAvailableAppLanguagesImpl } = require("..");
8
-
9
- it("return list of languages", () => {
10
- const languages = ["en", "de", "fr", "en-UK", "en-GB"];
11
-
12
- getAppData.mockReturnValue({ languages });
13
-
14
- expect(getAvailableAppLanguagesImpl()).toEqual(languages);
15
- });
16
-
17
- it("return list of languages", () => {
18
- getAppData.mockReturnValue(undefined);
19
-
20
- expect(getAvailableAppLanguagesImpl()).toEqual([]);
21
- });
22
- });