@applicaster/zapp-react-native-ui-components 12.0.0-rc.7 → 12.0.0-rc.70
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 +1 -1
- package/Components/Cell/Cell.tsx +7 -7
- package/Components/Cell/CellWithFocusable.tsx +38 -19
- package/Components/Cell/TvOSCellComponent.tsx +2 -2
- package/Components/ErrorScreen/index.tsx +1 -1
- package/Components/FocusableCell/index.tsx +7 -7
- package/Components/FocusableGroup/index.tsx +1 -0
- 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 +11 -8
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +4 -1
- package/Components/HookRenderer/index.tsx +1 -6
- package/Components/Image/Image.android.tsx +3 -26
- package/Components/Image/Image.tsx +18 -2
- package/Components/Image/utils/index.ts +39 -0
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +18 -107
- package/Components/Layout/TV/index.tsx +9 -121
- package/Components/Layout/index.tsx +1 -9
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +80 -110
- package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- 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/ImageContainer/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +17 -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/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- package/Components/MasterCell/utils/index.ts +16 -5
- 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 +48 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +64 -31
- 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/River.tsx +8 -5
- 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 +5 -6
- 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 +179 -0
- package/Components/Screen/__tests__/Screen.test.tsx +48 -36
- 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 +103 -44
- package/Components/Screen/navigationHandler.ts +0 -82
- package/Components/Screen/orientationHandler.ts +1 -1
- package/Components/ScreenResolver/index.tsx +4 -2
- package/Components/Tabs/TV/styles.ts +1 -1
- package/Components/TrackedView/index.tsx +6 -3
- package/Components/Transitioner/Scene.tsx +24 -19
- package/Components/Transitioner/Transitioner.tsx +9 -2
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +60 -14
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +81 -72
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +45 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +18 -28
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +154 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
- package/Components/VideoModal/PlayerDetails.tsx +6 -3
- package/Components/VideoModal/PlayerWrapper.tsx +82 -50
- 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 +246 -166
- package/Components/VideoModal/hooks/useModalSize.ts +13 -4
- package/Components/VideoModal/utils.ts +3 -3
- 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/index.js +2 -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.ts +3 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
- package/Decorators/RiverResolver/index.tsx +0 -4
- package/Decorators/index.tsx +0 -4
- package/events/index.ts +1 -0
- package/package.json +5 -6
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- package/Components/VideoModal/hooks/usePosition.ts +0 -50
- /package/Contexts/{index.js → index.ts} +0 -0
|
@@ -6,10 +6,15 @@ import {
|
|
|
6
6
|
import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
|
|
7
7
|
import { loggerLiveImageManager } from "./loggerHelper";
|
|
8
8
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
9
|
+
import { Component } from "react";
|
|
9
10
|
|
|
10
11
|
const { log_debug, log_info, log_error } = loggerLiveImageManager;
|
|
11
12
|
|
|
12
|
-
export type LiveImageManagerEvent =
|
|
13
|
+
export type LiveImageManagerEvent =
|
|
14
|
+
| "onEnd"
|
|
15
|
+
| "onStart"
|
|
16
|
+
| "onError"
|
|
17
|
+
| "onDestroy";
|
|
13
18
|
|
|
14
19
|
export type LiveImageManagerListenerData = {
|
|
15
20
|
id: string;
|
|
@@ -36,7 +41,8 @@ type Position = {
|
|
|
36
41
|
type LiveImageProps = {
|
|
37
42
|
player: Player;
|
|
38
43
|
playerId: string;
|
|
39
|
-
setMode
|
|
44
|
+
setMode?: (type: LiveImageType) => void;
|
|
45
|
+
component: Component;
|
|
40
46
|
// TODO: ...primary, powerCell, tvGallery, etc.
|
|
41
47
|
// type: string;
|
|
42
48
|
};
|
|
@@ -100,6 +106,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
100
106
|
}
|
|
101
107
|
|
|
102
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
|
+
});
|
|
103
119
|
};
|
|
104
120
|
|
|
105
121
|
public onViewportEnter = (item: LiveImage) => {
|
|
@@ -164,7 +180,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
164
180
|
|
|
165
181
|
// Fake close event, because we unmount native view
|
|
166
182
|
item.player?.onPlayerClose();
|
|
167
|
-
item.setMode(LiveImageType.Image);
|
|
183
|
+
item.setMode?.(LiveImageType.Image);
|
|
168
184
|
|
|
169
185
|
if (item === this.currentlyPlaying) {
|
|
170
186
|
this.currentlyPlaying = null;
|
|
@@ -191,8 +207,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
191
207
|
}
|
|
192
208
|
|
|
193
209
|
this.currentlyPlaying = item;
|
|
194
|
-
|
|
195
|
-
item.setMode(LiveImageType.Video);
|
|
210
|
+
item.setMode?.(LiveImageType.Video);
|
|
196
211
|
|
|
197
212
|
if (item.player.playerState.isReadyToPlay) {
|
|
198
213
|
item.player.play();
|
|
@@ -209,6 +224,11 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
209
224
|
this.pauseItem(item);
|
|
210
225
|
};
|
|
211
226
|
|
|
227
|
+
public onLiveImageCompleted = (_item: LiveImage) => {
|
|
228
|
+
// TODO: Notify listeners that player has died
|
|
229
|
+
// Do not try look for new playable, otherwise you will restart video finish to play
|
|
230
|
+
};
|
|
231
|
+
|
|
212
232
|
public muteAll = () => {
|
|
213
233
|
log_debug("muteAll");
|
|
214
234
|
|
|
@@ -235,6 +255,14 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
235
255
|
const playerItem = this.findNextPlayableItem();
|
|
236
256
|
|
|
237
257
|
if (playerItem) {
|
|
258
|
+
if (!playerItem.isFullyVisible) {
|
|
259
|
+
log_error(
|
|
260
|
+
`checkPlayerPosition: trying to start playback currently invisible item: ${playerInfo(
|
|
261
|
+
playerItem.player
|
|
262
|
+
)}`
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
|
|
238
266
|
// Will also check if it's item that already playing
|
|
239
267
|
this.playLiveImage(playerItem);
|
|
240
268
|
}
|
|
@@ -242,7 +270,6 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
242
270
|
|
|
243
271
|
onPrimaryPlayerClosed = () => {
|
|
244
272
|
const playerItem = this.findNextPlayableItem();
|
|
245
|
-
|
|
246
273
|
log_info("onPrimaryPlayerClosed: starting to play visible live-image");
|
|
247
274
|
|
|
248
275
|
this.currentlyPlaying = null;
|
|
@@ -338,6 +365,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
338
365
|
item,
|
|
339
366
|
playerId: this.currentlyPlaying?.playerId,
|
|
340
367
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
368
|
+
entry: item.getPlayer().getEntry(),
|
|
341
369
|
},
|
|
342
370
|
});
|
|
343
371
|
};
|
|
@@ -356,12 +384,12 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
356
384
|
// TODO: This branch was used when we had play button to toggle replay.
|
|
357
385
|
// Now we mute button instead but we keep it just in case.
|
|
358
386
|
if (IS_ALLOWED_REPLAY && !isTV() && isCurrentItemEnded) {
|
|
359
|
-
this.currentlyPlaying
|
|
360
|
-
this.currentlyPlaying
|
|
387
|
+
this.currentlyPlaying?.player.seekTo(0);
|
|
388
|
+
this.currentlyPlaying?.player.pause();
|
|
361
389
|
|
|
362
390
|
// TODO: ...Maybe player some other item
|
|
363
391
|
} else {
|
|
364
|
-
item.setMode(LiveImageType.Image);
|
|
392
|
+
item.setMode?.(LiveImageType.Image);
|
|
365
393
|
}
|
|
366
394
|
|
|
367
395
|
// Prevent receiving onEnd event from both `close` and `end` player events
|
|
@@ -372,15 +400,31 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
372
400
|
item,
|
|
373
401
|
playerId: this.currentlyPlaying?.playerId,
|
|
374
402
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
403
|
+
entry: item.getPlayer().getEntry(),
|
|
375
404
|
},
|
|
376
405
|
});
|
|
377
406
|
};
|
|
378
407
|
|
|
379
408
|
onLiveImageError = (item: LiveImage, error: Error) => {
|
|
380
|
-
item.setMode(LiveImageType.Image);
|
|
409
|
+
item.setMode?.(LiveImageType.Image);
|
|
381
410
|
|
|
382
|
-
|
|
411
|
+
const currentItem = this.currentlyPlaying;
|
|
412
|
+
|
|
413
|
+
log_debug(
|
|
414
|
+
`onLiveImageError: error: ${error.message}, live-image ${playerInfo(
|
|
415
|
+
item.player
|
|
416
|
+
)}, currentPlayingId: ${
|
|
417
|
+
this.currentlyPlaying?.playerId
|
|
418
|
+
}, primaryPlayerId: ${this.primaryPlayer?.playerId}`
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
if (currentItem === item) {
|
|
383
422
|
this.currentlyPlaying = null;
|
|
423
|
+
|
|
424
|
+
log_debug(
|
|
425
|
+
`onLiveImageError: currentitem: ${currentItem.playerId} was removed`
|
|
426
|
+
);
|
|
427
|
+
|
|
384
428
|
// TODO: ...Maybe player some other item
|
|
385
429
|
}
|
|
386
430
|
|
|
@@ -389,8 +433,9 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
389
433
|
event: {
|
|
390
434
|
item,
|
|
391
435
|
error,
|
|
392
|
-
playerId:
|
|
393
|
-
primaryPlayerId:
|
|
436
|
+
playerId: currentItem?.playerId,
|
|
437
|
+
primaryPlayerId: currentItem?.playerId,
|
|
438
|
+
entry: item.getPlayer().getEntry(),
|
|
394
439
|
},
|
|
395
440
|
});
|
|
396
441
|
};
|
|
@@ -446,12 +491,13 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
|
|
|
446
491
|
};
|
|
447
492
|
|
|
448
493
|
readonly playerId: string;
|
|
494
|
+
readonly component: Component;
|
|
449
495
|
|
|
450
496
|
constructor(props: LiveImageProps) {
|
|
451
497
|
this.player = props.player;
|
|
452
498
|
this.setMode = props.setMode;
|
|
453
499
|
this.playerId = this.player.playerId;
|
|
454
|
-
|
|
500
|
+
this.component = props.component;
|
|
455
501
|
this.player.addListener({ id: "live-image", listener: this });
|
|
456
502
|
}
|
|
457
503
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// /// <reference types="@applicaster/applicaster-types" />
|
|
2
2
|
//
|
|
3
3
|
import * as React from "react";
|
|
4
|
-
import * as R from "ramda";
|
|
5
4
|
|
|
6
5
|
import { AppState, AppStateStatus } from "react-native";
|
|
7
6
|
import { TrackedView } from "../TrackedView";
|
|
@@ -9,14 +8,13 @@ import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/l
|
|
|
9
8
|
|
|
10
9
|
import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
11
10
|
|
|
12
|
-
import { BufferAnimation } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/BufferAnimation";
|
|
13
11
|
import {
|
|
14
12
|
isApplePlatform,
|
|
15
13
|
isTV,
|
|
16
14
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
17
15
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
18
16
|
import { getUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
|
|
19
|
-
import
|
|
17
|
+
import Image from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/Image";
|
|
20
18
|
import { LiveImage, LiveImageManager, LiveImageType } from "./LiveImageManager";
|
|
21
19
|
|
|
22
20
|
import { AnimatedInOut } from "@applicaster/zapp-react-native-ui-components/Components/AnimatedInOut";
|
|
@@ -25,12 +23,13 @@ import { loggerLiveImageComponent } from "./loggerHelper";
|
|
|
25
23
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
26
24
|
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
|
|
27
25
|
import { getAutoplaySettings } from "./utils";
|
|
26
|
+
import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
27
|
+
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
28
28
|
|
|
29
29
|
const { log_error } = loggerLiveImageComponent;
|
|
30
30
|
|
|
31
|
-
const isMeasurement = (item) =>
|
|
32
|
-
|
|
33
|
-
};
|
|
31
|
+
const isMeasurement = (item: ZappEntry) =>
|
|
32
|
+
isString(item.id) && item.id.startsWith("pre-measurement-");
|
|
34
33
|
|
|
35
34
|
type Props = {
|
|
36
35
|
item: ZappEntry;
|
|
@@ -40,12 +39,13 @@ type Props = {
|
|
|
40
39
|
imageKey?: string;
|
|
41
40
|
screenConfig: Record<string, any>;
|
|
42
41
|
audioMutedByDefault?: boolean;
|
|
42
|
+
uri: string; // cover image url
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
const PlayerLiveImageComponent = (props: Props) => {
|
|
46
46
|
const dimensions = useDimensions("screen", { fullDimensions: true });
|
|
47
47
|
|
|
48
|
-
const { item, style, playerId
|
|
48
|
+
const { item, style, playerId } = props;
|
|
49
49
|
|
|
50
50
|
const timeoutRef = React.useRef<NodeJS.Timeout | null>(null);
|
|
51
51
|
const [mode, setMode] = React.useState(LiveImageType.Image);
|
|
@@ -55,20 +55,17 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
55
55
|
isTV() ? false : getUserCellPlayerMutedPreference(props.audioMutedByDefault)
|
|
56
56
|
);
|
|
57
57
|
|
|
58
|
-
const [PlayerViewComponent, setPlayerViewComponent] = React.useState(null);
|
|
59
|
-
const Player: any = PlayerViewComponent || BufferAnimation;
|
|
60
|
-
|
|
61
58
|
const ref = React.useRef(null);
|
|
62
59
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Debounced setMode function.
|
|
62
|
+
*
|
|
63
|
+
* Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
|
|
64
|
+
*
|
|
65
|
+
* @param type video or image
|
|
66
|
+
*/
|
|
67
|
+
const setModeDebounced = React.useCallback(
|
|
68
|
+
(type: LiveImageType) => {
|
|
72
69
|
if (type === LiveImageType.Video) {
|
|
73
70
|
if (type === mode) {
|
|
74
71
|
return;
|
|
@@ -80,45 +77,45 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
80
77
|
} else {
|
|
81
78
|
if (timeoutRef.current) {
|
|
82
79
|
clearTimeout(timeoutRef.current);
|
|
80
|
+
timeoutRef.current = null;
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
setMode(type);
|
|
86
84
|
}
|
|
87
|
-
}
|
|
85
|
+
},
|
|
86
|
+
[mode]
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const { screenConfig, playerPluginId } = props;
|
|
88
90
|
|
|
91
|
+
const liveImageItem: LiveImage = React.useMemo(() => {
|
|
89
92
|
const playerFactoryItem = playerFactory({
|
|
90
93
|
player: ref,
|
|
91
|
-
listener: props as Record<string, any>,
|
|
92
94
|
playerId,
|
|
93
95
|
autoplay: false,
|
|
94
96
|
entry: item,
|
|
95
|
-
muted,
|
|
96
|
-
playerPluginId:
|
|
97
|
-
screenConfig:
|
|
97
|
+
muted, // Initial muted state, not needed in dependencies
|
|
98
|
+
playerPluginId: playerPluginId,
|
|
99
|
+
screenConfig: screenConfig,
|
|
98
100
|
playerRole: PlayerRole.Cell,
|
|
99
101
|
});
|
|
100
102
|
|
|
101
|
-
const Component = playerFactoryItem?.Component;
|
|
102
|
-
|
|
103
|
-
if (!R.isNil(Component) && Component !== PlayerViewComponent) {
|
|
104
|
-
setPlayerViewComponent(Component);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
103
|
if (playerFactoryItem) {
|
|
108
104
|
return new LiveImage({
|
|
109
105
|
playerId,
|
|
110
106
|
player: playerFactoryItem.controller,
|
|
111
|
-
|
|
107
|
+
component: playerFactoryItem?.Component,
|
|
112
108
|
});
|
|
113
109
|
} else {
|
|
114
110
|
throw new Error("Player factory item is null");
|
|
115
111
|
}
|
|
116
|
-
}, [playerId, item
|
|
112
|
+
}, [playerId, item, playerPluginId, screenConfig]);
|
|
117
113
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
React.useEffect(() => {
|
|
115
|
+
liveImageItem.setMode = setModeDebounced;
|
|
116
|
+
}, [setModeDebounced, liveImageItem]);
|
|
117
|
+
|
|
118
|
+
const { start, end } = React.useMemo(() => getAutoplaySettings(item), [item]);
|
|
122
119
|
|
|
123
120
|
const controller = liveImageItem.getPlayer();
|
|
124
121
|
const player = usePlayer(playerId);
|
|
@@ -127,6 +124,10 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
127
124
|
ref.current = component;
|
|
128
125
|
};
|
|
129
126
|
|
|
127
|
+
const onLiveImageCompleted = React.useCallback(() => {
|
|
128
|
+
LiveImageManager.instance.onLiveImageCompleted(liveImageItem);
|
|
129
|
+
}, [liveImageItem]);
|
|
130
|
+
|
|
130
131
|
const onStop = React.useCallback(() => {
|
|
131
132
|
LiveImageManager.instance.pauseLiveImage(liveImageItem);
|
|
132
133
|
}, [liveImageItem]);
|
|
@@ -140,13 +141,14 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
140
141
|
const unregister = LiveImageManager.instance.register(liveImageItem);
|
|
141
142
|
|
|
142
143
|
return () => {
|
|
143
|
-
unregister();
|
|
144
|
-
|
|
145
144
|
if (timeoutRef.current) {
|
|
146
145
|
clearTimeout(timeoutRef.current);
|
|
146
|
+
timeoutRef.current = null;
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
unregister();
|
|
148
150
|
};
|
|
149
|
-
}, [
|
|
151
|
+
}, [item, liveImageItem]);
|
|
150
152
|
|
|
151
153
|
React.useEffect(() => {
|
|
152
154
|
if (!player) {
|
|
@@ -178,11 +180,12 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
178
180
|
setMuted(false);
|
|
179
181
|
},
|
|
180
182
|
onPlayerClose: () => {
|
|
183
|
+
onLiveImageCompleted();
|
|
181
184
|
setIsReady(false);
|
|
182
185
|
},
|
|
183
186
|
},
|
|
184
187
|
});
|
|
185
|
-
}, [player, onStop]);
|
|
188
|
+
}, [player, onStop, onLiveImageCompleted, start, end]);
|
|
186
189
|
|
|
187
190
|
React.useEffect(() => {
|
|
188
191
|
const subscription = AppState.addEventListener(
|
|
@@ -233,40 +236,48 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
233
236
|
};
|
|
234
237
|
}
|
|
235
238
|
}
|
|
236
|
-
}, [liveImageItem]);
|
|
237
|
-
|
|
238
|
-
const onPositionUpdated = (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
}, [liveImageItem, playerId, controller]);
|
|
240
|
+
|
|
241
|
+
const onPositionUpdated = React.useCallback(
|
|
242
|
+
(data) => {
|
|
243
|
+
const normalizedRect = (rect: {
|
|
244
|
+
left: number;
|
|
245
|
+
right: number;
|
|
246
|
+
top: number;
|
|
247
|
+
bottom: number;
|
|
248
|
+
}) => {
|
|
249
|
+
if (!rect) {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
243
252
|
|
|
244
|
-
|
|
253
|
+
const { left, right, top, bottom } = rect;
|
|
245
254
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
return {
|
|
256
|
+
left: left / dimensions.width,
|
|
257
|
+
right: right / dimensions.width,
|
|
258
|
+
top: top / dimensions.height,
|
|
259
|
+
bottom: bottom / dimensions.height,
|
|
260
|
+
centerX: (left + right) / 2 / dimensions.width,
|
|
261
|
+
centerY: (top + bottom) / 2 / dimensions.height,
|
|
262
|
+
};
|
|
253
263
|
};
|
|
254
|
-
};
|
|
255
264
|
|
|
256
|
-
|
|
265
|
+
liveImageItem.position = normalizedRect(data.rect);
|
|
257
266
|
|
|
258
|
-
|
|
267
|
+
const newIsFullyVisible = !!data.rect;
|
|
259
268
|
|
|
260
|
-
|
|
261
|
-
|
|
269
|
+
if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
|
|
270
|
+
liveImageItem.isFullyVisible = newIsFullyVisible;
|
|
262
271
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
272
|
+
liveImageItem.isFullyVisible
|
|
273
|
+
? LiveImageManager.instance.onViewportEnter(liveImageItem)
|
|
274
|
+
: LiveImageManager.instance.onViewportLeave(liveImageItem);
|
|
275
|
+
} else {
|
|
276
|
+
LiveImageManager.instance.checkPlayerPosition(liveImageItem);
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
[liveImageItem, dimensions]
|
|
280
|
+
);
|
|
270
281
|
|
|
271
282
|
const platformSpecificProps = isApplePlatform()
|
|
272
283
|
? { hideNativeControls: true, controls: false }
|
|
@@ -276,7 +287,9 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
276
287
|
const isVideoMode = mode === LiveImageType.Video;
|
|
277
288
|
const isBackgroundImageVisible = isImageMode || !isReadyToPlay;
|
|
278
289
|
const videoStyles = { ...style, position: "absolute", zIndex: -100 };
|
|
290
|
+
const Player: any = liveImageItem.component || BufferAnimation;
|
|
279
291
|
|
|
292
|
+
// TODO: nice to have - resolve imageKey when imageUrl is not provided
|
|
280
293
|
return (
|
|
281
294
|
<TrackedView
|
|
282
295
|
testId={`tracked-view-${playerId}-${item.title}`}
|
|
@@ -301,11 +314,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
301
314
|
animationConfig={overlayFadeIn}
|
|
302
315
|
staticStyles={style}
|
|
303
316
|
>
|
|
304
|
-
<
|
|
305
|
-
entry={item}
|
|
306
|
-
style={style}
|
|
307
|
-
imageKey={imageKey}
|
|
308
|
-
/>
|
|
317
|
+
<Image {...props} resizeMode="cover" style={style} applyMaxSize />
|
|
309
318
|
</AnimatedInOut>
|
|
310
319
|
}
|
|
311
320
|
</TrackedView>
|
|
@@ -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
|
});
|
|
@@ -13,35 +13,25 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
>
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
style={
|
|
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,
|
|
39
|
-
},
|
|
40
|
-
undefined,
|
|
41
|
-
]
|
|
16
|
+
<Image
|
|
17
|
+
applyMaxSize={true}
|
|
18
|
+
audioMutedByDefault={false}
|
|
19
|
+
imageKey="image1"
|
|
20
|
+
item={
|
|
21
|
+
Object {
|
|
22
|
+
"id": "1",
|
|
23
|
+
"title": "Test",
|
|
24
|
+
"type": Object {
|
|
25
|
+
"value": "",
|
|
26
|
+
},
|
|
42
27
|
}
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
}
|
|
29
|
+
onError={[Function]}
|
|
30
|
+
playerId="player1"
|
|
31
|
+
resizeMode="cover"
|
|
32
|
+
screenConfig={Object {}}
|
|
33
|
+
style={Object {}}
|
|
34
|
+
/>
|
|
45
35
|
</View>
|
|
46
36
|
</TrackedView>
|
|
47
37
|
`;
|
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
9
|
+
|
|
10
|
+
type Props = {
|
|
11
|
+
style: ViewStyle[];
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const AnimatedPlayerModalWrapper = (props: Props) => {
|
|
16
|
+
const {
|
|
17
|
+
playerAnimationState,
|
|
18
|
+
animatedValues: { lastScrollY, dragScrollY, translateYOffset },
|
|
19
|
+
modalSnapPoints,
|
|
20
|
+
setStartComponentsAnimation,
|
|
21
|
+
lastScrollYValue,
|
|
22
|
+
} = useModalAnimationContext();
|
|
23
|
+
|
|
24
|
+
const { height: screenHeight } = useDimensions("screen", {
|
|
25
|
+
deviceInfo: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const interpolateConfig: Animated.InterpolationConfigType = React.useMemo(
|
|
29
|
+
() => ({
|
|
30
|
+
inputRange: modalSnapPoints,
|
|
31
|
+
outputRange: modalSnapPoints,
|
|
32
|
+
extrapolate: "clamp",
|
|
33
|
+
}),
|
|
34
|
+
[modalSnapPoints]
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
let translateY;
|
|
38
|
+
|
|
39
|
+
if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
|
|
40
|
+
translateY = translateYOffset.interpolate(interpolateConfig);
|
|
41
|
+
} else {
|
|
42
|
+
const reverseLastScrollY = Animated.multiply(
|
|
43
|
+
new Animated.Value(-1),
|
|
44
|
+
lastScrollY
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
translateY = Animated.add(
|
|
48
|
+
translateYOffset,
|
|
49
|
+
Animated.add(dragScrollY, reverseLastScrollY)
|
|
50
|
+
).interpolate(interpolateConfig);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
React.useEffect(() => {
|
|
54
|
+
const translateYListener = translateY.addListener(({ value }) => {
|
|
55
|
+
const preparedValue = Math.round(
|
|
56
|
+
Math.abs(value) - lastScrollYValue.current
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
(playerAnimationState === PlayerAnimationStateEnum.minimize ||
|
|
60
|
+
playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
|
|
61
|
+
setStartComponentsAnimation(
|
|
62
|
+
preparedValue >= Math.round((screenHeight * 10) / 100)
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
translateYListener && translateY.removeListener(translateYListener);
|
|
68
|
+
};
|
|
69
|
+
}, [playerAnimationState]);
|
|
70
|
+
|
|
71
|
+
return (
|
|
72
|
+
<Animated.View
|
|
73
|
+
style={[props.style, { transform: [{ translateY: translateY }] }]}
|
|
74
|
+
>
|
|
75
|
+
{props.children}
|
|
76
|
+
</Animated.View>
|
|
77
|
+
);
|
|
78
|
+
};
|