@applicaster/zapp-react-native-utils 13.0.0-alpha.4244246222 → 13.0.0-alpha.4302300656
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 +159 -12
- package/actionsExecutor/consts.ts +4 -0
- package/appUtils/HooksManager/Hook.ts +4 -0
- package/appUtils/HooksManager/index.ts +2 -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 +1 -12
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -0
- package/appUtils/focusManager/index.ios.ts +14 -4
- package/appUtils/focusManager/index.ts +13 -0
- package/appUtils/focusManager/utils/__tests__/findChild.test.ts +35 -0
- package/appUtils/focusManager/utils/index.ts +5 -0
- package/appUtils/localizationsHelper.ts +31 -0
- package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +11 -7
- package/appUtils/playerManager/usePlayerTitleSummaryOverlay.tsx +7 -1
- package/cellUtils/index.ts +9 -5
- package/componentsUtils/__tests__/isFirstComponentGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isFirstComponentScreenPicker.test.ts +33 -0
- package/componentsUtils/__tests__/isGallery.test.ts +33 -0
- package/componentsUtils/__tests__/isScreenPicker.test.ts +33 -0
- package/componentsUtils/index.ts +39 -0
- package/dateUtils/index.ts +19 -0
- package/focusManager/FocusManager.ts +3 -1
- package/focusManager/index.ts +4 -30
- package/functionUtils/index.ts +25 -0
- package/index.d.ts +0 -12
- package/localizationUtils/index.ts +8 -13
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +13 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +6 -8
- package/manifestUtils/index.js +2 -0
- package/manifestUtils/keys.js +27 -2
- package/manifestUtils/sharedConfiguration/screenPicker/stylesFields.js +1 -2
- package/modalState/__tests__/index.test.ts +51 -0
- package/modalState/index.ts +32 -2
- package/navigationUtils/__tests__/__snapshots__/navigationUtils.test.js.snap +1 -0
- package/navigationUtils/index.ts +3 -1
- package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +23 -3
- package/numberUtils/index.ts +4 -0
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +6 -16
- package/playerUtils/index.ts +23 -0
- package/reactHooks/advertising/index.ts +5 -5
- package/reactHooks/app/useAppState.ts +2 -2
- package/reactHooks/feed/useBatchLoading.ts +10 -12
- package/reactHooks/feed/useFeedLoader.tsx +17 -8
- package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +39 -0
- 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/navigation/useRoute.ts +4 -6
- 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/README.md +30 -0
- package/utils/chunk.ts +5 -0
- package/utils/index.ts +5 -0
- package/utils/times.ts +5 -0
- package/zappFrameworkUtils/localStorageHelper.ts +38 -10
- package/zappFrameworkUtils/loginPluginUtils.ts +6 -2
- package/zappFrameworkUtils/types.ts +11 -0
|
@@ -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,37 @@ 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
|
+
* */
|
|
74
|
+
export const toDayJSLocaleMap = (code) => {
|
|
75
|
+
const map = {
|
|
76
|
+
hy: "hy-am",
|
|
77
|
+
fj: null,
|
|
78
|
+
la: null,
|
|
79
|
+
no: null,
|
|
80
|
+
pa: "pa-in",
|
|
81
|
+
qu: null,
|
|
82
|
+
sm: null,
|
|
83
|
+
to: null,
|
|
84
|
+
xh: null,
|
|
85
|
+
tt: null,
|
|
86
|
+
"es-LA": "es",
|
|
87
|
+
"en-UK": "en-gb",
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (map[code] === null) {
|
|
91
|
+
return "en";
|
|
92
|
+
} else if (map[code]) {
|
|
93
|
+
return map[code];
|
|
94
|
+
} else {
|
|
95
|
+
return code.toLowerCase();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
68
99
|
/**
|
|
69
100
|
* returns the localization for the app based on the locale. If the locale is null
|
|
70
101
|
* or undefined, or if the given locale doesn't exist in the localizations,
|
|
@@ -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
|
};
|
|
@@ -3,12 +3,18 @@ import { OverlaysObserver } from "./OverlayObserver/OverlaysObserver";
|
|
|
3
3
|
import { useFeedLoader } from "../../reactHooks";
|
|
4
4
|
import { usePlayer } from "./usePlayer";
|
|
5
5
|
|
|
6
|
+
const getLiveUrl = (url: string) => {
|
|
7
|
+
// Use the replace method with a regular expression to replace all instances of subClass with livePage
|
|
8
|
+
return url.replace(new RegExp("subClass", "g"), "livePage");
|
|
9
|
+
};
|
|
10
|
+
|
|
6
11
|
export const useTitleSummaryOverlay = (
|
|
7
|
-
feedUrl,
|
|
8
12
|
entry,
|
|
9
13
|
isLive = false,
|
|
10
14
|
interval: number
|
|
11
15
|
) => {
|
|
16
|
+
// TODO: Have generic place for live url from configuration. Currently its hardcoded for client.
|
|
17
|
+
const feedUrl = getLiveUrl(entry?.extensions?.live?.channel_src ?? "");
|
|
12
18
|
const player = usePlayer();
|
|
13
19
|
const [title, setTitle] = useState<string | number>(entry?.title || "");
|
|
14
20
|
const [summary, setSummary] = useState<string | number>(entry?.summary || "");
|
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
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isFirstComponentGallery } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("isFirstComponentGallery", () => {
|
|
4
|
+
it("should return true if the first component is a gallery", () => {
|
|
5
|
+
const components = [
|
|
6
|
+
{ component_type: "gallery-qb" },
|
|
7
|
+
{ component_type: "other-component" },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
expect(isFirstComponentGallery(components)).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("should return false if the first component is not a gallery", () => {
|
|
14
|
+
const components = [
|
|
15
|
+
{ component_type: "other-component" },
|
|
16
|
+
{ component_type: "gallery-qb" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("should return false if the components array is empty", () => {
|
|
23
|
+
const components = [];
|
|
24
|
+
|
|
25
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return false if the components array is undefined", () => {
|
|
29
|
+
const components = undefined;
|
|
30
|
+
|
|
31
|
+
expect(isFirstComponentGallery(components)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isFirstComponentScreenPicker } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isFirstComponentScreenPicker", () => {
|
|
4
|
+
it("should return true if the first component screen-picker", () => {
|
|
5
|
+
const items = [{ component_type: "screen-picker-qb-tv" }];
|
|
6
|
+
expect(isFirstComponentScreenPicker(items)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the first component type is not screen-picker", () => {
|
|
10
|
+
const items = [{ component_type: "other-component" }];
|
|
11
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const items = [{ component_type: undefined }];
|
|
16
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const items = null;
|
|
21
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const items = undefined;
|
|
26
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const items = {};
|
|
31
|
+
expect(isFirstComponentScreenPicker(items)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isGallery } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isGallery", () => {
|
|
4
|
+
it("should return true if the component type is 'gallery-qb'", () => {
|
|
5
|
+
const item = { component_type: "gallery-qb" };
|
|
6
|
+
expect(isGallery(item)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the component type is not 'gallery-qb'", () => {
|
|
10
|
+
const item = { component_type: "other-component" };
|
|
11
|
+
expect(isGallery(item)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const item = { component_type: undefined };
|
|
16
|
+
expect(isGallery(item)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const item = null;
|
|
21
|
+
expect(isGallery(item)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const item = undefined;
|
|
26
|
+
expect(isGallery(item)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const item = {};
|
|
31
|
+
expect(isGallery(item)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { isScreenPicker } from "..";
|
|
2
|
+
|
|
3
|
+
describe("isScreenPicker", () => {
|
|
4
|
+
it("should return true if the component type is 'screen-picker-qb-tv'", () => {
|
|
5
|
+
const item = { component_type: "screen-picker-qb-tv" };
|
|
6
|
+
expect(isScreenPicker(item)).toBe(true);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it("should return false if the component type is not 'screen-picker-qb-tv'", () => {
|
|
10
|
+
const item = { component_type: "other-component" };
|
|
11
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return false if the component type is undefined", () => {
|
|
15
|
+
const item = { component_type: undefined };
|
|
16
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return false if the item is null", () => {
|
|
20
|
+
const item = null;
|
|
21
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return false if the item is undefined", () => {
|
|
25
|
+
const item = undefined;
|
|
26
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should return false if the item is an empty object", () => {
|
|
30
|
+
const item = {};
|
|
31
|
+
expect(isScreenPicker(item)).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const GROUP = "group-qb";
|
|
2
|
+
const GROUP_INFO = "group-info-qb";
|
|
3
|
+
const GROUP_INFO_OLD = "group-info";
|
|
4
|
+
const EMPTY_GROUP_COMPONENT = "empty_group_component";
|
|
5
|
+
|
|
6
|
+
const GALLERY = "gallery-qb";
|
|
7
|
+
|
|
8
|
+
const SCREEN_PICKER = "screen-picker-qb-tv";
|
|
9
|
+
|
|
10
|
+
const HORIZONTAL_LIST = "horizontal_list_qb";
|
|
11
|
+
|
|
12
|
+
export const isGallery = (item): boolean => item?.component_type === GALLERY;
|
|
13
|
+
|
|
14
|
+
export const isHorizontalList = (item): boolean =>
|
|
15
|
+
item?.component_type === HORIZONTAL_LIST;
|
|
16
|
+
|
|
17
|
+
export const isScreenPicker = (item): boolean =>
|
|
18
|
+
item?.component_type === SCREEN_PICKER;
|
|
19
|
+
|
|
20
|
+
export const isFirstComponentScreenPicker = (
|
|
21
|
+
components: ZappUIComponent[]
|
|
22
|
+
): boolean => {
|
|
23
|
+
return isScreenPicker(components?.[0]);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const isFirstComponentGallery = (
|
|
27
|
+
components: ZappUIComponent[]
|
|
28
|
+
): boolean => {
|
|
29
|
+
return isGallery(components?.[0]);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const isGroup = (item): boolean => item?.component_type === GROUP;
|
|
33
|
+
|
|
34
|
+
export const isEmptyGroup = (item): boolean =>
|
|
35
|
+
item?.component_type === EMPTY_GROUP_COMPONENT;
|
|
36
|
+
|
|
37
|
+
export const isGroupInfo = (item): boolean =>
|
|
38
|
+
item?.component_type === GROUP_INFO ||
|
|
39
|
+
item?.component_type === GROUP_INFO_OLD;
|
package/dateUtils/index.ts
CHANGED
|
@@ -2,10 +2,29 @@ import dayjs from "dayjs";
|
|
|
2
2
|
import utc from "dayjs/plugin/utc";
|
|
3
3
|
import timezone from "dayjs/plugin/timezone";
|
|
4
4
|
import isoWeek from "dayjs/plugin/isoWeek";
|
|
5
|
+
import duration from "dayjs/plugin/duration";
|
|
6
|
+
import relativeTime from "dayjs/plugin/relativeTime";
|
|
5
7
|
|
|
6
8
|
// Extend dayjs with plugins
|
|
7
9
|
dayjs.extend(utc);
|
|
8
10
|
dayjs.extend(timezone);
|
|
9
11
|
dayjs.extend(isoWeek);
|
|
12
|
+
dayjs.extend(duration);
|
|
13
|
+
|
|
14
|
+
dayjs.extend(relativeTime, {
|
|
15
|
+
thresholds: [
|
|
16
|
+
{ l: "s", r: 1 },
|
|
17
|
+
{ l: "m", r: 1 },
|
|
18
|
+
{ l: "mm", r: 59, d: "minute" },
|
|
19
|
+
{ l: "h", r: 1 },
|
|
20
|
+
{ l: "hh", r: 23, d: "hour" },
|
|
21
|
+
{ l: "d", r: 1 },
|
|
22
|
+
{ l: "dd", r: 29, d: "day" },
|
|
23
|
+
{ l: "M", r: 1 },
|
|
24
|
+
{ l: "MM", r: 11, d: "month" },
|
|
25
|
+
{ l: "y", r: 1 },
|
|
26
|
+
{ l: "yy", d: "year" },
|
|
27
|
+
],
|
|
28
|
+
});
|
|
10
29
|
|
|
11
30
|
export { dayjs };
|
|
@@ -227,7 +227,9 @@ class FocusManager {
|
|
|
227
227
|
|
|
228
228
|
const nextNextFocus = FocusManager.getNextFocusable(direction, nextFocus);
|
|
229
229
|
|
|
230
|
-
|
|
230
|
+
if (nextNextFocus) {
|
|
231
|
+
FocusManager.instance.setFocus(nextNextFocus, options);
|
|
232
|
+
}
|
|
231
233
|
} else {
|
|
232
234
|
FocusManager.instance.setFocusLocal(nextFocus);
|
|
233
235
|
|
package/focusManager/index.ts
CHANGED
|
@@ -8,8 +8,6 @@ import { isNilOrEmpty } from "../reactUtils/helpers";
|
|
|
8
8
|
import { isAndroidTVPlatform } from "../reactUtils";
|
|
9
9
|
import { noop } from "../functionUtils";
|
|
10
10
|
|
|
11
|
-
const EMPTY_GROUP_COMPONENT = "empty_group_component";
|
|
12
|
-
|
|
13
11
|
export function useFocusManager() {
|
|
14
12
|
return focusManager;
|
|
15
13
|
}
|
|
@@ -76,14 +74,6 @@ export function useFocusEffect(onFocus, focusWatcher) {
|
|
|
76
74
|
}, focusWatcher);
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
export function shouldShowEmptyGroup(component) {
|
|
80
|
-
return (
|
|
81
|
-
component?.ui_components?.filter(
|
|
82
|
-
({ component_type }) => component_type === EMPTY_GROUP_COMPONENT
|
|
83
|
-
)?.length > 0
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
77
|
export const isFocusable = (component: ZappEntry | ZappUIComponent | any) =>
|
|
88
78
|
R.tryCatch(
|
|
89
79
|
R.compose(
|
|
@@ -101,6 +91,7 @@ type Props = {
|
|
|
101
91
|
|
|
102
92
|
export const useIsFocusable = (props: Props): void => {
|
|
103
93
|
const { component, zappPipesData } = props;
|
|
94
|
+
|
|
104
95
|
const { setIsFocusable } = useFocusable();
|
|
105
96
|
|
|
106
97
|
const componentCellsFocusable = toBooleanWithDefaultTrue(
|
|
@@ -117,33 +108,18 @@ export const useIsFocusable = (props: Props): void => {
|
|
|
117
108
|
isNilOrEmpty(zappPipesData?.data) ||
|
|
118
109
|
isNilOrEmpty(zappPipesData?.data?.entry);
|
|
119
110
|
|
|
120
|
-
const hasNoUIComponents = isNilOrEmpty(component?.ui_components);
|
|
121
|
-
|
|
122
111
|
const hasDataError = !!zappPipesData?.error;
|
|
123
112
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
const isGallery = component?.component_type === "gallery-qb";
|
|
127
|
-
|
|
128
|
-
const isGroup = component?.component_type === "group-qb";
|
|
129
|
-
|
|
130
|
-
const isHiddenDueToEmptyData =
|
|
131
|
-
!isLoadingData && hasNoData && hideIfDataEmpty && !hasEmptyGroup;
|
|
132
|
-
|
|
133
|
-
const isEmptyGroup = isGroup && hasNoUIComponents;
|
|
113
|
+
const isHiddenDueToEmptyData = !isLoadingData && hasNoData && hideIfDataEmpty;
|
|
134
114
|
|
|
135
115
|
const defaultFocusableLogic =
|
|
136
|
-
componentCellsFocusable &&
|
|
137
|
-
(!hasNoData || !hideIfDataEmpty) &&
|
|
138
|
-
!isEmptyGroup;
|
|
116
|
+
componentCellsFocusable && (!hasNoData || !hideIfDataEmpty);
|
|
139
117
|
|
|
140
118
|
React.useEffect(() => {
|
|
141
119
|
if (isAndroidTVPlatform()) {
|
|
142
120
|
let isFocusableNew = false;
|
|
143
121
|
|
|
144
|
-
if (
|
|
145
|
-
isFocusableNew = true;
|
|
146
|
-
} else if (isFocusable(component)) {
|
|
122
|
+
if (isFocusable(component)) {
|
|
147
123
|
isFocusableNew = defaultFocusableLogic;
|
|
148
124
|
}
|
|
149
125
|
|
|
@@ -152,9 +128,7 @@ export const useIsFocusable = (props: Props): void => {
|
|
|
152
128
|
}, [
|
|
153
129
|
defaultFocusableLogic,
|
|
154
130
|
isHiddenDueToEmptyData,
|
|
155
|
-
isGallery,
|
|
156
131
|
setIsFocusable,
|
|
157
132
|
hasDataError,
|
|
158
|
-
hasEmptyGroup,
|
|
159
133
|
]);
|
|
160
134
|
};
|
package/functionUtils/index.ts
CHANGED
|
@@ -258,3 +258,28 @@ export const extractDataFromProperty = (property, data): any =>
|
|
|
258
258
|
);
|
|
259
259
|
|
|
260
260
|
export const then = (fn) => (promise) => promise.then(fn);
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Returns a replacer function for JSON.stringify that handles circular references,
|
|
264
|
+
* functions, and React context objects
|
|
265
|
+
* @returns {Function} A replacer function that detects and handles circular references,
|
|
266
|
+
* functions, and React context objects
|
|
267
|
+
*/
|
|
268
|
+
export const getJsonReplacer = () => {
|
|
269
|
+
return (_key, value) => {
|
|
270
|
+
if (typeof value === "function") {
|
|
271
|
+
return "[Function]";
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (
|
|
275
|
+
typeof value === "object" &&
|
|
276
|
+
value !== null &&
|
|
277
|
+
value.Provider &&
|
|
278
|
+
value.Consumer
|
|
279
|
+
) {
|
|
280
|
+
return "[ReactContext]";
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return value;
|
|
284
|
+
};
|
|
285
|
+
};
|
package/index.d.ts
CHANGED
|
@@ -105,18 +105,6 @@ declare type NavBarState = {
|
|
|
105
105
|
title: string;
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
declare type StorageValuesToAdd = Record<string, NamespaceValues>;
|
|
109
|
-
|
|
110
|
-
declare type StorageValuesToRemove = {
|
|
111
|
-
string?: string[];
|
|
112
|
-
};
|
|
113
|
-
|
|
114
|
-
declare type StorageOwnedValues = {
|
|
115
|
-
string?: string[];
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
declare type NamespaceValues = Record<string, string>;
|
|
119
|
-
|
|
120
108
|
declare type RefreshProps = {
|
|
121
109
|
forceRefresh?: boolean;
|
|
122
110
|
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import * as R from "ramda";
|
|
2
1
|
import { ViewStyle } from "react-native";
|
|
3
2
|
|
|
4
3
|
import { useMemo } from "react";
|
|
5
|
-
import { getUILanguage } from "
|
|
6
|
-
import { utilsLogger } from "
|
|
4
|
+
import { getUILanguage } from "@applicaster/zapp-react-native-utils/appUtils/localizationsHelper";
|
|
5
|
+
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
7
6
|
|
|
8
7
|
export {
|
|
9
8
|
getLocale,
|
|
@@ -11,7 +10,7 @@ export {
|
|
|
11
10
|
getCountryCode,
|
|
12
11
|
getLocalizations,
|
|
13
12
|
getUILanguage,
|
|
14
|
-
} from "
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/localizationsHelper";
|
|
15
14
|
|
|
16
15
|
const RTL_LOCALES = [
|
|
17
16
|
"ar", // Arabic
|
|
@@ -29,14 +28,16 @@ const RTL_LOCALES = [
|
|
|
29
28
|
"yi", // Yiddish
|
|
30
29
|
];
|
|
31
30
|
|
|
32
|
-
export function useLocalizedStrings({ localizations }) {
|
|
31
|
+
export function useLocalizedStrings({ localizations = {} }) {
|
|
33
32
|
const languageCode = getUILanguage();
|
|
34
33
|
|
|
35
34
|
// TODO: probably we can call getLocalizations here from localizationsHelper.js
|
|
36
35
|
const result = useMemo(
|
|
37
36
|
() =>
|
|
38
37
|
localizations?.[languageCode] ||
|
|
39
|
-
|
|
38
|
+
Object.values(localizations).find(
|
|
39
|
+
(value) => typeof value === "object" && value !== null
|
|
40
|
+
) ||
|
|
40
41
|
{},
|
|
41
42
|
[languageCode, localizations]
|
|
42
43
|
);
|
|
@@ -53,13 +54,7 @@ export function getIsRTL(): boolean {
|
|
|
53
54
|
return false;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const lowerCaseLanguageCode = languageCode.toLocaleLowerCase();
|
|
59
|
-
|
|
60
|
-
const isRTL = R.contains(lowerCaseLanguageCode, RTL_LOCALES);
|
|
61
|
-
|
|
62
|
-
return isRTL;
|
|
57
|
+
return RTL_LOCALES.includes(uiLanguage.split("-")[0].toLocaleLowerCase());
|
|
63
58
|
}
|
|
64
59
|
|
|
65
60
|
export function useIsRTL(): boolean {
|
|
@@ -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",
|
|
@@ -2555,6 +2547,12 @@ function getPlayerConfiguration({ platform }) {
|
|
|
2555
2547
|
multiple: false,
|
|
2556
2548
|
label_tooltip: "Choose the default aspect ratio for the artwork",
|
|
2557
2549
|
},
|
|
2550
|
+
{
|
|
2551
|
+
key: "audio_player_artwork_border_radius",
|
|
2552
|
+
label: "Audio Player Artwork Corner Radius",
|
|
2553
|
+
type: "number_input",
|
|
2554
|
+
initial_value: 16,
|
|
2555
|
+
},
|
|
2558
2556
|
]
|
|
2559
2557
|
)
|
|
2560
2558
|
);
|
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
|
};
|