@applicaster/zapp-react-native-ui-components 13.0.0-alpha.7222980745 → 13.0.0-alpha.7223143213

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 (112) hide show
  1. package/Components/AppContainer/__tests__/AppContainer.test.js +4 -6
  2. package/Components/AudioPlayer/AudioPlayer.tsx +7 -0
  3. package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
  4. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +54 -111
  5. package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +36 -20
  6. package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
  7. package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
  8. package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
  9. package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
  10. package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
  11. package/Components/AudioPlayer/__tests__/title.test.js +3 -5
  12. package/Components/AudioPlayer/helpers.tsx +1 -0
  13. package/Components/BaseFocusable/index.tsx +1 -2
  14. package/Components/Cell/Cell.tsx +1 -0
  15. package/Components/Cell/CellWithFocusable.tsx +2 -1
  16. package/Components/Cell/TvOSCellComponent.tsx +20 -22
  17. package/Components/Cell/index.js +3 -1
  18. package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +46 -48
  19. package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
  20. package/Components/ComponentResolver/__tests__/componentResolver.test.js +16 -22
  21. package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
  22. package/Components/ErrorScreen/index.tsx +6 -6
  23. package/Components/Focusable/Focusable.tsx +1 -0
  24. package/Components/Focusable/FocusableTvOS.tsx +5 -1
  25. package/Components/Focusable/index.android.tsx +10 -3
  26. package/Components/FocusableCell/index.tsx +1 -1
  27. package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
  28. package/Components/FocusableGroup/index.tsx +0 -3
  29. package/Components/FocusableList/index.tsx +26 -9
  30. package/Components/FocusableScrollView/index.tsx +43 -13
  31. package/Components/Layout/TV/NavBarContainer.tsx +19 -23
  32. package/Components/Layout/TV/ScreenContainer.tsx +8 -1
  33. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
  34. package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +2 -1
  35. package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +3 -2
  36. package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +3 -2
  37. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
  38. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
  39. package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
  40. package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +4 -12
  41. package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +0 -229
  42. package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
  43. package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
  44. package/Components/MasterCell/utils/behaviorProvider.ts +139 -0
  45. package/Components/MasterCell/utils/index.ts +8 -134
  46. package/Components/ModalComponent/Button/index.tsx +6 -6
  47. package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
  48. package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
  49. package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
  50. package/Components/PlayerContainer/PlayerContainer.tsx +26 -13
  51. package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
  52. package/Components/PlayerImageBackground/index.tsx +1 -1
  53. package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -0
  54. package/Components/River/ComponentsMap/hooks/useLoadingState.ts +3 -3
  55. package/Components/River/TV/index.tsx +6 -1
  56. package/Components/River/__tests__/__snapshots__/river.test.js.snap +20 -82
  57. package/Components/River/__tests__/river.test.js +75 -40
  58. package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +11 -4
  59. package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
  60. package/Components/RouteManager/__tests__/testId.test.js +8 -6
  61. package/Components/Screen/TV/index.web.tsx +5 -6
  62. package/Components/Screen/hooks.ts +3 -6
  63. package/Components/Screen/index.tsx +4 -4
  64. package/Components/ScreenResolver/__tests__/screenResolver.test.js +91 -70
  65. package/Components/Tabs/Tab.tsx +5 -3
  66. package/Components/TextInputTv/index.tsx +2 -1
  67. package/Components/TrackedView/index.tsx +1 -0
  68. package/Components/Transitioner/AnimationManager.js +15 -15
  69. package/Components/Transitioner/Scene.tsx +1 -1
  70. package/Components/Transitioner/Transitioner.tsx +3 -3
  71. package/Components/Transitioner/__tests__/Scene.test.js +25 -14
  72. package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -68
  73. package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
  74. package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
  75. package/Components/VideoLive/PlayerLiveImageComponent.tsx +7 -3
  76. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
  77. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
  78. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +44 -30
  79. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +3 -3
  80. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +24 -11
  81. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +2 -2
  82. package/Components/VideoModal/PlayerDetails.tsx +9 -6
  83. package/Components/VideoModal/PlayerWrapper.tsx +2 -2
  84. package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
  85. package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
  86. package/Components/Viewport/__tests__/utils.test.js +5 -4
  87. package/Components/ZappUIComponent/Placeholder.tsx +3 -1
  88. package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
  89. package/Components/ZappUIComponent/index.tsx +3 -16
  90. package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
  91. package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
  92. package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
  93. package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
  94. package/Contexts/HeaderOffsetContext/index.tsx +4 -6
  95. package/Contexts/ScreenContext/index.tsx +3 -10
  96. package/Contexts/ScreenLayoutContext/index.tsx +5 -3
  97. package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
  98. package/Decorators/Navigator/index.tsx +1 -1
  99. package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +18 -24
  100. package/Decorators/RiverResolver/index.tsx +6 -8
  101. package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
  102. package/Decorators/ZappPipesDataConnector/index.tsx +2 -29
  103. package/package.json +7 -10
  104. package/tsconfig.json +2 -3
  105. package/Components/Cell/CellWithFocusable.ios.tsx +0 -126
  106. package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
  107. package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
  108. package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
  109. package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
  110. package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
  111. package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
  112. package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
