@applicaster/zapp-react-native-ui-components 12.0.0-rc.9 → 12.0.0-rc.91
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 +12 -7
- 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 +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/ScreenContainer.tsx +84 -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 +2 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +88 -113
- 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/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 +10 -2
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +6 -10
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- 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 -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 +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 +169 -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 +131 -44
- package/Components/Screen/navigationHandler.ts +0 -82
- 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 +21 -28
- 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 +70 -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 +352 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +158 -0
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +455 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +162 -0
- package/Components/VideoModal/ModalAnimation/index.ts +15 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +301 -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 +266 -166
- 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/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/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/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,
|
|
@@ -277,33 +274,25 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
277
274
|
// so only a single scene should be rendered,
|
|
278
275
|
// instead of dangerous nulls or duplicates.
|
|
279
276
|
renderSingleScene({ scenes, to }) {
|
|
280
|
-
const { contentStyle
|
|
281
|
-
const screenData =
|
|
282
|
-
|
|
283
|
-
const orientation = getScreenOrientation({
|
|
284
|
-
screenData,
|
|
285
|
-
layoutData,
|
|
286
|
-
});
|
|
277
|
+
const { contentStyle } = this.props;
|
|
278
|
+
const screenData = this.props.children.props.screenData;
|
|
279
|
+
const pathname = scenes[to.index].key;
|
|
287
280
|
|
|
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
281
|
return (
|
|
291
282
|
<View style={styles.container}>
|
|
292
|
-
{scenes[to.index] &&
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
</Scene>
|
|
306
|
-
)}
|
|
283
|
+
{scenes[to.index] && (
|
|
284
|
+
<Scene
|
|
285
|
+
{...{ style: to.style }}
|
|
286
|
+
pathname={pathname}
|
|
287
|
+
isActive={pathname === this.props.navigator.currentRoute}
|
|
288
|
+
contentStyle={contentStyle}
|
|
289
|
+
key={scenes[to.index].key}
|
|
290
|
+
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
291
|
+
screenData={screenData}
|
|
292
|
+
>
|
|
293
|
+
{scenes[to.index].children}
|
|
294
|
+
</Scene>
|
|
295
|
+
)}
|
|
307
296
|
</View>
|
|
308
297
|
);
|
|
309
298
|
}
|
|
@@ -319,12 +308,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
319
308
|
<Scene
|
|
320
309
|
key={scenes[from.index].key}
|
|
321
310
|
pathname={scenes[from.index].key}
|
|
311
|
+
isActive={scenes[from.index].key === this.props.navigator.currentRoute}
|
|
322
312
|
style={from.style}
|
|
323
313
|
pointerEvents="none"
|
|
324
314
|
overlayStyle={from.overlayStyle}
|
|
325
315
|
animating={this.state.animating}
|
|
326
316
|
contentStyle={contentStyle}
|
|
327
317
|
screenUniqueId={scenes[from.index].screenUniqueId}
|
|
318
|
+
screenData={scenes[from.index].children.props.screenData}
|
|
328
319
|
>
|
|
329
320
|
{scenes[from.index].children}
|
|
330
321
|
</Scene>
|
|
@@ -333,12 +324,14 @@ export class TransitionerComponent extends React.PureComponent<Props, State> {
|
|
|
333
324
|
const toScene = scenes[to.index] && (
|
|
334
325
|
<Scene
|
|
335
326
|
pathname={scenes[to.index].key}
|
|
327
|
+
isActive={scenes[to.index].key === this.props.navigator.currentRoute}
|
|
336
328
|
key={scenes[to.index].key}
|
|
337
329
|
style={to.style}
|
|
338
330
|
overlayStyle={to.overlayStyle}
|
|
339
331
|
animating={this.state.animating}
|
|
340
332
|
contentStyle={contentStyle}
|
|
341
333
|
screenUniqueId={scenes[to.index].screenUniqueId}
|
|
334
|
+
screenData={this.props.children.props.screenData}
|
|
342
335
|
>
|
|
343
336
|
{scenes[to.index].children}
|
|
344
337
|
</Scene>
|
|
@@ -21,7 +21,9 @@ exports[`<Scene /> renders correctly 1`] = `
|
|
|
21
21
|
]
|
|
22
22
|
}
|
|
23
23
|
>
|
|
24
|
-
<ContextProvider
|
|
24
|
+
<ContextProvider>
|
|
25
|
+
<ContextProvider />
|
|
26
|
+
</ContextProvider>
|
|
25
27
|
</ForwardRef(AnimatedComponentWrapper)>
|
|
26
28
|
`;
|
|
27
29
|
|
|
@@ -43,7 +45,9 @@ exports[`<Scene /> renders the overlay while animating 1`] = `
|
|
|
43
45
|
]
|
|
44
46
|
}
|
|
45
47
|
>
|
|
46
|
-
<ContextProvider
|
|
48
|
+
<ContextProvider>
|
|
49
|
+
<ContextProvider />
|
|
50
|
+
</ContextProvider>
|
|
47
51
|
<ForwardRef(AnimatedComponentWrapper)
|
|
48
52
|
style={
|
|
49
53
|
Object {
|
|
@@ -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,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
|
});
|