@applicaster/zapp-react-native-utils 12.0.0-rc.98 → 13.0.0-alpha.2322412833

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 (76) hide show
  1. package/analyticsUtils/AnalyticPlayerListener.ts +141 -0
  2. package/analyticsUtils/PlayerAnalyticsManager.ts +90 -0
  3. package/analyticsUtils/{analyticsTracker.ts → playerAnalyticsTracker.ts} +19 -10
  4. package/appUtils/HooksManager/{Hook.js → Hook.ts} +35 -23
  5. package/appUtils/HooksManager/__tests__/__snapshots__/hook.test.js.snap +4 -2
  6. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +693 -0
  7. package/appUtils/HooksManager/__tests__/hook.test.js +196 -184
  8. package/appUtils/HooksManager/__tests__/hooksManager.test.js +96 -99
  9. package/appUtils/HooksManager/{constants.js → constants.ts} +1 -1
  10. package/appUtils/HooksManager/{index.js → index.ts} +121 -112
  11. package/appUtils/HooksManager/types.ts +116 -0
  12. package/appUtils/RiverFocusManager/index.js +17 -12
  13. package/appUtils/accessibilityManager/hooks.ts +16 -7
  14. package/appUtils/accessibilityManager/index.ts +33 -28
  15. package/appUtils/focusManager/treeDataStructure/Tree/index.js +2 -3
  16. package/appUtils/focusManager/treeDataStructure/Utils/index.js +1 -3
  17. package/appUtils/{index.js → index.ts} +1 -1
  18. package/appUtils/keyCodes/__tests__/keyCodes.test.js +3 -3
  19. package/appUtils/keyCodes/{index.js → index.ts} +2 -0
  20. package/appUtils/keyCodes/keys/index.ts +3 -0
  21. package/appUtils/keyCodes/{keys.android.js → keys/keyEventMapper.ts} +0 -19
  22. package/appUtils/keyCodes/keys/keys.android.ts +18 -0
  23. package/appUtils/keyCodes/keys/keys.ios.ts +25 -0
  24. package/appUtils/keyCodes/keys/keys.ts +15 -0
  25. package/appUtils/platform/platformUtils.ts +35 -16
  26. package/appUtils/playerManager/index.ts +9 -27
  27. package/appUtils/playerManager/playerFactory.ts +5 -4
  28. package/appUtils/playerManager/playerHooks/usePlayerCurrentTime.tsx +57 -0
  29. package/appUtils/playerManager/playerNative.ts +1 -1
  30. package/appUtils/playerManager/usePlayerControllerSetup.tsx +1 -1
  31. package/appUtils/playerManager/usePlayerState.tsx +19 -34
  32. package/arrayUtils/index.ts +11 -0
  33. package/cellUtils/index.ts +38 -5
  34. package/domUtils/{cookieManager.js → cookieManager.ts} +1 -2
  35. package/focusManager/FocusManager.ts +20 -5
  36. package/focusManager/__tests__/FocusManager.test.ts +0 -1
  37. package/functionUtils/index.ts +53 -11
  38. package/index.d.ts +15 -0
  39. package/manifestUtils/defaultManifestConfigurations/player.js +121 -0
  40. package/manifestUtils/keys.js +2 -1
  41. package/modalState/index.ts +1 -5
  42. package/navigationUtils/index.ts +15 -6
  43. package/numberUtils/__tests__/toNumber.test.ts +2 -2
  44. package/numberUtils/__tests__/toPositiveNumberWithDefault.test.ts +66 -0
  45. package/numberUtils/__tests__/toPositiveNumberWithDefaultZero.test.ts +66 -0
  46. package/numberUtils/index.ts +20 -0
  47. package/package.json +2 -2
  48. package/playerUtils/configurationGenerator.ts +120 -0
  49. package/playerUtils/imaScriptDom.ts +59 -0
  50. package/reactHooks/cell-click/index.ts +17 -3
  51. package/reactHooks/debugging/__tests__/index.test.js +81 -11
  52. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +69 -6
  53. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +10 -2
  54. package/reactHooks/feed/useBatchLoading.ts +52 -28
  55. package/reactHooks/feed/useFeedLoader.tsx +11 -7
  56. package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +134 -0
  57. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -0
  58. package/reactHooks/navigation/index.ts +8 -5
  59. package/reactHooks/player/useAutoSeek.tsx +9 -7
  60. package/reactHooks/resolvers/useCellResolver.ts +5 -1
  61. package/reactHooks/useConfiguration.ts +2 -2
  62. package/reactHooks/utils/index.ts +13 -0
  63. package/reactUtils/index.ts +1 -16
  64. package/services/localStorageServiceSync.web.ts +48 -0
  65. package/services/sessionStorageServiceSync.web.ts +32 -0
  66. package/services/storageServiceSync.web.ts +24 -0
  67. package/services/storageWebUtils.web.ts +10 -0
  68. package/testUtils/index.tsx +42 -9
  69. package/appUtils/keyCodes/keys.ios.js +0 -46
  70. /package/appUtils/HooksManager/{logger.js → logger.ts} +0 -0
  71. /package/appUtils/{directionHelper.js → directionHelper.ts} +0 -0
  72. /package/appUtils/keyCodes/{androidTVKeys.js → androidTVKeys.ts} +0 -0
  73. /package/appUtils/keyCodes/{keys.web.js → keys/keys.web.ts} +0 -0
  74. /package/appUtils/keyCodes/{keysByPlatform.js → keys/keysByPlatform.ts} +0 -0
  75. /package/appUtils/{localizationsHelper.js → localizationsHelper.ts} +0 -0
  76. /package/domUtils/{logger.js → logger.ts} +0 -0
