@applicaster/zapp-react-native-ui-components 12.0.0-rc.12 → 12.0.0-rc.120
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/FastImage/index.android.js +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/FreezeWithCallback/Freeze.tsx +31 -0
- package/Components/FreezeWithCallback/LICENSE +21 -0
- package/Components/FreezeWithCallback/Suspender.tsx +17 -0
- package/Components/FreezeWithCallback/__tests__/index.test.tsx +170 -0
- package/Components/FreezeWithCallback/index.tsx +3 -0
- 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 -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 -117
- package/Components/MasterCell/DefaultComponents/CellBadge/index.tsx +21 -8
- 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 +71 -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 -10
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +7 -1
- 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 +66 -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/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 +1 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/index.web.tsx +178 -0
- package/Components/Screen/__tests__/Screen.test.tsx +43 -75
- 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 +104 -65
- package/Components/Screen/navigationHandler.ts +6 -85
- package/Components/Screen/orientationHandler.ts +18 -7
- package/Components/Screen/utils.ts +16 -0
- package/Components/ScreenResolver/index.tsx +10 -13
- package/Components/Tabs/TV/styles.ts +1 -1
- package/Components/TrackedView/index.tsx +6 -3
- package/Components/Transitioner/Scene.tsx +39 -26
- package/Components/Transitioner/Transitioner.tsx +46 -48
- package/Components/Transitioner/__tests__/Scene.test.js +7 -0
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -4
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -0
- package/Components/VideoLive/LiveImageManager.ts +70 -14
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +132 -95
- 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 +376 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +165 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +473 -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 +81 -49
- 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/ZappFrameworkComponents/BarView/BarView.tsx +4 -3
- 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/const.ts +6 -0
- package/events/index.ts +1 -0
- package/index.js +3 -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
|
@@ -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
|
|
|
@@ -479,6 +525,16 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
|
|
|
479
525
|
LiveImageManager.instance.onLiveImageError(this, error);
|
|
480
526
|
};
|
|
481
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
|
+
|
|
482
538
|
onVideoEnd = (_event) => {
|
|
483
539
|
log_info(
|
|
484
540
|
`onVideoEnd: live-image, video completed, switching back to image, ${playerInfo(
|
|
@@ -1,22 +1,20 @@
|
|
|
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
|
-
import { AppState, AppStateStatus } from "react-native";
|
|
5
|
+
import { AppState, AppStateStatus, View } from "react-native";
|
|
7
6
|
import { TrackedView } from "../TrackedView";
|
|
8
7
|
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
|
|
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,14 @@ 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
|
+
import { useEffect } from "react";
|
|
28
29
|
|
|
29
|
-
const { log_error } = loggerLiveImageComponent;
|
|
30
|
+
const { log_error, log_debug } = loggerLiveImageComponent;
|
|
30
31
|
|
|
31
|
-
const isMeasurement = (item) =>
|
|
32
|
-
|
|
33
|
-
};
|
|
32
|
+
const isMeasurement = (item: ZappEntry) =>
|
|
33
|
+
isString(item.id) && item.id.startsWith("pre-measurement-");
|
|
34
34
|
|
|
35
35
|
type Props = {
|
|
36
36
|
item: ZappEntry;
|
|
@@ -40,12 +40,13 @@ type Props = {
|
|
|
40
40
|
imageKey?: string;
|
|
41
41
|
screenConfig: Record<string, any>;
|
|
42
42
|
audioMutedByDefault?: boolean;
|
|
43
|
+
uri: string; // cover image url
|
|
43
44
|
};
|
|
44
45
|
|
|
45
46
|
const PlayerLiveImageComponent = (props: Props) => {
|
|
46
47
|
const dimensions = useDimensions("screen", { fullDimensions: true });
|
|
47
48
|
|
|
48
|
-
const { item, style, playerId
|
|
49
|
+
const { item, style, playerId } = props;
|
|
49
50
|
|
|
50
51
|
const timeoutRef = React.useRef<NodeJS.Timeout | null>(null);
|
|
51
52
|
const [mode, setMode] = React.useState(LiveImageType.Image);
|
|
@@ -55,20 +56,18 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
55
56
|
isTV() ? false : getUserCellPlayerMutedPreference(props.audioMutedByDefault)
|
|
56
57
|
);
|
|
57
58
|
|
|
58
|
-
const [PlayerViewComponent, setPlayerViewComponent] = React.useState(null);
|
|
59
|
-
const Player: any = PlayerViewComponent || BufferAnimation;
|
|
60
|
-
|
|
61
59
|
const ref = React.useRef(null);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
60
|
+
const trackViewRef = React.useRef(null);
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Debounced setMode function.
|
|
64
|
+
*
|
|
65
|
+
* Sets to video with a 1sec delay. Set to image happens immediately and cancels the timeout.
|
|
66
|
+
*
|
|
67
|
+
* @param type video or image
|
|
68
|
+
*/
|
|
69
|
+
const setModeDebounced = React.useCallback(
|
|
70
|
+
(type: LiveImageType) => {
|
|
72
71
|
if (type === LiveImageType.Video) {
|
|
73
72
|
if (type === mode) {
|
|
74
73
|
return;
|
|
@@ -80,45 +79,69 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
80
79
|
} else {
|
|
81
80
|
if (timeoutRef.current) {
|
|
82
81
|
clearTimeout(timeoutRef.current);
|
|
82
|
+
timeoutRef.current = null;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
setMode(type);
|
|
86
86
|
}
|
|
87
|
-
}
|
|
87
|
+
},
|
|
88
|
+
[mode]
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const entryToViewIdMapping = React.useRef({});
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
const nativeTag = trackViewRef.current?._nativeTag?.toString();
|
|
95
|
+
|
|
96
|
+
if (!nativeTag) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const prevValue = entryToViewIdMapping.current[nativeTag];
|
|
88
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
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
entryToViewIdMapping.current[nativeTag] = { itemId: item.id };
|
|
113
|
+
}, [trackViewRef.current, item.id, mode]);
|
|
114
|
+
|
|
115
|
+
const { screenConfig, playerPluginId } = props;
|
|
116
|
+
|
|
117
|
+
const liveImageItem: LiveImage = React.useMemo(() => {
|
|
89
118
|
const playerFactoryItem = playerFactory({
|
|
90
119
|
player: ref,
|
|
91
|
-
listener: props as Record<string, any>,
|
|
92
120
|
playerId,
|
|
93
121
|
autoplay: false,
|
|
94
122
|
entry: item,
|
|
95
|
-
muted,
|
|
96
|
-
playerPluginId:
|
|
97
|
-
screenConfig:
|
|
123
|
+
muted, // Initial muted state, not needed in dependencies
|
|
124
|
+
playerPluginId: playerPluginId,
|
|
125
|
+
screenConfig: screenConfig,
|
|
98
126
|
playerRole: PlayerRole.Cell,
|
|
99
127
|
});
|
|
100
128
|
|
|
101
|
-
const Component = playerFactoryItem?.Component;
|
|
102
|
-
|
|
103
|
-
if (!R.isNil(Component) && Component !== PlayerViewComponent) {
|
|
104
|
-
setPlayerViewComponent(Component);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
129
|
if (playerFactoryItem) {
|
|
108
130
|
return new LiveImage({
|
|
109
131
|
playerId,
|
|
110
132
|
player: playerFactoryItem.controller,
|
|
111
|
-
|
|
133
|
+
component: playerFactoryItem?.Component,
|
|
112
134
|
});
|
|
113
135
|
} else {
|
|
114
136
|
throw new Error("Player factory item is null");
|
|
115
137
|
}
|
|
116
|
-
}, [playerId, item
|
|
138
|
+
}, [playerId, item, playerPluginId, screenConfig]);
|
|
117
139
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
140
|
+
React.useEffect(() => {
|
|
141
|
+
liveImageItem.setMode = setModeDebounced;
|
|
142
|
+
}, [setModeDebounced, liveImageItem]);
|
|
143
|
+
|
|
144
|
+
const { start, end } = React.useMemo(() => getAutoplaySettings(item), [item]);
|
|
122
145
|
|
|
123
146
|
const controller = liveImageItem.getPlayer();
|
|
124
147
|
const player = usePlayer(playerId);
|
|
@@ -127,6 +150,10 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
127
150
|
ref.current = component;
|
|
128
151
|
};
|
|
129
152
|
|
|
153
|
+
const onLiveImageCompleted = React.useCallback(() => {
|
|
154
|
+
LiveImageManager.instance.onLiveImageCompleted(liveImageItem);
|
|
155
|
+
}, [liveImageItem]);
|
|
156
|
+
|
|
130
157
|
const onStop = React.useCallback(() => {
|
|
131
158
|
LiveImageManager.instance.pauseLiveImage(liveImageItem);
|
|
132
159
|
}, [liveImageItem]);
|
|
@@ -140,13 +167,14 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
140
167
|
const unregister = LiveImageManager.instance.register(liveImageItem);
|
|
141
168
|
|
|
142
169
|
return () => {
|
|
143
|
-
unregister();
|
|
144
|
-
|
|
145
170
|
if (timeoutRef.current) {
|
|
146
171
|
clearTimeout(timeoutRef.current);
|
|
172
|
+
timeoutRef.current = null;
|
|
147
173
|
}
|
|
174
|
+
|
|
175
|
+
unregister();
|
|
148
176
|
};
|
|
149
|
-
}, [
|
|
177
|
+
}, [item, liveImageItem]);
|
|
150
178
|
|
|
151
179
|
React.useEffect(() => {
|
|
152
180
|
if (!player) {
|
|
@@ -178,11 +206,12 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
178
206
|
setMuted(false);
|
|
179
207
|
},
|
|
180
208
|
onPlayerClose: () => {
|
|
209
|
+
onLiveImageCompleted();
|
|
181
210
|
setIsReady(false);
|
|
182
211
|
},
|
|
183
212
|
},
|
|
184
213
|
});
|
|
185
|
-
}, [player, onStop]);
|
|
214
|
+
}, [player, onStop, onLiveImageCompleted, start, end]);
|
|
186
215
|
|
|
187
216
|
React.useEffect(() => {
|
|
188
217
|
const subscription = AppState.addEventListener(
|
|
@@ -233,40 +262,48 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
233
262
|
};
|
|
234
263
|
}
|
|
235
264
|
}
|
|
236
|
-
}, [liveImageItem]);
|
|
237
|
-
|
|
238
|
-
const onPositionUpdated = (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
265
|
+
}, [liveImageItem, playerId, controller]);
|
|
266
|
+
|
|
267
|
+
const onPositionUpdated = React.useCallback(
|
|
268
|
+
(data) => {
|
|
269
|
+
const normalizedRect = (rect: {
|
|
270
|
+
left: number;
|
|
271
|
+
right: number;
|
|
272
|
+
top: number;
|
|
273
|
+
bottom: number;
|
|
274
|
+
}) => {
|
|
275
|
+
if (!rect) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
243
278
|
|
|
244
|
-
|
|
279
|
+
const { left, right, top, bottom } = rect;
|
|
245
280
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
281
|
+
return {
|
|
282
|
+
left: left / dimensions.width,
|
|
283
|
+
right: right / dimensions.width,
|
|
284
|
+
top: top / dimensions.height,
|
|
285
|
+
bottom: bottom / dimensions.height,
|
|
286
|
+
centerX: (left + right) / 2 / dimensions.width,
|
|
287
|
+
centerY: (top + bottom) / 2 / dimensions.height,
|
|
288
|
+
};
|
|
253
289
|
};
|
|
254
|
-
};
|
|
255
290
|
|
|
256
|
-
|
|
291
|
+
liveImageItem.position = normalizedRect(data.rect);
|
|
257
292
|
|
|
258
|
-
|
|
293
|
+
const newIsFullyVisible = !!data.rect;
|
|
259
294
|
|
|
260
|
-
|
|
261
|
-
|
|
295
|
+
if (liveImageItem.isFullyVisible !== newIsFullyVisible) {
|
|
296
|
+
liveImageItem.isFullyVisible = newIsFullyVisible;
|
|
262
297
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
298
|
+
liveImageItem.isFullyVisible
|
|
299
|
+
? LiveImageManager.instance.onViewportEnter(liveImageItem)
|
|
300
|
+
: LiveImageManager.instance.onViewportLeave(liveImageItem);
|
|
301
|
+
} else {
|
|
302
|
+
LiveImageManager.instance.checkPlayerPosition(liveImageItem);
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
[liveImageItem, dimensions]
|
|
306
|
+
);
|
|
270
307
|
|
|
271
308
|
const platformSpecificProps = isApplePlatform()
|
|
272
309
|
? { hideNativeControls: true, controls: false }
|
|
@@ -276,38 +313,38 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
276
313
|
const isVideoMode = mode === LiveImageType.Video;
|
|
277
314
|
const isBackgroundImageVisible = isImageMode || !isReadyToPlay;
|
|
278
315
|
const videoStyles = { ...style, position: "absolute", zIndex: -100 };
|
|
316
|
+
const Player: any = liveImageItem.component || BufferAnimation;
|
|
279
317
|
|
|
318
|
+
// TODO: nice to have - resolve imageKey when imageUrl is not provided
|
|
280
319
|
return (
|
|
281
320
|
<TrackedView
|
|
282
321
|
testId={`tracked-view-${playerId}-${item.title}`}
|
|
283
322
|
onPositionUpdated={onPositionUpdated}
|
|
284
323
|
>
|
|
285
|
-
{
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
)}
|
|
298
|
-
{
|
|
299
|
-
<AnimatedInOut
|
|
300
|
-
visible={isBackgroundImageVisible}
|
|
301
|
-
animationConfig={overlayFadeIn}
|
|
302
|
-
staticStyles={style}
|
|
303
|
-
>
|
|
304
|
-
<PlayerImageBackground
|
|
305
|
-
entry={item}
|
|
306
|
-
style={style}
|
|
307
|
-
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}
|
|
308
336
|
/>
|
|
309
|
-
|
|
310
|
-
|
|
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>
|
|
311
348
|
</TrackedView>
|
|
312
349
|
);
|
|
313
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
|
});
|