@applicaster/zapp-react-native-utils 12.0.0-alpha.5553532911 → 12.0.0-alpha.5624518702

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.
Files changed (39) hide show
  1. package/analyticsUtils/AnalyticPlayerListener.ts +155 -0
  2. package/analyticsUtils/AnalyticsEvents/index.ts +6 -0
  3. package/analyticsUtils/AnalyticsEvents/searchEvents.ts +21 -0
  4. package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
  5. package/analyticsUtils/analyticsPlugins.ts +25 -0
  6. package/analyticsUtils/events.ts +6 -0
  7. package/analyticsUtils/index.tsx +6 -0
  8. package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
  9. package/appUtils/playerManager/DelayedSeekPlayerWrapper.tsx +239 -0
  10. package/appUtils/playerManager/index.ts +9 -27
  11. package/appUtils/playerManager/player.ts +12 -4
  12. package/appUtils/playerManager/playerNative.ts +7 -2
  13. package/appUtils/playerManager/usePlayerControllerSetup.tsx +23 -4
  14. package/cellUtils/__tests__/cellUtils.test.ts +9 -20
  15. package/cellUtils/index.ts +6 -12
  16. package/dateUtils/index.ts +11 -0
  17. package/headersUtils/index.ts +1 -0
  18. package/inflatedUrlUtils/index.ts +4 -4
  19. package/localizationUtils/__tests__/localizationUtils.test.ts +72 -53
  20. package/localizationUtils/index.ts +13 -22
  21. package/numberUtils/index.ts +4 -0
  22. package/package.json +2 -2
  23. package/reactHooks/cell-click/__tests__/index.test.js +5 -0
  24. package/reactHooks/cell-click/index.ts +2 -2
  25. package/reactHooks/feed/__tests__/useInflatedUrl.test.ts +18 -3
  26. package/reactHooks/feed/useInflatedUrl.ts +44 -15
  27. package/reactHooks/navigation/__mocks__/index.ts +13 -0
  28. package/reactHooks/navigation/__mocks__/useNavigation.ts +3 -0
  29. package/reactHooks/navigation/__tests__/index.test.tsx +11 -8
  30. package/reactHooks/navigation/index.ts +17 -65
  31. package/reactHooks/player/__tests__/useAutoSeek.test.tsx +8 -1
  32. package/reactHooks/player/useAutoSeek.tsx +23 -7
  33. package/reactHooks/player/useTapSeek.tsx +13 -8
  34. package/reactHooks/screen/useScreenContext.ts +4 -3
  35. package/screenState/index.ts +0 -8
  36. package/stringUtils/index.ts +5 -0
  37. package/testUtils/getByTestId.ts +14 -0
  38. package/testUtils/index.tsx +24 -22
  39. package/types.ts +4 -0
@@ -3,7 +3,6 @@ import * as R from "ramda";
3
3
  import { subscriber } from "../../functionUtils";
4
4
  import { utilsLogger, createLogger } from "../../logger";
5
5
  import { Player } from "./player";
