@applicaster/zapp-react-native-utils 14.0.0-alpha.8419134002 → 14.0.0-alpha.9848043301

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 (46) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +1 -1
  2. package/analyticsUtils/AnalyticsEvents/helper.ts +0 -81
  3. package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +4 -14
  4. package/analyticsUtils/__tests__/analyticsUtils.test.js +0 -14
  5. package/analyticsUtils/events.ts +0 -8
  6. package/appUtils/accessibilityManager/index.ts +3 -3
  7. package/arrayUtils/__tests__/isFilledArray.test.ts +1 -1
  8. package/arrayUtils/index.ts +2 -7
  9. package/configurationUtils/__tests__/configurationUtils.test.js +31 -0
  10. package/configurationUtils/index.ts +34 -63
  11. package/focusManager/FocusManager.ts +6 -4
  12. package/manifestUtils/{_internals/index.js → _internals.js} +25 -2
  13. package/manifestUtils/createConfig.js +1 -4
  14. package/manifestUtils/defaultManifestConfigurations/player.js +200 -1239
  15. package/manifestUtils/progressBar/__tests__/mobileProgressBar.test.js +30 -0
  16. package/package.json +2 -2
  17. package/playerUtils/__tests__/configurationUtils.test.ts +65 -1
  18. package/playerUtils/configurationGenerator.ts +2572 -0
  19. package/playerUtils/configurationUtils.ts +44 -0
  20. package/playerUtils/index.ts +51 -2
  21. package/playerUtils/useValidatePlayerConfig.tsx +19 -22
  22. package/reactHooks/feed/useBatchLoading.ts +3 -3
  23. package/reactHooks/feed/usePipesCacheReset.ts +1 -1
  24. package/reactHooks/navigation/useIsScreenActive.ts +5 -9
  25. package/reactHooks/screen/useScreenContext.ts +1 -1
  26. package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +1 -2
  27. package/riverComponetsMeasurementProvider/index.tsx +1 -1
  28. package/services/js2native.ts +0 -1
  29. package/time/BackgroundTimer.ts +3 -5
  30. package/utils/index.ts +1 -16
  31. package/arrayUtils/__tests__/isEmptyArray.test.ts +0 -63
  32. package/audioPlayerUtils/__tests__/getArtworkImage.test.ts +0 -144
  33. package/audioPlayerUtils/__tests__/getBackgroundImage.test.ts +0 -72
  34. package/audioPlayerUtils/__tests__/getImageFromEntry.test.ts +0 -110
  35. package/audioPlayerUtils/assets/index.ts +0 -2
  36. package/audioPlayerUtils/index.ts +0 -242
  37. package/conf/player/__tests__/selectors.test.ts +0 -34
  38. package/conf/player/selectors.ts +0 -10
  39. package/configurationUtils/__tests__/getMediaItems.test.ts +0 -65
  40. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +0 -34
  41. package/manifestUtils/_internals/getDefaultConfiguration.js +0 -28
  42. package/playerUtils/__tests__/getPlayerActionButtons.test.ts +0 -54
  43. package/playerUtils/_internals/__tests__/utils.test.ts +0 -71
  44. package/playerUtils/_internals/index.ts +0 -1
  45. package/playerUtils/_internals/utils.ts +0 -31
  46. package/playerUtils/getPlayerActionButtons.ts +0 -17
@@ -1,6 +1,50 @@
1
1
  import { parseJsonIfNeeded } from "../functionUtils";
2
2
  import * as R from "ramda";
3
3
 
