@applicaster/zapp-react-native-utils 12.0.0-alpha.3977160850 → 12.0.0-alpha.4023252383
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/analyticsUtils/AnalyticPlayerListener.ts +141 -0
- package/analyticsUtils/AnalyticsEvents/index.ts +13 -0
- package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
- package/analyticsUtils/AnalyticsEvents/sendShareEvent.ts +21 -0
- package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
- package/analyticsUtils/analyticsPlugins.ts +25 -0
- package/analyticsUtils/events.ts +12 -0
- package/analyticsUtils/index.tsx +12 -0
- package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
- package/appUtils/HooksManager/index.js +3 -1
- package/appUtils/accessibilityManager/const.ts +50 -0
- package/appUtils/accessibilityManager/hooks.ts +40 -0
- package/appUtils/accessibilityManager/index.ts +166 -0
- package/appUtils/accessibilityManager/logger.ts +5 -0
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +2 -3
- package/appUtils/focusManager/__tests__/focusManager.test.js +4 -24
- package/appUtils/focusManager/__tests__/index.test.ts +2 -3
- package/appUtils/focusManager/index.ts +76 -57
- package/appUtils/focusManager/treeDataStructure/Utils/index.js +75 -35
- package/appUtils/focusManager/utils/index.ts +100 -0
- package/appUtils/focusManagerAux/index.ts +76 -0
- package/appUtils/focusManagerAux/utils/index.ts +100 -0
- package/appUtils/index.js +2 -0
- package/appUtils/keyCodes/keys.web.js +8 -0
- package/appUtils/keyCodes/keysByPlatform.js +11 -1
- package/appUtils/platform/const.ts +25 -0
- package/appUtils/platform/index.ts +3 -0
- package/appUtils/platform/platformUtils.ts +217 -0
- package/appUtils/playerManager/conts.ts +6 -0
- package/appUtils/playerManager/index.ts +20 -32
- package/appUtils/playerManager/nativePlayerManager.ts +12 -0
- package/appUtils/playerManager/player.ts +44 -3
- package/appUtils/playerManager/playerFactory.ts +13 -11
- package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +57 -0
- package/appUtils/playerManager/playerNative.ts +15 -15
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +8 -2
- package/appUtils/playerManager/usePlayerState.tsx +19 -34
- package/arrayUtils/__tests__/isFilledArray.test.ts +63 -0
- package/arrayUtils/index.ts +5 -0
- package/booleanUtils/index.ts +4 -4
- package/cellUtils/__tests__/cellUtils.test.ts +9 -20
- package/cellUtils/index.ts +48 -19
- package/dateUtils/index.ts +11 -0
- package/functionUtils/index.ts +38 -0
- package/headersUtils/index.ts +1 -0
- package/index.d.ts +15 -0
- package/inflatedUrlUtils/index.ts +4 -4
- package/keyboardState/index.ts +0 -0
- package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
- package/localizationUtils/index.ts +13 -22
- package/manifestUtils/defaultManifestConfigurations/generalContent.js +6 -0
- package/manifestUtils/defaultManifestConfigurations/player.js +2 -1
- package/manifestUtils/index.js +5 -1
- package/manifestUtils/secondaryImage/index.js +18 -15
- package/navigationUtils/index.ts +56 -4
- package/numberUtils/__tests__/isLikeNumber.test.ts +18 -0
- package/numberUtils/__tests__/toNumber.test.ts +2 -2
- package/numberUtils/index.ts +9 -18
- package/package.json +2 -2
- package/playerUtils/configurationGenerator.ts +3 -1
- package/playerUtils/imaScriptDom.ts +59 -0
- package/pluginUtils/index.ts +9 -0
- package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +2 -0
- package/reactHooks/autoscrolling/__tests__/{useTrackedView.test.ts → useTrackedView.test.tsx} +18 -1
- package/reactHooks/cell-click/__tests__/index.test.js +10 -1
- package/reactHooks/cell-click/index.ts +12 -12
- package/reactHooks/debugging/__tests__/index.test.js +81 -11
- package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +30 -70
- package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +6 -2
- package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
- package/reactHooks/feed/useBuildPipesUrl.ts +7 -10
- package/reactHooks/feed/useFeedRefresh.tsx +9 -7
- package/reactHooks/feed/useInflatedUrl.ts +44 -15
- package/reactHooks/layout/__tests__/{index.test.js → index.test.tsx} +44 -29
- package/reactHooks/layout/getDeviceInfo/index.ts +4 -2
- package/reactHooks/layout/types/index.ts +2 -0
- package/reactHooks/layout/useDimensions/useDimensions.ts +15 -7
- package/reactHooks/navigation/__mocks__/index.ts +15 -0
- package/reactHooks/navigation/__mocks__/useNavigation.ts +7 -0
- package/reactHooks/navigation/__tests__/index.test.tsx +26 -8
- package/reactHooks/navigation/index.ts +64 -21
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +3 -1
- package/reactHooks/resolvers/useCellResolver.ts +5 -1
- package/reactHooks/screen/__mocks__/useScreenContext.ts +3 -1
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +21 -23
- package/reactHooks/screen/index.ts +2 -0
- package/reactHooks/screen/useScreenBackgroundColor.ts +23 -0
- package/reactHooks/screen/useScreenContext.ts +4 -4
- package/reactHooks/screen/useScreenData.ts +1 -1
- package/reactHooks/screen/useTargetScreenData.ts +7 -0
- package/reactHooks/useListenEventBusEvent.ts +1 -4
- package/reactHooks/videoModal/index.ts +0 -3
- package/reactUtils/index.ts +104 -0
- package/screenState/index.ts +0 -8
- package/stringUtils/index.ts +5 -0
- package/testUtils/getByTestId.ts +14 -0
- package/testUtils/index.tsx +38 -23
- package/types.ts +4 -0
- package/appUtils/focusManager/FocusableEvents.ts +0 -8
- package/appUtils/focusManager/treeDataStructure/Utils/__tests__/Utils_android.test.js +0 -1094
- package/appUtils/focusManager/treeDataStructure/Utils/index.android.js +0 -261
package/cellUtils/index.ts
CHANGED
|
@@ -31,13 +31,12 @@ export const getKeyForLabel = (dataKey, customKey) => {
|
|
|
31
31
|
* This method will return true if the argument passed to it is either empty or nil
|
|
32
32
|
* The method prevents zero from being evaluated as falsey in an || condition
|
|
33
33
|
* i.e. - NaN, null, {}, "", [], should all return true
|
|
34
|
-
* @param {*} argument - argument passed to it could be any type
|
|
35
34
|
* @returns {Boolean} returns true if empty or nil
|
|
35
|
+
* @param value
|
|
36
36
|
*/
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
);
|
|
37
|
+
|
|
38
|
+
export const isEmptyOrNil = (value: any): boolean =>
|
|
39
|
+
Number.isNaN(value) || value == null || R.isEmpty(value);
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
42
|
* This method is used to find the appropriate label for any given text field.
|
|
@@ -182,8 +181,8 @@ export const getHeight = (width, aspectRatio) => {
|
|
|
182
181
|
* @returns {string} duration
|
|
183
182
|
*/
|
|
184
183
|
|
|
185
|
-
export const getDurationInMinutes = (seconds
|
|
186
|
-
if (seconds
|
|
184
|
+
export const getDurationInMinutes = (seconds?: number): string => {
|
|
185
|
+
if (!seconds) return "00:00";
|
|
187
186
|
const minutes = Math.floor(Number(seconds) / 60);
|
|
188
187
|
const secondsReminder = Math.floor(Number(seconds)) % 60;
|
|
189
188
|
const pad = (num: number): string => `${num < 10 ? "0" : ""}${num}`;
|
|
@@ -320,6 +319,7 @@ export const ifElseFocusedSelected = (
|
|
|
320
319
|
* @param {Object} stylesObj styles object with keys from zapp { button_icon_width: "10" }
|
|
321
320
|
* @returns {*} value, returns any type that can be used as styles
|
|
322
321
|
*/
|
|
322
|
+
|
|
323
323
|
export const getValue = (stylesObj) => (key) => {
|
|
324
324
|
return R.propOr(null, key, stylesObj);
|
|
325
325
|
};
|
|
@@ -447,28 +447,57 @@ export const toResizeMode = (
|
|
|
447
447
|
|
|
448
448
|
type GetColorFromData = {
|
|
449
449
|
data: Record<string, any>;
|
|
450
|
-
|
|
451
|
-
getValue: Function;
|
|
452
|
-
defaultColor: string;
|
|
450
|
+
valueFromLayout: string;
|
|
453
451
|
};
|
|
454
452
|
|
|
455
453
|
export const getColorFromData = ({
|
|
456
454
|
data,
|
|
457
|
-
|
|
458
|
-
getValue,
|
|
459
|
-
defaultColor,
|
|
455
|
+
valueFromLayout,
|
|
460
456
|
}: GetColorFromData): string => {
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
if (validateColor(
|
|
464
|
-
return
|
|
457
|
+
// Temporary hack to fix color validation when alpha is floating point number
|
|
458
|
+
// https://github.com/dreamyguy/validate-color/issues/44
|
|
459
|
+
if (validateColor(valueFromLayout.replace(".00", ""))) {
|
|
460
|
+
return valueFromLayout;
|
|
465
461
|
}
|
|
466
462
|
|
|
467
|
-
const pathValue = R.path(
|
|
463
|
+
const pathValue = R.path(valueFromLayout.split("."), data);
|
|
468
464
|
|
|
469
465
|
if (pathValue && validateColor(pathValue)) {
|
|
470
466
|
return pathValue;
|
|
471
467
|
}
|
|
472
468
|
|
|
473
|
-
return
|
|
469
|
+
return valueFromLayout;
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
export const getImageStyles = ({
|
|
473
|
+
image,
|
|
474
|
+
value,
|
|
475
|
+
}: {
|
|
476
|
+
image: any;
|
|
477
|
+
value: any;
|
|
478
|
+
}) => {
|
|
479
|
+
return {
|
|
480
|
+
width: image.imageContentWidth,
|
|
481
|
+
height: image.imageContentHeight,
|
|
482
|
+
aspectRatio: image.aspectRatio,
|
|
483
|
+
borderRadius: toNumberWithDefaultZero(value("image_corner_radius")),
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
|
|
487
|
+
export const getImageContainerPaddingStyles = ({ value }: { value: any }) => {
|
|
488
|
+
return {
|
|
489
|
+
paddingTop: value("image_padding_top"),
|
|
490
|
+
paddingBottom: value("image_padding_bottom"),
|
|
491
|
+
paddingLeft: value("image_padding_left"),
|
|
492
|
+
paddingRight: value("image_padding_right"),
|
|
493
|
+
};
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
export const getImageContainerMarginStyles = ({ value }: { value: any }) => {
|
|
497
|
+
return {
|
|
498
|
+
marginTop: value("image_margin_top"),
|
|
499
|
+
marginBottom: value("image_margin_bottom"),
|
|
500
|
+
marginLeft: value("image_margin_left"),
|
|
501
|
+
marginRight: value("image_margin_right"),
|
|
502
|
+
};
|
|
474
503
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import dayjs from "dayjs";
|
|
2
|
+
import utc from "dayjs/plugin/utc";
|
|
3
|
+
import timezone from "dayjs/plugin/timezone";
|
|
4
|
+
import isoWeek from "dayjs/plugin/isoWeek";
|
|
5
|
+
|
|
6
|
+
// Extend dayjs with plugins
|
|
7
|
+
dayjs.extend(utc);
|
|
8
|
+
dayjs.extend(timezone);
|
|
9
|
+
dayjs.extend(isoWeek);
|
|
10
|
+
|
|
11
|
+
export { dayjs };
|
package/functionUtils/index.ts
CHANGED
|
@@ -1,4 +1,42 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
|
+
import { useRef } from "react";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param callback - The function to throttle.
|
|
7
|
+
* @param delay - The delay in milliseconds.
|
|
8
|
+
* @returns A throttled version of the callback.
|
|
9
|
+
*/
|
|
10
|
+
export const useThrottle = (callback: () => void, delay: number) => {
|
|
11
|
+
const lastCallRef = useRef<number>(0);
|
|
12
|
+
const timeoutRef = useRef<any | null>(null);
|
|
13
|
+
|
|
14
|
+
const throttledFunction = () => {
|
|
15
|
+
const now = Date.now();
|
|
16
|
+
|
|
17
|
+
if (now - lastCallRef.current >= delay) {
|
|
18
|
+
callback();
|
|
19
|
+
lastCallRef.current = now;
|
|
20
|
+
} else if (!timeoutRef.current) {
|
|
21
|
+
const remainingTime = delay - (now - lastCallRef.current);
|
|
22
|
+
|
|
23
|
+
timeoutRef.current = setTimeout(() => {
|
|
24
|
+
callback();
|
|
25
|
+
lastCallRef.current = Date.now();
|
|
26
|
+
timeoutRef.current = null;
|
|
27
|
+
}, remainingTime);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const cancel = () => {
|
|
32
|
+
if (timeoutRef.current) {
|
|
33
|
+
clearTimeout(timeoutRef.current);
|
|
34
|
+
timeoutRef.current = null;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return { throttledFunction, cancel };
|
|
39
|
+
};
|
|
2
40
|
|
|
3
41
|
/**
|
|
4
42
|
* standard debounce function.
|
package/headersUtils/index.ts
CHANGED
|
@@ -28,5 +28,6 @@ export const getAppDataHeaders = (screenId: string) => {
|
|
|
28
28
|
"x-applicaster-signed-device-info-token": appData.signedDeviceInfoToken,
|
|
29
29
|
"x-applicaster-device-make": appData.deviceMake,
|
|
30
30
|
"x-applicaster-device-model": appData.deviceModel,
|
|
31
|
+
"x-applicaster-uuid": appData?.uuid,
|
|
31
32
|
};
|
|
32
33
|
};
|
package/index.d.ts
CHANGED
|
@@ -143,3 +143,18 @@ declare type BuilderData = {
|
|
|
143
143
|
river?: ZappRiver;
|
|
144
144
|
method?: string;
|
|
145
145
|
};
|
|
146
|
+
|
|
147
|
+
declare type AccessibilityState = {
|
|
148
|
+
screenReaderEnabled: boolean;
|
|
149
|
+
reduceMotionEnabled: boolean;
|
|
150
|
+
boldTextEnabled: boolean;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
declare type AccessibilityProps = {
|
|
154
|
+
accessibilityLabel?: string;
|
|
155
|
+
accessibilityHint?: string;
|
|
156
|
+
"aria-label"?: string;
|
|
157
|
+
"aria-description"?: string;
|
|
158
|
+
accessibilityRole?: string;
|
|
159
|
+
"aria-role"?: string;
|
|
160
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { last, head, isNil, includes,
|
|
1
|
+
import { last, head, isNil, includes, pathOr } from "ramda";
|
|
2
2
|
|
|
3
3
|
const stripBrackets = (path) => {
|
|
4
4
|
const withoutPrepened = last(path.split("{{"));
|
|
@@ -13,15 +13,15 @@ const hasValue = (context) => (path) => {
|
|
|
13
13
|
return !isNil(value);
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
export const
|
|
16
|
+
export const getMissingValues = (context, string): string[] => {
|
|
17
17
|
if (!includes("{{", string)) {
|
|
18
|
-
return
|
|
18
|
+
return [];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const SEARCH_REGEX = new RegExp(/{{.*?}}/g);
|
|
22
22
|
const paths = string.toString().match(SEARCH_REGEX);
|
|
23
23
|
|
|
24
|
-
return
|
|
24
|
+
return paths.filter((path) => !hasValue(context)(path));
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
export const isNonInflatedUrl = (url: string): boolean =>
|
|
File without changes
|
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const mocked_state = {
|
|
4
|
-
remoteConfigurations: { localizations: {} },
|
|
5
|
-
appData: {
|
|
6
|
-
languageCode: "en",
|
|
7
|
-
countryCode: "US",
|
|
8
|
-
},
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
let mocked_locale = ["en-US"];
|
|
12
|
-
|
|
13
|
-
jest.doMock("react-redux", () => ({
|
|
14
|
-
useSelector: jest.fn((fn) => fn(mocked_state)),
|
|
15
|
-
}));
|
|
1
|
+
import { NativeModules } from "react-native";
|
|
16
2
|
|
|
17
|
-
const
|
|
3
|
+
const settingsManagerMock = {
|
|
18
4
|
getConstants: jest.fn(() => ({
|
|
19
|
-
settings: { AppleLanguages:
|
|
5
|
+
settings: { AppleLanguages: ["en-US"] },
|
|
20
6
|
})),
|
|
21
7
|
};
|
|
22
8
|
|
|
23
|
-
const
|
|
9
|
+
const qbCommunicationModuleMock = {
|
|
24
10
|
languageLocale: "en",
|
|
25
11
|
countryLocale: "US",
|
|
12
|
+
uiLanguage: "en-US",
|
|
26
13
|
};
|
|
27
14
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ReactNative.NativeModules.QuickBrickCommunicationModule =
|
|
31
|
-
QuickBrickCommunicationModule;
|
|
32
|
-
|
|
33
|
-
const { useIsRTL } = require("../index");
|
|
15
|
+
NativeModules.SettingsManager = settingsManagerMock;
|
|
16
|
+
NativeModules.QuickBrickCommunicationModule = qbCommunicationModuleMock;
|
|
34
17
|
|
|
35
18
|
describe("localizationUtils", () => {
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
jest.resetModules();
|
|
21
|
+
});
|
|
22
|
+
|
|
36
23
|
describe("when the app has a single locale", () => {
|
|
37
24
|
describe("when the app has only a RTL language as locale", () => {
|
|
38
25
|
beforeEach(() => {
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
jest.resetModules();
|
|
27
|
+
const RN = require("react-native");
|
|
28
|
+
|
|
29
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
30
|
+
languageLocale: "he",
|
|
31
|
+
countryLocale: "IL",
|
|
32
|
+
uiLanguage: "he-HE",
|
|
41
33
|
};
|
|
42
34
|
});
|
|
43
35
|
|
|
44
36
|
it("useIsRTL returns true", () => {
|
|
37
|
+
const { useIsRTL } = require("../index");
|
|
45
38
|
expect(useIsRTL()).toBe(true);
|
|
46
39
|
});
|
|
47
40
|
});
|
|
48
41
|
|
|
49
42
|
describe("when the app has only a LTR language as locale", () => {
|
|
50
43
|
beforeEach(() => {
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
jest.resetModules();
|
|
45
|
+
|
|
46
|
+
const RN = require("react-native");
|
|
47
|
+
|
|
48
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
49
|
+
languageLocale: "en",
|
|
50
|
+
countryLocale: "US",
|
|
51
|
+
uiLanguage: "en",
|
|
53
52
|
};
|
|
54
53
|
});
|
|
55
54
|
|
|
56
55
|
it("useIsRTL returns false", () => {
|
|
56
|
+
const { useIsRTL } = require("../index");
|
|
57
57
|
expect(useIsRTL()).toBe(false);
|
|
58
58
|
});
|
|
59
59
|
});
|
|
@@ -63,45 +63,56 @@ describe("localizationUtils", () => {
|
|
|
63
63
|
describe("when device locale is in the app's locales", () => {
|
|
64
64
|
describe("when device locale is LTR", () => {
|
|
65
65
|
beforeEach(() => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
};
|
|
66
|
+
jest.resetModules();
|
|
67
|
+
|
|
68
|
+
const RN = require("react-native");
|
|
70
69
|
|
|
71
|
-
|
|
70
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
71
|
+
languageLocale: "en",
|
|
72
|
+
countryLocale: "US",
|
|
73
|
+
uiLanguage: "en-US",
|
|
74
|
+
};
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
it("useIsRTL returns false", () => {
|
|
78
|
+
const { useIsRTL } = require("../index");
|
|
75
79
|
expect(useIsRTL()).toBe(false);
|
|
76
80
|
});
|
|
77
81
|
});
|
|
78
82
|
|
|
79
83
|
describe("when device locale is RTL", () => {
|
|
80
84
|
beforeEach(() => {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
en: "http://url.com",
|
|
84
|
-
};
|
|
85
|
+
jest.resetModules();
|
|
86
|
+
const RN = require("react-native");
|
|
85
87
|
|
|
86
|
-
|
|
88
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
89
|
+
languageLocale: "he",
|
|
90
|
+
countryLocale: "IL",
|
|
91
|
+
uiLanguage: "he",
|
|
92
|
+
};
|
|
87
93
|
});
|
|
88
94
|
|
|
89
95
|
it("useIsRTL returns true", () => {
|
|
96
|
+
const { useIsRTL } = require("../index");
|
|
90
97
|
expect(useIsRTL()).toBe(true);
|
|
91
98
|
});
|
|
92
99
|
});
|
|
93
100
|
|
|
94
101
|
describe("when a device has a secondary language in a supported language", () => {
|
|
95
102
|
beforeEach(() => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
};
|
|
103
|
+
jest.resetModules();
|
|
104
|
+
|
|
105
|
+
const RN = require("react-native");
|
|
100
106
|
|
|
101
|
-
|
|
107
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
108
|
+
languageLocale: "he",
|
|
109
|
+
countryLocale: "IL",
|
|
110
|
+
uiLanguage: "he",
|
|
111
|
+
};
|
|
102
112
|
});
|
|
103
113
|
|
|
104
114
|
it("useIsRTL returns true", () => {
|
|
115
|
+
const { useIsRTL } = require("../index");
|
|
105
116
|
expect(useIsRTL()).toBe(true);
|
|
106
117
|
});
|
|
107
118
|
});
|
|
@@ -110,30 +121,38 @@ describe("localizationUtils", () => {
|
|
|
110
121
|
describe("when device locale is not in the app's locales", () => {
|
|
111
122
|
describe("when first app locale is LTR", () => {
|
|
112
123
|
beforeEach(() => {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
};
|
|
124
|
+
jest.resetModules();
|
|
125
|
+
|
|
126
|
+
const RN = require("react-native");
|
|
117
127
|
|
|
118
|
-
|
|
128
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
129
|
+
languageLocale: "fr",
|
|
130
|
+
countryLocale: "FR",
|
|
131
|
+
uiLanguage: "fr-FR",
|
|
132
|
+
};
|
|
119
133
|
});
|
|
120
134
|
|
|
121
135
|
it("useIsRTL returns false", () => {
|
|
136
|
+
const { useIsRTL } = require("../index");
|
|
122
137
|
expect(useIsRTL()).toBe(false);
|
|
123
138
|
});
|
|
124
139
|
});
|
|
125
140
|
|
|
126
141
|
describe("when first app locale is RTL", () => {
|
|
127
142
|
beforeEach(() => {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
};
|
|
143
|
+
jest.resetModules();
|
|
144
|
+
|
|
145
|
+
const RN = require("react-native");
|
|
132
146
|
|
|
133
|
-
|
|
147
|
+
RN.NativeModules.QuickBrickCommunicationModule = {
|
|
148
|
+
languageLocale: "he",
|
|
149
|
+
countryLocale: "HE",
|
|
150
|
+
uiLanguage: "he",
|
|
151
|
+
};
|
|
134
152
|
});
|
|
135
153
|
|
|
136
154
|
it("useIsRTL returns true", () => {
|
|
155
|
+
const { useIsRTL } = require("../index");
|
|
137
156
|
expect(useIsRTL()).toBe(true);
|
|
138
157
|
});
|
|
139
158
|
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import * as R from "ramda";
|
|
2
2
|
import { ViewStyle } from "react-native";
|
|
3
|
-
import { useSelector } from "react-redux";
|
|
4
3
|
|
|
5
|
-
import { getDeviceLocales } from "./deviceLocales";
|
|
6
4
|
import { useMemo } from "react";
|
|
7
5
|
import { getUILanguage } from "../appUtils/localizationsHelper";
|
|
6
|
+
import { utilsLogger } from "../logger";
|
|
8
7
|
|
|
9
8
|
export {
|
|
10
9
|
getLocale,
|
|
@@ -45,34 +44,26 @@ export function useLocalizedStrings({ localizations }) {
|
|
|
45
44
|
return result;
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
function
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
)
|
|
47
|
+
export function getIsRTL(): boolean {
|
|
48
|
+
const uiLanguage = getUILanguage();
|
|
49
|
+
|
|
50
|
+
if (!uiLanguage) {
|
|
51
|
+
utilsLogger.error({ message: "getUILanguage returned null or undefined" });
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
return R.head(matchingLanguages);
|
|
53
|
+
return false;
|
|
55
54
|
}
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
}
|
|
56
|
+
const [languageCode] = uiLanguage.split("-");
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
const deviceLocales = getDeviceLocales() || [];
|
|
62
|
-
const localeToUse = getLocaleToUse(deviceLocales, R.keys(localizations));
|
|
58
|
+
const lowerCaseLanguageCode = languageCode.toLocaleLowerCase();
|
|
63
59
|
|
|
64
|
-
|
|
65
|
-
}
|
|
60
|
+
const isRTL = R.contains(lowerCaseLanguageCode, RTL_LOCALES);
|
|
66
61
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"localizations",
|
|
70
|
-
]);
|
|
62
|
+
return isRTL;
|
|
63
|
+
}
|
|
71
64
|
|
|
72
65
|
export function useIsRTL(): boolean {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
return getIsRTLFromLocalizations(localizations);
|
|
66
|
+
return getIsRTL();
|
|
76
67
|
}
|
|
77
68
|
|
|
78
69
|
export const applyRTLStylesIfNeeded = (
|
|
@@ -1663,7 +1663,8 @@ function getPlayerConfiguration({ platform }) {
|
|
|
1663
1663
|
platform.includes("lg") ||
|
|
1664
1664
|
platform.includes("samsung") ||
|
|
1665
1665
|
platform.includes("android_tv") ||
|
|
1666
|
-
platform.includes("amazon")
|
|
1666
|
+
platform.includes("amazon") ||
|
|
1667
|
+
platform.includes("vizio")
|
|
1667
1668
|
) {
|
|
1668
1669
|
styles.fields.push(
|
|
1669
1670
|
// Captions Menu
|
package/manifestUtils/index.js
CHANGED
|
@@ -22,7 +22,11 @@ const {
|
|
|
22
22
|
const { buttonKey } = require("./buttons");
|
|
23
23
|
const { tvBadges } = require("./tvBadges");
|
|
24
24
|
const { mobileProgressBar, tvProgressBar } = require("./progressBar");
|
|
25
|
-
|
|
25
|
+
|
|
26
|
+
const {
|
|
27
|
+
secondaryImage,
|
|
28
|
+
getUpdatedSecondaryImageKeys,
|
|
29
|
+
} = require("./secondaryImage");
|
|
26
30
|
|
|
27
31
|
module.exports = {
|
|
28
32
|
fontKey,
|
|
@@ -132,29 +132,32 @@ function secondaryImage({
|
|
|
132
132
|
|
|
133
133
|
const POSITION_OVER_IMAGE = toSnakeCase(position_over_image);
|
|
134
134
|
|
|
135
|
-
const getUpdatedSecondaryImageKeys = (secondaryImageManifest) =>
|
|
136
|
-
|
|
135
|
+
const getUpdatedSecondaryImageKeys = (secondaryImageManifest) =>
|
|
136
|
+
secondaryImageManifest.fields.reduce((acc, item) => {
|
|
137
|
+
const key = item.key;
|
|
137
138
|
|
|
138
|
-
|
|
139
|
+
const conditionalFields = (item.conditional_fields || []).map(
|
|
140
|
+
(field) => field.key
|
|
141
|
+
);
|
|
139
142
|
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
const updatedConditionalFields = conditionalFields.reduce((acc, field) => {
|
|
144
|
+
const updatedKey = field.replace("secondary_image_", "nested_image_");
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
...acc,
|
|
148
|
+
[updatedKey]: field,
|
|
149
|
+
};
|
|
150
|
+
}, {});
|
|
151
|
+
|
|
152
|
+
const updatedKey = key.replace("secondary_image_", "nested_image_");
|
|
142
153
|
|
|
143
154
|
return {
|
|
144
155
|
...acc,
|
|
145
|
-
|
|
156
|
+
...updatedConditionalFields,
|
|
157
|
+
[updatedKey]: key,
|
|
146
158
|
};
|
|
147
159
|
}, {});
|
|
148
160
|
|
|
149
|
-
const updatedKey = key.replace("secondary_image_", "nested_image_");
|
|
150
|
-
|
|
151
|
-
return {
|
|
152
|
-
...acc,
|
|
153
|
-
...updatedConditionalFields,
|
|
154
|
-
[updatedKey]: key,
|
|
155
|
-
};
|
|
156
|
-
}, {});
|
|
157
|
-
|
|
158
161
|
module.exports = {
|
|
159
162
|
secondaryImage,
|
|
160
163
|
getUpdatedSecondaryImageKeys,
|
package/navigationUtils/index.ts
CHANGED
|
@@ -114,7 +114,11 @@ export function getNavigationProps({
|
|
|
114
114
|
} | null {
|
|
115
115
|
const { activeRiver } = navigator;
|
|
116
116
|
const { navigations, id: selected, home } = activeRiver; // use useRiver hook instead
|
|
117
|
-
|
|
117
|
+
|
|
118
|
+
const navigation: ZappNavigation = R.find(
|
|
119
|
+
R.propEq("category", category),
|
|
120
|
+
navigations
|
|
121
|
+
);
|
|
118
122
|
|
|
119
123
|
if (!navigation) {
|
|
120
124
|
return null;
|
|
@@ -127,9 +131,9 @@ export function getNavigationProps({
|
|
|
127
131
|
title,
|
|
128
132
|
home,
|
|
129
133
|
styles,
|
|
130
|
-
assets,
|
|
131
|
-
nav_items,
|
|
132
|
-
rules,
|
|
134
|
+
assets: assets as ZappNavBarAssets,
|
|
135
|
+
nav_items: nav_items as any as NavBarItem[],
|
|
136
|
+
rules: rules as any as ZappNavBarRules,
|
|
133
137
|
};
|
|
134
138
|
}
|
|
135
139
|
|
|
@@ -588,3 +592,51 @@ export function isMenuDisabled(
|
|
|
588
592
|
export function routeIsPlayerScreen(currentRoute) {
|
|
589
593
|
return currentRoute?.includes("/playable");
|
|
590
594
|
}
|
|
595
|
+
|
|
596
|
+
export const getNavBarProps =
|
|
597
|
+
(currentRiver: ZappRiver, pathname: string, title: string) => () => {
|
|
598
|
+
const props = getNavigationPropsV2({
|
|
599
|
+
currentRiver,
|
|
600
|
+
title,
|
|
601
|
+
category: "nav_bar",
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
if (props) {
|
|
605
|
+
return {
|
|
606
|
+
...props,
|
|
607
|
+
id: pathname,
|
|
608
|
+
pathname: pathname,
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
return null;
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
export const findMenuPlugin = (
|
|
616
|
+
navigations: ZappNavigation[],
|
|
617
|
+
plugins
|
|
618
|
+
): QuickBrickPlugin => {
|
|
619
|
+
return resolveNavigationPlugin({
|
|
620
|
+
category: "menu",
|
|
621
|
+
navigations,
|
|
622
|
+
plugins,
|
|
623
|
+
}) as QuickBrickPlugin;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
export const shouldNavBarDisplayMenu = (currentRiver: ZappRiver, plugins) =>
|
|
627
|
+
findMenuPlugin(currentRiver.navigations, plugins)?.identifier ===
|
|
628
|
+
"quick_brick_side_menu" ||
|
|
629
|
+
currentRiver?.navigations.findIndex(
|
|
630
|
+
(nav) => nav.category === "nav_bar" && nav.general?.override_menu_target
|
|
631
|
+
) > -1;
|
|
632
|
+
|
|
633
|
+
export const getScreenId = (
|
|
634
|
+
screenData: LegacyNavigationScreenData,
|
|
635
|
+
fallbackRiver: ZappRiver
|
|
636
|
+
) => {
|
|
637
|
+
return screenData?.targetScreen
|
|
638
|
+
? screenData?.targetScreen?.id ?? fallbackRiver.id
|
|
639
|
+
: "screen_id" in screenData
|
|
640
|
+
? screenData.screen_id
|
|
641
|
+
: fallbackRiver.id;
|
|
642
|
+
};
|
|
@@ -7,12 +7,24 @@ describe("isLikeNumber", () => {
|
|
|
7
7
|
expect(isLikeNumber(value)).toBe(true);
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
+
it("value is a number", () => {
|
|
11
|
+
const value = 123.45;
|
|
12
|
+
|
|
13
|
+
expect(isLikeNumber(value)).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
|
|
10
16
|
it("value is a string as number", () => {
|
|
11
17
|
const value = "123";
|
|
12
18
|
|
|
13
19
|
expect(isLikeNumber(value)).toBe(true);
|
|
14
20
|
});
|
|
15
21
|
|
|
22
|
+
it("value is a string as number", () => {
|
|
23
|
+
const value = "123.45";
|
|
24
|
+
|
|
25
|
+
expect(isLikeNumber(value)).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
16
28
|
it("value is empty string", () => {
|
|
17
29
|
const value = "";
|
|
18
30
|
|
|
@@ -54,4 +66,10 @@ describe("isLikeNumber", () => {
|
|
|
54
66
|
|
|
55
67
|
expect(isLikeNumber(value)).toBe(false);
|
|
56
68
|
});
|
|
69
|
+
|
|
70
|
+
it("NaN is not a number", () => {
|
|
71
|
+
const value = NaN;
|
|
72
|
+
|
|
73
|
+
expect(isLikeNumber(value)).toBe(false);
|
|
74
|
+
});
|
|
57
75
|
});
|