@applicaster/zapp-react-native-ui-components 12.0.0-alpha.5227180498 → 12.0.0-alpha.5347482137
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/BaseFocusable/index.tsx +3 -3
- package/Components/Cell/Cell.tsx +5 -5
- package/Components/Cell/CellWithFocusable.tsx +23 -9
- package/Components/Cell/TvOSCellComponent.tsx +3 -7
- package/Components/Focusable/Focusable.tsx +6 -1
- package/Components/FocusableGroup/index.tsx +11 -2
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +19 -75
- package/Components/Layout/TV/index.tsx +12 -11
- package/Components/Layout/TV/index.web.tsx +33 -0
- package/Components/Layout/index.tsx +15 -11
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +88 -112
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +10 -2
- package/Components/MasterCell/utils/__tests__/insertBetween.test.js +9 -0
- package/Components/MasterCell/utils/index.ts +17 -30
- package/Components/Navigator/StackNavigator.tsx +54 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +8 -1
- package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -0
- package/Components/River/RefreshControl.tsx +2 -2
- package/Components/River/TV/River.tsx +0 -23
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +186 -0
- package/Components/Screen/__tests__/Screen.test.tsx +3 -0
- package/Components/Screen/index.tsx +29 -1
- package/Components/ScreenResolver/index.tsx +3 -1
- package/Components/Transitioner/Scene.tsx +24 -19
- package/Components/Transitioner/Transitioner.tsx +21 -28
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +28 -1
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +48 -38
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +40 -33
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +98 -81
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +13 -5
- package/Components/VideoModal/ModalAnimation/utils.ts +6 -4
- package/Components/VideoModal/PlayerDetails.tsx +3 -3
- package/Components/VideoModal/PlayerWrapper.tsx +67 -60
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +32 -12
- package/Components/VideoModal/utils.ts +5 -2
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Contexts/FocusableGroupContext/FocusableGroupContext.ts +3 -0
- package/Contexts/FocusableGroupContext/FocusableGroupContextProvider.tsx +16 -0
- package/Contexts/FocusableGroupContext/__tests__/FocusableGroupContextProvider.test.tsx +22 -0
- package/Contexts/FocusableGroupContext/__tests__/withFocusableContext.test.tsx +26 -0
- package/Contexts/FocusableGroupContext/index.ts +7 -0
- package/Contexts/FocusableGroupContext/withFocusableContext.tsx +17 -0
- package/Contexts/ScreenDataContext/index.tsx +20 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
- /package/Components/FocusableGroup/{index.android.js → index.android.ts} +0 -0
- /package/Components/FocusableGroup/{index.ios.js → index.ios.ts} +0 -0
|
@@ -7,50 +7,28 @@ type BorderPosition = "inside" | "outside" | "center";
|
|
|
7
7
|
interface Props {
|
|
8
8
|
style: ImageStyle | ViewStyle;
|
|
9
9
|
borderPosition: BorderPosition;
|
|
10
|
+
borderPaddingTop: number;
|
|
11
|
+
borderPaddingRight: number;
|
|
12
|
+
borderPaddingBottom: number;
|
|
13
|
+
borderPaddingLeft: number;
|
|
10
14
|
children: React.ReactNode;
|
|
11
15
|
}
|
|
12
16
|
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
if (typeof value === "string" && value.endsWith("%")) {
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return false;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
const calculateContainerSpacing = ({
|
|
36
|
-
spacingKey,
|
|
37
|
-
style,
|
|
38
|
-
additionalSpacing,
|
|
39
|
-
}: {
|
|
40
|
-
spacingKey: typeof MARGINS[number] | typeof PADDINGS[number];
|
|
41
|
-
style: ImageStyle | ViewStyle;
|
|
42
|
-
additionalSpacing: number;
|
|
43
|
-
}) => {
|
|
44
|
-
return {
|
|
45
|
-
[spacingKey]:
|
|
46
|
-
toNumberWithDefaultZero(style[spacingKey]) + additionalSpacing,
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const getContainerBorderWidth = (
|
|
51
|
-
borderPosition: BorderPosition,
|
|
52
|
-
borderWidth
|
|
53
|
-
) => {
|
|
17
|
+
const COLOR_TRANSPARENT = "transparent";
|
|
18
|
+
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
overflow: "visible",
|
|
22
|
+
borderWidth: 0,
|
|
23
|
+
borderColor: COLOR_TRANSPARENT,
|
|
24
|
+
},
|
|
25
|
+
border: {
|
|
26
|
+
...StyleSheet.absoluteFillObject,
|
|
27
|
+
zIndex: 1,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
|
|
54
32
|
switch (borderPosition) {
|
|
55
33
|
case "inside":
|
|
56
34
|
return 0;
|
|
@@ -63,104 +41,102 @@ const getContainerBorderWidth = (
|
|
|
63
41
|
}
|
|
64
42
|
};
|
|
65
43
|
|
|
66
|
-
const
|
|
67
|
-
switch (borderPosition) {
|
|
68
|
-
case "inside":
|
|
69
|
-
return borderWidth;
|
|
70
|
-
case "center":
|
|
71
|
-
return borderWidth / 2;
|
|
72
|
-
case "outside":
|
|
73
|
-
return 0;
|
|
74
|
-
default:
|
|
75
|
-
return 0;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
const InsideBorder = ({
|
|
44
|
+
const Border = ({
|
|
80
45
|
style,
|
|
46
|
+
padding,
|
|
81
47
|
borderPosition,
|
|
82
48
|
}: {
|
|
83
49
|
style: ViewStyle;
|
|
50
|
+
padding: ViewStyle;
|
|
84
51
|
borderPosition: BorderPosition;
|
|
85
52
|
}) => {
|
|
86
|
-
if (borderPosition
|
|
53
|
+
if (!borderPosition) {
|
|
87
54
|
return null;
|
|
88
55
|
}
|
|
89
56
|
|
|
90
|
-
const
|
|
91
|
-
|
|
57
|
+
const borderWidth = toNumberWithDefaultZero(style.borderWidth);
|
|
58
|
+
const containerPadding = getBorderPadding(borderPosition, borderWidth);
|
|
59
|
+
|
|
60
|
+
const initialBorderRadius = toNumberWithDefaultZero(style.borderRadius);
|
|
61
|
+
const paddingTop = toNumberWithDefaultZero(padding.paddingTop);
|
|
62
|
+
const paddingRight = toNumberWithDefaultZero(padding.paddingRight);
|
|
63
|
+
const paddingBottom = toNumberWithDefaultZero(padding.paddingBottom);
|
|
64
|
+
const paddingLeft = toNumberWithDefaultZero(padding.paddingLeft);
|
|
65
|
+
|
|
66
|
+
const borderRadiusStyle = initialBorderRadius
|
|
67
|
+
? {
|
|
68
|
+
borderTopLeftRadius:
|
|
69
|
+
initialBorderRadius +
|
|
70
|
+
containerPadding +
|
|
71
|
+
Math.min(paddingTop, paddingLeft),
|
|
72
|
+
borderTopRightRadius:
|
|
73
|
+
initialBorderRadius +
|
|
74
|
+
containerPadding +
|
|
75
|
+
Math.min(paddingTop, paddingRight),
|
|
76
|
+
borderBottomLeftRadius:
|
|
77
|
+
initialBorderRadius +
|
|
78
|
+
containerPadding +
|
|
79
|
+
Math.min(paddingBottom, paddingLeft),
|
|
80
|
+
borderBottomRightRadius:
|
|
81
|
+
initialBorderRadius +
|
|
82
|
+
containerPadding +
|
|
83
|
+
Math.min(paddingBottom, paddingRight),
|
|
84
|
+
}
|
|
85
|
+
: {
|
|
86
|
+
borderTopLeftRadius: 0,
|
|
87
|
+
borderTopRightRadius: 0,
|
|
88
|
+
borderBottomLeftRadius: 0,
|
|
89
|
+
borderBottomRightRadius: 0,
|
|
90
|
+
};
|
|
92
91
|
|
|
93
92
|
return (
|
|
94
93
|
<View
|
|
94
|
+
pointerEvents="none"
|
|
95
95
|
style={{
|
|
96
|
-
...
|
|
97
|
-
|
|
96
|
+
...styles.border,
|
|
97
|
+
right: -containerPadding - paddingRight,
|
|
98
|
+
bottom: -containerPadding - paddingBottom,
|
|
99
|
+
left: -containerPadding - paddingLeft,
|
|
100
|
+
top: -containerPadding - paddingTop,
|
|
101
|
+
borderWidth,
|
|
98
102
|
borderColor: style.borderColor,
|
|
99
|
-
|
|
103
|
+
...borderRadiusStyle,
|
|
100
104
|
}}
|
|
101
105
|
/>
|
|
102
106
|
);
|
|
103
107
|
};
|
|
104
108
|
|
|
105
109
|
export const BorderContainerView = (props: Props) => {
|
|
106
|
-
const {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
const {
|
|
111
|
+
borderPosition,
|
|
112
|
+
borderPaddingTop,
|
|
113
|
+
borderPaddingRight,
|
|
114
|
+
borderPaddingBottom,
|
|
115
|
+
borderPaddingLeft,
|
|
116
|
+
style,
|
|
117
|
+
children,
|
|
118
|
+
} = props;
|
|
112
119
|
|
|
113
120
|
const borderStyleForMissingBorder =
|
|
114
121
|
style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
|
|
115
122
|
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const updatedPaddings = PADDINGS.reduce((acc, padding) => {
|
|
127
|
-
const paddingValue = calculateContainerSpacing({
|
|
128
|
-
spacingKey: padding,
|
|
129
|
-
style,
|
|
130
|
-
additionalSpacing: spacing,
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
return { ...acc, ...paddingValue };
|
|
134
|
-
}, {});
|
|
135
|
-
|
|
136
|
-
const updatedWidth = style.width
|
|
137
|
-
? isPercentageValue(style.width)
|
|
138
|
-
? style.width
|
|
139
|
-
: toNumberWithDefaultZero(style.width) - spacing * 2
|
|
140
|
-
: undefined;
|
|
141
|
-
|
|
142
|
-
const updatedHeight = style.height
|
|
143
|
-
? isPercentageValue(style.height)
|
|
144
|
-
? style.height
|
|
145
|
-
: toNumberWithDefaultZero(style.height) - spacing * 2
|
|
146
|
-
: undefined;
|
|
147
|
-
|
|
148
|
-
const containerStyle = {
|
|
149
|
-
borderWidth: getContainerBorderWidth(borderPosition, borderWidth),
|
|
150
|
-
padding: spacing,
|
|
151
|
-
...updatedMargins,
|
|
152
|
-
...updatedPaddings,
|
|
153
|
-
width: updatedWidth,
|
|
154
|
-
height: updatedHeight,
|
|
155
|
-
};
|
|
123
|
+
const padding =
|
|
124
|
+
borderPosition === "outside"
|
|
125
|
+
? {
|
|
126
|
+
paddingTop: borderPaddingTop,
|
|
127
|
+
paddingRight: borderPaddingRight,
|
|
128
|
+
paddingBottom: borderPaddingBottom,
|
|
129
|
+
paddingLeft: borderPaddingLeft,
|
|
130
|
+
}
|
|
131
|
+
: {};
|
|
156
132
|
|
|
157
133
|
return (
|
|
158
|
-
<View
|
|
134
|
+
<View
|
|
135
|
+
{...props}
|
|
136
|
+
style={[style, styles.container, borderStyleForMissingBorder]}
|
|
137
|
+
>
|
|
138
|
+
<Border style={style} padding={padding} borderPosition={borderPosition} />
|
|
159
139
|
{children}
|
|
160
|
-
<InsideBorder
|
|
161
|
-
style={{ ...style, ...borderStyleForMissingBorder }}
|
|
162
|
-
borderPosition={borderPosition}
|
|
163
|
-
/>
|
|
164
140
|
</View>
|
|
165
141
|
);
|
|
166
142
|
};
|
|
@@ -4,6 +4,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
|
|
|
4
4
|
|
|
5
5
|
type DynamicBadgeProps = {
|
|
6
6
|
cellUUID?: string;
|
|
7
|
+
uri?: string;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
|
|
@@ -12,11 +13,12 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
|
|
|
12
13
|
// TODO: Initial value should depends on player state (playing or not)
|
|
13
14
|
const [showImage, setShowImage] = React.useState(true);
|
|
14
15
|
const player = usePlayer(playerId);
|
|
16
|
+
const uri = props?.uri;
|
|
15
17
|
|
|
16
18
|
React.useEffect(() => {
|
|
17
19
|
if (playerId && player) {
|
|
18
20
|
return player.addListener({
|
|
19
|
-
id:
|
|
21
|
+
id: `dynamic-badges-${uri}`,
|
|
20
22
|
listener: {
|
|
21
23
|
onPlayerClose: () => {
|
|
22
24
|
setShowImage(true);
|
|
@@ -35,7 +37,7 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
|
|
|
35
37
|
} else {
|
|
36
38
|
setShowImage(true);
|
|
37
39
|
}
|
|
38
|
-
}, [player]);
|
|
40
|
+
}, [player, uri]);
|
|
39
41
|
|
|
40
42
|
if (!showImage) {
|
|
41
43
|
return null;
|
|
@@ -4,6 +4,7 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
|
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
7
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
8
|
|
|
8
9
|
const { Logger } = getXray();
|
|
9
10
|
|
|
@@ -35,7 +36,9 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
35
36
|
|
|
36
37
|
const focusableId = getFocusableId(prefixId, suffixId);
|
|
37
38
|
|
|
38
|
-
const focused =
|
|
39
|
+
const focused =
|
|
40
|
+
focusableId === focusedButtonId ||
|
|
41
|
+
toBooleanWithDefaultFalse(otherProps.focused);
|
|
39
42
|
|
|
40
43
|
const additionalStyles = focused ? focusedStyles : normalStyles;
|
|
41
44
|
|
|
@@ -61,7 +61,10 @@ export function ButtonContainerView({
|
|
|
61
61
|
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
62
62
|
{insertBetween(
|
|
63
63
|
(index) => (
|
|
64
|
-
<HorizontalSeparator
|
|
64
|
+
<HorizontalSeparator
|
|
65
|
+
key={`separator_${index}`}
|
|
66
|
+
width={horizontalGutter}
|
|
67
|
+
/>
|
|
65
68
|
),
|
|
66
69
|
cloneElementsWithIds(buttonIds, filteredChildren)
|
|
67
70
|
)}
|
|
@@ -7,6 +7,10 @@ import type {
|
|
|
7
7
|
ContainerProps,
|
|
8
8
|
ContainerChildren,
|
|
9
9
|
} from "./types";
|
|
10
|
+
import {
|
|
11
|
+
useIsRTL,
|
|
12
|
+
applyRTLStylesIfNeeded,
|
|
13
|
+
} from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
10
14
|
|
|
11
15
|
const HorizontalSeparator = ({ width }: HorizontalSeparatorProps) => (
|
|
12
16
|
<View style={{ width }} />
|
|
@@ -17,6 +21,7 @@ export function ButtonContainerView({
|
|
|
17
21
|
children,
|
|
18
22
|
...otherProps
|
|
19
23
|
}: ContainerProps) {
|
|
24
|
+
const isRTL = useIsRTL();
|
|
20
25
|
const horizontalGutter = R.pathOr(0, ["horizontalGutter"], otherProps);
|
|
21
26
|
|
|
22
27
|
const filteredChildren = useFilterChildren<ContainerChildren>(children);
|
|
@@ -26,10 +31,13 @@ export function ButtonContainerView({
|
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
return (
|
|
29
|
-
<View style={style}>
|
|
34
|
+
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
30
35
|
{insertBetween(
|
|
31
36
|
(index) => (
|
|
32
|
-
<HorizontalSeparator
|
|
37
|
+
<HorizontalSeparator
|
|
38
|
+
key={`separator_${index}`}
|
|
39
|
+
width={horizontalGutter}
|
|
40
|
+
/>
|
|
33
41
|
),
|
|
34
42
|
filteredChildren
|
|
35
43
|
)}
|
|
@@ -9,4 +9,13 @@ describe("insertBetween", () => {
|
|
|
9
9
|
|
|
10
10
|
expect(result).toEqual([1, "|", 2, "|", 3]);
|
|
11
11
|
});
|
|
12
|
+
|
|
13
|
+
it("insertBetween", () => {
|
|
14
|
+
const separator = (index) => `separator:${index}`;
|
|
15
|
+
const items = [1, 2, 3];
|
|
16
|
+
|
|
17
|
+
const result = insertBetween(separator, items);
|
|
18
|
+
|
|
19
|
+
expect(result).toEqual([1, "separator:0", 2, "separator:1", 3]);
|
|
20
|
+
});
|
|
12
21
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { useEffect, useMemo } from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
+
import validateColor from "validate-color";
|
|
3
4
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
5
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
6
|
|
|
@@ -9,6 +10,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
|
|
|
9
10
|
import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
|
|
10
11
|
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
11
12
|
import { getCellState } from "../../Cell/utils";
|
|
13
|
+
import { getColorFromData } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
12
14
|
|
|
13
15
|
const hasElementSpecificViewType = (viewType) => (element) => {
|
|
14
16
|
if (R.isNil(element)) {
|
|
@@ -47,44 +49,29 @@ export const hasElementsSpecificViewType = (viewType) => (elements) => {
|
|
|
47
49
|
return R.any(hasElementSpecificViewType(viewType))(elements);
|
|
48
50
|
};
|
|
49
51
|
|
|
50
|
-
const isColorOrEmpty = (value) =>
|
|
51
|
-
value === null ||
|
|
52
|
-
value === undefined ||
|
|
53
|
-
value === "" ||
|
|
54
|
-
value.startsWith("#") ||
|
|
55
|
-
value.startsWith("rgba") ||
|
|
56
|
-
value === "transparent";
|
|
57
|
-
|
|
58
52
|
function resolveColorForProp(entry, style, colorProp) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
const colorFromProp = style[colorProp];
|
|
54
|
+
const nestedEntryValue = R.path(colorFromProp.split("."), entry);
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
nestedEntryValue === undefined &&
|
|
58
|
+
!validateColor(colorFromProp.replace(".00", "")) // https://github.com/dreamyguy/validate-color/issues/44
|
|
59
|
+
) {
|
|
60
|
+
logWarning(colorFromProp, style, entry, nestedEntryValue);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (nestedEntryValue === null || typeof nestedEntryValue !== "object") {
|
|
70
|
-
logWarning(colorValue, style, entry, nestedEntryValue);
|
|
71
|
-
|
|
72
|
-
return style;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
nestedEntryValue = nestedEntryValue[part];
|
|
76
|
-
}
|
|
63
|
+
const colorValue = getColorFromData({
|
|
64
|
+
data: entry,
|
|
65
|
+
valueFromLayout: colorFromProp,
|
|
66
|
+
});
|
|
77
67
|
|
|
78
|
-
if (
|
|
79
|
-
logWarning(
|
|
68
|
+
if (!colorValue) {
|
|
69
|
+
logWarning(colorProp, style, entry, colorValue);
|
|
80
70
|
|
|
81
71
|
return style;
|
|
82
72
|
}
|
|
83
73
|
|
|
84
|
-
|
|
85
|
-
style[colorProp] = nestedEntryValue;
|
|
86
|
-
|
|
87
|
-
return style;
|
|
74
|
+
return { ...style, [colorProp]: colorValue };
|
|
88
75
|
}
|
|
89
76
|
|
|
90
77
|
export function resolveColor(entry, style) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { isEmpty } from "ramda";
|
|
3
|
+
|
|
4
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
+
import { getPathAttributes } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
6
|
+
import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
|
|
7
|
+
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
8
|
+
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
9
|
+
|
|
10
|
+
import { Screen } from "../Screen/TV/index.web";
|
|
11
|
+
import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
12
|
+
|
|
13
|
+
type Components = {
|
|
14
|
+
NavBar: React.ComponentType<any>;
|
|
15
|
+
Background: React.ComponentType<any>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type Props = {
|
|
19
|
+
Components: Components;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const StackNavigator = ({ Components }: Props) => {
|
|
23
|
+
const { mainStack } = useNavigation();
|
|
24
|
+
|
|
25
|
+
const renderScreen = ({ route, state }, index) => {
|
|
26
|
+
const pathAttributes = getPathAttributes({ pathname: route });
|
|
27
|
+
|
|
28
|
+
if (isEmpty(pathAttributes)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// HACK: Adding index to route to avoid conflicts in the navigator.
|
|
33
|
+
// Startup hooks are all using PUSH navigation action to navigate, but their routes are always like root routes.
|
|
34
|
+
// This means some hooks can have the same routes, e.g., ["hooks/context-setter", "/hooks/login-plug", "hooks/context-setter"].
|
|
35
|
+
const routeId = `${route}--${index}`;
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<FocusableGroup
|
|
39
|
+
id={route}
|
|
40
|
+
preferredFocus={isLast(index, mainStack.length)}
|
|
41
|
+
excludeFromFocusSearching
|
|
42
|
+
key={routeId}
|
|
43
|
+
>
|
|
44
|
+
<ScreenDataContext.Provider value={state}>
|
|
45
|
+
<PathnameContext.Provider value={route}>
|
|
46
|
+
<Screen route={route} Components={Components} />
|
|
47
|
+
</PathnameContext.Provider>
|
|
48
|
+
</ScreenDataContext.Provider>
|
|
49
|
+
</FocusableGroup>
|
|
50
|
+
);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return <>{mainStack.map(renderScreen)}</>;
|
|
54
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { StackNavigator } from "./StackNavigator";
|
|
@@ -68,6 +68,7 @@ type Props = {
|
|
|
68
68
|
mode?: VideoModalMode;
|
|
69
69
|
loadPipesData: (url: string, options: {}) => void;
|
|
70
70
|
disableCastAction?: boolean;
|
|
71
|
+
groupId?: string;
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
type ScreenStyles = ZappRiver["styles"] & {
|
|
@@ -200,6 +201,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
200
201
|
style: videoStyle,
|
|
201
202
|
mode = VideoModalMode.MAXIMIZED,
|
|
202
203
|
disableCastAction = false,
|
|
204
|
+
groupId,
|
|
203
205
|
} = props;
|
|
204
206
|
|
|
205
207
|
// Hooks
|
|
@@ -249,8 +251,12 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
249
251
|
return;
|
|
250
252
|
}
|
|
251
253
|
|
|
252
|
-
navigator.goBack();
|
|
253
254
|
showNavBar(true);
|
|
255
|
+
|
|
256
|
+
// Hack to close player screen on mobile only (tv handles that in InteractionManager)
|
|
257
|
+
if (!isTV()) {
|
|
258
|
+
navigator.goBack();
|
|
259
|
+
}
|
|
254
260
|
}, [isModal, navigator.goBack, showNavBar]);
|
|
255
261
|
|
|
256
262
|
const playEntry = (entry) => navigator.replaceTop(entry, { mode });
|
|
@@ -629,6 +635,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
629
635
|
style={styles.focusableGroup}
|
|
630
636
|
preferredFocus
|
|
631
637
|
shouldUsePreferredFocus
|
|
638
|
+
groupId={groupId}
|
|
632
639
|
>
|
|
633
640
|
{/* Video player and components */}
|
|
634
641
|
<View
|
|
@@ -271,6 +271,12 @@ function ComponentsMapComponent(props: Props) {
|
|
|
271
271
|
|
|
272
272
|
if (y >= 0 && y + height <= contentHeight) {
|
|
273
273
|
scrollY.setValue(y);
|
|
274
|
+
} else {
|
|
275
|
+
if (y <= 0) {
|
|
276
|
+
scrollY.setValue(0);
|
|
277
|
+
} else if (y + height > contentHeight) {
|
|
278
|
+
scrollY.setValue(contentHeight - height);
|
|
279
|
+
}
|
|
274
280
|
}
|
|
275
281
|
}, []);
|
|
276
282
|
|
|
@@ -134,10 +134,10 @@ export const useGetProgressViewOffset = () => {
|
|
|
134
134
|
switch (contentPosition) {
|
|
135
135
|
case "on_bottom_status_bar":
|
|
136
136
|
// navbar height
|
|
137
|
-
return offset + height
|
|
137
|
+
return offset + height;
|
|
138
138
|
case "on_top_screen":
|
|
139
139
|
// navbar height + status bar height
|
|
140
|
-
return offset + height;
|
|
140
|
+
return offset + height + top;
|
|
141
141
|
default:
|
|
142
142
|
return offset;
|
|
143
143
|
}
|
|
@@ -7,14 +7,10 @@ import * as R from "ramda";
|
|
|
7
7
|
import {
|
|
8
8
|
useFeedLoader,
|
|
9
9
|
useLayoutVersion,
|
|
10
|
-
useNavigationPluginData,
|
|
11
10
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
11
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
13
12
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
14
13
|
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
15
|
-
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
16
|
-
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
17
|
-
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
14
|
import {
|
|
19
15
|
useNavbarState,
|
|
20
16
|
useSetNavbarState,
|
|
@@ -51,8 +47,6 @@ export const River = (props: Props) => {
|
|
|
51
47
|
const { setTitle: setScreenTitle, setSummary: setScreenSummary } =
|
|
52
48
|
useSetNavbarState();
|
|
53
49
|
|
|
54
|
-
const navigationPluginData = useNavigationPluginData();
|
|
55
|
-
|
|
56
50
|
const rivers = useRivers();
|
|
57
51
|
const isV2 = useLayoutVersion({ isV2: true });
|
|
58
52
|
|
|
@@ -99,23 +93,6 @@ export const River = (props: Props) => {
|
|
|
99
93
|
}
|
|
100
94
|
}, [feedData, screenData, screenTitle, screenSummary]);
|
|
101
95
|
|
|
102
|
-
React.useEffect(() => {
|
|
103
|
-
if (
|
|
104
|
-
isWeb() &&
|
|
105
|
-
toBooleanWithDefaultFalse(
|
|
106
|
-
navigationPluginData?.rules?.focus_on_content
|
|
107
|
-
) &&
|
|
108
|
-
river &&
|
|
109
|
-
river.type !== "general_content"
|
|
110
|
-
) {
|
|
111
|
-
const groupId = R.pathOr("river", ["groupId"], componentsMapExtraProps);
|
|
112
|
-
|
|
113
|
-
focusManager.setupInitialFocus(groupId, true);
|
|
114
|
-
focusManager.setInitialFocus();
|
|
115
|
-
focusManager.enableAutomaticFocus();
|
|
116
|
-
}
|
|
117
|
-
}, [river, componentsMapExtraProps]);
|
|
118
|
-
|
|
119
96
|
if (!river) {
|
|
120
97
|
utilsLogger.error({
|
|
121
98
|
message: `River ${screenData.id} not found!`,
|
|
@@ -14,7 +14,7 @@ type Props = { pathname: string; screenData: Record<string, any> };
|
|
|
14
14
|
* @param {Props}: see props above
|
|
15
15
|
*/
|
|
16
16
|
export function RouteManager(props: Props) {
|
|
17
|
-
const { pathname, screenData
|
|
17
|
+
const { pathname, screenData } = useRoute();
|
|
18
18
|
const pathAttributes = getPathAttributes({ pathname });
|
|
19
19
|
|
|
20
20
|
const { screenType, screenId } = R.last(pathAttributes);
|
|
@@ -25,7 +25,7 @@ export function RouteManager(props: Props) {
|
|
|
25
25
|
screenType={screenType}
|
|
26
26
|
screenId={screenId}
|
|
27
27
|
{...props}
|
|
28
|
-
screenData={
|
|
28
|
+
screenData={screenData}
|
|
29
29
|
/>
|
|
30
30
|
</TestId>
|
|
31
31
|
);
|