4
+ import { getNativeName as nativeNameUtil } from "../localizationUtils/localeLanguage";
5
+
6
+ export const modifyDefaultConfigValues = (
7
+ configuration: ConfigurationKeys,
8
+ mapping: ConfigValuesMapping
9
+ ): DefaultConfiguration => {
10
+ return R.mapObjIndexed((value, key) => {
11
+ const isFieldlessKey = key === "custom_configuration_fields";
12
+ const keyMapping = mapping[key];
13
+ const fields = value?.fields || value;
14
+
15
+ if (!keyMapping) {
16
+ return value;
17
+ }
18
+
19
+ const mapper = (obj) => {
20
+ if (obj.fields) {
21
+ return R.mergeLeft({ fields: R.map(mapper)(obj.fields) })(obj);
22
+ }
23
+
24
+ return R.mergeLeft(keyMapping?.[obj.key])(obj);
25
+ };
26
+
27
+ const mappedFields = R.map(mapper)(fields);
28
+
29
+ return R.unless(() => isFieldlessKey, R.objOf("fields"))(mappedFields);
30
+ })(configuration);
31
+ };
32
+
33
+ export function nativeName(localeCode) {
34
+ try {
35
+ const {
36
+ getNativeName,
37
+ } = require("@applicaster/zapp-react-native-utils/localizationUtils/localeLanguage");
38
+
39
+ return getNativeName(localeCode);
40
+ } catch (error) {
41
+ // eslint-disable-next-line no-console
42
+ console.warn("Could not load localeLanguage utils from QB", error);
43
+
44
+ return nativeNameUtil(localeCode);
45
+ }
46
+ }
47
+
4
48
  const setTrackType = R.curry(
5
49
  (
6
50
  type: QuickBrickPlayer.TrackType,
@@ -5,8 +5,7 @@ import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
5
5
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
6
6
 
7
7
  import { getBoolFromConfigValue } from "../configurationUtils";
8
-
9
- export { getPlayerActionButtons } from "./getPlayerActionButtons";
8
+ import { Dimensions } from "react-native";
10
9
 
11
10
  /**
12
11
  * Gets duration value from player manager, and from extensions
@@ -97,3 +96,53 @@ export const isAudioItem = (item: Option<ZappEntry>) => {
97
96
  export const isInlineTV = (screenData) => {
98
97
  return isTV() && isFilledArray(screenData?.ui_components);
99
98
  };
99
+
100
+ const isPercentage = (value: string | number): boolean => {
101
+ if (typeof value === "string") {
102
+ return value.includes("%");
103
+ }
104
+
105
+ return false;
106
+ };
107
+
108
+ const getPercentageOf = (percent: string, value: number) => {
109
+ const percentageValue = parseFloat(percent.replace("%", ""));
110
+
111
+ if (isNaN(percentageValue)) {
112
+ return value;
113
+ }
114
+
115
+ return (value * percentageValue) / 100;
116
+ };
117
+
118
+ type DimensionsT = {
119
+ width: number | string;
120
+ height: number | string | undefined;
121
+ aspectRatio?: number;
122
+ };
123
+
124
+ export const getTabletWidth = (
125
+ tablet_landscape_sidebar_width,
126
+ dimensions: DimensionsT
127
+ ) => {
128
+ const { width: SCREEN_WIDTH } = Dimensions.get("screen");
129
+
130
+ const { width } = dimensions;
131
+ let widthValue = Number(width);
132
+
133
+ if (isPercentage(width)) {
134
+ widthValue = getPercentageOf(width.toString(), SCREEN_WIDTH);
135
+ }
136
+
137
+ const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
138
+
139
+ if (tablet_landscape_sidebar_width?.includes("%")) {
140
+ return widthValue * (1 - sidebarWidth / 100);
141
+ }
142
+
143
+ if (Number.isNaN(sidebarWidth)) {
144
+ return widthValue * 0.65;
145
+ }
146
+
147
+ return widthValue - sidebarWidth;
148
+ };
@@ -1,37 +1,34 @@
1
1
  import * as React from "react";
2
+ import * as R from "ramda";
3
+ import generateConfiguration from "./configurationGenerator";
2
4
  import { createLogger } from "../logger";
3
- import { createConfig } from "../manifestUtils/createConfig";
4
- import { getAllFields, getConfigurationDiff } from "./_internals";
5
5
 
6
6
  export const logger = createLogger({
7
7
  category: "useValidatePlayerConfig",
8
8
  subsystem: "useValidatePlayerConfig",
9
9
  });
10
10
 
11
- /** Default Player Configuration */
12
- const {
13
- styles,
14
- general,
15
- localizations,
16
- custom_configuration_fields,
17
- }: DefaultConfiguration = createConfig(
18
- () => {
19
- return {};
20
- },
21
- { extend: "player" }
22
- ) as any;
23
-
24
- const QBPlayerConfigFields = getAllFields(
25
- styles,
26
- general,
27
- localizations,
28
- custom_configuration_fields
29
- );
11
+ const configuration = generateConfiguration();
30
12
 
31
13
  export const useValidatePlayerConfig = (config) => {
32
14
  React.useEffect(() => {
33
15
  try {
34
- const diff = getConfigurationDiff(QBPlayerConfigFields, config);
16
+ const QBPlayerConfigFields = R.compose(
17
+ R.map(R.prop("key")),
18
+ R.flatten,
19
+ R.map(R.compose(R.when(R.propEq("group", true), R.prop("fields")))),
20
+ R.concat
21
+ )(
22
+ configuration.styles.fields,
23
+ configuration.general.fields,
24
+ configuration.localizations.fields,
25
+ configuration.custom_configuration_fields
26
+ );
27
+
28
+ const diff = R.compose(
29
+ R.difference(QBPlayerConfigFields),
30
+ R.keys
31
+ )(config);
35
32
 
36
33
  logger.log_info(
37
34
  "Missing following configuration properties. Some elements of the player may not work correctly. Check QuickBrickPlayerPlugin for the configuration reference https://github.com/applicaster/QuickBrick/tree/main/plugins/zapp-react-native-default-player/manifests",
@@ -10,7 +10,7 @@ import {
10
10
  getSearchContext,
11
11
  } from "@applicaster/zapp-react-native-utils/reactHooks";
12
12
  import { isGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
13
- import { useScreenContext } from "../screen";
13
+ import { useScreenContext } from "../screen/useScreenContext";
14
14
 
15
15
  type Options = {
16
16
  initialBatchSize?: number;
@@ -144,11 +144,11 @@ export const useBatchLoading = (
144
144
  }
145
145
  }
146
146
  });
147
- }, [feedUrls, feeds]);
147
+ }, [feedUrls]);
148
148
 
149
149
  React.useEffect(() => {
150
150
  runBatchLoading();
151
- }, [runBatchLoading]); // Adding runBatchLoading as a dependency to ensure that it reloads feeds when clearPipesData is called
151
+ }, []);
152
152
 
