@applicaster/zapp-react-native-ui-components 13.0.0-alpha.1486614302 → 13.0.0-alpha.1503493274
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 +0 -11
- package/Components/AudioPlayer/AudioPlayerLayout.tsx +8 -9
- package/Components/AudioPlayer/helpers.tsx +0 -2
- package/Components/CellRendererResolver/index.ts +2 -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/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/ModalComponent/BottomSheetModalContent.tsx +66 -54
- package/Components/ModalComponent/Button/Item.tsx +6 -5
- 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/PlayerContainer/PlayerContainer.tsx +23 -40
- package/Components/River/ComponentsMap/ComponentsMap.tsx +11 -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/__tests__/Screen.test.tsx +22 -14
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +2 -2
- package/Components/TopMarginApplicator/TopMarginApplicator.tsx +2 -3
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +1 -1
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +1 -2
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +9 -1
- package/Components/VideoModal/ModalAnimation/utils.ts +3 -9
- package/Components/VideoModal/PlayerDetails.tsx +9 -4
- package/Components/VideoModal/PlayerWrapper.tsx +9 -19
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +2 -40
- package/Components/VideoModal/utils.ts +1 -1
- package/package.json +5 -5
|
@@ -3,12 +3,10 @@ import { StyleSheet, TouchableOpacity, View } from "react-native";
|
|
|
3
3
|
import { Item, ItemProps } from "./Item";
|
|
4
4
|
import { ItemIcon, ItemIconProps } from "./ItemIcon";
|
|
5
5
|
import { ItemLabel, ItemLabelProps } from "./ItemLabel";
|
|
6
|
-
import * as assets from "./assets";
|
|
7
6
|
import { defaultSelectedAsset } from "./assets";
|
|
8
7
|
|
|
9
8
|
type ButtonProps = {
|
|
10
9
|
configuration: any;
|
|
11
|
-
width: number;
|
|
12
10
|
selectedItem?: any;
|
|
13
11
|
item: any; // Adjust type as needed
|
|
14
12
|
onPress: (item: any) => void; // Adjust type as needed
|
|
@@ -17,6 +15,9 @@ type ButtonProps = {
|
|
|
17
15
|
labelBaseProps?: ItemLabelProps;
|
|
18
16
|
disabled?: boolean;
|
|
19
17
|
label?: string | Record<string, string>;
|
|
18
|
+
iconPlacement?: "left" | "right";
|
|
19
|
+
selectedItemIcon?: ItemIconProps["asset"];
|
|
20
|
+
defaultItemIcon?: ItemIconProps["asset"];
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
const styles = StyleSheet.create({
|
|
@@ -31,81 +32,63 @@ export function Button({
|
|
|
31
32
|
item,
|
|
32
33
|
onPress,
|
|
33
34
|
configuration,
|
|
34
|
-
width,
|
|
35
35
|
iconBaseProps,
|
|
36
|
-
itemBaseProps,
|
|
36
|
+
itemBaseProps: itemProps,
|
|
37
37
|
labelBaseProps,
|
|
38
38
|
label,
|
|
39
|
+
iconPlacement = "left",
|
|
40
|
+
defaultItemIcon,
|
|
41
|
+
selectedItemIcon,
|
|
39
42
|
disabled = false,
|
|
40
43
|
}: ButtonProps) {
|
|
41
44
|
const [focused, setFocused] = useState(false);
|
|
42
45
|
|
|
43
|
-
const selected =
|
|
44
|
-
() => selectedItem && item.value === selectedItem?.value,
|
|
45
|
-
[selectedItem, selectedItem]
|
|
46
|
-
);
|
|
47
|
-
|
|
48
|
-
const itemProps = useMemo<ItemProps>(
|
|
49
|
-
() => ({
|
|
50
|
-
...itemBaseProps,
|
|
51
|
-
width,
|
|
52
|
-
}),
|
|
53
|
-
[configuration, width]
|
|
54
|
-
);
|
|
46
|
+
const selected = selectedItem && item.value === selectedItem?.value;
|
|
55
47
|
|
|
56
|
-
const
|
|
57
|
-
() =>
|
|
58
|
-
|
|
59
|
-
asset: configuration[item.asset] ?? assets[item.asset] ?? item.asset,
|
|
60
|
-
}),
|
|
61
|
-
[configuration, item.asset]
|
|
48
|
+
const itemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
|
|
49
|
+
() => configuration[item.asset] ?? item.asset ?? defaultItemIcon,
|
|
50
|
+
[item.asset, defaultItemIcon]
|
|
62
51
|
);
|
|
63
52
|
|
|
64
|
-
const
|
|
65
|
-
() =>
|
|
66
|
-
|
|
67
|
-
asset:
|
|
68
|
-
configuration["modal_bottom_sheet_item_selected_icon"] ||
|
|
69
|
-
defaultSelectedAsset,
|
|
70
|
-
marginRight: 10,
|
|
71
|
-
}),
|
|
72
|
-
[configuration]
|
|
53
|
+
const selectedItemIconPropsAssets = useMemo<ItemIconProps["asset"]>(
|
|
54
|
+
() => selectedItemIcon || defaultSelectedAsset,
|
|
55
|
+
[selectedItemIcon]
|
|
73
56
|
);
|
|
74
57
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
...
|
|
78
|
-
|
|
79
|
-
}),
|
|
80
|
-
[configuration, item?.label]
|
|
81
|
-
);
|
|
58
|
+
const renderItemIcon =
|
|
59
|
+
itemIconPropsAssets && itemIconPropsAssets.length > 0 ? (
|
|
60
|
+
<ItemIcon {...iconBaseProps} asset={itemIconPropsAssets} />
|
|
61
|
+
) : null;
|
|
82
62
|
|
|
83
63
|
if (disabled) return null;
|
|
84
64
|
|
|
85
65
|
return (
|
|
86
|
-
<
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
>
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
66
|
+
<TouchableOpacity
|
|
67
|
+
activeOpacity={1}
|
|
68
|
+
onPress={() => onPress(item)}
|
|
69
|
+
onPressIn={() => setFocused(true)}
|
|
70
|
+
onPressOut={() => setFocused(false)}
|
|
71
|
+
>
|
|
72
|
+
<Item {...itemProps} focused={focused} selected={selected}>
|
|
73
|
+
<View style={styles.label_icon_container}>
|
|
74
|
+
{iconPlacement === "left" && renderItemIcon}
|
|
75
|
+
|
|
76
|
+
{label ? (
|
|
77
|
+
<ItemLabel
|
|
78
|
+
{...labelBaseProps}
|
|
79
|
+
label={label ?? null}
|
|
80
|
+
focused={focused}
|
|
81
|
+
selected={selected}
|
|
82
|
+
/>
|
|
83
|
+
) : null}
|
|
84
|
+
</View>
|
|
85
|
+
|
|
86
|
+
{selected ? (
|
|
87
|
+
<ItemIcon {...iconBaseProps} asset={selectedItemIconPropsAssets} />
|
|
88
|
+
) : (
|
|
89
|
+
iconPlacement === "right" && renderItemIcon
|
|
90
|
+
)}
|
|
91
|
+
</Item>
|
|
92
|
+
</TouchableOpacity>
|
|
110
93
|
);
|
|
111
94
|
}
|
|
@@ -8,13 +8,18 @@ import { PluginConfiguration } from "../index";
|
|
|
8
8
|
type Props = {
|
|
9
9
|
dismiss: () => void;
|
|
10
10
|
configuration: PluginConfiguration;
|
|
11
|
-
width: number;
|
|
12
11
|
onLayout?: (event: LayoutChangeEvent) => void;
|
|
13
12
|
summary?: string;
|
|
14
13
|
title?: string;
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
const styles = StyleSheet.create({
|
|
17
|
+
noFlex: {
|
|
18
|
+
flex: 0,
|
|
19
|
+
},
|
|
20
|
+
flex: {
|
|
21
|
+
flex: 1,
|
|
22
|
+
},
|
|
18
23
|
container: {
|
|
19
24
|
flexDirection: "row",
|
|
20
25
|
alignItems: "center",
|
|
@@ -22,7 +27,7 @@ const styles = StyleSheet.create({
|
|
|
22
27
|
});
|
|
23
28
|
|
|
24
29
|
export function ModalHeader(props: Props) {
|
|
25
|
-
const { configuration, dismiss,
|
|
30
|
+
const { configuration, dismiss, onLayout, summary, title } = props;
|
|
26
31
|
|
|
27
32
|
const closeButtonProps = useMemo<CloseButtonProps>(
|
|
28
33
|
() => ({
|
|
@@ -55,15 +60,11 @@ export function ModalHeader(props: Props) {
|
|
|
55
60
|
|
|
56
61
|
return (
|
|
57
62
|
<View onLayout={onLayout} style={styles.container}>
|
|
58
|
-
<View
|
|
59
|
-
style={{
|
|
60
|
-
width: width - buttonsContainerWidth,
|
|
61
|
-
}}
|
|
62
|
-
>
|
|
63
|
+
<View style={styles.flex}>
|
|
63
64
|
{title ? <Title {...titleProps} /> : null}
|
|
64
65
|
{summary ? <Title {...summaryProps} /> : null}
|
|
65
66
|
</View>
|
|
66
|
-
<View style={{ width: buttonsContainerWidth }}>
|
|
67
|
+
<View style={[styles.noFlex, { width: buttonsContainerWidth }]}>
|
|
67
68
|
<CloseButton {...closeButtonProps} />
|
|
68
69
|
</View>
|
|
69
70
|
</View>
|
|
@@ -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
|
+
}
|
|
@@ -6,11 +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,
|
|
12
11
|
isAndroidTVPlatform,
|
|
12
|
+
isTvOSPlatform,
|
|
13
13
|
} from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
14
|
+
import {
|
|
15
|
+
isAudioItem,
|
|
16
|
+
isInlineTV as isInlineTVUtil,
|
|
17
|
+
} from "@applicaster/zapp-react-native-utils/playerUtils";
|
|
14
18
|
|
|
15
19
|
import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
|
|
16
20
|
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
@@ -21,7 +25,7 @@ import {
|
|
|
21
25
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
22
26
|
|
|
23
27
|
import { PlayerStateContext } from "../../Contexts/PlayerStateContext";
|
|
24
|
-
|
|
28
|
+
|
|
25
29
|
import {
|
|
26
30
|
QUICK_BRICK_EVENTS,
|
|
27
31
|
QuickBrickEvent,
|
|
@@ -96,6 +100,11 @@ const focusableBottomContainerId = "player-container-bottom";
|
|
|
96
100
|
|
|
97
101
|
const isAndroidTV = isAndroidTVPlatform();
|
|
98
102
|
|
|
103
|
+
const isTvOS = isTvOSPlatform();
|
|
104
|
+
|
|
105
|
+
// height for container with additional content below player
|
|
106
|
+
const INLINE_CONTAINER_CONTENT_HEIGHT = 400;
|
|
107
|
+
|
|
99
108
|
const withBorderHack = () => {
|
|
100
109
|
if (isAndroidTV) {
|
|
101
110
|
/* @HACK: see GH#7269 */
|
|
@@ -125,7 +134,7 @@ const webStyles = {
|
|
|
125
134
|
flex: "initial",
|
|
126
135
|
},
|
|
127
136
|
inlineRiver: {
|
|
128
|
-
height:
|
|
137
|
+
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
129
138
|
},
|
|
130
139
|
};
|
|
131
140
|
|
|
@@ -143,7 +152,7 @@ const nativeStyles = {
|
|
|
143
152
|
flex: 1,
|
|
144
153
|
},
|
|
145
154
|
inlineRiver: {
|
|
146
|
-
height:
|
|
155
|
+
height: INLINE_CONTAINER_CONTENT_HEIGHT,
|
|
147
156
|
},
|
|
148
157
|
};
|
|
149
158
|
|
|
@@ -163,12 +172,11 @@ const renderApplePlayer = ({
|
|
|
163
172
|
videoStyle,
|
|
164
173
|
playNextData,
|
|
165
174
|
}) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
if (!isAppleTV() || !player) {
|
|
175
|
+
if (!isTvOS || !player) {
|
|
169
176
|
return null;
|
|
170
177
|
}
|
|
171
178
|
|
|
179
|
+
// render audio_player for tvos
|
|
172
180
|
if (isAudioContent) {
|
|
173
181
|
return (
|
|
174
182
|
<AudioPlayer
|
|
@@ -182,6 +190,8 @@ const renderApplePlayer = ({
|
|
|
182
190
|
return null;
|
|
183
191
|
}
|
|
184
192
|
|
|
193
|
+
const { title, summary } = item || {};
|
|
194
|
+
|
|
185
195
|
return (
|
|
186
196
|
<ProgramInfo
|
|
187
197
|
title={title}
|
|
@@ -192,21 +202,6 @@ const renderApplePlayer = ({
|
|
|
192
202
|
);
|
|
193
203
|
};
|
|
194
204
|
|
|
195
|
-
const renderRestPlayers = ({ item, showAudioPlayer, pluginConfiguration }) => {
|
|
196
|
-
if (isApplePlatform()) {
|
|
197
|
-
return null;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return (
|
|
201
|
-
showAudioPlayer && (
|
|
202
|
-
<AudioPlayer
|
|
203
|
-
audio_item={item}
|
|
204
|
-
plugin_configuration={pluginConfiguration}
|
|
205
|
-
/>
|
|
206
|
-
)
|
|
207
|
-
);
|
|
208
|
-
};
|
|
209
|
-
|
|
210
205
|
const PlayerContainerComponent = (props: Props) => {
|
|
211
206
|
const {
|
|
212
207
|
Player,
|
|
@@ -336,7 +331,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
336
331
|
|
|
337
332
|
setState({ error: errorObj });
|
|
338
333
|
|
|
339
|
-
if (!
|
|
334
|
+
if (!isTvOS) {
|
|
340
335
|
setTimeout(() => {
|
|
341
336
|
close();
|
|
342
337
|
}, 800);
|
|
@@ -493,9 +488,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
493
488
|
// TODO: Skip hook call on TV platform
|
|
494
489
|
useBackHandler(backHandler);
|
|
495
490
|
|
|
496
|
-
const isAudioContent =
|
|
497
|
-
typeof item?.content?.type === "string" &&
|
|
498
|
-
item?.content?.type.includes("audio");
|
|
491
|
+
const isAudioContent = isAudioItem(item);
|
|
499
492
|
|
|
500
493
|
useEffect(() => {
|
|
501
494
|
if (!isAudioContent) {
|
|
@@ -569,10 +562,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
569
562
|
|
|
570
563
|
const uri = item?.content ? item.content?.src : null;
|
|
571
564
|
|
|
572
|
-
const isInlineTV =
|
|
573
|
-
screenData?.ui_components &&
|
|
574
|
-
screenData?.ui_components?.length > 0 &&
|
|
575
|
-
isTV();
|
|
565
|
+
const isInlineTV = isInlineTVUtil(screenData);
|
|
576
566
|
|
|
577
567
|
const inline =
|
|
578
568
|
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(mode) ||
|
|
@@ -597,7 +587,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
597
587
|
);
|
|
598
588
|
}
|
|
599
589
|
|
|
600
|
-
if (screen_background_color) {
|
|
590
|
+
if (screen_background_color && mode !== VideoModalMode.FULLSCREEN) {
|
|
601
591
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
602
592
|
}
|
|
603
593
|
|
|
@@ -615,6 +605,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
615
605
|
tv_component_container_height,
|
|
616
606
|
screen_background_color,
|
|
617
607
|
isInlineTV,
|
|
608
|
+
mode,
|
|
618
609
|
]);
|
|
619
610
|
|
|
620
611
|
const applePlayerProps = {
|
|
@@ -626,12 +617,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
626
617
|
playNextData,
|
|
627
618
|
};
|
|
628
619
|
|
|
629
|
-
const restPlayerProps = {
|
|
630
|
-
item,
|
|
631
|
-
showAudioPlayer: isAudioContent,
|
|
632
|
-
pluginConfiguration,
|
|
633
|
-
};
|
|
634
|
-
|
|
635
620
|
return (
|
|
636
621
|
<PlayerStateContext.Provider value={value}>
|
|
637
622
|
<PlayerContainerContextProvider
|
|
@@ -707,8 +692,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
707
692
|
</Player>
|
|
708
693
|
</PlayerFocusableWrapperView>
|
|
709
694
|
|
|
710
|
-
{renderRestPlayers(restPlayerProps)}
|
|
711
|
-
|
|
712
695
|
{state.error ? <ErrorDisplay error={state.error} /> : null}
|
|
713
696
|
</View>
|
|
714
697
|
{/* Components container */}
|
|
@@ -732,7 +715,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
732
715
|
screenId={screenData.id}
|
|
733
716
|
key={item.id}
|
|
734
717
|
groupId={FocusableGroupMainContainerId}
|
|
735
|
-
cellTapAction={
|
|
718
|
+
cellTapAction={onCellTap}
|
|
736
719
|
extraAnchorPointYOffset={-600}
|
|
737
720
|
isScreenWrappedInContainer={true}
|
|
738
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;
|
|
@@ -273,12 +277,12 @@ function ComponentsMapComponent(props: Props) {
|
|
|
273
277
|
}}
|
|
274
278
|
// Fix for WebView rerender crashes on Android API 28+
|
|
275
279
|
// https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
|
|
276
|
-
overScrollMode={
|
|
280
|
+
overScrollMode={isAndroid ? "never" : "auto"}
|
|
277
281
|
scrollIndicatorInsets={scrollIndicatorInsets}
|
|
278
282
|
extraData={feed}
|
|
279
283
|
stickyHeaderIndices={stickyHeaderIndices}
|
|
280
284
|
onLayout={handleOnLayout}
|
|
281
|
-
removeClippedSubviews
|
|
285
|
+
removeClippedSubviews={isAndroid}
|
|
282
286
|
initialNumToRender={3}
|
|
283
287
|
maxToRenderPerBatch={10}
|
|
284
288
|
windowSize={12}
|
|
@@ -299,6 +303,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
299
303
|
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
300
304
|
onScrollEndDrag={_onScrollEndDrag}
|
|
301
305
|
scrollEventThrottle={16}
|
|
306
|
+
maintainVisibleContentPosition={{
|
|
307
|
+
minIndexForVisible: 0,
|
|
308
|
+
autoscrollToTopThreshold: 10,
|
|
309
|
+
}}
|
|
302
310
|
{...scrollViewExtraProps}
|
|
303
311
|
/>
|
|
304
312
|
</ViewportTracker>
|
|
@@ -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
|
+
});
|
|
@@ -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", () => {
|