@applicaster/zapp-react-native-utils 15.0.0-alpha.3514407021 → 15.0.0-alpha.3564377339

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 (61) hide show
  1. package/actionsExecutor/ActionExecutorContext.tsx +3 -6
  2. package/actionsExecutor/feedDecorator.ts +6 -6
  3. package/adsUtils/index.ts +2 -2
  4. package/analyticsUtils/README.md +1 -1
  5. package/appUtils/HooksManager/index.ts +10 -10
  6. package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
  7. package/appUtils/accessibilityManager/const.ts +4 -0
  8. package/appUtils/accessibilityManager/hooks.ts +20 -13
  9. package/appUtils/accessibilityManager/index.ts +28 -1
  10. package/appUtils/accessibilityManager/utils.ts +59 -8
  11. package/appUtils/focusManager/index.ios.ts +8 -2
  12. package/appUtils/focusManagerAux/utils/index.ts +1 -1
  13. package/appUtils/focusManagerAux/utils/utils.ios.ts +60 -3
  14. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  15. package/appUtils/orientationHelper.ts +2 -4
  16. package/appUtils/platform/platformUtils.ts +117 -18
  17. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
  18. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  19. package/appUtils/playerManager/player.ts +4 -0
  20. package/appUtils/playerManager/playerNative.ts +29 -16
  21. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  22. package/cellUtils/index.ts +32 -0
  23. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  24. package/focusManager/aux/index.ts +1 -1
  25. package/manifestUtils/defaultManifestConfigurations/player.js +75 -1
  26. package/manifestUtils/keys.js +21 -0
  27. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  28. package/manifestUtils/tvAction/container/index.js +1 -1
  29. package/package.json +2 -2
  30. package/playerUtils/usePlayerTTS.ts +8 -3
  31. package/pluginUtils/index.ts +4 -0
  32. package/reactHooks/advertising/index.ts +2 -2
  33. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  34. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  35. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +3 -0
  36. package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
  37. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  38. package/reactHooks/feed/useInflatedUrl.ts +43 -17
  39. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  40. package/reactHooks/layout/index.ts +1 -1
  41. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  42. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  43. package/reactHooks/navigation/index.ts +7 -6
  44. package/reactHooks/navigation/useRoute.ts +8 -6
  45. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  46. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  47. package/reactHooks/resolvers/useComponentResolver.ts +8 -2
  48. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +10 -2
  49. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  50. package/reactHooks/state/useRivers.ts +1 -1
  51. package/reactHooks/usePluginConfiguration.ts +2 -2
  52. package/testUtils/index.tsx +29 -20
  53. package/utils/__tests__/mapAccum.test.ts +73 -0
  54. package/utils/__tests__/selectors.test.ts +124 -0
  55. package/utils/index.ts +14 -0
  56. package/utils/mapAccum.ts +23 -0
  57. package/utils/path.ts +6 -3
  58. package/utils/pathOr.ts +5 -1
  59. package/utils/selectors.ts +46 -0
  60. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +34 -11
  61. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