@@ -1,16 +1,25 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { shallow } from "enzyme";
4
- import { shallowToJson } from "enzyme-to-json";
3
+ import { renderWithProviders } from "@applicaster/zapp-react-native-utils/testUtils";
5
4
 
6
5
  import { testCellStyle } from "./TestCellStyle";
7
6
  import { singleView } from "./SingleView";
8
7
  import { entry } from "./testEntry";
9
8
  import { singleElement } from "./testElements";
10
9
 
11
- jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
12
- useRoute: jest.fn(() => ({ screenData: { id: "test" } })),
13
- }));
10
+ jest.mock(
11
+ "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute",
12
+ () => ({
13
+ useRoute: jest.fn(() => ({ screenData: { id: "test" } })),
14
+ })
15
+ );
16
+
17
+ jest.mock(
18
+ "@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
19
+ () => ({
20
+ useIsScreenActive: jest.fn(() => true),
21
+ })
22
+ );
14
23
 
15
24
  jest.mock("@applicaster/zapp-react-native-utils/screenState", () => ({
16
25
  useScreenState: jest.fn(() => ({
@@ -27,36 +36,27 @@ describe("masterCellBuilder", () => {
27
36
  describe("when using default options", () => {
28
37
  const MasterCell = masterCellBuilder({ cellConfiguration: testCellStyle });
29
38
 
30
- it("returns a function", () => {
31
- expect(MasterCell).toMatchSnapshot();
32
- });
33
-
34
39
  it("renders correctly", () => {
35
- const wrapper = shallow(
36
- <View>
40
+ const wrapper = renderWithProviders(
41
+ <View testID="master-cell">
37
42
  <MasterCell item={entry} />
38
43
  </View>
39
44
  );
40
45
 
41
- expect(shallowToJson(wrapper)).toMatchSnapshot();
42
- });
43
-
44
- it("can be invoked as a React Component", () => {
45
- const wrapper = shallow(<MasterCell item={entry} state={null} />);
46
-
47
- expect(shallowToJson(wrapper)).toMatchSnapshot();
46
+ expect(wrapper.getByTestId("master-cell").children[0]).toBeDefined();
48
47
  });
49
48
  });
50
49
 
51
- describe("when using custom containerStyle", () => {
50
+ describe.skip("when using custom containerStyle", () => {
52
51
  const MasterCell = masterCellBuilder({
53
52
  cellConfiguration: singleView,
54
53
  containerStyle: { backgroundColor: "black" },
55
54
  });
56
55
 
57
56
  it("renders correctly", () => {
58
- const renderer = shallow(<MasterCell item={entry} />);
59
- expect(shallowToJson(renderer)).toMatchSnapshot();
57
+ renderWithProviders(<MasterCell item={entry} />);
58
+
59
+ // TODO define the test need
60
60
  });
61
61
  });
62
62
 
@@ -69,14 +69,14 @@ describe("masterCellBuilder", () => {
69
69
  });
70
70
 
71
71
  it("renders correctly", () => {
72
- const renderer = shallow(<MasterCell item={entry} />);
73
- expect(shallowToJson(renderer)).toMatchSnapshot();
72
+ renderWithProviders(<MasterCell item={entry} />);
73
+ // TODO define the test need
74
74
 
75
75
  expect(dataAdapter).toHaveBeenCalledWith(singleView);
76
76
  });
77
77
  });
78
78
 
79
- describe("when using custom default components", () => {
79
+ describe.skip("when using custom default components", () => {
80
80
  // the collapsable prop is added here to easily check from the snapshot that the mock
81
81
  // component is being used instead of the default one
82
82
  const CustomView = jest.fn((props) => <View {...props} collapsable />);
@@ -88,8 +88,8 @@ describe("masterCellBuilder", () => {
88
88
  });
89
89
 
90
90
  it("renders correctly", () => {
91
- const renderer = shallow(<MasterCell item={entry} />);
92
- expect(shallowToJson(renderer)).toMatchSnapshot();
91
+ renderWithProviders(<MasterCell item={entry} />);
92
+ // TODO define the test need
93
93
  });
94
94
  });
95
95
  });
@@ -0,0 +1,139 @@
1
+ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
2
+ import { StorageSingleValueProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageSingleSelectProvider";
3
+ import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
4
+ import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
5
+ import React, { useEffect } from "react";
6
+ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
7
+ import { BehaviorSubject } from "rxjs";
8
+ import { masterCellLogger } from "../logger";
9
+ import * as R from "ramda";
10
+
11
+ const parseContextKey = (key: string): string | null => {
12
+ if (!key?.startsWith("@{ctx/")) return null;
13
+
14
+ return key.substring("@{ctx/".length, key.length - 1);
15
+ };
16
+
17
+ const getDataSourceProvider = (
18
+ behavior: Behavior
19
+ ): BehaviorSubject<string[] | string> | null => {
20
+ if (!behavior) return null;
21
+
22
+ const selection = String(behavior.current_selection);
23
+ const contextKey = parseContextKey(selection);
24
+
25
+ if (contextKey) {
26
+ if (behavior.select_mode === "multi") {
27
+ return StorageMultiSelectProvider.getProvider(contextKey).getObservable();
28
+ }
29
+
30
+ if (behavior.select_mode === "single") {
31
+ return StorageSingleValueProvider.getProvider(contextKey).getObservable();
32
+ }
33
+ }
34
+
35
+ if (behavior.selection_source === "@{push/topics}") {
36
+ return PushTopicManager.getInstance().getEntryObservable();
37
+ }
38
+
39
+ return null;
40
+ };
41
+
42
+ export const useBehaviorUpdate = (behavior: Behavior) => {
43
+ const [lastUpdate, setLastUpdate] = React.useState<number | null>(null);
44
+ const player = usePlayer();
45
+
46
+ const triggerUpdate = () => setLastUpdate(Date.now());
47
+
48
+ useEffect(() => {
49
+ if (!behavior) return;
50
+
51
+ const dataSource = getDataSourceProvider(behavior);
52
+
53
+ if (dataSource) {
54
+ const subscription = dataSource.subscribe(triggerUpdate);
55
+
56
+ return () => subscription.unsubscribe();
57
+ }
58
+ }, [behavior]);
59
+
60
+ useEffect(() => {
61
+ if (!behavior || !player || behavior.selection_source !== "now_playing") {
62
+ return;
63
+ }
64
+
65
+ const subscription = player.getEntryObservable().subscribe(triggerUpdate);
66
+
67
+ return () => subscription.unsubscribe();
68
+ }, [behavior, player]);
69
+
70
+ return lastUpdate;
71
+ };
72
+
73
+ // We cant use async in this function (its inside render),
74
+ // so we rely on useBehaviorUpdate to update current value and trigger re-render
75
+ export const isCellSelected = (
76
+ item: ZappEntry,
77
+ behavior?: Behavior
78
+ ): boolean => {
79
+ if (!behavior) return false;
80
+
81
+ // todo: find out what utility we have instead of Ramda
82
+ const id = behavior.selector
83
+ ? R.path(behavior.selector.split("."), item)
84
+ : item.id;
85
+
86
+ if (behavior.selection_source === "now_playing") {
87
+ const player = playerManager.getActivePlayer();
88
+
89
+ return player?.entry?.id === id;
90
+ }
91
+
92
+ if (behavior.selection_source === "@{push/topics}") {
93
+ if (behavior.select_mode === "single") {
94
+ masterCellLogger.warning(
95
+ "Unexpected single selection mode for push topics"
96
+ );
97
+ }
98
+
99
+ const tags = PushTopicManager.getInstance().getRegisteredTags();
100
+
101
+ return tags.includes(String(id));
102
+ }
103
+
104
+ const selection = String(behavior.current_selection);
105
+ const contextKey = parseContextKey(selection);
106
+
107
+ if (contextKey) {
108
+ if (behavior.select_mode === "single") {
109
+ const selectedItem =
110
+ StorageSingleValueProvider.getProvider(contextKey)?.getValue();
111
+
112
+ return selectedItem === String(id);
113
+ }
114
+
115
+ if (behavior.select_mode === "multi") {
116
+ const selectedItems =
117
+ StorageMultiSelectProvider.getProvider(contextKey)?.getSelectedItems();
118
+
119
+ return selectedItems?.includes(String(id));
120
+ }
121
+ }
122
+
123
+ if (behavior.select_mode === "single") {
124
+ return behavior.current_selection === id;
125
+ }
126
+
127
+ if (
128
+ behavior.select_mode === "multi" &&
129
+ Array.isArray(behavior.current_selection)
130
+ ) {
131
+ const currentSelection: string[] = behavior.current_selection.map(
132
+ (item): string => String(item)
133
+ );
134
+
135
+ return currentSelection.includes(String(id));
136
+ }
137
+
138
+ return false;
139
+ };
@@ -1,16 +1,13 @@
1
- import React, { useEffect, useMemo } from "react";
1
+ import React, { useMemo } from "react";
2
2
  import * as R from "ramda";
3
3
  import validateColor from "validate-color";
4
4
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
5
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
6
6
 
7
7
  import { masterCellLogger } from "../logger";
8
- import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
9
- import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
10
- import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
11
- import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
12
8
  import { getCellState } from "../../Cell/utils";
13
9
  import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
10
+ import { isCellSelected, useBehaviorUpdate } from "./behaviorProvider";
14
11
 
15
12
  const hasElementSpecificViewType = (viewType) => (element) => {
16
13
  if (R.isNil(element)) {
@@ -193,147 +190,24 @@ export const getFocusedButtonId = (focusable) => {
193
190
  });
194
191
  };
195
192
 
196
- export const isSelected = (id: string | number, behavior?: Behavior) => {
197
- if (!behavior) {
198
- return false;
199
- }
200
-
201
- if (behavior?.selection_source === "now_playing") {
202
- const player = playerManager.getActivePlayer();
203
-
204
- if (player?.entry?.id === id) {
205
- return true;
206
- }
207
- }
208
-
209
- if (behavior?.select_mode === "single") {
210
- return behavior.current_selection === id;
211
- }
212
-
213
- if (behavior?.select_mode === "multi") {
214
- // TODO: Use generic resolver source
215
-
216
- if (behavior.selection_source === "@{push/topics}") {
217
- const tags = PushTopicManager.getInstance().getRegisteredTags();
218
-
219
- return tags.includes(String(id));
220
- }
221
-
222
- if (Array.isArray(behavior.current_selection)) {
223
- return behavior.current_selection.includes(id);
224
- }
225
-
226
- const currentSelection = String(behavior.current_selection);
227
-
228
- if (currentSelection?.startsWith("@{ctx/")) {
229
- const keyWithoutCtx = currentSelection.substring(
230
- "@{ctx/".length,
231
- currentSelection.length - 1
232
- );
233
-
234
- const selectedItems =
235
- StorageMultiSelectProvider.getProvider(
236
- keyWithoutCtx
237
- )?.getSelectedItems();
238
-
239
- return selectedItems?.includes(String(id));
240
- }
241
- }
242
-
243
- return false;
244
- };
245
-
246
- export const useBehaviorUpdate = (behavior: Behavior) => {
247
- const [lastUpdate, setLastUpdate] = React.useState(null);
248
-
249
- const player = usePlayer();
250
-
251
- const triggerUpdate = () => {
252
- setLastUpdate(Date.now());
253
- };
254
-
255
- // TODO: Create generic RX to state update
256
- useEffect(() => {
257
- // TODO: Use generic resolver source
258
- if (!behavior) {
259
- return;
260
- }
261
-
262
- const currentSelection = String(behavior.current_selection);
263
-
264
- if (currentSelection?.startsWith("@{ctx/")) {
265
- const keyWithoutCtx = currentSelection.substring(
266
- "@{ctx/".length,
267
- currentSelection.length - 1
268
- );
269
-
270
- if (keyWithoutCtx) {
271
- const subscription = StorageMultiSelectProvider.getProvider(
272
- keyWithoutCtx
273
- )
274
- .getObservable()
275
- .subscribe(() => {
276
- triggerUpdate();
277
- });
278
-
279
- return () => {
280
- subscription.unsubscribe();
281
- };
282
- }
283
- }
284
- }, [behavior]);
285
-
286
- useEffect(() => {
287
- if (!behavior) {
288
- return;
289
- }
290
-
291
- if (behavior?.selection_source === "@{push/topics}") {
292
- const subscription = PushTopicManager.getInstance()
293
- .getEntryObservable()
294
- .subscribe(() => {
295
- triggerUpdate();
296
- });
297
-
298
- return () => {
299
- subscription.unsubscribe();
300
- };
301
- }
302
- }, [behavior]);
303
-
304
- useEffect(() => {
305
- if (!behavior) {
306
- return;
307
- }
308
-
309
- if (behavior?.selection_source === "now_playing" && player) {
310
- const subscription = player.getEntryObservable().subscribe(() => {
311
- triggerUpdate();
312
- });
313
-
314
- return () => {
315
- subscription.unsubscribe();
316
- };
317
- }
318
- }, [behavior, player]);
319
-
320
- return lastUpdate;
193
+ export const isSelected = (item: ZappEntry, behavior?: Behavior) => {
194
+ return isCellSelected(item, behavior);
321
195
  };
322
196
 
323
197
  export const useCellState = ({
324
- id,
198
+ item,
325
199
  behavior,
326
200
  focused,
327
201
  }: {
328
- id: string | number;
202
+ item: ZappEntry;
329
203
  behavior: Behavior;
330
204
  focused: boolean;
331
205
  }): CellState => {
332
206
  const lastUpdate = useBehaviorUpdate(behavior);
333
207
 
334
208
  const _isSelected = useMemo(
335
- () => isSelected(id, behavior),
336
- [behavior, id, lastUpdate]
209
+ () => isSelected(item, behavior),
210
+ [behavior, item, lastUpdate]
337
211
  );
338
212
 
339
213
  return getCellState({ focused, selected: _isSelected });
@@ -3,8 +3,8 @@ import { StyleSheet, TouchableOpacity, View } from "react-native";
3
3
  import { Item, ItemProps } from "./Item";
4
4
  import { ItemIcon, ItemIconProps } from "./ItemIcon";
5
5
  import { ItemLabel, ItemLabelProps } from "./ItemLabel";
6
- import { defaultSelectedAsset } from "./assets";
7
6
  import * as assets from "./assets";
7
+ import { defaultSelectedAsset } from "./assets";
8
8
 
9
9
  type ButtonProps = {
10
10
  configuration: any;
@@ -92,18 +92,18 @@ export function Button({
92
92
  >
93
93
  <Item {...itemProps} focused={focused} selected={selected}>
94
94
  <View style={styles.label_icon_container}>
95
- {itemIconProps.asset && itemIconProps.asset.length > 0 && (
95
+ {itemIconProps.asset && itemIconProps.asset.length > 0 ? (
96
96
  <ItemIcon {...itemIconProps} />
97
- )}
98
- {itemLabelProps.label && (
97
+ ) : null}
98
+ {itemLabelProps.label ? (
99
99
  <ItemLabel
100
100
  {...itemLabelProps}
101
101
  focused={focused}
102
102
  selected={selected}
103
103
  />
104
- )}
104
+ ) : null}
105
105
  </View>
106
- {selected && <ItemIcon {...selectedItemIconProps} />}
106
+ {selected ? <ItemIcon {...selectedItemIconProps} /> : null}
107
107
  </Item>
108
108
  </TouchableOpacity>
109
109
  </View>
@@ -90,7 +90,7 @@ export const NotificationView = (props: Props) => {
90
90
  return (
91
91
  <div onClick={onClose}>
92
92
  {children}
93
- {open && (
93
+ {open ? (
94
94
  <div style={styles.body}>
95
95
  <div style={styles.title}>
96
96
  <h2>{MSG}</h2>
@@ -98,7 +98,7 @@ export const NotificationView = (props: Props) => {
98
98
 
99
99
  <h4 style={styles.subtitle}>{EXTRA_MSG}</h4>
100
100
  </div>
101
- )}
101
+ ) : null}
102
102
  </div>
103
103
  );
104
104
  };
@@ -85,7 +85,7 @@ export const NotificationView = (props: Props) => {
85
85
  return (
86
86
  <div onClick={onClose}>
87
87
  {children}
88
- {shown && (
88
+ {shown ? (
89
89
  <div style={styles.body}>
90
90
  <div style={styles.title}>
91
91
  <h2>{title}</h2>
@@ -93,7 +93,7 @@ export const NotificationView = (props: Props) => {
93
93
 
94
94
  <h4 style={styles.subtitle}>{subtitle}</h4>
95
95
  </div>
96
- )}
96
+ ) : null}
97
97
  </div>
98
98
  );
99
99
  };
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
  import { Text, Animated } from "react-native";
3
3
 
4
- import { shallow } from "enzyme";
5
4
  import renderer from "react-test-renderer";
6
5
 
7
6
  jest.useFakeTimers();
@@ -40,10 +39,6 @@ const {
40
39
  } = require("../NotificationView");
41
40
 
42
41
  describe("NotificationView", () => {
43
- it("renders", () => {
44
- shallow(<NotificationView dismiss={dismiss} />);
45
- });
46
-
47
42
  it("Show online message when Online", () => {
48
43
  const component = renderer.create(
49
44
  <NotificationView online dismiss={dismiss} />
@@ -1,17 +1,17 @@
1
1
  import * as React from "react";
2
+ import { useEffect, useReducer } from "react";
2
3
  // @ts-ignore
3
- import { View, ViewStyle, TVMenuControl } from "react-native";
4
+ import { TVMenuControl, View, ViewStyle } from "react-native";
4
5
  import * as R from "ramda";
5
6
  import uuid from "uuid/v4";
6
7
  import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
7
8
  import {
8
9
  isApplePlatform,
9
- platformSelect,
10
10
  isTV,
11
+ platformSelect,
11
12
  } from "@applicaster/zapp-react-native-utils/reactUtils";
12
13
 
13
14
  import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
14
- import { useEffect, useReducer } from "react";
15
15
  import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
16
16
  import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
17
17
  import {
@@ -29,10 +29,10 @@ import {
29
29
  import { ProgramInfo } from "./ProgramInfo";
30
30
  import { AudioPlayer } from "../AudioPlayer";
31
31
  import {
32
- playerContainerLogger,
33
32
  log_debug,
34
33
  log_info,
35
34
  log_warning,
35
+ playerContainerLogger,
36
36
  } from "./logger";
37
37
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
38
38
  import { useSetNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
@@ -53,8 +53,8 @@ import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtil
53
53
  import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
54
54
 
55
55
  import {
56
- useModalAnimationContext,
57
56
  PlayerAnimationStateEnum,
57
+ useModalAnimationContext,
58
58
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
59
59
 
60
60
  type Props = {
@@ -91,6 +91,15 @@ export type PlayNextData = {
91
91
  onPlayNextPerformNextVideoPlay: () => void;
92
92
  };
93
93
 
94
+ export type PlayerState = {
95
+ duration: number;
96
+ currentTime?: number;
97
+ seekableDuration: number;
98
+ isLive: boolean;
99
+ isBuffering: boolean;
100
+ isPaused: boolean;
101
+ };
102
+
94
103
  const focusableBottomContainerId = "player-container-bottom";
95
104
 
96
105
  // Styles
@@ -335,9 +344,9 @@ const PlayerContainerComponent = (props: Props) => {
335
344
 
336
345
  const resumeTime = Number(item?.extensions?.resumeTime);
337
346
 
338
- // TODO: This is temp hack, will be removed on next pr with player refactoring
347
+ // Сhecking that the player itself knows where to start playing, and there is no need to call seekTo after returning from the Сhromecast
339
348
  if (
340
- !!playerManager.getActivePlayer()?.getContinueWatchingOffset === false &&
349
+ !playerManager.getActivePlayer()?.hasResumePosition() &&
341
350
  !isNaN(resumeTime)
342
351
  ) {
343
352
  player?.seekTo(resumeTime);
@@ -514,6 +523,12 @@ const PlayerContainerComponent = (props: Props) => {
514
523
  useEffect(() => {
515
524
  playerEvent("source_changed", { item });
516
525
 
526
+ return () => {
527
+ playerEvent("player_did_close", { item });
528
+ };
529
+ }, [item?.id, Player]);
530
+
531
+ useEffect(() => {
517
532
  if (!isModal) {
518
533
  showNavBar(false);
519
534
  }
@@ -523,13 +538,11 @@ const PlayerContainerComponent = (props: Props) => {
523
538
  }
524
539
 
525
540
  return () => {
526
- playerEvent("player_did_close", { item });
527
-
528
541
  if (!isModal) {
529
542
  showNavBar(true);
530
543
  }
531
544
  };
532
- }, [showNavBar, /* added as suggested: */ item?.id, isModal, Player]);
545
+ }, [showNavBar, isModal, Player]);
533
546
 
534
547
  useEffect(() => {
535
548
  if (prevItemId && !R.equals(prevItemId, item?.id)) {
@@ -683,10 +696,10 @@ const PlayerContainerComponent = (props: Props) => {
683
696
 
684
697
  {renderRestPlayers(restPlayerProps)}
685
698
 
686
- {state.error && <ErrorDisplay error={state.error} />}
699
+ {state.error ? <ErrorDisplay error={state.error} /> : null}
687
700
  </View>
688
701
  {/* Components container */}
689
- {isInlineTV && context.showComponentsContainer && (
702
+ {isInlineTV && context.showComponentsContainer ? (
690
703
  <View
691
704
  style={styles.inlineRiver}
692
705
  testID={"inline-river-component-wrapper"}
@@ -717,7 +730,7 @@ const PlayerContainerComponent = (props: Props) => {
717
730
  )}
718
731
  </ComponentFocusableWrapperView>
719
732
  </View>
720
- )}
733
+ ) : null}
721
734
  </View>
722
735
  </FocusableGroup>
723
736
  </TVEventHandlerComponent>
@@ -114,12 +114,12 @@ function ProgramInfoComponent({
114
114
  return (
115
115
  <View style={container}>
116
116
  <View style={programStyles.programInfo.container}>
117
- {logo && (
117
+ {logo ? (
118
118
  <Image
119
119
  source={{ uri: logo }}
120
120
  style={programStyles.programInfo.logo}
121
121
  />
122
- )}
122
+ ) : null}
123
123
  {!isAudioContent && transportInfo}
124
124
  </View>
125
125
  </View>
@@ -39,7 +39,7 @@ const PlayerImageBackgroundComponent = ({
39
39
  return (
40
40
  <View
41
41
  style={
42
- playerAnimationState === PlayerAnimationStateEnum.maximaze
42
+ playerAnimationState === PlayerAnimationStateEnum.maximize
43
43
  ? defaultImageDimensions
44
44
  : style
45
45
  }
@@ -34,6 +34,7 @@ type Props = {
34
34
  getStaticComponentFeed: any;
35
35
  pullToRefreshPipesV1RefreshingStateUpdater: () => boolean;
36
36
  refreshingPipesV1?: boolean;
37
+ stickyHeaderIndices?: number[];
37
38
  };
38
39
 
39
40
  const styles = StyleSheet.create({
@@ -61,6 +62,7 @@ function ComponentsMapComponent(props: Props) {
61
62
  // TODO: Remove when pipes v1 is deprecated.
62
63
  pullToRefreshPipesV1RefreshingStateUpdater,
63
64
  refreshingPipesV1,
65
+ stickyHeaderIndices,
64
66
  } = props;
65
67
 
66
68
  const flatListRef = React.useRef<FlatList | null>(null);
@@ -274,6 +276,7 @@ function ComponentsMapComponent(props: Props) {
274
276
  overScrollMode={Platform.OS === "android" ? "never" : "auto"}
275
277
  scrollIndicatorInsets={scrollIndicatorInsets}
276
278
  extraData={feed}
279
+ stickyHeaderIndices={stickyHeaderIndices}
277
280
  onLayout={handleOnLayout}
278
281
  removeClippedSubviews
279
282
  initialNumToRender={3}