@applicaster/zapp-react-native-ui-components 13.0.0-alpha.3013227535 → 13.0.0-alpha.3044917147
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/AppContainer/__tests__/AppContainer.test.js +4 -6
- package/Components/AudioPlayer/AudioPlayer.tsx +5 -9
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +8 -9
- package/Components/AudioPlayer/__tests__/Runtime.test.js +5 -8
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayer.test.js.snap +54 -111
- package/Components/AudioPlayer/__tests__/__snapshots__/audioPlayerLayout.test.js.snap +36 -20
- package/Components/AudioPlayer/__tests__/artWork.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayer.test.js +3 -5
- package/Components/AudioPlayer/__tests__/audioPlayerLayout.test.js +7 -8
- package/Components/AudioPlayer/__tests__/channel.test.js +3 -5
- package/Components/AudioPlayer/__tests__/summary.test.js +3 -5
- package/Components/AudioPlayer/__tests__/title.test.js +3 -5
- package/Components/AudioPlayer/helpers.tsx +1 -2
- package/Components/BaseFocusable/index.tsx +1 -2
- package/Components/Cell/Cell.tsx +4 -13
- package/Components/Cell/CellWithFocusable.tsx +50 -59
- package/Components/Cell/CellWrapper.tsx +18 -0
- package/Components/Cell/TvOSCellComponent.tsx +20 -22
- package/Components/Cell/__tests__/CellWIthFocusable.test.js +13 -6
- package/Components/Cell/index.js +3 -1
- package/Components/Cell/styles.ts +17 -0
- package/Components/CellRendererResolver/__tests__/cellRendererResolver.test.js +46 -48
- package/Components/CellRendererResolver/index.ts +2 -1
- package/Components/ComponentResolver/__tests__/__snapshots__/componentResolver.test.js.snap +1 -42
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +16 -22
- package/Components/ContentScreen/__tests__/contentScreen.test.js +3 -3
- package/Components/ErrorScreen/index.tsx +14 -6
- package/Components/Focusable/Focusable.tsx +1 -0
- package/Components/Focusable/FocusableTvOS.tsx +5 -1
- package/Components/Focusable/index.android.tsx +10 -3
- package/Components/FocusableCell/index.tsx +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
- package/Components/FocusableGroup/index.tsx +0 -3
- package/Components/FocusableList/index.tsx +26 -9
- package/Components/FocusableScrollView/index.tsx +43 -13
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +3 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +4 -2
- package/Components/GeneralContentScreen/utils/useEventAlerts.ts +30 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +21 -27
- package/Components/Layout/TV/LayoutBackground.tsx +28 -0
- package/Components/Layout/TV/NavBarContainer.tsx +19 -23
- package/Components/Layout/TV/ScreenContainer.tsx +8 -2
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +5 -0
- package/Components/Layout/TV/__tests__/ScreenContainer.test.tsx +2 -1
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +3 -2
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +3 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +15 -10
- package/Components/Layout/TV/__tests__/index.test.tsx +8 -2
- package/Components/Layout/TV/index.tsx +6 -20
- package/Components/Layout/TV/index.web.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +4 -3
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +11 -7
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const.ts +3 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +6 -6
- package/Components/MasterCell/SharedUI/ProgressBar/hooks/useFillInPercent.ts +2 -8
- package/Components/MasterCell/__tests__/__snapshots__/elementMapper.test.js.snap +4 -12
- package/Components/MasterCell/__tests__/__snapshots__/masterCell.test.js.snap +0 -229
- package/Components/MasterCell/__tests__/elementMapper.test.js +18 -5
- package/Components/MasterCell/__tests__/masterCell.test.js +26 -26
- package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +2 -2
- package/Components/MasterCell/utils/behaviorProvider.ts +136 -0
- package/Components/MasterCell/utils/index.ts +8 -134
- package/Components/ModalComponent/BottomSheetModalContent.tsx +66 -54
- package/Components/ModalComponent/Button/Item.tsx +6 -5
- package/Components/ModalComponent/Button/assets.ts +1 -1
- package/Components/ModalComponent/Button/index.tsx +45 -62
- package/Components/ModalComponent/Header/index.tsx +12 -11
- package/Components/ModalComponent/utils.ts +55 -7
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +0 -5
- package/Components/OfflineHandler/utils/index.ts +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +63 -54
- package/Components/PlayerContainer/ProgramInfo/index.tsx +2 -2
- package/Components/PlayerImageBackground/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +53 -68
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +78 -51
- package/Components/River/RiverFooter.tsx +39 -9
- package/Components/River/RiverItem.tsx +43 -3
- package/Components/River/TV/index.tsx +6 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +107 -32
- package/Components/River/__tests__/__snapshots__/river.test.js.snap +20 -82
- package/Components/River/__tests__/componentsMap.test.js +3 -4
- package/Components/River/__tests__/river.test.js +75 -40
- package/Components/RouteManager/TestId.tsx +1 -5
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +10 -4
- package/Components/RouteManager/__tests__/routeManager.test.js +29 -14
- package/Components/RouteManager/__tests__/testId.test.js +4 -6
- package/Components/Screen/TV/__tests__/index.web.test.tsx +26 -0
- package/Components/Screen/TV/index.web.tsx +5 -6
- package/Components/Screen/__tests__/Screen.test.tsx +22 -14
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -2
- package/Components/Screen/hooks.ts +53 -0
- package/Components/Screen/index.tsx +16 -43
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +91 -70
- package/Components/Tabs/Tab.tsx +5 -3
- package/Components/TextInputTv/index.tsx +2 -1
- package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
- package/Components/TrackedView/index.tsx +1 -0
- package/Components/Transitioner/AnimationManager.js +15 -15
- package/Components/Transitioner/Scene.tsx +1 -1
- package/Components/Transitioner/Transitioner.tsx +3 -3
- package/Components/Transitioner/__tests__/Scene.test.js +25 -14
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +12 -68
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +2 -2
- package/Components/Transitioner/__tests__/transitioner.test.js +13 -4
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +7 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +1 -1
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +46 -30
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +3 -3
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +45 -21
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +13 -6
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +108 -0
- package/Components/VideoModal/ModalAnimation/const.ts +5 -0
- package/Components/VideoModal/ModalAnimation/index.ts +2 -0
- package/Components/VideoModal/ModalAnimation/utils.ts +30 -0
- package/Components/VideoModal/PlayerDetails.tsx +18 -10
- package/Components/VideoModal/PlayerWrapper.tsx +37 -24
- package/Components/VideoModal/VideoModal.tsx +19 -4
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
- package/Components/VideoModal/utils.ts +3 -4
- package/Components/Viewport/ViewportAware/__tests__/__snapshots__/viewportAware.test.js.snap +24 -36
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -18
- package/Components/Viewport/__tests__/utils.test.js +5 -4
- package/Components/ZappUIComponent/Placeholder.tsx +3 -1
- package/Components/ZappUIComponent/__tests__/{ZappUIComponent.test.js → ZappUIComponent.test.tsx} +26 -10
- package/Components/ZappUIComponent/index.tsx +4 -17
- package/Components/default-cell-renderer/__tests__/defaultCellRenderer.test.tsx +20 -17
- package/Components/default-cell-renderer/viewTrees/tv/DefaultCell/__tests__/DefaultCell.test.tsx +15 -11
- package/Contexts/ComponentsMapOffsetContext/index.tsx +49 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +4 -10
- package/Contexts/HeaderOffsetContext/index.tsx +4 -6
- package/Contexts/ScreenContext/index.tsx +3 -10
- package/Contexts/ScreenLayoutContext/index.tsx +5 -3
- package/Decorators/Navigator/__tests__/navigator.test.js +16 -16
- package/Decorators/Navigator/index.tsx +1 -1
- package/Decorators/RiverResolver/__tests__/riverResolver.test.tsx +18 -24
- package/Decorators/RiverResolver/index.tsx +6 -8
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +29 -22
- package/Decorators/ZappPipesDataConnector/index.tsx +4 -30
- package/package.json +7 -11
- package/tsconfig.json +2 -3
- package/.babelrc +0 -8
- package/Components/Cell/CellStyles/FallbackCellStyle/index.js +0 -157
- package/Components/Cell/CellStyles/Hero/index.js +0 -111
- package/Components/Cell/CellStyles/ScreenSelector/index.js +0 -68
- package/Components/Cell/CellStyles/cellStylesResolver.ts +0 -19
- package/Components/Cell/CellStyles/colors.js +0 -40
- package/Components/Cell/CellStyles/index.js +0 -15
- package/Components/CellRendererResolver/__tests__/__snapshots__/cellRendererResolver.test.js.snap +0 -53
- package/Components/RouteManager/__tests__/__snapshots__/testId.test.js.snap +0 -17
- package/Components/ScreenResolver/__tests__/__snapshots__/screenResolver.test.js.snap +0 -17
- package/Components/ZappUIComponent/__tests__/__snapshots__/ZappUIComponent.test.js.snap +0 -91
- package/Components/default-cell-renderer/__tests__/__snapshots__/defaultCellRenderer.test.tsx.snap +0 -338
- package/Decorators/Navigator/__tests__/__snapshots__/navigator.test.js.snap +0 -18
- package/Decorators/RiverResolver/__tests__/__snapshots__/riverResolver.test.tsx.snap +0 -28
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { useEffect, useReducer } from "react";
|
|
2
3
|
// @ts-ignore
|
|
3
|
-
import { View, ViewStyle
|
|
4
|
+
import { TVMenuControl, View, ViewStyle } from "react-native";
|
|
4
5
|
import * as R from "ramda";
|
|
5
6
|
import uuid from "uuid/v4";
|
|
6
7
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
7
8
|
import {
|
|
8
|
-
isApplePlatform,
|
|
9
|
-
platformSelect,
|
|
10
9
|
isTV,
|
|
10
|
+
platformSelect,
|
|
11
|
+
isAndroidTVPlatform,
|
|
12
|
+
isTvOSPlatform,
|
|
11
13
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
+
import {
|
|
15
|
+
isAudioItem,
|
|
16
|
+
isInlineTV as isInlineTVUtil,
|
|
17
|
+
} from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
12
18
|
|
|
13
19
|
import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
|
|
14
|
-
import { useEffect, useReducer } from "react";
|
|
15
20
|
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
16
21
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
17
22
|
import {
|
|
@@ -20,7 +25,7 @@ import {
|
|
|
20
25
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
21
26
|
|
|
22
27
|
import { PlayerStateContext } from "../../Contexts/PlayerStateContext";
|
|
23
|
-
|
|
28
|
+
|
|
24
29
|
import {
|
|
25
30
|
QUICK_BRICK_EVENTS,
|
|
26
31
|
QuickBrickEvent,
|
|
@@ -29,10 +34,10 @@ import {
|
|
|
29
34
|
import { ProgramInfo } from "./ProgramInfo";
|
|
30
35
|
import { AudioPlayer } from "../AudioPlayer";
|
|
31
36
|
import {
|
|
32
|
-
playerContainerLogger,
|
|
33
37
|
log_debug,
|
|
34
38
|
log_info,
|
|
35
39
|
log_warning,
|
|
40
|
+
playerContainerLogger,
|
|
36
41
|
} from "./logger";
|
|
37
42
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
38
43
|
import { useSetNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
@@ -53,8 +58,8 @@ import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtil
|
|
|
53
58
|
import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
|
|
54
59
|
|
|
55
60
|
import {
|
|
56
|
-
useModalAnimationContext,
|
|
57
61
|
PlayerAnimationStateEnum,
|
|
62
|
+
useModalAnimationContext,
|
|
58
63
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
59
64
|
|
|
60
65
|
type Props = {
|
|
@@ -93,6 +98,25 @@ export type PlayNextData = {
|
|
|
93
98
|
|
|
94
99
|
const focusableBottomContainerId = "player-container-bottom";
|
|
95
100
|
|
|
101
|
+
const isAndroidTV = isAndroidTVPlatform();
|
|
102
|
+
|
|
103
|
+
const isTvOS = isTvOSPlatform();
|
|
104
|
+
|
|
105
|
+
// height for container with additional content below player
|
|
106
|
+
const INLINE_CONTAINER_CONTENT_HEIGHT = 400;
|
|
107
|
+
|
|
108
|
+
const withBorderHack = () => {
|
|
109
|
+
if (isAndroidTV) {
|
|
110
|
+
/* @HACK: see GH#7269 */
|
|
111
|
+
return {
|
|
112
|
+
borderWidth: 1,
|
|
113
|
+
borderColor: "transparent",
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return {};
|
|
118
|
+
};
|
|
119
|
+
|
|
96
120
|
// Styles
|
|
97
121
|
const webStyles = {
|
|
98
122
|
focusableGroup: {
|
|
@@ -110,7 +134,7 @@ const webStyles = {
|
|
|
110
134
|
flex: "initial",
|
|
111
135
|
},
|
|
112
136
|
inlineRiver: {
|
|
113
|
-
height:
|
|
137
|
+
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
114
138
|
},
|
|
115
139
|
};
|
|
116
140
|
|
|
@@ -128,7 +152,7 @@ const nativeStyles = {
|
|
|
128
152
|
flex: 1,
|
|
129
153
|
},
|
|
130
154
|
inlineRiver: {
|
|
131
|
-
height:
|
|
155
|
+
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
132
156
|
},
|
|
133
157
|
};
|
|
134
158
|
|
|
@@ -148,12 +172,11 @@ const renderApplePlayer = ({
|
|
|
148
172
|
videoStyle,
|
|
149
173
|
playNextData,
|
|
150
174
|
}) => {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (!isAppleTV() || !player) {
|
|
175
|
+
if (!isTvOS || !player) {
|
|
154
176
|
return null;
|
|
155
177
|
}
|
|
156
178
|
|
|
179
|
+
// render audio_player for tvos
|
|
157
180
|
if (isAudioContent) {
|
|
158
181
|
return (
|
|
159
182
|
<AudioPlayer
|
|
@@ -167,6 +190,8 @@ const renderApplePlayer = ({
|
|
|
167
190
|
return null;
|
|
168
191
|
}
|
|
169
192
|
|
|
193
|
+
const { title, summary } = item || {};
|
|
194
|
+
|
|
170
195
|
return (
|
|
171
196
|
<ProgramInfo
|
|
172
197
|
title={title}
|
|
@@ -177,21 +202,6 @@ const renderApplePlayer = ({
|
|
|
177
202
|
);
|
|
178
203
|
};
|
|
179
204
|
|
|
180
|
-
const renderRestPlayers = ({ item, showAudioPlayer, pluginConfiguration }) => {
|
|
181
|
-
if (isApplePlatform()) {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return (
|
|
186
|
-
showAudioPlayer && (
|
|
187
|
-
<AudioPlayer
|
|
188
|
-
audio_item={item}
|
|
189
|
-
plugin_configuration={pluginConfiguration}
|
|
190
|
-
/>
|
|
191
|
-
)
|
|
192
|
-
);
|
|
193
|
-
};
|
|
194
|
-
|
|
195
205
|
const PlayerContainerComponent = (props: Props) => {
|
|
196
206
|
const {
|
|
197
207
|
Player,
|
|
@@ -321,7 +331,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
321
331
|
|
|
322
332
|
setState({ error: errorObj });
|
|
323
333
|
|
|
324
|
-
if (!
|
|
334
|
+
if (!isTvOS) {
|
|
325
335
|
setTimeout(() => {
|
|
326
336
|
close();
|
|
327
337
|
}, 800);
|
|
@@ -335,9 +345,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
335
345
|
|
|
336
346
|
const resumeTime = Number(item?.extensions?.resumeTime);
|
|
337
347
|
|
|
338
|
-
//
|
|
348
|
+
// Сhecking that the player itself knows where to start playing, and there is no need to call seekTo after returning from the Сhromecast
|
|
339
349
|
if (
|
|
340
|
-
|
|
350
|
+
!playerManager.getActivePlayer()?.hasResumePosition() &&
|
|
341
351
|
!isNaN(resumeTime)
|
|
342
352
|
) {
|
|
343
353
|
player?.seekTo(resumeTime);
|
|
@@ -478,9 +488,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
478
488
|
// TODO: Skip hook call on TV platform
|
|
479
489
|
useBackHandler(backHandler);
|
|
480
490
|
|
|
481
|
-
const isAudioContent =
|
|
482
|
-
typeof item?.content?.type === "string" &&
|
|
483
|
-
item?.content?.type.includes("audio");
|
|
491
|
+
const isAudioContent = isAudioItem(item);
|
|
484
492
|
|
|
485
493
|
useEffect(() => {
|
|
486
494
|
if (!isAudioContent) {
|
|
@@ -514,6 +522,12 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
514
522
|
useEffect(() => {
|
|
515
523
|
playerEvent("source_changed", { item });
|
|
516
524
|
|
|
525
|
+
return () => {
|
|
526
|
+
playerEvent("player_did_close", { item });
|
|
527
|
+
};
|
|
528
|
+
}, [item?.id, Player]);
|
|
529
|
+
|
|
530
|
+
useEffect(() => {
|
|
517
531
|
if (!isModal) {
|
|
518
532
|
showNavBar(false);
|
|
519
533
|
}
|
|
@@ -523,13 +537,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
523
537
|
}
|
|
524
538
|
|
|
525
539
|
return () => {
|
|
526
|
-
playerEvent("player_did_close", { item });
|
|
527
|
-
|
|
528
540
|
if (!isModal) {
|
|
529
541
|
showNavBar(true);
|
|
530
542
|
}
|
|
531
543
|
};
|
|
532
|
-
}, [showNavBar,
|
|
544
|
+
}, [showNavBar, isModal, Player]);
|
|
533
545
|
|
|
534
546
|
useEffect(() => {
|
|
535
547
|
if (prevItemId && !R.equals(prevItemId, item?.id)) {
|
|
@@ -550,10 +562,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
550
562
|
|
|
551
563
|
const uri = item?.content ? item.content?.src : null;
|
|
552
564
|
|
|
553
|
-
const isInlineTV =
|
|
554
|
-
screenData?.ui_components &&
|
|
555
|
-
screenData?.ui_components?.length > 0 &&
|
|
556
|
-
isTV();
|
|
565
|
+
const isInlineTV = isInlineTVUtil(screenData);
|
|
557
566
|
|
|
558
567
|
const inline =
|
|
559
568
|
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
|
|
@@ -578,7 +587,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
578
587
|
);
|
|
579
588
|
}
|
|
580
589
|
|
|
581
|
-
if (screen_background_color) {
|
|
590
|
+
if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
|
|
582
591
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
583
592
|
}
|
|
584
593
|
|
|
@@ -596,6 +605,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
596
605
|
tv_component_container_height,
|
|
597
606
|
screen_background_color,
|
|
598
607
|
isInlineTV,
|
|
608
|
+
mode,
|
|
599
609
|
]);
|
|
600
610
|
|
|
601
611
|
const applePlayerProps = {
|
|
@@ -607,12 +617,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
607
617
|
playNextData,
|
|
608
618
|
};
|
|
609
619
|
|
|
610
|
-
const restPlayerProps = {
|
|
611
|
-
item,
|
|
612
|
-
showAudioPlayer: isAudioContent,
|
|
613
|
-
pluginConfiguration,
|
|
614
|
-
};
|
|
615
|
-
|
|
616
620
|
return (
|
|
617
621
|
<PlayerStateContext.Provider value={value}>
|
|
618
622
|
<PlayerContainerContextProvider
|
|
@@ -640,7 +644,14 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
640
644
|
testID={"player-screen-container"}
|
|
641
645
|
>
|
|
642
646
|
{/* Player container */}
|
|
643
|
-
<View
|
|
647
|
+
<View
|
|
648
|
+
style={[
|
|
649
|
+
styles.playerWrapper,
|
|
650
|
+
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
651
|
+
withBorderHack(),
|
|
652
|
+
]}
|
|
653
|
+
testID={"player-wrapper"}
|
|
654
|
+
>
|
|
644
655
|
<PlayerFocusableWrapperView
|
|
645
656
|
nextFocusDown={context.bottomFocusableId}
|
|
646
657
|
>
|
|
@@ -681,12 +692,10 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
681
692
|
</Player>
|
|
682
693
|
</PlayerFocusableWrapperView>
|
|
683
694
|
|
|
684
|
-
{
|
|
685
|
-
|
|
686
|
-
{state.error && <ErrorDisplay error={state.error} />}
|
|
695
|
+
{state.error ? <ErrorDisplay error={state.error} /> : null}
|
|
687
696
|
</View>
|
|
688
697
|
{/* Components container */}
|
|
689
|
-
{isInlineTV && context.showComponentsContainer
|
|
698
|
+
{isInlineTV && context.showComponentsContainer ? (
|
|
690
699
|
<View
|
|
691
700
|
style={styles.inlineRiver}
|
|
692
701
|
testID={"inline-river-component-wrapper"}
|
|
@@ -706,7 +715,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
706
715
|
screenId={screenData.id}
|
|
707
716
|
key={item.id}
|
|
708
717
|
groupId={FocusableGroupMainContainerId}
|
|
709
|
-
cellTapAction={
|
|
718
|
+
cellTapAction={onCellTap}
|
|
710
719
|
extraAnchorPointYOffset={-600}
|
|
711
720
|
isScreenWrappedInContainer={true}
|
|
712
721
|
containerHeight={styles.inlineRiver.height}
|
|
@@ -717,7 +726,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
717
726
|
)}
|
|
718
727
|
</ComponentFocusableWrapperView>
|
|
719
728
|
</View>
|
|
720
|
-
)}
|
|
729
|
+
) : null}
|
|
721
730
|
</View>
|
|
722
731
|
</FocusableGroup>
|
|
723
732
|
</TVEventHandlerComponent>
|
|
@@ -114,12 +114,12 @@ function ProgramInfoComponent({
|
|
|
114
114
|
return (
|
|
115
115
|
<View style={container}>
|
|
116
116
|
<View style={programStyles.programInfo.container}>
|
|
117
|
-
{logo
|
|
117
|
+
{logo ? (
|
|
118
118
|
<Image
|
|
119
119
|
source={{ uri: logo }}
|
|
120
120
|
style={programStyles.programInfo.logo}
|
|
121
121
|
/>
|
|
122
|
-
)}
|
|
122
|
+
) : null}
|
|
123
123
|
{!isAudioContent && transportInfo}
|
|
124
124
|
</View>
|
|
125
125
|
</View>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { View, StyleSheet,
|
|
3
|
+
import { View, StyleSheet, FlatList } from "react-native";
|
|
4
4
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
5
5
|
import { RiverItem } from "../RiverItem";
|
|
6
6
|
import { RiverFooter } from "../RiverFooter";
|
|
@@ -24,6 +24,10 @@ import { withComponentsMapProvider } from "@applicaster/zapp-react-native-ui-com
|
|
|
24
24
|
import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
25
25
|
import { useShallow } from "zustand/react/shallow";
|
|
26
26
|
|
|
27
|
+
import { isAndroidPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
28
|
+
|
|
29
|
+
const isAndroid = isAndroidPlatform();
|
|
30
|
+
|
|
27
31
|
type Props = {
|
|
28
32
|
feed: ZappFeed;
|
|
29
33
|
groupId?: string;
|
|
@@ -34,6 +38,7 @@ type Props = {
|
|
|
34
38
|
getStaticComponentFeed: any;
|
|
35
39
|
pullToRefreshPipesV1RefreshingStateUpdater: () => boolean;
|
|
36
40
|
refreshingPipesV1?: boolean;
|
|
41
|
+
stickyHeaderIndices?: number[];
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
const styles = StyleSheet.create({
|
|
@@ -61,6 +66,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
61
66
|
// TODO: Remove when pipes v1 is deprecated.
|
|
62
67
|
pullToRefreshPipesV1RefreshingStateUpdater,
|
|
63
68
|
refreshingPipesV1,
|
|
69
|
+
stickyHeaderIndices,
|
|
64
70
|
} = props;
|
|
65
71
|
|
|
66
72
|
const flatListRef = React.useRef<FlatList | null>(null);
|
|
@@ -70,21 +76,6 @@ function ComponentsMapComponent(props: Props) {
|
|
|
70
76
|
|
|
71
77
|
const [flatListHeight, setFlatListHeight] = React.useState(null);
|
|
72
78
|
|
|
73
|
-
const {
|
|
74
|
-
isAnyLoading,
|
|
75
|
-
isAllLoaded,
|
|
76
|
-
waitForAllComponents,
|
|
77
|
-
onLoadFinished,
|
|
78
|
-
onLoadFailed,
|
|
79
|
-
shouldShowLoadingError,
|
|
80
|
-
isAnyLoaded,
|
|
81
|
-
arePreviousComponentsLoaded,
|
|
82
|
-
} = useLoadingState(feed?.entry?.length || components.length);
|
|
83
|
-
|
|
84
|
-
const theme = useTheme();
|
|
85
|
-
|
|
86
|
-
const logTimestamp = useProfilerLogging();
|
|
87
|
-
|
|
88
79
|
const riverComponents = React.useMemo(() => {
|
|
89
80
|
if (feed?.entry?.length < components.length) {
|
|
90
81
|
return R.slice(0, feed?.entry?.length, components);
|
|
@@ -93,55 +84,42 @@ function ComponentsMapComponent(props: Props) {
|
|
|
93
84
|
return components;
|
|
94
85
|
}, [components, feed]);
|
|
95
86
|
|
|
87
|
+
const logTimestamp = useProfilerLogging();
|
|
88
|
+
|
|
89
|
+
const onLoadDone = React.useCallback(() => {
|
|
90
|
+
logTimestamp(riverId?.toString());
|
|
91
|
+
}, [logTimestamp]);
|
|
92
|
+
|
|
93
|
+
const { loadingState, onLoadFinished, onLoadFailed, shouldShowLoadingError } =
|
|
94
|
+
useLoadingState(riverComponents.length, onLoadDone);
|
|
95
|
+
|
|
96
|
+
const theme = useTheme();
|
|
97
|
+
|
|
96
98
|
const renderRiverItem = React.useCallback(
|
|
97
99
|
({ item, index }) => {
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
100
|
+
const riverItemProps = {
|
|
101
|
+
riverId,
|
|
102
|
+
item,
|
|
103
|
+
index,
|
|
104
|
+
isScreenWrappedInContainer,
|
|
105
|
+
feed,
|
|
106
|
+
groupId,
|
|
107
|
+
onLoadFailed,
|
|
108
|
+
onLoadFinished,
|
|
109
|
+
getStaticComponentFeed,
|
|
110
|
+
isLast: isLast(index, riverComponents.length),
|
|
111
|
+
loadingState,
|
|
102
112
|
};
|
|
103
113
|
|
|
104
114
|
return (
|
|
105
|
-
<
|
|
106
|
-
<
|
|
107
|
-
|
|
108
|
-
{...{
|
|
109
|
-
readyToBeDisplayed,
|
|
110
|
-
riverId,
|
|
111
|
-
item,
|
|
112
|
-
index,
|
|
113
|
-
isScreenWrappedInContainer,
|
|
114
|
-
feed,
|
|
115
|
-
groupId,
|
|
116
|
-
onLoadFailed,
|
|
117
|
-
onLoadFinished,
|
|
118
|
-
getStaticComponentFeed,
|
|
119
|
-
isLast: isLast(index, riverComponents.length),
|
|
120
|
-
}}
|
|
121
|
-
/>
|
|
122
|
-
</ScreenLoadingMeasurementsListItemWrapper>
|
|
123
|
-
</View>
|
|
115
|
+
<ScreenLoadingMeasurementsListItemWrapper index={index}>
|
|
116
|
+
<RiverItem {...riverItemProps} />
|
|
117
|
+
</ScreenLoadingMeasurementsListItemWrapper>
|
|
124
118
|
);
|
|
125
119
|
},
|
|
126
|
-
[
|
|
127
|
-
feed,
|
|
128
|
-
getStaticComponentFeed,
|
|
129
|
-
arePreviousComponentsLoaded,
|
|
130
|
-
onLoadFailed,
|
|
131
|
-
onLoadFinished,
|
|
132
|
-
]
|
|
120
|
+
[feed, getStaticComponentFeed, onLoadFailed, onLoadFinished]
|
|
133
121
|
);
|
|
134
122
|
|
|
135
|
-
const renderFooter = React.useCallback(() => {
|
|
136
|
-
return (
|
|
137
|
-
<RiverFooter
|
|
138
|
-
visible={isAnyLoading}
|
|
139
|
-
flatListHeight={flatListHeight}
|
|
140
|
-
isAnyLoaded={isAnyLoaded || waitForAllComponents}
|
|
141
|
-
/>
|
|
142
|
-
);
|
|
143
|
-
}, [flatListHeight, isAnyLoading, isAnyLoaded]);
|
|
144
|
-
|
|
145
123
|
const screenStyle = React.useMemo(
|
|
146
124
|
() => ({
|
|
147
125
|
paddingTop: ifEmptyUseFallback(
|
|
@@ -179,12 +157,6 @@ function ComponentsMapComponent(props: Props) {
|
|
|
179
157
|
|
|
180
158
|
usePipesCacheReset(riverId, riverComponents);
|
|
181
159
|
|
|
182
|
-
React.useEffect(() => {
|
|
183
|
-
if (isAllLoaded) {
|
|
184
|
-
logTimestamp(riverId?.toString());
|
|
185
|
-
}
|
|
186
|
-
}, [isAllLoaded]);
|
|
187
|
-
|
|
188
160
|
const refreshControl = React.useMemo(
|
|
189
161
|
() =>
|
|
190
162
|
pullToRefreshEnabled ? (
|
|
@@ -280,6 +252,11 @@ function ComponentsMapComponent(props: Props) {
|
|
|
280
252
|
}
|
|
281
253
|
}, []);
|
|
282
254
|
|
|
255
|
+
const contentContainerStyle = React.useMemo(
|
|
256
|
+
() => (isScreenWrappedInContainer ? {} : screenStyle),
|
|
257
|
+
[isScreenWrappedInContainer, screenStyle]
|
|
258
|
+
);
|
|
259
|
+
|
|
283
260
|
if (shouldShowLoadingError) {
|
|
284
261
|
return <RiverError />;
|
|
285
262
|
}
|
|
@@ -291,7 +268,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
291
268
|
<View style={styles.container}>
|
|
292
269
|
<ScreenLoadingMeasurements
|
|
293
270
|
riverId={riverId}
|
|
294
|
-
numberOfComponents={
|
|
271
|
+
numberOfComponents={riverComponents.length}
|
|
295
272
|
>
|
|
296
273
|
<ViewportTracker>
|
|
297
274
|
<FlatList
|
|
@@ -300,11 +277,12 @@ function ComponentsMapComponent(props: Props) {
|
|
|
300
277
|
}}
|
|
301
278
|
// Fix for WebView rerender crashes on Android API 28+
|
|
302
279
|
// https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
|
|
303
|
-
overScrollMode={
|
|
280
|
+
overScrollMode={isAndroid ? "never" : "auto"}
|
|
304
281
|
scrollIndicatorInsets={scrollIndicatorInsets}
|
|
305
282
|
extraData={feed}
|
|
283
|
+
stickyHeaderIndices={stickyHeaderIndices}
|
|
306
284
|
onLayout={handleOnLayout}
|
|
307
|
-
removeClippedSubviews
|
|
285
|
+
removeClippedSubviews={isAndroid}
|
|
308
286
|
initialNumToRender={3}
|
|
309
287
|
maxToRenderPerBatch={10}
|
|
310
288
|
windowSize={12}
|
|
@@ -312,16 +290,23 @@ function ComponentsMapComponent(props: Props) {
|
|
|
312
290
|
keyExtractor={keyExtractor}
|
|
313
291
|
renderItem={renderRiverItem}
|
|
314
292
|
data={riverComponents}
|
|
315
|
-
contentContainerStyle={
|
|
316
|
-
|
|
293
|
+
contentContainerStyle={contentContainerStyle}
|
|
294
|
+
ListFooterComponent={
|
|
295
|
+
<RiverFooter
|
|
296
|
+
flatListHeight={flatListHeight}
|
|
297
|
+
loadingState={loadingState}
|
|
298
|
+
/>
|
|
317
299
|
}
|
|
318
|
-
ListFooterComponent={renderFooter}
|
|
319
300
|
refreshControl={refreshControl}
|
|
320
301
|
onScrollBeginDrag={onScrollBeginDrag}
|
|
321
302
|
onScroll={onScroll}
|
|
322
303
|
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
323
304
|
onScrollEndDrag={_onScrollEndDrag}
|
|
324
305
|
scrollEventThrottle={16}
|
|
306
|
+
maintainVisibleContentPosition={{
|
|
307
|
+
minIndexForVisible: 0,
|
|
308
|
+
autoscrollToTopThreshold: 10,
|
|
309
|
+
}}
|
|
325
310
|
{...scrollViewExtraProps}
|
|
326
311
|
/>
|
|
327
312
|
</ViewportTracker>
|
|
@@ -1,50 +1,86 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const anyFalse = R.any(R.equals(false));
|
|
6
|
-
const anyTrue = R.any(R.equals(true));
|
|
2
|
+
import { isNil, set, lensIndex, T, slice } from "ramda";
|
|
3
|
+
import { BehaviorSubject } from "rxjs";
|
|
4
|
+
import { useRefWithInitialValue } from "@applicaster/zapp-react-native-utils/reactHooks/state/useRefWithInitialValue";
|
|
7
5
|
|
|
8
6
|
const reducer = (state, { payload }) => {
|
|
9
|
-
if (!
|
|
10
|
-
return
|
|
7
|
+
if (!isNil(payload) && !state[payload]) {
|
|
8
|
+
return set(lensIndex(payload), true)(state);
|
|
11
9
|
}
|
|
12
10
|
|
|
13
11
|
return state;
|
|
14
12
|
};
|
|
15
13
|
|
|
16
|
-
type
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
type LoadingState = {
|
|
15
|
+
index: number;
|
|
16
|
+
done: boolean;
|
|
19
17
|
waitForAllComponents: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type Return = {
|
|
21
|
+
loadingState: BehaviorSubject<LoadingState>;
|
|
20
22
|
onLoadFinished: (index: number) => void;
|
|
21
23
|
onLoadFailed: ({ error, index }: { error: Error; index: number }) => void;
|
|
22
24
|
shouldShowLoadingError: boolean;
|
|
23
|
-
isAnyLoaded: boolean;
|
|
24
25
|
arePreviousComponentsLoaded: (index: number) => boolean;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
|
-
type Action = { payload: { index: number } };
|
|
28
|
-
|
|
29
|
-
type Loaded = true;
|
|
30
|
-
type Loading = false;
|
|
31
|
-
|
|
32
|
-
type LoadingState = Array<Loaded | Loading>;
|
|
33
|
-
|
|
34
28
|
// TODO: Take this value from Zapp configuration, when feature is added to GeneralScreen
|
|
35
29
|
const SHOULD_FAIL_ON_COMPONENT_LOADING = false;
|
|
36
30
|
|
|
37
|
-
|
|
31
|
+
const createLoadingStateObservable = (count: number) =>
|
|
32
|
+
new BehaviorSubject<LoadingState>({
|
|
33
|
+
index: -1,
|
|
34
|
+
done: count === 0,
|
|
35
|
+
waitForAllComponents: SHOULD_FAIL_ON_COMPONENT_LOADING,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export const useLoadingState = (
|
|
39
|
+
count: number,
|
|
40
|
+
onLoadDone: () => void
|
|
41
|
+
): Return => {
|
|
42
|
+
const componentStateRef = React.useRef(new Array(count).fill(false));
|
|
38
43
|
const [loadingError, setLoadingError] = React.useState(null);
|
|
39
44
|
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
45
|
+
const loadingState = useRefWithInitialValue<BehaviorSubject<LoadingState>>(
|
|
46
|
+
() => createLoadingStateObservable(count)
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const arePreviousComponentsLoaded = React.useCallback((index) => {
|
|
50
|
+
if (index === 0) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
43
53
|
|
|
44
|
-
|
|
45
|
-
|
|
54
|
+
const componentsBefore = slice(0, index, componentStateRef.current);
|
|
55
|
+
|
|
56
|
+
return componentsBefore.every(T);
|
|
46
57
|
}, []);
|
|
47
58
|
|
|
59
|
+
const dispatch = React.useCallback(({ payload }) => {
|
|
60
|
+
const newState = reducer(componentStateRef.current, { payload });
|
|
61
|
+
componentStateRef.current = newState;
|
|
62
|
+
const isDone = arePreviousComponentsLoaded(count - 1);
|
|
63
|
+
|
|
64
|
+
const state = loadingState.current.getValue();
|
|
65
|
+
|
|
66
|
+
const newLoadingState = {
|
|
67
|
+
...state,
|
|
68
|
+
index: state.index < payload ? payload : state.index,
|
|
69
|
+
done: isDone,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
loadingState.current.next(newLoadingState);
|
|
73
|
+
|
|
74
|
+
if (isDone) {
|
|
75
|
+
onLoadDone();
|
|
76
|
+
}
|
|
77
|
+
}, []);
|
|
78
|
+
|
|
79
|
+
const handleComponentLoaded = React.useCallback(
|
|
80
|
+
(index) => dispatch({ payload: index }),
|
|
81
|
+
[]
|
|
82
|
+
);
|
|
83
|
+
|
|
48
84
|
const handleComponentLoadErrorWhenNeedToFail = React.useCallback(
|
|
49
85
|
({ error }) => {
|
|
50
86
|
if (error !== loadingError) {
|
|
@@ -55,35 +91,26 @@ export const useLoadingState = (count: number): Return => {
|
|
|
55
91
|
);
|
|
56
92
|
|
|
57
93
|
const handleComponentLoadErrorWhenNoNeedToFail = React.useCallback(
|
|
58
|
-
({ index }) =>
|
|
59
|
-
handleComponentLoaded(index);
|
|
60
|
-
},
|
|
94
|
+
({ index }) => handleComponentLoaded(index),
|
|
61
95
|
[]
|
|
62
96
|
);
|
|
63
97
|
|
|
64
|
-
|
|
65
|
-
(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
},
|
|
74
|
-
[
|
|
98
|
+
return React.useMemo(
|
|
99
|
+
() => ({
|
|
100
|
+
loadingState: loadingState.current,
|
|
101
|
+
onLoadFinished: handleComponentLoaded,
|
|
102
|
+
onLoadFailed: SHOULD_FAIL_ON_COMPONENT_LOADING
|
|
103
|
+
? handleComponentLoadErrorWhenNeedToFail
|
|
104
|
+
: handleComponentLoadErrorWhenNoNeedToFail,
|
|
105
|
+
shouldShowLoadingError: SHOULD_FAIL_ON_COMPONENT_LOADING && loadingError,
|
|
106
|
+
arePreviousComponentsLoaded,
|
|
107
|
+
}),
|
|
108
|
+
[
|
|
109
|
+
loadingError,
|
|
110
|
+
handleComponentLoaded,
|
|
111
|
+
handleComponentLoadErrorWhenNeedToFail,
|
|
112
|
+
handleComponentLoadErrorWhenNoNeedToFail,
|
|
113
|
+
arePreviousComponentsLoaded,
|
|
114
|
+
]
|
|
75
115
|
);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
isAnyLoading: anyFalse(componentsState),
|
|
79
|
-
isAllLoaded: allTrue(componentsState),
|
|
80
|
-
onLoadFinished: handleComponentLoaded,
|
|
81
|
-
onLoadFailed: SHOULD_FAIL_ON_COMPONENT_LOADING
|
|
82
|
-
? handleComponentLoadErrorWhenNeedToFail
|
|
83
|
-
: handleComponentLoadErrorWhenNoNeedToFail,
|
|
84
|
-
shouldShowLoadingError: SHOULD_FAIL_ON_COMPONENT_LOADING && loadingError,
|
|
85
|
-
isAnyLoaded: anyTrue(componentsState),
|
|
86
|
-
waitForAllComponents: SHOULD_FAIL_ON_COMPONENT_LOADING,
|
|
87
|
-
arePreviousComponentsLoaded,
|
|
88
|
-
};
|
|
89
116
|
};
|