@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 15.1.0-rc.2
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.ios.ts +2 -12
- package/Components/Cell/FocusableWrapper.tsx +0 -3
- package/Components/Cell/TvOSCellComponent.tsx +0 -5
- package/Components/Focusable/Focusable.tsx +2 -4
- package/Components/Focusable/FocusableTvOS.tsx +1 -18
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +0 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +1 -30
- package/Components/GeneralContentScreen/GeneralContentScreen.tsx +39 -28
- package/Components/GeneralContentScreen/__tests__/GeneralContentScreen.test.tsx +104 -0
- package/Components/GeneralContentScreen/utils/__tests__/getScreenDataSource.test.ts +19 -0
- package/Components/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +1 -1
- package/Components/GeneralContentScreen/utils/getScreenDataSource.ts +9 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +24 -42
- package/Components/HandlePlayable/utils.ts +31 -0
- package/Components/HookRenderer/HookRenderer.tsx +40 -10
- package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
- package/Components/Layout/TV/LayoutBackground.tsx +2 -5
- package/Components/Layout/TV/ScreenContainer.tsx +6 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -0
- package/Components/Layout/TV/index.tsx +4 -3
- package/Components/Layout/TV/index.web.tsx +4 -3
- package/Components/LinkHandler/LinkHandler.tsx +2 -2
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +10 -4
- package/Components/MasterCell/DefaultComponents/Image/Image.android.tsx +1 -5
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +3 -11
- package/Components/MasterCell/DefaultComponents/Image/Image.web.tsx +1 -9
- package/Components/MasterCell/DefaultComponents/Image/hooks/useImage.ts +14 -15
- package/Components/MasterCell/DefaultComponents/LiveImage/__tests__/prepareEntry.test.ts +352 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/executePreloadHooks.ts +136 -0
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +34 -16
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +6 -7
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +2 -6
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +11 -233
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +15 -19
- package/Components/Navigator/StackNavigator.tsx +6 -0
- package/Components/OfflineHandler/NotificationView/NotificationView.tsx +2 -2
- package/Components/OfflineHandler/NotificationView/__tests__/index.test.tsx +18 -17
- package/Components/OfflineHandler/__tests__/index.test.tsx +18 -27
- package/Components/PlayerContainer/PlayerContainer.tsx +14 -32
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +3 -4
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +9 -3
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/TV/River.tsx +14 -31
- package/Components/River/TV/index.tsx +4 -8
- package/Components/River/TV/withTVEventHandler.tsx +36 -0
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +0 -1
- package/Components/River/__tests__/componentsMap.test.js +0 -38
- package/Components/Screen/TV/index.web.tsx +2 -4
- package/Components/Screen/__tests__/Screen.test.tsx +43 -65
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +44 -68
- package/Components/Screen/hooks.ts +76 -5
- package/Components/Screen/index.tsx +10 -3
- package/Components/Screen/orientationHandler.ts +3 -3
- package/Components/ScreenFeedLoader/ScreenFeedLoader.tsx +46 -0
- package/Components/ScreenFeedLoader/__tests__/ScreenFeedLoader.test.tsx +94 -0
- package/Components/ScreenFeedLoader/index.ts +1 -0
- package/Components/ScreenResolver/__tests__/screenResolver.test.js +24 -0
- package/Components/ScreenResolver/hooks/index.ts +3 -0
- package/Components/ScreenResolver/hooks/useGetComponent.ts +15 -0
- package/Components/ScreenResolver/hooks/useScreenComponentResolver.tsx +90 -0
- package/Components/ScreenResolver/index.tsx +9 -115
- package/Components/ScreenResolver/utils/__tests__/getScreenTypeProps.test.ts +45 -0
- package/Components/ScreenResolver/utils/getScreenTypeProps.ts +43 -0
- package/Components/ScreenResolver/utils/index.ts +1 -0
- package/Components/ScreenResolver/withDefaultScreenContext.tsx +16 -0
- package/Components/ScreenResolverFeedProvider/ScreenResolverFeedProvider.tsx +25 -0
- package/Components/ScreenResolverFeedProvider/__tests__/ScreenResolverFeedProvider.test.tsx +44 -0
- package/Components/ScreenResolverFeedProvider/index.ts +1 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +8 -40
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +69 -86
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +4 -1
- package/Components/Tabs/TabContent.tsx +4 -7
- package/Components/Transitioner/Scene.tsx +9 -15
- package/Components/Transitioner/index.js +3 -3
- package/Components/VideoLive/LiveImageManager.ts +199 -54
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +5 -5
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +7 -15
- package/Components/VideoModal/utils.ts +9 -12
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +6 -4
- package/Components/ZappFrameworkComponents/BarView/__tests__/BarView.test.tsx +2 -2
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/index.js +1 -1
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +64 -26
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Decorators/Analytics/index.tsx +5 -6
- package/Decorators/ConfigurationWrapper/__tests__/__snapshots__/withConfigurationProvider.test.tsx.snap +0 -1
- package/Decorators/ConfigurationWrapper/const.ts +0 -1
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -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/index.js +19 -0
- package/package.json +5 -5
- package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
- package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +0 -101
- package/Components/River/TV/utils/__tests__/toStringOrEmpty.test.ts +0 -30
- package/Components/River/TV/utils/index.ts +0 -4
- package/Components/River/TV/withFocusableGroupForContent.tsx +0 -71
- package/Helpers/DataSourceHelper/__tests__/itemLimitForData.test.ts +0 -80
- package/Helpers/DataSourceHelper/index.ts +0 -19
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
|
@@ -22,7 +22,6 @@ type Props = {
|
|
|
22
22
|
onFocus?: FocusManager.FocusEventCB;
|
|
23
23
|
onBlur?: FocusManager.FocusEventCB;
|
|
24
24
|
selected?: boolean;
|
|
25
|
-
skipFocusManagerRegistration?: boolean;
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
export class BaseFocusable<
|
|
@@ -62,14 +61,10 @@ export class BaseFocusable<
|
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
componentDidMount() {
|
|
65
|
-
const { id
|
|
64
|
+
const { id } = this.props;
|
|
66
65
|
const component = this;
|
|
67
66
|
this.node = this.ref.current;
|
|
68
67
|
|
|
69
|
-
if (skipFocusManagerRegistration) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
68
|
focusManager.register({
|
|
74
69
|
id,
|
|
75
70
|
component: component,
|
|
@@ -123,12 +118,7 @@ export class BaseFocusable<
|
|
|
123
118
|
|
|
124
119
|
componentWillUnmount() {
|
|
125
120
|
this._isMounted = false;
|
|
126
|
-
const { id
|
|
127
|
-
|
|
128
|
-
if (skipFocusManagerRegistration) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
|
|
121
|
+
const { id } = this.props;
|
|
132
122
|
focusManager.unregister(id, { group: this.isGroup || false });
|
|
133
123
|
}
|
|
134
124
|
|
|
@@ -10,7 +10,6 @@ type Props = {
|
|
|
10
10
|
children: (focused: boolean) => React.ReactNode;
|
|
11
11
|
onFocus: (arg1: any, index?: number) => void;
|
|
12
12
|
onBlur: Callback;
|
|
13
|
-
skipFocusManagerRegistration?: boolean;
|
|
14
13
|
};
|
|
15
14
|
|
|
16
15
|
export const FocusableWrapper = ({
|
|
@@ -21,7 +20,6 @@ export const FocusableWrapper = ({
|
|
|
21
20
|
applyWrapper,
|
|
22
21
|
onFocus,
|
|
23
22
|
onBlur,
|
|
24
|
-
skipFocusManagerRegistration,
|
|
25
23
|
}: Props) => {
|
|
26
24
|
if (applyWrapper) {
|
|
27
25
|
return (
|
|
@@ -36,7 +34,6 @@ export const FocusableWrapper = ({
|
|
|
36
34
|
// @ts-ignore
|
|
37
35
|
offsetUpdater={noop}
|
|
38
36
|
isFocusable
|
|
39
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
40
37
|
>
|
|
41
38
|
{(focused) => children(focused)}
|
|
42
39
|
</Focusable>
|
|
@@ -80,7 +80,6 @@ type Props = {
|
|
|
80
80
|
componentsMapOffset: number;
|
|
81
81
|
applyFocusableWrapper: boolean;
|
|
82
82
|
hasFocusableInside: boolean;
|
|
83
|
-
skipFocusManagerRegistration?: boolean;
|
|
84
83
|
};
|
|
85
84
|
|
|
86
85
|
type State = {
|
|
@@ -267,7 +266,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
267
266
|
behavior,
|
|
268
267
|
applyFocusableWrapper,
|
|
269
268
|
hasFocusableInside,
|
|
270
|
-
skipFocusManagerRegistration,
|
|
271
269
|
} = this.props;
|
|
272
270
|
|
|
273
271
|
const { id } = item;
|
|
@@ -293,7 +291,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
293
291
|
onFocus={handleFocus}
|
|
294
292
|
onBlur={onBlur || this.onBlur}
|
|
295
293
|
applyWrapper={applyFocusableWrapper}
|
|
296
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
297
294
|
>
|
|
298
295
|
{(focused) => (
|
|
299
296
|
<CellWithFocusable
|
|
@@ -308,7 +305,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
308
305
|
focused={focused || this.props.focused}
|
|
309
306
|
behavior={behavior}
|
|
310
307
|
isFocusable={isFocusable}
|
|
311
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
312
308
|
/>
|
|
313
309
|
)}
|
|
314
310
|
</FocusableWrapper>
|
|
@@ -331,7 +327,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
331
327
|
offsetUpdater={offsetUpdater}
|
|
332
328
|
style={baseCellStyles}
|
|
333
329
|
isFocusable={isFocusable}
|
|
334
|
-
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
335
330
|
>
|
|
336
331
|
{(focused) => (
|
|
337
332
|
<FocusableCell
|
|
@@ -8,8 +8,6 @@ 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/zapp-react-native-utils/searchUtils";
|
|
12
|
-
|
|
13
11
|
type Props = {
|
|
14
12
|
initialFocus?: boolean;
|
|
15
13
|
id: string;
|
|
@@ -108,7 +106,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
108
106
|
onMouseEnter() {
|
|
109
107
|
const { id } = this.props;
|
|
110
108
|
|
|
111
|
-
if (
|
|
109
|
+
if (id !== "search_input_group_id") {
|
|
112
110
|
this.mouse = true;
|
|
113
111
|
this.props?.handleFocus?.({ mouse: true });
|
|
114
112
|
|
|
@@ -122,7 +120,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
122
120
|
onMouseLeave() {
|
|
123
121
|
const { id } = this.props;
|
|
124
122
|
|
|
125
|
-
if (
|
|
123
|
+
if (id !== "search_input_group_id") {
|
|
126
124
|
this.mouse = false;
|
|
127
125
|
this.blur(null);
|
|
128
126
|
}
|
|
@@ -10,12 +10,8 @@ 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";
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
emitFocused,
|
|
17
|
-
emitNativeRegistered,
|
|
18
|
-
} from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
14
|
+
function noop() {}
|
|
19
15
|
|
|
20
16
|
type Props = {
|
|
21
17
|
id: string;
|
|
@@ -43,7 +39,6 @@ type Props = {
|
|
|
43
39
|
hasReceivedFocus: () => void;
|
|
44
40
|
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
45
41
|
style: ViewStyle;
|
|
46
|
-
skipFocusManagerRegistration?: boolean;
|
|
47
42
|
};
|
|
48
43
|
|
|
49
44
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -58,7 +53,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
58
53
|
this.nextFocusableReactTags = {};
|
|
59
54
|
this.preferredFocus = this.preferredFocus.bind(this);
|
|
60
55
|
this.measureView = this.measureView.bind(this);
|
|
61
|
-
this.onRegistered = this.onRegistered.bind(this);
|
|
62
56
|
}
|
|
63
57
|
|
|
64
58
|
/**
|
|
@@ -90,9 +84,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
90
84
|
});
|
|
91
85
|
}
|
|
92
86
|
|
|
93
|
-
const id: string = nativeEvent.itemID;
|
|
94
|
-
emitFocused(id);
|
|
95
|
-
|
|
96
87
|
onFocus(nativeEvent);
|
|
97
88
|
}
|
|
98
89
|
|
|
@@ -178,13 +169,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
178
169
|
});
|
|
179
170
|
}
|
|
180
171
|
|
|
181
|
-
onRegistered({ nativeEvent }) {
|
|
182
|
-
const groupId = nativeEvent?.groupId;
|
|
183
|
-
const id = nativeEvent?.itemId;
|
|
184
|
-
|
|
185
|
-
emitNativeRegistered({ id, groupId, isGroup: false });
|
|
186
|
-
}
|
|
187
|
-
|
|
188
172
|
render() {
|
|
189
173
|
const {
|
|
190
174
|
children,
|
|
@@ -219,7 +203,6 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
219
203
|
focusable={isFocusable}
|
|
220
204
|
{...this.nextFocusableReactTags}
|
|
221
205
|
{...otherProps}
|
|
222
|
-
onRegistered={this.onRegistered}
|
|
223
206
|
>
|
|
224
207
|
{typeof children === "function" ? children(focused) : children}
|
|
225
208
|
</FocusableItemNative>
|
|
@@ -2,10 +2,6 @@ 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";
|
|
9
5
|
|
|
10
6
|
const { log_verbose } = createLogger({
|
|
11
7
|
subsystem: "General",
|
|
@@ -37,16 +33,9 @@ type Props = {
|
|
|
37
33
|
screenData: { screenId: string; parentScreenId: string };
|
|
38
34
|
};
|
|
39
35
|
|
|
40
|
-
class
|
|
36
|
+
export class FocusableGroup extends BaseFocusable<Props> {
|
|
41
37
|
public readonly isGroup: boolean = true;
|
|
42
38
|
|
|
43
|
-
onRegistered = ({ nativeEvent }) => {
|
|
44
|
-
const groupId = nativeEvent?.groupId;
|
|
45
|
-
const id = nativeEvent?.itemId;
|
|
46
|
-
|
|
47
|
-
emitNativeRegistered({ id, groupId, isGroup: true });
|
|
48
|
-
};
|
|
49
|
-
|
|
50
39
|
render() {
|
|
51
40
|
const {
|
|
52
41
|
children,
|
|
@@ -79,27 +68,9 @@ class FocusableGroupComponent extends BaseFocusable<Props> {
|
|
|
79
68
|
onGroupBlur={onGroupBlur}
|
|
80
69
|
style={style}
|
|
81
70
|
{...otherProps}
|
|
82
|
-
onRegistered={this.onRegistered}
|
|
83
71
|
>
|
|
84
72
|
{children}
|
|
85
73
|
</FocusableGroupNative>
|
|
86
74
|
);
|
|
87
75
|
}
|
|
88
76
|
}
|
|
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);
|
|
@@ -12,12 +12,26 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
|
12
12
|
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
13
13
|
import { ScreenTrackedViewPositionsContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenTrackedViewPositionsContext";
|
|
14
14
|
import { useEventAlerts } from "./utils/useEventAlerts";
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
import {
|
|
16
|
+
selectRiverById,
|
|
17
|
+
useAppSelector,
|
|
18
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
19
|
+
import { getScreenDataSource } from "./utils/getScreenDataSource";
|
|
20
|
+
import { ScreenResolverFeedProvider } from "../ScreenResolverFeedProvider/ScreenResolverFeedProvider";
|
|
21
|
+
|
|
22
|
+
const { log_debug } = createLogger({
|
|
17
23
|
category: "ScreenContainer",
|
|
18
24
|
subsystem: "General",
|
|
19
25
|
});
|
|
20
26
|
|
|
27
|
+
/** Provides screen-feed from general-screen configuration (if defined) */
|
|
28
|
+
const useFeedData = (id) => {
|
|
29
|
+
const river = useAppSelector((state) => selectRiverById(state, id));
|
|
30
|
+
const feedData = getScreenDataSource(river);
|
|
31
|
+
|
|
32
|
+
return feedData;
|
|
33
|
+
};
|
|
34
|
+
|
|
21
35
|
export const GeneralContentScreen = ({
|
|
22
36
|
feed,
|
|
23
37
|
screenId,
|
|
@@ -54,20 +68,15 @@ export const GeneralContentScreen = ({
|
|
|
54
68
|
useEffect(() => {
|
|
55
69
|
if (!riverActionProvidersReady) {
|
|
56
70
|
if (actionsInitialStateSetters.length > 0) {
|
|
57
|
-
log_info(
|
|
58
|
-
"ScreenContainer: starting to check river action providers to initialize",
|
|
59
|
-
{ actionsInitialStateSetters }
|
|
60
|
-
);
|
|
61
|
-
|
|
62
71
|
allSettled(actionsInitialStateSetters).finally(() => {
|
|
63
|
-
|
|
72
|
+
log_debug(
|
|
64
73
|
"ScreenContainer: action provider ready, completed. Starting to present screen"
|
|
65
74
|
);
|
|
66
75
|
|
|
67
76
|
setRiverActionProvidersReady(true);
|
|
68
77
|
});
|
|
69
78
|
} else {
|
|
70
|
-
|
|
79
|
+
log_debug(
|
|
71
80
|
"ScreenContainer: no action provider to check, completed. Starting to present screen"
|
|
72
81
|
);
|
|
73
82
|
|
|
@@ -108,24 +117,26 @@ export const GeneralContentScreen = ({
|
|
|
108
117
|
if (!isReady || isNilOrEmpty(components || uiComponents)) return null;
|
|
109
118
|
|
|
110
119
|
return (
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
<ScreenResolverFeedProvider id={screenId} useFeedData={useFeedData}>
|
|
121
|
+
<ScreenTrackedViewPositionsContext.Provider>
|
|
122
|
+
<CellTapContext.Provider value={contextValue}>
|
|
123
|
+
<ComponentsMap
|
|
124
|
+
feed={feed}
|
|
125
|
+
riverId={screenId}
|
|
126
|
+
groupId={groupId || `general-content-screen-${screenId}`}
|
|
127
|
+
riverComponents={components || uiComponents}
|
|
128
|
+
scrollViewExtraProps={scrollViewExtraProps}
|
|
129
|
+
getStaticComponentFeed={getStaticComponentFeed}
|
|
130
|
+
extraAnchorPointYOffset={extraAnchorPointYOffset}
|
|
131
|
+
isScreenWrappedInContainer={isScreenWrappedInContainer}
|
|
132
|
+
parentFocus={parentFocus}
|
|
133
|
+
focused={focused}
|
|
134
|
+
containerHeight={containerHeight}
|
|
135
|
+
preferredFocus={preferredFocus}
|
|
136
|
+
{...componentsMapExtraProps}
|
|
137
|
+
/>
|
|
138
|
+
</CellTapContext.Provider>
|
|
139
|
+
</ScreenTrackedViewPositionsContext.Provider>
|
|
140
|
+
</ScreenResolverFeedProvider>
|
|
130
141
|
);
|
|
131
142
|
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
import { GeneralContentScreen } from "../GeneralContentScreen";
|
|
4
|
+
|
|
5
|
+
const mockUseAppSelector = jest.fn();
|
|
6
|
+
const mockSelectRiverById = jest.fn();
|
|
7
|
+
const mockProviderSpy = jest.fn();
|
|
8
|
+
|
|
9
|
+
jest.mock("../../River/ComponentsMap", () => ({
|
|
10
|
+
ComponentsMap: () => {
|
|
11
|
+
const React = require("react");
|
|
12
|
+
const { View } = require("react-native");
|
|
13
|
+
|
|
14
|
+
return <View testID="components-map" />;
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/actions", () => ({
|
|
19
|
+
useActions: jest.fn(() => jest.fn()),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
jest.mock("../utils", () => ({
|
|
23
|
+
logger: { warn: jest.fn() },
|
|
24
|
+
whenMatchingType: jest.fn((_type, value) => value),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/layout", () => ({
|
|
28
|
+
useLayoutVersion: jest.fn(() => false),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
jest.mock(
|
|
32
|
+
"@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData",
|
|
33
|
+
() => ({
|
|
34
|
+
useScreenData: jest.fn(() => ({
|
|
35
|
+
ui_components: [{ id: "ui-component" }],
|
|
36
|
+
general: {},
|
|
37
|
+
})),
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
jest.mock("../utils/useCurationAPI", () => ({
|
|
42
|
+
useCurationAPI: jest.fn(() => [{ id: "curation-component" }]),
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
|
|
46
|
+
useRiverInitialState: jest.fn(() => []),
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
jest.mock("../utils/useEventAlerts", () => ({
|
|
50
|
+
useEventAlerts: jest.fn(),
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
jest.mock("@applicaster/zapp-react-native-redux", () => ({
|
|
54
|
+
useAppSelector: (...args) => mockUseAppSelector(...args),
|
|
55
|
+
selectRiverById: (...args) => mockSelectRiverById(...args),
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
jest.mock("../utils/getScreenDataSource", () => ({
|
|
59
|
+
getScreenDataSource: jest.fn(() => ({
|
|
60
|
+
source: "https://feed",
|
|
61
|
+
mapping: {},
|
|
62
|
+
})),
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
jest.mock(
|
|
66
|
+
"../../ScreenResolverFeedProvider/ScreenResolverFeedProvider",
|
|
67
|
+
() => ({
|
|
68
|
+
ScreenResolverFeedProvider: ({ id, useFeedData, children }) => {
|
|
69
|
+
const React = require("react");
|
|
70
|
+
const { View } = require("react-native");
|
|
71
|
+
|
|
72
|
+
mockProviderSpy(id, useFeedData);
|
|
73
|
+
useFeedData(id);
|
|
74
|
+
|
|
75
|
+
return <View testID="screen-resolver-feed-provider">{children}</View>;
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
describe("GeneralContentScreen", () => {
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
jest.clearAllMocks();
|
|
83
|
+
mockUseAppSelector.mockImplementation((selector) => selector({}));
|
|
84
|
+
mockSelectRiverById.mockReturnValue({ id: "screen-1" });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("wraps content with ScreenResolverFeedProvider and renders ComponentsMap", () => {
|
|
88
|
+
const { getByTestId } = render(
|
|
89
|
+
<GeneralContentScreen
|
|
90
|
+
screenId="screen-1"
|
|
91
|
+
feed={null}
|
|
92
|
+
components={[{ id: "component-1" }]}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(getByTestId("screen-resolver-feed-provider")).toBeDefined();
|
|
97
|
+
expect(getByTestId("components-map")).toBeDefined();
|
|
98
|
+
|
|
99
|
+
expect(mockProviderSpy).toHaveBeenCalledWith(
|
|
100
|
+
"screen-1",
|
|
101
|
+
expect.any(Function)
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getScreenDataSource } from "../getScreenDataSource";
|
|
2
|
+
|
|
3
|
+
describe("getScreenDataSource", () => {
|
|
4
|
+
it("returns screen_feed data when present", () => {
|
|
5
|
+
const result = getScreenDataSource({
|
|
6
|
+
data: {
|
|
7
|
+
screen_feed: {
|
|
8
|
+
source: "https://feed",
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(result).toEqual({ source: "https://feed" });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns undefined when screen_feed is missing", () => {
|
|
17
|
+
expect(getScreenDataSource({ data: {} })).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { get } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
|
+
|
|
3
|
+
const lookupPath = ["data", "screen_feed"];
|
|
4
|
+
|
|
5
|
+
export const getScreenDataSource = (
|
|
6
|
+
screenData: any
|
|
7
|
+
): Option<ZappDataSource> => {
|
|
8
|
+
return get(screenData, lookupPath) as ZappDataSource | undefined;
|
|
9
|
+
};
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
useContentTypes,
|
|
5
|
-
usePlugins,
|
|
6
|
-
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
7
|
-
import {
|
|
8
|
-
useDimensions,
|
|
9
|
-
useIsTablet as isTablet,
|
|
10
|
-
useNavigation,
|
|
11
|
-
useRivers,
|
|
12
|
-
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
2
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
13
4
|
|
|
14
5
|
import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
15
6
|
import { PlayerContainer } from "../PlayerContainer";
|
|
16
7
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
8
|
import { ViewStyle } from "react-native";
|
|
18
|
-
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
19
9
|
import { findCastPlugin, getPlayer } from "./utils";
|
|
10
|
+
import { useWaitForValidOrientation } from "../Screen/hooks";
|
|
20
11
|
|
|
21
12
|
type Props = {
|
|
22
13
|
item: ZappEntry;
|
|
@@ -31,23 +22,18 @@ type PlayableComponent = {
|
|
|
31
22
|
Component: React.ComponentType<any>;
|
|
32
23
|
};
|
|
33
24
|
|
|
34
|
-
const dimensionsContext: "window" | "screen" = platformSelect({
|
|
35
|
-
android_tv: "window",
|
|
36
|
-
amazon: "window",
|
|
37
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
38
|
-
default: isTablet() ? "window" : "screen", // on tablet, window represents correct values, on phone it's not as the screen could be rotated
|
|
39
|
-
});
|
|
40
|
-
|
|
41
25
|
export function HandlePlayable({
|
|
42
26
|
item,
|
|
43
27
|
isModal,
|
|
44
28
|
mode,
|
|
45
29
|
groupId,
|
|
46
30
|
}: Props): React.ReactElement | null {
|
|
47
|
-
const plugins =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
const { plugins, contentTypes, rivers, appData } = usePickFromState([
|
|
32
|
+
"plugins",
|
|
33
|
+
"contentTypes",
|
|
34
|
+
"rivers",
|
|
35
|
+
"appData",
|
|
36
|
+
]);
|
|
51
37
|
|
|
52
38
|
const { closeVideoModal } = useNavigation();
|
|
53
39
|
|
|
@@ -97,27 +83,23 @@ export function HandlePlayable({
|
|
|
97
83
|
});
|
|
98
84
|
}, [casting]);
|
|
99
85
|
|
|
100
|
-
const { width: screenWidth, height: screenHeight } =
|
|
101
|
-
useDimensions(dimensionsContext);
|
|
102
|
-
|
|
103
86
|
const modalSize = useModalSize();
|
|
104
87
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
);
|
|
88
|
+
const isOrientationReady = useWaitForValidOrientation();
|
|
89
|
+
|
|
90
|
+
const style = React.useMemo(() => {
|
|
91
|
+
const isFullScreenReady =
|
|
92
|
+
mode === "PIP" || (mode === "FULLSCREEN" && isOrientationReady);
|
|
93
|
+
|
|
94
|
+
const getDimensionValue = (value: string | number) => {
|
|
95
|
+
return isModal ? value : isFullScreenReady ? "100%" : 0; // do not show player, until full screen mode is ready
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
width: getDimensionValue(modalSize.width),
|
|
100
|
+
height: getDimensionValue(modalSize.height),
|
|
101
|
+
} as ViewStyle;
|
|
102
|
+
}, [modalSize, isModal, mode, isOrientationReady]);
|
|
121
103
|
|
|
122
104
|
const Component = playable?.Component;
|
|
123
105
|
|
|
@@ -5,6 +5,14 @@ import {
|
|
|
5
5
|
|
|
6
6
|
import { CHROMECAST_PLUGIN_ID, YOUTUBE_PLUGIN_ID } from "./const";
|
|
7
7
|
import { omit } from "@applicaster/zapp-react-native-utils/utils";
|
|
8
|
+
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
9
|
+
|
|
10
|
+
const { Logger } = getXray();
|
|
11
|
+
|
|
12
|
+
const logger = new Logger(
|
|
13
|
+
"QuickBrick",
|
|
14
|
+
"packages/zapp-react-native-ui-components/Components/HandlePlayable"
|
|
15
|
+
);
|
|
8
16
|
|
|
9
17
|
const getPlayerModuleProperties = (PlayerModule: ZappPlugin) => {
|
|
10
18
|
if (PlayerModule?.Component && typeof PlayerModule.Component === "object") {
|
|
@@ -52,10 +60,25 @@ export const getPlayer = (
|
|
|
52
60
|
if (type) {
|
|
53
61
|
PlayerModule = findPluginByIdentifier(type, plugins)?.module;
|
|
54
62
|
|
|
63
|
+
if (!PlayerModule) {
|
|
64
|
+
logger.error({
|
|
65
|
+
message:
|
|
66
|
+
"PlayerModule is undefined – type mapping may be wrong or type not set for player",
|
|
67
|
+
data: {
|
|
68
|
+
type,
|
|
69
|
+
screen_id,
|
|
70
|
+
item_type_value: item?.type?.value,
|
|
71
|
+
},
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return [null, {}];
|
|
75
|
+
}
|
|
76
|
+
|
|
55
77
|
return getPlayerWithModuleProperties(PlayerModule);
|
|
56
78
|
}
|
|
57
79
|
}
|
|
58
80
|
|
|
81
|
+
// TODO: Probably should be removed, Youtube plugin is deprecated
|
|
59
82
|
if (item?.content?.type === "youtube-id") {
|
|
60
83
|
PlayerModule = findYoutubePlugin(plugins)?.module;
|
|
61
84
|
|
|
@@ -70,5 +93,13 @@ export const getPlayer = (
|
|
|
70
93
|
)
|
|
71
94
|
);
|
|
72
95
|
|
|
96
|
+
if (!PlayerModule) {
|
|
97
|
+
logger.error({
|
|
98
|
+
message: "PlayerModule is undefined – playable plugin not found",
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
return [null, {}];
|
|
102
|
+
}
|
|
103
|
+
|
|
73
104
|
return getPlayerWithModuleProperties(PlayerModule);
|
|
74
105
|
};
|