@applicaster/zapp-react-native-utils 12.0.0-rc.99 → 13.0.0-alpha.2322412833
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/analyticsUtils/AnalyticPlayerListener.ts +141 -0
- package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
- package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
- package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
- package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +4 -2
- package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
- package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
- package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
- package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
- package/appUtils/HooksManager/{index.js → index.ts} +121 -112
- package/appUtils/HooksManager/types.ts +116 -0
- package/appUtils/RiverFocusManager/index.js +17 -12
- package/appUtils/accessibilityManager/hooks.ts +16 -7
- package/appUtils/accessibilityManager/index.ts +33 -28
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
- package/appUtils/{index.js → index.ts} +1 -1
- package/appUtils/keyCodes/__tests__/keyCodes.test.js +3 -3
- package/appUtils/keyCodes/{index.js → index.ts} +2 -0
- package/appUtils/keyCodes/keys/index.ts +3 -0
- package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
- package/appUtils/keyCodes/keys/keys.android.ts +18 -0
- package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
- package/appUtils/keyCodes/keys/keys.ts +15 -0
- package/appUtils/platform/platformUtils.ts +35 -16
- package/appUtils/playerManager/index.ts +9 -27
- package/appUtils/playerManager/playerFactory.ts +5 -4
- package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +57 -0
- package/appUtils/playerManager/playerNative.ts +1 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -1
- package/appUtils/playerManager/usePlayerState.tsx +19 -34
- package/arrayUtils/index.ts +11 -0
- package/cellUtils/index.ts +38 -5
- package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
- package/focusManager/FocusManager.ts +20 -5
- package/focusManager/__tests__/FocusManager.test.ts +0 -1
- package/functionUtils/index.ts +53 -11
- package/index.d.ts +15 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +121 -0
- package/manifestUtils/keys.js +2 -1
- package/modalState/index.ts +1 -5
- package/navigationUtils/index.ts +15 -6
- package/numberUtils/__tests__/toNumber.test.ts +2 -2
- package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +66 -0
- package/numberUtils/__tests__/toPositiveNumberWithDefaultZero.test.ts +66 -0
- package/numberUtils/index.ts +20 -0
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +120 -0
- package/playerUtils/imaScriptDom.ts +59 -0
- package/reactHooks/cell-click/index.ts +17 -3
- package/reactHooks/debugging/__tests__/index.test.js +81 -11
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +69 -6
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -2
- package/reactHooks/feed/useBatchLoading.ts +52 -28
- package/reactHooks/feed/useFeedLoader.tsx +11 -7
- package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +134 -0
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -0
- package/reactHooks/navigation/index.ts +8 -5
- package/reactHooks/player/useAutoSeek.tsx +9 -7
- package/reactHooks/resolvers/useCellResolver.ts +5 -1
- package/reactHooks/useConfiguration.ts +2 -2
- package/reactHooks/utils/index.ts +13 -0
- package/reactUtils/index.ts +1 -16
- package/services/localStorageServiceSync.web.ts +48 -0
- package/services/sessionStorageServiceSync.web.ts +32 -0
- package/services/storageServiceSync.web.ts +24 -0
- package/services/storageWebUtils.web.ts +10 -0
- package/testUtils/index.tsx +42 -9
- package/appUtils/keyCodes/keys.ios.js +0 -46
- /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
- /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
- /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
- /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
- /package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +0 -0
- /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
- /package/domUtils/{logger.js → logger.ts} +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { SubscriberObj } from "../../functionUtils";
|
|
2
|
+
import { HOOKS_EVENTS } from "./constants";
|
|
3
|
+
|
|
4
|
+
export interface HookConfiguration {}
|
|
5
|
+
|
|
6
|
+
/* existing Hook Plugn props: sample */
|
|
7
|
+
interface _HookModulePlugin {
|
|
8
|
+
Component:
|
|
9
|
+
| React.FC<HookPluginProps>
|
|
10
|
+
| React.Component<HookPluginProps, any>
|
|
11
|
+
| React.ReactNode;
|
|
12
|
+
ModalContainer?: React.FC<ModalProps> | React.Component<ModalProps, any>;
|
|
13
|
+
skipHook?: (payload: ZappRiver | ZappEntry) => boolean;
|
|
14
|
+
presentFullScreen: boolean;
|
|
15
|
+
showNavBar?: boolean;
|
|
16
|
+
isFlowBlocker: (() => boolean) | boolean; // narrow this
|
|
17
|
+
hasPlayerHook?: boolean;
|
|
18
|
+
name: string;
|
|
19
|
+
runInBackground?: (
|
|
20
|
+
item: HookPluginProps["payload"],
|
|
21
|
+
callback: hookCallback,
|
|
22
|
+
hookPlugin: HookScreenData,
|
|
23
|
+
presentUI: (payload?: HookPluginProps["payload"]) => void
|
|
24
|
+
) => any;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//* Derived from usage */
|
|
28
|
+
export interface HookModule {
|
|
29
|
+
ModalContainer?: React.ComponentType<any>;
|
|
30
|
+
Component: React.ComponentType<any>;
|
|
31
|
+
presentFullScreen: boolean;
|
|
32
|
+
run?: (
|
|
33
|
+
arg0: unknown,
|
|
34
|
+
callback: () => void,
|
|
35
|
+
configuration: HookConfiguration
|
|
36
|
+
) => void; // not sure about optional parameter
|
|
37
|
+
hasPlayerHook?: boolean;
|
|
38
|
+
configuration?: HookConfiguration;
|
|
39
|
+
isFlowBlocker: () => boolean;
|
|
40
|
+
skipHook?: (payload?: ZappRiver | ZappEntry) => boolean;
|
|
41
|
+
runInBackground?: (
|
|
42
|
+
arg0: unknown,
|
|
43
|
+
callback: () => void,
|
|
44
|
+
hookPlugin: Hook,
|
|
45
|
+
presentUI: (payload?: HookPluginProps["payload"]) => void
|
|
46
|
+
) => void;
|
|
47
|
+
name: string;
|
|
48
|
+
showNavBar?: boolean; // unsure
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export type HookManagerArgs = {
|
|
52
|
+
rivers: Record<string, ZappRiver>;
|
|
53
|
+
plugins: ZappPlugin[];
|
|
54
|
+
targetScreen: ZappRiver;
|
|
55
|
+
startUpHooksData?: {
|
|
56
|
+
startUpHooks?: unknown[] | "in_process";
|
|
57
|
+
setStartUpHooks?: (arg0: string) => void;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export interface HookManager {
|
|
62
|
+
subscriber: SubscriberObj;
|
|
63
|
+
presentScreenHook: (
|
|
64
|
+
hook: Hook,
|
|
65
|
+
payload: unknown,
|
|
66
|
+
callback: (...any) => void
|
|
67
|
+
) => void;
|
|
68
|
+
executeHook: (
|
|
69
|
+
hook: Hook,
|
|
70
|
+
payload: unknown,
|
|
71
|
+
callback: (...any) => void
|
|
72
|
+
) => void;
|
|
73
|
+
handleHooks: (payload: unknown) => void;
|
|
74
|
+
runInBackground: (
|
|
75
|
+
hook: Hook,
|
|
76
|
+
payload: unknown,
|
|
77
|
+
callback: (...any) => void,
|
|
78
|
+
presentUI: (payload?: HookPluginProps["payload"]) => void
|
|
79
|
+
) => void;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export type HookIniObj = {
|
|
83
|
+
hook: HookModule & {
|
|
84
|
+
module: HookModule;
|
|
85
|
+
general: unknown;
|
|
86
|
+
screen_id?: string;
|
|
87
|
+
identifier?: string;
|
|
88
|
+
weight?: number | string;
|
|
89
|
+
};
|
|
90
|
+
hooks: Hook<any>[];
|
|
91
|
+
manager: HookManager;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export interface Hook<T extends HookModule = HookModule> {
|
|
95
|
+
manager: HookManager;
|
|
96
|
+
lastHook: boolean;
|
|
97
|
+
state: number;
|
|
98
|
+
module: T;
|
|
99
|
+
screen_id: string;
|
|
100
|
+
identifier: string;
|
|
101
|
+
configuration: T["configuration"];
|
|
102
|
+
setStateAndNotify(
|
|
103
|
+
event: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS],
|
|
104
|
+
opts: {
|
|
105
|
+
error?: typeof Error;
|
|
106
|
+
route?: string;
|
|
107
|
+
hookPlugin: Hook<T>;
|
|
108
|
+
payload: unknown;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
general?: {
|
|
112
|
+
transition_type: typeof HOOKS_EVENTS[keyof typeof HOOKS_EVENTS];
|
|
113
|
+
allow_screen_plugin_presentation: boolean;
|
|
114
|
+
is_flow_blocker: boolean;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -26,7 +26,7 @@ export const riverFocusManager = (function () {
|
|
|
26
26
|
/**
|
|
27
27
|
* Retrieve screen focus data by id
|
|
28
28
|
*
|
|
29
|
-
* @param {
|
|
29
|
+
* @param {{screenFocusableGroupId: string}} screenFocusableGroupId Unique Id of the screen from layout.json
|
|
30
30
|
*
|
|
31
31
|
*/
|
|
32
32
|
function screenFocusableData({ screenFocusableGroupId }) {
|
|
@@ -36,8 +36,9 @@ export const riverFocusManager = (function () {
|
|
|
36
36
|
/**
|
|
37
37
|
* Clear screen data for specific screen
|
|
38
38
|
*
|
|
39
|
-
* @param {
|
|
40
|
-
*
|
|
39
|
+
* @param {{ screenId: string, isInsideContainer: boolean }}
|
|
40
|
+
* screenId Unique Id of the screen from layout.json
|
|
41
|
+
* isInsideContainer If this screen a screen picker child
|
|
41
42
|
*
|
|
42
43
|
*/
|
|
43
44
|
function clearScreenData({ screenId, isInsideContainer }) {
|
|
@@ -60,9 +61,13 @@ export const riverFocusManager = (function () {
|
|
|
60
61
|
/**
|
|
61
62
|
* Focus on selected items
|
|
62
63
|
*
|
|
63
|
-
* @param {
|
|
64
|
-
*
|
|
65
|
-
*
|
|
64
|
+
* @param {{
|
|
65
|
+
* screenFocusableGroupId: string,
|
|
66
|
+
* screenFocusedOnItem: () => void,
|
|
67
|
+
* previousAction: QuickBrickNavigationActionType,
|
|
68
|
+
* isDeepLink: boolean }} object contains data for focus
|
|
69
|
+
* - `screenFocusedOnItem` focusable item to focus
|
|
70
|
+
* - `previousActionhistory` navigator history object
|
|
66
71
|
*
|
|
67
72
|
*/
|
|
68
73
|
function focusOnSelectedItem({
|
|
@@ -115,15 +120,15 @@ export const riverFocusManager = (function () {
|
|
|
115
120
|
|
|
116
121
|
/**
|
|
117
122
|
* Create unique key that will be used for save focused group data inside specific screen
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
123
|
+
* @param {{ screenId: string, isInsideContainer: boolean }}
|
|
124
|
+
* screenId Unique Id of the screen from layout.json
|
|
125
|
+
* isInsideContainer If this screen a screen picker child
|
|
121
126
|
*
|
|
122
127
|
*/
|
|
123
128
|
function screenFocusableGroupId({ screenId, isInsideContainer }) {
|
|
124
|
-
return
|
|
125
|
-
?
|
|
126
|
-
|
|
129
|
+
return `RiverFocusableGroup-${screenId}${
|
|
130
|
+
R.isNil(isInsideContainer) ? "" : "-isInsideContainer"
|
|
131
|
+
}`;
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
return {
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import { useEffect, useMemo } from "react";
|
|
2
|
-
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
2
|
import { AccessibilityManager } from "./index";
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
/**
|
|
5
|
+
* This hook is used to instantiate the accessibility manager and update localizations used by the class.
|
|
6
|
+
* If the plugin config is not provided or it does not contain any localizations, the accessibility manager will not be updated.
|
|
7
|
+
* We use the plugin configuration because it offers a flattened structure where we can easily access the accessibility labels and hints
|
|
8
|
+
* i.e. pluginConfiguration = {
|
|
9
|
+
* accessibility_close_label: "Close",
|
|
10
|
+
* accessibility_close_hint: "Press here to close",
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
export const useAccessibilityManager = (
|
|
14
|
+
pluginConfiguration: Record<string, any> = {}
|
|
15
|
+
) => {
|
|
9
16
|
const accessibilityManager = useMemo(() => {
|
|
10
17
|
return AccessibilityManager.getInstance();
|
|
11
18
|
}, []);
|
|
12
19
|
|
|
13
20
|
useEffect(() => {
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
if (pluginConfiguration) {
|
|
22
|
+
accessibilityManager.updateLocalizations(pluginConfiguration);
|
|
23
|
+
}
|
|
24
|
+
}, [pluginConfiguration, accessibilityManager]);
|
|
16
25
|
|
|
17
26
|
useEffect(() => {
|
|
18
27
|
const subscription = accessibilityManager.getStateAsObservable().subscribe({
|
|
@@ -1,21 +1,8 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
2
|
import { accessibilityManagerLogger as logger } from "./logger";
|
|
3
3
|
import { TTSManager } from "../platform/platformUtils";
|
|
4
|
-
import { getLocalizations } from "../../localizationUtils";
|
|
5
4
|
import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
|
|
6
|
-
|
|
7
|
-
export interface AccessibilityState {
|
|
8
|
-
screenReaderEnabled: boolean;
|
|
9
|
-
reduceMotionEnabled: boolean;
|
|
10
|
-
boldTextEnabled: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface AccessibilityProps {
|
|
14
|
-
accessibilityLabel?: string;
|
|
15
|
-
accessibilityHint?: string;
|
|
16
|
-
"aria-label"?: string;
|
|
17
|
-
"aria-description"?: string;
|
|
18
|
-
}
|
|
5
|
+
import { AccessibilityRole } from "react-native";
|
|
19
6
|
|
|
20
7
|
export class AccessibilityManager {
|
|
21
8
|
private static _instance: AccessibilityManager | null = null;
|
|
@@ -32,13 +19,9 @@ export class AccessibilityManager {
|
|
|
32
19
|
} | null>(null);
|
|
33
20
|
|
|
34
21
|
private ttsManager = TTSManager.getInstance();
|
|
35
|
-
private localizations: { [key: string]: string };
|
|
22
|
+
private localizations: { [key: string]: string } = {};
|
|
36
23
|
|
|
37
|
-
private constructor(
|
|
38
|
-
if (localizations) {
|
|
39
|
-
this.localizations = getLocalizations({ localizations });
|
|
40
|
-
}
|
|
41
|
-
}
|
|
24
|
+
private constructor() {}
|
|
42
25
|
|
|
43
26
|
public static getInstance(): AccessibilityManager {
|
|
44
27
|
if (!AccessibilityManager._instance) {
|
|
@@ -48,8 +31,17 @@ export class AccessibilityManager {
|
|
|
48
31
|
return AccessibilityManager._instance;
|
|
49
32
|
}
|
|
50
33
|
|
|
34
|
+
/**
|
|
35
|
+
* The method now accepts any object with localizations using a flattened structure
|
|
36
|
+
*
|
|
37
|
+
* i.e. { accessibility_close_label: "Close", accessibility_close_hint: "Press here to close" }
|
|
38
|
+
*
|
|
39
|
+
* No longer accepts:
|
|
40
|
+
*
|
|
41
|
+
* i.e. localizations: [{ en: { accessibility_close_label: "Close", accessibility_close_hint: "Press here to close" } }]
|
|
42
|
+
*/
|
|
51
43
|
public updateLocalizations(localizations: { [key: string]: string }) {
|
|
52
|
-
this.localizations =
|
|
44
|
+
this.localizations = localizations;
|
|
53
45
|
}
|
|
54
46
|
|
|
55
47
|
public getState(): AccessibilityState {
|
|
@@ -71,7 +63,7 @@ export class AccessibilityManager {
|
|
|
71
63
|
text: string;
|
|
72
64
|
keyOfLocalizedText?: string;
|
|
73
65
|
}) {
|
|
74
|
-
|
|
66
|
+
let textToRead = text;
|
|
75
67
|
|
|
76
68
|
if (keyOfLocalizedText) {
|
|
77
69
|
if (!this.localizations) {
|
|
@@ -90,16 +82,14 @@ export class AccessibilityManager {
|
|
|
90
82
|
return;
|
|
91
83
|
}
|
|
92
84
|
|
|
93
|
-
|
|
85
|
+
textToRead = localizedMessage;
|
|
94
86
|
}
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
this.ttsManager.readText(text);
|
|
98
|
-
}
|
|
88
|
+
this.ttsManager && this.ttsManager.readText(textToRead);
|
|
99
89
|
|
|
100
90
|
this.announcements$.next({
|
|
101
|
-
message:
|
|
102
|
-
localizedMessage: keyOfLocalizedText ?
|
|
91
|
+
message: textToRead,
|
|
92
|
+
localizedMessage: keyOfLocalizedText ? textToRead : undefined,
|
|
103
93
|
timestamp: Date.now(),
|
|
104
94
|
});
|
|
105
95
|
}
|
|
@@ -113,6 +103,8 @@ export class AccessibilityManager {
|
|
|
113
103
|
accessibilityHint: `Press button to perform action on ${buttonName}`,
|
|
114
104
|
"aria-label": buttonName,
|
|
115
105
|
"aria-description": `Press button to perform action on ${buttonName}`,
|
|
106
|
+
accessibilityRole: "button" as AccessibilityRole,
|
|
107
|
+
"aria-role": "button",
|
|
116
108
|
};
|
|
117
109
|
}
|
|
118
110
|
|
|
@@ -130,6 +122,19 @@ export class AccessibilityManager {
|
|
|
130
122
|
accessibilityHint: hint,
|
|
131
123
|
"aria-label": label,
|
|
132
124
|
"aria-description": hint,
|
|
125
|
+
accessibilityRole: "button" as AccessibilityRole,
|
|
126
|
+
"aria-role": "button",
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public getInputAccessibilityProps(inputName: string): AccessibilityProps {
|
|
131
|
+
return {
|
|
132
|
+
accessibilityLabel: inputName,
|
|
133
|
+
accessibilityHint: `Enter text into ${inputName}`,
|
|
134
|
+
"aria-label": inputName,
|
|
135
|
+
"aria-description": `Enter text into ${inputName}`,
|
|
136
|
+
accessibilityRole: "textbox" as AccessibilityRole,
|
|
137
|
+
"aria-role": "textbox",
|
|
133
138
|
};
|
|
134
139
|
}
|
|
135
140
|
|
|
@@ -59,7 +59,7 @@ export class Tree {
|
|
|
59
59
|
/**
|
|
60
60
|
* Update node with provided data from newNode
|
|
61
61
|
* @private
|
|
62
|
-
* @param {Object}
|
|
62
|
+
* @param {Object} currentNode to update
|
|
63
63
|
* @param {Object} newNode node to take data from
|
|
64
64
|
*/
|
|
65
65
|
updateNode(currentNode, newNode) {
|
|
@@ -175,7 +175,6 @@ export class Tree {
|
|
|
175
175
|
* @private
|
|
176
176
|
* @param {Object} node to check
|
|
177
177
|
* @returns True if node has defined groupID
|
|
178
|
-
* @returns False if node has NOT defined groupID
|
|
179
178
|
*/
|
|
180
179
|
hasGroupID(node) {
|
|
181
180
|
return node.component && node.component.props.groupId;
|
|
@@ -191,7 +190,7 @@ export class Tree {
|
|
|
191
190
|
const findChildNode = this.findInTree(node.component.props.groupId);
|
|
192
191
|
|
|
193
192
|
if (findChildNode) {
|
|
194
|
-
this.root.children.pop(
|
|
193
|
+
this.root.children.pop();
|
|
195
194
|
node.children.push(findChildNode);
|
|
196
195
|
}
|
|
197
196
|
}
|
|
@@ -191,7 +191,6 @@ const toDistance = ({ target, direction, comparisonRect }) => {
|
|
|
191
191
|
* Get target in shortest distance in specified direction
|
|
192
192
|
* @private
|
|
193
193
|
* @param {Object} direction of the navigation, which led to this focus change
|
|
194
|
-
* @param {Object} excludedNode node which should be excluded from target group
|
|
195
194
|
* @param {Array} targetNodes array of input target nodes
|
|
196
195
|
* @param {Object} comparisonRect rectangle to compare sides in direction.
|
|
197
196
|
* @returns {Object} target in direction.
|
|
@@ -300,8 +299,7 @@ export function findFocusableNode(direction, currentFocusNode) {
|
|
|
300
299
|
* @public
|
|
301
300
|
* @param {Object} direction of the navigation, which led to this focus change
|
|
302
301
|
* @param {Object} component - object to check props.prioritiseFocusOn
|
|
303
|
-
* @returns {Boolean} TRUE if object has priority in direction.
|
|
304
|
-
* @returns {Boolean} FALSE if object has NO priority in direction.
|
|
302
|
+
* @returns {Boolean} TRUE if object has priority in direction. FALSE if object has NO priority in direction.
|
|
305
303
|
*/
|
|
306
304
|
export function hasPriorityInDirection(direction, component) {
|
|
307
305
|
const { prioritiseFocusOn = 0 } = component.props;
|
|
@@ -9,7 +9,7 @@ export { KEYS, ARROW_KEYS } from "./keyCodes/keys";
|
|
|
9
9
|
|
|
10
10
|
export { playerManager } from "./playerManager";
|
|
11
11
|
|
|
12
|
-
export {
|
|
12
|
+
export { AccessibilityManager } from "./accessibilityManager";
|
|
13
13
|
|
|
14
14
|
export function deprecationMessage(fn, replacement) {
|
|
15
15
|
if (__DEV__ && process.env.NODE_ENV !== "test") {
|
|
@@ -13,7 +13,7 @@ const globalTizen = {
|
|
|
13
13
|
describe("keyCodes", () => {
|
|
14
14
|
describe("keyCode", () => {
|
|
15
15
|
const { keyCode } = require("..");
|
|
16
|
-
const { KEYS } = require("../keys.web");
|
|
16
|
+
const { KEYS } = require("../keys/keys.web");
|
|
17
17
|
|
|
18
18
|
it("returns an object for a given key event", () => {
|
|
19
19
|
expect(keyCode(KEYS.Enter)).toMatchSnapshot();
|
|
@@ -63,7 +63,7 @@ describe("keyCodes", () => {
|
|
|
63
63
|
it("uses the proper keyCode for the environment", () => {
|
|
64
64
|
Platform.OS = "samsung_tv";
|
|
65
65
|
const { keyCode } = require("../");
|
|
66
|
-
const { KEYS } = require("../keys.web");
|
|
66
|
+
const { KEYS } = require("../keys/keys.web");
|
|
67
67
|
|
|
68
68
|
expect(globalTizen.tvinputdevice.registerKeyBatch).toHaveBeenCalledWith([
|
|
69
69
|
"MediaPlay",
|
|
@@ -97,7 +97,7 @@ describe("keyCodes", () => {
|
|
|
97
97
|
it("uses the proper keyCode for the environment", () => {
|
|
98
98
|
Platform.OS = "lg_tv";
|
|
99
99
|
const { keyCode } = require("..");
|
|
100
|
-
const { KEYS } = require("../keys.web");
|
|
100
|
+
const { KEYS } = require("../keys/keys.web");
|
|
101
101
|
// Back is reserved on LG
|
|
102
102
|
expect(keyCode({ keyCode: 417 }).matches(KEYS.Forward)).toBeTruthy();
|
|
103
103
|
});
|
|
@@ -1,22 +1,3 @@
|
|
|
1
|
-
export const KEYS = {
|
|
2
|
-
Enter: { code: "Enter", keyCode: 13 },
|
|
3
|
-
EnterKeyboard: { code: "EnterKeyboard", keyCode: 66 },
|
|
4
|
-
Back: { code: "Back", keyCode: 8 },
|
|
5
|
-
Space: { code: "Space", keyCode: 32 },
|
|
6
|
-
m: { code: "m", keyCode: 77 },
|
|
7
|
-
ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
|
|
8
|
-
ArrowUp: { code: "ArrowUp", keyCode: 38 },
|
|
9
|
-
ArrowRight: { code: "ArrowRight", keyCode: 39 },
|
|
10
|
-
ArrowDown: { code: "ArrowDown", keyCode: 40 },
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export const ARROW_KEYS = [
|
|
14
|
-
KEYS.ArrowUp,
|
|
15
|
-
KEYS.ArrowLeft,
|
|
16
|
-
KEYS.ArrowDown,
|
|
17
|
-
KEYS.ArrowRight,
|
|
18
|
-
];
|
|
19
|
-
|
|
20
1
|
export function keyEventMapper(keyCode) {
|
|
21
2
|
switch (keyCode) {
|
|
22
3
|
case 19: // ArrowUp
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const KEYS = {
|
|
2
|
+
Enter: { code: "Enter", keyCode: 13 },
|
|
3
|
+
EnterKeyboard: { code: "EnterKeyboard", keyCode: 66 },
|
|
4
|
+
Back: { code: "Back", keyCode: 8 },
|
|
5
|
+
Space: { code: "Space", keyCode: 32 },
|
|
6
|
+
m: { code: "m", keyCode: 77 },
|
|
7
|
+
ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
|
|
8
|
+
ArrowUp: { code: "ArrowUp", keyCode: 38 },
|
|
9
|
+
ArrowRight: { code: "ArrowRight", keyCode: 39 },
|
|
10
|
+
ArrowDown: { code: "ArrowDown", keyCode: 40 },
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const ARROW_KEYS = [
|
|
14
|
+
KEYS.ArrowUp,
|
|
15
|
+
KEYS.ArrowLeft,
|
|
16
|
+
KEYS.ArrowDown,
|
|
17
|
+
KEYS.ArrowRight,
|
|
18
|
+
];
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const KEYS = {
|
|
2
|
+
Enter: { code: "Enter", keyCode: 13 },
|
|
3
|
+
Space: { code: "Space", keyCode: 32 },
|
|
4
|
+
m: { code: "m", keyCode: 77 },
|
|
5
|
+
ArrowLeft: { code: "ArrowLeft", keyCode: 37 },
|
|
6
|
+
ArrowUp: { code: "ArrowUp", keyCode: 38 },
|
|
7
|
+
ArrowRight: { code: "ArrowRight", keyCode: 39 },
|
|
8
|
+
ArrowDown: { code: "ArrowDown", keyCode: 40 },
|
|
9
|
+
Back: { code: "Backspace", keyCode: 8 },
|
|
10
|
+
Play: { code: "PlayPause", keyCode: 179 },
|
|
11
|
+
Pause: { code: "Pause", keyCode: 179 },
|
|
12
|
+
Forward: { code: "Forward", keyCode: 176 },
|
|
13
|
+
Rewind: { code: "Rewind", keyCode: 177 },
|
|
14
|
+
VolumeUp: { code: "VolumeUp", keyCode: 175 },
|
|
15
|
+
VolumeDown: { code: "VolumeDown", keyCode: 174 },
|
|
16
|
+
ToggleMute: { code: "VolumeMute", keyCode: 173 },
|
|
17
|
+
Stop: { code: "Q", keyCode: 81 },
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const ARROW_KEYS = [
|
|
21
|
+
KEYS.ArrowUp,
|
|
22
|
+
KEYS.ArrowLeft,
|
|
23
|
+
KEYS.ArrowDown,
|
|
24
|
+
KEYS.ArrowRight,
|
|
25
|
+
];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// dummy file to make sure the folder structure is created
|
|
2
|
+
export const KEYS: Record<string, { code: string; keyCode: number }> = {
|
|
3
|
+
ArrowLeft: { code: "ArrowLeft", keyCode: -1 },
|
|
4
|
+
ArrowUp: { code: "ArrowUp", keyCode: -1 },
|
|
5
|
+
ArrowRight: { code: "ArrowRight", keyCode: -1 },
|
|
6
|
+
ArrowDown: { code: "ArrowDown", keyCode: -1 },
|
|
7
|
+
Back: { code: "Back", keyCode: -1 },
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ARROW_KEYS = [
|
|
11
|
+
KEYS.ArrowUp,
|
|
12
|
+
KEYS.ArrowLeft,
|
|
13
|
+
KEYS.ArrowDown,
|
|
14
|
+
KEYS.ArrowRight,
|
|
15
|
+
];
|
|
@@ -1,32 +1,21 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
2
|
|
|
3
3
|
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
4
|
+
import {
|
|
5
|
+
isLgPlatform,
|
|
6
|
+
isSamsungPlatform,
|
|
7
|
+
} from "@applicaster/zapp-react-dom-app/App/Loader/utils/platform";
|
|
4
8
|
|
|
5
9
|
import { PLATFORM_KEYS, PLATFORMS } from "./const";
|
|
6
10
|
import { createLogger, utilsLogger } from "../../logger";
|
|
7
11
|
|
|
8
|
-
declare global {
|
|
9
|
-
interface Window {
|
|
10
|
-
VIZIO?: {
|
|
11
|
-
exitApplication: () => void;
|
|
12
|
-
Chromevox: {
|
|
13
|
-
play: (text: string) => void;
|
|
14
|
-
};
|
|
15
|
-
setClosedCaptionHandler: (
|
|
16
|
-
callback: (isCCEnabled: boolean) => void
|
|
17
|
-
) => void;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
12
|
const { log_debug } = createLogger({
|
|
23
13
|
category: "General",
|
|
24
14
|
subsystem: "PlatformUtils",
|
|
25
15
|
parent: utilsLogger,
|
|
26
16
|
});
|
|
27
17
|
|
|
28
|
-
export const getUserAgent = () =>
|
|
29
|
-
window?.navigator?.userAgent || global?.navigator?.userAgent;
|
|
18
|
+
export const getUserAgent = () => window?.navigator?.userAgent;
|
|
30
19
|
|
|
31
20
|
/** VIZIO UTILS */
|
|
32
21
|
|
|
@@ -39,6 +28,8 @@ export const getUserAgent = () =>
|
|
|
39
28
|
export const isVizioPlatform = () => {
|
|
40
29
|
const userAgent = getUserAgent();
|
|
41
30
|
|
|
31
|
+
if (!userAgent) return false;
|
|
32
|
+
|
|
42
33
|
const isVizioAgent =
|
|
43
34
|
userAgent.includes(PLATFORMS.vizio) ||
|
|
44
35
|
userAgent.includes(PLATFORMS.smartcast) ||
|
|
@@ -178,6 +169,34 @@ export class TTSManager {
|
|
|
178
169
|
}
|
|
179
170
|
|
|
180
171
|
readText(text: string) {
|
|
172
|
+
if (isSamsungPlatform() && window.speechSynthesis) {
|
|
173
|
+
const utterance = new SpeechSynthesisUtterance(text);
|
|
174
|
+
window.speechSynthesis.speak(utterance);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (isLgPlatform() && window.webOS?.service) {
|
|
178
|
+
try {
|
|
179
|
+
window.webOS.service.request("luna://com.webos.service.tts", {
|
|
180
|
+
method: "speak",
|
|
181
|
+
onFailure(error: any) {
|
|
182
|
+
log_debug("There was a failure setting up webOS TTS service", {
|
|
183
|
+
error,
|
|
184
|
+
});
|
|
185
|
+
},
|
|
186
|
+
onSuccess(response: any) {
|
|
187
|
+
log_debug("webOS TTS service is configured successfully", {
|
|
188
|
+
response,
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
parameters: {
|
|
192
|
+
text,
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
} catch (error) {
|
|
196
|
+
log_debug("webOS TTS service error", { error });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
181
200
|
if (!window.VIZIO?.Chromevox) return;
|
|
182
201
|
|
|
183
202
|
window.VIZIO.Chromevox.play(text);
|
|
@@ -3,7 +3,6 @@ import * as R from "ramda";
|
|
|
3
3
|
import { subscriber } from "../../functionUtils";
|
|
4
4
|
import { utilsLogger, createLogger } from "../../logger";
|
|
5
5
|
import { Player } from "./player";
|
|
6
|
-
import { AnalyticsTracker } from "../../analyticsUtils/analyticsTracker";
|
|
7
6
|
import {
|
|
8
7
|
hasTizenAPIs,
|
|
9
8
|
subscribeToDeviceNetworkChanges,
|
|
@@ -37,7 +36,10 @@ export interface PlayerLifecycleListener {
|
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
type PlayersMap = {
|
|
40
|
-
[id: string]: {
|
|
39
|
+
[id: string]: {
|
|
40
|
+
player: Player;
|
|
41
|
+
isInViewport: boolean;
|
|
42
|
+
};
|
|
41
43
|
};
|
|
42
44
|
|
|
43
45
|
export class PlayerManager {
|
|
@@ -46,7 +48,6 @@ export class PlayerManager {
|
|
|
46
48
|
private playersMap: PlayersMap = {};
|
|
47
49
|
private manager = subscriber();
|
|
48
50
|
private castingReceiver: Player;
|
|
49
|
-
private analyticsTracker: AnalyticsTracker;
|
|
50
51
|
private lifecycleListeners: PlayerLifecycleListener[] = [];
|
|
51
52
|
|
|
52
53
|
public static getInstance() {
|
|
@@ -57,7 +58,7 @@ export class PlayerManager {
|
|
|
57
58
|
return PlayerManager.instance;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
public getActivePlayerId = ():
|
|
61
|
+
public getActivePlayerId = (): string | null => {
|
|
61
62
|
return this.activePlayerId;
|
|
62
63
|
};
|
|
63
64
|
|
|
@@ -102,7 +103,10 @@ export class PlayerManager {
|
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
private addPlayer = (id: string, player: Player) => {
|
|
105
|
-
this.playersMap[id] = {
|
|
106
|
+
this.playersMap[id] = {
|
|
107
|
+
player: player,
|
|
108
|
+
isInViewport: false,
|
|
109
|
+
};
|
|
106
110
|
};
|
|
107
111
|
|
|
108
112
|
public isPlayerRegistered = (id: string) => !!this.playersMap[id];
|
|
@@ -251,28 +255,6 @@ export class PlayerManager {
|
|
|
251
255
|
this.castingReceiver = null;
|
|
252
256
|
}
|
|
253
257
|
|
|
254
|
-
/**
|
|
255
|
-
* Handles analytic events, generates a new analytics tracker and transmits events
|
|
256
|
-
* Passes entry data, and playerState to the tracker for additional context
|
|
257
|
-
* The end result is an event formatted and passed to AnalyticsBridge.postEvent
|
|
258
|
-
* When we get the synthetic event we need to pull the data in the e object
|
|
259
|
-
* e contains the return value from native
|
|
260
|
-
*/
|
|
261
|
-
public handleAnalyticEvent(event, data = {}, entry: ZappEntry) {
|
|
262
|
-
const playerState = this.getActivePlayer()?.getState();
|
|
263
|
-
|
|
264
|
-
if (!this.analyticsTracker?.handleAnalyticEvent) {
|
|
265
|
-
this.analyticsTracker = new AnalyticsTracker(entry);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
this.analyticsTracker?.handleAnalyticEvent?.(
|
|
269
|
-
event,
|
|
270
|
-
data,
|
|
271
|
-
entry,
|
|
272
|
-
playerState
|
|
273
|
-
);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
258
|
/**
|
|
277
259
|
* Method retrieves the instantiated player instance controller
|
|
278
260
|
* Instance controller exposes methods like getContentDuration, getContentPosision
|