@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1700735421 → 13.0.0-alpha.1711912250
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 +3 -5
- package/Components/AudioPlayer/AudioPlayer.tsx +5 -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 +3 -6
- package/Components/FocusableGroup/index.tsx +0 -1
- 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/ScreenContainer.tsx +0 -1
- 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/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/elementMapper.tsx +2 -1
- package/Components/MasterCell/utils/behaviorProvider.ts +4 -1
- package/Components/MasterCell/utils/index.ts +6 -6
- package/Components/ModalComponent/BottomSheetModalContent.tsx +49 -41
- 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 +34 -7
- package/Components/PlayerImageBackground/index.tsx +4 -24
- package/Components/River/ComponentsMap/ComponentsMap.tsx +15 -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/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/VideoLive/animationUtils.ts +3 -3
- 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 +9 -4
- 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/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
- package/Decorators/RiverResolver/index.tsx +5 -7
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -1
- package/package.json +6 -6
- 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
|
@@ -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 };
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
isApplePlatform,
|
|
10
10
|
isTV,
|
|
11
11
|
platformSelect,
|
|
12
|
+
isAndroidTVPlatform,
|
|
12
13
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
13
14
|
|
|
14
15
|
import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
|
|
@@ -93,6 +94,20 @@ export type PlayNextData = {
|
|
|
93
94
|
|
|
94
95
|
const focusableBottomContainerId = "player-container-bottom";
|
|
95
96
|
|
|
97
|
+
const isAndroidTV = isAndroidTVPlatform();
|
|
98
|
+
|
|
99
|
+
const withBorderHack = () => {
|
|
100
|
+
if (isAndroidTV) {
|
|
101
|
+
/* @HACK: see GH#7269 */
|
|
102
|
+
return {
|
|
103
|
+
borderWidth: 1,
|
|
104
|
+
borderColor: "transparent",
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {};
|
|
109
|
+
};
|
|
110
|
+
|
|
96
111
|
// Styles
|
|
97
112
|
const webStyles = {
|
|
98
113
|
focusableGroup: {
|
|
@@ -335,9 +350,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
335
350
|
|
|
336
351
|
const resumeTime = Number(item?.extensions?.resumeTime);
|
|
337
352
|
|
|
338
|
-
//
|
|
353
|
+
// Сhecking that the player itself knows where to start playing, and there is no need to call seekTo after returning from the Сhromecast
|
|
339
354
|
if (
|
|
340
|
-
|
|
355
|
+
!playerManager.getActivePlayer()?.hasResumePosition() &&
|
|
341
356
|
!isNaN(resumeTime)
|
|
342
357
|
) {
|
|
343
358
|
player?.seekTo(resumeTime);
|
|
@@ -514,6 +529,12 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
514
529
|
useEffect(() => {
|
|
515
530
|
playerEvent("source_changed", { item });
|
|
516
531
|
|
|
532
|
+
return () => {
|
|
533
|
+
playerEvent("player_did_close", { item });
|
|
534
|
+
};
|
|
535
|
+
}, [item?.id, Player]);
|
|
536
|
+
|
|
537
|
+
useEffect(() => {
|
|
517
538
|
if (!isModal) {
|
|
518
539
|
showNavBar(false);
|
|
519
540
|
}
|
|
@@ -523,13 +544,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
523
544
|
}
|
|
524
545
|
|
|
525
546
|
return () => {
|
|
526
|
-
playerEvent("player_did_close", { item });
|
|
527
|
-
|
|
528
547
|
if (!isModal) {
|
|
529
548
|
showNavBar(true);
|
|
530
549
|
}
|
|
531
550
|
};
|
|
532
|
-
}, [showNavBar,
|
|
551
|
+
}, [showNavBar, isModal, Player]);
|
|
533
552
|
|
|
534
553
|
useEffect(() => {
|
|
535
554
|
if (prevItemId && !R.equals(prevItemId, item?.id)) {
|
|
@@ -578,7 +597,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
578
597
|
);
|
|
579
598
|
}
|
|
580
599
|
|
|
581
|
-
if (screen_background_color) {
|
|
600
|
+
if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
|
|
582
601
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
583
602
|
}
|
|
584
603
|
|
|
@@ -596,6 +615,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
596
615
|
tv_component_container_height,
|
|
597
616
|
screen_background_color,
|
|
598
617
|
isInlineTV,
|
|
618
|
+
mode,
|
|
599
619
|
]);
|
|
600
620
|
|
|
601
621
|
const applePlayerProps = {
|
|
@@ -640,7 +660,14 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
640
660
|
testID={"player-screen-container"}
|
|
641
661
|
>
|
|
642
662
|
{/* Player container */}
|
|
643
|
-
<View
|
|
663
|
+
<View
|
|
664
|
+
style={[
|
|
665
|
+
styles.playerWrapper,
|
|
666
|
+
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
667
|
+
withBorderHack(),
|
|
668
|
+
]}
|
|
669
|
+
testID={"player-wrapper"}
|
|
670
|
+
>
|
|
644
671
|
<PlayerFocusableWrapperView
|
|
645
672
|
nextFocusDown={context.bottomFocusableId}
|
|
646
673
|
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { PropsWithChildren
|
|
1
|
+
import React, { PropsWithChildren } from "react";
|
|
2
2
|
import { ImageBackground, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
type Props = PropsWithChildren<{
|
|
13
13
|
entry: ZappEntry;
|
|
14
14
|
style?: { [K: string]: any };
|
|
15
|
-
docked?: boolean;
|
|
16
15
|
imageStyle?: { [K: string]: any };
|
|
17
16
|
imageKey?: string;
|
|
18
17
|
defaultImageDimensions?: { [K: string]: any };
|
|
@@ -24,7 +23,6 @@ const PlayerImageBackgroundComponent = ({
|
|
|
24
23
|
entry,
|
|
25
24
|
children,
|
|
26
25
|
style,
|
|
27
|
-
docked,
|
|
28
26
|
imageStyle,
|
|
29
27
|
imageKey,
|
|
30
28
|
defaultImageDimensions,
|
|
@@ -36,42 +34,24 @@ const PlayerImageBackgroundComponent = ({
|
|
|
36
34
|
|
|
37
35
|
const { playerAnimationState } = useModalAnimationContext();
|
|
38
36
|
|
|
39
|
-
const [lastNonNullAnimationState, setLastNonNullAnimationState] =
|
|
40
|
-
useState(playerAnimationState);
|
|
41
|
-
|
|
42
|
-
useEffect(() => {
|
|
43
|
-
if (playerAnimationState !== null) {
|
|
44
|
-
setLastNonNullAnimationState(playerAnimationState);
|
|
45
|
-
}
|
|
46
|
-
}, [playerAnimationState]);
|
|
47
|
-
|
|
48
37
|
if (!source) return <>{children}</>;
|
|
49
38
|
|
|
50
|
-
const imageBackgroundStyle =
|
|
51
|
-
lastNonNullAnimationState !== PlayerAnimationStateEnum.minimize && !docked
|
|
52
|
-
? defaultImageDimensions
|
|
53
|
-
: imageSize;
|
|
54
|
-
|
|
55
39
|
return (
|
|
56
40
|
<View
|
|
57
41
|
style={
|
|
58
|
-
playerAnimationState === PlayerAnimationStateEnum.
|
|
42
|
+
playerAnimationState === PlayerAnimationStateEnum.maximize
|
|
59
43
|
? defaultImageDimensions
|
|
60
44
|
: style
|
|
61
45
|
}
|
|
62
46
|
>
|
|
63
47
|
<AnimationComponent
|
|
64
|
-
style={
|
|
65
|
-
playerAnimationState === PlayerAnimationStateEnum.maximaze
|
|
66
|
-
? defaultImageDimensions
|
|
67
|
-
: style
|
|
68
|
-
}
|
|
48
|
+
style={style}
|
|
69
49
|
animationType={ComponentAnimationType.player}
|
|
70
50
|
additionalData={defaultImageDimensions}
|
|
71
51
|
>
|
|
72
52
|
<ImageBackground
|
|
73
53
|
resizeMode="cover"
|
|
74
|
-
style={
|
|
54
|
+
style={imageSize}
|
|
75
55
|
imageStyle={imageStyle}
|
|
76
56
|
source={source}
|
|
77
57
|
>
|
|
@@ -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,14 +277,16 @@ 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}
|
|
289
|
+
listKey={riverId}
|
|
282
290
|
keyExtractor={keyExtractor}
|
|
283
291
|
renderItem={renderRiverItem}
|
|
284
292
|
data={riverComponents}
|
|
@@ -295,6 +303,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
295
303
|
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
296
304
|
onScrollEndDrag={_onScrollEndDrag}
|
|
297
305
|
scrollEventThrottle={16}
|
|
306
|
+
maintainVisibleContentPosition={{
|
|
307
|
+
minIndexForVisible: 0,
|
|
308
|
+
autoscrollToTopThreshold: 10,
|
|
309
|
+
}}
|
|
298
310
|
{...scrollViewExtraProps}
|
|
299
311
|
/>
|
|
300
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={
|
|
@@ -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
|
|
@@ -7,15 +7,12 @@ import {
|
|
|
7
7
|
useCurrentScreenData,
|
|
8
8
|
useDimensions,
|
|
9
9
|
useRoute,
|
|
10
|
+
useIsTablet,
|
|
10
11
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
11
12
|
import { useMemo, useEffect, useState } from "react";
|
|
12
13
|
|
|
13
14
|
export const useWaitForValidOrientation = () => {
|
|
14
|
-
const {
|
|
15
|
-
width: screenWidth,
|
|
16
|
-
height,
|
|
17
|
-
deviceInfo,
|
|
18
|
-
} = useDimensions("screen", {
|
|
15
|
+
const { width: screenWidth, height } = useDimensions("screen", {
|
|
19
16
|
fullDimensions: true,
|
|
20
17
|
updateForInactiveScreens: false,
|
|
21
18
|
});
|
|
@@ -26,7 +23,7 @@ export const useWaitForValidOrientation = () => {
|
|
|
26
23
|
|
|
27
24
|
const [readyState, setReadyState] = useState(false);
|
|
28
25
|
|
|
29
|
-
const isTablet =
|
|
26
|
+
const isTablet = useIsTablet();
|
|
30
27
|
|
|
31
28
|
const { appData } = usePickFromState(["appData"]);
|
|
32
29
|
const isTabletPortrait = appData?.isTabletPortrait;
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { View, ViewProps, ViewStyle } from "react-native";
|
|
3
3
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
4
4
|
import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
|
+
import { isFirstComponentScreenPicker } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
5
6
|
|
|
6
7
|
interface IProps {
|
|
7
8
|
targetScreenId?: string;
|
|
@@ -31,11 +32,9 @@ export const useMarginTop = (targetScreenId: string): number => {
|
|
|
31
32
|
* ScreenPicker is a component but should really be a screen.
|
|
32
33
|
* We need to skip margin top for it as it's already applied to the target screen
|
|
33
34
|
**/
|
|
34
|
-
const isScreenPicker =
|
|
35
|
-
screenData?.ui_components?.[0]?.component_type === "screen-picker-qb-tv";
|
|
36
35
|
|
|
37
36
|
// ignore margin on screenPicker
|
|
38
|
-
if (
|
|
37
|
+
if (isFirstComponentScreenPicker(screenData?.ui_components)) {
|
|
39
38
|
return 0;
|
|
40
39
|
}
|
|
41
40
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Animated, Easing, EasingFunction, StyleProp } from "react-native";
|
|
2
2
|
|
|
3
3
|
type AnimatedInterpolatedStyle =
|
|
4
|
-
| Animated.AnimatedInterpolation
|
|
5
|
-
| [{ [Key: string]: Animated.AnimatedInterpolation
|
|
4
|
+
| Animated.AnimatedInterpolation
|
|
5
|
+
| [{ [Key: string]: Animated.AnimatedInterpolation }];
|
|
6
6
|
|
|
7
7
|
type AnimationConfig = {
|
|
8
8
|
duration: number;
|
|
@@ -31,7 +31,7 @@ const interpolate = (
|
|
|
31
31
|
animatedValue: Animated.Value,
|
|
32
32
|
from: number = 0,
|
|
33
33
|
to: number = 1
|
|
34
|
-
): Animated.AnimatedInterpolation
|
|
34
|
+
): Animated.AnimatedInterpolation =>
|
|
35
35
|
animatedValue.interpolate({
|
|
36
36
|
inputRange: [0, 1],
|
|
37
37
|
outputRange: [from, to],
|
|
@@ -46,7 +46,7 @@ export const AnimatedPlayerModalWrapper = (props: Props) => {
|
|
|
46
46
|
|
|
47
47
|
React.useEffect(() => {
|
|
48
48
|
(playerAnimationState === PlayerAnimationStateEnum.minimize ||
|
|
49
|
-
playerAnimationState === PlayerAnimationStateEnum.
|
|
49
|
+
playerAnimationState === PlayerAnimationStateEnum.maximize) &&
|
|
50
50
|
setStartComponentsAnimation(true);
|
|
51
51
|
}, [playerAnimationState]);
|
|
52
52
|
|