@applicaster/zapp-react-dom-app 13.0.0-alpha.1632352572 → 13.0.0-alpha.1673005505
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.
- package/App/InteractionManager/index.tsx +153 -83
- package/App/Loader/__tests__/__snapshots__/loadDomPlugins.test.js.snap +6 -6
- package/App/Loader/loadLocale.js +2 -2
- package/App/Loader/utils/platform.js +46 -26
- package/Polyfills/Storage/__tests__/__snapshots__/storage.test.js.snap +4 -4
- package/index.js +0 -7
- package/package.json +17 -8
- package/App/Router/index.js +0 -17
- package/App/Splash/Spinner.js +0 -30
- package/App/Splash/spinner-styles.css +0 -81
|
@@ -31,7 +31,10 @@ 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 {
|
|
34
|
+
import {
|
|
35
|
+
getXray,
|
|
36
|
+
createLogger,
|
|
37
|
+
} from "@applicaster/zapp-react-native-utils/logger";
|
|
35
38
|
|
|
36
39
|
import {
|
|
37
40
|
confirmationDialogStore,
|
|
@@ -51,6 +54,11 @@ import { KeyInputHandler } from "@applicaster/zapp-react-native-utils/appUtils/k
|
|
|
51
54
|
const { withXray } = getXray();
|
|
52
55
|
const globalAny: any = global;
|
|
53
56
|
|
|
57
|
+
const { log_debug, log_warning } = createLogger({
|
|
58
|
+
category: "InteractionManager",
|
|
59
|
+
subsystem: "zapp-react-dom-app",
|
|
60
|
+
});
|
|
61
|
+
|
|
54
62
|
const shouldUseOnScreenKeyboard = () =>
|
|
55
63
|
isVizioPlatform() || window.applicaster.useOnScreenKeyboard;
|
|
56
64
|
|
|
@@ -140,13 +148,16 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
140
148
|
this.onConfirmDialogOpen = this.onConfirmDialogOpen.bind(this);
|
|
141
149
|
this.onConfirmDialogClose = this.onConfirmDialogClose.bind(this);
|
|
142
150
|
|
|
151
|
+
this.handlePhysicalKeyboardDismiss =
|
|
152
|
+
this.handlePhysicalKeyboardDismiss.bind(this);
|
|
153
|
+
|
|
143
154
|
this.confirmDialog.setConfirmAction(this.performExit);
|
|
144
155
|
this.confirmDialog.setCancelAction(this.onConfirmDialogClose);
|
|
145
156
|
this.longPressDetector = new KeyboardLongPressManager();
|
|
146
157
|
}
|
|
147
158
|
|
|
148
159
|
componentDidMount() {
|
|
149
|
-
window.addEventListener("keydown", this.onKeyDownListener);
|
|
160
|
+
window.addEventListener("keydown", this.onKeyDownListener, true);
|
|
150
161
|
window.addEventListener("keyup", this.onKeyUp);
|
|
151
162
|
window.addEventListener("mousemove", this.onMouseMoveListener);
|
|
152
163
|
|
|
@@ -181,6 +192,11 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
181
192
|
"onLongPressRelease",
|
|
182
193
|
this.handleLongPressRelease.bind(this)
|
|
183
194
|
);
|
|
195
|
+
|
|
196
|
+
document.addEventListener(
|
|
197
|
+
"keyboardDismissedByPhysicalKeypress",
|
|
198
|
+
this.handlePhysicalKeyboardDismiss
|
|
199
|
+
);
|
|
184
200
|
}
|
|
185
201
|
|
|
186
202
|
componentWillUnmount() {
|
|
@@ -209,6 +225,11 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
209
225
|
"onLongPressRelease",
|
|
210
226
|
this.handleLongPressRelease
|
|
211
227
|
);
|
|
228
|
+
|
|
229
|
+
document.removeEventListener(
|
|
230
|
+
"keyboardDismissedByPhysicalKeypress",
|
|
231
|
+
this.handlePhysicalKeyboardDismiss
|
|
232
|
+
);
|
|
212
233
|
}
|
|
213
234
|
|
|
214
235
|
performExit() {
|
|
@@ -270,8 +291,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
270
291
|
this.handleWebOsBack();
|
|
271
292
|
}
|
|
272
293
|
} catch (e) {
|
|
273
|
-
|
|
274
|
-
console.warn("Failed to execute platformBack", e);
|
|
294
|
+
log_warning("Failed to execute platformBack", e);
|
|
275
295
|
}
|
|
276
296
|
}
|
|
277
297
|
|
|
@@ -341,8 +361,10 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
341
361
|
this.longPressDetector.endKeyPressMonitoring(event.code);
|
|
342
362
|
}
|
|
343
363
|
|
|
344
|
-
if (
|
|
345
|
-
|
|
364
|
+
if (
|
|
365
|
+
keyCode(event).matches(KEYS.Enter) ||
|
|
366
|
+
(__DEV__ && keyCode(event).matches(KEYS.X))
|
|
367
|
+
) {
|
|
346
368
|
focusManager.pressOut();
|
|
347
369
|
}
|
|
348
370
|
|
|
@@ -363,29 +385,109 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
363
385
|
}
|
|
364
386
|
}
|
|
365
387
|
|
|
366
|
-
|
|
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) {
|
|
367
396
|
const { displayState, setDisplayState, navigator } = this.props;
|
|
397
|
+
const { isDialogVisible } = confirmationDialogStore.getState();
|
|
368
398
|
const { isKeyboardVisible } = this.state;
|
|
369
399
|
|
|
370
|
-
|
|
400
|
+
log_debug("onBackPress", {
|
|
401
|
+
eventCode: event.code,
|
|
402
|
+
displayState,
|
|
403
|
+
isDialogVisible,
|
|
404
|
+
isKeyboardVisible,
|
|
405
|
+
});
|
|
371
406
|
|
|
372
407
|
if (isKeyboardVisible && shouldUseOnScreenKeyboard()) {
|
|
373
|
-
|
|
374
|
-
this.handleKeyboardDismiss();
|
|
375
|
-
}
|
|
376
|
-
|
|
408
|
+
this.handleKeyboardDismiss();
|
|
377
409
|
event.preventDefault();
|
|
378
410
|
event.stopPropagation();
|
|
379
411
|
|
|
380
412
|
return;
|
|
381
413
|
}
|
|
382
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
|
+
|
|
383
485
|
if (this.keySupportsLongPress(event)) {
|
|
384
486
|
this.longPressDetector.monitorKeyPress(event.code, event);
|
|
385
487
|
}
|
|
386
488
|
|
|
387
|
-
//
|
|
388
|
-
if (event.repeat) return;
|
|
489
|
+
// Only handle repeat events for arrow keys
|
|
490
|
+
if (event.repeat && !keyCode(event).matchesAny(...ARROW_KEYS)) return;
|
|
389
491
|
|
|
390
492
|
/**
|
|
391
493
|
When the player is displayed, we listen to Native Play / Pause / Stop
|
|
@@ -445,64 +547,14 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
445
547
|
}
|
|
446
548
|
}
|
|
447
549
|
|
|
448
|
-
/**
|
|
449
|
-
When pressing backspace or the Native "Back" button:
|
|
450
|
-
if on the transport controls: we show the player
|
|
451
|
-
if on the player : we show the UI
|
|
452
|
-
if on the UI : we exit the app
|
|
453
|
-
*/
|
|
454
|
-
|
|
455
550
|
if (
|
|
456
|
-
keyCode(event).
|
|
457
|
-
|
|
458
|
-
KEYS.Escape,
|
|
459
|
-
KEYS.EscapeDevice,
|
|
460
|
-
KEYS.Backspace
|
|
461
|
-
)
|
|
551
|
+
keyCode(event).matches(KEYS.Enter) ||
|
|
552
|
+
(__DEV__ && keyCode(event).matches(KEYS.X))
|
|
462
553
|
) {
|
|
463
|
-
switch (displayState) {
|
|
464
|
-
case DISPLAY_STATES.DEFAULT:
|
|
465
|
-
case DISPLAY_STATES.PLAYER:
|
|
466
|
-
if (isDialogVisible) {
|
|
467
|
-
this.onConfirmDialogClose();
|
|
468
|
-
} else if (navigator.canGoBack()) {
|
|
469
|
-
navigator.goBack();
|
|
470
|
-
} else if (this.isHomeScreen()) {
|
|
471
|
-
this.platformBack();
|
|
472
|
-
} else if (navigator.currentRoute.includes("hook")) {
|
|
473
|
-
// If code reaches this block navigator cant go back, it is not home,
|
|
474
|
-
// and this is a login plugin that was pushed on top of the home
|
|
475
|
-
// Treat it like a home screen and run platformBack()
|
|
476
|
-
const entryData = navigator?.data?.entry;
|
|
477
|
-
const isHookInHomescreen = entryData?.payload?.home;
|
|
478
|
-
|
|
479
|
-
const isHookFlowBlocker =
|
|
480
|
-
entryData?.hookPlugin?.module?.isFlowBlocker();
|
|
481
|
-
|
|
482
|
-
if (isHookInHomescreen && isHookFlowBlocker) {
|
|
483
|
-
this.platformBack();
|
|
484
|
-
} else {
|
|
485
|
-
navigator.goBack(false, true);
|
|
486
|
-
}
|
|
487
|
-
} else {
|
|
488
|
-
this.goToHome();
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
break;
|
|
492
|
-
case DISPLAY_STATES.HUD:
|
|
493
|
-
// IF transport controls are open, close them instead of closing player
|
|
494
|
-
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
495
|
-
break;
|
|
496
|
-
default:
|
|
497
|
-
setDisplayState(DISPLAY_STATES.PLAYER);
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
if (keyCode(event).matches(KEYS.Enter) || keyCode(event).matches(KEYS.X)) {
|
|
503
554
|
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
504
555
|
setDisplayState(DISPLAY_STATES.HUD);
|
|
505
556
|
} else {
|
|
557
|
+
focusManager.pressIn();
|
|
506
558
|
focusManager.press();
|
|
507
559
|
}
|
|
508
560
|
|
|
@@ -519,10 +571,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
519
571
|
this.platformBack();
|
|
520
572
|
}
|
|
521
573
|
|
|
522
|
-
if (
|
|
523
|
-
keyCode(event).matchesAny(...ARROW_KEYS) &&
|
|
524
|
-
!this.state.isKeyboardVisible
|
|
525
|
-
) {
|
|
574
|
+
if (keyCode(event).matchesAny(...ARROW_KEYS)) {
|
|
526
575
|
if (displayState === DISPLAY_STATES.PLAYER) {
|
|
527
576
|
setDisplayState(DISPLAY_STATES.HUD);
|
|
528
577
|
}
|
|
@@ -535,12 +584,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
535
584
|
focusManager.moveFocus(direction);
|
|
536
585
|
}
|
|
537
586
|
|
|
538
|
-
if (!isDialogVisible) {
|
|
539
|
-
// run focus recovery on user interaction attempt
|
|
540
|
-
// probably we failed to set initial focus for some reason
|
|
541
|
-
focusManager.recoverFocus();
|
|
542
|
-
}
|
|
543
|
-
|
|
544
587
|
if (
|
|
545
588
|
displayState === DISPLAY_STATES.PLAYER ||
|
|
546
589
|
displayState === DISPLAY_STATES.HUD
|
|
@@ -616,6 +659,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
616
659
|
|
|
617
660
|
if (
|
|
618
661
|
(target.tagName === "INPUT" && target.type === "text") ||
|
|
662
|
+
(target.tagName === "INPUT" && target.type === "password") ||
|
|
619
663
|
target.tagName === "TEXTAREA"
|
|
620
664
|
) {
|
|
621
665
|
this.setState({
|
|
@@ -644,7 +688,7 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
644
688
|
}
|
|
645
689
|
}
|
|
646
690
|
|
|
647
|
-
handleKeyboardDismiss
|
|
691
|
+
handleKeyboardDismiss() {
|
|
648
692
|
this.isDismissing = true;
|
|
649
693
|
|
|
650
694
|
this.setState(
|
|
@@ -655,9 +699,10 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
655
699
|
},
|
|
656
700
|
() => {
|
|
657
701
|
this.isDismissing = false;
|
|
702
|
+
focusManager.recoverFocus();
|
|
658
703
|
}
|
|
659
704
|
);
|
|
660
|
-
}
|
|
705
|
+
}
|
|
661
706
|
|
|
662
707
|
handleKeyboardInput = (value: string) => {
|
|
663
708
|
const { activeInputRef } = this.state;
|
|
@@ -717,10 +762,6 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
717
762
|
// TODO: Delete it on next PR if not needed
|
|
718
763
|
private handleLongPress = (event: CustomEvent) => {
|
|
719
764
|
const { keyCode } = event.detail;
|
|
720
|
-
const { displayState } = this.props;
|
|
721
|
-
const playerState = displayState === DISPLAY_STATES.PLAYER;
|
|
722
|
-
const hudState = displayState === DISPLAY_STATES.HUD;
|
|
723
|
-
const playbackState = playerState || hudState;
|
|
724
765
|
this.longPressActive = true;
|
|
725
766
|
this.cancelHudTimeout();
|
|
726
767
|
|
|
@@ -757,6 +798,35 @@ class InteractionManagerClass extends React.Component<Props, State> {
|
|
|
757
798
|
].includes(event.code);
|
|
758
799
|
}
|
|
759
800
|
|
|
801
|
+
handlePhysicalKeyboardDismiss(event: CustomEvent) {
|
|
802
|
+
const { value, position, inputElement } = event.detail;
|
|
803
|
+
|
|
804
|
+
this.isDismissing = true;
|
|
805
|
+
|
|
806
|
+
this.setState(
|
|
807
|
+
{
|
|
808
|
+
isKeyboardVisible: false,
|
|
809
|
+
keyboardInput: "",
|
|
810
|
+
activeInputRef: null,
|
|
811
|
+
},
|
|
812
|
+
() => {
|
|
813
|
+
if (inputElement) {
|
|
814
|
+
inputElement.value = value;
|
|
815
|
+
inputElement.focus();
|
|
816
|
+
inputElement.setSelectionRange(position, position);
|
|
817
|
+
|
|
818
|
+
const keyboardEvent = new CustomEvent("keyboardUpdate", {
|
|
819
|
+
detail: { value },
|
|
820
|
+
});
|
|
821
|
+
|
|
822
|
+
document.dispatchEvent(keyboardEvent);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
this.isDismissing = false;
|
|
826
|
+
}
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
|
|
760
830
|
render() {
|
|
761
831
|
return (
|
|
762
832
|
(shouldUseOnScreenKeyboard() && this.state.isKeyboardVisible && (
|
|
@@ -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
|
-
|
|
5
|
-
|
|
4
|
+
[
|
|
5
|
+
[
|
|
6
6
|
"could not initialize plugin Plugin with Dom node & no init method - it doesn't have an init method",
|
|
7
|
-
|
|
8
|
-
"plugin":
|
|
9
|
-
"configuration":
|
|
7
|
+
{
|
|
8
|
+
"plugin": {
|
|
9
|
+
"configuration": {
|
|
10
10
|
"foo": "bar",
|
|
11
11
|
},
|
|
12
|
-
"module":
|
|
12
|
+
"module": {
|
|
13
13
|
"requiresAppendingDomNode": true,
|
|
14
14
|
},
|
|
15
15
|
"name": "Plugin with Dom node & no init method",
|
package/App/Loader/loadLocale.js
CHANGED
|
@@ -4,8 +4,8 @@ import { QuickBrickCommunicationModule } from "../../Polyfills/QuickBrickCommuni
|
|
|
4
4
|
import { loadLocaleImpl, getLanguageCode } from "./utils";
|
|
5
5
|
|
|
6
6
|
type Locale = {
|
|
7
|
-
language: string
|
|
8
|
-
country: string
|
|
7
|
+
language: string;
|
|
8
|
+
country: string;
|
|
9
9
|
};
|
|
10
10
|
|
|
11
11
|
async function getBrowserLocale() {
|
|
@@ -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
|
|
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
|
-
|
|
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
|
|
63
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
76
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
92
|
-
* @param {string} key - key
|
|
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
|
-
*
|
|
98
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
13
|
+
{
|
|
14
14
|
"baz_::_foo": "baz",
|
|
15
15
|
"baz_::_otherKey": "otherValue",
|
|
16
16
|
"foo": "bar",
|
|
@@ -19,14 +19,14 @@ 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
|
-
|
|
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
|
-
|
|
29
|
+
{
|
|
30
30
|
"foo": "baz",
|
|
31
31
|
"otherKey": "otherValue",
|
|
32
32
|
}
|
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.
|
|
3
|
+
"version": "13.0.0-alpha.1673005505",
|
|
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.
|
|
26
|
-
"@applicaster/zapp-react-native-bridge": "13.0.0-alpha.
|
|
27
|
-
"@applicaster/zapp-react-native-redux": "13.0.0-alpha.
|
|
28
|
-
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.
|
|
29
|
-
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.
|
|
25
|
+
"@applicaster/zapp-react-dom-ui-components": "13.0.0-alpha.1673005505",
|
|
26
|
+
"@applicaster/zapp-react-native-bridge": "13.0.0-alpha.1673005505",
|
|
27
|
+
"@applicaster/zapp-react-native-redux": "13.0.0-alpha.1673005505",
|
|
28
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-alpha.1673005505",
|
|
29
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-alpha.1673005505",
|
|
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,19 @@
|
|
|
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": "*",
|
|
40
|
+
"@types/node": "*",
|
|
39
41
|
"core-js": "3.29.1",
|
|
42
|
+
"immer": "*",
|
|
40
43
|
"react": "17.0.2",
|
|
41
44
|
"react-dom": "17.0.2",
|
|
42
|
-
"react-native
|
|
45
|
+
"react-native": "*",
|
|
46
|
+
"react-native-safe-area-context": "*",
|
|
47
|
+
"react-native-svg": "*",
|
|
48
|
+
"react-native-web": "0.18.11",
|
|
49
|
+
"uglify-js": "*",
|
|
50
|
+
"validate-color": "*",
|
|
51
|
+
"zustand": "*"
|
|
43
52
|
}
|
|
44
53
|
}
|
package/App/Router/index.js
DELETED
|
@@ -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
|
-
};
|
package/App/Splash/Spinner.js
DELETED
|
@@ -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
|
-
}
|