153
153
  React.useEffect(() => {
154
154
  // check if all feeds are ready and set hasEverBeenReady to true
@@ -5,7 +5,7 @@ import { getDatasourceUrl } from "@applicaster/zapp-react-native-ui-components/D
5
5
  import { usePipesContexts } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/usePipesContexts";
6
6
  import { clearPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
7
7
 
8
- import { useRoute } from "../navigation";
8
+ import { useRoute } from "../navigation/useRoute";
9
9
 
10
10
  /**
11
11
  * reset river components cache when screen is unmounted
@@ -1,4 +1,3 @@
1
- import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
2
1
  import { useNavigation } from "./useNavigation";
3
2
  import { usePathname } from "./usePathname";
4
3
 
@@ -7,14 +6,11 @@ export const useIsScreenActive = () => {
7
6
  const pathname = usePathname();
8
7
  const { currentRoute, videoModalState } = useNavigation();
9
8
 
10
- if (videoModalState.visible) {
11
- if (pathname.includes(ROUTE_TYPES.VIDEO_MODAL)) {
12
- return true;
13
- }
14
-
15
- if (["FULLSCREEN", "MAXIMIZED", "PIP"].includes(videoModalState.mode)) {
16
- return false;
17
- }
9
+ if (
10
+ videoModalState.visible &&
11
+ ["FULLSCREEN", "MAXIMIZED", "PIP"].includes(videoModalState.mode)
12
+ ) {
13
+ return false;
18
14
  }
19
15
 
20
16
  return pathname === currentRoute;
@@ -2,7 +2,7 @@ import { useContext, useMemo } from "react";
2
2
 
3
3
  import { useModalNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ModalNavigationContext";
4
4
  import { useNestedNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext";
5
- import { useNavigation } from "../navigation";
5
+ import { useNavigation } from "../navigation/useNavigation";
6
6
 
7
7
  import { ScreenContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenContext";
8
8
  import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
@@ -1,8 +1,7 @@
1
- /* eslint-disable no-console */
2
1
  import React from "react";
3
2
  import { render, screen } from "@testing-library/react-native";
4
3
  import { Text } from "react-native";
5
- import { useZStore, ZStoreProvider } from "../ZStoreProvider";
4
+ import { ZStoreProvider, useZStore } from "../ZStoreProvider";
6
5
  import { useStore } from "zustand";
7
6
 
8
7
  interface TestState {
@@ -3,7 +3,7 @@ import { NativeModules, StyleSheet, View } from "react-native";
3
3
  import { getXray } from "@applicaster/zapp-react-native-utils/logger";
4
4
 
5
5
  import { isApplePlatform, isWeb } from "../reactUtils";
6
- import { useRivers } from "../reactHooks";
6
+ import { useRivers } from "../reactHooks/state";
7
7
 
8
8
  const layoutReducer = (state, { payload }) => {
9
9
  return state.map((item, index, _state) => ({
@@ -496,7 +496,6 @@ async function removeStorageListenerHandler(payload: { listenerId?: string }) {
496
496
  function log({ level, messages }) {
497
497
  try {
498
498
  const parsedMessages = parseJsonIfNeeded(messages);
499
- // eslint-disable-next-line no-console
500
499
  const logFn = console[level] || console.log;
501
500
 
502
501
  if (Array.isArray(parsedMessages)) {
@@ -13,15 +13,13 @@ class BackgroundTimer {
13
13
 
14
14
  const EventEmitter = platformSelect({
15
15
  android: DeviceEventEmitter,
16
- android_tv: DeviceEventEmitter,
17
- amazon: DeviceEventEmitter, // probably does not exist and uses android_tv
16
+ ios: undefined,
18
17
  default: undefined,
19
18
  });
20
19
 
21
20
  EventEmitter?.addListener("BackgroundTimer.timer.fired", (id: number) => {
22
- const callback = this.callbacks[id];
23
-
24
- if (callback) {
21
+ if (this.callbacks[id]) {
22
+ const callback = this.callbacks[id];
25
23
  delete this.callbacks[id];
26
24
  callback();
27
25
  }
package/utils/index.ts CHANGED
@@ -2,19 +2,4 @@ export { chunk } from "./chunk";
2
2
 
3
3
  export { times } from "./times";
4
4
 
5
- export {
6
- cloneDeep as clone,
7
- flatten,
8
- drop,
9
- size,
10
- isNil,
11
- isEmpty,
12
- get,
13
- has,
14
- flatMap,
15
- difference,
16
- take,
17
- map,
18
- trim,
19
- toString,
20
- } from "lodash";
5
+ export { cloneDeep as clone, flatten, drop, size, isNil } from "lodash";
@@ -1,63 +0,0 @@
1
- import { isEmptyArray } from "..";
2
-
3
- describe("isEmptyArray", () => {
4
- it("non-empty array is not empty", () => {
5
- const value = [1, 2, 3];
6
-
7
- expect(isEmptyArray(value)).toBe(false);
8
- });
9
-
10
- it("empty array is empty", () => {
11
- const value = [];
12
-
13
- expect(isEmptyArray(value)).toBe(true);
14
- });
15
-
16
- it("number is not array", () => {
17
- const value = 123;
18
-
19
- expect(isEmptyArray(value)).toBe(false);
20
- });
21
-
22
- it("string is not array", () => {
23
- const value = "vfnjdk";
24
-
25
- expect(isEmptyArray(value)).toBe(false);
26
- });
27
-
28
- it("empty string is not array", () => {
29
- const value = "";
30
-
31
- expect(isEmptyArray(value)).toBe(false);
32
- });
33
-
34
- it("NaN is not array", () => {
35
- const value = NaN;
36
-
37
- expect(isEmptyArray(value)).toBe(false);
38
- });
39
-
40
- it("object is not array", () => {
41
- const value = { test: 1 };
42
-
43
- expect(isEmptyArray(value)).toBe(false);
44
- });
45
-
46
- it("empty object is not array", () => {
47
- const value = {};
48
-
49
- expect(isEmptyArray(value)).toBe(false);
50
- });
51
-
52
- it("undefined is not array", () => {
53
- const value = undefined;
54
-
55
- expect(isEmptyArray(value)).toBe(false);
56
- });
57
-
58
- it("null is not array", () => {
59
- const value = null;
60
-
61
- expect(isEmptyArray(value)).toBe(false);
62
- });
63
- });
@@ -1,144 +0,0 @@
1
- import { getArtworkImage } from "..";
2
- import { DEFAULT_IMAGE } from "../assets";
3
-
4
- describe("getArtworkImage", () => {
5
- const entryWithImage = {
6
- media_group: [
7
- {
8
- type: "image",
9
- media_item: [
10
- { key: "artwork_key", src: "image_from_entry" },
11
- { key: "other_key", src: "other_image" },
12
- ],
13
- },
14
- ],
15
- extensions: {
16
- artwork_key: "artwork_key",
17
- },
18
- };
19
-
20
- const entryWithoutImage = {
21
- media_group: [
22
- {
23
- type: "image",
24
- media_item: [{ key: "other_key", src: "other_image" }],
25
- },
26
- ],
27
- extensions: {
28
- artwork_key: "artwork_key",
29
- },
30
- };
31
-
32
- const pluginConfigWithImage = {
33
- artwork_key: "plugin_artwork_key",
34
- };
35
-
36
- it("returns image from entry extensions key", () => {
37
- const result = getArtworkImage({
38
- key: "artwork_key",
39
- entry: entryWithImage,
40
- plugin_configuration: {},
41
- });
42
-
43
- expect(result).toBe("image_from_entry");
44
- });
45
-
46
- it("returns image from plugin configuration key if not in entry", () => {
47
- const entryNoMatch = {
48
- ...entryWithoutImage,
49
- extensions: { artwork_key: "not_found_key" },
50
- };
51
-
52
- const pluginConfig = {
53
- artwork_key: "plugin_artwork_key",
54
- };
55
-
56
- const entryWithPluginImage = {
57
- ...entryNoMatch,
58
- media_group: [
59
- {
60
- type: "image",
61
- media_item: [{ key: "plugin_artwork_key", src: "image_from_plugin" }],
62
- },
63
- ],
64
- };
65
-
66
- const result = getArtworkImage({
67
- key: "artwork_key",
68
- entry: entryWithPluginImage,
69
- plugin_configuration: pluginConfig,
70
- });
71
-
72
- expect(result).toBe("image_from_plugin");
73
- });
74
-
75
- it("returns DEFAULT_IMAGE if neither entry nor plugin configuration has image", () => {
76
- const entryNoImage = {
77
- media_group: [
78
- {
79
- type: "image",
80
- media_item: [{ key: "other_key", src: "other_image" }],
81
- },
82
- ],
83
- extensions: { artwork_key: "not_found_key" },
84
- };
85
-
86
- const pluginConfig = { artwork_key: "not_found_key" };
87
-
88
- const result = getArtworkImage({
89
- key: "artwork_key",
90
- entry: entryNoImage,
91
- plugin_configuration: pluginConfig,
92
- });
93
-
94
- expect(result).toBe(DEFAULT_IMAGE);
95
- });
96
-
97
- it("handles undefined key gracefully", () => {
98
- const result = getArtworkImage({
99
- key: undefined,
100
- entry: entryWithImage,
101
- plugin_configuration: pluginConfigWithImage,
102
- });
103
-
104
- expect(result).toBe(DEFAULT_IMAGE);
105
- });
106
-
107
- it("handles missing entry or plugin_configuration gracefully", () => {
108
- const result = getArtworkImage({
109
- key: "artwork_key",
110
- entry: undefined,
111
- plugin_configuration: undefined,
112
- });
113
-
114
- expect(result).toBe(DEFAULT_IMAGE);
115
- });
116
-
117
- it("handles empty media_group", () => {
118
- const entryEmptyMedia = {
119
- media_group: [],
120
- extensions: { artwork_key: "artwork_key" },
121
- };
122
-
123
- const result = getArtworkImage({
124
- key: "artwork_key",
125
- entry: entryEmptyMedia,
126
- plugin_configuration: pluginConfigWithImage,
127
- });
128
-
129
- expect(result).toBe(DEFAULT_IMAGE);
130
- });
131
-
132
- it("handles missing extensions/config keys", () => {
133
- const entryNoExt = { media_group: [], extensions: {} };
134
- const pluginConfig = {};
135
-
136
- const result = getArtworkImage({
137
- key: "artwork_key",
138
- entry: entryNoExt,
139
- plugin_configuration: pluginConfig,
140
- });
141
-
142
- expect(result).toBe(DEFAULT_IMAGE);
143
- });
144
- });
@@ -1,72 +0,0 @@
1
- import { getBackgroundImage } from "..";
2
- import { DEFAULT_IMAGE } from "../assets";
3
-
4
- describe("getBackgroundImage", () => {
5
- const entryBase = {
6
- media_group: [
7
- {
8
- media_item: [
9
- { key: "image_key_1", src: "image_src_1" },
10
- { key: "image_key_2", src: "image_src_2" },
11
- ],
12
- type: "image",
13
- },
14
- ],
15
- extensions: {},
16
- };
17
-
18
- const pluginConfigBase = {};
19
-
20
- it("returns image from entry.extensions.image_key if present", () => {
21
- const entry = {
22
- ...entryBase,
23
- extensions: { image_key: "image_key_2" },
24
- };
25
-
26
- const result = getBackgroundImage({
27
- entry,
28
- plugin_configuration: pluginConfigBase,
29
- });
30
-
31
- expect(result).toBe("image_src_2");
32
- });
33
-
34
- it("returns audio_player_background_image from entry.extensions if present and no image_key image", () => {
35
- const entry = {
36
- ...entryBase,
37
- extensions: { audio_player_background_image: "audio_img_ext" },
38
- };
39
-
40
- const result = getBackgroundImage({
41
- entry,
42
- plugin_configuration: pluginConfigBase,
43
- });
44
-
45
- expect(result).toBe("audio_img_ext");
46
- });
47
-
48
- it("returns image from plugin_configuration.audio_player_image_key if present and not found in entry.extensions", () => {
49
- const entry = { ...entryBase };
50
- const plugin_configuration = { audio_player_image_key: "image_key_1" };
51
- const result = getBackgroundImage({ entry, plugin_configuration });
52
- expect(result).toBe("image_src_1");
53
- });
54
-
55
- it("returns audio_player_background_image from plugin_configuration if present and not found in entry/extensions", () => {
56
- const entry = { ...entryBase };
57
-
58
- const plugin_configuration = {
59
- audio_player_background_image: "audio_img_conf",
60
- };
61
-
62
- const result = getBackgroundImage({ entry, plugin_configuration });
63
- expect(result).toBe("audio_img_conf");
64
- });
65
-
66
- it("returns DEFAULT_IMAGE if nothing is found", () => {
67
- const entry = { media_group: [], extensions: {} };
68
- const plugin_configuration = {};
69
- const result = getBackgroundImage({ entry, plugin_configuration });
70
- expect(result).toBe(DEFAULT_IMAGE);
71
- });
72
- });