@applicaster/zapp-react-native-utils 15.0.0-rc.98 → 15.1.0-alpha.1852552014
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 +51 -5
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/adsUtils/index.ts +2 -2
- package/analyticsUtils/AnalyticsEvents/sendMenuClickEvent.ts +2 -2
- package/analyticsUtils/PlayerAnalyticsManager.ts +11 -1
- package/analyticsUtils/README.md +1 -1
- package/analyticsUtils/__tests__/analyticsMapper.test.ts +35 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testACP_events.json +1 -1
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testBlockUnlistedParams_rules.json +1 -1
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEmptyRenameKeepsName_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testEventRegex_events.json +3 -9
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_events.json +18 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testIgnoreOrdering_rules.json +16 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexEventNoFallback_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexMultiGroupRename_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_events.json +4 -0
- package/analyticsUtils/__tests__/fixtures/analytics_mapper_testRegexNonNamedFullMatch_rules.json +6 -0
- package/analyticsUtils/__tests__/fixtures/index.js +20 -0
- package/analyticsUtils/analyticsMapper.ts +4 -1
- package/analyticsUtils/playerAnalyticsTracker.ts +26 -3
- package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +188 -0
- package/appUtils/HooksManager/__tests__/hooksManager.test.js +2 -16
- package/appUtils/HooksManager/index.ts +47 -17
- package/appUtils/RiverFocusManager/{index.ts → index.js} +18 -25
- package/appUtils/accessibilityManager/const.ts +0 -4
- package/appUtils/accessibilityManager/utils.ts +1 -0
- package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +2 -7
- package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +0 -48
- package/appUtils/contextKeysManager/contextResolver.ts +22 -51
- package/appUtils/contextKeysManager/index.ts +10 -65
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +0 -3
- package/appUtils/focusManager/index.ios.ts +4 -43
- package/appUtils/focusManagerAux/utils/index.ts +3 -5
- package/appUtils/focusManagerAux/utils/utils.ios.ts +3 -199
- package/appUtils/keyCodes/keys/keys.web.ts +4 -1
- package/appUtils/localizationsHelper.ts +4 -0
- package/appUtils/orientationHelper.ts +4 -2
- package/appUtils/platform/platformUtils.ts +1 -1
- package/appUtils/playerManager/__tests__/playerFactory.test.ts +150 -0
- package/appUtils/playerManager/index.ts +9 -0
- package/appUtils/playerManager/player.ts +1 -5
- package/appUtils/playerManager/playerFactory.ts +17 -34
- package/appUtils/playerManager/playerNative.ts +22 -30
- package/appUtils/playerManager/usePlayer.tsx +5 -3
- package/appUtils/playerManager/usePlayerState.tsx +2 -14
- package/cellUtils/__tests__/cellUtils.test.ts +39 -0
- package/cellUtils/index.ts +14 -6
- package/cloudEventsUtils/index.ts +1 -65
- package/colorUtils/__tests__/isTransparentColor.test.ts +76 -0
- package/colorUtils/__tests__/isValidColor.test.ts +70 -0
- package/colorUtils/index.ts +50 -0
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
- package/dateUtils/__tests__/dayjs.test.ts +0 -3
- package/dateUtils/index.ts +2 -0
- package/focusManager/aux/index.ts +1 -1
- package/headersUtils/__tests__/headersUtils.test.js +1 -11
- package/headersUtils/index.ts +1 -2
- package/manifestUtils/defaultManifestConfigurations/player.js +7 -75
- package/manifestUtils/keys.js +1 -0
- package/manifestUtils/platformIsTV.js +14 -0
- package/manifestUtils/tvAction/container/index.js +1 -1
- package/numberUtils/__tests__/toNumber.test.ts +0 -12
- package/numberUtils/index.ts +1 -19
- package/package.json +4 -4
- package/pipesUtils/__tests__/buildUrlWithQuery.test.ts +33 -0
- package/pipesUtils/__tests__/withPipesEndpoint.test.tsx +56 -0
- package/pipesUtils/index.ts +1 -0
- package/pipesUtils/withPipesEndpoint.tsx +54 -0
- package/playerUtils/index.ts +24 -2
- package/pluginUtils/index.ts +4 -9
- package/reactHooks/advertising/index.ts +2 -2
- package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +2 -1
- package/reactHooks/casting/index.ts +1 -0
- package/reactHooks/casting/useIsCasting.tsx +57 -0
- package/reactHooks/cell-click/__tests__/index.test.js +3 -1
- package/reactHooks/componentsMap/index.ts +55 -0
- package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
- package/reactHooks/connection/__tests__/index.test.js +1 -1
- package/reactHooks/debugging/__tests__/index.test.js +4 -4
- package/reactHooks/device/useIsTablet.tsx +19 -14
- package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
- package/reactHooks/events/index.ts +20 -0
- package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +23 -32
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
- package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +1 -4
- package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +30 -42
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +1 -1
- package/reactHooks/feed/__tests__/useInflatedUrl.test.tsx +1 -1
- package/reactHooks/feed/useBatchLoading.ts +1 -7
- package/reactHooks/feed/useEntryScreenId.ts +2 -2
- package/reactHooks/feed/useInflatedUrl.ts +1 -1
- package/reactHooks/feed/usePipesCacheReset.ts +1 -3
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +16 -13
- package/reactHooks/index.ts +2 -0
- package/reactHooks/layout/__tests__/index.test.tsx +1 -1
- package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
- package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.tsx → useDimensions.test.ts} +25 -105
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
- package/reactHooks/navigation/__tests__/index.test.tsx +4 -2
- package/reactHooks/navigation/index.ts +6 -7
- package/reactHooks/navigation/useRoute.ts +6 -8
- package/reactHooks/player/TVSeekControlller/TVSeekController.ts +10 -27
- package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
- package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
- package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
- package/reactHooks/resolvers/useCellResolver.ts +2 -6
- package/reactHooks/resolvers/useComponentResolver.ts +13 -9
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
- package/reactHooks/screen/__tests__/useCurrentScreenIsHook.test.ts +103 -0
- package/reactHooks/screen/__tests__/useCurrentScreenIsStartupHook.test.ts +94 -0
- package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +4 -12
- package/reactHooks/screen/index.ts +6 -0
- package/reactHooks/screen/useCurrentScreenIsHook.ts +9 -0
- package/reactHooks/screen/useCurrentScreenIsStartupHook.ts +8 -0
- package/reactHooks/screen/useIsStandaloneFullscreen.ts +12 -0
- package/reactHooks/screen/useTargetScreenData.ts +2 -4
- package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
- package/reactHooks/state/index.ts +2 -0
- package/reactHooks/state/useComponentScreenState.ts +45 -0
- package/reactHooks/state/useRivers.ts +1 -1
- package/reactHooks/usePluginConfiguration.ts +2 -2
- package/reactHooks/utils/__tests__/index.test.js +1 -1
- package/reactHooks/videoModal/hooks/useVideoModalScreenData.tsx +22 -4
- package/rectUtils/index.ts +2 -2
- package/riverComponetsMeasurementProvider/index.tsx +12 -8
- package/screenPickerUtils/index.ts +5 -0
- package/screenState/__tests__/index.test.ts +1 -1
- package/stringUtils/index.ts +1 -1
- package/testUtils/index.tsx +21 -30
- package/typeGuards/index.ts +0 -4
- package/utils/__tests__/clone.test.ts +158 -0
- package/utils/clone.ts +7 -0
- package/utils/index.ts +1 -13
- package/utils/path.ts +3 -6
- package/utils/pathOr.ts +1 -5
- package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +2 -2
- package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
- package/zappFrameworkUtils/loginPluginUtils.ts +1 -1
- package/adsUtils/__tests__/createVMAP.test.ts +0 -419
- package/appDataUtils/__tests__/urlScheme.test.ts +0 -678
- package/appUtils/focusManagerAux/utils/index.ios.ts +0 -122
- package/cloudEventsUtils/__tests__/index.test.ts +0 -529
- package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +0 -207
- package/errorUtils/__tests__/GeneralError.test.ts +0 -97
- package/errorUtils/__tests__/HttpStatusCode.test.ts +0 -344
- package/errorUtils/__tests__/MissingPluginError.test.ts +0 -113
- package/errorUtils/__tests__/NetworkError.test.ts +0 -202
- package/errorUtils/__tests__/getParsedResponse.test.ts +0 -188
- package/errorUtils/__tests__/invariant.test.ts +0 -112
- package/numberUtils/__tests__/toPositiveNumber.test.ts +0 -165
- package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +0 -537
- package/reactHooks/dev/__tests__/useReRenderLog.test.ts +0 -188
- package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +0 -580
- package/rectUtils/__tests__/index.test.ts +0 -549
- package/screenPickerUtils/__tests__/index.test.ts +0 -333
- package/searchUtils/const.ts +0 -7
- package/searchUtils/index.ts +0 -3
- package/time/__tests__/BackgroundTimer.test.ts +0 -156
- package/time/__tests__/Timer.test.ts +0 -236
- package/typeGuards/__tests__/isString.test.ts +0 -21
- package/utils/__tests__/mergeRight.test.ts +0 -48
- package/utils/__tests__/selectors.test.ts +0 -124
- package/utils/mergeRight.ts +0 -5
- package/utils/selectors.ts +0 -46
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as R from "ramda";
|
|
2
2
|
|
|
3
3
|
import { StorageLevel, StorageType } from "./consts";
|
|
4
4
|
import {
|
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
localStorage as LocalStorage,
|
|
14
14
|
secureStorage as SecureStorage,
|
|
15
15
|
} from "./storage";
|
|
16
|
-
import { NativeModules } from "react-native";
|
|
17
16
|
|
|
18
17
|
export { StorageLevel };
|
|
19
18
|
|
|
@@ -155,65 +154,11 @@ export class ContextKeysManager {
|
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
public async getKeys(
|
|
158
|
-
keys: Array<KeyName
|
|
159
|
-
contextObj?: { key: string; required?: boolean }[]
|
|
157
|
+
keys: Array<KeyName>
|
|
160
158
|
): Promise<Map<KeyName, ValueOrNothing>> {
|
|
161
|
-
|
|
162
|
-
const keysObj: Record<string, boolean> = {};
|
|
159
|
+
const values = await Promise.all(keys.map((key) => this.getKey(key)));
|
|
163
160
|
|
|
164
|
-
|
|
165
|
-
contextObj?.map((item) => [item.key, item.required ?? false]) ?? []
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
let hasResolvableKeys = false;
|
|
169
|
-
|
|
170
|
-
const normalizedKeys: Array<{
|
|
171
|
-
original: KeyName;
|
|
172
|
-
normalized: string | null;
|
|
173
|
-
}> = [];
|
|
174
|
-
|
|
175
|
-
for (const key of keys) {
|
|
176
|
-
const {
|
|
177
|
-
isValid: isValidKey,
|
|
178
|
-
key: parsedKey,
|
|
179
|
-
namespace: parsedNamespace,
|
|
180
|
-
} = this.parseKey(key);
|
|
181
|
-
|
|
182
|
-
if (!isValidKey) {
|
|
183
|
-
normalizedKeys.push({ original: key, normalized: null });
|
|
184
|
-
continue;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
const normalized = buildNamespaceKey(parsedKey, parsedNamespace);
|
|
188
|
-
|
|
189
|
-
keysObj[normalized] = requiredByKey.get(normalized) ?? false;
|
|
190
|
-
hasResolvableKeys = true;
|
|
191
|
-
normalizedKeys.push({ original: key, normalized });
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (!hasResolvableKeys) {
|
|
195
|
-
return new Map(
|
|
196
|
-
normalizedKeys.map(({ original }) => [original, NOTHING])
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const res =
|
|
201
|
-
await NativeModules.ContextResolverBridge.resolveContextKeys(keysObj);
|
|
202
|
-
|
|
203
|
-
const resolved = res ?? {};
|
|
204
|
-
|
|
205
|
-
return new Map(
|
|
206
|
-
normalizedKeys.map(({ original, normalized }) => {
|
|
207
|
-
if (!normalized) return [original, NOTHING];
|
|
208
|
-
|
|
209
|
-
return [original, resolved[normalized] ?? NOTHING];
|
|
210
|
-
})
|
|
211
|
-
);
|
|
212
|
-
} else {
|
|
213
|
-
const values = await Promise.all(keys.map((key) => this.getKey(key)));
|
|
214
|
-
|
|
215
|
-
return new Map(keys.map((key, index) => [key, values[index]]));
|
|
216
|
-
}
|
|
161
|
+
return new Map(R.zip(keys, values));
|
|
217
162
|
}
|
|
218
163
|
|
|
219
164
|
public async getKey(key: KeyName): Promise<ValueOrNothing> {
|
|
@@ -236,7 +181,7 @@ export class ContextKeysManager {
|
|
|
236
181
|
parsedNamespace
|
|
237
182
|
);
|
|
238
183
|
|
|
239
|
-
if (!isNil(resultByReference)) {
|
|
184
|
+
if (!R.isNil(resultByReference)) {
|
|
240
185
|
return resultByReference;
|
|
241
186
|
}
|
|
242
187
|
|
|
@@ -247,7 +192,7 @@ export class ContextKeysManager {
|
|
|
247
192
|
parsedNamespace
|
|
248
193
|
);
|
|
249
194
|
|
|
250
|
-
if (!isNil(resultFromSessionStorage)) {
|
|
195
|
+
if (!R.isNil(resultFromSessionStorage)) {
|
|
251
196
|
return resultFromSessionStorage;
|
|
252
197
|
}
|
|
253
198
|
|
|
@@ -256,7 +201,7 @@ export class ContextKeysManager {
|
|
|
256
201
|
parsedNamespace
|
|
257
202
|
);
|
|
258
203
|
|
|
259
|
-
if (!isNil(resultFromLocalStorage)) {
|
|
204
|
+
if (!R.isNil(resultFromLocalStorage)) {
|
|
260
205
|
return resultFromLocalStorage;
|
|
261
206
|
}
|
|
262
207
|
|
|
@@ -265,7 +210,7 @@ export class ContextKeysManager {
|
|
|
265
210
|
parsedNamespace
|
|
266
211
|
);
|
|
267
212
|
|
|
268
|
-
if (!isNil(resultFromSecureStorage)) {
|
|
213
|
+
if (!R.isNil(resultFromSecureStorage)) {
|
|
269
214
|
return resultFromSecureStorage;
|
|
270
215
|
}
|
|
271
216
|
|
|
@@ -330,7 +275,7 @@ export class ContextKeysManager {
|
|
|
330
275
|
keysProp.map((keyProp) => this.setKey(keyProp))
|
|
331
276
|
);
|
|
332
277
|
|
|
333
|
-
return new Map(
|
|
278
|
+
return new Map(R.zip(keys, values));
|
|
334
279
|
}
|
|
335
280
|
|
|
336
281
|
// when succeed saving - return true
|
|
@@ -439,7 +384,7 @@ export class ContextKeysManager {
|
|
|
439
384
|
public async removeKeys(keys: KeyName[]): Promise<Map<KeyName, boolean>> {
|
|
440
385
|
const values = await Promise.all(keys.map((key) => this.removeKey(key)));
|
|
441
386
|
|
|
442
|
-
return new Map(
|
|
387
|
+
return new Map(R.zip(keys, values));
|
|
443
388
|
}
|
|
444
389
|
// REMOVE
|
|
445
390
|
}
|
|
@@ -71,9 +71,6 @@ exports[`focusManagerIOS should be defined 1`] = `
|
|
|
71
71
|
"invokeHandler": [Function],
|
|
72
72
|
"isChildOf": [Function],
|
|
73
73
|
"isFocusOn": [Function],
|
|
74
|
-
"isFocusOnContent": [Function],
|
|
75
|
-
"isFocusOnMenu": [Function],
|
|
76
|
-
"isFocusOnTabsScreenContent": [Function],
|
|
77
74
|
"isGroupItemFocused": [Function],
|
|
78
75
|
"moveFocus": [Function],
|
|
79
76
|
"on": [Function],
|
|
@@ -4,11 +4,7 @@ import * as R from "ramda";
|
|
|
4
4
|
import {
|
|
5
5
|
isCurrentFocusOn,
|
|
6
6
|
isChildOf as isChildOfUtils,
|
|
7
|
-
|
|
8
|
-
isPartOfContent,
|
|
9
|
-
isPartOfTabsScreenContent,
|
|
10
|
-
} from "../focusManagerAux/utils/index.ios";
|
|
11
|
-
|
|
7
|
+
} from "../focusManagerAux/utils";
|
|
12
8
|
import { Tree } from "./treeDataStructure/Tree";
|
|
13
9
|
import { findFocusableNode } from "./treeDataStructure/Utils";
|
|
14
10
|
import { subscriber } from "../../functionUtils";
|
|
@@ -192,15 +188,9 @@ export const focusManager = (function () {
|
|
|
192
188
|
function register({ id, component }) {
|
|
193
189
|
const { isGroup = false } = component;
|
|
194
190
|
|
|
195
|
-
|
|
196
|
-
registerGroup(id, component);
|
|
197
|
-
} else {
|
|
198
|
-
registerItem(id, component);
|
|
199
|
-
}
|
|
191
|
+
emitRegistered(id);
|
|
200
192
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
emitRegistered({ id, groupId, isGroup });
|
|
193
|
+
return isGroup ? registerGroup(id, component) : registerItem(id, component);
|
|
204
194
|
}
|
|
205
195
|
|
|
206
196
|
function unregister(id, { group = false } = {}) {
|
|
@@ -283,9 +273,7 @@ export const focusManager = (function () {
|
|
|
283
273
|
function setFocus(
|
|
284
274
|
id: string,
|
|
285
275
|
direction?: FocusManager.IOS.Direction,
|
|
286
|
-
options?: Partial<{
|
|
287
|
-
groupFocusedChanged: boolean;
|
|
288
|
-
}>,
|
|
276
|
+
options?: Partial<{ groupFocusedChanged: boolean }>,
|
|
289
277
|
callback?: any
|
|
290
278
|
) {
|
|
291
279
|
blur(direction);
|
|
@@ -424,30 +412,6 @@ export const focusManager = (function () {
|
|
|
424
412
|
return id && isCurrentFocusOn(id, currentFocusNode);
|
|
425
413
|
}
|
|
426
414
|
|
|
427
|
-
function isFocusOnMenu(): boolean {
|
|
428
|
-
const currentFocusable = getCurrentFocus();
|
|
429
|
-
|
|
430
|
-
return isPartOfMenu(focusableTree, currentFocusable?.props?.id);
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function isFocusOnContent(): boolean {
|
|
434
|
-
const currentFocusable = getCurrentFocus();
|
|
435
|
-
|
|
436
|
-
return isPartOfContent(focusableTree, currentFocusable?.props?.id);
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
function isFocusOnTabsScreenContent(
|
|
440
|
-
screenPickerContentContainerId: string
|
|
441
|
-
): boolean {
|
|
442
|
-
const currentFocusable = getCurrentFocus();
|
|
443
|
-
|
|
444
|
-
return isPartOfTabsScreenContent(
|
|
445
|
-
focusableTree,
|
|
446
|
-
screenPickerContentContainerId,
|
|
447
|
-
currentFocusable?.props?.id
|
|
448
|
-
);
|
|
449
|
-
}
|
|
450
|
-
|
|
451
415
|
function isChildOf(childId, parentId): boolean {
|
|
452
416
|
return isChildOfUtils(focusableTree, childId, parentId);
|
|
453
417
|
}
|
|
@@ -474,9 +438,6 @@ export const focusManager = (function () {
|
|
|
474
438
|
isGroupItemFocused,
|
|
475
439
|
getPreferredFocusChild,
|
|
476
440
|
isFocusOn,
|
|
477
|
-
isFocusOnMenu,
|
|
478
|
-
isFocusOnContent,
|
|
479
|
-
isFocusOnTabsScreenContent,
|
|
480
441
|
isChildOf,
|
|
481
442
|
};
|
|
482
443
|
})();
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
15
|
getFocusableId,
|
|
16
|
-
|
|
16
|
+
isTabsScreenContentContainerId,
|
|
17
17
|
} from "@applicaster/zapp-react-native-utils/screenPickerUtils";
|
|
18
18
|
|
|
19
19
|
// run check each 300 ms
|
|
@@ -24,8 +24,6 @@ const isTopMenu = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
|
|
|
24
24
|
const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
|
|
25
25
|
const isRoot = (node) => node?.id === "root";
|
|
26
26
|
|
|
27
|
-
const isScrenPicker = (node) => startsWith(SCREEN_PICKER_CONTAINER, node?.id);
|
|
28
|
-
|
|
29
27
|
type Props = {
|
|
30
28
|
maxTimeout: number;
|
|
31
29
|
conditionFn: () => boolean;
|
|
@@ -102,7 +100,7 @@ export const getNavbarNode = (focusableTree) => {
|
|
|
102
100
|
|
|
103
101
|
export const waitForContent = (focusableTree) => {
|
|
104
102
|
const contentHasAnyChildren = (): boolean => {
|
|
105
|
-
const countOfChildren = pathOr
|
|
103
|
+
const countOfChildren = pathOr(
|
|
106
104
|
0,
|
|
107
105
|
["children", "length"],
|
|
108
106
|
getContentNode(focusableTree)
|
|
@@ -136,7 +134,7 @@ export const isTabsScreenOnContentFocused = (node) => {
|
|
|
136
134
|
return false;
|
|
137
135
|
}
|
|
138
136
|
|
|
139
|
-
if (
|
|
137
|
+
if (isTabsScreenContentContainerId(node?.id)) {
|
|
140
138
|
return true;
|
|
141
139
|
}
|
|
142
140
|
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import { ReplaySubject
|
|
2
|
-
import { filter
|
|
3
|
-
|
|
1
|
+
import { ReplaySubject } from "rxjs";
|
|
2
|
+
import { filter } from "rxjs/operators";
|
|
4
3
|
import { BUTTON_PREFIX } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const";
|
|
5
4
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
6
|
-
import { isPartOfMenu, isPartOfContent } from "./index.ios";
|
|
7
5
|
|
|
8
6
|
type FocusableID = string;
|
|
9
7
|
type RegistrationEvent = {
|
|
@@ -11,25 +9,6 @@ type RegistrationEvent = {
|
|
|
11
9
|
registered: boolean;
|
|
12
10
|
};
|
|
13
11
|
|
|
14
|
-
let focusableViewRegistrationSubject$ = new Subject<{
|
|
15
|
-
id: FocusableID;
|
|
16
|
-
groupId: FocusableID;
|
|
17
|
-
}>();
|
|
18
|
-
|
|
19
|
-
let focusableGroupRegistrationSubject$ = new ReplaySubject<{
|
|
20
|
-
id: FocusableID;
|
|
21
|
-
}>();
|
|
22
|
-
|
|
23
|
-
let focusableNativeViewRegistrationSubject$ = new Subject<{
|
|
24
|
-
id: FocusableID;
|
|
25
|
-
groupId: FocusableID;
|
|
26
|
-
}>();
|
|
27
|
-
|
|
28
|
-
let focusableNativeGroupRegistrationSubject$ = new ReplaySubject<{
|
|
29
|
-
id: FocusableID;
|
|
30
|
-
groupId: FocusableID;
|
|
31
|
-
}>();
|
|
32
|
-
|
|
33
12
|
const isFocusableButton = (id: Option<FocusableID>): boolean =>
|
|
34
13
|
id && id.includes?.(BUTTON_PREFIX);
|
|
35
14
|
|
|
@@ -43,189 +22,14 @@ export const focusableButtonsRegistration$ = (focusableGroupId: string) =>
|
|
|
43
22
|
)
|
|
44
23
|
);
|
|
45
24
|
|
|
46
|
-
export const
|
|
47
|
-
// complete the old subject so subscribers are notified and resources are freed
|
|
48
|
-
if (!focusableViewRegistrationSubject$.closed) {
|
|
49
|
-
focusableViewRegistrationSubject$.complete();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!focusableGroupRegistrationSubject$.closed) {
|
|
53
|
-
focusableGroupRegistrationSubject$.complete();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (!focusableNativeViewRegistrationSubject$.closed) {
|
|
57
|
-
focusableNativeViewRegistrationSubject$.complete();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!focusableNativeGroupRegistrationSubject$.closed) {
|
|
61
|
-
focusableNativeGroupRegistrationSubject$.complete();
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
focusableViewRegistrationSubject$ = new Subject<{
|
|
65
|
-
id: FocusableID;
|
|
66
|
-
groupId: FocusableID;
|
|
67
|
-
}>();
|
|
68
|
-
|
|
69
|
-
focusableGroupRegistrationSubject$ = new ReplaySubject<{
|
|
70
|
-
id: FocusableID;
|
|
71
|
-
}>();
|
|
72
|
-
|
|
73
|
-
focusableNativeViewRegistrationSubject$ = new Subject<{
|
|
74
|
-
id: FocusableID;
|
|
75
|
-
groupId: FocusableID;
|
|
76
|
-
}>();
|
|
77
|
-
|
|
78
|
-
focusableNativeGroupRegistrationSubject$ = new ReplaySubject<{
|
|
79
|
-
id: FocusableID;
|
|
80
|
-
groupId: FocusableID;
|
|
81
|
-
}>();
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const focusableNativeViewRegistration = ({ focusableView, focusableGroup }) => {
|
|
85
|
-
return focusableNativeViewRegistrationSubject$.pipe(
|
|
86
|
-
filter(
|
|
87
|
-
(focusableNativeView) => focusableNativeView.id === focusableView.id
|
|
88
|
-
),
|
|
89
|
-
take(1),
|
|
90
|
-
switchMap((focusableNativeView) =>
|
|
91
|
-
// start waiting registration of its parent FocusableNativeGroup
|
|
92
|
-
focusableNativeGroupRegistrationSubject$.pipe(
|
|
93
|
-
filter(
|
|
94
|
-
(focusableNativeGroup) =>
|
|
95
|
-
focusableNativeGroup.id === focusableNativeView.groupId
|
|
96
|
-
),
|
|
97
|
-
take(1),
|
|
98
|
-
map((focusableNativeGroup) => ({
|
|
99
|
-
focusableNativeGroup,
|
|
100
|
-
focusableNativeView,
|
|
101
|
-
focusableView,
|
|
102
|
-
focusableGroup,
|
|
103
|
-
}))
|
|
104
|
-
)
|
|
105
|
-
)
|
|
106
|
-
);
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
export const firstFocusableViewRegistrationFactory = () =>
|
|
110
|
-
focusableViewRegistrationSubject$.pipe(
|
|
111
|
-
take(1), // we care about only first FocusableView registration
|
|
112
|
-
switchMap((focusableView) =>
|
|
113
|
-
// start waiting registration of its parent FocusableGroup
|
|
114
|
-
focusableGroupRegistrationSubject$.pipe(
|
|
115
|
-
filter((focusableGroup) => focusableGroup.id === focusableView.groupId),
|
|
116
|
-
take(1),
|
|
117
|
-
map((focusableGroup) => ({
|
|
118
|
-
focusableView,
|
|
119
|
-
focusableGroup,
|
|
120
|
-
}))
|
|
121
|
-
)
|
|
122
|
-
),
|
|
123
|
-
// start waiting registration for FocusableNativeView and its parent FocusableNativeGroup
|
|
124
|
-
switchMap(({ focusableView, focusableGroup }) =>
|
|
125
|
-
focusableNativeViewRegistration({
|
|
126
|
-
focusableView,
|
|
127
|
-
focusableGroup,
|
|
128
|
-
})
|
|
129
|
-
)
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
// registration on RN level(into RN focusManager)
|
|
133
|
-
export const emitRegistered = ({
|
|
134
|
-
id,
|
|
135
|
-
groupId,
|
|
136
|
-
isGroup,
|
|
137
|
-
}: {
|
|
138
|
-
id: Option<FocusableID>;
|
|
139
|
-
groupId: Option<FocusableID>;
|
|
140
|
-
isGroup: boolean;
|
|
141
|
-
}): void => {
|
|
25
|
+
export const emitRegistered = (id: Option<FocusableID>): void => {
|
|
142
26
|
if (isFocusableButton(id)) {
|
|
143
27
|
registeredSubject$.next({ id, registered: true });
|
|
144
28
|
}
|
|
145
|
-
|
|
146
|
-
if (isGroup && id) {
|
|
147
|
-
focusableGroupRegistrationSubject$.next({ id });
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (!isGroup && id && groupId) {
|
|
151
|
-
focusableViewRegistrationSubject$.next({ id, groupId });
|
|
152
|
-
}
|
|
153
29
|
};
|
|
154
30
|
|
|
155
|
-
// unregistration on RN level(into RN focusManager)
|
|
156
31
|
export const emitUnregistered = (id: Option<FocusableID>): void => {
|
|
157
32
|
if (isFocusableButton(id)) {
|
|
158
33
|
registeredSubject$.next({ id, registered: false });
|
|
159
34
|
}
|
|
160
35
|
};
|
|
161
|
-
|
|
162
|
-
// registration focusableNativeView and focusableNativeGroup
|
|
163
|
-
export const emitNativeRegistered = ({
|
|
164
|
-
id,
|
|
165
|
-
groupId,
|
|
166
|
-
isGroup,
|
|
167
|
-
}: {
|
|
168
|
-
id: Option<FocusableID>;
|
|
169
|
-
groupId: Option<FocusableID>;
|
|
170
|
-
isGroup: boolean;
|
|
171
|
-
}): void => {
|
|
172
|
-
if (!isGroup && id && groupId) {
|
|
173
|
-
focusableNativeViewRegistrationSubject$.next({ id, groupId });
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (isGroup && id && groupId) {
|
|
177
|
-
focusableNativeGroupRegistrationSubject$.next({ id, groupId });
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
// /////
|
|
182
|
-
|
|
183
|
-
const focusedSubject$ = new Subject<FocusableID>();
|
|
184
|
-
|
|
185
|
-
const focused$ = focusedSubject$.asObservable();
|
|
186
|
-
|
|
187
|
-
export const emitFocused = (id: FocusableID): void => {
|
|
188
|
-
focusedSubject$.next(id);
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
export const topMenuItemFocused$ = focused$.pipe(
|
|
192
|
-
filter((id) => id && isPartOfMenu(focusManager.focusableTree, id))
|
|
193
|
-
);
|
|
194
|
-
|
|
195
|
-
export const contentFocused$ = focused$.pipe(
|
|
196
|
-
filter((id) => {
|
|
197
|
-
const isContent = isPartOfContent(focusManager.focusableTree, id);
|
|
198
|
-
|
|
199
|
-
return id && isContent;
|
|
200
|
-
})
|
|
201
|
-
);
|
|
202
|
-
|
|
203
|
-
const createFocusableRegistry = () => {
|
|
204
|
-
const subject$ = new ReplaySubject<FocusableID | undefined>(1);
|
|
205
|
-
|
|
206
|
-
return {
|
|
207
|
-
observable$: subject$.asObservable(),
|
|
208
|
-
register: (id: FocusableID) => {
|
|
209
|
-
// save focusable_id on registration
|
|
210
|
-
subject$.next(id);
|
|
211
|
-
},
|
|
212
|
-
unregister: () => {
|
|
213
|
-
// reset focusable_id on unregistration
|
|
214
|
-
subject$.next(undefined);
|
|
215
|
-
},
|
|
216
|
-
};
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
/// HOME_TOP_MENU_ITEM
|
|
220
|
-
export const HomeTopMenuItemRegistry = createFocusableRegistry();
|
|
221
|
-
|
|
222
|
-
export const homeTopMenuItemFocused$ = topMenuItemFocused$.pipe(
|
|
223
|
-
withLatestFrom(HomeTopMenuItemRegistry.observable$),
|
|
224
|
-
filter(([id, homeId]) => id === homeId)
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
/// SCREEN_PICKER
|
|
228
|
-
export const ScreenPickerContentContainerRegistry = createFocusableRegistry();
|
|
229
|
-
|
|
230
|
-
/// SEARCH_INPUT
|
|
231
|
-
export const SearchInputRegistry = createFocusableRegistry();
|
|
@@ -10,7 +10,10 @@ import { Platform } from "react-native";
|
|
|
10
10
|
* platformKeys[Platform.OS] should only include keys
|
|
11
11
|
* that are unique to that platform, i.e. Exit: { keyCode: 10182 }
|
|
12
12
|
*/
|
|
13
|
-
export const KEYS = Object.assign(
|
|
13
|
+
export const KEYS = Object.assign(
|
|
14
|
+
platformKeys["web"],
|
|
15
|
+
platformKeys[Platform.OS]
|
|
16
|
+
);
|
|
14
17
|
|
|
15
18
|
export const ARROW_KEYS = [
|
|
16
19
|
KEYS.ArrowUp,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ReactNative from "react-native";
|
|
2
|
-
import {
|
|
2
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
3
|
|
|
4
4
|
import { isTV, platformSelect } from "../reactUtils";
|
|
5
5
|
import { useIsTablet } from "../reactHooks";
|
|
@@ -184,7 +184,9 @@ export const getScreenOrientation = ({
|
|
|
184
184
|
|
|
185
185
|
export const useGetScreenOrientation = (screenData) => {
|
|
186
186
|
const isTablet = useIsTablet();
|
|
187
|
-
|
|
187
|
+
|
|
188
|
+
const { appData } = usePickFromState(["appData"]);
|
|
189
|
+
const isTabletPortrait = appData?.isTabletPortrait;
|
|
188
190
|
|
|
189
191
|
return getScreenOrientation({
|
|
190
192
|
screenData,
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const mockAppStoreGet = jest.fn();
|
|
2
|
+
const mockFindPluginByIdentifier = jest.fn();
|
|
3
|
+
|
|
4
|
+
jest.mock("@applicaster/zapp-react-native-redux/AppStore", () => ({
|
|
5
|
+
appStore: { get: (key: string) => mockAppStoreGet(key) },
|
|
6
|
+
}));
|
|
7
|
+
|
|
8
|
+
jest.mock("@applicaster/zapp-react-native-utils/pluginUtils", () => ({
|
|
9
|
+
findPluginByIdentifier: (id: string, plugins: any) =>
|
|
10
|
+
mockFindPluginByIdentifier(id, plugins),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
import { PlayerRole } from "../conts";
|
|
14
|
+
import { playerFactory } from "../playerFactory";
|
|
15
|
+
|
|
16
|
+
const fakeComponent = () => null;
|
|
17
|
+
|
|
18
|
+
class FakeController {
|
|
19
|
+
receivedConfig: any;
|
|
20
|
+
constructor(config: any) {
|
|
21
|
+
this.receivedConfig = config;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const baseConfig = {
|
|
26
|
+
player: {},
|
|
27
|
+
playerId: "p1",
|
|
28
|
+
autoplay: false,
|
|
29
|
+
entry: { id: "entry-1" } as any,
|
|
30
|
+
muted: false,
|
|
31
|
+
playerPluginId: "test-plugin",
|
|
32
|
+
screenConfig: { foo: "bar" },
|
|
33
|
+
playerRole: PlayerRole.Cell,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const installPluginWithProtocol = (
|
|
37
|
+
protocolReturn: any | ((screenConfig: any, entry: any) => any)
|
|
38
|
+
) => {
|
|
39
|
+
const playerProtocol =
|
|
40
|
+
typeof protocolReturn === "function"
|
|
41
|
+
? protocolReturn
|
|
42
|
+
: () => protocolReturn;
|
|
43
|
+
|
|
44
|
+
mockAppStoreGet.mockImplementation((key: string) =>
|
|
45
|
+
key === "plugins" ? { "test-plugin": {} } : null
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
mockFindPluginByIdentifier.mockReturnValue({
|
|
49
|
+
module: { playerProtocol },
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe("playerFactory", () => {
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
mockAppStoreGet.mockReset();
|
|
56
|
+
mockFindPluginByIdentifier.mockReset();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("resolves with controller and Component when playerProtocol returns synchronously", async () => {
|
|
60
|
+
installPluginWithProtocol({
|
|
61
|
+
Component: fakeComponent,
|
|
62
|
+
controllerClass: FakeController,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const item = await playerFactory(baseConfig);
|
|
66
|
+
|
|
67
|
+
expect(item).not.toBeNull();
|
|
68
|
+
expect(item?.Component).toBe(fakeComponent);
|
|
69
|
+
expect(item?.controller).toBeInstanceOf(FakeController);
|
|
70
|
+
|
|
71
|
+
expect((item?.controller as FakeController).receivedConfig).toBe(
|
|
72
|
+
baseConfig
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("resolves with controller and Component when playerProtocol returns a Promise (delayed import)", async () => {
|
|
77
|
+
installPluginWithProtocol(async () => ({
|
|
78
|
+
Component: fakeComponent,
|
|
79
|
+
controllerClass: FakeController,
|
|
80
|
+
}));
|
|
81
|
+
|
|
82
|
+
const item = await playerFactory(baseConfig);
|
|
83
|
+
|
|
84
|
+
expect(item).not.toBeNull();
|
|
85
|
+
expect(item?.Component).toBe(fakeComponent);
|
|
86
|
+
expect(item?.controller).toBeInstanceOf(FakeController);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("passes screenConfig and entry through to playerProtocol", async () => {
|
|
90
|
+
const playerProtocol = jest.fn(() => ({
|
|
91
|
+
Component: fakeComponent,
|
|
92
|
+
controllerClass: FakeController,
|
|
93
|
+
}));
|
|
94
|
+
|
|
95
|
+
mockAppStoreGet.mockImplementation((key: string) =>
|
|
96
|
+
key === "plugins" ? { "test-plugin": {} } : null
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
mockFindPluginByIdentifier.mockReturnValue({ module: { playerProtocol } });
|
|
100
|
+
|
|
101
|
+
await playerFactory(baseConfig);
|
|
102
|
+
|
|
103
|
+
expect(playerProtocol).toHaveBeenCalledWith(
|
|
104
|
+
baseConfig.screenConfig,
|
|
105
|
+
baseConfig.entry
|
|
106
|
+
);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("resolves to null when playerPluginId is missing", async () => {
|
|
110
|
+
expect(
|
|
111
|
+
await playerFactory({ ...baseConfig, playerPluginId: "" } as any)
|
|
112
|
+
).toBeNull();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("resolves to null when appStore has no plugins", async () => {
|
|
116
|
+
mockAppStoreGet.mockReturnValue(null);
|
|
117
|
+
|
|
118
|
+
expect(await playerFactory(baseConfig)).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("resolves to null when the plugin has no playerProtocol", async () => {
|
|
122
|
+
mockAppStoreGet.mockImplementation((key: string) =>
|
|
123
|
+
key === "plugins" ? { "test-plugin": {} } : null
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
mockFindPluginByIdentifier.mockReturnValue({ module: {} });
|
|
127
|
+
|
|
128
|
+
expect(await playerFactory(baseConfig)).toBeNull();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("resolves to null when playerProtocol returns without a Component", async () => {
|
|
132
|
+
installPluginWithProtocol({ controllerClass: FakeController });
|
|
133
|
+
|
|
134
|
+
expect(await playerFactory(baseConfig)).toBeNull();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("resolves to null when playerProtocol returns without a controllerClass", async () => {
|
|
138
|
+
installPluginWithProtocol({ Component: fakeComponent });
|
|
139
|
+
|
|
140
|
+
expect(await playerFactory(baseConfig)).toBeNull();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("rejects when playerProtocol throws synchronously", async () => {
|
|
144
|
+
installPluginWithProtocol(() => {
|
|
145
|
+
throw new Error("boom");
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
await expect(playerFactory(baseConfig)).rejects.toThrow("boom");
|
|
149
|
+
});
|
|
150
|
+
});
|