@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.
- package/Components/AppContainer/__tests__/AppContainer.test.js +4 -6
- package/Components/AudioPlayer/AudioPlayer.tsx +7 -0
- package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +54 -111
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +36 -20
- package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
- package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
- package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
- package/Components/AudioPlayer/__tests__/title.test.js +3 -5
- package/Components/AudioPlayer/helpers.tsx +1 -0
- package/Components/BaseFocusable/index.tsx +1 -2
- package/Components/Cell/Cell.tsx +1 -0
- package/Components/Cell/CellWithFocusable.tsx +2 -1
- package/Components/Cell/TvOSCellComponent.tsx +20 -22
- package/Components/Cell/index.js +3 -1
- package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +46 -48
- package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +16 -22
- package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
- package/Components/ErrorScreen/index.tsx +6 -6
- package/Components/Focusable/Focusable.tsx +1 -0
- package/Components/Focusable/FocusableTvOS.tsx +5 -1
- package/Components/Focusable/index.android.tsx +10 -3
- package/Components/FocusableCell/index.tsx +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
- package/Components/FocusableGroup/index.tsx +0 -3
- package/Components/FocusableList/index.tsx +26 -9
- package/Components/FocusableScrollView/index.tsx +43 -13
- package/Components/Layout/TV/NavBarContainer.tsx +19 -23
- package/Components/Layout/TV/ScreenContainer.tsx +8 -1
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +2 -1
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +3 -2
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +3 -2
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
- package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +4 -12
- package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +0 -229
- package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
- package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
- package/Components/MasterCell/utils/behaviorProvider.ts +139 -0
- package/Components/MasterCell/utils/index.ts +8 -134
- package/Components/ModalComponent/Button/index.tsx +6 -6
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
- package/Components/PlayerContainer/PlayerContainer.tsx +26 -13
- package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
- package/Components/PlayerImageBackground/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -0
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +3 -3
- package/Components/River/TV/index.tsx +6 -1
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +20 -82
- package/Components/River/__tests__/river.test.js +75 -40
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +11 -4
- package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
- package/Components/RouteManager/__tests__/testId.test.js +8 -6
- package/Components/Screen/TV/index.web.tsx +5 -6
- package/Components/Screen/hooks.ts +3 -6
- package/Components/Screen/index.tsx +4 -4
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +91 -70
- package/Components/Tabs/Tab.tsx +5 -3
- package/Components/TextInputTv/index.tsx +2 -1
- package/Components/TrackedView/index.tsx +1 -0
- package/Components/Transitioner/AnimationManager.js +15 -15
- package/Components/Transitioner/Scene.tsx +1 -1
- package/Components/Transitioner/Transitioner.tsx +3 -3
- package/Components/Transitioner/__tests__/Scene.test.js +25 -14
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -68
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
- package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +7 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +44 -30
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +3 -3
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +24 -11
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +2 -2
- package/Components/VideoModal/PlayerDetails.tsx +9 -6
- package/Components/VideoModal/PlayerWrapper.tsx +2 -2
- package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
- package/Components/Viewport/__tests__/utils.test.js +5 -4
- package/Components/ZappUIComponent/Placeholder.tsx +3 -1
- package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
- package/Components/ZappUIComponent/index.tsx +3 -16
- package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
- package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
- package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
- package/Contexts/HeaderOffsetContext/index.tsx +4 -6
- package/Contexts/ScreenContext/index.tsx +3 -10
- package/Contexts/ScreenLayoutContext/index.tsx +5 -3
- package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
- package/Decorators/Navigator/index.tsx +1 -1
- package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +18 -24
- package/Decorators/RiverResolver/index.tsx +6 -8
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -29
- package/package.json +7 -10
- package/tsconfig.json +2 -3
- package/Components/Cell/CellWithFocusable.ios.tsx +0 -126
- package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
- package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
- package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
- package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
- package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
- 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 {
|
|
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(
|
|
12
|
-
useRoute
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
59
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
92
|
-
|
|
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, {
|
|
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 = (
|
|
197
|
-
|
|
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
|
-
|
|
198
|
+
item,
|
|
325
199
|
behavior,
|
|
326
200
|
focused,
|
|
327
201
|
}: {
|
|
328
|
-
|
|
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(
|
|
336
|
-
[behavior,
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
-
|
|
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,
|
|
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
|
|
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>
|
|
@@ -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}
|