@applicaster/zapp-react-native-ui-components 15.0.0-rc.14 → 15.0.0-rc.140
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/AnimatedInOut/index.tsx +69 -26
- package/Components/BaseFocusable/index.ios.ts +12 -2
- package/Components/Cell/Cell.tsx +14 -3
- package/Components/Cell/CellWithFocusable.tsx +9 -0
- package/Components/Cell/FocusableWrapper.tsx +3 -0
- package/Components/Cell/TvOSCellComponent.tsx +25 -6
- package/Components/Focusable/Focusable.tsx +4 -2
- package/Components/Focusable/FocusableTvOS.tsx +18 -1
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
- package/Components/FocusableGroup/FocusableTvOS.tsx +32 -1
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
- package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +22 -6
- package/Components/HandlePlayable/HandlePlayable.tsx +33 -94
- package/Components/HandlePlayable/const.ts +3 -0
- package/Components/HandlePlayable/utils.ts +105 -0
- package/Components/HookRenderer/HookRenderer.tsx +40 -10
- package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
- package/Components/Layout/TV/LayoutBackground.tsx +5 -2
- package/Components/Layout/TV/NavBarContainer.tsx +1 -10
- package/Components/Layout/TV/ScreenContainer.tsx +2 -6
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/index.tsx +3 -4
- package/Components/Layout/TV/index.web.tsx +3 -4
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
- package/Components/MasterCell/DefaultComponents/Button.tsx +0 -15
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
- package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +43 -22
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +261 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
- package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +10 -14
- package/Components/MasterCell/DefaultComponents/index.ts +2 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +42 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +127 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ButtonContainerView.ts +23 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +32 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +195 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +140 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +222 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +104 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +73 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +86 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +35 -48
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +39 -144
- package/Components/MasterCell/elementMapper.tsx +1 -0
- package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
- package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
- package/Components/MasterCell/index.tsx +2 -0
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
- package/Components/MasterCell/utils/index.ts +61 -31
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
- package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
- package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
- package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
- package/Components/PlayerContainer/PlayerContainer.tsx +43 -64
- package/Components/PlayerImageBackground/index.tsx +3 -22
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +18 -16
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +19 -82
- package/Components/River/River.tsx +9 -82
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/TV/River.tsx +31 -14
- package/Components/River/TV/index.tsx +8 -4
- package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
- package/Components/River/TV/utils/index.ts +4 -0
- package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/River/__tests__/componentsMap.test.js +38 -0
- package/Components/River/hooks/__tests__/usePullToRefresh.test.ts +132 -0
- package/Components/River/hooks/index.ts +1 -0
- package/Components/River/hooks/usePullToRefresh.ts +51 -0
- package/Components/Screen/TV/index.web.tsx +4 -2
- package/Components/Screen/__tests__/Screen.test.tsx +66 -42
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
- package/Components/Screen/hooks.ts +75 -6
- package/Components/Screen/index.tsx +9 -4
- package/Components/Screen/navigationHandler.ts +49 -24
- package/Components/Screen/orientationHandler.ts +10 -13
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
- package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
- package/Components/ScreenFeedLoader/index.ts +1 -0
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
- package/Components/ScreenResolver/hooks/index.ts +3 -0
- package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
- package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
- package/Components/ScreenResolver/index.tsx +15 -111
- package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
- package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
- package/Components/ScreenResolver/utils/index.ts +1 -0
- package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
- package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
- package/Components/ScreenResolverFeedProvider/index.ts +1 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +44 -26
- package/Components/Tabs/TV/Tabs.tsx +20 -3
- package/Components/Tabs/TabContent.tsx +7 -4
- package/Components/TopCutoffOverlay/hooks/__tests__/useMarginTop.test.ts +130 -0
- package/Components/TopCutoffOverlay/hooks/index.ts +1 -0
- package/Components/TopCutoffOverlay/hooks/useMarginTop.ts +59 -0
- package/Components/TopCutoffOverlay/index.tsx +55 -0
- package/Components/Transitioner/Scene.tsx +10 -3
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoLive/LiveImageManager.ts +199 -54
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
- package/Components/VideoModal/ModalAnimation/index.ts +2 -13
- package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
- package/Components/VideoModal/PlayerWrapper.tsx +14 -88
- package/Components/VideoModal/VideoModal.tsx +1 -5
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
- package/Components/VideoModal/hooks/useModalSize.ts +10 -5
- package/Components/VideoModal/playerWrapperStyle.ts +70 -0
- package/Components/VideoModal/playerWrapperUtils.ts +91 -0
- package/Components/VideoModal/utils.ts +19 -9
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
- package/Components/Viewport/ViewportAware/index.tsx +16 -7
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
- package/Components/index.js +1 -1
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +71 -19
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappHookModalContext/index.tsx +37 -61
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Contexts/index.ts +0 -2
- package/Decorators/Analytics/index.tsx +6 -5
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +1 -0
- package/Decorators/ConfigurationWrapper/const.ts +1 -0
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
- package/Helpers/DataSourceHelper/index.ts +19 -0
- package/events/index.ts +3 -0
- package/events/scrollEndReached.ts +15 -0
- package/index.d.ts +7 -0
- package/package.json +6 -5
- package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
- package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/River/TV/withTVEventHandler.tsx +0 -27
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
- package/Helpers/DataSourceHelper/index.js +0 -19
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -4,9 +4,14 @@ import {
|
|
|
4
4
|
playerManager,
|
|
5
5
|
} from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
6
6
|
import { setUserCellPlayerMutedPreference } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/userCellPlayerMutedPreference";
|
|
7
|
+
import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
8
|
+
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
|
|
7
9
|
import { loggerLiveImageManager } from "./loggerHelper";
|
|
8
10
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
9
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
executePreloadHooks,
|
|
13
|
+
PreloadHookConfig,
|
|
14
|
+
} from "../MasterCell/DefaultComponents/LiveImage/executePreloadHooks";
|
|
10
15
|
|
|
11
16
|
const TIMEOUT_FOR_DELAY_CHECK_PLAYER_POSITION = 500; // ms
|
|
12
17
|
|
|
@@ -40,13 +45,21 @@ type Position = {
|
|
|
40
45
|
right: number;
|
|
41
46
|
};
|
|
42
47
|
|
|
48
|
+
type PlayerFactoryConfig = {
|
|
49
|
+
player: any; // React ref for native view
|
|
50
|
+
playerId: string;
|
|
51
|
+
muted: boolean;
|
|
52
|
+
playerPluginId: string;
|
|
53
|
+
screenConfig: Record<string, any>;
|
|
54
|
+
entry: ZappEntry; // original entry, used as fallback if no hooks
|
|
55
|
+
};
|
|
56
|
+
|
|
43
57
|
type LiveImageProps = {
|
|
44
|
-
player: Player;
|
|
45
58
|
playerId: string;
|
|
46
59
|
setMode?: (type: LiveImageType) => void;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
preloadHooks?: PreloadHookConfig[];
|
|
61
|
+
factoryConfig: PlayerFactoryConfig;
|
|
62
|
+
tag: string;
|
|
50
63
|
};
|
|
51
64
|
|
|
52
65
|
// Disabled because we have only unmute button but no play/pause state anymore
|
|
@@ -85,7 +98,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
85
98
|
|
|
86
99
|
public register = (item: LiveImage): (() => void) => {
|
|
87
100
|
this.items.push(item);
|
|
88
|
-
log_debug(`register: live image ${
|
|
101
|
+
log_debug(`register: live image ${item.playerId} - ${item.tag}`);
|
|
89
102
|
|
|
90
103
|
// TV only Start playing video once registered
|
|
91
104
|
if (isTV()) {
|
|
@@ -96,15 +109,13 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
96
109
|
};
|
|
97
110
|
|
|
98
111
|
public unregister = (item: LiveImage) => {
|
|
99
|
-
log_debug(`unregister: live-image ${
|
|
112
|
+
log_debug(`unregister: live-image ${item.playerId} - ${item.tag}`);
|
|
100
113
|
|
|
101
114
|
if (this.currentlyPlaying === item) {
|
|
102
115
|
this.currentlyPlaying = null;
|
|
103
116
|
|
|
104
117
|
log_debug(
|
|
105
|
-
`unregister: currently playing live-image was destroyed, ${
|
|
106
|
-
item.player
|
|
107
|
-
)}`
|
|
118
|
+
`unregister: currently playing live-image was destroyed, ${item.playerId} - ${item.tag}`
|
|
108
119
|
);
|
|
109
120
|
|
|
110
121
|
// TODO: Maybe start another one
|
|
@@ -118,7 +129,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
118
129
|
item,
|
|
119
130
|
playerId: this.currentlyPlaying?.playerId,
|
|
120
131
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
121
|
-
entry: item.getPlayer()
|
|
132
|
+
entry: item.getPlayer()?.getEntry(),
|
|
122
133
|
},
|
|
123
134
|
});
|
|
124
135
|
};
|
|
@@ -130,9 +141,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
130
141
|
|
|
131
142
|
public onViewportEnter = (item: LiveImage) => {
|
|
132
143
|
log_debug(
|
|
133
|
-
`onViewportEnter: live-image ${playerInfo(
|
|
134
|
-
item.player
|
|
135
|
-
)}, primary ${playerInfo(this.primaryPlayer)}`
|
|
144
|
+
`onViewportEnter: live-image ${item.playerId} - ${item.tag}, primary ${playerInfo(this.primaryPlayer)} - position:${item.positionToString()}`
|
|
136
145
|
);
|
|
137
146
|
|
|
138
147
|
if (!isTV()) {
|
|
@@ -154,9 +163,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
154
163
|
|
|
155
164
|
public onViewportLeave = (item: LiveImage) => {
|
|
156
165
|
log_debug(
|
|
157
|
-
`onViewportLeave: live-image playerId
|
|
158
|
-
item.player
|
|
159
|
-
)}, primary ${playerInfo(this.primaryPlayer)}`
|
|
166
|
+
`onViewportLeave: live-image ${item.playerId} - ${item.tag}, primary ${playerInfo(this.primaryPlayer)} - position:${item.positionToString()}`
|
|
160
167
|
);
|
|
161
168
|
|
|
162
169
|
this.pauseItem(item);
|
|
@@ -190,20 +197,29 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
190
197
|
this.items.find((i) => i.playerId === playerId) || null;
|
|
191
198
|
|
|
192
199
|
private pauseItem = (item: LiveImage) => {
|
|
193
|
-
log_debug(`pauseItem: live-image ${
|
|
200
|
+
log_debug(`pauseItem: live-image ${item.playerId} - ${item.tag}`);
|
|
201
|
+
|
|
202
|
+
if (!item.player) {
|
|
203
|
+
// Player not yet created (e.g. hooks still running) — just reset mode
|
|
204
|
+
item.setMode?.(LiveImageType.Image);
|
|
205
|
+
|
|
206
|
+
if (item === this.currentlyPlaying) {
|
|
207
|
+
this.currentlyPlaying = null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
194
212
|
|
|
195
213
|
if (!item.player.playerState.isReadyToPlay) {
|
|
196
214
|
log_debug(
|
|
197
|
-
`
|
|
198
|
-
item.player
|
|
199
|
-
)}`
|
|
215
|
+
`pauseItem: live-image not ready, ${item.playerId} - ${item.tag}`
|
|
200
216
|
);
|
|
201
217
|
} else {
|
|
202
|
-
item.player
|
|
218
|
+
item.player.pause();
|
|
203
219
|
}
|
|
204
220
|
|
|
205
221
|
// Fake close event, because we unmount native view
|
|
206
|
-
item.player
|
|
222
|
+
item.player.onPlayerClose();
|
|
207
223
|
item.setMode?.(LiveImageType.Image);
|
|
208
224
|
|
|
209
225
|
if (item === this.currentlyPlaying) {
|
|
@@ -213,9 +229,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
213
229
|
|
|
214
230
|
public playLiveImage = (item: LiveImage) => {
|
|
215
231
|
log_debug(
|
|
216
|
-
`playLiveImage: live-image ${playerInfo(
|
|
217
|
-
item.player
|
|
218
|
-
)}, primary ${playerInfo(this.primaryPlayer)}`
|
|
232
|
+
`playLiveImage: live-image ${item.playerId} - ${item.tag}, primary ${playerInfo(this.primaryPlayer)}`
|
|
219
233
|
);
|
|
220
234
|
|
|
221
235
|
if (this.primaryPlayer) {
|
|
@@ -223,7 +237,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
223
237
|
}
|
|
224
238
|
|
|
225
239
|
if (this.currentlyPlaying) {
|
|
226
|
-
if (this.currentlyPlaying
|
|
240
|
+
if (this.currentlyPlaying.playerId === item.playerId) {
|
|
227
241
|
return;
|
|
228
242
|
} else {
|
|
229
243
|
this.pauseItem(this.currentlyPlaying);
|
|
@@ -231,18 +245,42 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
231
245
|
}
|
|
232
246
|
|
|
233
247
|
this.currentlyPlaying = item;
|
|
234
|
-
item.setMode?.(LiveImageType.Video);
|
|
235
248
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
249
|
+
item
|
|
250
|
+
.prepareForPlayback()
|
|
251
|
+
.then((result) => {
|
|
252
|
+
if (!result) {
|
|
253
|
+
log_error(
|
|
254
|
+
`Failed to prepare live image ${item.playerId} - ${item.tag} for playback: prepareForPlayback returned false`
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
this.currentlyPlaying = null;
|
|
258
|
+
item.setMode?.(LiveImageType.Image);
|
|
259
|
+
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Guard: item might have been replaced while hooks were running
|
|
264
|
+
if (this.currentlyPlaying !== item) return;
|
|
265
|
+
|
|
266
|
+
item.setMode?.(LiveImageType.Video);
|
|
267
|
+
|
|
268
|
+
if (item.player?.playerState.isReadyToPlay) {
|
|
269
|
+
item.player.play();
|
|
270
|
+
}
|
|
271
|
+
})
|
|
272
|
+
.catch((error) => {
|
|
273
|
+
log_error(
|
|
274
|
+
`Failed to prepare live image ${item.playerId} - ${item.tag} for playback: ${error?.message}`
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
this.onLiveImageError(item, error);
|
|
278
|
+
});
|
|
239
279
|
};
|
|
240
280
|
|
|
241
281
|
public pauseLiveImage = (item: LiveImage) => {
|
|
242
282
|
log_debug(
|
|
243
|
-
`pauseLiveImage: live-image playerId
|
|
244
|
-
item.player
|
|
245
|
-
)}, primary ${playerInfo(this.primaryPlayer)}`
|
|
283
|
+
`pauseLiveImage: live-image ${item.playerId} - ${item.tag}, primary ${playerInfo(this.primaryPlayer)}`
|
|
246
284
|
);
|
|
247
285
|
|
|
248
286
|
this.pauseItem(item);
|
|
@@ -258,7 +296,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
258
296
|
|
|
259
297
|
setUserCellPlayerMutedPreference(true);
|
|
260
298
|
|
|
261
|
-
this.items.forEach((liveImage) => liveImage.player
|
|
299
|
+
this.items.forEach((liveImage) => liveImage.player?.mute());
|
|
262
300
|
};
|
|
263
301
|
|
|
264
302
|
public unmuteAll = () => {
|
|
@@ -266,16 +304,36 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
266
304
|
|
|
267
305
|
setUserCellPlayerMutedPreference(false);
|
|
268
306
|
|
|
269
|
-
this.items.forEach((liveImage) => liveImage.player
|
|
307
|
+
this.items.forEach((liveImage) => liveImage.player?.unmute());
|
|
270
308
|
};
|
|
271
309
|
|
|
272
|
-
public
|
|
310
|
+
public onViewPositionChanged = (item: LiveImage) => {
|
|
311
|
+
log_debug(
|
|
312
|
+
`onViewPositionChanged: live-image ${item.playerId} - ${item.tag}, primary ${playerInfo(this.primaryPlayer)} - position:${item.positionToString()}`
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
if (!isTV()) {
|
|
316
|
+
// mobile only
|
|
317
|
+
// we have to delay running checkPlayerPosition, because sometimes on fast scrolling we get wrong order onEnter, then onLeave.
|
|
318
|
+
// which could cause select wrong item to play
|
|
319
|
+
|
|
320
|
+
this.cancelCheckPlayerPositionTimeout();
|
|
321
|
+
|
|
322
|
+
this.checkPlayerPositionTimeout = setTimeout(() => {
|
|
323
|
+
this.cancelCheckPlayerPositionTimeout();
|
|
324
|
+
|
|
325
|
+
this.checkPlayerPosition(item);
|
|
326
|
+
}, TIMEOUT_FOR_DELAY_CHECK_PLAYER_POSITION);
|
|
327
|
+
} else {
|
|
328
|
+
this.checkPlayerPosition(item);
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
private checkPlayerPosition = (item: LiveImage) => {
|
|
273
333
|
this.cancelCheckPlayerPositionTimeout();
|
|
274
334
|
|
|
275
335
|
log_debug(
|
|
276
|
-
`checkPlayerPosition: live-image playerId
|
|
277
|
-
item.player
|
|
278
|
-
)}, primary ${playerInfo(this.primaryPlayer)}`
|
|
336
|
+
`checkPlayerPosition: live-image ${item.playerId} - ${item.tag}, primary ${playerInfo(this.primaryPlayer)}`
|
|
279
337
|
);
|
|
280
338
|
|
|
281
339
|
const playerItem = this.findNextPlayableItem();
|
|
@@ -391,7 +449,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
391
449
|
item,
|
|
392
450
|
playerId: this.currentlyPlaying?.playerId,
|
|
393
451
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
394
|
-
entry: item.getPlayer()
|
|
452
|
+
entry: item.getPlayer()?.getEntry(),
|
|
395
453
|
},
|
|
396
454
|
});
|
|
397
455
|
};
|
|
@@ -426,7 +484,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
426
484
|
item,
|
|
427
485
|
playerId: this.currentlyPlaying?.playerId,
|
|
428
486
|
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
429
|
-
entry: item.getPlayer()
|
|
487
|
+
entry: item.getPlayer()?.getEntry(),
|
|
430
488
|
},
|
|
431
489
|
});
|
|
432
490
|
};
|
|
@@ -448,7 +506,7 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
448
506
|
this.currentlyPlaying = null;
|
|
449
507
|
|
|
450
508
|
log_debug(
|
|
451
|
-
`onLiveImageError:
|
|
509
|
+
`onLiveImageError: currentItem: ${currentItem.playerId} - ${currentItem.tag} was removed`
|
|
452
510
|
);
|
|
453
511
|
|
|
454
512
|
// TODO: ...Maybe player some other item
|
|
@@ -460,8 +518,8 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
460
518
|
item,
|
|
461
519
|
error,
|
|
462
520
|
playerId: currentItem?.playerId,
|
|
463
|
-
primaryPlayerId:
|
|
464
|
-
entry: item.getPlayer()
|
|
521
|
+
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
522
|
+
entry: item.getPlayer()?.getEntry(),
|
|
465
523
|
},
|
|
466
524
|
});
|
|
467
525
|
};
|
|
@@ -503,10 +561,10 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
503
561
|
LiveImageManager.instance;
|
|
504
562
|
|
|
505
563
|
export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
|
|
506
|
-
public player: Player;
|
|
507
|
-
public setMode
|
|
508
|
-
// Will be replaced with rects
|
|
564
|
+
public player: Player | null = null;
|
|
565
|
+
public setMode?: (type: LiveImageType) => void;
|
|
509
566
|
public isFullyVisible: boolean = false;
|
|
567
|
+
public tag: string;
|
|
510
568
|
public position: Position = {
|
|
511
569
|
centerX: 0,
|
|
512
570
|
centerY: 0,
|
|
@@ -516,18 +574,105 @@ export class LiveImage implements QuickBrickPlayer.SharedPlayerCallBacks {
|
|
|
516
574
|
left: 0,
|
|
517
575
|
};
|
|
518
576
|
|
|
577
|
+
positionToString() {
|
|
578
|
+
if (!this.position) {
|
|
579
|
+
return "position not set";
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const { centerX, centerY, top, bottom, left, right } = this.position;
|
|
583
|
+
|
|
584
|
+
return `centerX: ${centerX.toFixed(2)}, centerY: ${centerY.toFixed(2)}, top: ${top.toFixed(2)}, bottom: ${bottom.toFixed(2)}, left: ${left.toFixed(2)}, right: ${right.toFixed(2)}`;
|
|
585
|
+
}
|
|
586
|
+
|
|
519
587
|
readonly playerId: string;
|
|
520
|
-
|
|
588
|
+
public component: any = null;
|
|
589
|
+
|
|
590
|
+
private factoryConfig: PlayerFactoryConfig;
|
|
591
|
+
public preloadHooks?: PreloadHookConfig[];
|
|
592
|
+
public processedEntry: ZappEntry | null = null;
|
|
593
|
+
private _preparePromise: Promise<boolean> | null = null;
|
|
521
594
|
|
|
522
595
|
constructor(props: LiveImageProps) {
|
|
523
|
-
this.player = props.player;
|
|
524
596
|
this.setMode = props.setMode;
|
|
525
|
-
this.playerId =
|
|
526
|
-
this.
|
|
527
|
-
this.
|
|
597
|
+
this.playerId = props.playerId;
|
|
598
|
+
this.preloadHooks = props.preloadHooks;
|
|
599
|
+
this.factoryConfig = props.factoryConfig;
|
|
600
|
+
this.tag = props.tag || "untagged";
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
async prepareForPlayback(): Promise<boolean> {
|
|
604
|
+
// Already prepared — player exists
|
|
605
|
+
if (this.player) {
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Deduplicate: if preparation is already in flight, await the same promise
|
|
610
|
+
if (this._preparePromise) {
|
|
611
|
+
return this._preparePromise;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
this._preparePromise = (async (): Promise<boolean> => {
|
|
615
|
+
// 1. Run hooks if configured
|
|
616
|
+
let entry = this.factoryConfig.entry;
|
|
617
|
+
|
|
618
|
+
if (this.preloadHooks?.length) {
|
|
619
|
+
const result = await executePreloadHooks({
|
|
620
|
+
preloadHooks: this.preloadHooks,
|
|
621
|
+
entry,
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
if (result) {
|
|
625
|
+
this.processedEntry = result;
|
|
626
|
+
entry = result;
|
|
627
|
+
} else {
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// 2. Create the player with the correct entry
|
|
633
|
+
const factoryItem = playerFactory({
|
|
634
|
+
player: this.factoryConfig.player,
|
|
635
|
+
playerId: this.factoryConfig.playerId,
|
|
636
|
+
autoplay: false,
|
|
637
|
+
entry,
|
|
638
|
+
muted: this.factoryConfig.muted,
|
|
639
|
+
playerPluginId: this.factoryConfig.playerPluginId,
|
|
640
|
+
screenConfig: this.factoryConfig.screenConfig,
|
|
641
|
+
playerRole: PlayerRole.Cell,
|
|
642
|
+
});
|
|
643
|
+
|
|
644
|
+
if (!factoryItem) {
|
|
645
|
+
throw new Error("Player factory returned null");
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
this.player = factoryItem.controller;
|
|
649
|
+
this.component = factoryItem.Component;
|
|
650
|
+
|
|
651
|
+
// 3. Register callbacks — player now exists
|
|
652
|
+
this.player.addListener({ id: "live-image", listener: this });
|
|
653
|
+
|
|
654
|
+
return true;
|
|
655
|
+
})()
|
|
656
|
+
.then((result) => {
|
|
657
|
+
this._preparePromise = null;
|
|
658
|
+
|
|
659
|
+
return result;
|
|
660
|
+
})
|
|
661
|
+
.catch((error) => {
|
|
662
|
+
this._preparePromise = null;
|
|
663
|
+
|
|
664
|
+
log_error(
|
|
665
|
+
`prepareForPlayback: live-image ${this.playerId}, error preparing for playback: ${error?.message}`,
|
|
666
|
+
{ error }
|
|
667
|
+
);
|
|
668
|
+
|
|
669
|
+
throw error;
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
return this._preparePromise;
|
|
528
673
|
}
|
|
529
674
|
|
|
530
|
-
public getPlayer = (): Player => {
|
|
675
|
+
public getPlayer = (): Player | null => {
|
|
531
676
|
return this.player;
|
|
532
677
|
};
|
|
533
678
|
|
|
@@ -7,8 +7,6 @@ import { AppState, AppStateStatus, View } from "react-native";
|
|
|
7
7
|
import { TrackedView } from "../TrackedView";
|
|
8
8
|
import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks/layout";
|
|
9
9
|
|
|
10
|
-
import { playerFactory } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
|
|
11
|
-
|
|
12
10
|
import {
|
|
13
11
|
isApplePlatform,
|
|
14
12
|
isTV,
|
|
@@ -22,15 +20,15 @@ import { AnimatedInOut } from "@applicaster/zapp-react-native-ui-components/Comp
|
|
|
22
20
|
import { overlayFadeIn } from "./animationUtils";
|
|
23
21
|
import { loggerLiveImageComponent } from "./loggerHelper";
|
|
24
22
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
25
|
-
import { PlayerRole } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/conts";
|
|
26
23
|
import { getAutoplaySettings } from "./utils";
|
|
27
24
|
import { isString } from "@applicaster/zapp-react-native-utils/stringUtils";
|
|
28
25
|
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
26
|
+
import { PreloadHookConfig } from "../MasterCell/DefaultComponents/LiveImage/executePreloadHooks";
|
|
29
27
|
|
|
30
28
|
const { log_error, log_debug } = loggerLiveImageComponent;
|
|
31
29
|
|
|
32
|
-
const isMeasurement = (
|
|
33
|
-
isString(
|
|
30
|
+
const isMeasurement = (itemId: string | number | null): boolean =>
|
|
31
|
+
isString(itemId) && itemId.startsWith("pre-measurement-");
|
|
34
32
|
|
|
35
33
|
// Pixels by which the view can slightly extend outside the viewport and still be considered fully visible.
|
|
36
34
|
const CLIP_THRESHOLD = 10;
|
|
@@ -44,6 +42,7 @@ type Props = {
|
|
|
44
42
|
screenConfig: Record<string, any>;
|
|
45
43
|
audioMutedByDefault?: boolean;
|
|
46
44
|
uri: string; // cover image url
|
|
45
|
+
preloadHooks?: PreloadHookConfig[];
|
|
47
46
|
};
|
|
48
47
|
|
|
49
48
|
const PlayerLiveImageComponent = (props: Props) => {
|
|
@@ -116,43 +115,36 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
entryToViewIdMapping.current[nativeTag] = { itemId: item.id };
|
|
119
|
-
}, [
|
|
118
|
+
}, [item.id, mode]);
|
|
120
119
|
|
|
121
|
-
const { screenConfig, playerPluginId } = props;
|
|
120
|
+
const { screenConfig, playerPluginId, preloadHooks } = props;
|
|
122
121
|
|
|
123
122
|
const liveImageItem: LiveImage = React.useMemo(() => {
|
|
124
|
-
|
|
125
|
-
player: ref,
|
|
123
|
+
return new LiveImage({
|
|
126
124
|
playerId,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
playerPluginId: playerPluginId,
|
|
131
|
-
screenConfig: screenConfig,
|
|
132
|
-
playerRole: PlayerRole.Cell,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
if (playerFactoryItem) {
|
|
136
|
-
return new LiveImage({
|
|
125
|
+
preloadHooks,
|
|
126
|
+
factoryConfig: {
|
|
127
|
+
player: ref,
|
|
137
128
|
playerId,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
129
|
+
muted,
|
|
130
|
+
playerPluginId: playerPluginId,
|
|
131
|
+
screenConfig: screenConfig,
|
|
132
|
+
entry: item,
|
|
133
|
+
},
|
|
134
|
+
tag: item.title?.toString(),
|
|
135
|
+
});
|
|
136
|
+
}, [playerId, preloadHooks, muted, playerPluginId, screenConfig, item]);
|
|
145
137
|
|
|
146
138
|
React.useEffect(() => {
|
|
147
139
|
liveImageItem.setMode = setModeDebounced;
|
|
148
140
|
}, [setModeDebounced, liveImageItem]);
|
|
149
141
|
|
|
142
|
+
// todo: no need for it to be react, can be moved into `player.addListener`
|
|
150
143
|
const { start, end } = React.useMemo(
|
|
151
144
|
() => getAutoplaySettings(item),
|
|
152
145
|
[item.id]
|
|
153
146
|
);
|
|
154
147
|
|
|
155
|
-
const controller = liveImageItem.getPlayer();
|
|
156
148
|
const player = usePlayer(playerId);
|
|
157
149
|
|
|
158
150
|
const _assignRoot = (component) => {
|
|
@@ -169,7 +161,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
169
161
|
|
|
170
162
|
React.useEffect(() => {
|
|
171
163
|
// FIXME - find a more elegant way to disable live-image on cell for measurement
|
|
172
|
-
if (isMeasurement(item)) {
|
|
164
|
+
if (isMeasurement(item.id)) {
|
|
173
165
|
return;
|
|
174
166
|
}
|
|
175
167
|
|
|
@@ -253,7 +245,13 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
253
245
|
}, [item.id]);
|
|
254
246
|
|
|
255
247
|
React.useEffect(() => {
|
|
256
|
-
if (isMeasurement(item) || !playerManager) {
|
|
248
|
+
if (isMeasurement(item.id) || !playerManager) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const controller = liveImageItem.getPlayer();
|
|
253
|
+
|
|
254
|
+
if (!controller) {
|
|
257
255
|
return;
|
|
258
256
|
}
|
|
259
257
|
|
|
@@ -273,7 +271,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
273
271
|
playerManager.unregisterPlayer(playerId);
|
|
274
272
|
};
|
|
275
273
|
}
|
|
276
|
-
}, [liveImageItem, playerId,
|
|
274
|
+
}, [liveImageItem, playerId, mode, item.id]);
|
|
277
275
|
|
|
278
276
|
const onPositionUpdated = React.useCallback(
|
|
279
277
|
(data) => {
|
|
@@ -310,7 +308,7 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
310
308
|
? LiveImageManager.instance.onViewportEnter(liveImageItem)
|
|
311
309
|
: LiveImageManager.instance.onViewportLeave(liveImageItem);
|
|
312
310
|
} else {
|
|
313
|
-
LiveImageManager.instance.
|
|
311
|
+
LiveImageManager.instance.onViewPositionChanged(liveImageItem);
|
|
314
312
|
}
|
|
315
313
|
},
|
|
316
314
|
[liveImageItem, dimensions.height, dimensions.width]
|
|
@@ -338,11 +336,11 @@ const PlayerLiveImageComponent = (props: Props) => {
|
|
|
338
336
|
<Player
|
|
339
337
|
autoplay={false}
|
|
340
338
|
ref={_assignRoot}
|
|
341
|
-
entry={item} // Must be passed first in list
|
|
339
|
+
entry={liveImageItem.processedEntry || item} // Must be passed first in list
|
|
342
340
|
style={videoStyles}
|
|
343
341
|
playerId={playerId}
|
|
344
342
|
muted={muted}
|
|
345
|
-
listener={
|
|
343
|
+
listener={liveImageItem.getPlayer()?.getListener()}
|
|
346
344
|
resizeMode={"cover"}
|
|
347
345
|
{...platformSpecificProps}
|
|
348
346
|
/>
|
|
@@ -120,29 +120,14 @@ describe("PlayerLiveImageComponent", () => {
|
|
|
120
120
|
// TODO: implement this test
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
it("should register the player
|
|
123
|
+
it("should not register the player at mount (lazy creation)", () => {
|
|
124
124
|
render(
|
|
125
125
|
<Wrapper>
|
|
126
126
|
<PlayerLiveImage {...defaultProps} />
|
|
127
127
|
</Wrapper>
|
|
128
128
|
);
|
|
129
129
|
|
|
130
|
-
|
|
131
|
-
defaultProps.playerId
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
expect(isPlayerRegistered).toBe(true);
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
it("should unregister the player for normal item", () => {
|
|
138
|
-
const component = render(
|
|
139
|
-
<Wrapper>
|
|
140
|
-
<PlayerLiveImage {...defaultProps} />
|
|
141
|
-
</Wrapper>
|
|
142
|
-
);
|
|
143
|
-
|
|
144
|
-
component.unmount();
|
|
145
|
-
|
|
130
|
+
// Player is not registered until playback starts (lazy creation)
|
|
146
131
|
const isPlayerRegistered = playerManager.isPlayerRegistered(
|
|
147
132
|
defaultProps.playerId
|
|
148
133
|
);
|