@applicaster/zapp-react-native-utils 14.0.0-alpha.1216545755 → 14.0.0-alpha.1308901965

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.
@@ -237,8 +237,14 @@ const prepareDefaultActions = (actionExecutor) => {
237
237
  context?: Record<string, any>
238
238
  ): Promise<ActionResult> => {
239
239
  const route = context?.screenRoute;
240
- const { key, value } = action.options;
241
- screenSetVariable(route, key, value);
240
+ const screenStateStore = context?.screenStateStore;
241
+
242
+ await screenSetVariable(
243
+ route,
244
+ screenStateStore,
245
+ { entry: context?.entry, options: action.options },
246
+ action
247
+ );
242
248
 
243
249
  return Promise.resolve(ActionResult.Success);
244
250
  }
@@ -6,12 +6,83 @@ import { get } from "lodash";
6
6
 
7
7
  import { onMaxTagsReached } from "./StorageActions";
8
8
  import { ScreenMultiSelectProvider } from "../storage/ScreenStateMultiSelectProvider";
9
+ import { ScreenSingleValueProvider } from "../storage/ScreenSingleValueProvider";
9
10
 
10
- export const screenSetVariable = (
11
- _screenRoute: string,
12
- _key: string,
13
- _value: string
14
- ) => {};
11
+ export const screenSetVariable = async (
12
+ screenRoute: string,
13
+ screenStateStore: ScreenStateStore,
14
+ context: Record<string, any>,
15
+ action: ActionType
16
+ ): Promise<ActionResult> => {
17
+ if (!context) {
18
+ log_error("handleAction: screenSetVariable action missing context");
19
+
20
+ return ActionResult.Error;
21
+ }
22
+
23
+ const entry = context?.entry as ZappEntry;
24
+
25
+ if (!entry) {
26
+ log_error(
27
+ "handleAction: screenSetVariable action missing entry. Entry is required to get the value."
28
+ );
29
+
30
+ return ActionResult.Error;
31
+ }
32
+
33
+ const tag = action.options?.selector
34
+ ? get(entry, action.options.selector)
35
+ : (entry.extensions?.tag ?? entry.id);
36
+
37
+ const keyNamespace = action.options?.key;
38
+
39
+ if (!keyNamespace) {
40
+ log_error("handleAction: screenSetVariable action missing key namespace", {
41
+ keyNamespace,
42
+ });
43
+
44
+ return ActionResult.Error;
45
+ }
46
+
47
+ if (!tag) {
48
+ log_error(
49
+ "handleAction: screenSetVariable action could not determine tag",
50
+ { selector: action.options?.selector, value: action.options?.value }
51
+ );
52
+
53
+ return ActionResult.Error;
54
+ }
55
+
56
+ try {
57
+ const singleValueProvider = ScreenSingleValueProvider.getProvider(
58
+ keyNamespace,
59
+ screenRoute,
60
+ screenStateStore
61
+ );
62
+
63
+ const currentValue = await singleValueProvider.getValueAsync();
64
+
65
+ log_info(
66
+ `handleAction: screenSetVariable setting value: ${tag} for keyNamespace: ${keyNamespace}, previous value: ${currentValue}`
67
+ );
68
+
69
+ await singleValueProvider.setValue(String(tag));
70
+
71
+ log_info(
72
+ `handleAction: screenSetVariable successfully set value: ${tag} for keyNamespace: ${keyNamespace}`
73
+ );
74
+
75
+ return ActionResult.Success;
76
+ } catch (error) {
77
+ log_error("handleAction: screenSetVariable failed to set value", {
78
+ keyNamespace,
79
+ tag,
80
+ error,
81
+ });
82
+
83
+ return ActionResult.Error;
84
+ }
85
+ };
15
86
 
