@applicaster/zapp-react-native-utils 13.0.0-rc.99 → 14.0.0-alpha.1054425138
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 +86 -66
- package/actionsExecutor/ScreenActions.ts +90 -0
- package/actionsExecutor/StorageActions.ts +110 -0
- package/actionsExecutor/consts.ts +4 -0
- 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/contextKeysManager/contextResolver.ts +15 -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/cellUtils/index.ts +9 -5
- package/componentsUtils/index.ts +8 -1
- package/localizationUtils/index.ts +3 -3
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +0 -8
- package/manifestUtils/index.js +2 -0
- package/manifestUtils/keys.js +27 -2
- package/navigationUtils/__tests__/navigationUtils.test.js +0 -65
- package/navigationUtils/index.ts +0 -31
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +0 -16
- package/playerUtils/index.ts +17 -0
- package/reactHooks/app/useAppState.ts +2 -2
- package/reactHooks/cell-click/index.ts +5 -1
- package/reactHooks/feed/useBatchLoading.ts +10 -12
- package/reactHooks/feed/useFeedLoader.tsx +13 -6
- package/reactHooks/navigation/{useGetTabBarHeight.ts → getTabBarHeight.ts} +1 -1
- 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/typeGuards/index.ts +3 -0
- package/utils/index.ts +1 -1
- package/zappFrameworkUtils/localStorageHelper.ts +32 -10
|
@@ -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;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { ContextKeysManager } from "./index";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import { screenStates } from "@applicaster/zapp-react-native-bridge/ZappStorage/ScreenSingleValueProvider";
|
|
3
4
|
|
|
4
|
-
interface IResolver {
|
|
5
|
+
export interface IResolver {
|
|
5
6
|
resolve: (string) => Promise<string | number | object>;
|
|
6
7
|
}
|
|
7
8
|
|
|
9
|
+
// TODO: Rename to ObjectKeyResolver or similar
|
|
8
10
|
export class EntryResolver implements IResolver {
|
|
9
11
|
entry: ZappEntry;
|
|
10
12
|
|
|
@@ -21,6 +23,18 @@ export class EntryResolver implements IResolver {
|
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
25
|
|
|
26
|
+
// TODO: Move to proper place
|
|
27
|
+
|
|
28
|
+
export class ScreenStateResolver implements IResolver {
|
|
29
|
+
constructor(private route: string) {}
|
|
30
|
+
|
|
31
|
+
async resolve(key: string) {
|
|
32
|
+
const screenState = screenStates[this.route];
|
|
33
|
+
|
|
34
|
+
return screenState?.[key];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
export class ContextResolver implements IResolver {
|
|
25
39
|
resolve = async (compositeKey: string) =>
|
|
26
40
|
ContextKeysManager.instance.getKey(compositeKey);
|
|
@@ -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
|
};
|
package/cellUtils/index.ts
CHANGED
|
@@ -2,12 +2,16 @@ import * as R from "ramda";
|
|
|
2
2
|
import dayjs from "dayjs";
|
|
3
3
|
import validateColor from "validate-color";
|
|
4
4
|
|
|
5
|
+
import { transformColorCode as fixColorHexCode } from "@applicaster/zapp-react-native-utils/transform";
|
|
6
|
+
import {
|
|
7
|
+
capitalize,
|
|
8
|
+
isString,
|
|
9
|
+
} from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
10
|
+
import { cellUtilsLogger } from "@applicaster/zapp-react-native-utils/cellUtils/logger";
|
|
11
|
+
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
12
|
+
import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
13
|
+
|
|
5
14
|
import { toNumberWithDefault, toNumberWithDefaultZero } from "../numberUtils";
|
|
6
|
-
import { transformColorCode as fixColorHexCode } from "../transform";
|
|
7
|
-
import { capitalize, isString } from "../stringUtils";
|
|
8
|
-
import { cellUtilsLogger } from "./logger";
|
|
9
|
-
import { isWeb } from "../reactUtils";
|
|
10
|
-
import { isNotNil } from "../reactUtils/helpers";
|
|
11
15
|
|
|
12
16
|
const CUSTOM_KEY = "other";
|
|
13
17
|
|
package/componentsUtils/index.ts
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
const GROUP = "group-qb";
|
|
2
2
|
const GROUP_INFO = "group-info-qb";
|
|
3
|
+
const GROUP_INFO_OLD = "group-info";
|
|
3
4
|
const EMPTY_GROUP_COMPONENT = "empty_group_component";
|
|
4
5
|
|
|
5
6
|
const GALLERY = "gallery-qb";
|
|
6
7
|
|
|
7
8
|
const SCREEN_PICKER = "screen-picker-qb-tv";
|
|
8
9
|
|
|
10
|
+
const HORIZONTAL_LIST = "horizontal_list_qb";
|
|
11
|
+
|
|
9
12
|
export const isGallery = (item): boolean => item?.component_type === GALLERY;
|
|
10
13
|
|
|
14
|
+
export const isHorizontalList = (item): boolean =>
|
|
15
|
+
item?.component_type === HORIZONTAL_LIST;
|
|
16
|
+
|
|
11
17
|
export const isScreenPicker = (item): boolean =>
|
|
12
18
|
item?.component_type === SCREEN_PICKER;
|
|
13
19
|
|
|
@@ -29,4 +35,5 @@ export const isEmptyGroup = (item): boolean =>
|
|
|
29
35
|
item?.component_type === EMPTY_GROUP_COMPONENT;
|
|
30
36
|
|
|
31
37
|
export const isGroupInfo = (item): boolean =>
|
|
32
|
-
item?.component_type === GROUP_INFO
|
|
38
|
+
item?.component_type === GROUP_INFO ||
|
|
39
|
+
item?.component_type === GROUP_INFO_OLD;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ViewStyle } from "react-native";
|
|
2
2
|
|
|
3
3
|
import { useMemo } from "react";
|
|
4
|
-
import { getUILanguage } from "
|
|
5
|
-
import { utilsLogger } from "
|
|
4
|
+
import { getUILanguage } from "@applicaster/zapp-react-native-utils/appUtils/localizationsHelper";
|
|
5
|
+
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
6
6
|
|
|
7
7
|
export {
|
|
8
8
|
getLocale,
|
|
@@ -10,7 +10,7 @@ export {
|
|
|
10
10
|
getCountryCode,
|
|
11
11
|
getLocalizations,
|
|
12
12
|
getUILanguage,
|
|
13
|
-
} from "
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/localizationsHelper";
|
|
14
14
|
|
|
15
15
|
const RTL_LOCALES = [
|
|
16
16
|
"ar", // Arabic
|
|
@@ -251,6 +251,19 @@ const generalContent = () => ({
|
|
|
251
251
|
key: "screen_title",
|
|
252
252
|
initial_value: null,
|
|
253
253
|
},
|
|
254
|
+
{
|
|
255
|
+
type: "text_input",
|
|
256
|
+
label: "Maximum Selection Reached - Alert Description",
|
|
257
|
+
key: "msg_maximum_selection_reached_message",
|
|
258
|
+
initial_value:
|
|
259
|
+
"You’ve reached the maximum number of items you can select.",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
type: "text_input",
|
|
263
|
+
label: "Maximum Selection Reached - Alert Button",
|
|
264
|
+
key: "msg_maximum_selection_reached_message_ok_button",
|
|
265
|
+
initial_value: "Got it",
|
|
266
|
+
},
|
|
254
267
|
],
|
|
255
268
|
},
|
|
256
269
|
advertising: {
|
|
@@ -42,14 +42,6 @@ function getPlayerConfiguration({ platform }) {
|
|
|
42
42
|
label_tooltip:
|
|
43
43
|
"Enable if you want to have adaptive background gradient based on audio background image.",
|
|
44
44
|
},
|
|
45
|
-
{
|
|
46
|
-
key: "audio_player_background_image_query",
|
|
47
|
-
label: "Audio Player Image Query",
|
|
48
|
-
initial_value: "",
|
|
49
|
-
type: "text_input",
|
|
50
|
-
label_tooltip:
|
|
51
|
-
"Set the query params which control the size of the image e.g width, height. This will help to optimize the loading time, when magic background is enabled.",
|
|
52
|
-
},
|
|
53
45
|
{
|
|
54
46
|
key: "audio_player_background_image_default_color",
|
|
55
47
|
label: "Audio Player Background Image Default Color",
|
package/manifestUtils/index.js
CHANGED
|
@@ -8,6 +8,7 @@ const {
|
|
|
8
8
|
|
|
9
9
|
const { tvActionButtonsContainer } = require("./tvAction/container");
|
|
10
10
|
const { tvActionButton } = require("./tvAction/button");
|
|
11
|
+
const { compact } = require("./_internals");
|
|
11
12
|
|
|
12
13
|
const { spacingKey, absolutePositionElement } = require("./containers");
|
|
13
14
|
|
|
@@ -46,4 +47,5 @@ module.exports = {
|
|
|
46
47
|
tvProgressBar,
|
|
47
48
|
secondaryImage,
|
|
48
49
|
getUpdatedSecondaryImageKeys,
|
|
50
|
+
compact,
|
|
49
51
|
};
|
package/manifestUtils/keys.js
CHANGED
|
@@ -21,7 +21,30 @@ const ZAPPIFEST_FIELDS = {
|
|
|
21
21
|
},
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
-
const
|
|
24
|
+
const TV_PLATFORMS_FOR_FONTS = [
|
|
25
|
+
"tvOS",
|
|
26
|
+
"android",
|
|
27
|
+
"LG",
|
|
28
|
+
"samsung",
|
|
29
|
+
"roku",
|
|
30
|
+
"vizio",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const MOBILE_PLATFORMS = [
|
|
34
|
+
"ios",
|
|
35
|
+
"ios_for_quickbrick",
|
|
36
|
+
"android",
|
|
37
|
+
"android_for_quickbrick",
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const TV_PLATFORMS = [
|
|
41
|
+
"android_tv_for_quickbrick",
|
|
42
|
+
"amazon_fire_tv_for_quickbrick",
|
|
43
|
+
"tvos_for_quickbrick",
|
|
44
|
+
"samsung_tv",
|
|
45
|
+
"lg_tv",
|
|
46
|
+
"vizio",
|
|
47
|
+
];
|
|
25
48
|
|
|
26
49
|
const FontPropsForTVPlatform = (platform) => ({
|
|
27
50
|
[`${R.toLower(platform)}FontFamily`]: {
|
|
@@ -92,7 +115,7 @@ const TV_FONT_KEY_DATA = {
|
|
|
92
115
|
name: "focused font color",
|
|
93
116
|
type: ZAPPIFEST_FIELDS.color_picker,
|
|
94
117
|
},
|
|
95
|
-
...R.reduce(addTVFontsForPlatform, {},
|
|
118
|
+
...R.reduce(addTVFontsForPlatform, {}, TV_PLATFORMS_FOR_FONTS),
|
|
96
119
|
textAlignment: {
|
|
97
120
|
name: "text alignment",
|
|
98
121
|
type: ZAPPIFEST_FIELDS.select,
|
|
@@ -2083,4 +2106,6 @@ module.exports = {
|
|
|
2083
2106
|
TV_CELL_BADGE_FIELDS,
|
|
2084
2107
|
progressBarFields,
|
|
2085
2108
|
secondaryImageFields,
|
|
2109
|
+
TV_PLATFORMS,
|
|
2110
|
+
MOBILE_PLATFORMS,
|
|
2086
2111
|
};
|
|
@@ -319,68 +319,3 @@ describe("getRiverFromRoute", () => {
|
|
|
319
319
|
expect(getRiverFromRoute({ route, rivers })).toEqual(river);
|
|
320
320
|
});
|
|
321
321
|
});
|
|
322
|
-
|
|
323
|
-
describe("isPreviousRouteHook", () => {
|
|
324
|
-
const { isPreviousRouteHook } = navigationUtils;
|
|
325
|
-
|
|
326
|
-
const history = {
|
|
327
|
-
entries: [],
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
it("returns false if it's a root route", () => {
|
|
331
|
-
history.entries.push({ pathname: "/river/root" });
|
|
332
|
-
const currentResult = isPreviousRouteHook(history.entries);
|
|
333
|
-
expect(currentResult).toBe(false);
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
it("returns false if previous root is not a hook", () => {
|
|
337
|
-
history.entries.push({ pathname: "/almostHooks/secondLevel" });
|
|
338
|
-
const currentResult = isPreviousRouteHook(history.entries);
|
|
339
|
-
expect(currentResult).toBe(false);
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
it("returns true if previous root is a hook", () => {
|
|
343
|
-
history.entries.push({ pathname: "/hooks/ThirdLevel" });
|
|
344
|
-
history.entries.push({ pathname: "/almostHooks/forthLevel" });
|
|
345
|
-
const currentResult = isPreviousRouteHook(history.entries);
|
|
346
|
-
expect(currentResult).toBe(true);
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
describe("getPreviousHooksCount", () => {
|
|
351
|
-
const { getPreviousHooksCount } = navigationUtils;
|
|
352
|
-
|
|
353
|
-
const history = {
|
|
354
|
-
entries: [],
|
|
355
|
-
};
|
|
356
|
-
|
|
357
|
-
it("returns 0 if it's a root route", () => {
|
|
358
|
-
history.entries.push({ pathname: "/river/root" });
|
|
359
|
-
const currentResult = getPreviousHooksCount(history);
|
|
360
|
-
expect(currentResult).toBe(0);
|
|
361
|
-
});
|
|
362
|
-
|
|
363
|
-
it("returns 0 if previous root is not a hook", () => {
|
|
364
|
-
history.entries.push({ pathname: "/almostHooks/secondLevel" });
|
|
365
|
-
const currentResult = getPreviousHooksCount(history);
|
|
366
|
-
expect(currentResult).toBe(0);
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
it("returns 1 if previous root is a hook", () => {
|
|
370
|
-
history.entries = [];
|
|
371
|
-
history.entries.push({ pathname: "/hooks/ThirdLevel" });
|
|
372
|
-
history.entries.push({ pathname: "/almostHooks/forthLevel" });
|
|
373
|
-
const currentResult = getPreviousHooksCount(history);
|
|
374
|
-
expect(currentResult).toBe(1);
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
it("returns 2 if 2 previous routes are a hooks", () => {
|
|
378
|
-
history.entries = [];
|
|
379
|
-
history.entries.push({ pathname: "/almostHooks/forthLevel" });
|
|
380
|
-
history.entries.push({ pathname: "/hooks/myHook" });
|
|
381
|
-
history.entries.push({ pathname: "/hooks/myHook" });
|
|
382
|
-
history.entries.push({ pathname: "/almostHooks/forthLevel" });
|
|
383
|
-
const currentResult = getPreviousHooksCount(history);
|
|
384
|
-
expect(currentResult).toBe(2);
|
|
385
|
-
});
|
|
386
|
-
});
|
package/navigationUtils/index.ts
CHANGED
|
@@ -363,37 +363,6 @@ export function getRiverFromRoute({
|
|
|
363
363
|
return screenType && screenId ? { screenType, screenId } : null;
|
|
364
364
|
}
|
|
365
365
|
|
|
366
|
-
/**
|
|
367
|
-
* Function returns true if the previous route (in the react-router history) is a hook plugin
|
|
368
|
-
* @param {*} entries - React-Router History Object
|
|
369
|
-
* @return boolean
|
|
370
|
-
*/
|
|
371
|
-
export function isPreviousRouteHook(entries: [{ pathname: string }]): boolean {
|
|
372
|
-
const previousRoute = entries[entries.length - 2];
|
|
373
|
-
if (!previousRoute) return false;
|
|
374
|
-
|
|
375
|
-
return R.test(/\/hooks\/.*/g, previousRoute.pathname);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Function returns number of consecutive hooks that are behind the current route
|
|
380
|
-
* @param {*} history - React-Router History Object
|
|
381
|
-
* @return true
|
|
382
|
-
*/
|
|
383
|
-
export function getPreviousHooksCount(history: {
|
|
384
|
-
entries: [{ pathname: string }];
|
|
385
|
-
}): number {
|
|
386
|
-
let hooksCount = 0;
|
|
387
|
-
let entries = R.clone(history.entries);
|
|
388
|
-
|
|
389
|
-
while (isPreviousRouteHook(entries)) {
|
|
390
|
-
hooksCount++;
|
|
391
|
-
entries = R.init(entries);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return hooksCount;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
366
|
export const usesVideoModal = (
|
|
398
367
|
item: ZappEntry,
|
|
399
368
|
rivers: Record<string, ZappRiver>,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "14.0.0-alpha.1054425138",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "
|
|
30
|
+
"@applicaster/applicaster-types": "14.0.0-alpha.1054425138",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -39,22 +39,6 @@ function getPlayerConfiguration({ platform }) {
|
|
|
39
39
|
label_tooltip:
|
|
40
40
|
"Disable if you don't want the content to have a right orientation",
|
|
41
41
|
},
|
|
42
|
-
{
|
|
43
|
-
key: "magic_background",
|
|
44
|
-
label: "Enable Magic Background",
|
|
45
|
-
initial_value: false,
|
|
46
|
-
type: "switch",
|
|
47
|
-
label_tooltip:
|
|
48
|
-
"Enable if you want to have adaptive background gradient based on audio background image.",
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
key: "audio_player_background_image_query",
|
|
52
|
-
label: "Audio Player Image Query",
|
|
53
|
-
initial_value: "",
|
|
54
|
-
type: "text_input",
|
|
55
|
-
label_tooltip:
|
|
56
|
-
"Set the query params which control the size of the image e.g width, height. This will help to optimize the loading time, when magic background is enabled.",
|
|
57
|
-
},
|
|
58
42
|
{
|
|
59
43
|
key: "audio_player_background_image_default_color",
|
|
60
44
|
label: "Audio Player Background Image Default Color",
|
package/playerUtils/index.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
3
|
+
import { isString } from "@applicaster/zapp-react-native-utils/typeGuards";
|
|
4
|
+
|
|
3
5
|
import { getBoolFromConfigValue } from "../configurationUtils";
|
|
4
6
|
|
|
5
7
|
/**
|
|
@@ -72,3 +74,18 @@ function isLiveByManager(): boolean {
|
|
|
72
74
|
export function isLive(entry: ZappEntry): boolean {
|
|
73
75
|
return isEntryLive(entry) || isLiveByManager();
|
|
74
76
|
}
|
|
77
|
+
|
|
78
|
+
export const isAudioItem = (item: Option<ZappEntry>) => {
|
|
79
|
+
if (
|
|
80
|
+
isString(item?.content?.type) &&
|
|
81
|
+
item?.content?.type?.includes?.("audio")
|
|
82
|
+
) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (isString(item?.type?.value) && item?.type?.value?.includes?.("audio")) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
};
|
|
@@ -14,10 +14,10 @@ export function useAppState(returnIsActive) {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
React.useEffect(() => {
|
|
17
|
-
AppState.addEventListener("change", setAppState);
|
|
17
|
+
const subscription = AppState.addEventListener("change", setAppState);
|
|
18
18
|
|
|
19
19
|
return () => {
|
|
20
|
-
|
|
20
|
+
subscription.remove();
|
|
21
21
|
};
|
|
22
22
|
}, []);
|
|
23
23
|
|
|
@@ -16,7 +16,7 @@ import { ActionExecutorContext } from "@applicaster/zapp-react-native-utils/acti
|
|
|
16
16
|
import { isFunction, noop } from "../../functionUtils";
|
|
17
17
|
import { useSendAnalyticsOnPress } from "../analytics";
|
|
18
18
|
import { logOnPress, warnEmptyContentType } from "./helpers";
|
|
19
|
-
import { useCurrentScreenData } from "../screen";
|
|
19
|
+
import { useCurrentScreenData, useScreenContext } from "../screen";
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* If onCellTap is defined execute the function and
|
|
@@ -46,6 +46,7 @@ export const useCellClick = ({
|
|
|
46
46
|
const onCellTap: Option<Function> = React.useContext(CellTapContext);
|
|
47
47
|
const actionExecutor = React.useContext(ActionExecutorContext);
|
|
48
48
|
const screenData = useCurrentScreenData();
|
|
49
|
+
const screenState = useScreenContext()?.options;
|
|
49
50
|
|
|
50
51
|
const cellSelectable = toBooleanWithDefaultTrue(
|
|
51
52
|
component?.rules?.component_cells_selectable
|
|
@@ -83,6 +84,8 @@ export const useCellClick = ({
|
|
|
83
84
|
await actionExecutor?.handleEntryActions(selectedItem, {
|
|
84
85
|
component,
|
|
85
86
|
screenData,
|
|
87
|
+
screenState,
|
|
88
|
+
screenRoute: pathname,
|
|
86
89
|
});
|
|
87
90
|
}
|
|
88
91
|
|
|
@@ -117,6 +120,7 @@ export const useCellClick = ({
|
|
|
117
120
|
push,
|
|
118
121
|
sendAnalyticsOnPress,
|
|
119
122
|
screenData,
|
|
123
|
+
screenState,
|
|
120
124
|
]
|
|
121
125
|
);
|
|
122
126
|
|