@@ -27,20 +27,20 @@ describe("Debug utils", () => {
27
27
  it("should create new timer if timer with a label does not exist", () => {
28
28
  performanceNowMock.mockReturnValue(1000);
29
29
  time("timer1");
30
- expect(timers["timer1"]).toBeDefined();
31
- expect(timers["timer1"].startTime).toBe(1000);
30
+ expect(timers.timer1).toBeDefined();
31
+ expect(timers.timer1.startTime).toBe(1000);
32
32
  });
33
33
 
34
34
  it("should update start time of timer if timer with a label exists", () => {
35
35
  // First call to time()
36
36
  performanceNowMock.mockReturnValue(1000);
37
37
  time("timer1");
38
- const previousStartTime = timers["timer1"].startTime;
38
+ const previousStartTime = timers.timer1.startTime;
39
39
 
40
40
  // Second call to time()
41
41
  performanceNowMock.mockReturnValue(2000);
42
42
  time("timer1");
43
- const currentStartTime = timers["timer1"].startTime;
43
+ const currentStartTime = timers.timer1.startTime;
44
44
 
45
45
  expect(previousStartTime).toBe(1000);
46
46
  expect(currentStartTime).toBe(2000);
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
3
2
  import { useIsTablet } from "./useIsTablet";
3
+ import { useAppData } from "@applicaster/zapp-react-native-redux";
4
4
 
5
5
  export const useMemoizedIsTablet = () => {
6
6
  const isTablet = useIsTablet();
@@ -14,9 +14,9 @@ export const useMemoizedIsTablet = () => {
14
14
  };
15
15
 
16
16
  export const useIsTabletLandscape = (): boolean => {
17
- const { appData } = usePickFromState(["appData"]);
17
+ const { isTabletPortrait } = useAppData();
18
18
 
19
19
  const isTablet = useIsTablet();
20
20
 
21
- return isTablet && !appData.isTabletPortrait;
21
+ return isTablet && !isTabletPortrait;
22
22
  };
@@ -10,6 +10,9 @@ describe("useEntryScreenId", () => {
10
10
  const mappedScreenId = "mapped-id";
11
11
 
12
12
  const initialState = {
13
+ rivers: {
14
+ [mappedScreenId]: { id: mappedScreenId, type: "any" },
15
+ },
13
16
  contentTypes: { mappedEntry: { screen_id: mappedScreenId } },
14
17
  };
15
18
 
@@ -1,3 +1,34 @@
1
+ import React from "react";
2
+
3
+ import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
4
+
5
+ import {
6
+ getInflatedDataSourceUrl,
7
+ getSearchContext,
8
+ useGetUrlInflater,
9
+ } from "../useInflatedUrl";
10
+
11
+ import { reactHooksLogger } from "../../logger";
12
+
13
+ jest.mock("../../navigation", () => ({
14
+ useRoute: () => ({ pathname: "/mock/path" }),
15
+ }));
16
+
17
+ // mock contexts hooks
18
+ jest.mock("@applicaster/zapp-react-native-ui-components/Contexts", () => ({
19
+ ZappPipesEntryContext: {
20
+ useZappPipesContext: () => [
21
+ { id: "entry-1", extensions: { showId: "A123" } },
22
+ ],
23
+ },
24
+ ZappPipesSearchContext: {
25
+ useZappPipesContext: () => ["user%20query"],
26
+ },
27
+ ZappPipesScreenContext: {
28
+ useZappPipesContext: () => [{ id: "screen-1" }],
29
+ },
30
+ }));
31
+
1
32
  jest.mock("../../logger", () => ({
2
33
  reactHooksLogger: {
3
34
  warning: jest.fn(),
@@ -5,13 +36,6 @@ jest.mock("../../logger", () => ({
5
36
  },
6
37
  }));
7
38
 
8
- const {
9
- getInflatedDataSourceUrl,
10
- getSearchContext,
11
- } = require("../useInflatedUrl");
12
-
13
- const { reactHooksLogger } = require("../../logger");
14
-
15
39
  let mockStore;
16
40
 
17
41
  describe("getInflatedDataSourceUrl", () => {
@@ -188,3 +212,34 @@ describe("getSearchContext", () => {
188
212
  expect(result).toHaveProperty(mapping.queryParam.property, searchContext);
189
213
  });
190
214
  });
215
+
216
+ describe("useGetUrlInflater", () => {
217
+ const { renderHook } = require("@testing-library/react-hooks");
218
+
219
+ it("returns original url when mapping is not provided", () => {
220
+ const { result } = renderHook(() => useGetUrlInflater(), {
221
+ wrapper: WrappedWithProviders,
222
+ });
223
+
224
+ const src = "https://foo.com/feed";
225
+ expect(result.current(src)).toBe(src);
226
+ });
227
+
228
+ it("inflates url using entry/search/screen contexts when mapping provided", () => {
229
+ const { result } = renderHook(() => useGetUrlInflater(), {
230
+ wrapper: ({ children }) => (
231
+ <WrappedWithProviders>{children}</WrappedWithProviders>
232
+ ),
233
+ });
234
+
235
+ const source = "https://foo.com/shows/{{showId}}?q={{q}}";
236
+
237
+ const mapping = {
238
+ showId: { source: "entry", property: "extensions.showId" },
239
+ q: { source: "search", property: "q" },
240
+ };
241
+
242
+ const url = result.current(source, mapping);
243
+ expect(url).toBe("https://foo.com/shows/A123?q=user%20query");
244
+ });
245
+ });
@@ -1,7 +1,7 @@
1
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
1
+ import { useContentTypes } from "@applicaster/zapp-react-native-redux";
2
2
 
3
3
  export const useEntryScreenId = (entry?: ZappEntry): string | undefined => {
4
- const { contentTypes } = usePickFromState("contentTypes");
4
+ const contentTypes = useContentTypes();
5
5
 
6
6
  if (!entry) {
7
7
  return;
@@ -1,4 +1,4 @@
1
- import { useMemo } from "react";
1
+ import { useCallback, useMemo, useRef } from "react";
2
2
  import * as R from "ramda";
3
3
 
4
4
  import {
@@ -169,7 +169,7 @@ const encodeIfNeeded: (string) => string = R.tryCatch(
169
169
 
170
170
  export function getSearchContext(
171
171
  searchContext: string,
172
- mapping: ZappTypeMapping
172
+ mapping: Nullable<ZappTypeMapping>
173
173
  ) {
174
174
  if (!mapping) {
175
175
  return {};
@@ -183,31 +183,57 @@ export function getSearchContext(
183
183
  return { [property]: encodeIfNeeded(searchContext) };
184
184
  }
185
185
 
186
- export function useInflatedUrl({
187
- feedUrl,
188
- mapping,
189
- }: {
190
- feedUrl?: string;
191
- mapping?: ZappTypeMapping;
192
- }) {
186
+ /**
187
+ * Hook returns a function that replace placeholders with context values
188
+ * @returns function that inflates urls based on contexts
189
+ */
190
+ export const useGetUrlInflater = () => {
193
191
  const { pathname } = useRoute();
194
192
 
195
193
  const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname);
196
194
  const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
197
195
  const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
198
196
 
199
- const url = useMemo(
200
- () =>
201
- getInflatedDataSourceUrl({
197
+ const entryContextRef = useRef(entryContext);
198
+ entryContextRef.current = entryContext;
199
+
200
+ const screenContextRef = useRef(screenContext);
201
+ screenContextRef.current = screenContext;
202
+
203
+ const searchContextRef = useRef(searchContext);
204
+ searchContextRef.current = searchContext;
205
+
206
+ return useCallback(
207
+ (
208
+ feedUrl: Nullable<string>,
209
+ mapping?: Nullable<ZappTypeMapping>
210
+ ): Nullable<string> => {
211
+ return getInflatedDataSourceUrl({
202
212
  source: feedUrl,
203
213
  contexts: {
204
- entry: entryContext,
205
- screen: screenContext,
206
- search: getSearchContext(searchContext, mapping),
214
+ entry: entryContextRef.current,
215
+ screen: screenContextRef.current,
216
+ search: getSearchContext(searchContextRef.current, mapping),
207
217
  },
208
218
  mapping,
209
- }),
210
- [entryContext, feedUrl, mapping, screenContext, searchContext]
219
+ });
220
+ },
221
+ []
222
+ );
223
+ };
224
+
225
+ export function useInflatedUrl({
226
+ feedUrl,
227
+ mapping,
228
+ }: {
229
+ feedUrl?: string;
230
+ mapping?: ZappTypeMapping;
231
+ }) {
232
+ const urlInflater = useGetUrlInflater();
233
+
234
+ const url = useMemo(
235
+ () => urlInflater(feedUrl, mapping),
236
+ [urlInflater, feedUrl, mapping]
211
237
  );
212
238
 
213
239
  return url;
@@ -1,10 +1,8 @@
1
1
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
2
2
  import React from "react";
3
3
 
4
- type Return = (index: number) => void;
5
-
6
4
  type Predicate = (
7
- entry: ZappUIComponentProps["zappPipesData"]["data"]["entry"],
5
+ entryLength: number,
8
6
  index: number,
9
7
  numberOfColumns: number
10
8
  ) => boolean;
@@ -12,19 +10,15 @@ type Predicate = (
12
10
  type Props = {
13
11
  ifNeeded: Predicate;
14
12
  loadNextData: () => void;
15
- entry: ZappUIComponentProps["zappPipesData"]["data"]["entry"];
13
+ entryLength: number;
16
14
  numberOfColumns?: number;
17
15
  };
18
16
 
19
17
  const handleLoadNextPage =
20
18
  (
21
- ifNeeded: (
22
- entry: ZappEntry[],
23
- index: number,
24
- numberOfColumns?: number
25
- ) => boolean,
19
+ ifNeeded: Predicate,
26
20
  loadNextData: () => void,
27
- entry: ZappEntry[],
21
+ entryLength: number,
28
22
  numberOfColumns
29
23
  ) =>
30
24
  (index: number) => {
@@ -32,7 +26,7 @@ const handleLoadNextPage =
32
26
  * Lazy-Loading, invoke nextLoadData if we reach the end of the List
33
27
  */
34
28
 
35
- if (ifNeeded(entry, index, numberOfColumns)) {
29
+ if (ifNeeded(entryLength, index, numberOfColumns)) {
36
30
  loadNextData();
37
31
  }
38
32
  };
@@ -40,11 +34,14 @@ const handleLoadNextPage =
40
34
  export const useLoadNextPageIfNeeded = ({
41
35
  ifNeeded,
42
36
  loadNextData = noop,
43
- entry,
37
+ entryLength,
44
38
  numberOfColumns = 0,
45
- }: Props): Return => {
46
- return React.useCallback(
47
- handleLoadNextPage(ifNeeded, loadNextData, entry, numberOfColumns),
48
- [ifNeeded, loadNextData, entry, numberOfColumns]
39
+ }: Props) => {
40
+ const memoFn = React.useMemo(
41
+ () =>
42
+ handleLoadNextPage(ifNeeded, loadNextData, entryLength, numberOfColumns),
43
+ [ifNeeded, loadNextData, entryLength, numberOfColumns]
49
44
  );
45
+
46
+ return memoFn;
50
47
  };
@@ -44,7 +44,7 @@ export function useStatusBarHeight() {
44
44
 
45
45
  return platformSelect({
46
46
  ios: StatusBarHeight,
47
- android: StatusBar.currentHeight,
47
+ android: StatusBar.currentHeight ?? 0,
48
48
  default: 0,
49
49
  });
50
50
  }
@@ -1,16 +1,10 @@
1
- import { renderHook } from "@testing-library/react-hooks";
1
+ import React from "react";
2
+ import { renderHook } from "@testing-library/react-native";
2
3
  import { Dimensions, StatusBar } from "react-native";
3
4
  import { useDimensions } from "../useDimensions";
4
- import { usePickFromState } from "@applicaster/zapp-react-native-redux";
5
5
 
6
6
  import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive";
7
-
8
- jest.mock("@applicaster/zapp-react-native-redux/hooks", () => {
9
- return {
10
- ...jest.requireActual("@applicaster/zapp-react-native-redux/hooks"),
11
- usePickFromState: jest.fn(),
12
- };
13
- });
7
+ import { WrappedWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
14
8
 
15
9
  jest.mock(
16
10
  "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
@@ -42,12 +36,22 @@ describe("useDimensions", () => {
42
36
 
43
37
  beforeEach(() => {
44
38
  StatusBar.currentHeight = 20;
45
- (usePickFromState as jest.Mock).mockReturnValue({ appData: mockAppData });
46
39
  });
47
40
 
48
41
  it("returns correct initial dimensions", () => {
49
- const { result } = renderHook(() =>
50
- useDimensions("window", { fullDimensions: false })
42
+ const { result } = renderHook(
43
+ () => useDimensions("window", { fullDimensions: false }),
44
+ {
45
+ wrapper: ({ children }) => (
46
+ <WrappedWithProviders
47
+ store={{
48
+ appData: mockAppData,
49
+ }}
50
+ >
51
+ {children}
52
+ </WrappedWithProviders>
53
+ ),
54
+ }
51
55
  );
52
56
 
53
57
  expect(result.current).toMatchObject({
@@ -56,7 +60,17 @@ describe("useDimensions", () => {
56
60
  });
57
61
 
58
62
  it("calls handler on mount", () => {
59
- renderHook(() => useDimensions("window", { fullDimensions: false }));
63
+ renderHook(() => useDimensions("window", { fullDimensions: false }), {
64
+ wrapper: ({ children }) => (
65
+ <WrappedWithProviders
66
+ store={{
67
+ appData: mockAppData,
68
+ }}
69
+ >
70
+ {children}
71
+ </WrappedWithProviders>
72
+ ),
73
+ });
60
74
 
61
75
  expect(Dimensions.addEventListener).toHaveBeenCalledWith(
62
76
  "change",
@@ -65,12 +79,23 @@ describe("useDimensions", () => {
65
79
  });
66
80
 
67
81
  it("calls handler on isActive change", () => {
68
- const { rerender } = renderHook(() =>
69
- useDimensions("window", { fullDimensions: false })
82
+ const { rerender } = renderHook(
83
+ () => useDimensions("window", { fullDimensions: false }),
84
+ {
85
+ wrapper: ({ children }) => (
86
+ <WrappedWithProviders
87
+ store={{
88
+ appData: mockAppData,
89
+ }}
90
+ >
91
+ {children}
92
+ </WrappedWithProviders>
93
+ ),
94
+ }
70
95
  );
71
96
 
72
97
  (useIsScreenActive as jest.Mock).mockReturnValue(false);
73
- rerender();
98
+ rerender({});
74
99
 
75
100
  expect(Dimensions.addEventListener).toHaveBeenCalledWith(
76
101
  "change",
@@ -79,8 +104,19 @@ describe("useDimensions", () => {
79
104
  });
80
105
 
81
106
  it("handles fullDimensions option", () => {
82
- const { result } = renderHook(() =>
83
- useDimensions("window", { fullDimensions: true })
107
+ const { result } = renderHook(
108
+ () => useDimensions("window", { fullDimensions: true }),
109
+ {
110
+ wrapper: ({ children }) => (
111
+ <WrappedWithProviders
112
+ store={{
113
+ appData: mockAppData,
114
+ }}
115
+ >
116
+ {children}
117
+ </WrappedWithProviders>
118
+ ),
119
+ }
84
120
  );
85
121
 
86
122
  expect(result.current).toMatchObject({
@@ -91,8 +127,19 @@ describe("useDimensions", () => {
91
127
  });
92
128
 
93
129
  it("handles excludeStatusBar option", () => {
94
- const { result } = renderHook(() =>
95
- useDimensions("window", { excludeStatusBar: true })
130
+ const { result } = renderHook(
131
+ () => useDimensions("window", { excludeStatusBar: true }),
132
+ {
133
+ wrapper: ({ children }) => (
134
+ <WrappedWithProviders
135
+ store={{
136
+ appData: mockAppData,
137
+ }}
138
+ >
139
+ {children}
140
+ </WrappedWithProviders>
141
+ ),
142
+ }
96
143
  );
97
144
 
98
145
  expect(result.current.height).toBe(
@@ -101,8 +148,19 @@ describe("useDimensions", () => {
101
148
  });
102
149
 
103
150
  it("handles rounded option", () => {
104
- const { result } = renderHook(() =>
105
- useDimensions("window", { rounded: true })
151
+ const { result } = renderHook(
152
+ () => useDimensions("window", { rounded: true }),
153
+ {
154
+ wrapper: ({ children }) => (
155
+ <WrappedWithProviders
156
+ store={{
157
+ appData: mockAppData,
158
+ }}
159
+ >
160
+ {children}
161
+ </WrappedWithProviders>
162
+ ),
163
+ }
106
164
  );
107
165
 
108
166
  expect(result.current.width).toBe(Math.ceil(mockDimensions.width));
@@ -110,8 +168,19 @@ describe("useDimensions", () => {
110
168
  });
111
169
 
112
170
  it("handles deviceInfo option", () => {
113
- const { result } = renderHook(() =>
114
- useDimensions("window", { deviceInfo: true })
171
+ const { result } = renderHook(
172
+ () => useDimensions("window", { deviceInfo: true }),
173
+ {
174
+ wrapper: ({ children }) => (
175
+ <WrappedWithProviders
176
+ store={{
177
+ appData: mockAppData,
178
+ }}
179
+ >
180
+ {children}
181
+ </WrappedWithProviders>
182
+ ),
183
+ }
115
184
  );
116
185
 
117
186
  expect(result.current.deviceInfo).toMatchObject({
@@ -121,7 +190,18 @@ describe("useDimensions", () => {
121
190
 
122
191
  it("logs deprecation warning when fullDimensions is boolean", () => {
123
192
  const consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation();
124
- renderHook(() => useDimensions("window", true));
193
+
194
+ renderHook(() => useDimensions("window", true), {
195
+ wrapper: ({ children }) => (
196
+ <WrappedWithProviders
197
+ store={{
198
+ appData: mockAppData,
199
+ }}
200
+ >
201
+ {children}
202
+ </WrappedWithProviders>
203
+ ),
204
+ });
125
205
 
126
206
  expect(consoleWarnSpy).toHaveBeenCalledWith(
127
207
  "Deprecation Warning\nSecond argument is now the options object. {fullDimensions: boolean, ...}"
@@ -3,7 +3,7 @@ import { useLayoutEffect, useMemo, useRef, useState } from "react";
3
3
  import * as R from "ramda";
4
4
 
5
5
  import { Dimensions, Platform, StatusBar } from "react-native";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import { useAppData } from "@applicaster/zapp-react-native-redux/hooks";
7
7
 
8
8
  import { isTV } from "../../../reactUtils";
9
9
 
@@ -37,7 +37,7 @@ export const useDimensions: UseDimensions = (
37
37
  ) => {
38
38
  const statusBarHeight = StatusBar?.currentHeight;
39
39
  const isActive = useIsScreenActive();
40
- const { appData } = usePickFromState(["appData"]);
40
+ const appData = useAppData();
41
41
 
42
42
  if (typeof fullDimensions === "boolean") {
43
43
  // eslint-disable-next-line no-console
@@ -3,7 +3,7 @@ import { BackHandler } from "react-native";
3
3
 
4
4
  import {
5
5
  useContentTypes,
6
- usePickFromState,
6
+ usePlugins,
7
7
  } from "@applicaster/zapp-react-native-redux/hooks";
8
8
  import { HooksManager } from "@applicaster/zapp-react-native-utils/appUtils/HooksManager";
9
9
 
@@ -16,6 +16,8 @@ import { useConnectionInfo } from "../connection";
16
16
 
17
17
  import { isTV, isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
18
18
  import { useNavbarState } from "../screen";
19
+ import { useRivers } from "../state";
20
+ import { useLayoutVersion } from "../layout";
19
21
 
20
22
  export { useNavigation } from "./useNavigation";
21
23
 
@@ -164,11 +166,10 @@ export const useZappHooksForEntry = (
164
166
  setIsRunningInBackground,
165
167
  }: HookModalContextT = useContext(ZappHookModalContext.ReactContext);
166
168
 
167
- const {
168
- appData: { layoutVersion },
169
- rivers,
170
- plugins,
171
- } = usePickFromState(["appData", "rivers", "plugins"]);
169
+ const plugins = usePlugins();
170
+ const rivers = useRivers();
171
+
172
+ const layoutVersion = useLayoutVersion();
172
173
 
173
174
  const contentTypes = useContentTypes();
174
175
 
@@ -3,7 +3,10 @@
3
3
 
4
4
  import { useContext } from "react";
5
5
 
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import {
7
+ useContentTypes,
8
+ usePlugins,
9
+ } from "@applicaster/zapp-react-native-redux/hooks";
7
10
 
8
11
  import { legacyScreenData } from "@applicaster/quick-brick-core/App/NavigationProvider/utils";
9
12
 
@@ -14,6 +17,7 @@ import { useNavigation } from "./useNavigation";
14
17
  import { useModalStoreState } from "../../modalState";
15
18
  import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
16
19
  import { usePathname } from "./usePathname";
20
+ import { useRivers } from "../state";
17
21
 
18
22
  // starts with modal/
19
23
  const isModalPathname = (pathname: string) => /^modal\//.test(pathname);
@@ -42,11 +46,9 @@ export const useRoute = (
42
46
  ? legacyScreenData(screenContext)
43
47
  : screenContext;
44
48
 
45
- const { plugins, contentTypes, rivers } = usePickFromState([
46
- "plugins",
47
- "rivers",
48
- "contentTypes",
49
- ]);
49
+ const plugins = usePlugins();
50
+ const rivers = useRivers();
51
+ const contentTypes = useContentTypes();
50
52
 
51
53
  const modalState = useModalStoreState();
52
54
 
@@ -147,17 +147,34 @@ export class TVSeekController
147
147
 
148
148
  let targetPos = currentPos;
149
149
 
150
- if (this.currentSeekType === SEEK_TYPE.FORWARD) {
151
- targetPos = Math.min(
152
- currentPos + offset,
153
- this.playerController.getSeekableDuration()
154
- );
155
- } else if (this.currentSeekType === SEEK_TYPE.REWIND) {
156
- targetPos = Math.max(0, currentPos - offset);
150
+ const isLive = this.playerController.isLive();
151
+
152
+ if (isLive) {
153
+ if (this.currentSeekType === SEEK_TYPE.REWIND) {
154
+ targetPos = Math.min(
155
+ currentPos + offset,
156
+ this.playerController.getSeekableDuration()
157
+ );
158
+ } else if (this.currentSeekType === SEEK_TYPE.FORWARD) {
159
+ targetPos = Math.max(0, currentPos - offset);
160
+ } else {
161
+ log_warning(
162
+ `TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
163
+ );
164
+ }
157
165
  } else {
158
- log_warning(
159
- `TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
160
- );
166
+ if (this.currentSeekType === SEEK_TYPE.FORWARD) {
167
+ targetPos = Math.min(
168
+ currentPos + offset,
169
+ this.playerController.getSeekableDuration()
170
+ );
171
+ } else if (this.currentSeekType === SEEK_TYPE.REWIND) {
172
+ targetPos = Math.max(0, currentPos - offset);
173
+ } else {
174
+ log_warning(
175
+ `TVSeekController: handleDelayedSeek - invalid seek type: ${this.currentSeekType}`
176
+ );
177
+ }
161
178
  }
162
179
 
163
180
  log_debug(
@@ -3,7 +3,10 @@ import memoizee from "memoizee";
3
3
  import * as R from "ramda";
4
4
 
5
5
  import { CellRendererResolver } from "@applicaster/zapp-react-native-ui-components/Components/CellRendererResolver";
6
- import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
6
+ import {
7
+ usePlugins,
8
+ useCellStyles,
9
+ } from "@applicaster/zapp-react-native-redux";
7
10
  import { useDimensions } from "../layout";
8
11
  import { useIsRTL } from "../../localizationUtils";
9
12
 
@@ -53,7 +56,8 @@ export function useCellResolver({
53
56
  updateForInactiveScreens: false,
54
57
  });
55
58
 
56
- const { plugins, cellStyles } = usePickFromState(["plugins", "cellStyles"]);
59
+ const plugins = usePlugins();
60
+ const cellStyles = useCellStyles();
57
61
  const isRTL = useIsRTL();
58
62
 
59
63
  const options = {