6
- import { AnalyticsTracker } from "../../analyticsUtils/analyticsTracker";
7
6
  import {
8
7
  hasTizenAPIs,
9
8
  subscribeToDeviceNetworkChanges,
@@ -36,7 +35,10 @@ export interface PlayerLifecycleListener {
36
35
  }
37
36
 
38
37
  type PlayersMap = {
39
- [id: string]: { player: Player; isInViewport: boolean };
38
+ [id: string]: {
39
+ player: Player;
40
+ isInViewport: boolean;
41
+ };
40
42
  };
41
43
 
42
44
  export class PlayerManager {
@@ -45,7 +47,6 @@ export class PlayerManager {
45
47
  private playersMap: PlayersMap = {};
46
48
  private manager = subscriber();
47
49
  private castingReceiver: Player;
48
- private analyticsTracker: AnalyticsTracker;
49
50
  private lifecycleListeners: PlayerLifecycleListener[] = [];
50
51
 
51
52
  public static getInstance() {
@@ -56,7 +57,7 @@ export class PlayerManager {
56
57
  return PlayerManager.instance;
57
58
  }
58
59
 
59
- public getActivePlayerId = (): String | null => {
60
+ public getActivePlayerId = (): string | null => {
60
61
  return this.activePlayerId;
61
62
  };
62
63
 
@@ -101,7 +102,10 @@ export class PlayerManager {
101
102
  }
102
103
 
103
104
  private addPlayer = (id: string, player: Player) => {
104
- this.playersMap[id] = { player: player, isInViewport: false };
105
+ this.playersMap[id] = {
106
+ player: player,
107
+ isInViewport: false,
108
+ };
105
109
  };
106
110
 
107
111
  public isPlayerRegistered = (id: string) => !!this.playersMap[id];
@@ -246,28 +250,6 @@ export class PlayerManager {
246
250
  this.castingReceiver = null;
247
251
  }
248
252
 
249
- /**
250
- * Handles analytic events, generates a new analytics tracker and transmits events
251
- * Passes entry data, and playerState to the tracker for additional context
252
- * The end result is an event formatted and passed to AnalyticsBridge.postEvent
253
- * When we get the synthetic event we need to pull the data in the e object
254
- * e contains the return value from native
255
- */
256
- public handleAnalyticEvent(event, data = {}, entry: ZappEntry) {
257
- const playerState = this.getActivePlayer()?.getState();
258
-
259
- if (!this.analyticsTracker?.handleAnalyticEvent) {
260
- this.analyticsTracker = new AnalyticsTracker(entry);
261
- }
262
-
263
- this.analyticsTracker?.handleAnalyticEvent?.(
264
- event,
265
- data,
266
- entry,
267
- playerState
268
- );
269
- }
270
-
271
253
  /**
272
254
  * Method retrieves the instantiated player instance controller
273
255
  * Instance controller exposes methods like getContentDuration, getContentPosision
@@ -321,7 +321,7 @@ export class Player {
321
321
  * You should use dispatchPlayerEvent at PlayerContainer or call playerManager.invokeHandler directly
322
322
  * This allows you to use one method for everything.
323
323
  */
324
- onSeekStart = (event: QuickBrickPlayer.OnSeekStartEvent) => {
324
+ onPlayerSeekStart = (event: QuickBrickPlayer.OnSeekStartEvent) => {
325
325
  const { isLive, seekableDuration, currentTime, duration, seekTime } = event;
326
326
 
327
327
  this.setPlaybackState({ currentTime, duration, seekableDuration, isLive });
@@ -336,10 +336,11 @@ export class Player {
336
336
  });
337
337
  };
338
338
 
339
- onSeekComplete = (event: QuickBrickPlayer.OnSeekCompleteEvent) => {
339
+ onPlayerSeekComplete = (event: QuickBrickPlayer.OnSeekCompleteEvent) => {
340
340
  const { isLive, seekableDuration, currentTime, duration } = event;
341
341
 
342
342
  this.setPlaybackState({ currentTime, duration, seekableDuration, isLive });
343
+
343
344
  this.playerState.seekPosition = null;
344
345
 
345
346
  if (!isLive) {
@@ -646,8 +647,8 @@ export class Player {
646
647
  };
647
648
 
648
649
  public getListener = (): QuickBrickPlayer.SharedPlayerCallBacks => ({
649
- onPlayerSeekStart: this.onSeekStart,
650
- onPlayerSeekComplete: this.onSeekComplete,
650
+ onPlayerSeekStart: this.onPlayerSeekStart,
651
+ onPlayerSeekComplete: this.onPlayerSeekComplete,
651
652
  onVideoEnd: this.onVideoEnd,
652
653
  onError: this.onError,
653
654
  onLoad: this.onLoad,
@@ -727,4 +728,11 @@ export class Player {
727
728
  }
728
729
 
729
730
  public supportsNativeControls = (): boolean => false;
731
+ public supportNativeCast = (): boolean => false;
732
+
733
+ public isInDelayedSeek = (): boolean => false;
734
+ public enterDelayedSeek() {
735
+ }
736
+
737
+ public exitDelayedSeek() {}
730
738
  }
@@ -70,7 +70,7 @@ export class PlayerNative extends Player {
70
70
  currentPlayerComponent = (): ReactComponent<PlayerProps> =>
71
71
  this.playerComponent?.current;
72
72
 
73
- getState = () => this.currentPlayerComponent()?.["getState"]?.() ?? {};
73
+ getState = () => this.playerState;
74
74
 
75
75
  // TODO: Try to add module interface
76
76
  invokeNativeFunction = (funcName: string, ...params: any[]): boolean => {
@@ -111,7 +111,7 @@ export class PlayerNative extends Player {
111
111
  return;
112
112
  }
113
113
 
114
- const newPosition = R.clamp(0, position, this.playerState.seekableDuration);
114
+ const newPosition = R.clamp(0, this.playerState.seekableDuration, position);
115
115
 
116
116
  if (
117
117
  !this.invokeNativeFunction(
@@ -295,4 +295,9 @@ export class PlayerNative extends Player {
295
295
 
296
296
  supportsNativeControls = (): boolean =>
297
297
  toBooleanWithDefaultFalse(this.getConfig()?.["supports_native_controls"]);
298
+
299
+ supportNativeCast = (): boolean =>
300
+ toBooleanWithDefaultFalse(
301
+ this.playerPluginId === "quick-brick-player-brightcove"
302
+ );
298
303
  }
@@ -4,6 +4,9 @@ import { useEffect } from "react";
4
4
  import { playerManager } from "./index";
5
5
  import { useValidatePlayerConfig } from "../../playerUtils/useValidatePlayerConfig";
6
6
  import { PlayerRole } from "./conts";
7
+ import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
8
+ import { isTV } from "../../reactUtils";
9
+ import { DelayedSeekPlayerWrapper } from "./DelayedSeekPlayerWrapper";
7
10
 
8
11
  // TODO: Rename to ControllerType
9
12
  export const usePlayerControllerSetup = ({
@@ -34,17 +37,33 @@ export const usePlayerControllerSetup = ({
34
37
  useValidatePlayerConfig(config);
35
38
 
36
39
  useEffect(() => {
37
- const newPlayerController = new ControllerType({
40
+ const newConfig = isAppleTV()
41
+ ? { supports_native_controls: true, ...config }
42
+ : config;
43
+
44
+ const combinedProps = {
38
45
  player: ref,
39
46
  listener: props as any,
40
- config,
47
+ config: newConfig,
41
48
  playerId,
42
49
  entry,
43
50
  playerPluginId: pluginId,
44
51
  playerRole: PlayerRole.Primary,
45
- });
52
+ };
46
53
 
47
- setPlayerController(newPlayerController);
54
+ if (isTV()) {
55
+ const wrappedPlayerController = new ControllerType({
56
+ ...combinedProps,
57
+ playerRole: PlayerRole.Unspecified,
58
+ playerId: playerId + "." + "wrapped",
59
+ });
60
+
61
+ setPlayerController(
62
+ new DelayedSeekPlayerWrapper(combinedProps, wrappedPlayerController)
63
+ );
64
+ } else {
65
+ setPlayerController(new ControllerType(combinedProps));
66
+ }
48
67
  }, [playerId, entry?.id]);
49
68
 
50
69
  React.useEffect(() => {
@@ -24,7 +24,6 @@ import {
24
24
  EMPTY,
25
25
  FALLBACK,
26
26
  TRANSFORM,
27
- defaultColor,
28
27
  } from "./fixtures";
29
28
 
30
29
  describe("getKeyForLabel", () => {
@@ -395,9 +394,7 @@ describe("getColorFromData", () => {
395
394
  it("should return value directly if valid color", () => {
396
395
  const result = getColorFromData({
397
396
  data: entry,
398
- key: "background_color",
399
- getValue: getValue(componentStyle),
400
- defaultColor,
397
+ valueFromLayout: "#123456",
401
398
  });
402
399
 
403
400
  expect(result).toBe("#123456");
@@ -406,9 +403,7 @@ describe("getColorFromData", () => {
406
403
  it("should return valid rgba color name", () => {
407
404
  const result = getColorFromData({
408
405
  data: entry,
409
- key: "component_background_color",
410
- getValue: getValue(componentStyle),
411
- defaultColor,
406
+ valueFromLayout: "rgba(255, 255, 255, 0)",
412
407
  });
413
408
 
414
409
  expect(result).toBe("rgba(255, 255, 255, 0)");
@@ -417,33 +412,27 @@ describe("getColorFromData", () => {
417
412
  it("should return path value if path value is set and is valid color", () => {
418
413
  const result = getColorFromData({
419
414
  data: entry,
420
- key: VAL.colorKeyPath,
421
- getValue: getValue(componentStyle),
422
- defaultColor,
415
+ valueFromLayout: "background_color",
423
416
  });
424
417
 
425
418
  expect(result).toBe("#123456");
426
419
  });
427
420
 
428
- it("should return defaultColor if key value and path value are invalid", () => {
421
+ it("should return path value if path value is set, nested and is valid color", () => {
429
422
  const result = getColorFromData({
430
423
  data: entry,
431
- key: VAL.invalidColorKey,
432
- getValue: getValue(componentStyle),
433
- defaultColor,
424
+ valueFromLayout: "extensions.background_color",
434
425
  });
435
426
 
436
- expect(result).toBe(defaultColor);
427
+ expect(result).toBe("#123456");
437
428
  });
438
429
 
439
- it("should return defaultColor if path does not exist", () => {
430
+ it("should return valueFromLayout if path does not exist", () => {
440
431
  const result = getColorFromData({
441
432
  data: entry,
442
- key: VAL.invalidColorKeyPath,
443
- getValue: getValue(componentStyle),
444
- defaultColor,
433
+ valueFromLayout: "invalid_color",
445
434
  });
446
435
 
447
- expect(result).toBe(defaultColor);
436
+ expect(result).toBe("invalid_color");
448
437
  });
449
438
  });
@@ -447,30 +447,24 @@ export const toResizeMode = (
447
447
 
448
448
  type GetColorFromData = {
449
449
  data: Record<string, any>;
450
- key: string;
451
- getValue: Function;
452
- defaultColor: string;
450
+ valueFromLayout: string;
453
451
  };
454
452
 
455
453
  export const getColorFromData = ({
456
454
  data,
457
- key,
458
- getValue,
459
- defaultColor,
455
+ valueFromLayout,
460
456
  }: GetColorFromData): string => {
461
- const value = getValue(key);
462
-
463
457
  // Temporary hack to fix color validation when alpha is floating point number
464
458
  // https://github.com/dreamyguy/validate-color/issues/44
465
- if (validateColor(value.replace(".00", ""))) {
466
- return value;
459
+ if (validateColor(valueFromLayout.replace(".00", ""))) {
460
+ return valueFromLayout;
467
461
  }
468
462
 
469
- const pathValue = R.path(value.split("."), data);
463
+ const pathValue = R.path(valueFromLayout.split("."), data);
470
464
 
471
465
  if (pathValue && validateColor(pathValue)) {
472
466
  return pathValue;
473
467
  }
474
468
 
475
- return defaultColor;
469
+ return valueFromLayout;
476
470
  };
@@ -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 };
@@ -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
  };
@@ -1,4 +1,4 @@
1
- import { last, head, isNil, includes, all, pathOr } from "ramda";
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 isEnoughDataToInflateString = (context, string): boolean => {
16
+ export const getMissingValues = (context, string): string[] => {
17
17
  if (!includes("{{", string)) {
18
- return true;
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 all(hasValue(context), paths);
24
+ return paths.filter((path) => !hasValue(context)(path));
25
25
  };
26
26
 
27
27
  export const isNonInflatedUrl = (url: string): boolean =>
@@ -1,59 +1,59 @@
1
- import * as ReactNative from "react-native";
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 SettingsManager = {
3
+ const settingsManagerMock = {
18
4
  getConstants: jest.fn(() => ({
19
- settings: { AppleLanguages: mocked_locale },
5
+ settings: { AppleLanguages: ["en-US"] },
20
6
  })),
21
7
  };
22
8
 
23
- const QuickBrickCommunicationModule = {
9
+ const qbCommunicationModuleMock = {
24
10
  languageLocale: "en",
25
11
  countryLocale: "US",
12
+ uiLanguage: "en-US",
26
13
  };
27
14
 
28
- ReactNative.NativeModules.SettingsManager = SettingsManager;
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
- mocked_state.remoteConfigurations.localizations = {
40
- he: "http://url.com",
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
- mocked_state.remoteConfigurations.localizations = {
52
- en: "http://url.com",
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
- mocked_state.remoteConfigurations.localizations = {
67
- he: "http://url.com",
68
- en: "http://url.com",
69
- };
66
+ jest.resetModules();
67
+
68
+ const RN = require("react-native");
70
69
 
71
- mocked_locale = ["en-US"];
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
- mocked_state.remoteConfigurations.localizations = {
82
- he: "http://url.com",
83
- en: "http://url.com",
84
- };
85
+ jest.resetModules();
86
+ const RN = require("react-native");
85
87
 
86
- mocked_locale = ["he-HE"];
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
- mocked_state.remoteConfigurations.localizations = {
97
- en: "http://url.com",
98
- he: "http://url.com",
99
- };
103
+ jest.resetModules();
104
+
105
+ const RN = require("react-native");
100
106
 
101
- mocked_locale = ["es-SP", "he-HE"];
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
- mocked_state.remoteConfigurations.localizations = {
114
- en: "http://url.com",
115
- he: "http://url.com",
116
- };
124
+ jest.resetModules();
125
+
126
+ const RN = require("react-native");
117
127
 
118
- mocked_locale = ["fr-FR"];
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
- mocked_state.remoteConfigurations.localizations = {
129
- he: "http://url.com",
130
- en: "http://url.com",
131
- };
143
+ jest.resetModules();
144
+
145
+ const RN = require("react-native");
132
146
 
133
- mocked_locale = ["fr-FR"];
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 getLocaleToUse(languageCodes, localizations) {
49
- const matchingLanguages = languageCodes.filter(
50
- R.contains(R.__, localizations)
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
- if (matchingLanguages?.length) {
54
- return R.head(matchingLanguages);
53
+ return false;
55
54
  }
56
55
 
57
- return R.head(localizations);
58
- }
56
+ const [languageCode] = uiLanguage.split("-");
59
57
 
60
- export function getIsRTLFromLocalizations(localizations): boolean {
61
- const deviceLocales = getDeviceLocales() || [];
62
- const localeToUse = getLocaleToUse(deviceLocales, R.keys(localizations));
58
+ const lowerCaseLanguageCode = languageCode.toLocaleLowerCase();
63
59
 
64
- return R.contains(localeToUse, RTL_LOCALES);
65
- }
60
+ const isRTL = R.contains(lowerCaseLanguageCode, RTL_LOCALES);
66
61
 
67
- const remoteConfigLocalizationSelector = R.path([
68
- "remoteConfigurations",
69
- "localizations",
70
- ]);
62
+ return isRTL;
63
+ }
71
64
 
72
65
  export function useIsRTL(): boolean {
73
- const localizations = useSelector(remoteConfigLocalizationSelector);
74
-
75
- return getIsRTLFromLocalizations(localizations);
66
+ return getIsRTL();
76
67
  }
77
68
 
78
69
  export const applyRTLStylesIfNeeded = (
@@ -75,3 +75,7 @@ export const isLikeNumber = (value: any): boolean => {
75
75
 
76
76
  export const isZero = (value: unknown): boolean =>
77
77
  Object.is(value, -0) || Object.is(value, 0);
78
+
79
+ export const isMinusZero = (value: number) => {
80
+ return 1 / value === -Infinity;
81
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "12.0.0-alpha.5553532911",
3
+ "version": "12.0.0-alpha.5624518702",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "homepage": "https://github.com/applicaster/quickbrick#readme",
30
30
  "dependencies": {
31
- "@applicaster/applicaster-types": "12.0.0-alpha.5553532911",
31
+ "@applicaster/applicaster-types": "12.0.0-alpha.5624518702",
32
32
  "buffer": "^5.2.1",
33
33
  "camelize": "^1.0.0",
34
34
  "create-react-context": "^0.2.3",
@@ -6,6 +6,7 @@ import { waitFor } from "@testing-library/react-native";
6
6
  const navigator = {
7
7
  getPathname: () => "pathnameMock",
8
8
  push: jest.fn(),
9
+ data: {},
9
10
  };
10
11
 
11
12
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
@@ -28,6 +29,10 @@ jest.mock("@applicaster/zapp-react-native-ui-components/Contexts", () => ({
28
29
  },
29
30
  }));
30
31
 
32
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
33
+ useScreenContext: jest.fn(() => navigator.data),
34
+ }));
35
+
31
36
  const { useCellClick } = require("../");
32
37
 
33
38
  const mockProps = {