@@ -77,8 +77,6 @@ describe("useBatchLoading", () => {
77
77
 
78
78
  const actions = store.getActions();
79
79
 
80
- expect(useDispatchSpy).toBeCalledTimes(1);
81
-
82
80
  expect(actions).toHaveLength(2);
83
81
 
84
82
  expect(actions[0]).toMatchObject({
@@ -129,6 +127,8 @@ describe("useBatchLoading", () => {
129
127
  // ... more items
130
128
  ];
131
129
 
130
+ expect(useDispatchSpy).toBeCalledTimes(0);
131
+
132
132
  renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
133
133
  wrapper,
134
134
  initialProps: { store },
@@ -136,8 +136,6 @@ describe("useBatchLoading", () => {
136
136
 
137
137
  const actions = store.getActions();
138
138
 
139
- expect(useDispatchSpy).toBeCalledTimes(1);
140
-
141
139
  expect(actions).toHaveLength(1);
142
140
 
143
141
  expect(actions[0]).toMatchObject({
@@ -172,8 +170,6 @@ describe("useBatchLoading", () => {
172
170
  initialProps: { store },
173
171
  });
174
172
 
175
- expect(useDispatchSpy).toBeCalledTimes(1);
176
-
177
173
  const actions = store.getActions();
178
174
 
179
175
  expect(actions).toHaveLength(3);
@@ -218,6 +214,73 @@ describe("useBatchLoading", () => {
218
214
 
219
215
  expect(result.current).toBe(true);
220
216
  });
217
+
218
+ it("gallery-qb: loadPipesData should be called only once for first component in the gallery", () => {
219
+ const store = mockStore({
220
+ zappPipes: {},
221
+ test: "true",
222
+ });
223
+
224
+ useDispatchSpy.mockReturnValue(store.dispatch);
225
+
226
+ const initialBatchSize = 3;
227
+ const riverId = "123";
228
+
229
+ const data = [
230
+ {
231
+ component_type: "gallery-qb",
232
+ ui_components: [{ data: { source: "url1" } }],
233
+ },
234
+ { data: { source: "url2" } },
235
+ { data: { source: "url3" } },
236
+ { data: { source: "url4" } },
237
+ { data: { source: "url5" } },
238
+ { data: { source: "url6" } },
239
+ // ... more items
240
+ ];
241
+
242
+ renderHook(() => useBatchLoading(data, { initialBatchSize, riverId }), {
243
+ wrapper,
244
+ initialProps: { store },
245
+ });
246
+
247
+ const actions = store.getActions();
248
+
249
+ expect(actions).toHaveLength(1);
250
+ });
251
+
252
+ it("gallery-qb: initial batch ready when all initial items loaded", () => {
253
+ const store = mockStore({
254
+ zappPipes: {
255
+ url1: {
256
+ loading: false,
257
+ error: false,
258
+ data: {},
259
+ },
260
+ },
261
+ });
262
+
263
+ useDispatchSpy.mockReturnValue(store.dispatch);
264
+
265
+ const initialBatchSize = 3;
266
+ const riverId = "123";
267
+
268
+ const data: Partial<ZappUIComponent>[] = [
269
+ {
270
+ component_type: "gallery-qb",
271
+ ui_components: [{ data: { source: "url1" } }],
272
+ },
273
+ { data: { source: "url2" } },
274
+ { data: { source: "url3" } },
275
+ ];
276
+
277
+ const { result } = renderHook(
278
+ () => useBatchLoading(data, { initialBatchSize, riverId }),
279
+ { wrapper, initialProps: { store } }
280
+ );
281
+
282
+ expect(result.current).toBe(true);
283
+ });
221
284
  });
222
285
 
223
286
  describe("allFeedsIsReady", () => {
@@ -135,7 +135,11 @@ describe("useFeedLoader", () => {
135
135
  );
136
136
 
137
137
  expect(result.current.data).toBeNull();
138
- expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {});
138
+
139
+ expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {
140
+ clearCache: true,
141
+ riverId: undefined,
142
+ });
139
143
 
140
144
  const store2 = mockStore({
141
145
  plugins: [],
@@ -172,7 +176,11 @@ describe("useFeedLoader", () => {
172
176
  );
173
177
 
174
178
  expect(result.current.data).toBeNull();
175
- expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {});
179
+
180
+ expect(loadPipesDataSpy).toBeCalledWith(feedUrl, {
181
+ clearCache: true,
182
+ riverId: undefined,
183
+ });
176
184
 
177
185
  const store2 = mockStore({
178
186
  plugins: [],
@@ -45,19 +45,23 @@ const filterEmptyData = (data) => {
45
45
  return true;
46
46
  };
47
47
 
48
- const extractData = compose(uniq, map(dataOf));
48
+ const getData = (rawData) =>
49
+ rawData.component_type === "gallery-qb"
50
+ ? rawData.ui_components[0].data
51
+ : rawData.data;
52
+
53
+ const extractData = compose(uniq, map(getData));
49
54
 
50
55
  export const allFeedsIsReady = (
51
56
  feeds: ZappPipesCollection,
52
57
  urls: (ZappDataSourceSource | null)[]
53
58
  ): boolean =>
54
- urls
55
- .filter(complement(isNil))
56
- .map((url) => (url ? checkFeedIsReady(feeds[url]) : false))
57
- .every(Boolean);
59
+ urls.every((url) =>
60
+ isNil(url) ? true : url && feeds[url] ? checkFeedIsReady(feeds[url]) : false
61
+ );
58
62
 
59
63
  export const useBatchLoading = (
60
- data: { data?: ZappDataSource }[],
64
+ componentsToRender: { data?: ZappDataSource; component_type: string }[],
61
65
  options: Options
62
66
  ) => {
63
67
  const dispatch = useDispatch();
@@ -65,10 +69,18 @@ export const useBatchLoading = (
65
69
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
66
70
  const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
67
71
 
68
- const takeBatchSize = take(
69
- min(options.initialBatchSize ?? DEFAULT_BATCH_SIZE, data.length)
70
- );
72
+ // if first component is gallery-qb, take only one component for initial load
73
+ const takeSize =
74
+ componentsToRender?.[0]?.component_type === "gallery-qb"
75
+ ? 1
76
+ : min(
77
+ options.initialBatchSize ?? DEFAULT_BATCH_SIZE,
78
+ componentsToRender.length
79
+ );
80
+
81
+ const takeBatchSize = React.useCallback(take(takeSize), [takeSize]);
71
82
 
83
+ // Prepare inflated url for datasource
72
84
  const getUrl = React.useCallback(
73
85
  (data) => {
74
86
  const mappedFeed = data.mapping
@@ -88,13 +100,16 @@ export const useBatchLoading = (
88
100
  [entryContext, screenContext, searchContext]
89
101
  );
90
102
 
91
- const batchData = takeBatchSize(data);
103
+ // components for initial load
104
+ const batchComponents = takeBatchSize(componentsToRender);
92
105
 
106
+ // contains datasources from batch components loading
93
107
  const feedData: ZappDataSource[] = React.useMemo(
94
- () => extractData(batchData).filter(filterEmptyData),
95
- [batchData]
108
+ () => extractData(batchComponents).filter(filterEmptyData),
109
+ [batchComponents]
96
110
  );
97
111
 
112
+ // contains inflated urls from batch components loading
98
113
  const feedUrls: ZappDataSourceSource[] = React.useMemo(
99
114
  () =>
100
115
  feedData.map((data) => {
@@ -102,34 +117,43 @@ export const useBatchLoading = (
102
117
 
103
118
  return mappedFeedUrl;
104
119
  }),
105
- [] // No watchers as batch loaders is used only for initial load
120
+ []
106
121
  );
107
122
 
108
123
  const feeds = useZappPipesFeeds(feedUrls);
109
124
 
110
- React.useEffect(() => {
111
- const datasources = map(dataOf, batchData)
112
- .filter(filterEmptyData)
113
- .filter((data) => {
114
- const feed = feeds[data.source];
125
+ // dispatch loadPipesData for each feed that is not loaded
126
+ const runBatchLoading = React.useCallback(() => {
127
+ batchComponents.forEach((rawData: any) => {
128
+ // 1. get data (dataOf)
115
129
 
116
- if (!feed) return true;
130
+ const data = getData(rawData);
117
131
 
118
- return !feedHasData(feed) && !feedIsLoading(feed);
119
- });
132
+ // 2. filter out empty data filterEmptyData
133
+ if (!filterEmptyData(data)) return false;
120
134
 
121
- datasources.forEach((data) => {
122
- const mappedFeedUrl = getUrl(data);
135
+ // 3. filter out data that is already loaded (feeds[data.source]) & !feedHasData(feed) && !feedIsLoading(feed);
136
+ const feed = feeds[data?.source];
123
137
 
124
- if (mappedFeedUrl) {
125
- return dispatch(
126
- loadPipesData(mappedFeedUrl, { riverId: options.riverId })
127
- );
138
+ if (!feed || (!feedHasData(feed) && !feedIsLoading(feed))) {
139
+ const mappedFeedUrl = getUrl(data);
140
+
141
+ if (mappedFeedUrl) {
142
+ // 4. load data
143
+ return dispatch(
144
+ loadPipesData(mappedFeedUrl, { riverId: options.riverId })
145
+ );
146
+ }
128
147
  }
129
148
  });
130
- }, []); // No watchers as batch loaders is used only for initial load
149
+ }, [feedUrls]);
150
+
151
+ React.useEffect(() => {
152
+ runBatchLoading();
153
+ }, []);
131
154
 
132
155
  React.useEffect(() => {
156
+ // check if all feeds are ready and set hasEverBeenReady to true
133
157
  if (allFeedsIsReady(feeds, feedUrls) && !hasEverBeenReady) {
134
158
  setHasEverBeenReady(true);
135
159
  }
@@ -1,12 +1,11 @@
1
1
  import React, { useEffect } from "react";
2
- import { path } from "ramda";
3
2
  import { useDispatch } from "react-redux";
4
3
 
5
4
  import { loadPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
6
5
  import { useZappPipesFeed } from "@applicaster/zapp-react-native-redux/hooks";
7
6
 
8
7
  import { reactHooksLogger } from "../logger";
9
- import { useIsInitialRender } from "../utils";
8
+ import { useIsInitialRender, shouldDispatchData } from "../utils";
10
9
  import { useInflatedUrl } from "./useInflatedUrl";
11
10
  import { useRoute } from "../navigation";
12
11
 
@@ -56,8 +55,6 @@ export const useFeedLoader = ({
56
55
 
57
56
  const currentFeed = useZappPipesFeed(callableFeedUrl);
58
57
 
59
- const cachedFeed = React.useMemo(() => path(["data"])(currentFeed), []);
60
-
61
58
  const riverId = screenData?.id;
62
59
 
63
60
  const reloadData = React.useCallback<ReloadDataFunction>(
@@ -92,11 +89,18 @@ export const useFeedLoader = ({
92
89
  }
93
90
  }, [callableFeedUrl, currentFeed?.data]);
94
91
 
95
- // If feed doesn't exist, load it
96
92
  useEffect(() => {
97
- if (!cachedFeed || pipesOptions.clearCache) {
93
+ if (
94
+ shouldDispatchData(callableFeedUrl, currentFeed, pipesOptions.clearCache)
95
+ ) {
98
96
  if (callableFeedUrl) {
99
- dispatch(loadPipesData(callableFeedUrl, { ...pipesOptions, riverId }));
97
+ dispatch(
98
+ loadPipesData(callableFeedUrl, {
99
+ ...pipesOptions,
100
+ clearCache: true,
101
+ riverId,
102
+ })
103
+ );
100
104
  } else {
101
105
  logger.info({
102
106
  message:
@@ -0,0 +1,134 @@
1
+ import { renderHook } from "@testing-library/react-hooks";
2
+ import { Dimensions, StatusBar } from "react-native";
3
+
4
+ const mockUsePickFromState = jest.fn();
5
+ const mockUseIsScreenActive = jest.fn();
6
+ const mockGetInitialDimensions = jest.fn();
7
+ const mockGetDeviceInfo = jest.fn();
8
+
9
+ jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
10
+ ...(jest.requireActual("@applicaster/zapp-react-native-redux/hooks") as {}),
11
+ usePickFromState: mockUsePickFromState,
12
+ }));
13
+
14
+ jest.mock("../../../navigation", () => ({
15
+ useIsScreenActive: mockUseIsScreenActive,
16
+ }));
17
+
18
+ jest.mock("../helpers", () => ({
19
+ getInitialDimensions: mockGetInitialDimensions,
20
+ }));
21
+
22
+ jest.mock("../../getDeviceInfo", () => ({
23
+ getDeviceInfo: mockGetDeviceInfo,
24
+ }));
25
+
26
+ const { useDimensions } = require("../useDimensions");
27
+
28
+ describe("useDimensions", () => {
29
+ const mockDimensions = { width: 100, height: 200, scale: 1, fontScale: 1 };
30
+ const mockAppData = { someData: "test" };
31
+
32
+ beforeEach(() => {
33
+ jest.clearAllMocks();
34
+ Dimensions.get = jest.fn().mockReturnValue(mockDimensions);
35
+
36
+ Dimensions.addEventListener = jest.fn().mockReturnValue({
37
+ remove: jest.fn(),
38
+ });
39
+
40
+ mockUsePickFromState.mockReturnValue({ appData: mockAppData });
41
+ mockUseIsScreenActive.mockReturnValue(true);
42
+ mockGetInitialDimensions.mockReturnValue(mockDimensions);
43
+ mockGetDeviceInfo.mockReturnValue({ deviceInfo: "testDeviceInfo" });
44
+ });
45
+
46
+ it("returns correct initial dimensions", () => {
47
+ const { result } = renderHook(() =>
48
+ useDimensions("window", { fullDimensions: false })
49
+ );
50
+
51
+ expect(result.current).toEqual({
52
+ ...mockDimensions,
53
+ statusBarHeight: StatusBar.currentHeight,
54
+ });
55
+
56
+ expect(mockGetInitialDimensions).toHaveBeenCalledWith("window");
57
+ });
58
+
59
+ it("calls handler on mount", () => {
60
+ renderHook(() => useDimensions("window", { fullDimensions: false }));
61
+
62
+ expect(Dimensions.addEventListener).toHaveBeenCalledWith(
63
+ "change",
64
+ expect.any(Function)
65
+ );
66
+ });
67
+
68
+ it("calls handler on isActive change", () => {
69
+ const { rerender } = renderHook(() =>
70
+ useDimensions("window", { fullDimensions: false })
71
+ );
72
+
73
+ mockUseIsScreenActive.mockReturnValue(false);
74
+ rerender();
75
+
76
+ expect(Dimensions.addEventListener).toHaveBeenCalledWith(
77
+ "change",
78
+ expect.any(Function)
79
+ );
80
+ });
81
+
82
+ it("handles fullDimensions option", () => {
83
+ const { result } = renderHook(() =>
84
+ useDimensions("window", { fullDimensions: true })
85
+ );
86
+
87
+ expect(result.current).toEqual({
88
+ ...mockDimensions,
89
+ scale: 1,
90
+ fontScale: 1,
91
+ statusBarHeight: StatusBar.currentHeight,
92
+ });
93
+ });
94
+
95
+ it("handles excludeStatusBar option", () => {
96
+ const { result } = renderHook(() =>
97
+ useDimensions("window", { excludeStatusBar: true })
98
+ );
99
+
100
+ expect(result.current.height).toBe(
101
+ mockDimensions.height - StatusBar.currentHeight ?? 0
102
+ );
103
+ });
104
+
105
+ it("handles rounded option", () => {
106
+ const { result } = renderHook(() =>
107
+ useDimensions("window", { rounded: true })
108
+ );
109
+
110
+ expect(result.current.width).toBe(Math.ceil(mockDimensions.width));
111
+ expect(result.current.height).toBe(Math.ceil(mockDimensions.height));
112
+ });
113
+
114
+ it("handles deviceInfo option", () => {
115
+ const { result } = renderHook(() =>
116
+ useDimensions("window", { deviceInfo: true })
117
+ );
118
+
119
+ expect(result.current.deviceInfo).toMatchObject({
120
+ deviceInfo: "testDeviceInfo",
121
+ });
122
+ });
123
+
124
+ it("logs deprecation warning when fullDimensions is boolean", () => {
125
+ const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation();
126
+ renderHook(() => useDimensions("window", true));
127
+
128
+ expect(consoleWarnSpy).toHaveBeenCalledWith(
129
+ "Deprecation Warning\nSecond argument is now the options object. {fullDimensions: boolean, ...}"
130
+ );
131
+
132
+ consoleWarnSpy.mockRestore();
133
+ });
134
+ });
@@ -95,6 +95,8 @@ export const useDimensions: UseDimensions = (
95
95
 
96
96
  const activeSubscription = Dimensions.addEventListener("change", handler);
97
97
 
98
+ handler({ [context]: Dimensions.get(context) });
99
+
98
100
  return () => {
99
101
  activeSubscription.remove();
100
102
  };
@@ -17,7 +17,7 @@ import {
17
17
  QUICK_BRICK_NAVBAR,
18
18
  QUICK_BRICK_CONTENT,
19
19
  } from "@applicaster/quick-brick-core/const";
20
- import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/ZappHooksModal";
20
+ import { useZappHooksModalState } from "@applicaster/zapp-react-dom-ui-components/Components/ZappHooksModal/hooks/useZappHooksModalState";
21
21
  import { ZappHookModalContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
22
22
  import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
23
23
  import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
@@ -320,16 +320,19 @@ export const useZappHooksForEntry = (
320
320
  callbacks?.handleHookComplete?.(props);
321
321
  };
322
322
 
323
- const hookManager = HooksManager(hooksOptions)
323
+ const hookManager = HooksManager(hooksOptions);
324
+
325
+ hookManager.subscriber
324
326
  .on(HOOKS_EVENTS.PRESENT_SCREEN_HOOK, handleHookPresent)
325
327
  .on(HOOKS_EVENTS.ERROR, handleHookError)
326
328
  .on(HOOKS_EVENTS.CANCEL, handleHookCancel)
327
329
  .on(HOOKS_EVENTS.START_BACKGROUND_HOOK, handleBackgroundHook)
328
- .on(HOOKS_EVENTS.COMPLETE, handleHookComplete)
329
- .handleHooks(entry);
330
+ .on(HOOKS_EVENTS.COMPLETE, handleHookComplete);
331
+
332
+ hookManager.handleHooks(entry);
330
333
 
331
334
  return () => {
332
- hookManager
335
+ hookManager.subscriber
333
336
  .removeHandler(HOOKS_EVENTS.PRESENT_SCREEN_HOOK, handleHookPresent)
334
337
  .removeHandler(HOOKS_EVENTS.ERROR, handleHookError)
335
338
  .removeHandler(HOOKS_EVENTS.CANCEL, handleHookCancel)
@@ -1,5 +1,4 @@
1
1
  import React, { useEffect, useState } from "react";
2
- import * as R from "ramda";
3
2
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
4
3
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
5
4
  import {
@@ -17,10 +16,6 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
17
16
  const intervalTimer = React.useRef(null);
18
17
  const prevRunning = usePrevious(isRunning);
19
18
 
20
- const setIntervalTimer = (cb) => {
21
- intervalTimer.current = setInterval(cb, ON_HOLD_INTERVAL);
22
- };
23
-
24
19
  const clearIntervalTimer = () => {
25
20
  try {
26
21
  clearInterval(intervalTimer.current);
@@ -29,6 +24,11 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
29
24
  }
30
25
  };
31
26
 
27
+ const setIntervalTimer = (cb) => {
28
+ clearIntervalTimer();
29
+ intervalTimer.current = setInterval(cb, ON_HOLD_INTERVAL);
30
+ };
31
+
32
32
  const resetState = () => {
33
33
  setIsRunning(false);
34
34
  setDirection(null);
@@ -42,7 +42,7 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
42
42
  if (!player) return;
43
43
 
44
44
  if (direction) {
45
- player[direction](R.min(MAX_SEEK_TIME, SKIP_TIME_BASE * multiplier));
45
+ player[direction](Math.min(MAX_SEEK_TIME, SKIP_TIME_BASE * multiplier));
46
46
  resetHUDTimer();
47
47
  }
48
48
  }, [multiplier, direction]);
@@ -50,7 +50,9 @@ export const useAutoSeek = (resetHUDTimer = noop) => {
50
50
  useEffect(() => {
51
51
  if (isRunning && isRunning !== prevRunning) {
52
52
  setIntervalTimer(() => {
53
- setMultiplier(R.add(1));
53
+ setMultiplier((prev) => {
54
+ return prev + 1;
55
+ });
54
56
  });
55
57
  } else if (!isRunning && isRunning !== prevRunning) {
56
58
  resetState();
@@ -48,7 +48,11 @@ export function useCellResolver({
48
48
  ...cellResolverOptions
49
49
  }: Props) {
50
50
  let _component = Object.assign({}, component);
51
- const { width, height } = useDimensions("screen");
51
+
52
+ const { width, height } = useDimensions("screen", {
53
+ updateForInactiveScreens: false,
54
+ });
55
+
52
56
  const { plugins, cellStyles } = usePickFromState(["plugins", "cellStyles"]);
53
57
  const isRTL = useIsRTL();
54
58
 
@@ -67,7 +67,7 @@ export const useConfiguration = ({
67
67
  if (component) {
68
68
  const remappedStylesConfiguration = remapUpdatedKeys(
69
69
  pluginManifest,
70
- component.styles
70
+ component
71
71
  );
72
72
 
73
73
  R.forEachObjIndexed((value, key) => {
@@ -83,7 +83,7 @@ export const useConfiguration = ({
83
83
 
84
84
  const styles = populateConfigurationValues(
85
85
  pluginManifest?.styles?.fields,
86
- remappedStylesConfiguration,
86
+ remappedStylesConfiguration.styles,
87
87
  skipDefaults
88
88
  );
89
89
 
@@ -30,3 +30,16 @@ export const useIsInitialRender = (): boolean => {
30
30
 
31
31
  return isInitialRenderRef.current;
32
32
  };
33
+
34
+ export const checkIsLocalFeed = (feedUrl) => feedUrl?.startsWith("pipesv2://");
35
+
36
+ export const shouldDispatchData = (
37
+ url: string,
38
+ feed: ZappPipesData | null,
39
+ clearCache: boolean
40
+ ) => {
41
+ const currentFeedHasData = feed?.data;
42
+ const isLocalFeed = checkIsLocalFeed(url);
43
+
44
+ return !currentFeedHasData || clearCache || isLocalFeed;
45
+ };
@@ -109,20 +109,6 @@ export const isTvOSPlatform = () => getPlatform() === "tvos";
109
109
 
110
110
  export const isAndroidTVPlatform = () => getPlatform() === "android_tv";
111
111
 
112
- declare global {
113
- interface Window {
114
- VIZIO?: {
115
- Chromevox: {
116
- play: (text: string) => void;
117
- };
118
- exitApplication: () => void;
119
- setClosedCaptionHandler: (
120
- callback: (isCCEnabled: boolean) => void
121
- ) => void;
122
- };
123
- }
124
- }
125
-
126
112
  /**
127
113
  * Platforms found in userAgent string, please note that simulators
128
114
  * might not have the same agents that the devices have
@@ -152,8 +138,7 @@ export const hasTizen = typeof window?.tizen !== "undefined";
152
138
  */
153
139
  export const hasWebOS = typeof window?.webOS !== "undefined";
154
140
 
155
- export const getUserAgent = () =>
156
- window?.navigator?.userAgent || global?.navigator?.userAgent;
141
+ export const getUserAgent = () => window?.navigator?.userAgent;
157
142
 
158
143
  export const isLgPlatform = () => {
159
144
  const userAgent = getUserAgent();
@@ -0,0 +1,48 @@
1
+ import {
2
+ DEFAULT_STORAGE_NAMESPACE,
3
+ getWebStorageKey,
4
+ NAMESPACE_STORAGE_SEPARATOR_WEB,
5
+ } from "./storageWebUtils.web";
6
+
7
+ export function saveSync(
8
+ key: string,
9
+ value: string,
10
+ namespace: string = DEFAULT_STORAGE_NAMESPACE
11
+ ) {
12
+ const storageWebKey = getWebStorageKey(key, namespace);
13
+
14
+ return localStorage.setItem(storageWebKey, value);
15
+ }
16
+
17
+ export function getSync(
18
+ key: string,
19
+ namespace: string = DEFAULT_STORAGE_NAMESPACE
20
+ ) {
21
+ const storageWebKey = getWebStorageKey(key, namespace);
22
+
23
+ return localStorage.getItem(storageWebKey);
24
+ }
25
+
26
+ export function getAllSync(namespace: string = DEFAULT_STORAGE_NAMESPACE) {
27
+ const allItems = {};
28
+
29
+ for (let i = 0; i < localStorage.length; i++) {
30
+ const key = localStorage.key(i);
31
+
32
+ if (key && key.startsWith(namespace + NAMESPACE_STORAGE_SEPARATOR_WEB)) {
33
+ const itemKey = key.split(NAMESPACE_STORAGE_SEPARATOR_WEB)[1];
34
+ allItems[itemKey] = localStorage.getItem(key);
35
+ }
36
+ }
37
+
38
+ return allItems;
39
+ }
40
+
41
+ export function removeSync(
42
+ key: string,
43
+ namespace: string = DEFAULT_STORAGE_NAMESPACE
44
+ ) {
45
+ const storageWebKey = getWebStorageKey(key, namespace);
46
+
47
+ return localStorage.removeItem(storageWebKey);
48
+ }