@applicaster/zapp-react-native-utils 12.0.0-alpha.9262177070 → 12.0.0-alpha.9388848580
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/appUtils/accessibilityManager/const.ts +50 -0
- package/appUtils/accessibilityManager/hooks.ts +40 -0
- package/appUtils/accessibilityManager/index.ts +155 -0
- package/appUtils/accessibilityManager/logger.ts +5 -0
- package/appUtils/focusManager/index.ts +0 -1
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -1
- package/appUtils/index.js +2 -0
- package/appUtils/platform/platformUtils.ts +43 -81
- package/appUtils/playerManager/player.ts +1 -0
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -0
- package/cellUtils/index.ts +5 -5
- package/index.d.ts +15 -0
- package/navigationUtils/index.ts +48 -0
- package/numberUtils/__tests__/toNumber.test.ts +2 -2
- package/package.json +2 -2
- package/playerUtils/imaScriptDom.ts +59 -0
- package/pluginUtils/index.ts +9 -0
- package/reactHooks/navigation/index.ts +4 -0
- package/reactUtils/index.ts +4 -2
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export const BUTTON_ACCESSIBILITY_KEYS = {
|
|
2
|
+
play: {
|
|
3
|
+
label: "accessibility_play_label",
|
|
4
|
+
hint: "accessibility_play_hint",
|
|
5
|
+
mini: {
|
|
6
|
+
label: "accessibility_play_mini_label",
|
|
7
|
+
hint: "accessibility_play_mini_hint",
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
pause: {
|
|
11
|
+
label: "accessibility_pause_label",
|
|
12
|
+
hint: "accessibility_pause_hint",
|
|
13
|
+
mini: {
|
|
14
|
+
label: "accessibility_pause_mini_label",
|
|
15
|
+
hint: "accessibility_pause_mini_hint",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
rewind: {
|
|
19
|
+
label: "accessibility_rewind_label",
|
|
20
|
+
hint: "accessibility_rewind_hint",
|
|
21
|
+
},
|
|
22
|
+
forward: {
|
|
23
|
+
label: "accessibility_forward_label",
|
|
24
|
+
hint: "accessibility_forward_hint",
|
|
25
|
+
},
|
|
26
|
+
close: {
|
|
27
|
+
label: "accessibility_close_label",
|
|
28
|
+
hint: "accessibility_close_hint",
|
|
29
|
+
mini: {
|
|
30
|
+
label: "accessibility_close_mini_label",
|
|
31
|
+
hint: "accessibility_close_mini_hint",
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
maximize: {
|
|
35
|
+
label: "accessibility_maximize_label",
|
|
36
|
+
hint: "accessibility_maximize_hint",
|
|
37
|
+
},
|
|
38
|
+
subtitles: {
|
|
39
|
+
label: "accessibility_subtitle_label",
|
|
40
|
+
hint: "accessibility_subtitle_hint",
|
|
41
|
+
},
|
|
42
|
+
back: {
|
|
43
|
+
label: "accessibility_back_label",
|
|
44
|
+
hint: "accessibility_back_hint",
|
|
45
|
+
},
|
|
46
|
+
fullscreen: {
|
|
47
|
+
label: "accessibility_fullscreen_label",
|
|
48
|
+
hint: "accessibility_fullscreen_hint",
|
|
49
|
+
},
|
|
50
|
+
} as const;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useEffect, useMemo } from "react";
|
|
2
|
+
import { AccessibilityManager } from "./index";
|
|
3
|
+
|
|
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
|
+
) => {
|
|
16
|
+
const accessibilityManager = useMemo(() => {
|
|
17
|
+
return AccessibilityManager.getInstance();
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (pluginConfiguration) {
|
|
22
|
+
accessibilityManager.updateLocalizations(pluginConfiguration);
|
|
23
|
+
}
|
|
24
|
+
}, [pluginConfiguration, accessibilityManager]);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const subscription = accessibilityManager.getStateAsObservable().subscribe({
|
|
28
|
+
next: () => {
|
|
29
|
+
// TODO: handle accessibility states
|
|
30
|
+
// screenReaderEnabled: false
|
|
31
|
+
// reduceMotionEnabled: false
|
|
32
|
+
// boldTextEnabled: false
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return () => subscription.unsubscribe();
|
|
37
|
+
}, [accessibilityManager]);
|
|
38
|
+
|
|
39
|
+
return accessibilityManager;
|
|
40
|
+
};
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
import { accessibilityManagerLogger as logger } from "./logger";
|
|
3
|
+
import { TTSManager } from "../platform/platformUtils";
|
|
4
|
+
import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
|
|
5
|
+
import { AccessibilityRole } from "react-native";
|
|
6
|
+
|
|
7
|
+
export class AccessibilityManager {
|
|
8
|
+
private static _instance: AccessibilityManager | null = null;
|
|
9
|
+
private state$ = new BehaviorSubject<AccessibilityState>({
|
|
10
|
+
screenReaderEnabled: false,
|
|
11
|
+
reduceMotionEnabled: false,
|
|
12
|
+
boldTextEnabled: false,
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
private announcements$ = new BehaviorSubject<{
|
|
16
|
+
message: string;
|
|
17
|
+
localizedMessage?: string | undefined;
|
|
18
|
+
timestamp: number;
|
|
19
|
+
} | null>(null);
|
|
20
|
+
|
|
21
|
+
private ttsManager = TTSManager.getInstance();
|
|
22
|
+
private localizations: { [key: string]: string } = {};
|
|
23
|
+
|
|
24
|
+
private constructor() {}
|
|
25
|
+
|
|
26
|
+
public static getInstance(): AccessibilityManager {
|
|
27
|
+
if (!AccessibilityManager._instance) {
|
|
28
|
+
AccessibilityManager._instance = new AccessibilityManager();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return AccessibilityManager._instance;
|
|
32
|
+
}
|
|
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
|
+
*/
|
|
43
|
+
public updateLocalizations(localizations: { [key: string]: string }) {
|
|
44
|
+
this.localizations = localizations;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public getState(): AccessibilityState {
|
|
48
|
+
return this.state$.getValue();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public getStateAsObservable() {
|
|
52
|
+
return this.state$.asObservable();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* text you want to be read, if you want to use localized text pass keyOfLocalizedText instead
|
|
57
|
+
* keyOfLocalizedText is the key to the localized text
|
|
58
|
+
*/
|
|
59
|
+
public readText({
|
|
60
|
+
text,
|
|
61
|
+
keyOfLocalizedText,
|
|
62
|
+
}: {
|
|
63
|
+
text: string;
|
|
64
|
+
keyOfLocalizedText?: string;
|
|
65
|
+
}) {
|
|
66
|
+
let textToRead = text;
|
|
67
|
+
|
|
68
|
+
if (keyOfLocalizedText) {
|
|
69
|
+
if (!this.localizations) {
|
|
70
|
+
logger.error(
|
|
71
|
+
"Attempting to use localized key without initialized localizations"
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const localizedMessage = this.getLocalizedMessage(keyOfLocalizedText);
|
|
78
|
+
|
|
79
|
+
if (!localizedMessage) {
|
|
80
|
+
logger.warn(`No localization found for key: ${keyOfLocalizedText}`);
|
|
81
|
+
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
textToRead = localizedMessage;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.ttsManager) {
|
|
89
|
+
logger.debug({
|
|
90
|
+
message: `Reading text: ${textToRead}`,
|
|
91
|
+
data: {
|
|
92
|
+
textToRead,
|
|
93
|
+
text,
|
|
94
|
+
keyOfLocalizedText,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
this.ttsManager.readText(textToRead);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
this.announcements$.next({
|
|
102
|
+
message: textToRead,
|
|
103
|
+
localizedMessage: keyOfLocalizedText ? textToRead : undefined,
|
|
104
|
+
timestamp: Date.now(),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public getButtonAccessibilityProps(buttonName: string): AccessibilityProps {
|
|
109
|
+
const buttonConfig = BUTTON_ACCESSIBILITY_KEYS[buttonName];
|
|
110
|
+
|
|
111
|
+
if (!buttonConfig) {
|
|
112
|
+
return {
|
|
113
|
+
accessibilityLabel: buttonName,
|
|
114
|
+
accessibilityHint: `Press button to perform action on ${buttonName}`,
|
|
115
|
+
"aria-label": buttonName,
|
|
116
|
+
"aria-description": `Press button to perform action on ${buttonName}`,
|
|
117
|
+
accessibilityRole: "button" as AccessibilityRole,
|
|
118
|
+
"aria-role": "button",
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const labelKey = buttonConfig.label;
|
|
123
|
+
const hintKey = buttonConfig.hint;
|
|
124
|
+
|
|
125
|
+
const label = this.getLocalizedMessage(labelKey) || buttonName;
|
|
126
|
+
|
|
127
|
+
const hint =
|
|
128
|
+
this.getLocalizedMessage(hintKey) ||
|
|
129
|
+
`Press button to perform action on ${buttonName}`;
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
accessibilityLabel: label,
|
|
133
|
+
accessibilityHint: hint,
|
|
134
|
+
"aria-label": label,
|
|
135
|
+
"aria-description": hint,
|
|
136
|
+
accessibilityRole: "button" as AccessibilityRole,
|
|
137
|
+
"aria-role": "button",
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public getLocalizedMessage(key: string): string | void {
|
|
142
|
+
if (!key) return;
|
|
143
|
+
|
|
144
|
+
if (!this.localizations) {
|
|
145
|
+
logger.error(
|
|
146
|
+
"Attempting to use localized key without initialized localizations",
|
|
147
|
+
{ key }
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return this.localizations[key];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
import { subscriber } from "../../functionUtils";
|
|
14
14
|
import * as FOCUS_EVENTS from "./events";
|
|
15
15
|
import { coreLogger } from "../../logger";
|
|
16
|
-
|
|
17
16
|
const logger = coreLogger.addSubsystem("focusManager");
|
|
18
17
|
|
|
19
18
|
const isFocusEnabled = (focusableItem): boolean => {
|
|
@@ -206,7 +206,7 @@ export function getTargetInDirection(
|
|
|
206
206
|
const overrideTarget = currentNode?.component?.props[overridePropName];
|
|
207
207
|
|
|
208
208
|
if (overrideTarget) {
|
|
209
|
-
const target = targetNodes.find((n) => n
|
|
209
|
+
const target = targetNodes.find((n) => n?.id === overrideTarget);
|
|
210
210
|
|
|
211
211
|
if (target) return target;
|
|
212
212
|
}
|
package/appUtils/index.js
CHANGED
|
@@ -9,6 +9,8 @@ export { KEYS, ARROW_KEYS } from "./keyCodes/keys";
|
|
|
9
9
|
|
|
10
10
|
export { playerManager } from "./playerManager";
|
|
11
11
|
|
|
12
|
+
export { accessibilityManager } from "./accessibilityManager";
|
|
13
|
+
|
|
12
14
|
export function deprecationMessage(fn, replacement) {
|
|
13
15
|
if (__DEV__ && process.env.NODE_ENV !== "test") {
|
|
14
16
|
console.warn("/** DEPRECATION WARNING **/");
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { BehaviorSubject } from "rxjs";
|
|
2
2
|
|
|
3
3
|
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
4
|
-
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
5
|
-
import { PlayerWebController } from "@applicaster/zapp-react-native-default-player/src/playerFactory/players/playerWebController";
|
|
6
4
|
|
|
7
5
|
import { PLATFORM_KEYS, PLATFORMS } from "./const";
|
|
8
6
|
import { createLogger, utilsLogger } from "../../logger";
|
|
@@ -11,6 +9,9 @@ declare global {
|
|
|
11
9
|
interface Window {
|
|
12
10
|
VIZIO?: {
|
|
13
11
|
exitApplication: () => void;
|
|
12
|
+
Chromevox: {
|
|
13
|
+
play: (text: string) => void;
|
|
14
|
+
};
|
|
14
15
|
setClosedCaptionHandler: (
|
|
15
16
|
callback: (isCCEnabled: boolean) => void
|
|
16
17
|
) => void;
|
|
@@ -18,7 +19,7 @@ declare global {
|
|
|
18
19
|
}
|
|
19
20
|
}
|
|
20
21
|
|
|
21
|
-
const { log_debug
|
|
22
|
+
const { log_debug } = createLogger({
|
|
22
23
|
category: "General",
|
|
23
24
|
subsystem: "PlatformUtils",
|
|
24
25
|
parent: utilsLogger,
|
|
@@ -63,7 +64,7 @@ export const hasVizioAPIs = () => {
|
|
|
63
64
|
* Manages device based closed captioning state
|
|
64
65
|
* Returns an observable that emits the current state and updates whenever it changes
|
|
65
66
|
*/
|
|
66
|
-
class ClosedCaptioningManager {
|
|
67
|
+
export class ClosedCaptioningManager {
|
|
67
68
|
private ccState$ = new BehaviorSubject<boolean>(false);
|
|
68
69
|
private static ccManagerInstance: ClosedCaptioningManager;
|
|
69
70
|
|
|
@@ -128,96 +129,57 @@ export const getClosedCaptionState = () => {
|
|
|
128
129
|
return ccManager.getStateAsObservable();
|
|
129
130
|
};
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
static
|
|
138
|
-
if (!TextTrackManager.instance) {
|
|
139
|
-
TextTrackManager.instance = new TextTrackManager();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return TextTrackManager.instance;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
initialize(controller: PlayerWebController) {
|
|
146
|
-
if (!controller) {
|
|
147
|
-
throw new Error(
|
|
148
|
-
"Controller is required for TextTrackManager initialization"
|
|
149
|
-
);
|
|
150
|
-
}
|
|
132
|
+
/**
|
|
133
|
+
* Manages device based closed captioning state
|
|
134
|
+
* Returns an observable that emits the current state and updates whenever it changes
|
|
135
|
+
*/
|
|
136
|
+
export class TTSManager {
|
|
137
|
+
private ttsState$ = new BehaviorSubject<boolean>(false);
|
|
138
|
+
private static ttsManagerInstance: TTSManager;
|
|
151
139
|
|
|
152
|
-
|
|
140
|
+
private constructor() {
|
|
141
|
+
this.initialize();
|
|
153
142
|
}
|
|
154
143
|
|
|
155
|
-
|
|
156
|
-
if (!
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return;
|
|
144
|
+
static getInstance(): TTSManager {
|
|
145
|
+
if (!TTSManager.ttsManagerInstance) {
|
|
146
|
+
TTSManager.ttsManagerInstance = new TTSManager();
|
|
160
147
|
}
|
|
161
148
|
|
|
162
|
-
|
|
163
|
-
const textTracks = this.controller.getTracksState().textTracks;
|
|
164
|
-
const preferredTextTrack = await this.getPreferredTextTrack(textTracks);
|
|
165
|
-
|
|
166
|
-
if (preferredTextTrack) {
|
|
167
|
-
this.controller.selectTrack(preferredTextTrack);
|
|
168
|
-
}
|
|
169
|
-
} else {
|
|
170
|
-
this.controller.selectTrack(null);
|
|
171
|
-
}
|
|
149
|
+
return TTSManager.ttsManagerInstance;
|
|
172
150
|
}
|
|
173
151
|
|
|
174
|
-
async
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
152
|
+
async initialize() {
|
|
153
|
+
if (!isVizioPlatform()) return;
|
|
154
|
+
|
|
155
|
+
document.addEventListener(
|
|
156
|
+
"VIZIO_TTS_ENABLED",
|
|
157
|
+
() => {
|
|
158
|
+
this.ttsState$.next(true);
|
|
159
|
+
},
|
|
160
|
+
false
|
|
182
161
|
);
|
|
183
162
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if (userPreferredTextLanguage?.id) {
|
|
193
|
-
return userPreferredTextLanguage;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const enableAutoTextTrackSelection =
|
|
197
|
-
this.controller.getPluginConfiguration()
|
|
198
|
-
?.enable_auto_text_track_selection ||
|
|
199
|
-
this.controller.getTracksState().textTracks.length > 0;
|
|
200
|
-
|
|
201
|
-
if (enableAutoTextTrackSelection) {
|
|
202
|
-
const languageCode = await sessionStorage.getItem("languageCode");
|
|
203
|
-
|
|
204
|
-
if (languageCode) {
|
|
205
|
-
const chosenTextTrackBySystemLanguage = textTracks.find(
|
|
206
|
-
(track) => track.language === languageCode
|
|
207
|
-
);
|
|
163
|
+
document.addEventListener(
|
|
164
|
+
"VIZIO_TTS_DISABLED",
|
|
165
|
+
() => {
|
|
166
|
+
this.ttsState$.next(false);
|
|
167
|
+
},
|
|
168
|
+
false
|
|
169
|
+
);
|
|
170
|
+
}
|
|
208
171
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
}
|
|
172
|
+
getCurrentState(): boolean {
|
|
173
|
+
return this.ttsState$.getValue();
|
|
174
|
+
}
|
|
214
175
|
|
|
215
|
-
|
|
176
|
+
getStateAsObservable() {
|
|
177
|
+
return this.ttsState$.asObservable();
|
|
216
178
|
}
|
|
217
179
|
|
|
218
|
-
|
|
219
|
-
if (!
|
|
180
|
+
readText(text: string) {
|
|
181
|
+
if (!window.VIZIO?.Chromevox) return;
|
|
220
182
|
|
|
221
|
-
|
|
183
|
+
window.VIZIO.Chromevox.play(text);
|
|
222
184
|
}
|
|
223
185
|
}
|
package/cellUtils/index.ts
CHANGED
|
@@ -31,13 +31,12 @@ export const getKeyForLabel = (dataKey, customKey) => {
|
|
|
31
31
|
* This method will return true if the argument passed to it is either empty or nil
|
|
32
32
|
* The method prevents zero from being evaluated as falsey in an || condition
|
|
33
33
|
* i.e. - NaN, null, {}, "", [], should all return true
|
|
34
|
-
* @param {*} argument - argument passed to it could be any type
|
|
35
34
|
* @returns {Boolean} returns true if empty or nil
|
|
35
|
+
* @param value
|
|
36
36
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
);
|
|
37
|
+
|
|
38
|
+
export const isEmptyOrNil = (value: any): boolean =>
|
|
39
|
+
Number.isNaN(value) || value == null || R.isEmpty(value);
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
42
|
* This method is used to find the appropriate label for any given text field.
|
|
@@ -320,6 +319,7 @@ export const ifElseFocusedSelected = (
|
|
|
320
319
|
* @param {Object} stylesObj styles object with keys from zapp { button_icon_width: "10" }
|
|
321
320
|
* @returns {*} value, returns any type that can be used as styles
|
|
322
321
|
*/
|
|
322
|
+
|
|
323
323
|
export const getValue = (stylesObj) => (key) => {
|
|
324
324
|
return R.propOr(null, key, stylesObj);
|
|
325
325
|
};
|
package/index.d.ts
CHANGED
|
@@ -143,3 +143,18 @@ declare type BuilderData = {
|
|
|
143
143
|
river?: ZappRiver;
|
|
144
144
|
method?: string;
|
|
145
145
|
};
|
|
146
|
+
|
|
147
|
+
declare type AccessibilityState = {
|
|
148
|
+
screenReaderEnabled: boolean;
|
|
149
|
+
reduceMotionEnabled: boolean;
|
|
150
|
+
boldTextEnabled: boolean;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
declare type AccessibilityProps = {
|
|
154
|
+
accessibilityLabel?: string;
|
|
155
|
+
accessibilityHint?: string;
|
|
156
|
+
"aria-label"?: string;
|
|
157
|
+
"aria-description"?: string;
|
|
158
|
+
accessibilityRole?: string;
|
|
159
|
+
"aria-role"?: string;
|
|
160
|
+
};
|
package/navigationUtils/index.ts
CHANGED
|
@@ -592,3 +592,51 @@ export function isMenuDisabled(
|
|
|
592
592
|
export function routeIsPlayerScreen(currentRoute) {
|
|
593
593
|
return currentRoute?.includes("/playable");
|
|
594
594
|
}
|
|
595
|
+
|
|
596
|
+
export const getNavBarProps =
|
|
597
|
+
(currentRiver: ZappRiver, pathname: string, title: string) => () => {
|
|
598
|
+
const props = getNavigationPropsV2({
|
|
599
|
+
currentRiver,
|
|
600
|
+
title,
|
|
601
|
+
category: "nav_bar",
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
if (props) {
|
|
605
|
+
return {
|
|
606
|
+
...props,
|
|
607
|
+
id: pathname,
|
|
608
|
+
pathname: pathname,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return null;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
export const findMenuPlugin = (
|
|
616
|
+
navigations: ZappNavigation[],
|
|
617
|
+
plugins
|
|
618
|
+
): QuickBrickPlugin => {
|
|
619
|
+
return resolveNavigationPlugin({
|
|
620
|
+
category: "menu",
|
|
621
|
+
navigations,
|
|
622
|
+
plugins,
|
|
623
|
+
}) as QuickBrickPlugin;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
export const shouldNavBarDisplayMenu = (currentRiver: ZappRiver, plugins) =>
|
|
627
|
+
findMenuPlugin(currentRiver.navigations, plugins)?.identifier ===
|
|
628
|
+
"quick_brick_side_menu" ||
|
|
629
|
+
currentRiver?.navigations.findIndex(
|
|
630
|
+
(nav) => nav.category === "nav_bar" && nav.general?.override_menu_target
|
|
631
|
+
) > -1;
|
|
632
|
+
|
|
633
|
+
export const getScreenId = (
|
|
634
|
+
screenData: LegacyNavigationScreenData,
|
|
635
|
+
fallbackRiver: ZappRiver
|
|
636
|
+
) => {
|
|
637
|
+
return screenData?.targetScreen
|
|
638
|
+
? screenData?.targetScreen?.id ?? fallbackRiver.id
|
|
639
|
+
: "screen_id" in screenData
|
|
640
|
+
? screenData.screen_id
|
|
641
|
+
: fallbackRiver.id;
|
|
642
|
+
};
|
|
@@ -2,7 +2,7 @@ import { toNumber } from "..";
|
|
|
2
2
|
|
|
3
3
|
describe("toNumber", () => {
|
|
4
4
|
it("return number if input is number", () => {
|
|
5
|
-
const inputs = [-1, 0, 1, 100];
|
|
5
|
+
const inputs = [-1, 0, 1, 100, 0.2];
|
|
6
6
|
expect.assertions(inputs.length);
|
|
7
7
|
|
|
8
8
|
inputs.forEach((input) => {
|
|
@@ -12,7 +12,7 @@ describe("toNumber", () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it("return number if input is string as number", () => {
|
|
15
|
-
const inputs = ["-1", "0", "1", "100"];
|
|
15
|
+
const inputs = ["-1", "0", "1", "100", "0.2"];
|
|
16
16
|
expect.assertions(inputs.length);
|
|
17
17
|
|
|
18
18
|
inputs.forEach((input) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.9388848580",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.9388848580",
|
|
32
32
|
"buffer": "^5.2.1",
|
|
33
33
|
"camelize": "^1.0.0",
|
|
34
34
|
"create-react-context": "^0.2.3",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createLogger } from "../logger";
|
|
2
|
+
|
|
3
|
+
export const logger = createLogger({
|
|
4
|
+
category: "ImaDomUtils",
|
|
5
|
+
subsystem: "Player/ImaDomUtils",
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
const { log_debug, log_error, log_verbose } = logger;
|
|
9
|
+
|
|
10
|
+
const removeElement = (node) => {
|
|
11
|
+
if (node) {
|
|
12
|
+
const parentNode = node.parentNode;
|
|
13
|
+
|
|
14
|
+
if (parentNode) {
|
|
15
|
+
parentNode.removeChild(node);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
// TODO: This should probably be loaded to root of project before player init
|
|
21
|
+
export const loadIMAScript = async () => {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
// If ima script is already loaded, resolve
|
|
24
|
+
const imaScript = document.getElementById("ima-script");
|
|
25
|
+
|
|
26
|
+
if (imaScript) {
|
|
27
|
+
log_verbose("loadIMAScript: IMA script already loaded");
|
|
28
|
+
|
|
29
|
+
return resolve(true);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const script = document.createElement("script");
|
|
33
|
+
|
|
34
|
+
if (__DEV__) {
|
|
35
|
+
script.src = "https://imasdk.googleapis.com/js/sdkloader/ima3_debug.js";
|
|
36
|
+
} else {
|
|
37
|
+
script.src = "https://imasdk.googleapis.com/js/sdkloader/ima3.js";
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
script.async = true;
|
|
41
|
+
script.id = "ima-script";
|
|
42
|
+
|
|
43
|
+
script.onload = () => {
|
|
44
|
+
removeElement(script);
|
|
45
|
+
log_debug("loadIMAScript: Loaded ima script", script.src);
|
|
46
|
+
resolve(true);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
script.onerror = (_e) => {
|
|
50
|
+
removeElement(script);
|
|
51
|
+
log_error("loadIMAScript: Failed to load ima script", script.src);
|
|
52
|
+
resolve(false);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
if (document.head) {
|
|
56
|
+
document.head.appendChild(script);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
};
|
package/pluginUtils/index.ts
CHANGED
|
@@ -245,3 +245,12 @@ export function generateManifest({ manifestConfig, version }) {
|
|
|
245
245
|
|
|
246
246
|
return manifestConfig({ platform, version });
|
|
247
247
|
}
|
|
248
|
+
|
|
249
|
+
const getPluginType = R.pathOr("unknown_plugin_type", [
|
|
250
|
+
"state",
|
|
251
|
+
"screen",
|
|
252
|
+
"plugin_type",
|
|
253
|
+
]);
|
|
254
|
+
|
|
255
|
+
export const isPlayerPlugin = (routeState): boolean =>
|
|
256
|
+
getPluginType(routeState) === "player";
|
package/reactUtils/index.ts
CHANGED
|
@@ -112,6 +112,9 @@ export const isAndroidTVPlatform = () => getPlatform() === "android_tv";
|
|
|
112
112
|
declare global {
|
|
113
113
|
interface Window {
|
|
114
114
|
VIZIO?: {
|
|
115
|
+
Chromevox: {
|
|
116
|
+
play: (text: string) => void;
|
|
117
|
+
};
|
|
115
118
|
exitApplication: () => void;
|
|
116
119
|
setClosedCaptionHandler: (
|
|
117
120
|
callback: (isCCEnabled: boolean) => void
|
|
@@ -149,8 +152,7 @@ export const hasTizen = typeof window?.tizen !== "undefined";
|
|
|
149
152
|
*/
|
|
150
153
|
export const hasWebOS = typeof window?.webOS !== "undefined";
|
|
151
154
|
|
|
152
|
-
export const getUserAgent = () =>
|
|
153
|
-
window?.navigator?.userAgent || global?.navigator?.userAgent;
|
|
155
|
+
export const getUserAgent = () => window?.navigator?.userAgent;
|
|
154
156
|
|
|
155
157
|
export const isLgPlatform = () => {
|
|
156
158
|
const userAgent = getUserAgent();
|