@applicaster/zapp-react-native-ui-components 12.0.0-alpha.7725319213 → 12.0.0-alpha.7843515010
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/AudioPlayer.tsx +9 -1
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +5 -0
- package/Components/AudioPlayer/helpers.tsx +1 -0
- package/Components/BaseFocusable/index.tsx +3 -3
- package/Components/Cell/Cell.tsx +32 -11
- package/Components/Cell/CellWithFocusable.tsx +40 -19
- package/Components/Cell/TvOSCellComponent.tsx +5 -9
- package/Components/ErrorScreen/index.tsx +1 -1
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableCell/index.tsx +7 -7
- package/Components/FocusableGroup/index.tsx +11 -2
- package/Components/FocusableList/FocusableChild.ts +24 -14
- package/Components/FocusableList/FocusableItem.tsx +1 -1
- package/Components/FocusableList/FocusableListItemWrapper.tsx +76 -0
- package/Components/FocusableList/hooks/useCellState.android.ts +3 -1
- package/Components/FocusableList/index.tsx +26 -25
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +6 -3
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/HookRenderer/index.tsx +1 -6
- package/Components/Image/Image.android.tsx +3 -25
- package/Components/Image/Image.tsx +18 -2
- package/Components/Image/utils/index.ts +39 -0
- package/Components/Layout/TV/ScreenContainer.tsx +79 -5
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +38 -28
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +25 -13
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +20 -108
- package/Components/Layout/TV/index.tsx +15 -84
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +86 -116
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +9 -26
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImageSize.ts +65 -0
- package/Components/MasterCell/DefaultComponents/ImageBorderContainer/index.ts +57 -0
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +37 -2
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +3 -2
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
- package/Components/MasterCell/DefaultComponents/index.ts +2 -0
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -14
- package/Components/MasterCell/dataAdapter.ts +21 -7
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- package/Components/MasterCell/index.tsx +5 -3
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +33 -35
- package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
- package/Components/ModalComponent/BottomSheetModalContent.tsx +121 -0
- package/Components/ModalComponent/Button/Item.tsx +82 -0
- package/Components/ModalComponent/Button/ItemIcon.tsx +60 -0
- package/Components/ModalComponent/Button/ItemLabel.tsx +101 -0
- package/Components/ModalComponent/Button/assets.ts +4 -0
- package/Components/ModalComponent/Button/index.tsx +111 -0
- package/Components/ModalComponent/Header/CloseButton.tsx +59 -0
- package/Components/ModalComponent/Header/Title.tsx +70 -0
- package/Components/ModalComponent/Header/assets.ts +4 -0
- package/Components/ModalComponent/Header/index.tsx +71 -0
- package/Components/ModalComponent/Header/utils.ts +79 -0
- package/Components/ModalComponent/index.tsx +38 -0
- package/Components/ModalComponent/utils.ts +126 -0
- package/Components/Navigator/StackNavigator.tsx +57 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +65 -32
- package/Components/PlayerContainer/ProgramInfo/index.tsx +3 -1
- package/Components/PlayerImageBackground/index.tsx +34 -8
- package/Components/River/ComponentsMap/ComponentsMap.tsx +97 -2
- package/Components/River/RefreshControl.tsx +55 -1
- package/Components/River/TV/River.tsx +2 -25
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -1
- package/Components/River/__tests__/componentsMap.test.js +7 -0
- package/Components/River/useScreenConfiguration.ts +2 -2
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +1 -0
- package/Components/RouteManager/__tests__/routeManager.test.js +9 -2
- package/Components/RouteManager/index.tsx +4 -2
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +165 -0
- package/Components/Screen/__tests__/Screen.test.tsx +91 -74
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +24 -6
- package/Components/Screen/__tests__/navigationHandler.test.ts +1 -178
- package/Components/Screen/index.tsx +110 -53
- package/Components/Screen/navigationHandler.ts +5 -82
- package/Components/ScreenResolver/index.tsx +10 -13
- package/Components/Tabs/TV/styles.ts +1 -1
- package/Components/Transitioner/Scene.tsx +32 -26
- package/Components/Transitioner/Transitioner.tsx +38 -43
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +30 -3
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +79 -48
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +21 -29
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +66 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +360 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +456 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +182 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +302 -0
- package/Components/VideoModal/PlayerDetails.tsx +6 -3
- package/Components/VideoModal/PlayerWrapper.tsx +77 -47
- package/Components/VideoModal/VideoModal.tsx +23 -40
- package/Components/VideoModal/__tests__/PlayerDetails.test.tsx +0 -2
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +12 -1
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +312 -166
- package/Components/VideoModal/hooks/useModalSize.ts +10 -12
- package/Components/VideoModal/utils.ts +8 -5
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +26 -21
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +4 -5
- package/Components/Viewport/ViewportTracker/index.tsx +1 -0
- package/Components/Viewport/utils.js +1 -1
- package/Components/ZappUIComponent/index.tsx +22 -12
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +4 -4
- package/Components/index.js +2 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
- package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
- package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
- package/Contexts/ScreenContext/index.tsx +95 -29
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
- package/events/index.ts +1 -0
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
- /package/Contexts/{index.js → index.ts} +0 -0
|
@@ -4,10 +4,7 @@ import * as R from "ramda";
|
|
|
4
4
|
|
|
5
5
|
import { AnimationManager } from "./AnimationManager";
|
|
6
6
|
import { Scene } from "./Scene";
|
|
7
|
-
|
|
8
|
-
getScreenOrientation,
|
|
9
|
-
isOrientationCompatible,
|
|
10
|
-
} from "@applicaster/zapp-react-native-utils/appUtils/orientationHelper";
|
|
7
|
+
|
|
11
8
|
import {
|
|
12
9
|
getSceneByRoute,
|
|
13
10
|
shouldSkipAnimationForPreviousWebViewScene,
|
|
@@ -169,21 +166,23 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
169
166
|
|
|
170
167
|
transitionWithoutAnimation(resetState) {
|
|
171
168
|
const { scenes } = this.state;
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
169
|
+
const newScene = prepareScene(this.props.children);
|
|
170
|
+
const isLastSceneHook = scenes[scenes.length - 1].key.startsWith("/hook");
|
|
171
|
+
|
|
172
|
+
let newState;
|
|
173
|
+
|
|
174
|
+
if (resetState) {
|
|
175
|
+
newState = {
|
|
176
|
+
scenes: [newScene],
|
|
177
|
+
to: { index: 0 },
|
|
178
|
+
};
|
|
179
|
+
} else if (isLastSceneHook || scenes.length === 1) {
|
|
180
|
+
newState = { scenes: R.update(scenes.length - 1, newScene, scenes) };
|
|
181
|
+
} else {
|
|
182
|
+
newState = {
|
|
183
|
+
scenes: R.compose(R.tail, R.append(newScene))(scenes),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
187
186
|
|
|
188
187
|
this.setState(newState);
|
|
189
188
|
}
|
|
@@ -277,33 +276,25 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
277
276
|
// so only a single scene should be rendered,
|
|
278
277
|
// instead of dangerous nulls or duplicates.
|
|
279
278
|
renderSingleScene({ scenes, to }) {
|
|
280
|
-
const { contentStyle
|
|
281
|
-
const screenData =
|
|
282
|
-
|
|
283
|
-
const orientation = getScreenOrientation({
|
|
284
|
-
screenData,
|
|
285
|
-
layoutData,
|
|
286
|
-
});
|
|
279
|
+
const { contentStyle } = this.props;
|
|
280
|
+
const screenData = this.props.children.props.screenData;
|
|
281
|
+
const pathname = scenes[to.index].key;
|
|
287
282
|
|
|
288
|
-
// We prevent rendering of the screen until UI is actually rotated to screen desired orientation.
|
|
289
|
-
// This saves unnecessary re-renders and user will not see distorted aspect screen.
|
|
290
283
|
return (
|
|
291
284
|
<View style={styles.container}>
|
|
292
|
-
{scenes[to.index] &&
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
</Scene>
|
|
306
|
-
)}
|
|
285
|
+
{scenes[to.index] && (
|
|
286
|
+
<Scene
|
|
287
|
+
{...{ style: to.style }}
|
|
288
|
+
pathname={pathname}
|
|
289
|
+
isActive={pathname === this.props.navigator.currentRoute}
|
|
290
|
+
contentStyle={contentStyle}
|
|
291
|
+
key={scenes[to.index].key}
|
|
292
|
+
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
293
|
+
screenData={screenData}
|
|
294
|
+
>
|
|
295
|
+
{scenes[to.index].children}
|
|
296
|
+
</Scene>
|
|
297
|
+
)}
|
|
307
298
|
</View>
|
|
308
299
|
);
|
|
309
300
|
}
|
|
@@ -319,12 +310,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
319
310
|
<Scene
|
|
320
311
|
key={scenes[from.index].key}
|
|
321
312
|
pathname={scenes[from.index].key}
|
|
313
|
+
isActive={scenes[from.index].key === this.props.navigator.currentRoute}
|
|
322
314
|
style={from.style}
|
|
323
315
|
pointerEvents="none"
|
|
324
316
|
overlayStyle={from.overlayStyle}
|
|
325
317
|
animating={this.state.animating}
|
|
326
318
|
contentStyle={contentStyle}
|
|
327
319
|
screenUniqueId={scenes[from.index].screenUniqueId}
|
|
320
|
+
screenData={scenes[from.index].children.props.screenData}
|
|
328
321
|
>
|
|
329
322
|
{scenes[from.index].children}
|
|
330
323
|
</Scene>
|
|
@@ -333,12 +326,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
333
326
|
const toScene = scenes[to.index] && (
|
|
334
327
|
<Scene
|
|
335
328
|
pathname={scenes[to.index].key}
|
|
329
|
+
isActive={scenes[to.index].key === this.props.navigator.currentRoute}
|
|
336
330
|
key={scenes[to.index].key}
|
|
337
331
|
style={to.style}
|
|
338
332
|
overlayStyle={to.overlayStyle}
|
|
339
333
|
animating={this.state.animating}
|
|
340
334
|
contentStyle={contentStyle}
|
|
341
335
|
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
336
|
+
screenData={this.props.children.props.screenData}
|
|
342
337
|
>
|
|
343
338
|
{scenes[to.index].children}
|
|
344
339
|
</Scene>
|
|
@@ -21,7 +21,11 @@ exports[`<Scene /> renders correctly 1`] = `
|
|
|
21
21
|
]
|
|
22
22
|
}
|
|
23
23
|
>
|
|
24
|
-
<ContextProvider
|
|
24
|
+
<ContextProvider>
|
|
25
|
+
<ContextProvider>
|
|
26
|
+
<ScreenContextProvider />
|
|
27
|
+
</ContextProvider>
|
|
28
|
+
</ContextProvider>
|
|
25
29
|
</ForwardRef(AnimatedComponentWrapper)>
|
|
26
30
|
`;
|
|
27
31
|
|
|
@@ -37,13 +41,17 @@ exports[`<Scene /> renders the overlay while animating 1`] = `
|
|
|
37
41
|
"paddingBottom": 49,
|
|
38
42
|
},
|
|
39
43
|
Object {
|
|
40
|
-
"height":
|
|
41
|
-
"width":
|
|
44
|
+
"height": "100%",
|
|
45
|
+
"width": "100%",
|
|
42
46
|
},
|
|
43
47
|
]
|
|
44
48
|
}
|
|
45
49
|
>
|
|
46
|
-
<ContextProvider
|
|
50
|
+
<ContextProvider>
|
|
51
|
+
<ContextProvider>
|
|
52
|
+
<ScreenContextProvider />
|
|
53
|
+
</ContextProvider>
|
|
54
|
+
</ContextProvider>
|
|
47
55
|
<ForwardRef(AnimatedComponentWrapper)
|
|
48
56
|
style={
|
|
49
57
|
Object {
|
|
@@ -10,7 +10,11 @@ import { Component } from "react";
|
|
|
10
10
|
|
|
11
11
|
const { log_debug, log_info, log_error } = loggerLiveImageManager;
|
|
12
12
|
|
|
13
|
-
export type LiveImageManagerEvent =
|
|
13
|
+
export type LiveImageManagerEvent =
|
|
14
|
+
| "onEnd"
|
|
15
|
+
| "onStart"
|
|
16
|
+
| "onError"
|
|
17
|
+
| "onDestroy";
|
|
14
18
|
|
|
15
19
|
export type LiveImageManagerListenerData = {
|
|
16
20
|
id: string;
|
|
@@ -102,6 +106,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
this.items = this.items.filter((i) => i !== item);
|
|
109
|
+
|
|
110
|
+
this.invokeListenersUpdate({
|
|
111
|
+
callbackName: "onDestroy",
|
|
112
|
+
event: {
|
|
113
|
+
item,
|
|
114
|
+
playerId: this.currentlyPlaying?.playerId,
|
|
115
|
+
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
116
|
+
entry: item.getPlayer().getEntry(),
|
|
117
|
+
},
|
|
118
|
+
});
|
|
105
119
|
};
|
|
106
120
|
|
|
107
121
|
public onViewportEnter = (item: LiveImage) => {
|
|
@@ -351,6 +365,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
351
365
|
item,
|
|
352
366
|
playerId: this.currentlyPlaying?.playerId,
|
|
353
367
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
368
|
+
entry: item.getPlayer().getEntry(),
|
|
354
369
|
},
|
|
355
370
|
});
|
|
356
371
|
};
|
|
@@ -369,8 +384,8 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
369
384
|
// TODO: This branch was used when we had play button to toggle replay.
|
|
370
385
|
// Now we mute button instead but we keep it just in case.
|
|
371
386
|
if (IS_ALLOWED_REPLAY && !isTV() && isCurrentItemEnded) {
|
|
372
|
-
this.currentlyPlaying
|
|
373
|
-
this.currentlyPlaying
|
|
387
|
+
this.currentlyPlaying?.player.seekTo(0);
|
|
388
|
+
this.currentlyPlaying?.player.pause();
|
|
374
389
|
|
|
375
390
|
// TODO: ...Maybe player some other item
|
|
376
391
|
} else {
|
|
@@ -385,6 +400,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
385
400
|
item,
|
|
386
401
|
playerId: this.currentlyPlaying?.playerId,
|
|
387
402
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
403
|
+
entry: item.getPlayer().getEntry(),
|
|
388
404
|
},
|
|
389
405
|
});
|
|
390
406
|
};
|
|
@@ -419,6 +435,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
419
435
|
error,
|
|
420
436
|
playerId: currentItem?.playerId,
|
|
421
437
|
primaryPlayerId: currentItem?.playerId,
|
|
438
|
+
entry: item.getPlayer().getEntry(),
|
|
422
439
|
},
|
|
423
440
|
});
|
|
424
441
|
};
|
|
@@ -508,6 +525,16 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
|
|
|
508
525
|
LiveImageManager.instance.onLiveImageError(this, error);
|
|
509
526
|
};
|
|
510
527
|
|
|
528
|
+
onVideoError = (error: Error) => {
|
|
529
|
+
log_error(
|
|
530
|
+
`onVideoError: live-image, fail to play, switching back to image. error: ${
|
|
531
|
+
error?.message
|
|
532
|
+
}, ${playerInfo(this.player)}`
|
|
533
|
+
);
|
|
534
|
+
|
|
535
|
+
LiveImageManager.instance.onLiveImageError(this, error);
|
|
536
|
+
};
|
|
537
|
+
|
|
511
538
|
onVideoEnd = (_event) => {
|
|
512
539
|
log_info(
|
|
513
540
|
`onVideoEnd: live-image, video completed, switching back to image, ${playerInfo(
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
|
|
5
|
-
import { AppState, AppStateStatus } from "react-native";
|
|
5
|
+
import { AppState, AppStateStatus, View } from "react-native";
|
|
6
6
|
import { TrackedView } from "../TrackedView";
|
|
7
7
|
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
15
15
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
16
16
|
import { getUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
|
|
17
|
-
import
|
|
17
|
+
import Image from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/Image";
|
|
18
18
|
import { LiveImage, LiveImageManager, LiveImageType } from "./LiveImageManager";
|
|
19
19
|
|
|
20
20
|
import { AnimatedInOut } from "@applicaster/zapp-react-native-ui-components/Components/AnimatedInOut";
|
|
@@ -25,8 +25,9 @@ import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/player
|
|
|
25
25
|
import { getAutoplaySettings } from "./utils";
|
|
26
26
|
import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
27
27
|
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
28
|
+
import { useEffect } from "react";
|
|
28
29
|
|
|
29
|
-
const { log_error } = loggerLiveImageComponent;
|
|
30
|
+
const { log_error, log_debug } = loggerLiveImageComponent;
|
|
30
31
|
|
|
31
32
|
const isMeasurement = (item: ZappEntry) =>
|
|
32
33
|
isString(item.id) && item.id.startsWith("pre-measurement-");
|
|
@@ -39,12 +40,13 @@ type Props = {
|
|
|
39
40
|
imageKey?: string;
|
|
40
41
|
screenConfig: Record<string, any>;
|
|
41
42
|
audioMutedByDefault?: boolean;
|
|
43
|
+
uri: string; // cover image url
|
|
42
44
|
};
|
|
43
45
|
|
|
44
46
|
const PlayerLiveImageComponent = (props: Props) => {
|
|
45
47
|
const dimensions = useDimensions("screen", { fullDimensions: true });
|
|
46
48
|
|
|
47
|
-
const { item, style, playerId
|
|
49
|
+
const { item, style, playerId } = props;
|
|
48
50
|
|
|
49
51
|
const timeoutRef = React.useRef<NodeJS.Timeout | null>(null);
|
|
50
52
|
const [mode, setMode] = React.useState(LiveImageType.Image);
|
|
@@ -55,6 +57,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
55
57
|
);
|
|
56
58
|
|
|
57
59
|
const ref = React.useRef(null);
|
|
60
|
+
const trackViewRef = React.useRef(null);
|
|
58
61
|
|
|
59
62
|
/**
|
|
60
63
|
* Debounced setMode function.
|
|
@@ -63,24 +66,51 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
63
66
|
*
|
|
64
67
|
* @param type video or image
|
|
65
68
|
*/
|
|
66
|
-
const setModeDebounced = React.useCallback(
|
|
67
|
-
|
|
68
|
-
if (type ===
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
const setModeDebounced = React.useCallback(
|
|
70
|
+
(type: LiveImageType) => {
|
|
71
|
+
if (type === LiveImageType.Video) {
|
|
72
|
+
if (type === mode) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
timeoutRef.current = setTimeout(() => {
|
|
77
|
+
setMode(type);
|
|
78
|
+
}, 1000) as unknown as NodeJS.Timeout;
|
|
79
|
+
} else {
|
|
80
|
+
if (timeoutRef.current) {
|
|
81
|
+
clearTimeout(timeoutRef.current);
|
|
82
|
+
timeoutRef.current = null;
|
|
83
|
+
}
|
|
71
84
|
|
|
72
|
-
timeoutRef.current = setTimeout(() => {
|
|
73
85
|
setMode(type);
|
|
74
|
-
}, 1000) as unknown as NodeJS.Timeout;
|
|
75
|
-
} else {
|
|
76
|
-
if (timeoutRef.current) {
|
|
77
|
-
clearTimeout(timeoutRef.current);
|
|
78
|
-
timeoutRef.current = null;
|
|
79
86
|
}
|
|
87
|
+
},
|
|
88
|
+
[mode]
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const entryToViewIdMapping = React.useRef({});
|
|
80
92
|
|
|
81
|
-
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
const nativeTag = trackViewRef.current?._nativeTag?.toString();
|
|
95
|
+
|
|
96
|
+
if (!nativeTag) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const prevValue = entryToViewIdMapping.current[nativeTag];
|
|
101
|
+
|
|
102
|
+
if (prevValue && prevValue.itemId !== item.id) {
|
|
103
|
+
if (mode === LiveImageType.Video) {
|
|
104
|
+
log_debug(
|
|
105
|
+
"Entry to view association changed, stopping current live image"
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
setMode(LiveImageType.Image);
|
|
109
|
+
}
|
|
82
110
|
}
|
|
83
|
-
|
|
111
|
+
|
|
112
|
+
entryToViewIdMapping.current[nativeTag] = { itemId: item.id };
|
|
113
|
+
}, [trackViewRef.current, item.id, mode]);
|
|
84
114
|
|
|
85
115
|
const { screenConfig, playerPluginId } = props;
|
|
86
116
|
|
|
@@ -100,7 +130,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
100
130
|
return new LiveImage({
|
|
101
131
|
playerId,
|
|
102
132
|
player: playerFactoryItem.controller,
|
|
103
|
-
component: playerFactoryItem?.Component
|
|
133
|
+
component: playerFactoryItem?.Component,
|
|
104
134
|
});
|
|
105
135
|
} else {
|
|
106
136
|
throw new Error("Player factory item is null");
|
|
@@ -111,10 +141,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
111
141
|
liveImageItem.setMode = setModeDebounced;
|
|
112
142
|
}, [setModeDebounced, liveImageItem]);
|
|
113
143
|
|
|
114
|
-
const { start, end } = React.useMemo(
|
|
115
|
-
() => getAutoplaySettings(item),
|
|
116
|
-
[item]
|
|
117
|
-
);
|
|
144
|
+
const { start, end } = React.useMemo(() => getAutoplaySettings(item), [item]);
|
|
118
145
|
|
|
119
146
|
const controller = liveImageItem.getPlayer();
|
|
120
147
|
const player = usePlayer(playerId);
|
|
@@ -239,7 +266,12 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
239
266
|
|
|
240
267
|
const onPositionUpdated = React.useCallback(
|
|
241
268
|
(data) => {
|
|
242
|
-
const normalizedRect = (rect: {
|
|
269
|
+
const normalizedRect = (rect: {
|
|
270
|
+
left: number;
|
|
271
|
+
right: number;
|
|
272
|
+
top: number;
|
|
273
|
+
bottom: number;
|
|
274
|
+
}) => {
|
|
243
275
|
if (!rect) {
|
|
244
276
|
return null;
|
|
245
277
|
}
|
|
@@ -283,37 +315,36 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
283
315
|
const videoStyles = { ...style, position: "absolute", zIndex: -100 };
|
|
284
316
|
const Player: any = liveImageItem.component || BufferAnimation;
|
|
285
317
|
|
|
318
|
+
// TODO: nice to have - resolve imageKey when imageUrl is not provided
|
|
286
319
|
return (
|
|
287
320
|
<TrackedView
|
|
288
321
|
testId={`tracked-view-${playerId}-${item.title}`}
|
|
289
322
|
onPositionUpdated={onPositionUpdated}
|
|
290
323
|
>
|
|
291
|
-
{
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
)}
|
|
304
|
-
{
|
|
305
|
-
<AnimatedInOut
|
|
306
|
-
visible={isBackgroundImageVisible}
|
|
307
|
-
animationConfig={overlayFadeIn}
|
|
308
|
-
staticStyles={style}
|
|
309
|
-
>
|
|
310
|
-
<PlayerImageBackground
|
|
311
|
-
entry={item}
|
|
312
|
-
style={style}
|
|
313
|
-
imageKey={imageKey}
|
|
324
|
+
<View ref={trackViewRef}>
|
|
325
|
+
{isVideoMode && (
|
|
326
|
+
<Player
|
|
327
|
+
autoplay={false}
|
|
328
|
+
ref={_assignRoot}
|
|
329
|
+
entry={item} // Must be passed first in list
|
|
330
|
+
style={videoStyles}
|
|
331
|
+
playerId={playerId}
|
|
332
|
+
muted={muted}
|
|
333
|
+
listener={controller?.getListener()}
|
|
334
|
+
resizeMode={"cover"}
|
|
335
|
+
{...platformSpecificProps}
|
|
314
336
|
/>
|
|
315
|
-
|
|
316
|
-
|
|
337
|
+
)}
|
|
338
|
+
{
|
|
339
|
+
<AnimatedInOut
|
|
340
|
+
visible={isBackgroundImageVisible}
|
|
341
|
+
animationConfig={overlayFadeIn}
|
|
342
|
+
staticStyles={style}
|
|
343
|
+
>
|
|
344
|
+
<Image {...props} resizeMode="cover" style={style} applyMaxSize />
|
|
345
|
+
</AnimatedInOut>
|
|
346
|
+
}
|
|
347
|
+
</View>
|
|
317
348
|
</TrackedView>
|
|
318
349
|
);
|
|
319
350
|
};
|
|
@@ -3,7 +3,14 @@ import * as React from "react";
|
|
|
3
3
|
import { render } from "@testing-library/react-native";
|
|
4
4
|
import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
5
5
|
import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
|
|
6
|
+
import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
|
|
7
|
+
import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
8
|
+
|
|
6
9
|
import { PlayerLiveImage } from "../PlayerLiveImageComponent";
|
|
10
|
+
import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
11
|
+
|
|
12
|
+
import { Provider } from "react-redux";
|
|
13
|
+
import configureStore from "redux-mock-store";
|
|
7
14
|
|
|
8
15
|
const seekTo = jest.fn();
|
|
9
16
|
|
|
@@ -16,6 +23,27 @@ jest.mock(
|
|
|
16
23
|
})
|
|
17
24
|
);
|
|
18
25
|
|
|
26
|
+
jest
|
|
27
|
+
.spyOn(useNavigationHooks, "useNavigation")
|
|
28
|
+
.mockImplementation(() => ({ videoModalState: { visible: false } }));
|
|
29
|
+
|
|
30
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
|
|
31
|
+
|
|
32
|
+
const mockStore = configureStore();
|
|
33
|
+
|
|
34
|
+
const store = mockStore({ appData: {} });
|
|
35
|
+
|
|
36
|
+
const Wrapper = ({ children }: { children: React.ReactChildren }) => (
|
|
37
|
+
/* @ts-ignore */
|
|
38
|
+
<Provider store={store}>
|
|
39
|
+
<ThemeContext.Provider
|
|
40
|
+
value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
|
|
41
|
+
>
|
|
42
|
+
{children}
|
|
43
|
+
</ThemeContext.Provider>
|
|
44
|
+
</Provider>
|
|
45
|
+
);
|
|
46
|
+
|
|
19
47
|
describe("PlayerLiveImageComponent", () => {
|
|
20
48
|
const defaultProps = {
|
|
21
49
|
item: { id: "1", title: "Test", type: { value: "" } },
|
|
@@ -36,10 +64,16 @@ describe("PlayerLiveImageComponent", () => {
|
|
|
36
64
|
controller: new Player({}),
|
|
37
65
|
Component: () => null,
|
|
38
66
|
}));
|
|
67
|
+
|
|
68
|
+
jest.spyOn(navigationHooks, "useIsScreenActive").mockReturnValue(true);
|
|
39
69
|
});
|
|
40
70
|
|
|
41
71
|
it("should render correctly with default props", () => {
|
|
42
|
-
const component = render(
|
|
72
|
+
const component = render(
|
|
73
|
+
<Wrapper>
|
|
74
|
+
<PlayerLiveImage {...defaultProps} />
|
|
75
|
+
</Wrapper>
|
|
76
|
+
);
|
|
43
77
|
|
|
44
78
|
expect(component.toJSON()).toMatchSnapshot();
|
|
45
79
|
});
|
|
@@ -53,7 +87,11 @@ describe("PlayerLiveImageComponent", () => {
|
|
|
53
87
|
},
|
|
54
88
|
};
|
|
55
89
|
|
|
56
|
-
render(
|
|
90
|
+
render(
|
|
91
|
+
<Wrapper>
|
|
92
|
+
<PlayerLiveImage {...props} />
|
|
93
|
+
</Wrapper>
|
|
94
|
+
);
|
|
57
95
|
|
|
58
96
|
// TODO: implement this test
|
|
59
97
|
});
|
|
@@ -67,7 +105,11 @@ describe("PlayerLiveImageComponent", () => {
|
|
|
67
105
|
},
|
|
68
106
|
};
|
|
69
107
|
|
|
70
|
-
render(
|
|
108
|
+
render(
|
|
109
|
+
<Wrapper>
|
|
110
|
+
<PlayerLiveImage {...props} />
|
|
111
|
+
</Wrapper>
|
|
112
|
+
);
|
|
71
113
|
|
|
72
114
|
// TODO: implement this test
|
|
73
115
|
});
|
|
@@ -5,41 +5,33 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
|
|
|
5
5
|
onPositionUpdated={[Function]}
|
|
6
6
|
testId="tracked-view-player1-Test"
|
|
7
7
|
>
|
|
8
|
-
<View
|
|
9
|
-
collapsable={false}
|
|
10
|
-
style={
|
|
11
|
-
Object {
|
|
12
|
-
"opacity": 1,
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
>
|
|
8
|
+
<View>
|
|
16
9
|
<View
|
|
17
|
-
|
|
18
|
-
style={
|
|
10
|
+
collapsable={false}
|
|
11
|
+
style={
|
|
12
|
+
Object {
|
|
13
|
+
"opacity": 1,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
19
16
|
>
|
|
20
17
|
<Image
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
applyMaxSize={true}
|
|
19
|
+
audioMutedByDefault={false}
|
|
20
|
+
imageKey="image1"
|
|
21
|
+
item={
|
|
23
22
|
Object {
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
Array [
|
|
29
|
-
Object {
|
|
30
|
-
"bottom": 0,
|
|
31
|
-
"left": 0,
|
|
32
|
-
"position": "absolute",
|
|
33
|
-
"right": 0,
|
|
34
|
-
"top": 0,
|
|
35
|
-
},
|
|
36
|
-
Object {
|
|
37
|
-
"height": undefined,
|
|
38
|
-
"width": undefined,
|
|
23
|
+
"id": "1",
|
|
24
|
+
"title": "Test",
|
|
25
|
+
"type": Object {
|
|
26
|
+
"value": "",
|
|
39
27
|
},
|
|
40
|
-
|
|
41
|
-
]
|
|
28
|
+
}
|
|
42
29
|
}
|
|
30
|
+
onError={[Function]}
|
|
31
|
+
playerId="player1"
|
|
32
|
+
resizeMode="cover"
|
|
33
|
+
screenConfig={Object {}}
|
|
34
|
+
style={Object {}}
|
|
43
35
|
/>
|
|
44
36
|
</View>
|
|
45
37
|
</View>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Animated, ViewStyle } from "react-native";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
useModalAnimationContext,
|
|
6
|
+
PlayerAnimationStateEnum,
|
|
7
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
style: ViewStyle[];
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const AnimatedPlayerModalWrapper = (props: Props) => {
|
|
15
|
+
const {
|
|
16
|
+
playerAnimationState,
|
|
17
|
+
animatedValues: { lastScrollY, dragScrollY, translateYOffset },
|
|
18
|
+
modalSnapPoints,
|
|
19
|
+
setStartComponentsAnimation,
|
|
20
|
+
} = useModalAnimationContext();
|
|
21
|
+
|
|
22
|
+
const interpolateConfig: Animated.InterpolationConfigType = React.useMemo(
|
|
23
|
+
() => ({
|
|
24
|
+
inputRange: modalSnapPoints,
|
|
25
|
+
outputRange: modalSnapPoints,
|
|
26
|
+
extrapolate: "clamp",
|
|
27
|
+
}),
|
|
28
|
+
[modalSnapPoints]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
let translateY;
|
|
32
|
+
|
|
33
|
+
if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
|
|
34
|
+
translateY = translateYOffset.interpolate(interpolateConfig);
|
|
35
|
+
} else {
|
|
36
|
+
const reverseLastScrollY = Animated.multiply(
|
|
37
|
+
new Animated.Value(-1),
|
|
38
|
+
lastScrollY
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
translateY = Animated.add(
|
|
42
|
+
translateYOffset,
|
|
43
|
+
Animated.add(dragScrollY, reverseLastScrollY)
|
|
44
|
+
).interpolate(interpolateConfig);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
const translateYListener = translateY.addListener(() => {
|
|
49
|
+
(playerAnimationState === PlayerAnimationStateEnum.minimize ||
|
|
50
|
+
playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
|
|
51
|
+
setStartComponentsAnimation(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return () => {
|
|
55
|
+
translateYListener && translateY.removeListener(translateYListener);
|
|
56
|
+
};
|
|
57
|
+
}, [playerAnimationState]);
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<Animated.View
|
|
61
|
+
style={[props.style, { transform: [{ translateY: translateY }] }]}
|
|
62
|
+
>
|
|
63
|
+
{props.children}
|
|
64
|
+
</Animated.View>
|
|
65
|
+
);
|
|
66
|
+
};
|