@applicaster/zapp-react-native-ui-components 15.0.0-alpha.5945373352 → 15.0.0-alpha.6010600030
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 +69 -26
- package/Components/BaseFocusable/index.ios.ts +12 -2
- package/Components/Cell/Cell.tsx +8 -3
- package/Components/Cell/FocusableWrapper.tsx +3 -0
- package/Components/Cell/TvOSCellComponent.tsx +26 -5
- package/Components/Focusable/Focusable.tsx +4 -2
- package/Components/Focusable/FocusableTvOS.tsx +18 -1
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
- package/Components/FocusableGroup/FocusableTvOS.tsx +32 -1
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +14 -3
- package/Components/HandlePlayable/HandlePlayable.tsx +17 -65
- package/Components/HandlePlayable/const.ts +3 -0
- package/Components/HandlePlayable/utils.ts +74 -0
- package/Components/Layout/TV/LayoutBackground.tsx +5 -2
- package/Components/Layout/TV/ScreenContainer.tsx +2 -6
- package/Components/Layout/TV/index.tsx +3 -4
- package/Components/Layout/TV/index.web.tsx +3 -4
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/BorderContainerView/__tests__/index.test.tsx +16 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +30 -2
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +11 -3
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +9 -1
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +15 -14
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +10 -6
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +8 -8
- package/Components/MasterCell/index.tsx +2 -0
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +82 -3
- package/Components/MasterCell/utils/index.ts +61 -31
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +102 -87
- package/Components/MeasurmentsPortal/__tests__/MeasurementsPortal.test.tsx +355 -0
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +17 -18
- package/Components/OfflineHandler/__tests__/index.test.tsx +27 -18
- package/Components/PlayerContainer/PlayerContainer.tsx +51 -55
- package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +101 -0
- package/Components/PlayerImageBackground/index.tsx +3 -22
- package/Components/River/TV/River.tsx +31 -14
- package/Components/River/TV/index.tsx +5 -4
- package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +30 -0
- package/Components/River/TV/utils/index.ts +4 -0
- package/Components/River/TV/withFocusableGroupForContent.tsx +71 -0
- package/Components/Screen/TV/index.web.tsx +4 -2
- package/Components/Screen/__tests__/Screen.test.tsx +65 -42
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +68 -44
- package/Components/Screen/hooks.ts +2 -3
- package/Components/Screen/index.tsx +2 -3
- package/Components/Screen/navigationHandler.ts +49 -24
- package/Components/Screen/orientationHandler.ts +3 -3
- package/Components/ScreenResolver/index.tsx +13 -7
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +40 -8
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +86 -69
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +44 -26
- package/Components/Tabs/TV/Tabs.tsx +20 -3
- package/Components/Transitioner/Scene.tsx +15 -2
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +1 -0
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +118 -171
- package/Components/VideoModal/ModalAnimation/index.ts +2 -13
- package/Components/VideoModal/ModalAnimation/utils.ts +1 -327
- package/Components/VideoModal/PlayerWrapper.tsx +14 -88
- package/Components/VideoModal/VideoModal.tsx +1 -5
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -0
- package/Components/VideoModal/hooks/useModalSize.ts +10 -5
- package/Components/VideoModal/playerWrapperStyle.ts +70 -0
- package/Components/VideoModal/playerWrapperUtils.ts +91 -0
- package/Components/VideoModal/utils.ts +19 -9
- package/Decorators/Analytics/index.tsx +6 -5
- package/Decorators/ZappPipesDataConnector/__tests__/zappPipesDataConnector.test.js +1 -1
- package/Decorators/ZappPipesDataConnector/index.tsx +2 -2
- package/Decorators/ZappPipesDataConnector/resolvers/StaticFeedResolver.tsx +1 -1
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +80 -0
- package/Helpers/DataSourceHelper/index.ts +19 -0
- package/index.d.ts +7 -0
- package/package.json +6 -5
- package/Components/River/TV/withTVEventHandler.tsx +0 -27
- package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +0 -60
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +0 -417
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +0 -294
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +0 -176
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +0 -93
- package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +0 -500
- package/Components/VideoModal/ModalAnimation/__tests__/getMoveUpValue.test.ts +0 -108
- package/Helpers/DataSourceHelper/index.js +0 -19
|
@@ -6,10 +6,6 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
6
6
|
|
|
7
7
|
type AnimatedInterpolatedStyle = any;
|
|
8
8
|
|
|
9
|
-
// type AnimatedInterpolatedStyle =
|
|
10
|
-
// | Animated.AnimatedInterpolation
|
|
11
|
-
// | [{ [Key: string]: Animated.AnimatedInterpolation }];
|
|
12
|
-
|
|
13
9
|
type AnimationConfig = {
|
|
14
10
|
duration: number;
|
|
15
11
|
easing: EasingFunction;
|
|
@@ -45,32 +41,57 @@ export function AnimatedInOut({
|
|
|
45
41
|
children,
|
|
46
42
|
}: Props) {
|
|
47
43
|
const [animatedValue] = React.useState(new Animated.Value(visible ? 1 : 0));
|
|
48
|
-
const
|
|
44
|
+
const animationRef = React.useRef<Animated.CompositeAnimation | null>(null);
|
|
45
|
+
const delayTimerRef = React.useRef<NodeJS.Timeout | null>(null);
|
|
49
46
|
|
|
50
47
|
const previousVisible = usePrevious(toBooleanWithDefaultFalse(visible));
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const startAnimation = React.useCallback(
|
|
50
|
+
(toValue: number, config: AnimationConfig) => {
|
|
51
|
+
if (delayTimerRef.current) {
|
|
52
|
+
clearTimeout(delayTimerRef.current);
|
|
53
|
+
delayTimerRef.current = null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (animationRef.current) {
|
|
57
|
+
animationRef.current.stop();
|
|
58
|
+
animationRef.current = null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const { duration, easing, delay = 0, onAnimationEnd = noop } = config;
|
|
62
|
+
|
|
63
|
+
const runAnimation = () => {
|
|
64
|
+
animationRef.current = Animated.timing(animatedValue, {
|
|
65
|
+
duration,
|
|
66
|
+
toValue,
|
|
67
|
+
easing,
|
|
68
|
+
useNativeDriver: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
animationRef.current.start(({ finished }) => {
|
|
72
|
+
if (finished) {
|
|
73
|
+
animationRef.current = null;
|
|
74
|
+
onAnimationEnd();
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (delay > 0) {
|
|
80
|
+
delayTimerRef.current = setTimeout(runAnimation, delay);
|
|
81
|
+
} else {
|
|
82
|
+
runAnimation();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
[animatedValue]
|
|
86
|
+
);
|
|
58
87
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
easing,
|
|
63
|
-
delay,
|
|
64
|
-
useNativeDriver: true,
|
|
65
|
-
}).start(() => {
|
|
66
|
-
setAnimating(undefined);
|
|
67
|
-
onAnimationEnd();
|
|
68
|
-
});
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
if (previousVisible === undefined) {
|
|
90
|
+
animatedValue.setValue(visible ? 1 : 0);
|
|
69
91
|
|
|
70
|
-
|
|
71
|
-
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
72
94
|
|
|
73
|
-
React.useEffect(() => {
|
|
74
95
|
if (!previousVisible && visible) {
|
|
75
96
|
startAnimation(1.0, getAnimation(animationConfig, "in"));
|
|
76
97
|
}
|
|
@@ -78,7 +99,29 @@ export function AnimatedInOut({
|
|
|
78
99
|
if (previousVisible && !visible) {
|
|
79
100
|
startAnimation(0.0, getAnimation(animationConfig, "out"));
|
|
80
101
|
}
|
|
81
|
-
}, [
|
|
102
|
+
}, [
|
|
103
|
+
visible,
|
|
104
|
+
previousVisible,
|
|
105
|
+
animatedValue,
|
|
106
|
+
startAnimation,
|
|
107
|
+
animationConfig,
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
React.useEffect(() => {
|
|
111
|
+
return () => {
|
|
112
|
+
if (delayTimerRef.current) {
|
|
113
|
+
clearTimeout(delayTimerRef.current);
|
|
114
|
+
delayTimerRef.current = null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (animationRef.current) {
|
|
118
|
+
animationRef.current.stop();
|
|
119
|
+
animationRef.current = null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
animatedValue.stopAnimation();
|
|
123
|
+
};
|
|
124
|
+
}, [animatedValue]);
|
|
82
125
|
|
|
83
126
|
const styles = visible
|
|
84
127
|
? getAnimation(animationConfig, "in").styles
|
|
@@ -86,7 +129,7 @@ export function AnimatedInOut({
|
|
|
86
129
|
|
|
87
130
|
return (
|
|
88
131
|
<Animated.View
|
|
89
|
-
renderToHardwareTextureAndroid={
|
|
132
|
+
renderToHardwareTextureAndroid={!!animationRef.current}
|
|
90
133
|
style={[styles(animatedValue), staticStyles]}
|
|
91
134
|
>
|
|
92
135
|
{children}
|
|
@@ -22,6 +22,7 @@ type Props = {
|
|
|
22
22
|
onFocus?: FocusManager.FocusEventCB;
|
|
23
23
|
onBlur?: FocusManager.FocusEventCB;
|
|
24
24
|
selected?: boolean;
|
|
25
|
+
skipFocusManagerRegistration?: boolean;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
export class BaseFocusable<
|
|
@@ -61,10 +62,14 @@ export class BaseFocusable<
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
componentDidMount() {
|
|
64
|
-
const { id } = this.props;
|
|
65
|
+
const { id, skipFocusManagerRegistration } = this.props;
|
|
65
66
|
const component = this;
|
|
66
67
|
this.node = this.ref.current;
|
|
67
68
|
|
|
69
|
+
if (skipFocusManagerRegistration) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
focusManager.register({
|
|
69
74
|
id,
|
|
70
75
|
component: component,
|
|
@@ -118,7 +123,12 @@ export class BaseFocusable<
|
|
|
118
123
|
|
|
119
124
|
componentWillUnmount() {
|
|
120
125
|
this._isMounted = false;
|
|
121
|
-
const { id } = this.props;
|
|
126
|
+
const { id, skipFocusManagerRegistration } = this.props;
|
|
127
|
+
|
|
128
|
+
if (skipFocusManagerRegistration) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
focusManager.unregister(id, { group: this.isGroup || false });
|
|
123
133
|
}
|
|
124
134
|
|
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -208,14 +208,14 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
208
208
|
this.accessibilityManager.readText({
|
|
209
209
|
text: " ",
|
|
210
210
|
});
|
|
211
|
-
} else {
|
|
211
|
+
} else if (this.state.cellFocused) {
|
|
212
212
|
this.accessibilityManager.readText({
|
|
213
213
|
text: `${positionLabel}`,
|
|
214
214
|
});
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
218
|
+
componentDidUpdate(prevProps: Readonly<Props>, prevState: Readonly<State>) {
|
|
219
219
|
if (prevProps.item !== this.props.item) {
|
|
220
220
|
this.setState({
|
|
221
221
|
hasFocusableInside: this.props.CellRenderer.hasFocusableInside?.(
|
|
@@ -224,7 +224,12 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
224
224
|
});
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
|
|
227
|
+
if (
|
|
228
|
+
prevState.cellFocused !== this.state.cellFocused ||
|
|
229
|
+
this.state.hasFocusableInside
|
|
230
|
+
) {
|
|
231
|
+
this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
|
|
232
|
+
}
|
|
228
233
|
}
|
|
229
234
|
|
|
230
235
|
render() {
|
|
@@ -10,6 +10,7 @@ type Props = {
|
|
|
10
10
|
children: (focused: boolean) => React.ReactNode;
|
|
11
11
|
onFocus: (arg1: any, index?: number) => void;
|
|
12
12
|
onBlur: Callback;
|
|
13
|
+
skipFocusManagerRegistration?: boolean;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export const FocusableWrapper = ({
|
|
@@ -20,6 +21,7 @@ export const FocusableWrapper = ({
|
|
|
20
21
|
applyWrapper,
|
|
21
22
|
onFocus,
|
|
22
23
|
onBlur,
|
|
24
|
+
skipFocusManagerRegistration,
|
|
23
25
|
}: Props) => {
|
|
24
26
|
if (applyWrapper) {
|
|
25
27
|
return (
|
|
@@ -34,6 +36,7 @@ export const FocusableWrapper = ({
|
|
|
34
36
|
// @ts-ignore
|
|
35
37
|
offsetUpdater={noop}
|
|
36
38
|
isFocusable
|
|
39
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
37
40
|
>
|
|
38
41
|
{(focused) => children(focused)}
|
|
39
42
|
</Focusable>
|
|
@@ -17,6 +17,7 @@ import { CellWithFocusable } from "./CellWithFocusable";
|
|
|
17
17
|
import { FocusableWrapper } from "./FocusableWrapper";
|
|
18
18
|
|
|
19
19
|
import { focusableButtonsRegistration$ } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
20
|
+
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
20
21
|
|
|
21
22
|
type Props = {
|
|
22
23
|
item: ZappEntry;
|
|
@@ -37,6 +38,10 @@ type Props = {
|
|
|
37
38
|
component: {
|
|
38
39
|
id: number | string;
|
|
39
40
|
component_type: string;
|
|
41
|
+
styles?: {
|
|
42
|
+
component_margin_top?: number;
|
|
43
|
+
component_padding_top?: number;
|
|
44
|
+
};
|
|
40
45
|
};
|
|
41
46
|
selected: boolean;
|
|
42
47
|
CellRenderer: React.FunctionComponent<any> & {
|
|
@@ -75,6 +80,7 @@ type Props = {
|
|
|
75
80
|
componentsMapOffset: number;
|
|
76
81
|
applyFocusableWrapper: boolean;
|
|
77
82
|
hasFocusableInside: boolean;
|
|
83
|
+
skipFocusManagerRegistration?: boolean;
|
|
78
84
|
};
|
|
79
85
|
|
|
80
86
|
type State = {
|
|
@@ -201,14 +207,25 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
201
207
|
) {
|
|
202
208
|
const { headerOffset } = getHeaderOffset();
|
|
203
209
|
|
|
204
|
-
const extraAnchorPointYOffset =
|
|
205
|
-
screenLayout?.extraAnchorPointYOffset
|
|
210
|
+
const extraAnchorPointYOffset = toNumberWithDefaultZero(
|
|
211
|
+
screenLayout?.extraAnchorPointYOffset
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const componentMarginTop = toNumberWithDefaultZero(
|
|
215
|
+
component?.styles?.component_margin_top
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const componentPaddingTop = toNumberWithDefaultZero(
|
|
219
|
+
component?.styles?.component_padding_top
|
|
220
|
+
);
|
|
206
221
|
|
|
207
222
|
const totalOffset =
|
|
208
223
|
headerOffset +
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
224
|
+
toNumberWithDefaultZero(componentAnchorPointY) +
|
|
225
|
+
extraAnchorPointYOffset -
|
|
226
|
+
toNumberWithDefaultZero(componentsMapOffset) +
|
|
227
|
+
componentMarginTop +
|
|
228
|
+
componentPaddingTop;
|
|
212
229
|
|
|
213
230
|
mainOffsetUpdater?.(
|
|
214
231
|
{ tag: this.target },
|
|
@@ -250,6 +267,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
250
267
|
behavior,
|
|
251
268
|
applyFocusableWrapper,
|
|
252
269
|
hasFocusableInside,
|
|
270
|
+
skipFocusManagerRegistration,
|
|
253
271
|
} = this.props;
|
|
254
272
|
|
|
255
273
|
const { id } = item;
|
|
@@ -275,6 +293,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
275
293
|
onFocus={handleFocus}
|
|
276
294
|
onBlur={onBlur || this.onBlur}
|
|
277
295
|
applyWrapper={applyFocusableWrapper}
|
|
296
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
278
297
|
>
|
|
279
298
|
{(focused) => (
|
|
280
299
|
<CellWithFocusable
|
|
@@ -289,6 +308,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
289
308
|
focused={focused || this.props.focused}
|
|
290
309
|
behavior={behavior}
|
|
291
310
|
isFocusable={isFocusable}
|
|
311
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
292
312
|
/>
|
|
293
313
|
)}
|
|
294
314
|
</FocusableWrapper>
|
|
@@ -311,6 +331,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
311
331
|
offsetUpdater={offsetUpdater}
|
|
312
332
|
style={baseCellStyles}
|
|
313
333
|
isFocusable={isFocusable}
|
|
334
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
314
335
|
>
|
|
315
336
|
{(focused) => (
|
|
316
337
|
<FocusableCell
|
|
@@ -8,6 +8,8 @@ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withF
|
|
|
8
8
|
import { StyleSheet, ViewStyle } from "react-native";
|
|
9
9
|
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
10
10
|
|
|
11
|
+
import { isSearchInputId } from "@applicaster/search-screen/src/tv/utils";
|
|
12
|
+
|
|
11
13
|
type Props = {
|
|
12
14
|
initialFocus?: boolean;
|
|
13
15
|
id: string;
|
|
@@ -106,7 +108,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
106
108
|
onMouseEnter() {
|
|
107
109
|
const { id } = this.props;
|
|
108
110
|
|
|
109
|
-
if (id
|
|
111
|
+
if (!isSearchInputId(id)) {
|
|
110
112
|
this.mouse = true;
|
|
111
113
|
this.props?.handleFocus?.({ mouse: true });
|
|
112
114
|
|
|
@@ -120,7 +122,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
120
122
|
onMouseLeave() {
|
|
121
123
|
const { id } = this.props;
|
|
122
124
|
|
|
123
|
-
if (id
|
|
125
|
+
if (!isSearchInputId(id)) {
|
|
124
126
|
this.mouse = false;
|
|
125
127
|
this.blur(null);
|
|
126
128
|
}
|
|
@@ -10,8 +10,12 @@ import {
|
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
12
|
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
import {
|
|
16
|
+
emitFocused,
|
|
17
|
+
emitNativeRegistered,
|
|
18
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
15
19
|
|
|
16
20
|
type Props = {
|
|
17
21
|
id: string;
|
|
@@ -39,6 +43,7 @@ type Props = {
|
|
|
39
43
|
hasReceivedFocus: () => void;
|
|
40
44
|
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
41
45
|
style: ViewStyle;
|
|
46
|
+
skipFocusManagerRegistration?: boolean;
|
|
42
47
|
};
|
|
43
48
|
|
|
44
49
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -53,6 +58,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
53
58
|
this.nextFocusableReactTags = {};
|
|
54
59
|
this.preferredFocus = this.preferredFocus.bind(this);
|
|
55
60
|
this.measureView = this.measureView.bind(this);
|
|
61
|
+
this.onRegistered = this.onRegistered.bind(this);
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
/**
|
|
@@ -84,6 +90,9 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
84
90
|
});
|
|
85
91
|
}
|
|
86
92
|
|
|
93
|
+
const id: string = nativeEvent.itemID;
|
|
94
|
+
emitFocused(id);
|
|
95
|
+
|
|
87
96
|
onFocus(nativeEvent);
|
|
88
97
|
}
|
|
89
98
|
|
|
@@ -169,6 +178,13 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
169
178
|
});
|
|
170
179
|
}
|
|
171
180
|
|
|
181
|
+
onRegistered({ nativeEvent }) {
|
|
182
|
+
const groupId = nativeEvent?.groupId;
|
|
183
|
+
const id = nativeEvent?.itemId;
|
|
184
|
+
|
|
185
|
+
emitNativeRegistered({ id, groupId, isGroup: false });
|
|
186
|
+
}
|
|
187
|
+
|
|
172
188
|
render() {
|
|
173
189
|
const {
|
|
174
190
|
children,
|
|
@@ -203,6 +219,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
203
219
|
focusable={isFocusable}
|
|
204
220
|
{...this.nextFocusableReactTags}
|
|
205
221
|
{...otherProps}
|
|
222
|
+
onRegistered={this.onRegistered}
|
|
206
223
|
>
|
|
207
224
|
{typeof children === "function" ? children(focused) : children}
|
|
208
225
|
</FocusableItemNative>
|
|
@@ -2,6 +2,10 @@ import * as React from "react";
|
|
|
2
2
|
import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
|
|
3
3
|
import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";
|
|
4
4
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
5
|
+
import { LayoutContext } from "@applicaster/zapp-react-native-tvos-app/Context/LayoutContext";
|
|
6
|
+
import { useRoute } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute";
|
|
7
|
+
import { isScreenPlayable } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
8
|
+
import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
5
9
|
|
|
6
10
|
const { log_verbose } = createLogger({
|
|
7
11
|
subsystem: "General",
|
|
@@ -33,7 +37,16 @@ type Props = {
|
|
|
33
37
|
screenData: { screenId: string; parentScreenId: string };
|
|
34
38
|
};
|
|
35
39
|
|
|
36
|
-
|
|
40
|
+
class FocusableGroupComponent extends BaseFocusable<Props> {
|
|
41
|
+
public readonly isGroup: boolean = true;
|
|
42
|
+
|
|
43
|
+
onRegistered = ({ nativeEvent }) => {
|
|
44
|
+
const groupId = nativeEvent?.groupId;
|
|
45
|
+
const id = nativeEvent?.itemId;
|
|
46
|
+
|
|
47
|
+
emitNativeRegistered({ id, groupId, isGroup: true });
|
|
48
|
+
};
|
|
49
|
+
|
|
37
50
|
render() {
|
|
38
51
|
const {
|
|
39
52
|
children,
|
|
@@ -66,9 +79,27 @@ export class FocusableGroup extends BaseFocusable<Props> {
|
|
|
66
79
|
onGroupBlur={onGroupBlur}
|
|
67
80
|
style={style}
|
|
68
81
|
{...otherProps}
|
|
82
|
+
onRegistered={this.onRegistered}
|
|
69
83
|
>
|
|
70
84
|
{children}
|
|
71
85
|
</FocusableGroupNative>
|
|
72
86
|
);
|
|
73
87
|
}
|
|
74
88
|
}
|
|
89
|
+
|
|
90
|
+
export const withFocusDisabled = (Component) => {
|
|
91
|
+
return function WithFocusDisabled(props) {
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
const { screenFocusBlocked } = React.useContext(LayoutContext.ReactContext);
|
|
94
|
+
|
|
95
|
+
const { pathname } = useRoute();
|
|
96
|
+
|
|
97
|
+
const isPlayerPresented = isScreenPlayable(pathname);
|
|
98
|
+
|
|
99
|
+
const blockScreenFocus = isPlayerPresented === false && screenFocusBlocked;
|
|
100
|
+
|
|
101
|
+
return <Component {...props} isFocusDisabled={blockScreenFocus} />;
|
|
102
|
+
};
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const FocusableGroup = withFocusDisabled(FocusableGroupComponent);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { all, equals,
|
|
1
|
+
import { all, equals, isEmpty, path, pluck, prop, values } from "ramda";
|
|
2
2
|
|
|
3
3
|
import { useEffect, useMemo } from "react";
|
|
4
4
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
|
|
25
25
|
import { produce } from "immer";
|
|
26
26
|
import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
27
|
+
|
|
27
28
|
// types reference
|
|
28
29
|
|
|
29
30
|
declare interface CurationEntry {
|
|
@@ -35,6 +36,7 @@ type Feeds = Record<string, ZappPipesData>;
|
|
|
35
36
|
|
|
36
37
|
type LayoutPresets = PresetsMapping["presets_mappings"];
|
|
37
38
|
|
|
39
|
+
const TABS_SCREEN_TYPE = "tabs_screen";
|
|
38
40
|
const SMART_COMPONENT_TYPE = "quick-brick-smart-component";
|
|
39
41
|
const SOURCE_PATH = ["data", "source"];
|
|
40
42
|
const MAPPING_PATH = ["data", "mapping"];
|
|
@@ -53,7 +55,10 @@ export const getTransformedPreset = (
|
|
|
53
55
|
const presetComponent = layoutPresets?.[preset?.preset_name];
|
|
54
56
|
|
|
55
57
|
if (!presetComponent) {
|
|
56
|
-
logger.log_error(
|
|
58
|
+
logger.log_error(
|
|
59
|
+
`Preset "${preset?.preset_name}" missing or wrong data format`,
|
|
60
|
+
{ entry: preset }
|
|
61
|
+
);
|
|
57
62
|
|
|
58
63
|
return;
|
|
59
64
|
}
|
|
@@ -131,10 +136,16 @@ export const useCurationAPI = (
|
|
|
131
136
|
);
|
|
132
137
|
|
|
133
138
|
const { pathname } = useRoute();
|
|
134
|
-
const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname);
|
|
135
139
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
136
140
|
const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
137
141
|
|
|
142
|
+
const isNestedScreen = screenContext?.type === TABS_SCREEN_TYPE;
|
|
143
|
+
|
|
144
|
+
const [entryContext] = ZappPipesEntryContext.useZappPipesContext(
|
|
145
|
+
pathname,
|
|
146
|
+
isNestedScreen
|
|
147
|
+
);
|
|
148
|
+
|
|
138
149
|
const urlsMap = useMemo<{ [key: string]: string }>(() => {
|
|
139
150
|
const map = {};
|
|
140
151
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import * as R from "ramda";
|
|
3
2
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
useAppData,
|
|
4
|
+
useContentTypes,
|
|
5
|
+
usePlugins,
|
|
6
|
+
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
7
|
import {
|
|
9
8
|
useDimensions,
|
|
10
9
|
useIsTablet as isTablet,
|
|
11
10
|
useNavigation,
|
|
11
|
+
useRivers,
|
|
12
12
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
13
|
|
|
14
14
|
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
@@ -16,6 +16,7 @@ import { PlayerContainer } from "../PlayerContainer";
|
|
|
16
16
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
17
|
import { ViewStyle } from "react-native";
|
|
18
18
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
19
|
+
import { findCastPlugin, getPlayer } from "./utils";
|
|
19
20
|
|
|
20
21
|
type Props = {
|
|
21
22
|
item: ZappEntry;
|
|
@@ -26,62 +27,6 @@ type Props = {
|
|
|
26
27
|
groupId?: string;
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
30
|
-
const CHROMECAST_PLUGIN_ID = "chromecast_qb";
|
|
31
|
-
|
|
32
|
-
const getPlayerWithModuleProperties = (
|
|
33
|
-
PlayerModule: ZappPlugin
|
|
34
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
35
|
-
const getPlayerModuleProperties = R.ifElse(
|
|
36
|
-
R.is(Object) && R.has("Component"),
|
|
37
|
-
R.omit(["Component"]),
|
|
38
|
-
() => ({})
|
|
39
|
-
);
|
|
40
|
-
|
|
41
|
-
return [
|
|
42
|
-
PlayerModule?.Component || PlayerModule,
|
|
43
|
-
getPlayerModuleProperties(PlayerModule),
|
|
44
|
-
];
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const getPlayer = (
|
|
48
|
-
item: ZappEntry,
|
|
49
|
-
state
|
|
50
|
-
): [ZappPlugin, PlayerModuleProperties] => {
|
|
51
|
-
const {
|
|
52
|
-
plugins,
|
|
53
|
-
contentTypes,
|
|
54
|
-
rivers,
|
|
55
|
-
appData: { layoutVersion },
|
|
56
|
-
} = state;
|
|
57
|
-
|
|
58
|
-
let PlayerModule;
|
|
59
|
-
|
|
60
|
-
if (layoutVersion === "v2") {
|
|
61
|
-
const { screen_id } = contentTypes?.[item?.type?.value] || {};
|
|
62
|
-
const { type } = rivers?.[screen_id] || {};
|
|
63
|
-
|
|
64
|
-
if (type) {
|
|
65
|
-
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
66
|
-
|
|
67
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (item?.content?.type === "youtube-id") {
|
|
72
|
-
PlayerModule = findPluginByIdentifier(YOUTUBE_PLUGIN_ID, plugins)?.module;
|
|
73
|
-
|
|
74
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
PlayerModule = findPluginByType(
|
|
78
|
-
"playable",
|
|
79
|
-
plugins.filter(({ identifier }) => identifier !== YOUTUBE_PLUGIN_ID)
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
return getPlayerWithModuleProperties(PlayerModule);
|
|
83
|
-
};
|
|
84
|
-
|
|
85
30
|
type PlayableComponent = {
|
|
86
31
|
Component: React.ComponentType<any>;
|
|
87
32
|
};
|
|
@@ -99,14 +44,21 @@ export function HandlePlayable({
|
|
|
99
44
|
mode,
|
|
100
45
|
groupId,
|
|
101
46
|
}: Props): React.ReactElement | null {
|
|
102
|
-
const
|
|
47
|
+
const plugins = usePlugins();
|
|
48
|
+
const contentTypes = useContentTypes();
|
|
49
|
+
const rivers = useRivers();
|
|
50
|
+
const appData = useAppData();
|
|
103
51
|
|
|
104
52
|
const { closeVideoModal } = useNavigation();
|
|
105
53
|
|
|
106
|
-
const [Player, playerModuleProperties] = getPlayer(item,
|
|
54
|
+
const [Player, playerModuleProperties] = getPlayer(item, {
|
|
55
|
+
plugins,
|
|
56
|
+
contentTypes,
|
|
57
|
+
rivers,
|
|
58
|
+
appData,
|
|
59
|
+
});
|
|
107
60
|
|
|
108
|
-
const { module: CastPlugin } =
|
|
109
|
-
findPluginByIdentifier(CHROMECAST_PLUGIN_ID, state.plugins, true) || {};
|
|
61
|
+
const { module: CastPlugin } = findCastPlugin(plugins);
|
|
110
62
|
|
|
111
63
|
const [playable, setPlayable] =
|
|
112
64
|
React.useState<Nullable<PlayableComponent>>(null);
|