@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1724095599 → 13.0.0-alpha.1731130113
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 +5 -9
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +8 -9
- package/Components/AudioPlayer/helpers.tsx +1 -2
- package/Components/Cell/Cell.tsx +3 -13
- package/Components/Cell/CellWithFocusable.tsx +21 -15
- package/Components/Cell/CellWrapper.tsx +18 -0
- package/Components/Cell/styles.ts +17 -0
- package/Components/CellRendererResolver/index.ts +2 -1
- package/Components/ErrorScreen/index.tsx +8 -0
- package/Components/FocusableCell/index.tsx +1 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +34 -86
- package/Components/FocusableGroup/index.tsx +0 -3
- 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 +2 -1
- 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 +1 -0
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +1 -0
- 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/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/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 +9 -8
- package/Components/ModalComponent/utils.ts +55 -7
- package/Components/OfflineHandler/utils/index.ts +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +55 -46
- package/Components/PlayerImageBackground/index.tsx +1 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +14 -3
- package/Components/River/ComponentsMap/hooks/useLoadingState.ts +3 -3
- package/Components/River/RiverItem.tsx +8 -3
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +7 -1
- package/Components/RouteManager/TestId.tsx +1 -5
- package/Components/RouteManager/__tests__/__snapshots__/routeManager.test.js.snap +0 -1
- package/Components/RouteManager/__tests__/testId.test.js +0 -4
- 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 +3 -6
- package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
- package/Components/TrackedView/index.tsx +1 -0
- package/Components/Transitioner/AnimationManager.js +15 -15
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +4 -0
- 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 +35 -19
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +3 -3
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +38 -14
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +11 -3
- 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 +13 -5
- package/Components/VideoModal/PlayerWrapper.tsx +35 -22
- 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/ZappUIComponent/index.tsx +4 -4
- 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/RiverResolver/index.tsx +5 -7
- package/Decorators/ZappPipesDataConnector/index.tsx +4 -30
- package/package.json +5 -9
- 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/Cell/CellWithFocusable.ios.tsx +0 -126
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
2
|
-
import { PluginConfiguration } from "./
|
|
2
|
+
import { PluginConfiguration } from "./";
|
|
3
|
+
import { ItemIconProps } from "./Button/ItemIcon";
|
|
4
|
+
import { ItemLabelProps } from "./Button/ItemLabel";
|
|
5
|
+
import { ItemProps } from "./Button/Item";
|
|
3
6
|
|
|
4
7
|
export function defaultItemProps(
|
|
5
8
|
config: PluginConfiguration,
|
|
6
9
|
maxWidth: number
|
|
7
|
-
) {
|
|
10
|
+
): ItemProps {
|
|
8
11
|
const {
|
|
9
12
|
modal_bottom_sheet_item_background_color,
|
|
10
13
|
modal_bottom_sheet_item_focus_background_color,
|
|
11
14
|
modal_bottom_sheet_item_selected_background_color,
|
|
12
|
-
|
|
15
|
+
modal_bottom_sheet_item_focused_selected_background_color,
|
|
13
16
|
modal_bottom_sheet_item_corner_radius,
|
|
14
17
|
modal_bottom_sheet_item_margin_bottom,
|
|
15
18
|
modal_bottom_sheet_item_margin_left,
|
|
@@ -25,8 +28,8 @@ export function defaultItemProps(
|
|
|
25
28
|
backgroundColor: modal_bottom_sheet_item_background_color,
|
|
26
29
|
focusedBackgroundColor: modal_bottom_sheet_item_focus_background_color,
|
|
27
30
|
selectedBackgroundColor: modal_bottom_sheet_item_selected_background_color,
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
focusedSelectedBackgroundColor:
|
|
32
|
+
modal_bottom_sheet_item_focused_selected_background_color,
|
|
30
33
|
borderRadius: modal_bottom_sheet_item_corner_radius,
|
|
31
34
|
marginBottom: modal_bottom_sheet_item_margin_bottom,
|
|
32
35
|
marginTop: modal_bottom_sheet_item_margin_top,
|
|
@@ -43,7 +46,7 @@ export function defaultItemProps(
|
|
|
43
46
|
export function defaultItemLabelProps(
|
|
44
47
|
config: PluginConfiguration,
|
|
45
48
|
sheetWidth: number
|
|
46
|
-
) {
|
|
49
|
+
): ItemLabelProps {
|
|
47
50
|
const {
|
|
48
51
|
modal_bottom_sheet_item_label_android_letter_spacing,
|
|
49
52
|
modal_bottom_sheet_item_label_ios_letter_spacing,
|
|
@@ -103,7 +106,9 @@ export function defaultItemLabelProps(
|
|
|
103
106
|
};
|
|
104
107
|
}
|
|
105
108
|
|
|
106
|
-
export function defaultItemIconProps(
|
|
109
|
+
export function defaultItemIconProps(
|
|
110
|
+
config: PluginConfiguration
|
|
111
|
+
): ItemIconProps {
|
|
107
112
|
const {
|
|
108
113
|
modal_bottom_sheet_item_icon_height,
|
|
109
114
|
modal_bottom_sheet_item_icon_width,
|
|
@@ -124,3 +129,46 @@ export function defaultItemIconProps(config: PluginConfiguration) {
|
|
|
124
129
|
marginRight: modal_bottom_sheet_item_icon_margin_right,
|
|
125
130
|
};
|
|
126
131
|
}
|
|
132
|
+
|
|
133
|
+
export function getItemIconProps(
|
|
134
|
+
theme: PluginConfiguration,
|
|
135
|
+
iconProps?: ((theme: PluginConfiguration) => ItemIconProps) | ItemIconProps
|
|
136
|
+
) {
|
|
137
|
+
if (iconProps) {
|
|
138
|
+
return typeof iconProps === "function" ? iconProps(theme) : iconProps;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return defaultItemIconProps(theme);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function getItemLabelProps(
|
|
145
|
+
theme: PluginConfiguration,
|
|
146
|
+
width: number,
|
|
147
|
+
labelProps?:
|
|
148
|
+
| ((theme: PluginConfiguration, width: number) => ItemLabelProps)
|
|
149
|
+
| ItemLabelProps
|
|
150
|
+
) {
|
|
151
|
+
if (labelProps) {
|
|
152
|
+
return typeof labelProps === "function"
|
|
153
|
+
? labelProps(theme, width)
|
|
154
|
+
: labelProps;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return defaultItemLabelProps(theme, width);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function getItemProps(
|
|
161
|
+
theme: PluginConfiguration,
|
|
162
|
+
width: number,
|
|
163
|
+
itemProps?:
|
|
164
|
+
| ((theme: PluginConfiguration, width: number) => ItemProps)
|
|
165
|
+
| ItemProps
|
|
166
|
+
) {
|
|
167
|
+
if (itemProps) {
|
|
168
|
+
return typeof itemProps === "function"
|
|
169
|
+
? itemProps(theme, width)
|
|
170
|
+
: itemProps;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return defaultItemProps(theme, width);
|
|
174
|
+
}
|
|
@@ -57,7 +57,7 @@ export const useNotificationHeight = () => {
|
|
|
57
57
|
|
|
58
58
|
const navBarHeight = platformSelect({ ios: 44, android: 56 });
|
|
59
59
|
|
|
60
|
-
const statusHeight =
|
|
60
|
+
const statusHeight = insets.top;
|
|
61
61
|
const notificationHeight = statusHeight + navBarHeight;
|
|
62
62
|
|
|
63
63
|
return { statusHeight, notificationHeight };
|
|
@@ -6,10 +6,15 @@ import * as R from "ramda";
|
|
|
6
6
|
import uuid from "uuid/v4";
|
|
7
7
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
8
8
|
import {
|
|
9
|
-
isApplePlatform,
|
|
10
9
|
isTV,
|
|
11
10
|
platformSelect,
|
|
11
|
+
isAndroidTVPlatform,
|
|
12
|
+
isTvOSPlatform,
|
|
12
13
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
+
import {
|
|
15
|
+
isAudioItem,
|
|
16
|
+
isInlineTV as isInlineTVUtil,
|
|
17
|
+
} from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
13
18
|
|
|
14
19
|
import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
|
|
15
20
|
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
@@ -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,
|
|
@@ -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,8 +692,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
681
692
|
</Player>
|
|
682
693
|
</PlayerFocusableWrapperView>
|
|
683
694
|
|
|
684
|
-
{renderRestPlayers(restPlayerProps)}
|
|
685
|
-
|
|
686
695
|
{state.error ? <ErrorDisplay error={state.error} /> : null}
|
|
687
696
|
</View>
|
|
688
697
|
{/* Components container */}
|
|
@@ -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}
|
|
@@ -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);
|
|
@@ -271,11 +277,12 @@ function ComponentsMapComponent(props: Props) {
|
|
|
271
277
|
}}
|
|
272
278
|
// Fix for WebView rerender crashes on Android API 28+
|
|
273
279
|
// https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
|
|
274
|
-
overScrollMode={
|
|
280
|
+
overScrollMode={isAndroid ? "never" : "auto"}
|
|
275
281
|
scrollIndicatorInsets={scrollIndicatorInsets}
|
|
276
282
|
extraData={feed}
|
|
283
|
+
stickyHeaderIndices={stickyHeaderIndices}
|
|
277
284
|
onLayout={handleOnLayout}
|
|
278
|
-
removeClippedSubviews
|
|
285
|
+
removeClippedSubviews={isAndroid}
|
|
279
286
|
initialNumToRender={3}
|
|
280
287
|
maxToRenderPerBatch={10}
|
|
281
288
|
windowSize={12}
|
|
@@ -296,6 +303,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
296
303
|
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
297
304
|
onScrollEndDrag={_onScrollEndDrag}
|
|
298
305
|
scrollEventThrottle={16}
|
|
306
|
+
maintainVisibleContentPosition={{
|
|
307
|
+
minIndexForVisible: 0,
|
|
308
|
+
autoscrollToTopThreshold: 10,
|
|
309
|
+
}}
|
|
299
310
|
{...scrollViewExtraProps}
|
|
300
311
|
/>
|
|
301
312
|
</ViewportTracker>
|
|
@@ -28,10 +28,10 @@ type Return = {
|
|
|
28
28
|
// TODO: Take this value from Zapp configuration, when feature is added to GeneralScreen
|
|
29
29
|
const SHOULD_FAIL_ON_COMPONENT_LOADING = false;
|
|
30
30
|
|
|
31
|
-
const createLoadingStateObservable = () =>
|
|
31
|
+
const createLoadingStateObservable = (count: number) =>
|
|
32
32
|
new BehaviorSubject<LoadingState>({
|
|
33
33
|
index: -1,
|
|
34
|
-
done:
|
|
34
|
+
done: count === 0,
|
|
35
35
|
waitForAllComponents: SHOULD_FAIL_ON_COMPONENT_LOADING,
|
|
36
36
|
});
|
|
37
37
|
|
|
@@ -43,7 +43,7 @@ export const useLoadingState = (
|
|
|
43
43
|
const [loadingError, setLoadingError] = React.useState(null);
|
|
44
44
|
|
|
45
45
|
const loadingState = useRefWithInitialValue<BehaviorSubject<LoadingState>>(
|
|
46
|
-
createLoadingStateObservable
|
|
46
|
+
() => createLoadingStateObservable(count)
|
|
47
47
|
);
|
|
48
48
|
|
|
49
49
|
const arePreviousComponentsLoaded = React.useCallback((index) => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import { isGroup } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
3
4
|
|
|
4
5
|
import { applyDecorators } from "../../Decorators";
|
|
5
6
|
|
|
@@ -47,16 +48,20 @@ const useLoadingState = (
|
|
|
47
48
|
loadingState: RiverItemType["loadingState"]
|
|
48
49
|
) => {
|
|
49
50
|
const [readyToBeDisplayed, setReadyToBeDisplayed] = React.useState(
|
|
50
|
-
loadingState.getValue().index + 1
|
|
51
|
+
loadingState.getValue().index + 1 >= currentIndex
|
|
51
52
|
);
|
|
52
53
|
|
|
53
54
|
useEffect(() => {
|
|
54
55
|
const subscription = loadingState.subscribe(({ index }) => {
|
|
55
|
-
if (index + 1
|
|
56
|
+
if (index + 1 >= currentIndex) {
|
|
56
57
|
setReadyToBeDisplayed(true);
|
|
57
58
|
}
|
|
58
59
|
});
|
|
59
60
|
|
|
61
|
+
if (loadingState.getValue().index + 1 >= currentIndex) {
|
|
62
|
+
setReadyToBeDisplayed(true);
|
|
63
|
+
}
|
|
64
|
+
|
|
60
65
|
return () => {
|
|
61
66
|
subscription.unsubscribe();
|
|
62
67
|
};
|
|
@@ -112,7 +117,7 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
112
117
|
jsOnly: true,
|
|
113
118
|
});
|
|
114
119
|
|
|
115
|
-
if (!CellRenderer && item
|
|
120
|
+
if (!CellRenderer && !isGroup(item)) {
|
|
116
121
|
riverLogger.warning({
|
|
117
122
|
message: "Cell Renderer is null - will fallback to default cell",
|
|
118
123
|
data: { item, CellRenderer },
|
|
@@ -135,6 +135,12 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
135
135
|
getItemCount={[Function]}
|
|
136
136
|
initialNumToRender={3}
|
|
137
137
|
keyExtractor={[Function]}
|
|
138
|
+
maintainVisibleContentPosition={
|
|
139
|
+
{
|
|
140
|
+
"autoscrollToTopThreshold": 10,
|
|
141
|
+
"minIndexForVisible": 0,
|
|
142
|
+
}
|
|
143
|
+
}
|
|
138
144
|
maxToRenderPerBatch={10}
|
|
139
145
|
onContentSizeChange={[Function]}
|
|
140
146
|
onLayout={[Function]}
|
|
@@ -145,7 +151,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
145
151
|
onScrollEndDrag={[Function]}
|
|
146
152
|
overScrollMode="auto"
|
|
147
153
|
refreshControl={null}
|
|
148
|
-
removeClippedSubviews={
|
|
154
|
+
removeClippedSubviews={false}
|
|
149
155
|
renderItem={[Function]}
|
|
150
156
|
scrollEventThrottle={16}
|
|
151
157
|
scrollIndicatorInsets={
|
|
@@ -12,11 +12,7 @@ const styles = StyleSheet.create({
|
|
|
12
12
|
|
|
13
13
|
export function TestId({ screenId, children }: Props) {
|
|
14
14
|
return (
|
|
15
|
-
<View
|
|
16
|
-
testID={screenId}
|
|
17
|
-
accessibilityLabel={screenId}
|
|
18
|
-
style={styles.container}
|
|
19
|
-
>
|
|
15
|
+
<View testID={screenId} style={styles.container}>
|
|
20
16
|
{children}
|
|
21
17
|
</View>
|
|
22
18
|
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const {
|
|
2
|
+
useScreenBackgroundColor,
|
|
3
|
+
} = require("@applicaster/zapp-react-native-utils/reactHooks/screen");
|
|
4
|
+
|
|
5
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
|
|
6
|
+
useScreenBackgroundColor: jest.fn(),
|
|
7
|
+
useNavbarState: jest.fn().mockReturnValue({ visible: true }),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
describe("TV Screen Component", () => {
|
|
11
|
+
it("uses the useScreenBackgroundColor hook with the correct screen ID", () => {
|
|
12
|
+
useScreenBackgroundColor.mockReturnValue("#FF0000");
|
|
13
|
+
|
|
14
|
+
expect(useScreenBackgroundColor("test-screen-id")).toBe("#FF0000");
|
|
15
|
+
|
|
16
|
+
// Verify the hook was called with the correct screen ID
|
|
17
|
+
expect(useScreenBackgroundColor).toHaveBeenCalledWith("test-screen-id");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("returns 'transparent' when the screen background color is not defined", () => {
|
|
21
|
+
useScreenBackgroundColor.mockReturnValue("transparent");
|
|
22
|
+
|
|
23
|
+
// Verify the hook returns 'transparent'
|
|
24
|
+
expect(useScreenBackgroundColor("test-screen-id")).toBe("transparent");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -92,6 +92,10 @@ const getNavigations = ({
|
|
|
92
92
|
return fallbackNavigations;
|
|
93
93
|
};
|
|
94
94
|
|
|
95
|
+
const onRelease = () => {
|
|
96
|
+
focusManager.setInitialFocus();
|
|
97
|
+
};
|
|
98
|
+
|
|
95
99
|
export const Screen = ({ route, Components }: Props) => {
|
|
96
100
|
if (isNilOrEmpty(route)) {
|
|
97
101
|
throw Error("Required props: route is missing");
|
|
@@ -152,12 +156,7 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
152
156
|
const isScreenActive = useIsScreenActive();
|
|
153
157
|
|
|
154
158
|
return (
|
|
155
|
-
<FreezeWithCallback
|
|
156
|
-
freeze={!isScreenActive}
|
|
157
|
-
onRelease={() => {
|
|
158
|
-
focusManager.setInitialFocus();
|
|
159
|
-
}}
|
|
160
|
-
>
|
|
159
|
+
<FreezeWithCallback freeze={!isScreenActive} onRelease={onRelease}>
|
|
161
160
|
<View style={[styles.container, { backgroundColor }]}>
|
|
162
161
|
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
163
162
|
<NavBar
|
|
@@ -68,21 +68,21 @@ jest.mock(
|
|
|
68
68
|
})
|
|
69
69
|
);
|
|
70
70
|
|
|
71
|
-
jest.mock(
|
|
72
|
-
"@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData",
|
|
73
|
-
() => ({
|
|
74
|
-
useScreenData: jest.fn(() => ({
|
|
75
|
-
id: "testId",
|
|
76
|
-
navigations: [{ id: "testId", category: "nav_bar" }],
|
|
77
|
-
})),
|
|
78
|
-
})
|
|
79
|
-
);
|
|
80
|
-
|
|
81
71
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
82
72
|
isNavBarVisible: mockIsNavBarVisible,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
73
|
+
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
77
|
+
useCurrentScreenData: jest.fn(() => ({
|
|
78
|
+
id: "testId",
|
|
79
|
+
})),
|
|
80
|
+
useNavbarState: jest.fn(() => ({
|
|
81
|
+
title: "Test Title",
|
|
82
|
+
})),
|
|
83
|
+
useScreenData: jest.fn(() => ({
|
|
84
|
+
id: "testId",
|
|
85
|
+
navigations: [{ id: "testId", category: "nav_bar" }],
|
|
86
86
|
})),
|
|
87
87
|
useNavigation: jest.fn(() => ({
|
|
88
88
|
canGoBack: () => false,
|
|
@@ -91,7 +91,15 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
|
91
91
|
screenData: { id: "testId" },
|
|
92
92
|
data: { screen: { id: "testId" } },
|
|
93
93
|
})),
|
|
94
|
-
|
|
94
|
+
useRoute: jest.fn(() => ({
|
|
95
|
+
pathname: "/river/testId",
|
|
96
|
+
screenData: { id: "testId" },
|
|
97
|
+
})),
|
|
98
|
+
useDimensions: jest.fn(() => ({
|
|
99
|
+
width: 1920,
|
|
100
|
+
height: 1080,
|
|
101
|
+
})),
|
|
102
|
+
useIsTablet: jest.fn(() => false),
|
|
95
103
|
}));
|
|
96
104
|
|
|
97
105
|
jest.mock("@applicaster/zapp-react-native-redux/hooks/usePickFromState", () => {
|
|
@@ -16,7 +16,7 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
|
|
|
16
16
|
pathname="/river/testId"
|
|
17
17
|
selected="testId"
|
|
18
18
|
testID="navBar"
|
|
19
|
-
title=""
|
|
19
|
+
title="Test Title"
|
|
20
20
|
/>
|
|
21
21
|
<View>
|
|
22
22
|
<View
|
|
@@ -48,7 +48,7 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
|
|
|
48
48
|
pathname="/river/testId"
|
|
49
49
|
selected="testId"
|
|
50
50
|
testID="navBar"
|
|
51
|
-
title=""
|
|
51
|
+
title="Test Title"
|
|
52
52
|
/>
|
|
53
53
|
<View>
|
|
54
54
|
<View
|