@applicaster/zapp-react-native-utils 13.0.0-rc.99 → 14.0.0-alpha.1235043154
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/actionsExecutor/ActionExecutorContext.tsx +55 -6
- package/actionsExecutor/consts.ts +4 -0
- package/analyticsUtils/AnalyticsEvents/sendHeaderClickEvent.ts +1 -1
- package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -1
- package/analyticsUtils/index.tsx +3 -4
- package/analyticsUtils/manager.ts +1 -1
- package/appUtils/__tests__/__snapshots__/localizationsHelper.test.ts.snap +151 -0
- package/appUtils/__tests__/allZappLocales.ts +79 -0
- package/appUtils/__tests__/{localizationsHelper.test.js → localizationsHelper.test.ts} +11 -0
- package/appUtils/accessibilityManager/const.ts +18 -0
- package/appUtils/accessibilityManager/index.ts +4 -1
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +1 -0
- package/appUtils/focusManager/index.ios.ts +14 -4
- package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
- package/appUtils/focusManager/utils/index.ts +5 -0
- package/appUtils/localizationsHelper.ts +10 -2
- package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
- package/arrayUtils/__tests__/isEmptyArray.test.ts +63 -0
- package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
- package/arrayUtils/index.ts +7 -2
- package/audioPlayerUtils/__tests__/getArtworkImage.test.ts +144 -0
- package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +72 -0
- package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +110 -0
- package/audioPlayerUtils/assets/index.ts +2 -0
- package/audioPlayerUtils/index.ts +242 -0
- package/cellUtils/index.ts +9 -5
- package/componentsUtils/index.ts +8 -1
- package/conf/player/__tests__/selectors.test.ts +34 -0
- package/conf/player/selectors.ts +10 -0
- package/configurationUtils/__tests__/configurationUtils.test.js +0 -31
- package/configurationUtils/__tests__/getMediaItems.test.ts +65 -0
- package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +34 -0
- package/configurationUtils/index.ts +63 -34
- package/localizationUtils/index.ts +3 -3
- package/manifestUtils/_internals/getDefaultConfiguration.js +28 -0
- package/manifestUtils/{_internals.js → _internals/index.js} +2 -25
- package/manifestUtils/createConfig.js +4 -1
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +1228 -205
- package/manifestUtils/index.js +2 -0
- package/manifestUtils/keys.js +27 -2
- package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +0 -30
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +1 -2
- package/navigationUtils/__tests__/navigationUtils.test.js +0 -65
- package/navigationUtils/index.ts +0 -31
- package/package.json +2 -2
- package/playerUtils/__tests__/configurationUtils.test.ts +1 -65
- package/playerUtils/__tests__/getPlayerActionButtons.test.ts +54 -0
- package/playerUtils/_internals/__tests__/utils.test.ts +71 -0
- package/playerUtils/_internals/index.ts +1 -0
- package/playerUtils/_internals/utils.ts +31 -0
- package/playerUtils/configurationUtils.ts +0 -44
- package/playerUtils/getPlayerActionButtons.ts +17 -0
- package/playerUtils/index.ts +25 -0
- package/playerUtils/useValidatePlayerConfig.tsx +22 -19
- package/reactHooks/app/useAppState.ts +2 -2
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +12 -13
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +39 -88
- package/reactHooks/feed/useBatchLoading.ts +12 -14
- package/reactHooks/navigation/{useGetTabBarHeight.ts → getTabBarHeight.ts} +1 -1
- package/reactHooks/navigation/index.ts +2 -2
- package/reactHooks/navigation/useGetBottomTabBarHeight.ts +10 -3
- package/reactHooks/navigation/useNavigationPluginData.ts +8 -4
- package/reactHooks/navigation/useNavigationType.ts +4 -2
- package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +69 -0
- package/reactHooks/screen/useScreenBackgroundColor.ts +3 -15
- package/reactHooks/state/README.md +79 -0
- package/reactHooks/state/ZStoreProvider.tsx +71 -0
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +66 -0
- package/reactHooks/state/index.ts +2 -0
- package/reactHooks/useListenEventBusEvent.ts +1 -1
- package/reactUtils/index.ts +9 -0
- package/testUtils/index.tsx +7 -8
- package/typeGuards/index.ts +3 -0
- package/utils/index.ts +12 -1
- package/zappFrameworkUtils/localStorageHelper.ts +32 -10
- package/playerUtils/configurationGenerator.ts +0 -2588
|
@@ -5,9 +5,14 @@ import {
|
|
|
5
5
|
actionExecutor as _actionExecutor,
|
|
6
6
|
ActionResult,
|
|
7
7
|
} from "./ActionExecutor";
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
batchRemoveAllFromNamespaceForStorage,
|
|
10
|
+
batchSave,
|
|
11
|
+
} from "../zappFrameworkUtils/localStorageHelper";
|
|
12
|
+
import { sessionStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/SessionStorage";
|
|
13
|
+
|
|
10
14
|
import * as QuickBrickManager from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
15
|
+
import { QUICK_BRICK_EVENTS } from "@applicaster/zapp-react-native-bridge/QuickBrick";
|
|
11
16
|
import { showConfirmationDialog } from "../alertUtils";
|
|
12
17
|
import { createCloudEvent, sendCloudEvent } from "../cloudEventsUtils";
|
|
13
18
|
import { createLogger } from "../logger";
|
|
@@ -26,6 +31,9 @@ import {
|
|
|
26
31
|
useContentTypes,
|
|
27
32
|
usePickFromState,
|
|
28
33
|
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
34
|
+
import { TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT } from "./consts";
|
|
35
|
+
import { postEvent, useSubscriberFor } from "../reactHooks/useSubscriberFor";
|
|
36
|
+
import { APP_EVENTS } from "../appUtils/events";
|
|
29
37
|
|
|
30
38
|
export const { log_error, log_info, log_debug } = createLogger({
|
|
31
39
|
subsystem: "ActionExecutorContext",
|
|
@@ -74,10 +82,31 @@ function findParentComponent(
|
|
|
74
82
|
return null;
|
|
75
83
|
}
|
|
76
84
|
|
|
85
|
+
// send all data just in case (like for message string formatting)
|
|
86
|
+
// Type is not exported for now
|
|
87
|
+
type MaxTagsReachedEvent = {
|
|
88
|
+
selectedItems: string[];
|
|
89
|
+
maxItems: number;
|
|
90
|
+
tag: string;
|
|
91
|
+
keyNamespace: string;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
async function onMaxTagsReached(data: MaxTagsReachedEvent) {
|
|
95
|
+
postEvent(TOGGLE_FLAG_MAX_ITEMS_REACHED_EVENT, [data]);
|
|
96
|
+
}
|
|
97
|
+
|
|
77
98
|
const prepareDefaultActions = (actionExecutor) => {
|
|
78
99
|
actionExecutor.registerAction("localStorageSet", async (action) => {
|
|
79
100
|
const namespaces = action.options.content;
|
|
80
|
-
await
|
|
101
|
+
await batchSave(namespaces, localStorage);
|
|
102
|
+
// TODO: Add support for ownershipKey and ownershipNamespace
|
|
103
|
+
|
|
104
|
+
return ActionResult.Success;
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
actionExecutor.registerAction("sessionStorageSet", async (action) => {
|
|
108
|
+
const namespaces = action.options.content;
|
|
109
|
+
await batchSave(namespaces, sessionStorage);
|
|
81
110
|
// TODO: Add support for ownershipKey and ownershipNamespace
|
|
82
111
|
|
|
83
112
|
return ActionResult.Success;
|
|
@@ -134,15 +163,13 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
134
163
|
actionExecutor.registerAction("confirmDialog", async (action) => {
|
|
135
164
|
log_info("handleAction: confirmDialog event");
|
|
136
165
|
|
|
137
|
-
|
|
166
|
+
return new Promise<ActionResult>((resolve) => {
|
|
138
167
|
showConfirmationDialog({
|
|
139
168
|
...action.options,
|
|
140
169
|
confirmCompletion: () => resolve(ActionResult.Success),
|
|
141
170
|
cancelCompletion: () => resolve(ActionResult.Cancel),
|
|
142
171
|
});
|
|
143
172
|
});
|
|
144
|
-
|
|
145
|
-
return confirmationPromise;
|
|
146
173
|
});
|
|
147
174
|
|
|
148
175
|
actionExecutor.registerAction("sendCloudEvent", async (action, context) => {
|
|
@@ -241,6 +268,13 @@ const prepareDefaultActions = (actionExecutor) => {
|
|
|
241
268
|
`handleAction: localStorageToggleFlag event reached max items limit: ${maxItems}, cannot add tag: ${tag}`
|
|
242
269
|
);
|
|
243
270
|
|
|
271
|
+
await onMaxTagsReached({
|
|
272
|
+
selectedItems,
|
|
273
|
+
maxItems,
|
|
274
|
+
tag,
|
|
275
|
+
keyNamespace,
|
|
276
|
+
});
|
|
277
|
+
|
|
244
278
|
return ActionResult.Cancel;
|
|
245
279
|
}
|
|
246
280
|
|
|
@@ -281,9 +315,24 @@ export function withActionExecutor(Component) {
|
|
|
281
315
|
};
|
|
282
316
|
}, []);
|
|
283
317
|
|
|
318
|
+
useSubscriberFor(APP_EVENTS.onLogout, () => {
|
|
319
|
+
log_debug(
|
|
320
|
+
"User profile: onLogout event received, clearing user profile data"
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
const userAccountKey = "user_account";
|
|
324
|
+
void batchRemoveAllFromNamespaceForStorage(userAccountKey, localStorage);
|
|
325
|
+
|
|
326
|
+
void batchRemoveAllFromNamespaceForStorage(
|
|
327
|
+
userAccountKey,
|
|
328
|
+
sessionStorage
|
|
329
|
+
);
|
|
330
|
+
});
|
|
331
|
+
|
|
284
332
|
useEffect(() => {
|
|
285
333
|
return _actionExecutor.registerAction(
|
|
286
334
|
"navigateToScreen",
|
|
335
|
+
|
|
287
336
|
async (action: ActionType, context?: Record<string, any>) => {
|
|
288
337
|
const screenType = action.options?.typeMapping;
|
|
289
338
|
|
|
@@ -4,7 +4,7 @@ import { postAnalyticEvent } from "../manager";
|
|
|
4
4
|
import { ANALYTICS_CORE_EVENTS } from "../events";
|
|
5
5
|
|
|
6
6
|
type SendHeaderClickEventProps = {
|
|
7
|
-
extraProps:
|
|
7
|
+
extraProps: Record<string, any>;
|
|
8
8
|
component?: ZappUIComponent;
|
|
9
9
|
zappPipesData?: ZappPipesData;
|
|
10
10
|
item?: ZappEntry;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
/// <reference types="../../" />
|
|
1
2
|
import { log_error, log_debug } from "../logger";
|
|
2
3
|
import { replaceAnalyticsPropsNils } from "./helper";
|
|
3
4
|
import { postAnalyticEvent } from "../manager";
|
|
4
5
|
|
|
5
6
|
import { ANALYTICS_CORE_EVENTS } from "../events";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
type AnalyticsDefaultHelperProperties = {
|
|
8
9
|
analyticsScreenData: AnalyticsScreenProperties;
|
|
9
10
|
extraProps: any;
|
|
10
11
|
props;
|
package/analyticsUtils/index.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/// <reference types="@applicaster/zapp-react-native-utils" />
|
|
2
1
|
import * as R from "ramda";
|
|
3
2
|
import * as React from "react";
|
|
4
3
|
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
@@ -31,7 +30,7 @@ import { ANALYTICS_CORE_EVENTS } from "./events";
|
|
|
31
30
|
import { noop } from "../functionUtils";
|
|
32
31
|
|
|
33
32
|
type ComponentWithChildrenProps = {
|
|
34
|
-
children: React.
|
|
33
|
+
children: React.ReactElement;
|
|
35
34
|
};
|
|
36
35
|
|
|
37
36
|
export function sendSelectCellEvent(item, component, headerTitle, itemIndex) {
|
|
@@ -120,11 +119,11 @@ export function getAnalyticsFunctions({
|
|
|
120
119
|
export const AnalyticsContext =
|
|
121
120
|
React.createContext<GetAnalyticsFunctions>(noop);
|
|
122
121
|
|
|
123
|
-
export function AnalyticsProvider(
|
|
122
|
+
export function AnalyticsProvider({ children }: ComponentWithChildrenProps) {
|
|
124
123
|
return (
|
|
125
124
|
// @ts-ignore - this is a valid context provider
|
|
126
125
|
<AnalyticsContext.Provider value={getAnalyticsFunctions}>
|
|
127
|
-
{
|
|
126
|
+
{children}
|
|
128
127
|
</AnalyticsContext.Provider>
|
|
129
128
|
);
|
|
130
129
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { NativeModules } from "react-native";
|
|
4
|
-
import { ANALYTICS_CORE_EVENTS } from "
|
|
4
|
+
import { ANALYTICS_CORE_EVENTS } from "./events";
|
|
5
5
|
|
|
6
6
|
import { analyticsUtilsLogger } from "./logger";
|
|
7
7
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`toDayJSLocaleMap [af] returns a valid dayjs locale 1`] = `"af"`;
|
|
4
|
+
|
|
5
|
+
exports[`toDayJSLocaleMap [ar] returns a valid dayjs locale 1`] = `"ar"`;
|
|
6
|
+
|
|
7
|
+
exports[`toDayJSLocaleMap [bg] returns a valid dayjs locale 1`] = `"bg"`;
|
|
8
|
+
|
|
9
|
+
exports[`toDayJSLocaleMap [bn] returns a valid dayjs locale 1`] = `"bn"`;
|
|
10
|
+
|
|
11
|
+
exports[`toDayJSLocaleMap [bo] returns a valid dayjs locale 1`] = `"bo"`;
|
|
12
|
+
|
|
13
|
+
exports[`toDayJSLocaleMap [ca] returns a valid dayjs locale 1`] = `"ca"`;
|
|
14
|
+
|
|
15
|
+
exports[`toDayJSLocaleMap [cs] returns a valid dayjs locale 1`] = `"cs"`;
|
|
16
|
+
|
|
17
|
+
exports[`toDayJSLocaleMap [da] returns a valid dayjs locale 1`] = `"da"`;
|
|
18
|
+
|
|
19
|
+
exports[`toDayJSLocaleMap [de] returns a valid dayjs locale 1`] = `"de"`;
|
|
20
|
+
|
|
21
|
+
exports[`toDayJSLocaleMap [el] returns a valid dayjs locale 1`] = `"el"`;
|
|
22
|
+
|
|
23
|
+
exports[`toDayJSLocaleMap [en] returns a valid dayjs locale 1`] = `"en"`;
|
|
24
|
+
|
|
25
|
+
exports[`toDayJSLocaleMap [en-GB] returns a valid dayjs locale 1`] = `"en-gb"`;
|
|
26
|
+
|
|
27
|
+
exports[`toDayJSLocaleMap [en-UK] returns a valid dayjs locale 1`] = `"en-gb"`;
|
|
28
|
+
|
|
29
|
+
exports[`toDayJSLocaleMap [es] returns a valid dayjs locale 1`] = `"es"`;
|
|
30
|
+
|
|
31
|
+
exports[`toDayJSLocaleMap [es-LA] returns a valid dayjs locale 1`] = `"es"`;
|
|
32
|
+
|
|
33
|
+
exports[`toDayJSLocaleMap [es-MX] returns a valid dayjs locale 1`] = `"es-mx"`;
|
|
34
|
+
|
|
35
|
+
exports[`toDayJSLocaleMap [es-US] returns a valid dayjs locale 1`] = `"es-us"`;
|
|
36
|
+
|
|
37
|
+
exports[`toDayJSLocaleMap [et] returns a valid dayjs locale 1`] = `"et"`;
|
|
38
|
+
|
|
39
|
+
exports[`toDayJSLocaleMap [eu] returns a valid dayjs locale 1`] = `"eu"`;
|
|
40
|
+
|
|
41
|
+
exports[`toDayJSLocaleMap [fa] returns a valid dayjs locale 1`] = `"fa"`;
|
|
42
|
+
|
|
43
|
+
exports[`toDayJSLocaleMap [fi] returns a valid dayjs locale 1`] = `"fi"`;
|
|
44
|
+
|
|
45
|
+
exports[`toDayJSLocaleMap [fj] returns a valid dayjs locale 1`] = `"en"`;
|
|
46
|
+
|
|
47
|
+
exports[`toDayJSLocaleMap [fr] returns a valid dayjs locale 1`] = `"fr"`;
|
|
48
|
+
|
|
49
|
+
exports[`toDayJSLocaleMap [ga] returns a valid dayjs locale 1`] = `"ga"`;
|
|
50
|
+
|
|
51
|
+
exports[`toDayJSLocaleMap [gu] returns a valid dayjs locale 1`] = `"gu"`;
|
|
52
|
+
|
|
53
|
+
exports[`toDayJSLocaleMap [he] returns a valid dayjs locale 1`] = `"he"`;
|
|
54
|
+
|
|
55
|
+
exports[`toDayJSLocaleMap [hi] returns a valid dayjs locale 1`] = `"hi"`;
|
|
56
|
+
|
|
57
|
+
exports[`toDayJSLocaleMap [hr] returns a valid dayjs locale 1`] = `"hr"`;
|
|
58
|
+
|
|
59
|
+
exports[`toDayJSLocaleMap [hu] returns a valid dayjs locale 1`] = `"hu"`;
|
|
60
|
+
|
|
61
|
+
exports[`toDayJSLocaleMap [hy] returns a valid dayjs locale 1`] = `"hy-am"`;
|
|
62
|
+
|
|
63
|
+
exports[`toDayJSLocaleMap [id] returns a valid dayjs locale 1`] = `"id"`;
|
|
64
|
+
|
|
65
|
+
exports[`toDayJSLocaleMap [is] returns a valid dayjs locale 1`] = `"is"`;
|
|
66
|
+
|
|
67
|
+
exports[`toDayJSLocaleMap [it] returns a valid dayjs locale 1`] = `"it"`;
|
|
68
|
+
|
|
69
|
+
exports[`toDayJSLocaleMap [ja] returns a valid dayjs locale 1`] = `"ja"`;
|
|
70
|
+
|
|
71
|
+
exports[`toDayJSLocaleMap [ka] returns a valid dayjs locale 1`] = `"ka"`;
|
|
72
|
+
|
|
73
|
+
exports[`toDayJSLocaleMap [km] returns a valid dayjs locale 1`] = `"km"`;
|
|
74
|
+
|
|
75
|
+
exports[`toDayJSLocaleMap [ko] returns a valid dayjs locale 1`] = `"ko"`;
|
|
76
|
+
|
|
77
|
+
exports[`toDayJSLocaleMap [la] returns a valid dayjs locale 1`] = `"en"`;
|
|
78
|
+
|
|
79
|
+
exports[`toDayJSLocaleMap [lt] returns a valid dayjs locale 1`] = `"lt"`;
|
|
80
|
+
|
|
81
|
+
exports[`toDayJSLocaleMap [lv] returns a valid dayjs locale 1`] = `"lv"`;
|
|
82
|
+
|
|
83
|
+
exports[`toDayJSLocaleMap [mi] returns a valid dayjs locale 1`] = `"mi"`;
|
|
84
|
+
|
|
85
|
+
exports[`toDayJSLocaleMap [mk] returns a valid dayjs locale 1`] = `"mk"`;
|
|
86
|
+
|
|
87
|
+
exports[`toDayJSLocaleMap [ml] returns a valid dayjs locale 1`] = `"ml"`;
|
|
88
|
+
|
|
89
|
+
exports[`toDayJSLocaleMap [mn] returns a valid dayjs locale 1`] = `"mn"`;
|
|
90
|
+
|
|
91
|
+
exports[`toDayJSLocaleMap [mr] returns a valid dayjs locale 1`] = `"mr"`;
|
|
92
|
+
|
|
93
|
+
exports[`toDayJSLocaleMap [ms] returns a valid dayjs locale 1`] = `"ms"`;
|
|
94
|
+
|
|
95
|
+
exports[`toDayJSLocaleMap [mt] returns a valid dayjs locale 1`] = `"mt"`;
|
|
96
|
+
|
|
97
|
+
exports[`toDayJSLocaleMap [ne] returns a valid dayjs locale 1`] = `"ne"`;
|
|
98
|
+
|
|
99
|
+
exports[`toDayJSLocaleMap [nl] returns a valid dayjs locale 1`] = `"nl"`;
|
|
100
|
+
|
|
101
|
+
exports[`toDayJSLocaleMap [no] returns a valid dayjs locale 1`] = `"en"`;
|
|
102
|
+
|
|
103
|
+
exports[`toDayJSLocaleMap [pa] returns a valid dayjs locale 1`] = `"pa-in"`;
|
|
104
|
+
|
|
105
|
+
exports[`toDayJSLocaleMap [pl] returns a valid dayjs locale 1`] = `"pl"`;
|
|
106
|
+
|
|
107
|
+
exports[`toDayJSLocaleMap [pt] returns a valid dayjs locale 1`] = `"pt"`;
|
|
108
|
+
|
|
109
|
+
exports[`toDayJSLocaleMap [pt-BR] returns a valid dayjs locale 1`] = `"pt-br"`;
|
|
110
|
+
|
|
111
|
+
exports[`toDayJSLocaleMap [qu] returns a valid dayjs locale 1`] = `"en"`;
|
|
112
|
+
|
|
113
|
+
exports[`toDayJSLocaleMap [ro] returns a valid dayjs locale 1`] = `"ro"`;
|
|
114
|
+
|
|
115
|
+
exports[`toDayJSLocaleMap [ru] returns a valid dayjs locale 1`] = `"ru"`;
|
|
116
|
+
|
|
117
|
+
exports[`toDayJSLocaleMap [sk] returns a valid dayjs locale 1`] = `"sk"`;
|
|
118
|
+
|
|
119
|
+
exports[`toDayJSLocaleMap [sl] returns a valid dayjs locale 1`] = `"sl"`;
|
|
120
|
+
|
|
121
|
+
exports[`toDayJSLocaleMap [sm] returns a valid dayjs locale 1`] = `"en"`;
|
|
122
|
+
|
|
123
|
+
exports[`toDayJSLocaleMap [sq] returns a valid dayjs locale 1`] = `"sq"`;
|
|
124
|
+
|
|
125
|
+
exports[`toDayJSLocaleMap [sr] returns a valid dayjs locale 1`] = `"sr"`;
|
|
126
|
+
|
|
127
|
+
exports[`toDayJSLocaleMap [sv] returns a valid dayjs locale 1`] = `"sv"`;
|
|
128
|
+
|
|
129
|
+
exports[`toDayJSLocaleMap [sw] returns a valid dayjs locale 1`] = `"sw"`;
|
|
130
|
+
|
|
131
|
+
exports[`toDayJSLocaleMap [ta] returns a valid dayjs locale 1`] = `"ta"`;
|
|
132
|
+
|
|
133
|
+
exports[`toDayJSLocaleMap [te] returns a valid dayjs locale 1`] = `"te"`;
|
|
134
|
+
|
|
135
|
+
exports[`toDayJSLocaleMap [th] returns a valid dayjs locale 1`] = `"th"`;
|
|
136
|
+
|
|
137
|
+
exports[`toDayJSLocaleMap [to] returns a valid dayjs locale 1`] = `"en"`;
|
|
138
|
+
|
|
139
|
+
exports[`toDayJSLocaleMap [tr] returns a valid dayjs locale 1`] = `"tr"`;
|
|
140
|
+
|
|
141
|
+
exports[`toDayJSLocaleMap [tt] returns a valid dayjs locale 1`] = `"en"`;
|
|
142
|
+
|
|
143
|
+
exports[`toDayJSLocaleMap [uk] returns a valid dayjs locale 1`] = `"uk"`;
|
|
144
|
+
|
|
145
|
+
exports[`toDayJSLocaleMap [ur] returns a valid dayjs locale 1`] = `"ur"`;
|
|
146
|
+
|
|
147
|
+
exports[`toDayJSLocaleMap [uz] returns a valid dayjs locale 1`] = `"uz"`;
|
|
148
|
+
|
|
149
|
+
exports[`toDayJSLocaleMap [vi] returns a valid dayjs locale 1`] = `"vi"`;
|
|
150
|
+
|
|
151
|
+
exports[`toDayJSLocaleMap [zh] returns a valid dayjs locale 1`] = `"zh"`;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export default [
|
|
2
|
+
// common locales from https://rubygems.org/gems/language_list
|
|
3
|
+
"en",
|
|
4
|
+
"fr",
|
|
5
|
+
"de",
|
|
6
|
+
"nl",
|
|
7
|
+
"ru",
|
|
8
|
+
"es",
|
|
9
|
+
"he",
|
|
10
|
+
"hy",
|
|
11
|
+
"sq",
|
|
12
|
+
"af",
|
|
13
|
+
"ar",
|
|
14
|
+
"eu",
|
|
15
|
+
"bn",
|
|
16
|
+
"bg",
|
|
17
|
+
"zh",
|
|
18
|
+
"cs",
|
|
19
|
+
"km",
|
|
20
|
+
"ca",
|
|
21
|
+
"hr",
|
|
22
|
+
"da",
|
|
23
|
+
"et",
|
|
24
|
+
"fj",
|
|
25
|
+
"fi",
|
|
26
|
+
"gu",
|
|
27
|
+
"ka",
|
|
28
|
+
"hu",
|
|
29
|
+
"hi",
|
|
30
|
+
"it",
|
|
31
|
+
"is",
|
|
32
|
+
"id",
|
|
33
|
+
"ga",
|
|
34
|
+
"ja",
|
|
35
|
+
"ko",
|
|
36
|
+
"la",
|
|
37
|
+
"lv",
|
|
38
|
+
"lt",
|
|
39
|
+
"ms",
|
|
40
|
+
"mi",
|
|
41
|
+
"mn",
|
|
42
|
+
"mt",
|
|
43
|
+
"mk",
|
|
44
|
+
"el",
|
|
45
|
+
"mr",
|
|
46
|
+
"ml",
|
|
47
|
+
"ne",
|
|
48
|
+
"no",
|
|
49
|
+
"pa",
|
|
50
|
+
"pl",
|
|
51
|
+
"pt",
|
|
52
|
+
"fa",
|
|
53
|
+
"qu",
|
|
54
|
+
"ro",
|
|
55
|
+
"sk",
|
|
56
|
+
"sm",
|
|
57
|
+
"sr",
|
|
58
|
+
"sw",
|
|
59
|
+
"sv",
|
|
60
|
+
"sl",
|
|
61
|
+
"to",
|
|
62
|
+
"tr",
|
|
63
|
+
"th",
|
|
64
|
+
"te",
|
|
65
|
+
"bo",
|
|
66
|
+
"tt",
|
|
67
|
+
"ta",
|
|
68
|
+
"uk",
|
|
69
|
+
"ur",
|
|
70
|
+
"uz",
|
|
71
|
+
"vi",
|
|
72
|
+
// Extra locales https://github.com/applicaster/zapp/blob/5604794f15cfd270ae494b0db85e542de4cebfaa/config/additional_languages.yml
|
|
73
|
+
"en-UK",
|
|
74
|
+
"en-GB",
|
|
75
|
+
"es-LA",
|
|
76
|
+
"pt-BR",
|
|
77
|
+
"es-MX",
|
|
78
|
+
"es-US",
|
|
79
|
+
];
|
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
getLocale,
|
|
9
9
|
getLanguageCode,
|
|
10
10
|
getCountryCode,
|
|
11
|
+
toDayJSLocaleMap,
|
|
11
12
|
} = require("../localizationsHelper");
|
|
12
13
|
|
|
13
14
|
describe("getLocale", () => {
|
|
@@ -69,3 +70,13 @@ describe("getCountryCode", () => {
|
|
|
69
70
|
expect(currentValue).toEqual(expectedValue);
|
|
70
71
|
});
|
|
71
72
|
});
|
|
73
|
+
|
|
74
|
+
describe("toDayJSLocaleMap", () => {
|
|
75
|
+
const allZappLocales: string[] = require("./allZappLocales").default;
|
|
76
|
+
|
|
77
|
+
it.each(allZappLocales)("[%s] returns a valid dayjs locale", (locale) => {
|
|
78
|
+
const dayJSLocale = toDayJSLocaleMap(locale);
|
|
79
|
+
expect(dayJSLocale).toBeDefined();
|
|
80
|
+
expect(dayJSLocale).toMatchSnapshot();
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -47,4 +47,22 @@ export const BUTTON_ACCESSIBILITY_KEYS = {
|
|
|
47
47
|
label: "accessibility_fullscreen_label",
|
|
48
48
|
hint: "accessibility_fullscreen_hint",
|
|
49
49
|
},
|
|
50
|
+
// EPG-specific buttons
|
|
51
|
+
now: {
|
|
52
|
+
label: "accessibility_now_label",
|
|
53
|
+
hint: "accessibility_now_hint",
|
|
54
|
+
},
|
|
55
|
+
day: {
|
|
56
|
+
label: "accessibility_day_label",
|
|
57
|
+
hint: "accessibility_day_hint",
|
|
58
|
+
},
|
|
59
|
+
program: {
|
|
60
|
+
label: "accessibility_program_label",
|
|
61
|
+
hint: "accessibility_program_hint",
|
|
62
|
+
},
|
|
63
|
+
// Menu-specific buttons
|
|
64
|
+
menu_item: {
|
|
65
|
+
label: "accessibility_menu_item_label",
|
|
66
|
+
hint: "accessibility_menu_item_hint",
|
|
67
|
+
},
|
|
50
68
|
} as const;
|
|
@@ -3,6 +3,7 @@ import { accessibilityManagerLogger as logger } from "./logger";
|
|
|
3
3
|
import { TTSManager } from "../platform/platformUtils";
|
|
4
4
|
import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
|
|
5
5
|
import { AccessibilityRole } from "react-native";
|
|
6
|
+
import _ from "lodash";
|
|
6
7
|
|
|
7
8
|
export class AccessibilityManager {
|
|
8
9
|
private static _instance: AccessibilityManager | null = null;
|
|
@@ -135,7 +136,9 @@ export class AccessibilityManager {
|
|
|
135
136
|
});
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
public getButtonAccessibilityProps(
|
|
139
|
+
public getButtonAccessibilityProps(name: string): AccessibilityProps {
|
|
140
|
+
const buttonName = _.toString(name);
|
|
141
|
+
|
|
139
142
|
const buttonConfig = BUTTON_ACCESSIBILITY_KEYS[buttonName];
|
|
140
143
|
|
|
141
144
|
if (!buttonConfig) {
|
|
@@ -61,6 +61,7 @@ exports[`focusManagerIOS should be defined 1`] = `
|
|
|
61
61
|
"getCurrentGroup": [Function],
|
|
62
62
|
"getGroupById": [Function],
|
|
63
63
|
"getGroupRootById": [Function],
|
|
64
|
+
"getPreferredFocusChild": [Function],
|
|
64
65
|
"invokeHandler": [Function],
|
|
65
66
|
"isGroupItemFocused": [Function],
|
|
66
67
|
"moveFocus": [Function],
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { NativeModules } from "react-native";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
|
|
3
4
|
import { Tree } from "./treeDataStructure/Tree";
|
|
4
5
|
import { findFocusableNode } from "./treeDataStructure/Utils";
|
|
5
6
|
import { subscriber } from "../../functionUtils";
|
|
7
|
+
import { findChild } from "./utils";
|
|
6
8
|
|
|
7
9
|
const { FocusableManagerModule } = NativeModules;
|
|
8
10
|
|
|
@@ -52,10 +54,7 @@ export const focusManager = (function () {
|
|
|
52
54
|
const node = focusableTree.findInTree(groupId);
|
|
53
55
|
|
|
54
56
|
if (node?.children?.length > 0) {
|
|
55
|
-
const preferredFocus =
|
|
56
|
-
R.find(R.pathEq(["component", "props", "preferredFocus"], true)),
|
|
57
|
-
R.prop("children")
|
|
58
|
-
)(node);
|
|
57
|
+
const preferredFocus = findChild(true, node);
|
|
59
58
|
|
|
60
59
|
if (preferredFocus?.component?.isGroup) {
|
|
61
60
|
return getPreferredFocusInGroup({ groupId: preferredFocus?.id });
|
|
@@ -382,6 +381,16 @@ export const focusManager = (function () {
|
|
|
382
381
|
forceFocusOnItem({ focusableItem, callback });
|
|
383
382
|
}
|
|
384
383
|
|
|
384
|
+
function getPreferredFocusChild(id) {
|
|
385
|
+
const node = focusableTree.findInTree(id);
|
|
386
|
+
|
|
387
|
+
if (node?.children?.length > 0) {
|
|
388
|
+
return findChild(true, node) || findChild(false, node);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return node;
|
|
392
|
+
}
|
|
393
|
+
|
|
385
394
|
return {
|
|
386
395
|
on,
|
|
387
396
|
invokeHandler,
|
|
@@ -402,5 +411,6 @@ export const focusManager = (function () {
|
|
|
402
411
|
getCurrentGroup,
|
|
403
412
|
getGroupRootById,
|
|
404
413
|
isGroupItemFocused,
|
|
414
|
+
getPreferredFocusChild,
|
|
405
415
|
};
|
|
406
416
|
})();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { findChild } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("findChild", () => {
|
|
4
|
+
const makeNode = (children = []) => ({ children });
|
|
5
|
+
|
|
6
|
+
const child = (preferredFocus: boolean) => ({
|
|
7
|
+
component: { props: { preferredFocus } },
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("returns the child with preferredFocus=true", () => {
|
|
11
|
+
const node = makeNode([child(false), child(true), child(false)]);
|
|
12
|
+
expect(findChild(true, node)).toBe(node.children[1]);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("returns the child with preferredFocus=false", () => {
|
|
16
|
+
const node = makeNode([child(false), child(true), child(false)]);
|
|
17
|
+
expect(findChild(false, node)).toBe(node.children[0]);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns undefined if no child matches preferredFocus", () => {
|
|
21
|
+
const node = makeNode([child(false), child(false)]);
|
|
22
|
+
expect(findChild(true, node)).toBeUndefined();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns undefined if node has no children", () => {
|
|
26
|
+
const node = makeNode();
|
|
27
|
+
expect(findChild(true, node)).toBeUndefined();
|
|
28
|
+
expect(findChild(false, node)).toBeUndefined();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("returns undefined if children is not an array", () => {
|
|
32
|
+
const node = { children: null };
|
|
33
|
+
expect(findChild(true, node)).toBeUndefined();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -98,3 +98,8 @@ export const waitForContent = (focusableTree) => {
|
|
|
98
98
|
conditionFn: contentHasAnyChildren,
|
|
99
99
|
});
|
|
100
100
|
};
|
|
101
|
+
|
|
102
|
+
export const findChild = (preferredFocus: boolean, node) =>
|
|
103
|
+
(node?.children || []).find(
|
|
104
|
+
(child) => child?.component?.props?.preferredFocus === preferredFocus
|
|
105
|
+
);
|
|
@@ -65,6 +65,12 @@ export function getUILanguage() {
|
|
|
65
65
|
return getLanguageCode();
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
/**
|
|
69
|
+
* fallback to en for missing dayjslocalization
|
|
70
|
+
* converts the locale code to a dayjs compatible locale code
|
|
71
|
+
* lowercase input code is expected, e.g. "en-GB" => "en-gb"
|
|
72
|
+
* @param {string} code - locale code, e.g. "en", "fr", "es-LA"
|
|
73
|
+
* */
|
|
68
74
|
export const toDayJSLocaleMap = (code) => {
|
|
69
75
|
const map = {
|
|
70
76
|
hy: "hy-am",
|
|
@@ -73,10 +79,12 @@ export const toDayJSLocaleMap = (code) => {
|
|
|
73
79
|
no: null,
|
|
74
80
|
pa: "pa-in",
|
|
75
81
|
qu: null,
|
|
76
|
-
"es-LA": "es",
|
|
77
82
|
sm: null,
|
|
78
83
|
to: null,
|
|
79
84
|
xh: null,
|
|
85
|
+
tt: null,
|
|
86
|
+
"es-LA": "es",
|
|
87
|
+
"en-UK": "en-gb",
|
|
80
88
|
};
|
|
81
89
|
|
|
82
90
|
if (map[code] === null) {
|
|
@@ -84,7 +92,7 @@ export const toDayJSLocaleMap = (code) => {
|
|
|
84
92
|
} else if (map[code]) {
|
|
85
93
|
return map[code];
|
|
86
94
|
} else {
|
|
87
|
-
return code;
|
|
95
|
+
return code.toLowerCase();
|
|
88
96
|
}
|
|
89
97
|
};
|
|
90
98
|
|
|
@@ -12,7 +12,7 @@ import { useThrottle } from "../../../functionUtils";
|
|
|
12
12
|
export const usePlayerCurrentTime = (
|
|
13
13
|
listenerId: string,
|
|
14
14
|
playerId?: string
|
|
15
|
-
): number | null => {
|
|
15
|
+
): { currentTime: number | null; cancel: () => void } => {
|
|
16
16
|
const [currentTime, setCurrentTime] = useState<number | null>(null);
|
|
17
17
|
const player: Player = usePlayer(playerId);
|
|
18
18
|
|
|
@@ -20,15 +20,17 @@ export const usePlayerCurrentTime = (
|
|
|
20
20
|
if (player) {
|
|
21
21
|
const newCurrentTime = player.getContentPosition();
|
|
22
22
|
|
|
23
|
-
setCurrentTime(
|
|
24
|
-
prevTime !== newCurrentTime ? newCurrentTime : prevTime
|
|
25
|
-
);
|
|
23
|
+
setCurrentTime(newCurrentTime);
|
|
26
24
|
}
|
|
27
25
|
}, [player]);
|
|
28
26
|
|
|
27
|
+
// We update the current time every ~250ms since player can have rate set to 2x.
|
|
28
|
+
// We update more often than 2x a second to avoid noticiable 'pulsation' in update,
|
|
29
|
+
// since native level also updates the current time every ~250ms,
|
|
30
|
+
// and combined with assorted delays it creates interference pattern.
|
|
29
31
|
const { throttledFunction: throttledUpdate, cancel } = useThrottle(
|
|
30
32
|
updateCurrentTime,
|
|
31
|
-
1000
|
|
33
|
+
1000 / 4
|
|
32
34
|
);
|
|
33
35
|
|
|
34
36
|
useEffect(() => {
|
|
@@ -36,7 +38,9 @@ export const usePlayerCurrentTime = (
|
|
|
36
38
|
throttledUpdate();
|
|
37
39
|
|
|
38
40
|
const listeners = {
|
|
39
|
-
onVideoProgress:
|
|
41
|
+
onVideoProgress: () => {
|
|
42
|
+
setCurrentTime(player.getContentPosition());
|
|
43
|
+
},
|
|
40
44
|
};
|
|
41
45
|
|
|
42
46
|
const id = `${listenerId}_player_current_time`;
|
|
@@ -53,5 +57,5 @@ export const usePlayerCurrentTime = (
|
|
|
53
57
|
}
|
|
54
58
|
}, [player, listenerId, throttledUpdate, cancel]);
|
|
55
59
|
|
|
56
|
-
return currentTime;
|
|
60
|
+
return { currentTime, cancel };
|
|
57
61
|
};
|