@applicaster/zapp-react-native-ui-components 16.0.0-rc.11 → 16.0.0-rc.111
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/AudioPlayer/tv/__tests__/audioPlayer.test.js +19 -0
- package/Components/AudioPlayer/tv/__tests__/index.test.tsx +120 -0
- package/Components/AudioPlayer/tv/index.tsx +5 -1
- package/Components/Cell/Cell.tsx +3 -6
- package/Components/Cell/TvOSCellComponent.tsx +0 -1
- package/Components/CellRendererResolver/index.ts +2 -2
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +11 -7
- package/Components/GeneralContentScreen/GeneralContentScreenHookAdapter.tsx +54 -0
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreenHookAdapter.test.tsx +64 -0
- package/Components/GeneralContentScreen/__tests__/HookContentFocusGroup.web.test.tsx +91 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/networkService.test.ts +74 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/runInBackground.test.ts +139 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/skipExpression.test.ts +294 -0
- package/Components/GeneralContentScreen/hookAdapter/__tests__/validationHelper.test.ts +188 -0
- package/Components/GeneralContentScreen/hookAdapter/logger.ts +6 -0
- package/Components/GeneralContentScreen/hookAdapter/networkService.ts +53 -0
- package/Components/GeneralContentScreen/hookAdapter/runInBackground.ts +48 -0
- package/Components/GeneralContentScreen/hookAdapter/skipExpression.ts +252 -0
- package/Components/GeneralContentScreen/hookAdapter/validationHelper.ts +90 -0
- package/Components/GeneralContentScreen/hookFocus/index.tsx +13 -0
- package/Components/GeneralContentScreen/hookFocus/index.web.tsx +69 -0
- package/Components/GeneralContentScreen/index.ts +2 -0
- package/Components/Layout/FullWidthRow.tsx +38 -0
- package/Components/LinkHandler/LinkHandler.tsx +2 -7
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +47 -21
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/ActionButtonController.tsx +19 -4
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/components/__tests__/ActionButtonController.test.tsx +43 -1
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +34 -6
- package/Components/MasterCell/DefaultComponents/Button.tsx +1 -0
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/__tests__/withDimensions.test.ts +420 -125
- package/Components/MasterCell/DefaultComponents/Image/hoc/utils/index.ts +114 -19
- package/Components/MasterCell/DefaultComponents/Image/hoc/withDimensions.tsx +19 -8
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +2 -4
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -3
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +29 -9
- package/Components/MasterCell/DefaultComponents/Text/hooks/useText.ts +4 -0
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +36 -14
- package/Components/MasterCell/DefaultComponents/__tests__/Toggle.test.tsx +167 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ActionButton.tsx +154 -100
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/AssetComponent.tsx +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +56 -22
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +6 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +3 -1
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +32 -21
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +15 -4
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +23 -16
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +8 -3
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/insertButtonsBetweenLabels.test.ts +45 -13
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +2 -2
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/factory.test.ts +32 -0
- package/Components/MasterCell/contexts/PressedStateContext.ts +3 -0
- package/Components/MasterCell/dataAdapter.ts +15 -5
- package/Components/MasterCell/hooks/index.ts +2 -0
- package/Components/MasterCell/hooks/usePressedState.ts +4 -0
- package/Components/MasterCell/index.tsx +30 -5
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
- package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
- package/Components/MasterCell/utils/index.ts +85 -46
- package/Components/ModalComponent/ActionsBottomSheet/ActionButton.tsx +56 -0
- package/Components/ModalComponent/ActionsBottomSheet/__tests__/openActionsBottomSheet.test.ts +38 -0
- package/Components/ModalComponent/ActionsBottomSheet/boundActionButton.tsx +24 -0
- package/Components/ModalComponent/ActionsBottomSheet/index.ts +9 -0
- package/Components/ModalComponent/ActionsBottomSheet/openActionsBottomSheet.ts +61 -0
- package/Components/ModalComponent/AudioPlayer/Components/Button.tsx +392 -0
- package/Components/ModalComponent/AudioPlayer/Components/Header.tsx +772 -0
- package/Components/ModalComponent/AudioPlayer/Components/Input.tsx +728 -0
- package/Components/ModalComponent/AudioPlayer/Components/Item.tsx +1028 -0
- package/Components/ModalComponent/AudioPlayer/Components/NowPlayingHeaderSection.tsx +205 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/Item.test.tsx +164 -0
- package/Components/ModalComponent/AudioPlayer/Components/__tests__/NowPlayingHeaderSection.test.tsx +36 -0
- package/Components/ModalComponent/AudioPlayer/Components/index.ts +9 -0
- package/Components/ModalComponent/AudioPlayer/utils/__tests__/mergeStyles.test.ts +393 -0
- package/Components/ModalComponent/AudioPlayer/utils/mergeStyles.ts +523 -0
- package/Components/ModalComponent/BottomSheetDragArea.tsx +33 -0
- package/Components/ModalComponent/BottomSheetModalContent.tsx +436 -50
- package/Components/ModalComponent/Button/index.tsx +5 -3
- package/Components/ModalComponent/Header/CloseButton.tsx +12 -0
- package/Components/ModalComponent/Header/__tests__/CloseButton.test.tsx +72 -0
- package/Components/ModalComponent/Header/index.tsx +20 -7
- package/Components/ModalComponent/Header/utils.ts +1 -1
- package/Components/ModalComponent/ModalBlocksStyleContext.tsx +10 -0
- package/Components/ModalComponent/SortableList.tsx +156 -0
- package/Components/ModalComponent/SortableList.web.tsx +34 -0
- package/Components/ModalComponent/TextInputContent.tsx +135 -0
- package/Components/ModalComponent/__tests__/BottomSheetDragArea.test.tsx +74 -0
- package/Components/ModalComponent/__tests__/BottomSheetModalContent.test.tsx +343 -0
- package/Components/ModalComponent/__tests__/SortableList.web.test.tsx +16 -0
- package/Components/ModalComponent/__tests__/TextInputContent.test.tsx +169 -0
- package/Components/ModalComponent/__tests__/showTextInput.test.ts +95 -0
- package/Components/ModalComponent/index.tsx +18 -9
- package/Components/ModalComponent/presets/__tests__/getCell.test.ts +90 -0
- package/Components/ModalComponent/presets/dynamicCollectionCell.tsx +78 -0
- package/Components/ModalComponent/presets/index.ts +27 -0
- package/Components/ModalComponent/presets/selectableCell.tsx +28 -0
- package/Components/ModalComponent/presets/standardCell.tsx +41 -0
- package/Components/ModalComponent/presets/types.ts +35 -0
- package/Components/ModalComponent/showTextInput.ts +52 -0
- package/Components/ModalComponent/utils.ts +82 -21
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +4 -85
- package/Components/OfflineHandler/__tests__/index.test.tsx +186 -17
- package/Components/OfflineHandler/hooks.ts +111 -0
- package/Components/OfflineHandler/index.tsx +91 -75
- package/Components/OfflineHandler/utils/index.ts +1 -13
- package/Components/PlayerContainer/PlayerContainer.tsx +33 -18
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -4
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +337 -0
- package/Components/PreloaderWrapper/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +87 -61
- package/Components/River/River.tsx +4 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +140 -89
- package/Components/River/__tests__/componentsMap.test.js +8 -3
- package/Components/River/__tests__/resultCallback.test.tsx +47 -0
- package/Components/Screen/__tests__/Screen.test.tsx +24 -0
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -0
- package/Components/Screen/index.tsx +13 -4
- package/Components/Screen/navigationHandler.ts +8 -8
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +5 -3
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +1 -1
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +18 -2
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +36 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +56 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +21 -4
- package/Components/TopCutoffOverlay/index.tsx +2 -2
- package/Components/Transitioner/AnimationManager.js +1 -1
- package/Components/Transitioner/Scene.tsx +4 -3
- package/Components/Transitioner/Transitioner.tsx +98 -49
- package/Components/Transitioner/__tests__/transitioner.test.js +372 -3
- package/Components/VideoLive/LiveImageManager.ts +9 -3
- package/Components/VideoLive/__tests__/LiveImageManager.test.ts +59 -0
- package/Components/VideoModal/utils.ts +6 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Contexts/CachedDimensionsContext/__tests__/index.test.ts +154 -0
- package/Contexts/CachedDimensionsContext/index.ts +17 -2
- package/Contexts/ModalNavigationContext/__tests__/index.test.tsx +15 -0
- package/Contexts/ModalNavigationContext/index.tsx +2 -2
- package/Helpers/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/index.js +0 -39
- package/Hooks/useEntryActionsExpander.ts +63 -0
- package/assets/empty-Info.png +0 -0
- package/package.json +6 -5
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +0 -112
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +0 -107
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +0 -153
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -66
- package/Components/OfflineHandler/NotificationView/utils.ts +0 -34
- package/Components/Screen/utils.ts +0 -16
- package/Helpers/Analytics/index.js +0 -95
- /package/Components/BackgroundImage/{BackgroundImage.tv.android.tsx → BackgroundImage.android.tv.tsx} +0 -0
- /package/Components/BackgroundImage/{BackgroundImage.tv.ios.tsx → BackgroundImage.ios.tv.tsx} +0 -0
- /package/Components/MasterCell/DefaultComponents/ButtonContainerView/{index.tv.android.tsx → index.android.tv.tsx} +0 -0
- /package/Decorators/ZappPipesDataConnector/__tests__/{Hero.js → Hero.tsx} +0 -0
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Text, View } from "react-native";
|
|
2
|
+
import { Animated, Text, View } from "react-native";
|
|
3
|
+
import { v4 as uuidV4 } from "uuid";
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { AnimationManager } from "../AnimationManager";
|
|
6
|
+
import {
|
|
7
|
+
NAV_ACTION_BACK,
|
|
8
|
+
NAV_ACTION_PUSH,
|
|
9
|
+
NAV_ACTION_REPLACE,
|
|
10
|
+
TransitionerComponent,
|
|
11
|
+
} from "../Transitioner";
|
|
12
|
+
import { act, render } from "@testing-library/react-native";
|
|
6
13
|
|
|
7
14
|
jest.mock("../Scene", () => {
|
|
8
15
|
const View = jest.requireActual("react-native").View;
|
|
@@ -40,6 +47,47 @@ const transitionerComponentProps = {
|
|
|
40
47
|
|
|
41
48
|
jest.mock("uuid");
|
|
42
49
|
|
|
50
|
+
const sceneTransitionConfig = () => ({
|
|
51
|
+
push: {
|
|
52
|
+
duration: 0,
|
|
53
|
+
easing: jest.fn(),
|
|
54
|
+
from: { style: {} },
|
|
55
|
+
to: { style: {} },
|
|
56
|
+
},
|
|
57
|
+
back: {
|
|
58
|
+
duration: 0,
|
|
59
|
+
easing: jest.fn(),
|
|
60
|
+
from: { style: {} },
|
|
61
|
+
to: { style: {} },
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const sceneFor = (route) => (
|
|
66
|
+
<View pathname={route}>
|
|
67
|
+
<Text>{route}</Text>
|
|
68
|
+
</View>
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const root = "/river/root";
|
|
72
|
+
const child = `${root}/river/child`;
|
|
73
|
+
const grandchild = `${child}/river/grandchild`;
|
|
74
|
+
|
|
75
|
+
const propsFor = (route, previousAction, children = sceneFor(route)) => ({
|
|
76
|
+
navigator: {
|
|
77
|
+
previousAction,
|
|
78
|
+
currentRoute: route,
|
|
79
|
+
screenData: {},
|
|
80
|
+
},
|
|
81
|
+
transitionConfig: sceneTransitionConfig,
|
|
82
|
+
layoutData: {
|
|
83
|
+
isTablet: false,
|
|
84
|
+
isTabletPortrait: false,
|
|
85
|
+
},
|
|
86
|
+
children,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const sceneKeys = (ref) => ref.current.state.scenes.map((scene) => scene.key);
|
|
90
|
+
|
|
43
91
|
describe("<TransitionerComponent />", () => {
|
|
44
92
|
it("renders correctly", () => {
|
|
45
93
|
const wrapper = render(
|
|
@@ -50,4 +98,325 @@ describe("<TransitionerComponent />", () => {
|
|
|
50
98
|
|
|
51
99
|
expect(wrapper.toJSON()).toMatchSnapshot();
|
|
52
100
|
});
|
|
101
|
+
|
|
102
|
+
it("removes both intermediate scenes when backing out to the tab root", () => {
|
|
103
|
+
jest
|
|
104
|
+
.spyOn(AnimationManager.prototype, "animate")
|
|
105
|
+
.mockImplementation((_, done) => done());
|
|
106
|
+
|
|
107
|
+
const ref = React.createRef();
|
|
108
|
+
|
|
109
|
+
const { rerender } = render(
|
|
110
|
+
<TransitionerComponent
|
|
111
|
+
ref={ref}
|
|
112
|
+
{...propsFor(root, NAV_ACTION_REPLACE)}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
act(() => {
|
|
117
|
+
rerender(
|
|
118
|
+
<TransitionerComponent
|
|
119
|
+
ref={ref}
|
|
120
|
+
{...propsFor(child, NAV_ACTION_PUSH)}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
act(() => {
|
|
126
|
+
rerender(
|
|
127
|
+
<TransitionerComponent
|
|
128
|
+
ref={ref}
|
|
129
|
+
{...propsFor(grandchild, NAV_ACTION_PUSH)}
|
|
130
|
+
/>
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
act(() => {
|
|
135
|
+
rerender(
|
|
136
|
+
<TransitionerComponent ref={ref} {...propsFor(root, NAV_ACTION_BACK)} />
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(sceneKeys(ref)).toEqual([root]);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe("with interruptible animations", () => {
|
|
144
|
+
// End callback of the animation that is currently "running"
|
|
145
|
+
let runningAnimationEnd = null;
|
|
146
|
+
|
|
147
|
+
const finishAnimation = () => {
|
|
148
|
+
act(() => {
|
|
149
|
+
const done = runningAnimationEnd;
|
|
150
|
+
runningAnimationEnd = null;
|
|
151
|
+
done?.();
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const mountTransitioner = ({
|
|
156
|
+
initialRoute = root,
|
|
157
|
+
renderScene = sceneFor,
|
|
158
|
+
} = {}) => {
|
|
159
|
+
const ref = React.createRef();
|
|
160
|
+
|
|
161
|
+
const transitioner = (route, action) => (
|
|
162
|
+
<TransitionerComponent
|
|
163
|
+
ref={ref}
|
|
164
|
+
{...propsFor(route, action, renderScene(route))}
|
|
165
|
+
/>
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const { rerender } = render(
|
|
169
|
+
transitioner(initialRoute, NAV_ACTION_REPLACE)
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const navigate = (route, action) => {
|
|
173
|
+
act(() => {
|
|
174
|
+
rerender(transitioner(route, action));
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return { ref, navigate };
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
beforeEach(() => {
|
|
182
|
+
let sceneCount = 0;
|
|
183
|
+
uuidV4.mockImplementation(() => `scene-${++sceneCount}`);
|
|
184
|
+
|
|
185
|
+
jest
|
|
186
|
+
.spyOn(AnimationManager.prototype, "animate")
|
|
187
|
+
.mockImplementation((_, done) => {
|
|
188
|
+
runningAnimationEnd = done;
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const setValue = Animated.Value.prototype.setValue;
|
|
192
|
+
|
|
193
|
+
// RN 0.77: setValue() stops the running animation, which calls
|
|
194
|
+
// its end callback synchronously with { finished: false }
|
|
195
|
+
jest
|
|
196
|
+
.spyOn(Animated.Value.prototype, "setValue")
|
|
197
|
+
.mockImplementation(function (value) {
|
|
198
|
+
const interrupted = runningAnimationEnd;
|
|
199
|
+
runningAnimationEnd = null;
|
|
200
|
+
interrupted?.();
|
|
201
|
+
|
|
202
|
+
return setValue.call(this, value);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
afterEach(() => {
|
|
207
|
+
runningAnimationEnd = null;
|
|
208
|
+
jest.restoreAllMocks();
|
|
209
|
+
uuidV4.mockReset();
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it("drops interrupted scenes when going back twice during a back animation", () => {
|
|
213
|
+
const { ref, navigate } = mountTransitioner();
|
|
214
|
+
|
|
215
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
216
|
+
finishAnimation();
|
|
217
|
+
navigate(grandchild, NAV_ACTION_PUSH);
|
|
218
|
+
finishAnimation();
|
|
219
|
+
|
|
220
|
+
navigate(child, NAV_ACTION_BACK);
|
|
221
|
+
navigate(root, NAV_ACTION_BACK);
|
|
222
|
+
|
|
223
|
+
expect(ref.current.state.animating).toBe(true);
|
|
224
|
+
|
|
225
|
+
finishAnimation();
|
|
226
|
+
|
|
227
|
+
expect(sceneKeys(ref)).toEqual([root]);
|
|
228
|
+
expect(ref.current.state.animating).toBe(false);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("remounts the screen when revisiting it after a quick double back", () => {
|
|
232
|
+
const mounts = {};
|
|
233
|
+
|
|
234
|
+
const MountProbe = ({ pathname }) => {
|
|
235
|
+
React.useEffect(() => {
|
|
236
|
+
mounts[pathname] = (mounts[pathname] || 0) + 1;
|
|
237
|
+
}, [pathname]);
|
|
238
|
+
|
|
239
|
+
return <Text>{pathname}</Text>;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const { ref, navigate } = mountTransitioner({
|
|
243
|
+
renderScene: (route) => <MountProbe pathname={route} />,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
247
|
+
finishAnimation();
|
|
248
|
+
|
|
249
|
+
const originalChildId = ref.current.state.scenes[1].screenUniqueId;
|
|
250
|
+
|
|
251
|
+
navigate(grandchild, NAV_ACTION_PUSH);
|
|
252
|
+
finishAnimation();
|
|
253
|
+
navigate(child, NAV_ACTION_BACK);
|
|
254
|
+
navigate(root, NAV_ACTION_BACK);
|
|
255
|
+
finishAnimation();
|
|
256
|
+
|
|
257
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
258
|
+
finishAnimation();
|
|
259
|
+
|
|
260
|
+
const { scenes, to } = ref.current.state;
|
|
261
|
+
|
|
262
|
+
expect(scenes).toHaveLength(2);
|
|
263
|
+
expect(to.index).toBe(1);
|
|
264
|
+
expect(scenes[1].screenUniqueId).not.toBe(originalChildId);
|
|
265
|
+
expect(mounts[child]).toBe(2);
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("keeps a single scene when going back from the first scene", () => {
|
|
269
|
+
const { ref, navigate } = mountTransitioner({ initialRoute: child });
|
|
270
|
+
|
|
271
|
+
navigate(root, NAV_ACTION_BACK);
|
|
272
|
+
finishAnimation();
|
|
273
|
+
|
|
274
|
+
expect(sceneKeys(ref)).toEqual([root]);
|
|
275
|
+
expect(ref.current.state.to.index).toBe(0);
|
|
276
|
+
expect(ref.current.state.animating).toBe(false);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("pushes a fresh scene after a completed single back", () => {
|
|
280
|
+
const { ref, navigate } = mountTransitioner();
|
|
281
|
+
|
|
282
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
283
|
+
finishAnimation();
|
|
284
|
+
|
|
285
|
+
const originalChildId = ref.current.state.scenes[1].screenUniqueId;
|
|
286
|
+
|
|
287
|
+
navigate(root, NAV_ACTION_BACK);
|
|
288
|
+
finishAnimation();
|
|
289
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
290
|
+
finishAnimation();
|
|
291
|
+
|
|
292
|
+
const { scenes, to } = ref.current.state;
|
|
293
|
+
|
|
294
|
+
expect(sceneKeys(ref)).toEqual([root, child]);
|
|
295
|
+
expect(to.index).toBe(1);
|
|
296
|
+
expect(scenes[1].screenUniqueId).not.toBe(originalChildId);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it("ignores the end of a back animation that a newer back superseded", () => {
|
|
300
|
+
const { ref, navigate } = mountTransitioner();
|
|
301
|
+
|
|
302
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
303
|
+
finishAnimation();
|
|
304
|
+
navigate(grandchild, NAV_ACTION_PUSH);
|
|
305
|
+
finishAnimation();
|
|
306
|
+
|
|
307
|
+
navigate(child, NAV_ACTION_BACK);
|
|
308
|
+
|
|
309
|
+
const supersededEnd = runningAnimationEnd;
|
|
310
|
+
|
|
311
|
+
// Deliver the interrupted animation's end late, after the newer one started
|
|
312
|
+
Animated.Value.prototype.setValue.mockImplementation(() => {});
|
|
313
|
+
|
|
314
|
+
navigate(root, NAV_ACTION_BACK);
|
|
315
|
+
|
|
316
|
+
act(() => {
|
|
317
|
+
supersededEnd();
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
expect(ref.current.state.animating).toBe(true);
|
|
321
|
+
expect(sceneKeys(ref)).toEqual([root, child, grandchild]);
|
|
322
|
+
|
|
323
|
+
finishAnimation();
|
|
324
|
+
|
|
325
|
+
expect(sceneKeys(ref)).toEqual([root]);
|
|
326
|
+
expect(ref.current.state.animating).toBe(false);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it("drops the pushed scene when going back before its push animation ends", () => {
|
|
330
|
+
const { ref, navigate } = mountTransitioner();
|
|
331
|
+
|
|
332
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
333
|
+
navigate(root, NAV_ACTION_BACK);
|
|
334
|
+
|
|
335
|
+
expect(ref.current.state.animating).toBe(true);
|
|
336
|
+
|
|
337
|
+
finishAnimation();
|
|
338
|
+
|
|
339
|
+
expect(sceneKeys(ref)).toEqual([root]);
|
|
340
|
+
expect(ref.current.state.animating).toBe(false);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it("pushes right after the visible scene even when stale scenes are left behind", () => {
|
|
344
|
+
const { ref, navigate } = mountTransitioner();
|
|
345
|
+
|
|
346
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
347
|
+
finishAnimation();
|
|
348
|
+
|
|
349
|
+
// Leftover past to.index, as some other path could leave behind
|
|
350
|
+
act(() => {
|
|
351
|
+
ref.current.setState(({ scenes }) => ({
|
|
352
|
+
scenes: [
|
|
353
|
+
...scenes,
|
|
354
|
+
{
|
|
355
|
+
...scenes[1],
|
|
356
|
+
key: `${root}/river/stale`,
|
|
357
|
+
screenUniqueId: "stale",
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
}));
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
navigate(grandchild, NAV_ACTION_PUSH);
|
|
364
|
+
finishAnimation();
|
|
365
|
+
|
|
366
|
+
const { scenes, to } = ref.current.state;
|
|
367
|
+
|
|
368
|
+
expect(sceneKeys(ref)).toEqual([root, child, grandchild]);
|
|
369
|
+
expect(scenes[to.index].key).toBe(grandchild);
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("shows the replaced screen when going home during a back animation", () => {
|
|
373
|
+
const home = "/river/home";
|
|
374
|
+
const { ref, navigate } = mountTransitioner();
|
|
375
|
+
|
|
376
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
377
|
+
finishAnimation();
|
|
378
|
+
|
|
379
|
+
navigate(root, NAV_ACTION_BACK);
|
|
380
|
+
navigate(home, NAV_ACTION_REPLACE);
|
|
381
|
+
|
|
382
|
+
const { scenes, to } = ref.current.state;
|
|
383
|
+
|
|
384
|
+
expect(scenes[to.index].key).toBe(home);
|
|
385
|
+
|
|
386
|
+
finishAnimation();
|
|
387
|
+
|
|
388
|
+
expect(sceneKeys(ref)).toEqual([home]);
|
|
389
|
+
expect(ref.current.state.animating).toBe(false);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it("shows the pushed screen when pushing during a back animation", () => {
|
|
393
|
+
const sibling = `${root}/river/sibling`;
|
|
394
|
+
const { ref, navigate } = mountTransitioner();
|
|
395
|
+
|
|
396
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
397
|
+
finishAnimation();
|
|
398
|
+
|
|
399
|
+
navigate(root, NAV_ACTION_BACK);
|
|
400
|
+
navigate(sibling, NAV_ACTION_PUSH);
|
|
401
|
+
|
|
402
|
+
const { scenes, to } = ref.current.state;
|
|
403
|
+
|
|
404
|
+
expect(scenes[to.index].key).toBe(sibling);
|
|
405
|
+
|
|
406
|
+
finishAnimation();
|
|
407
|
+
|
|
408
|
+
expect(sceneKeys(ref)).not.toContain(child);
|
|
409
|
+
expect(ref.current.state.animating).toBe(false);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
it("keeps both scenes when pushing during a push animation", () => {
|
|
413
|
+
const { ref, navigate } = mountTransitioner();
|
|
414
|
+
|
|
415
|
+
navigate(child, NAV_ACTION_PUSH);
|
|
416
|
+
navigate(grandchild, NAV_ACTION_PUSH);
|
|
417
|
+
|
|
418
|
+
expect(sceneKeys(ref)).toEqual([child, grandchild]);
|
|
419
|
+
expect(ref.current.state.to.index).toBe(1);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
53
422
|
});
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
6
6
|
import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
|
|
7
7
|
import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
8
|
-
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/
|
|
8
|
+
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/const";
|
|
9
9
|
import { loggerLiveImageManager } from "./loggerHelper";
|
|
10
10
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
11
11
|
import {
|
|
@@ -213,10 +213,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
213
213
|
log_debug(
|
|
214
214
|
`pauseItem: live-image not ready, ${item.playerId} - ${item.tag}`
|
|
215
215
|
);
|
|
216
|
-
} else {
|
|
217
|
-
item.player.pause();
|
|
218
216
|
}
|
|
219
217
|
|
|
218
|
+
// Pause even when the player is not ready yet: the underlying player may
|
|
219
|
+
// still be loading and would otherwise start playing on its own once it
|
|
220
|
+
// has buffered, leaving the live-image audible underneath the primary
|
|
221
|
+
// player. Note this is best effort - the web controller's pause() only
|
|
222
|
+
// logs while the player component is unmounted - so the player itself also
|
|
223
|
+
// refuses buffer-driven starts when it was never asked to play.
|
|
224
|
+
item.player.pause();
|
|
225
|
+
|
|
220
226
|
// Fake close event, because we unmount native view
|
|
221
227
|
item.player.onPlayerClose();
|
|
222
228
|
item.setMode?.(LiveImageType.Image);
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
const { LiveImageManager } = require("../LiveImageManager");
|
|
2
2
|
|
|
3
3
|
describe("LiveImageManager", () => {
|
|
4
|
+
const flushPromises = () => new Promise(setImmediate);
|
|
5
|
+
|
|
4
6
|
it("should subscribe to LiveImageManager events", () => {
|
|
5
7
|
const sampleListener = {
|
|
6
8
|
id: "1",
|
|
@@ -78,4 +80,61 @@ describe("LiveImageManager", () => {
|
|
|
78
80
|
expect(mockOnEnd1).toHaveBeenCalledWith(eventBody);
|
|
79
81
|
expect(mockOnEnd2).toHaveBeenCalledWith(eventBody);
|
|
80
82
|
});
|
|
83
|
+
|
|
84
|
+
it("should start a prepared live image when the mounted player loads", async () => {
|
|
85
|
+
const manager = new LiveImageManager();
|
|
86
|
+
|
|
87
|
+
const item = {
|
|
88
|
+
playerId: "live-image",
|
|
89
|
+
tag: "Live image",
|
|
90
|
+
player: {
|
|
91
|
+
playerId: "live-image",
|
|
92
|
+
playerState: { isReadyToPlay: false },
|
|
93
|
+
getEntry: jest.fn(),
|
|
94
|
+
play: jest.fn(),
|
|
95
|
+
},
|
|
96
|
+
getPlayer: jest.fn(),
|
|
97
|
+
prepareForPlayback: jest.fn().mockResolvedValue(true),
|
|
98
|
+
setMode: jest.fn(),
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
manager.playLiveImage(item);
|
|
102
|
+
await flushPromises();
|
|
103
|
+
|
|
104
|
+
expect(item.setMode).toHaveBeenCalledWith("video");
|
|
105
|
+
expect(item.player.play).not.toHaveBeenCalled();
|
|
106
|
+
|
|
107
|
+
manager.onLiveImageVideoLoaded(item);
|
|
108
|
+
|
|
109
|
+
expect(item.player.play).toHaveBeenCalledTimes(1);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("should not start a live image that was paused before the player loaded", async () => {
|
|
113
|
+
const manager = new LiveImageManager();
|
|
114
|
+
|
|
115
|
+
const item = {
|
|
116
|
+
playerId: "live-image",
|
|
117
|
+
tag: "Live image",
|
|
118
|
+
player: {
|
|
119
|
+
playerId: "live-image",
|
|
120
|
+
playerState: { isReadyToPlay: false },
|
|
121
|
+
getEntry: jest.fn(),
|
|
122
|
+
play: jest.fn(),
|
|
123
|
+
pause: jest.fn(),
|
|
124
|
+
onPlayerClose: jest.fn(),
|
|
125
|
+
},
|
|
126
|
+
getPlayer: jest.fn(),
|
|
127
|
+
prepareForPlayback: jest.fn().mockResolvedValue(true),
|
|
128
|
+
setMode: jest.fn(),
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
manager.playLiveImage(item);
|
|
132
|
+
await flushPromises();
|
|
133
|
+
manager.pauseLiveImage(item);
|
|
134
|
+
manager.onLiveImageVideoLoaded(item);
|
|
135
|
+
|
|
136
|
+
expect(item.player.pause).toHaveBeenCalledTimes(1);
|
|
137
|
+
expect(item.player.play).not.toHaveBeenCalled();
|
|
138
|
+
expect(item.setMode).toHaveBeenLastCalledWith("image");
|
|
139
|
+
});
|
|
81
140
|
});
|
|
@@ -10,6 +10,7 @@ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
|
10
10
|
import { create } from "zustand";
|
|
11
11
|
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
12
|
import { selectPluginConfigurationsByPluginId } from "@applicaster/zapp-react-native-redux";
|
|
13
|
+
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
13
14
|
|
|
14
15
|
export const useConfiguration = () => {
|
|
15
16
|
const {
|
|
@@ -18,6 +19,7 @@ export const useConfiguration = () => {
|
|
|
18
19
|
|
|
19
20
|
const rivers = useRivers();
|
|
20
21
|
const contentTypes = useContentTypes();
|
|
22
|
+
const player = usePlayer();
|
|
21
23
|
|
|
22
24
|
const targetScreenId = contentTypes?.[item?.type?.value]?.screen_id;
|
|
23
25
|
const targetScreenConfiguration = rivers?.[targetScreenId];
|
|
@@ -26,7 +28,10 @@ export const useConfiguration = () => {
|
|
|
26
28
|
selectPluginConfigurationsByPluginId(state, targetScreenConfiguration?.type)
|
|
27
29
|
);
|
|
28
30
|
|
|
29
|
-
const playerPluginConfig =
|
|
31
|
+
const playerPluginConfig =
|
|
32
|
+
player?.getPluginConfiguration() ??
|
|
33
|
+
playerManager.getInstanceController()?.getPluginConfiguration() ??
|
|
34
|
+
{};
|
|
30
35
|
|
|
31
36
|
const config = mergeRight(playerPluginConfig, {
|
|
32
37
|
...configuration_json,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { StyleSheet,
|
|
3
|
-
|
|
2
|
+
import { StyleSheet, SafeAreaView as RNSafeAreaView } from "react-native";
|
|
3
|
+
import { SafeAreaView } from "react-native-safe-area-context";
|
|
4
4
|
import { useIsRTL } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
5
5
|
import CloseButton from "./Buttons/CloseButton";
|
|
6
6
|
import BackButton from "./Buttons/BackButton";
|
|
7
7
|
import BarTitle from "./BarTitle";
|
|
8
|
+
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
8
9
|
|
|
9
10
|
type Props = {
|
|
10
11
|
screenStyles: {
|
|
@@ -23,6 +24,11 @@ const defaultState: NavBarState = {
|
|
|
23
24
|
title: "",
|
|
24
25
|
};
|
|
25
26
|
|
|
27
|
+
const SafeAreaViewPlatform = platformSelect({
|
|
28
|
+
ios: RNSafeAreaView,
|
|
29
|
+
android: SafeAreaView,
|
|
30
|
+
});
|
|
31
|
+
|
|
26
32
|
const BarView = ({ screenStyles, barState = defaultState }: Props) => {
|
|
27
33
|
const isRTL = useIsRTL();
|
|
28
34
|
|
|
@@ -44,14 +50,15 @@ const BarView = ({ screenStyles, barState = defaultState }: Props) => {
|
|
|
44
50
|
);
|
|
45
51
|
|
|
46
52
|
return (
|
|
47
|
-
<
|
|
53
|
+
<SafeAreaViewPlatform
|
|
54
|
+
edges={["top", "left", "right"]}
|
|
48
55
|
style={[style.view, isRTL ? style.rtlStyle : {}]}
|
|
49
|
-
testID="BarView-
|
|
56
|
+
testID="BarView-safeAreaView"
|
|
50
57
|
>
|
|
51
58
|
{backButton}
|
|
52
59
|
<BarTitle title={barState.title} screenStyles={screenStyles} />
|
|
53
60
|
{closeButton}
|
|
54
|
-
</
|
|
61
|
+
</SafeAreaViewPlatform>
|
|
55
62
|
);
|
|
56
63
|
};
|
|
57
64
|
|
|
@@ -46,7 +46,7 @@ describe("BarView", () => {
|
|
|
46
46
|
<BarView screenStyles={screenStyles} barState={barState} />
|
|
47
47
|
);
|
|
48
48
|
|
|
49
|
-
expect(getByTestId("BarView-
|
|
49
|
+
expect(getByTestId("BarView-safeAreaView").props.style).toContainEqual({
|
|
50
50
|
transform: [{ scaleX: -1 }],
|
|
51
51
|
});
|
|
52
52
|
});
|
|
@@ -58,7 +58,7 @@ describe("BarView", () => {
|
|
|
58
58
|
<BarView screenStyles={screenStyles} barState={barState} />
|
|
59
59
|
);
|
|
60
60
|
|
|
61
|
-
expect(getByTestId("BarView-
|
|
61
|
+
expect(getByTestId("BarView-safeAreaView").props.style).not.toContainEqual({
|
|
62
62
|
transform: [{ scaleX: -1 }],
|
|
63
63
|
});
|
|
64
64
|
});
|