@applicaster/zapp-react-native-ui-components 14.0.0-alpha.8419134002 → 14.0.0-alpha.8583696651
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 +5 -3
- package/Components/Focusable/Focusable.tsx +5 -3
- package/Components/Focusable/FocusableTvOS.tsx +3 -3
- package/Components/Focusable/FocusableiOS.tsx +1 -1
- package/Components/Focusable/__tests__/index.android.test.tsx +3 -0
- package/Components/Focusable/index.android.tsx +12 -8
- package/Components/FocusableList/index.tsx +4 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +25 -9
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +4 -27
- package/Components/MasterCell/elementMapper.tsx +1 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +13 -18
- package/Components/OfflineHandler/__tests__/__snapshots__/index.test.tsx.snap +9 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +41 -28
- package/Components/River/ComponentsMap/ComponentsMap.tsx +0 -1
- package/Components/River/TV/withTVEventHandler.tsx +1 -1
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +76 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +107 -0
- package/Components/ScreenRevealManager/__tests__/withScreenRevealManager.test.tsx +96 -0
- package/Components/ScreenRevealManager/index.ts +1 -0
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +79 -0
- package/Components/Tabs/TV/Tabs.android.tsx +0 -2
- package/Components/Touchable/__tests__/__snapshots__/touchable.test.tsx.snap +34 -0
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +15 -9
- package/Components/VideoLive/animationUtils.ts +3 -3
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +9 -1
- package/Components/VideoModal/PlayerDetails.tsx +24 -2
- package/Components/VideoModal/PlayerWrapper.tsx +26 -142
- package/Components/VideoModal/VideoModal.tsx +3 -17
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +1 -7
- package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +44 -240
- package/Components/VideoModal/hooks/index.ts +0 -2
- package/Components/VideoModal/hooks/useModalSize.ts +18 -2
- package/Components/VideoModal/utils.ts +6 -0
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +12 -16
- package/Components/Viewport/ViewportTracker/__tests__/viewportTracker.test.js +84 -24
- package/Decorators/ConfigurationWrapper/withConfigurationProvider.tsx +2 -2
- package/package.json +5 -9
- package/Components/VideoModal/hooks/useBackgroundColor.ts +0 -10
|
@@ -4,9 +4,11 @@ import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/uti
|
|
|
4
4
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
5
5
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
6
6
|
|
|
7
|
-
type AnimatedInterpolatedStyle =
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
type AnimatedInterpolatedStyle = any;
|
|
8
|
+
|
|
9
|
+
// type AnimatedInterpolatedStyle =
|
|
10
|
+
// | Animated.AnimatedInterpolation
|
|
11
|
+
// | [{ [Key: string]: Animated.AnimatedInterpolation }];
|
|
10
12
|
|
|
11
13
|
type AnimationConfig = {
|
|
12
14
|
duration: number;
|
|
@@ -5,6 +5,7 @@ import { BaseFocusable } from "../BaseFocusable";
|
|
|
5
5
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
6
6
|
import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
|
|
7
7
|
import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
|
|
8
|
+
import { StyleSheet, ViewStyle } from "react-native";
|
|
8
9
|
|
|
9
10
|
type Props = {
|
|
10
11
|
initialFocus?: boolean;
|
|
@@ -21,7 +22,7 @@ type Props = {
|
|
|
21
22
|
handleFocus?: ({ mouse }: { mouse: boolean }) => void;
|
|
22
23
|
children: (boolean, string) => React.ComponentType<any>;
|
|
23
24
|
selected?: boolean;
|
|
24
|
-
style?:
|
|
25
|
+
style?: ViewStyle[] | ViewStyle;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
class Focusable extends BaseFocusable<Props> {
|
|
@@ -122,7 +123,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
render() {
|
|
125
|
-
const { children, style } = this.props;
|
|
126
|
+
const { children, style, ...otherProps } = this.props;
|
|
126
127
|
const { focused } = this.state;
|
|
127
128
|
|
|
128
129
|
const id = this.getId();
|
|
@@ -139,7 +140,8 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
139
140
|
onMouseUp={this.pressOut}
|
|
140
141
|
data-testid={focusableId}
|
|
141
142
|
focused-teststate={focused ? "focused" : "default"}
|
|
142
|
-
style={style}
|
|
143
|
+
style={StyleSheet.flatten(style) as any as React.CSSProperties}
|
|
144
|
+
{...otherProps}
|
|
143
145
|
>
|
|
144
146
|
{children(focused, { mouse: this.mouse })}
|
|
145
147
|
</div>
|
|
@@ -16,9 +16,9 @@ function noop() {}
|
|
|
16
16
|
type Props = {
|
|
17
17
|
id: string;
|
|
18
18
|
groupId: string;
|
|
19
|
-
onPress?: (nativeEvent:
|
|
20
|
-
onFocus?: (nativeEvent:
|
|
21
|
-
onBlur?: (nativeEvent:
|
|
19
|
+
onPress?: (nativeEvent: any) => void;
|
|
20
|
+
onFocus?: (nativeEvent: any) => void;
|
|
21
|
+
onBlur?: (nativeEvent: any) => void;
|
|
22
22
|
children: (focused?: boolean) => React.ReactNode;
|
|
23
23
|
isParallaxDisabled: boolean;
|
|
24
24
|
preferredFocus?: boolean;
|
|
@@ -38,6 +38,9 @@ describe("Focusable", () => {
|
|
|
38
38
|
});
|
|
39
39
|
|
|
40
40
|
it("updates disableFocus state when disableFocus prop changes", () => {
|
|
41
|
+
const unregister = jest.fn();
|
|
42
|
+
mockFocusManager.registerFocusable.mockReturnValue(unregister);
|
|
43
|
+
|
|
41
44
|
const { rerender } = render(
|
|
42
45
|
<Focusable id="test-id" disableFocus={false}>
|
|
43
46
|
<Touchable testID="touchable" />
|
|
@@ -43,11 +43,13 @@ export const FocusableContext = React.createContext<
|
|
|
43
43
|
// eslint-disable-next-line
|
|
44
44
|
setIsFocusable: (enableFocus: boolean) => void;
|
|
45
45
|
ref: FocusManager.FocusableRef;
|
|
46
|
+
parentFocusableId: Option<string>;
|
|
46
47
|
} & ParentFocus
|
|
47
48
|
>({
|
|
48
49
|
focused: false,
|
|
49
50
|
setIsFocusable: () => {},
|
|
50
51
|
ref: { current: null },
|
|
52
|
+
parentFocusableId: undefined,
|
|
51
53
|
});
|
|
52
54
|
|
|
53
55
|
export const useFocusable = () => React.useContext(FocusableContext);
|
|
@@ -74,7 +76,7 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
74
76
|
|
|
75
77
|
const isRTL = useIsRTL();
|
|
76
78
|
const focusManager = useFocusManager();
|
|
77
|
-
const { ref:
|
|
79
|
+
const { ref: parentFocusableRef, parentFocusableId } = useFocusable();
|
|
78
80
|
const touchableRef = React.useRef(null);
|
|
79
81
|
|
|
80
82
|
const [focused, setFocused] = React.useState(() =>
|
|
@@ -98,13 +100,14 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
98
100
|
}
|
|
99
101
|
}, [disableFocus]);
|
|
100
102
|
|
|
101
|
-
React.
|
|
103
|
+
React.useLayoutEffect(() => {
|
|
102
104
|
if (id) {
|
|
103
|
-
const unregister = focusManager.registerFocusable(
|
|
105
|
+
const unregister = focusManager.registerFocusable({
|
|
104
106
|
touchableRef,
|
|
105
|
-
|
|
106
|
-
isFocusableCell
|
|
107
|
-
|
|
107
|
+
parentFocusableRef,
|
|
108
|
+
isFocusableCell,
|
|
109
|
+
parentFocusableId,
|
|
110
|
+
});
|
|
108
111
|
|
|
109
112
|
onRegister();
|
|
110
113
|
|
|
@@ -112,7 +115,7 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
112
115
|
unregister();
|
|
113
116
|
};
|
|
114
117
|
}
|
|
115
|
-
}, [id, onRegister, isFocusableCell]);
|
|
118
|
+
}, [id, onRegister, isFocusableCell, parentFocusableId]);
|
|
116
119
|
|
|
117
120
|
if (R.isNil(id)) {
|
|
118
121
|
// eslint-disable-next-line no-console
|
|
@@ -164,8 +167,9 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
164
167
|
...parentFocus,
|
|
165
168
|
ref: touchableRef,
|
|
166
169
|
setIsFocusable,
|
|
170
|
+
parentFocusableId: id,
|
|
167
171
|
};
|
|
168
|
-
}, [parentFocus, focused]);
|
|
172
|
+
}, [parentFocus, focused, id]);
|
|
169
173
|
|
|
170
174
|
return (
|
|
171
175
|
<Touchable
|
|
@@ -91,6 +91,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
91
91
|
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
92
92
|
omitPropsPropagation = [],
|
|
93
93
|
useScrollView = false,
|
|
94
|
+
onScrollToIndexFailed = noop,
|
|
94
95
|
} = props;
|
|
95
96
|
|
|
96
97
|
useCheckItemIdsForUnique({ componentId: props.id, items: data });
|
|
@@ -277,6 +278,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
277
278
|
"withStateMemory",
|
|
278
279
|
"useSequentialLoading",
|
|
279
280
|
"useScrollView",
|
|
281
|
+
"onScrollToIndexFailed",
|
|
280
282
|
...omitPropsPropagation,
|
|
281
283
|
],
|
|
282
284
|
R.__
|
|
@@ -305,6 +307,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
305
307
|
{...getFlatListProps(props)}
|
|
306
308
|
onEndReached={onEndReached}
|
|
307
309
|
initialNumToRender={initialNumToRender}
|
|
310
|
+
onScrollToIndexFailed={onScrollToIndexFailed}
|
|
308
311
|
renderItem={renderItem}
|
|
309
312
|
focused={focused}
|
|
310
313
|
data={data}
|
|
@@ -319,6 +322,7 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
319
322
|
renderItem={renderItem}
|
|
320
323
|
onEndReached={onEndReached}
|
|
321
324
|
initialNumToRender={initialNumToRender}
|
|
325
|
+
onScrollToIndexFailed={onScrollToIndexFailed}
|
|
322
326
|
/>
|
|
323
327
|
)}
|
|
324
328
|
</ChildrenFocusDeactivatorView>
|
|
@@ -7,12 +7,15 @@ import {
|
|
|
7
7
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
8
|
import {
|
|
9
9
|
useDimensions,
|
|
10
|
+
useIsTablet as isTablet,
|
|
10
11
|
useNavigation,
|
|
11
12
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
13
|
|
|
13
14
|
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
14
15
|
import { PlayerContainer } from "../PlayerContainer";
|
|
15
16
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
|
+
import { ViewStyle } from "react-native";
|
|
18
|
+
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
16
19
|
|
|
17
20
|
type Props = {
|
|
18
21
|
item: ZappEntry;
|
|
@@ -83,6 +86,13 @@ type PlayableComponent = {
|
|
|
83
86
|
Component: React.ComponentType<any>;
|
|
84
87
|
};
|
|
85
88
|
|
|
89
|
+
const dimensionsContext: "window" | "screen" = platformSelect({
|
|
90
|
+
android_tv: "window",
|
|
91
|
+
amazon: "window",
|
|
92
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
93
|
+
default: isTablet() ? "window" : "screen", // on tablet, window represents correct values, on phone it's not as the screen could be rotated
|
|
94
|
+
});
|
|
95
|
+
|
|
86
96
|
export function HandlePlayable({
|
|
87
97
|
item,
|
|
88
98
|
isModal,
|
|
@@ -135,19 +145,25 @@ export function HandlePlayable({
|
|
|
135
145
|
});
|
|
136
146
|
}, [casting]);
|
|
137
147
|
|
|
138
|
-
const { width: screenWidth, height: screenHeight } =
|
|
148
|
+
const { width: screenWidth, height: screenHeight } =
|
|
149
|
+
useDimensions(dimensionsContext);
|
|
139
150
|
|
|
140
151
|
const modalSize = useModalSize();
|
|
141
152
|
|
|
142
153
|
const style = React.useMemo(
|
|
143
|
-
() =>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
() =>
|
|
155
|
+
({
|
|
156
|
+
width: isModal
|
|
157
|
+
? modalSize.width
|
|
158
|
+
: mode === "PIP"
|
|
159
|
+
? "100%"
|
|
160
|
+
: screenWidth,
|
|
161
|
+
height: isModal
|
|
162
|
+
? modalSize.height
|
|
163
|
+
: mode === "PIP"
|
|
164
|
+
? "100%"
|
|
165
|
+
: screenHeight,
|
|
166
|
+
}) as ViewStyle,
|
|
151
167
|
[screenWidth, screenHeight, modalSize, isModal, mode]
|
|
152
168
|
);
|
|
153
169
|
|
|
@@ -2,7 +2,6 @@ import React, { useMemo } from "react";
|
|
|
2
2
|
import { ImageStyle } from "react-native";
|
|
3
3
|
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
|
-
import * as R from "ramda";
|
|
6
5
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
7
6
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
8
7
|
import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
|
|
@@ -67,32 +66,10 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
67
66
|
const handleFocus = (focusable) => {
|
|
68
67
|
const focusedButtonId = getFocusedButtonId(focusable);
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const right = left + width;
|
|
75
|
-
|
|
76
|
-
const boundingRect = {
|
|
77
|
-
x,
|
|
78
|
-
y,
|
|
79
|
-
pageX,
|
|
80
|
-
pageY,
|
|
81
|
-
width,
|
|
82
|
-
height,
|
|
83
|
-
top,
|
|
84
|
-
bottom,
|
|
85
|
-
left,
|
|
86
|
-
right,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
otherProps?.onToggleFocus?.({
|
|
90
|
-
focusable: {
|
|
91
|
-
getRect: R.always(boundingRect),
|
|
92
|
-
},
|
|
93
|
-
focusedButtonId,
|
|
94
|
-
mouse: focusable.mouse,
|
|
95
|
-
});
|
|
69
|
+
otherProps?.onToggleFocus?.({
|
|
70
|
+
focusable: wrapperRef.current,
|
|
71
|
+
focusedButtonId,
|
|
72
|
+
mouse: focusable.mouse,
|
|
96
73
|
});
|
|
97
74
|
|
|
98
75
|
if (ttsLabel) {
|
|
@@ -73,7 +73,6 @@ export function elementMapper(
|
|
|
73
73
|
: {};
|
|
74
74
|
|
|
75
75
|
const componentProps = {
|
|
76
|
-
key,
|
|
77
76
|
style,
|
|
78
77
|
skipButtons: otherProps?.skipButtons,
|
|
79
78
|
emitAsyncElementRegistrate: otherProps?.emitAsyncElementRegistrate,
|
|
@@ -91,7 +90,7 @@ export function elementMapper(
|
|
|
91
90
|
const fn = mapElementWithKey(elementMapper(components, otherProps));
|
|
92
91
|
|
|
93
92
|
return (
|
|
94
|
-
<Component {...componentProps}>
|
|
93
|
+
<Component key={key} {...componentProps}>
|
|
95
94
|
{focusableTypes.has(type) && elements.length > 0
|
|
96
95
|
? elements.map(fn)
|
|
97
96
|
: null}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Text, Animated } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
3
4
|
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
import {
|
|
6
|
+
NotificationView,
|
|
7
|
+
onlinePhrase,
|
|
8
|
+
offlinePhrase,
|
|
9
|
+
} from "../NotificationView";
|
|
7
10
|
|
|
8
11
|
jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
|
|
9
12
|
usePickFromState: () => ({
|
|
@@ -32,39 +35,31 @@ jest.mock("react-native-safe-area-context", () => ({
|
|
|
32
35
|
|
|
33
36
|
const dismiss = jest.fn();
|
|
34
37
|
|
|
35
|
-
const {
|
|
36
|
-
NotificationView,
|
|
37
|
-
onlinePhrase,
|
|
38
|
-
offlinePhrase,
|
|
39
|
-
} = require("../NotificationView");
|
|
40
|
-
|
|
41
38
|
describe("NotificationView", () => {
|
|
42
39
|
it("Show online message when Online", () => {
|
|
43
|
-
const component =
|
|
44
|
-
<NotificationView online dismiss={dismiss} />
|
|
45
|
-
);
|
|
40
|
+
const component = render(<NotificationView online dismiss={dismiss} />);
|
|
46
41
|
|
|
47
|
-
expect(component.
|
|
42
|
+
expect(component.UNSAFE_getByType(Text).props.children).toBe(onlinePhrase);
|
|
48
43
|
});
|
|
49
44
|
|
|
50
45
|
it("Show offline message when Online", () => {
|
|
51
|
-
const component =
|
|
46
|
+
const component = render(
|
|
52
47
|
<NotificationView online={false} dismiss={dismiss} />
|
|
53
48
|
);
|
|
54
49
|
|
|
55
|
-
expect(component.
|
|
50
|
+
expect(component.UNSAFE_getByType(Text).props.children).toBe(offlinePhrase);
|
|
56
51
|
});
|
|
57
52
|
|
|
58
53
|
it("When hidden is false to true notification is visible", () => {
|
|
59
|
-
const component =
|
|
54
|
+
const component = render(
|
|
60
55
|
<NotificationView online={false} hidden={false} dismiss={dismiss} />
|
|
61
56
|
);
|
|
62
57
|
|
|
63
|
-
component.
|
|
58
|
+
component.rerender(
|
|
64
59
|
<NotificationView online={false} hidden={true} dismiss={dismiss} />
|
|
65
60
|
);
|
|
66
61
|
|
|
67
|
-
const animatedView = component.
|
|
62
|
+
const animatedView = component.UNSAFE_getByType(Animated.View);
|
|
68
63
|
const animatedViewStyles = animatedView.props.style;
|
|
69
64
|
|
|
70
65
|
expect(animatedViewStyles.opacity).toBe(1);
|
|
@@ -21,6 +21,15 @@ exports[`OfflineHandler renders 1`] = `
|
|
|
21
21
|
}
|
|
22
22
|
>
|
|
23
23
|
<View
|
|
24
|
+
accessibilityState={
|
|
25
|
+
{
|
|
26
|
+
"busy": undefined,
|
|
27
|
+
"checked": undefined,
|
|
28
|
+
"disabled": undefined,
|
|
29
|
+
"expanded": undefined,
|
|
30
|
+
"selected": undefined,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
24
33
|
accessible={true}
|
|
25
34
|
collapsable={false}
|
|
26
35
|
focusable={true}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { useEffect, useReducer } from "react";
|
|
3
|
-
|
|
4
|
-
import { TVMenuControl, View, ViewStyle } from "react-native";
|
|
3
|
+
import { View, ViewStyle } from "react-native";
|
|
5
4
|
import * as R from "ramda";
|
|
6
5
|
import uuid from "uuid/v4";
|
|
7
6
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager";
|
|
@@ -62,6 +61,11 @@ import {
|
|
|
62
61
|
useModalAnimationContext,
|
|
63
62
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
64
63
|
|
|
64
|
+
import {
|
|
65
|
+
PlayerNativeCommandTypes,
|
|
66
|
+
PlayerNativeSendCommand,
|
|
67
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerNativeCommand";
|
|
68
|
+
|
|
65
69
|
type Props = {
|
|
66
70
|
Player: React.ComponentType<any>;
|
|
67
71
|
PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
|
|
@@ -88,7 +92,7 @@ export const VideoModalMode = {
|
|
|
88
92
|
MAXIMIZED: "MAXIMIZED",
|
|
89
93
|
MINIMIZED: "MINIMIZED",
|
|
90
94
|
FULLSCREEN: "FULLSCREEN",
|
|
91
|
-
};
|
|
95
|
+
} as const;
|
|
92
96
|
|
|
93
97
|
export type PlayNextData = {
|
|
94
98
|
state: PlayNextState;
|
|
@@ -127,7 +131,7 @@ const webStyles = {
|
|
|
127
131
|
playerScreen: {
|
|
128
132
|
flex: 1,
|
|
129
133
|
height: "100vh",
|
|
130
|
-
|
|
134
|
+
backgroundColor: "black",
|
|
131
135
|
},
|
|
132
136
|
playerWrapper: {
|
|
133
137
|
height: "100%",
|
|
@@ -145,7 +149,6 @@ const nativeStyles = {
|
|
|
145
149
|
},
|
|
146
150
|
playerScreen: {
|
|
147
151
|
flex: 1,
|
|
148
|
-
backgroundColor: "black",
|
|
149
152
|
overflow: "hidden",
|
|
150
153
|
},
|
|
151
154
|
playerWrapper: {
|
|
@@ -260,9 +263,15 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
260
263
|
return;
|
|
261
264
|
}
|
|
262
265
|
|
|
266
|
+
// send command to clear and stop player
|
|
267
|
+
PlayerNativeSendCommand(
|
|
268
|
+
PlayerNativeCommandTypes.clearPlayerData,
|
|
269
|
+
state.playerId
|
|
270
|
+
);
|
|
271
|
+
|
|
263
272
|
showNavBar(true);
|
|
264
273
|
navigator.goBack();
|
|
265
|
-
}, [isModal, navigator.goBack, showNavBar]);
|
|
274
|
+
}, [isModal, navigator.goBack, state.playerId, showNavBar]);
|
|
266
275
|
|
|
267
276
|
const playEntry = (entry) => navigator.replaceTop(entry, { mode });
|
|
268
277
|
|
|
@@ -390,13 +399,17 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
390
399
|
}
|
|
391
400
|
};
|
|
392
401
|
|
|
393
|
-
const playerRemoteHandler = (
|
|
394
|
-
|
|
402
|
+
const playerRemoteHandler = React.useCallback(
|
|
403
|
+
(isLanguageOverlayVisible = false) =>
|
|
404
|
+
(event) => {
|
|
405
|
+
const { eventType } = event;
|
|
395
406
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
407
|
+
if (!isLanguageOverlayVisible && eventType === "menu") {
|
|
408
|
+
close();
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
[close]
|
|
412
|
+
);
|
|
400
413
|
|
|
401
414
|
// Effects
|
|
402
415
|
useEffect(() => {
|
|
@@ -509,16 +522,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
509
522
|
}
|
|
510
523
|
}, [isAudioContent]);
|
|
511
524
|
|
|
512
|
-
// Needs to handle back button on Apple TV
|
|
513
|
-
// https://github.com/facebook/react-native/issues/18930
|
|
514
|
-
useEffect(() => {
|
|
515
|
-
TVMenuControl?.enableTVMenuKey();
|
|
516
|
-
|
|
517
|
-
return () => {
|
|
518
|
-
TVMenuControl?.disableTVMenuKey();
|
|
519
|
-
};
|
|
520
|
-
}, []);
|
|
521
|
-
|
|
522
525
|
useEffect(() => {
|
|
523
526
|
playerEvent("source_changed", { item });
|
|
524
527
|
|
|
@@ -565,8 +568,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
565
568
|
const isInlineTV = isInlineTVUtil(screenData);
|
|
566
569
|
|
|
567
570
|
const inline =
|
|
568
|
-
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
569
|
-
|
|
571
|
+
[VideoModalMode.MAXIMIZED, VideoModalMode.MINIMIZED].includes(
|
|
572
|
+
mode as any
|
|
573
|
+
) || isInlineTV;
|
|
570
574
|
|
|
571
575
|
const value = React.useMemo(
|
|
572
576
|
() => ({ playerId: state.playerId }),
|
|
@@ -587,7 +591,11 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
587
591
|
);
|
|
588
592
|
}
|
|
589
593
|
|
|
590
|
-
if (
|
|
594
|
+
if (
|
|
595
|
+
screen_background_color &&
|
|
596
|
+
mode !== VideoModalMode.FULLSCREEN &&
|
|
597
|
+
isTV()
|
|
598
|
+
) {
|
|
591
599
|
updatedStyles.playerScreen.backgroundColor = screen_background_color;
|
|
592
600
|
}
|
|
593
601
|
|
|
@@ -617,6 +625,8 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
617
625
|
playNextData,
|
|
618
626
|
};
|
|
619
627
|
|
|
628
|
+
const pointerEventsProp = mode === "MINIMIZED" ? "box-none" : "auto";
|
|
629
|
+
|
|
620
630
|
return (
|
|
621
631
|
<PlayerStateContext.Provider value={value}>
|
|
622
632
|
<PlayerContainerContextProvider
|
|
@@ -627,9 +637,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
627
637
|
<PlayerContainerContext.Consumer>
|
|
628
638
|
{(context) => (
|
|
629
639
|
<TVEventHandlerComponent
|
|
630
|
-
tvEventHandler={(
|
|
631
|
-
|
|
632
|
-
}
|
|
640
|
+
tvEventHandler={playerRemoteHandler(
|
|
641
|
+
context.isLanguageOverlayVisible
|
|
642
|
+
)}
|
|
633
643
|
>
|
|
634
644
|
<FocusableGroup
|
|
635
645
|
id={FocusableGroupMainContainerId}
|
|
@@ -637,14 +647,17 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
637
647
|
preferredFocus
|
|
638
648
|
shouldUsePreferredFocus
|
|
639
649
|
groupId={groupId}
|
|
650
|
+
pointerEvents={pointerEventsProp}
|
|
640
651
|
>
|
|
641
652
|
{/* Video player and components */}
|
|
642
653
|
<View
|
|
643
654
|
style={styles.playerScreen}
|
|
644
655
|
testID={"player-screen-container"}
|
|
656
|
+
pointerEvents={pointerEventsProp}
|
|
645
657
|
>
|
|
646
658
|
{/* Player container */}
|
|
647
659
|
<View
|
|
660
|
+
pointerEvents={pointerEventsProp}
|
|
648
661
|
style={[
|
|
649
662
|
styles.playerWrapper,
|
|
650
663
|
// eslint-disable-next-line react-native/no-inline-styles, react-native/no-color-literals
|
|
@@ -8,7 +8,7 @@ export const withTvEventHandler = (Component) => {
|
|
|
8
8
|
return function WithTVEventHandler(props) {
|
|
9
9
|
const navigator = useNavigation();
|
|
10
10
|
|
|
11
|
-
const remoteHandler = (
|
|
11
|
+
const remoteHandler = (event) => {
|
|
12
12
|
const { eventType } = event;
|
|
13
13
|
|
|
14
14
|
const canGoBack = navigator.canGoBack();
|
|
@@ -159,6 +159,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
159
159
|
>
|
|
160
160
|
<View>
|
|
161
161
|
<View
|
|
162
|
+
onFocusCapture={[Function]}
|
|
162
163
|
onLayout={[Function]}
|
|
163
164
|
style={null}
|
|
164
165
|
>
|
|
@@ -174,6 +175,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
174
175
|
</View>
|
|
175
176
|
</View>
|
|
176
177
|
<View
|
|
178
|
+
onFocusCapture={[Function]}
|
|
177
179
|
onLayout={[Function]}
|
|
178
180
|
style={null}
|
|
179
181
|
>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { makeListOf } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
2
|
+
import { isFirstComponentGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
3
|
+
import { once } from "ramda";
|
|
4
|
+
|
|
5
|
+
const INITIAL_NUMBER_TO_LOAD = 3;
|
|
6
|
+
|
|
7
|
+
// Infer the values of COMPONENT_LOADING_STATE as a type
|
|
8
|
+
type ComponentLoadingState =
|
|
9
|
+
(typeof COMPONENT_LOADING_STATE)[keyof typeof COMPONENT_LOADING_STATE];
|
|
10
|
+
|
|
11
|
+
export const COMPONENT_LOADING_STATE = {
|
|
12
|
+
UNKNOWN: "UNKNOWN",
|
|
13
|
+
LOADED_WITH_SUCCESS: "LOADED_WITH_SUCCESS",
|
|
14
|
+
LOADED_WITH_FAILURE: "LOADED_WITH_FAILURE",
|
|
15
|
+
} as const;
|
|
16
|
+
|
|
17
|
+
// Function to get the number of loaded components
|
|
18
|
+
const getNumberOfLoaded = (states: ComponentLoadingState[]): number => {
|
|
19
|
+
return states.filter((value) => value !== COMPONENT_LOADING_STATE.UNKNOWN)
|
|
20
|
+
.length;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getNumberOfComponentsWaitToLoadBeforePresent = (
|
|
24
|
+
componentsToRender: ZappUIComponent[]
|
|
25
|
+
): number => {
|
|
26
|
+
// when Gallery is the first component, no need to wait the others
|
|
27
|
+
if (isFirstComponentGallery(componentsToRender)) {
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Math.min(INITIAL_NUMBER_TO_LOAD, componentsToRender.length);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export class ScreenRevealManager {
|
|
35
|
+
public numberOfComponentsWaitToLoadBeforePresent: number;
|
|
36
|
+
private renderingState: Array<ComponentLoadingState>;
|
|
37
|
+
private callback: Callback;
|
|
38
|
+
|
|
39
|
+
constructor(componentsToRender: ZappUIComponent[], callback: Callback) {
|
|
40
|
+
this.numberOfComponentsWaitToLoadBeforePresent =
|
|
41
|
+
getNumberOfComponentsWaitToLoadBeforePresent(componentsToRender);
|
|
42
|
+
|
|
43
|
+
this.renderingState = makeListOf<ComponentLoadingState>(
|
|
44
|
+
COMPONENT_LOADING_STATE.UNKNOWN,
|
|
45
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
this.callback = once(callback);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
onLoadFinished = (index: number): void => {
|
|
52
|
+
this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_SUCCESS;
|
|
53
|
+
|
|
54
|
+
if (
|
|
55
|
+
getNumberOfLoaded(this.renderingState) >=
|
|
56
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
57
|
+
) {
|
|
58
|
+
this.setIsReadyToShow();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
onLoadFailed = (index: number): void => {
|
|
63
|
+
this.renderingState[index] = COMPONENT_LOADING_STATE.LOADED_WITH_FAILURE;
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
getNumberOfLoaded(this.renderingState) >=
|
|
67
|
+
this.numberOfComponentsWaitToLoadBeforePresent
|
|
68
|
+
) {
|
|
69
|
+
this.setIsReadyToShow();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
setIsReadyToShow = (): void => {
|
|
74
|
+
this.callback();
|
|
75
|
+
};
|
|
76
|
+
}
|