16
87
  export const screenToggleFlag = async (
17
88
  screenRoute: string,
@@ -115,7 +115,7 @@ function makeSingleSelect(feed: ZappFeed, key, decoratedFeed) {
115
115
  return {
116
116
  type: "screenSetVariable",
117
117
  options: {
118
- key: `@{screen/${key}}`,
118
+ key,
119
119
  value: entry.id,
120
120
  },
121
121
  };
@@ -4,9 +4,12 @@ import {
4
4
  ANALYTICS_COMPONENT_EVENTS,
5
5
  ANALYTICS_CORE_EVENTS,
6
6
  ANALYTICS_ENTRY_EVENTS,
7
+ ANALYTICS_PREFERENCES_EVENTS,
7
8
  DOWNLOADS_EVENTS,
8
9
  } from "../events";
9
10
  import { isEmptyOrNil } from "../../cellUtils";
11
+ import { get } from "lodash";
12
+ import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-utils/storage/StorageMultiSelectProvider";
10
13
 
11
14
  export enum OfflineItemState {
12
15
  notExist = "NOT_EXISTS",
@@ -102,6 +105,84 @@ export function eventForComponent(
102
105
  return analyticsProps;
103
106
  }
104
107
 
108
+ /**
109
+ * Checks if an item is currently selected in localStorage based on its actions
110
+ * @param item - The item to check
111
+ * @returns boolean indicating if the item is currently selected
112
+ */
113
+ function isItemPreviouslySelected(item: any): boolean {
114
+ const actions = item?.extensions?.tap_actions?.actions;
115
+
116
+ if (!actions) {
117
+ return false;
118
+ }
119
+
120
+ const localStorageAction = actions.find(
121
+ (action) => action?.type === "localStorageToggleFlag"
122
+ );
123
+
124
+ if (!localStorageAction?.options?.key) {
125
+ return false;
126
+ }
127
+
128
+ const keyNamespace = localStorageAction.options.key;
129
+
130
+ const tag = localStorageAction.options?.selector
131
+ ? get(item, localStorageAction.options.selector)
132
+ : (item.extensions?.tag ?? item.id);
133
+
134
+ if (!tag) {
135
+ return false;
136
+ }
137
+
138
+ try {
139
+ const multiSelectProvider =
140
+ StorageMultiSelectProvider.getProvider(keyNamespace);
141
+
142
+ const selectedItems = multiSelectProvider.getSelectedItems();
143
+
144
+ return selectedItems.includes(tag);
145
+ } catch (error) {
146
+ return false;
147
+ }
148
+ }
149
+
150
+ export function getLocalStorageSetPayload(extraProps) {
151
+ const { item } = extraProps;
152
+
153
+ const hasLocalStorageSetAction = item?.extensions?.tap_actions?.actions?.some(
154
+ (action) => action?.type === "localStorageSet"
155
+ );
156
+
157
+ if (!hasLocalStorageSetAction) {
158
+ return null;
159
+ }
160
+
161
+ return {
162
+ [ANALYTICS_PREFERENCES_EVENTS.ITEM_SELECTED_STATUS]: true,
163
+ };
164
+ }
165
+
166
+ export function getLocalStorageToggleFlagPayload(extraProps) {
167
+ const { item } = extraProps;
168
+
169
+ const hasLocalStorageToggleAction =
170
+ item?.extensions?.tap_actions?.actions?.some(
171
+ (action) => action?.type === "localStorageToggleFlag"
172
+ );
173
+
174
+ if (!hasLocalStorageToggleAction) {
175
+ return null;
176
+ }
177
+
178
+ const previouslySelected = isItemPreviouslySelected(item);
179
+
180
+ return {
181
+ [ANALYTICS_PREFERENCES_EVENTS.ITEM_SELECTED_STATUS]: !previouslySelected,
182
+ [ANALYTICS_PREFERENCES_EVENTS.PREVIOUS_SELECTED_STATE]: previouslySelected,
183
+ };
184
+ }
185
+
105
186
  export function playEventForType(item) {
106
187
  const itemType = item?.type && item.type?.value;
107
188
 
@@ -1,13 +1,13 @@
1
1
  import { log_error, log_debug } from "../logger";
2
-
3
- import { ANALYTICS_CORE_EVENTS } from "../events";
4
-
2
+ import { ANALYTICS_CORE_EVENTS, ACTION_TYPE } from "../events";
5
3
  import { postAnalyticEvent } from "../manager";
6
4
  import {
7
5
  replaceAnalyticsPropsNils,
8
6
  eventForEntry,
9
7
  eventForComponent,
10
8
  extensionsEvents,
9
+ getLocalStorageSetPayload,
10
+ getLocalStorageToggleFlagPayload,
11
11
  } from "./helper";
12
12
 
13
13
  declare type AnalyticsDefaultHelperProperties = {
@@ -26,7 +26,16 @@ export const sendOnClickEvent = ({
26
26
  const castedExtraProps: ExtraProps = extraProps;
27
27
  const componentData = component || extraProps.component;
28
28
  const data = zappPipesData || extraProps.zappPipesData;
29
- const eventName = ANALYTICS_CORE_EVENTS.TAP_CELL;
29
+
30
+ const actionCellPayload =
31
+ extraProps?.item?.type?.value === ACTION_TYPE
32
+ ? getLocalStorageSetPayload(extraProps) ||
33
+ getLocalStorageToggleFlagPayload(extraProps)
34
+ : null;
35
+
36
+ const eventName = actionCellPayload
37
+ ? ANALYTICS_CORE_EVENTS.TAP_SELECTABLE_CELL
38
+ : ANALYTICS_CORE_EVENTS.TAP_CELL;
30
39
 
31
40
  if (!analyticsScreenData) {
32
41
  log_error(
@@ -44,6 +53,7 @@ export const sendOnClickEvent = ({
44
53
  ...replaceAnalyticsPropsNils({
45
54
  ...analyticsScreenData,
46
55
  }),
56
+ ...actionCellPayload,
47
57
  };
48
58
 
49
59
  if (analyticsCustomProperties) {
@@ -3,8 +3,22 @@ import { ANALYTICS_CORE_EVENTS } from "../events";
3
3
 
4
4
  jest.mock("@applicaster/zapp-react-native-utils/reactUtils", () => ({
5
5
  isWeb: jest.fn(),
6
+ platformSelect: jest.fn(
7
+ (options) => options.android || options.ios || options.web
8
+ ),
6
9
  }));
7
10
 
11
+ jest.mock(
12
+ "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider",
13
+ () => ({
14
+ StorageMultiSelectProvider: {
15
+ getProvider: jest.fn(() => ({
16
+ getSelectedItems: jest.fn(() => []),
17
+ })),
18
+ },
19
+ })
20
+ );
21
+
8
22
  const mock_postAnalyticEvent = jest.fn();
9
23
  const mock_startAnalyticsTimedEvent = jest.fn();
10
24
  const mock_endAnalyticsTimedEvent = jest.fn();
@@ -17,8 +17,11 @@ export const SCREEN_VIEW_EVENTS = {
17
17
  TIME_ON_SCREEN: "time_on_screen",
18
18
  };
19
19
 
20
+ export const ACTION_TYPE = "action";
21
+
20
22
  export const TAPPING_EVENTS = {
21
23
  TAP_CELL: "tap_cell",
24
+ TAP_SELECTABLE_CELL: "tap_selectable_cell",
22
25
  TAP_MENU: "tap_menu",
23
26
  TAP_NAVBAR_BACK_BUTTON: "tap_navbar_back_button",
24
27
  };
@@ -99,6 +102,11 @@ export const ANALYTICS_COMPONENT_EVENTS = {
99
102
  COMPONENT_SOURCE: "component_source",
100
103
  };
101
104
 
105
+ export const ANALYTICS_PREFERENCES_EVENTS = {
106
+ ITEM_SELECTED_STATUS: "item_selected_status",
107
+ PREVIOUS_SELECTED_STATE: "previous_selected_state",
108
+ };
109
+
102
110
  // ---------------- EVENTS ---------------------
103
111
  export const AD_EVENT = {
104
112
  ad_break_start: "player_ad_break_start",
@@ -1,9 +1,9 @@
1
1
  import { BehaviorSubject } from "rxjs";
2
2
  import { accessibilityManagerLogger as logger } from "./logger";
3
- import { TTSManager } from "../platform/platformUtils";
3
+ import { TTSManager } from "../platform";
4
4
  import { BUTTON_ACCESSIBILITY_KEYS } from "./const";
5
5
  import { AccessibilityRole } from "react-native";
6
- import _ from "lodash";
6
+ import { toString } from "../../utils";
7
7
 
8
8
  export class AccessibilityManager {
9
9
  private static _instance: AccessibilityManager | null = null;
@@ -137,7 +137,7 @@ export class AccessibilityManager {
137
137
  }
138
138
 
139
139
  public getButtonAccessibilityProps(name: string): AccessibilityProps {
140
- const buttonName = _.toString(name);
140
+ const buttonName = toString(name);
141
141
 
142
142
  const buttonConfig = BUTTON_ACCESSIBILITY_KEYS[buttonName];
143
143
 
@@ -176,18 +176,30 @@ class FocusManager {
176
176
  }
177
177
  }
178
178
 
179
- registerFocusable(
180
- component: FocusManager.TouchableReactRef,
181
- parentFocusable: FocusManager.TouchableReactRef,
182
- isFocusableCell: boolean
183
- ) {
184
- const focusableId = getFocusableId(component);
179
+ registerFocusable({
180
+ touchableRef,
181
+ parentFocusableRef,
182
+ isFocusableCell,
183
+ parentFocusableId,
184
+ }: {
185
+ touchableRef: FocusManager.TouchableReactRef;
186
+ parentFocusableRef: FocusManager.TouchableReactRef;
187
+ isFocusableCell: boolean;
188
+ parentFocusableId: string;
189
+ }) {
190
+ const focusableId = getFocusableId(touchableRef);
191
+
185
192
  const focusableComponent = FocusManager.findFocusable(focusableId);
186
193
 
187
- if (!focusableComponent && component) {
188
- this.focusableComponents.push(component);
194
+ if (!focusableComponent && touchableRef) {
195
+ this.focusableComponents.push(touchableRef);
189
196
 
190
- this.tree.add(component, parentFocusable, isFocusableCell);
197
+ this.tree.add(
198
+ touchableRef,
199
+ parentFocusableRef,
200
+ isFocusableCell,
201
+ parentFocusableId
202
+ );
191
203
  } else {
192
204
  logger.warning("Focusable component already registered", {
193
205
  id: focusableId,
@@ -243,12 +255,10 @@ class FocusManager {
243
255
  }
244
256
 
245
257
  blurPrevious(options?: FocusManager.Android.CallbackOptions) {
246
- if (options) {
247
- FocusManager.instance.prevFocused?.onBlur?.(
248
- FocusManager.instance.prevFocused,
249
- options
250
- );
251
- }
258
+ FocusManager.instance.prevFocused?.onBlur?.(
259
+ FocusManager.instance.prevFocused,
260
+ options ?? {} // Adding fallback to avoid potential regression caused by #7509
261
+ );
252
262
  }
253
263
 
254
264
  onDisableFocusChange = (id) => {
@@ -269,7 +279,7 @@ class FocusManager {
269
279
 
270
280
  if (nextFocus) {
271
281
  // HACK: hack to fix the hack below
272
- // HACK: putting call to the end of the event loop so the next component has a chane to be registered
282
+ // HACK: putting call to the end of the event loop so the next component has a chance to be registered
273
283
  setTimeout(() => {
274
284
  FocusManager.instance.setFocus(nextFocus, {
275
285
  direction: "down",
@@ -8,37 +8,41 @@ export class Tree {
8
8
  this.tree = focusManagerTree;
9
9
  }
10
10
 
11
- add(component, parentFocusable, isFocusableCell) {
12
- const focusableId = getFocusableId(component);
13
- const parentId = getFocusableId(parentFocusable);
11
+ add(
12
+ touchableRef: FocusManager.TouchableReactRef,
13
+ parentFocusableRef: FocusManager.TouchableReactRef,
14
+ isFocusableCell: boolean,
15
+ parentFocusableId: string
16
+ ) {
17
+ const focusableId = getFocusableId(touchableRef);
18
+ const parentId = getFocusableId(parentFocusableRef) || parentFocusableId;
14
19
  const focusableComponentInTree = this.find(focusableId);
15
20
 
16
21
  // update node if it already exists
17
22
  if (focusableComponentInTree) {
18
- focusableComponentInTree.updateNode(component);
23
+ focusableComponentInTree.updateNode(touchableRef);
19
24
  }
20
25
 
21
- if (parentFocusable?.current) {
22
- if (!this.find(parentId)) {
23
- this.tree.push(new TreeNode(null, parentId, null, isFocusableCell));
24
- }
26
+ if (!this.find(parentId)) {
27
+ // create temporary node to the root of the tree
28
+ this.tree.push(new TreeNode(null, parentId, null, isFocusableCell));
29
+ }
25
30
 
26
- const parentNode = this.find(parentId);
31
+ const parentNode = this.find(parentId);
27
32
 
28
- if (parentNode) {
29
- if (focusableComponentInTree) {
30
- focusableComponentInTree.isFocusableCell = isFocusableCell;
31
- focusableComponentInTree.parentId = parentNode.id;
33
+ if (parentNode) {
34
+ if (focusableComponentInTree) {
35
+ focusableComponentInTree.isFocusableCell = isFocusableCell;
36
+ focusableComponentInTree.parentId = parentNode.id;
32
37
 
33
- parentNode.addChild(focusableComponentInTree);
38
+ parentNode.addChild(focusableComponentInTree);
34
39
 
35
- // remove root object from the list
36
- this.tree = this.tree.filter(
37
- (node) => node !== focusableComponentInTree
38
- );
39
- } else {
40
- parentNode.addChild(component, focusableId, isFocusableCell);
41
- }
40
+ // remove root object from the list
41
+ this.tree = this.tree.filter(
42
+ (node) => node !== focusableComponentInTree
43
+ );
44
+ } else {
45
+ parentNode.addChild(touchableRef, focusableId, isFocusableCell);
42
46
  }
43
47
  }
44
48
  }
@@ -1,5 +1,8 @@
1
1
  import { focusManager } from "../FocusManager";
2
2
 
3
+ const isFocusableCell = true;
4
+ const parentFocusableId = "parentFocusableId";
5
+
3
6
  const group = {
4
7
  current: {
5
8
  props: {
@@ -62,13 +65,47 @@ jest.useFakeTimers();
62
65
 
63
66
  describe("FocusManager", () => {
64
67
  beforeAll(() => {
65
- focusManager.registerFocusable(group, { current: null });
66
- focusManager.registerFocusable(child1, group);
67
- focusManager.registerFocusable(child2, group);
68
- focusManager.registerFocusable(child3, child2);
69
-
70
- focusManager.registerFocusable(child4, child2);
71
- focusManager.registerFocusable(child5, child2);
68
+ focusManager.registerFocusable({
69
+ touchableRef: group,
70
+ parentFocusableRef: { current: null },
71
+ isFocusableCell,
72
+ parentFocusableId,
73
+ });
74
+
75
+ focusManager.registerFocusable({
76
+ touchableRef: child1,
77
+ parentFocusableRef: group,
78
+ isFocusableCell,
79
+ parentFocusableId,
80
+ });
81
+
82
+ focusManager.registerFocusable({
83
+ touchableRef: child2,
84
+ parentFocusableRef: group,
85
+ isFocusableCell,
86
+ parentFocusableId,
87
+ });
88
+
89
+ focusManager.registerFocusable({
90
+ touchableRef: child3,
91
+ parentFocusableRef: child2,
92
+ isFocusableCell,
93
+ parentFocusableId,
94
+ });
95
+
96
+ focusManager.registerFocusable({
97
+ touchableRef: child4,
98
+ parentFocusableRef: child2,
99
+ isFocusableCell,
100
+ parentFocusableId,
101
+ });
102
+
103
+ focusManager.registerFocusable({
104
+ touchableRef: child5,
105
+ parentFocusableRef: child2,
106
+ isFocusableCell,
107
+ parentFocusableId,
108
+ });
72
109
  });
73
110
 
74
111
  it("focusManager should be defined", () => {
@@ -199,7 +236,12 @@ describe("FocusManager", () => {
199
236
  });
200
237
 
201
238
  it("focusManager registerFocusable should register", () => {
202
- focusManager.registerFocusable(child5, child2);
239
+ focusManager.registerFocusable({
240
+ touchableRef: child5,
241
+ parentFocusableRef: child2,
242
+ isFocusableCell,
243
+ parentFocusableId,
244
+ });
203
245
 
204
246
  expect(
205
247
  focusManager.isFocusableChildOf(child5.current.props.id, child2)
@@ -2985,6 +2985,14 @@ function getPlayerConfiguration({ platform, version }) {
2985
2985
  type: "uploader",
2986
2986
  default: "",
2987
2987
  },
2988
+ {
2989
+ key: "audio_player_background_image_overlay",
2990
+ label: "Background Image Overlay",
2991
+ label_tooltip:
2992
+ "Add a semi-transparent color overlay to improve text readability over the background image.",
2993
+ type: "color_picker_rgba",
2994
+ initial_value: "rgba(17, 17, 17, 0.5)",
2995
+ },
2988
2996
  {
2989
2997
  type: "text_input",
2990
2998
  label: "Item Image Key",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "14.0.0-alpha.1216545755",
3
+ "version": "14.0.0-alpha.1308901965",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,7 +27,7 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "14.0.0-alpha.1216545755",
30
+ "@applicaster/applicaster-types": "14.0.0-alpha.1308901965",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
@@ -1,4 +1,4 @@
1
- import { take, map, trim } from "lodash";
1
+ import { map, take, trim } from "../utils";
2
2
  import { selectActionButtons } from "../conf/player/selectors";
3
3
 
4
4
  /**
@@ -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/useScreenContext";
13
+ import { useScreenContext } from "../screen";
14
14
 
15
15
  type Options = {
16
16
  initialBatchSize?: number;
@@ -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/useRoute";
8
+ import { useRoute } from "../navigation";
9
9
 
10
10
  /**
11
11
  * reset river components cache when screen is unmounted
@@ -1,3 +1,4 @@
1
+ import { ROUTE_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/routeTypes";
1
2
  import { useNavigation } from "./useNavigation";
2
3
  import { usePathname } from "./usePathname";
3
4
 
@@ -6,11 +7,14 @@ export const useIsScreenActive = () => {
6
7
  const pathname = usePathname();
7
8
  const { currentRoute, videoModalState } = useNavigation();
8
9
 
9
- if (
10
- videoModalState.visible &&
11
- ["FULLSCREEN", "MAXIMIZED", "PIP"].includes(videoModalState.mode)
12
- ) {
13
- return false;
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
+ }
14
18
  }
15
19
 
16
20
  return pathname === currentRoute;
@@ -5,7 +5,7 @@ export const useScreenStateStore = () => {
5
5
  const route = useRoute(false);
6
6
 
7
7
  return useMemo(
8
- () => route.screenData?.screenStateStore,
9
- [route.screenData?.screenStateStore]
8
+ () => route.screenData["screenStateStore"],
9
+ [route.screenData["screenStateStore"]]
10
10
  );
11
11
  };
@@ -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/useNavigation";
5
+ import { useNavigation } from "../navigation";
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,7 +1,8 @@
1
+ /* eslint-disable no-console */
1
2
  import React from "react";
2
3
  import { render, screen } from "@testing-library/react-native";
3
4
  import { Text } from "react-native";
4
- import { ZStoreProvider, useZStore } from "../ZStoreProvider";
5
+ import { useZStore, ZStoreProvider } from "../ZStoreProvider";
5
6
  import { useStore } from "zustand";
6
7
 
7
8
  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/state";
6
+ import { useRivers } from "../reactHooks";
7
7
 
8
8
  const layoutReducer = (state, { payload }) => {
9
9
  return state.map((item, index, _state) => ({
@@ -496,6 +496,7 @@ 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
499
500
  const logFn = console[level] || console.log;
500
501
 
501
502
  if (Array.isArray(parsedMessages)) {
@@ -1,9 +1,13 @@
1
1
  import { BehaviorSubject } from "rxjs";
2
- import {
3
- log_debug,
4
- log_error,
5
- SingleValueProvider,
6
- } from "./StorageSingleSelectProvider";
2
+ import { SingleValueProvider } from "./StorageSingleSelectProvider";
3
+ import { createLogger } from "../logger";
4
+ import { bridgeLogger } from "../../zapp-react-native-bridge/logger";
5
+
6
+ export const { log_debug, log_error } = createLogger({
7
+ category: "ScreenSingleValueProvider",
8
+ subsystem: "zapp-react-native-bridge",
9
+ parent: bridgeLogger,
10
+ });
7
11
 
8
12
  export class ScreenSingleValueProvider implements SingleValueProvider {
9
13
  // @ts-ignore
@@ -154,7 +158,6 @@ export class ScreenSingleValueProvider implements SingleValueProvider {
154
158
  const currentValue = this.screenStateStore.getState().data[this.key];
155
159
  const value = currentValue || null;
156
160
  const selected = this.getValue();
157
-
158
161
  const valuesAreEqual = value === selected;
159
162
 
160
163
  const bothEmpty =
@@ -1,9 +1,13 @@
1
- import {
2
- log_debug,
3
- log_error,
4
- MultiSelectProvider,
5
- } from "./StorageMultiSelectProvider";
1
+ import { MultiSelectProvider } from "./StorageMultiSelectProvider";
6
2
  import { BehaviorSubject } from "rxjs";
3
+ import { createLogger } from "../logger";
4
+ import { bridgeLogger } from "../../zapp-react-native-bridge/logger";
5
+
6
+ export const { log_debug, log_error } = createLogger({
7
+ category: "ScreenMultiSelectProvider",
8
+ subsystem: "zapp-react-native-bridge",
9
+ parent: bridgeLogger,
10
+ });
7
11
 
8
12
  export class ScreenMultiSelectProvider implements MultiSelectProvider {
9
13
  // @ts-ignore
@@ -85,6 +89,10 @@ export class ScreenMultiSelectProvider implements MultiSelectProvider {
85
89
  }
86
90
 
87
91
  private updateStore(screenStateStore: ScreenStateStore): void {
92
+ if (screenStateStore === this.screenStateStore) {
93
+ return;
94
+ }
95
+
88
96
  this.cleanup();
89
97
  this.screenStateStore = screenStateStore;
90
98
  this.setupScreenStateSubscription();
@@ -123,22 +131,16 @@ export class ScreenMultiSelectProvider implements MultiSelectProvider {
123
131
  );
124
132
  }
125
133
 
126
- private parseStoredValue(value: any): string[] {
134
+ private parseStoredValue(value: string): string[] {
127
135
  if (!value) return [];
128
136
 
129
- try {
130
- const parsed = JSON.parse(value);
131
-
132
- return Array.isArray(parsed) ? parsed.map(String) : [];
133
- } catch {
134
- return typeof value === "string"
135
- ? value.split(",").filter((item) => item.length > 0)
136
- : [];
137
- }
137
+ return typeof value === "string"
138
+ ? value.split(",").filter((item) => item.length > 0)
139
+ : [];
138
140
  }
139
141
 
140
142
  private formatValueForStorage(items: string[]): string {
141
- return JSON.stringify(items);
143
+ return items.join(",");
142
144
  }
143
145
 
144
146
  private getCurrentItems(): Set<string> {
@@ -219,10 +221,6 @@ export class ScreenMultiSelectProvider implements MultiSelectProvider {
219
221
  }
220
222
 
221
223
  getSelectedItems(): string[] {
222
- console.log("Anton getSelectedItems", {
223
- currentValue: this.itemSubject.value,
224
- });
225
-
226
224
  return this.itemSubject.value || [];
227
225
  }
228
226
 
@@ -266,7 +264,6 @@ export class ScreenMultiSelectProvider implements MultiSelectProvider {
266
264
 
267
265
  setSelectedItems(items: string[]): Promise<void> {
268
266
  this.updateScreenState(new Set(items));
269
-
270
267
  log_debug(`setSelectedItems: items set to: [${items.join(", ")}]`);
271
268
 
272
269
  return Promise.resolve();
@@ -13,13 +13,15 @@ class BackgroundTimer {
13
13
 
14
14
  const EventEmitter = platformSelect({
15
15
  android: DeviceEventEmitter,
16
- ios: undefined,
16
+ android_tv: DeviceEventEmitter,
17
+ amazon: DeviceEventEmitter, // probably does not exist and uses android_tv
17
18
  default: undefined,
18
19
  });
19
20
 
20
21
  EventEmitter?.addListener("BackgroundTimer.timer.fired", (id: number) => {
21
- if (this.callbacks[id]) {
22
- const callback = this.callbacks[id];
22
+ const callback = this.callbacks[id];
23
+
24
+ if (callback) {
23
25
  delete this.callbacks[id];
24
26
  callback();
25
27
  }
package/utils/index.ts CHANGED
@@ -13,4 +13,8 @@ export {
13
13
  has,
14
14
  flatMap,
15
15
  difference,
16
+ take,
17
+ map,
18
+ trim,
19
+ toString,
16
20
  } from "lodash";