@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 15.1.0-alpha.1852552014
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/BackgroundImage/BackgroundImage.tv.android.tsx +28 -0
- package/Components/BackgroundImage/BackgroundImage.tv.ios.tsx +24 -0
- package/Components/BackgroundImage/BackgroundImage.tv.web.tsx +42 -0
- package/Components/BackgroundImage/index.ts +8 -0
- package/Components/BaseFocusable/index.ios.ts +2 -12
- package/Components/Cell/FocusableWrapper.tsx +0 -3
- package/Components/Cell/TvOSCellComponent.tsx +0 -5
- package/Components/CellRendererResolver/index.ts +1 -1
- package/Components/ComponentResolver/__tests__/componentResolver.test.js +1 -1
- 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 +12 -37
- 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/FullWidthRow.tsx +38 -0
- package/Components/Layout/TV/ScreenContainer.tsx +11 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +5 -1
- package/Components/Layout/TV/index.tsx +6 -6
- package/Components/Layout/TV/index.web.tsx +6 -6
- 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/MasterCell/dataAdapter.ts +15 -5
- package/Components/MasterCell/index.tsx +10 -1
- package/Components/MasterCell/utils/__tests__/resolveColor.test.js +169 -132
- package/Components/MasterCell/utils/__tests__/resolveColorForProp.test.js +92 -0
- package/Components/MasterCell/utils/index.ts +89 -46
- 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 +20 -34
- package/Components/PlayerContainer/__tests__/PlayerContainer.test.tsx +286 -0
- 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 -16
- package/Components/River/__tests__/componentsMap.test.js +0 -38
- package/Components/Screen/TV/hooks/__tests__/useAfterPaint.test.ts +60 -0
- package/Components/Screen/TV/hooks/index.ts +2 -0
- package/Components/Screen/TV/hooks/useAfterPaint.ts +23 -0
- package/Components/Screen/TV/index.web.tsx +18 -11
- 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 +18 -7
- 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/Overlay.tsx +34 -0
- package/Components/ScreenRevealManager/ScreenRevealManager.ts +8 -40
- package/Components/ScreenRevealManager/__tests__/Overlay.test.tsx +88 -0
- package/Components/ScreenRevealManager/__tests__/ScreenRevealManager.test.ts +69 -86
- package/Components/ScreenRevealManager/withScreenRevealManager.tsx +10 -18
- 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 +209 -53
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +32 -32
- 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 +16 -13
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappFrameworkComponents/BarView/BarView.tsx +12 -5
- 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/CachedDimensionsContext/index.ts +17 -2
- 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/ComponentCellSelectionHelper/index.js +0 -6
- package/Helpers/DataSourceHelper/index.js +19 -0
- package/Helpers/index.js +7 -40
- package/package.json +5 -5
- package/Components/Layout/TV/LayoutBackground.tsx +0 -31
- 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/Components/Screen/utils.ts +0 -16
- package/Helpers/Analytics/index.js +0 -95
- 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
|
@@ -14,6 +14,7 @@ import { tvPluginsWithCellRenderer } from "../../const";
|
|
|
14
14
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
15
15
|
import type { BehaviorSubject } from "rxjs";
|
|
16
16
|
import { useCallbackActions } from "@applicaster/zapp-react-native-utils/zappFrameworkUtils/HookCallback/useCallbackActions";
|
|
17
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
17
18
|
|
|
18
19
|
export type RiverItemType = {
|
|
19
20
|
item: ZappUIComponent;
|
|
@@ -112,33 +113,38 @@ function RiverItemComponent(props: RiverItemType) {
|
|
|
112
113
|
CellRenderer = undefined;
|
|
113
114
|
}
|
|
114
115
|
|
|
115
|
-
|
|
116
|
-
riverLogger.log({
|
|
117
|
-
message: "mounting component",
|
|
118
|
-
data: { item, feedUrl, Component, CellRenderer },
|
|
119
|
-
jsOnly: true,
|
|
120
|
-
});
|
|
116
|
+
const isComponentMissing = isNilOrEmpty(Component);
|
|
121
117
|
|
|
122
|
-
|
|
118
|
+
/**
|
|
119
|
+
* TODO: Move this plugin existence check further up the stack (before ComponentsMap).
|
|
120
|
+
* Filtering items at the list-rendering or data-processing level would prevent
|
|
121
|
+
* mounting RiverItem entirely for missing components.
|
|
122
|
+
*/
|
|
123
|
+
React.useEffect(() => {
|
|
124
|
+
if (isComponentMissing) {
|
|
123
125
|
riverLogger.warning({
|
|
124
|
-
message:
|
|
125
|
-
|
|
126
|
+
message: `Component ${item.component_type} is null - skipping rendering`,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
onLoadFinished(index);
|
|
130
|
+
} else {
|
|
131
|
+
riverLogger.log({
|
|
132
|
+
message: "mounting component",
|
|
133
|
+
data: { item, feedUrl, Component, CellRenderer },
|
|
126
134
|
jsOnly: true,
|
|
127
135
|
});
|
|
136
|
+
|
|
137
|
+
if (!CellRenderer && !isGroup(item)) {
|
|
138
|
+
riverLogger.warning({
|
|
139
|
+
message: "Cell Renderer is null - will fallback to default cell",
|
|
140
|
+
data: { item, CellRenderer },
|
|
141
|
+
jsOnly: true,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
128
144
|
}
|
|
129
145
|
}, []);
|
|
130
146
|
|
|
131
|
-
if (!readyToBeDisplayed) {
|
|
132
|
-
return null;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
if (Component === null || typeof Component === "undefined") {
|
|
136
|
-
riverLogger.warning({
|
|
137
|
-
message: `Component ${item.component_type} is null - skipping rendering`,
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
onLoadFinished(index);
|
|
141
|
-
|
|
147
|
+
if (!readyToBeDisplayed || isComponentMissing) {
|
|
142
148
|
return null;
|
|
143
149
|
}
|
|
144
150
|
|
|
@@ -2,8 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Text } from "react-native";
|
|
5
|
-
|
|
6
|
-
import { mergeRight } from "@applicaster/zapp-react-native-utils/utils";
|
|
5
|
+
import * as R from "ramda";
|
|
7
6
|
|
|
8
7
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
9
8
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
@@ -14,8 +13,6 @@ import {
|
|
|
14
13
|
} from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
15
14
|
import { useRivers } from "@applicaster/zapp-react-native-utils/reactHooks/state";
|
|
16
15
|
|
|
17
|
-
import { toStringOrEmpty } from "./utils";
|
|
18
|
-
|
|
19
16
|
type Props = {
|
|
20
17
|
screenId: string;
|
|
21
18
|
screenData: ZappRiver | ZappEntry;
|
|
@@ -27,7 +24,6 @@ type Props = {
|
|
|
27
24
|
isInsideContainer?: boolean;
|
|
28
25
|
extraAnchorPointYOffset: number;
|
|
29
26
|
river?: ZappRiver | ZappEntry;
|
|
30
|
-
groupId: string;
|
|
31
27
|
};
|
|
32
28
|
|
|
33
29
|
export const River = (props: Props) => {
|
|
@@ -39,7 +35,6 @@ export const River = (props: Props) => {
|
|
|
39
35
|
componentsMapExtraProps,
|
|
40
36
|
isInsideContainer,
|
|
41
37
|
extraAnchorPointYOffset,
|
|
42
|
-
groupId,
|
|
43
38
|
} = props;
|
|
44
39
|
|
|
45
40
|
const { title: screenTitle, summary: screenSummary } = useNavbarState();
|
|
@@ -56,41 +51,28 @@ export const River = (props: Props) => {
|
|
|
56
51
|
[screenId]
|
|
57
52
|
);
|
|
58
53
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
extraData,
|
|
64
|
-
screenData: mergeRight(river, { groupId: extraData?.groupId }),
|
|
65
|
-
componentsMapExtraProps: mergeRight(componentsMapExtraProps, { groupId }),
|
|
66
|
-
};
|
|
67
|
-
}, [
|
|
68
|
-
extraProps,
|
|
69
|
-
screenResolverExtraProps,
|
|
70
|
-
river,
|
|
71
|
-
componentsMapExtraProps,
|
|
72
|
-
groupId,
|
|
73
|
-
]);
|
|
54
|
+
const stringOrEmpty = (value: string | number | undefined): string =>
|
|
55
|
+
R.isNil(value) ? "" : String(value);
|
|
74
56
|
|
|
75
57
|
React.useEffect(() => {
|
|
76
58
|
if (!isInsideContainer) {
|
|
77
|
-
setScreenTitle(
|
|
78
|
-
setScreenSummary(
|
|
59
|
+
setScreenTitle(stringOrEmpty(screenData?.title));
|
|
60
|
+
setScreenSummary(stringOrEmpty(screenData?.summary));
|
|
79
61
|
}
|
|
80
62
|
}, [screenData.id]);
|
|
81
63
|
|
|
82
64
|
React.useEffect(() => {
|
|
83
65
|
if (feedData && !isInsideContainer) {
|
|
84
66
|
if (feedData.title && feedData.title !== screenTitle) {
|
|
85
|
-
setScreenTitle(
|
|
67
|
+
setScreenTitle(stringOrEmpty(feedData.title));
|
|
86
68
|
}
|
|
87
69
|
|
|
88
70
|
if (feedData.summary && feedData.summary !== screenSummary) {
|
|
89
|
-
setScreenSummary(
|
|
71
|
+
setScreenSummary(stringOrEmpty(feedData.summary));
|
|
90
72
|
}
|
|
91
73
|
} else {
|
|
92
|
-
setScreenTitle(
|
|
93
|
-
setScreenSummary(
|
|
74
|
+
setScreenTitle(stringOrEmpty(screenData?.title));
|
|
75
|
+
setScreenSummary(stringOrEmpty(screenData?.summary));
|
|
94
76
|
}
|
|
95
77
|
}, [feedData, screenData, screenTitle, screenSummary]);
|
|
96
78
|
|
|
@@ -104,13 +86,15 @@ export const River = (props: Props) => {
|
|
|
104
86
|
}
|
|
105
87
|
|
|
106
88
|
if (river.type !== "general_content") {
|
|
89
|
+
const extraData = { ...R.mergeRight(extraProps, screenResolverExtraProps) };
|
|
90
|
+
|
|
107
91
|
return (
|
|
108
92
|
<ScreenResolver
|
|
109
93
|
screenType={river.type}
|
|
110
94
|
screenId={screenId}
|
|
111
|
-
screenData={
|
|
112
|
-
componentsMapExtraProps={
|
|
113
|
-
{...
|
|
95
|
+
screenData={R.merge(river, { groupId: extraData?.groupId })}
|
|
96
|
+
componentsMapExtraProps={componentsMapExtraProps}
|
|
97
|
+
{...extraData}
|
|
114
98
|
/>
|
|
115
99
|
);
|
|
116
100
|
}
|
|
@@ -122,7 +106,6 @@ export const River = (props: Props) => {
|
|
|
122
106
|
isScreenWrappedInContainer={isInsideContainer}
|
|
123
107
|
extraAnchorPointYOffset={extraAnchorPointYOffset}
|
|
124
108
|
componentsMapExtraProps={componentsMapExtraProps}
|
|
125
|
-
groupId={groupId}
|
|
126
109
|
/>
|
|
127
110
|
);
|
|
128
111
|
};
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { compose
|
|
2
|
-
import { isTvOSPlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
|
-
|
|
1
|
+
import { compose } from "ramda";
|
|
4
2
|
import { River as RiverComponent } from "./River";
|
|
3
|
+
import { withTvEventHandler } from "./withTVEventHandler";
|
|
5
4
|
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
6
5
|
import { withRiverDataLoader } from "./withRiverDataLoader";
|
|
7
|
-
import { withFocusableGroupForContent } from "./withFocusableGroupForContent";
|
|
8
|
-
|
|
9
|
-
const isTVOS = isTvOSPlatform();
|
|
10
6
|
|
|
11
7
|
export const River = compose(
|
|
8
|
+
withTvEventHandler,
|
|
12
9
|
withComponentsMapOffsetContext,
|
|
13
|
-
withRiverDataLoader
|
|
14
|
-
isTVOS ? withFocusableGroupForContent : identity
|
|
10
|
+
withRiverDataLoader
|
|
15
11
|
)(RiverComponent);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/* eslint max-len: off */
|
|
2
|
+
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
|
|
5
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
|
+
import { useIsStandaloneFullscreen } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
7
|
+
|
|
8
|
+
export const withTvEventHandler = (Component) => {
|
|
9
|
+
return function WithTVEventHandler(props) {
|
|
10
|
+
const navigator = useNavigation();
|
|
11
|
+
|
|
12
|
+
const isStandaloneFullscreen = useIsStandaloneFullscreen();
|
|
13
|
+
|
|
14
|
+
const remoteHandler = (event) => {
|
|
15
|
+
const { eventType } = event;
|
|
16
|
+
|
|
17
|
+
const canGoBack = navigator.canGoBack();
|
|
18
|
+
|
|
19
|
+
if (eventType === "menu" && isStandaloneFullscreen) {
|
|
20
|
+
navigator.goHome();
|
|
21
|
+
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (eventType === "menu" && canGoBack) {
|
|
26
|
+
navigator.goBack();
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<TVEventHandlerComponent tvEventHandler={remoteHandler}>
|
|
32
|
+
<Component {...props} />
|
|
33
|
+
</TVEventHandlerComponent>
|
|
34
|
+
);
|
|
35
|
+
};
|
|
36
|
+
};
|
|
@@ -10,11 +10,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
10
10
|
>
|
|
11
11
|
<View
|
|
12
12
|
onLayout={[Function]}
|
|
13
|
-
style={
|
|
14
|
-
{
|
|
15
|
-
"flex": 1,
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
13
|
>
|
|
19
14
|
<RCTScrollView
|
|
20
15
|
ListFooterComponent={
|
|
@@ -155,7 +150,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
155
150
|
}
|
|
156
151
|
}
|
|
157
152
|
stickyHeaderIndices={[]}
|
|
158
|
-
testID="components-map-flat-list"
|
|
159
153
|
viewabilityConfigCallbackPairs={[]}
|
|
160
154
|
windowSize={12}
|
|
161
155
|
>
|
|
@@ -167,11 +161,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
167
161
|
>
|
|
168
162
|
<View
|
|
169
163
|
onLayout={[Function]}
|
|
170
|
-
style={
|
|
171
|
-
{
|
|
172
|
-
"flex": 1,
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
164
|
>
|
|
176
165
|
<View />
|
|
177
166
|
</View>
|
|
@@ -183,11 +172,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
183
172
|
>
|
|
184
173
|
<View
|
|
185
174
|
onLayout={[Function]}
|
|
186
|
-
style={
|
|
187
|
-
{
|
|
188
|
-
"flex": 1,
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
175
|
/>
|
|
192
176
|
</View>
|
|
193
177
|
<View
|
|
@@ -139,13 +139,7 @@ jest.mock(
|
|
|
139
139
|
})
|
|
140
140
|
);
|
|
141
141
|
|
|
142
|
-
jest.mock("@applicaster/zapp-react-native-ui-components/events", () => ({
|
|
143
|
-
...jest.requireActual("@applicaster/zapp-react-native-ui-components/events"),
|
|
144
|
-
emitScrollEndReached: jest.fn(),
|
|
145
|
-
}));
|
|
146
|
-
|
|
147
142
|
const { View } = require("react-native");
|
|
148
|
-
const events = require("@applicaster/zapp-react-native-ui-components/events");
|
|
149
143
|
const { ComponentsMap } = require("../ComponentsMap/ComponentsMap");
|
|
150
144
|
const theme = require("./theme-mock.json");
|
|
151
145
|
|
|
@@ -196,36 +190,4 @@ describe("componentsMap", () => {
|
|
|
196
190
|
|
|
197
191
|
expect(toJSON()).toMatchSnapshot();
|
|
198
192
|
});
|
|
199
|
-
|
|
200
|
-
it("calls emitScrollEndReached when onScroll was called and isScreenWrappedInContainer is false", () => {
|
|
201
|
-
themeSpy = jest
|
|
202
|
-
.spyOn(themeUtils, "useTheme")
|
|
203
|
-
.mockImplementation(() => () => theme);
|
|
204
|
-
|
|
205
|
-
events.emitScrollEndReached.mockClear();
|
|
206
|
-
|
|
207
|
-
const { getByTestId } = render(
|
|
208
|
-
<Provider store={store}>
|
|
209
|
-
<ComponentsMap
|
|
210
|
-
{...props}
|
|
211
|
-
isScreenWrappedInContainer={false}
|
|
212
|
-
feed={{ entry: [] }}
|
|
213
|
-
/>
|
|
214
|
-
</Provider>
|
|
215
|
-
);
|
|
216
|
-
|
|
217
|
-
const flatList = getByTestId("components-map-flat-list");
|
|
218
|
-
|
|
219
|
-
flatList.props.onScroll({
|
|
220
|
-
nativeEvent: {
|
|
221
|
-
contentOffset: { y: 0 },
|
|
222
|
-
layoutMeasurement: { height: 100 },
|
|
223
|
-
contentSize: { height: 200 },
|
|
224
|
-
},
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
flatList.props.onEndReached();
|
|
228
|
-
|
|
229
|
-
expect(events.emitScrollEndReached).toHaveBeenCalledTimes(1);
|
|
230
|
-
});
|
|
231
193
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { renderHook, act } from "@testing-library/react-native";
|
|
2
|
+
|
|
3
|
+
import { useAfterPaint } from "../useAfterPaint";
|
|
4
|
+
|
|
5
|
+
describe("useAfterPaint", () => {
|
|
6
|
+
let frameCallbacks: FrameRequestCallback[];
|
|
7
|
+
let originalRaf: typeof requestAnimationFrame;
|
|
8
|
+
let originalCancelRaf: typeof cancelAnimationFrame;
|
|
9
|
+
|
|
10
|
+
const flushFrame = () => {
|
|
11
|
+
const callbacks = frameCallbacks;
|
|
12
|
+
frameCallbacks = [];
|
|
13
|
+
|
|
14
|
+
act(() => {
|
|
15
|
+
callbacks.forEach((cb) => cb(0));
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
frameCallbacks = [];
|
|
21
|
+
originalRaf = global.requestAnimationFrame;
|
|
22
|
+
originalCancelRaf = global.cancelAnimationFrame;
|
|
23
|
+
|
|
24
|
+
global.requestAnimationFrame = jest.fn((cb: FrameRequestCallback) => {
|
|
25
|
+
frameCallbacks.push(cb);
|
|
26
|
+
|
|
27
|
+
return frameCallbacks.length;
|
|
28
|
+
}) as unknown as typeof requestAnimationFrame;
|
|
29
|
+
|
|
30
|
+
global.cancelAnimationFrame = jest.fn();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
global.requestAnimationFrame = originalRaf;
|
|
35
|
+
global.cancelAnimationFrame = originalCancelRaf;
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("returns false on the initial render", () => {
|
|
39
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
40
|
+
|
|
41
|
+
expect(result.current).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it("stays false after only one animation frame (before paint completes)", () => {
|
|
45
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
46
|
+
|
|
47
|
+
flushFrame();
|
|
48
|
+
|
|
49
|
+
expect(result.current).toBe(false);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("returns true after two animation frames (a real post-paint boundary)", () => {
|
|
53
|
+
const { result } = renderHook(() => useAfterPaint());
|
|
54
|
+
|
|
55
|
+
flushFrame();
|
|
56
|
+
flushFrame();
|
|
57
|
+
|
|
58
|
+
expect(result.current).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export const useAfterPaint = (): boolean => {
|
|
4
|
+
const [painted, setPainted] = React.useState(false);
|
|
5
|
+
|
|
6
|
+
React.useEffect(() => {
|
|
7
|
+
let secondFrame: number | undefined;
|
|
8
|
+
|
|
9
|
+
const firstFrame = requestAnimationFrame(() => {
|
|
10
|
+
secondFrame = requestAnimationFrame(() => setPainted(true));
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
return () => {
|
|
14
|
+
cancelAnimationFrame(firstFrame);
|
|
15
|
+
|
|
16
|
+
if (secondFrame !== undefined) {
|
|
17
|
+
cancelAnimationFrame(secondFrame);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}, []);
|
|
21
|
+
|
|
22
|
+
return painted;
|
|
23
|
+
};
|
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
useIsScreenActive,
|
|
11
11
|
useNavigation,
|
|
12
|
-
useRivers,
|
|
13
12
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
14
13
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
15
|
-
import {
|
|
14
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
16
15
|
import {
|
|
17
16
|
useNavbarState,
|
|
18
17
|
useScreenBackgroundColor,
|
|
@@ -21,7 +20,7 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
21
20
|
|
|
22
21
|
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
23
22
|
import { ScreenResolver } from "../../ScreenResolver";
|
|
24
|
-
import { useInitialFocus } from "./hooks";
|
|
23
|
+
import { useInitialFocus, useAfterPaint } from "./hooks";
|
|
25
24
|
import { isPlayerPlugin } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
26
25
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
27
26
|
import { FreezeWithCallback } from "../../FreezeWithCallback";
|
|
@@ -103,8 +102,7 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
const navigator = useNavigation();
|
|
106
|
-
const plugins =
|
|
107
|
-
const rivers = useRivers();
|
|
105
|
+
const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
|
|
108
106
|
|
|
109
107
|
const pathAttributes = getPathAttributes({ pathname: route });
|
|
110
108
|
const routeState = navigator.getStackForPathname(route);
|
|
@@ -157,6 +155,13 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
157
155
|
|
|
158
156
|
const isScreenActive = useIsScreenActive();
|
|
159
157
|
|
|
158
|
+
// We need to render menu first and then proceed with screen content,
|
|
159
|
+
// otherwise screen will stay black until everything is loaded and screen
|
|
160
|
+
// rendering put huge load the CPU pushing rendering even further.
|
|
161
|
+
// With this approach, menu will be rendered immediately and screen content
|
|
162
|
+
// will be rendered after paint, which makes it more responsive and prevents black screen.
|
|
163
|
+
const isContentReady = useAfterPaint();
|
|
164
|
+
|
|
160
165
|
return (
|
|
161
166
|
<FreezeWithCallback freeze={!isScreenActive} onRelease={onRelease}>
|
|
162
167
|
<View style={[styles.container, { backgroundColor }]}>
|
|
@@ -167,12 +172,14 @@ export const Screen = ({ route, Components }: Props) => {
|
|
|
167
172
|
navigationProps={navigationProps}
|
|
168
173
|
/>
|
|
169
174
|
</NavBarContainer>
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
175
|
+
{isContentReady ? (
|
|
176
|
+
<ScreenResolver
|
|
177
|
+
screenType={screenType}
|
|
178
|
+
screenId={screenId}
|
|
179
|
+
screenData={screenData}
|
|
180
|
+
groupId={route}
|
|
181
|
+
/>
|
|
182
|
+
) : null}
|
|
176
183
|
</View>
|
|
177
184
|
</FreezeWithCallback>
|
|
178
185
|
);
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { View } from "react-native";
|
|
3
|
-
import {
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
4
|
|
|
5
5
|
const Mocked_RouteManager = jest.fn((props) => (
|
|
6
6
|
<View testID="routeManager" {...props} />
|
|
7
7
|
));
|
|
8
8
|
|
|
9
|
+
const mock_navBarVisibleFlag = true;
|
|
10
|
+
|
|
11
|
+
const mockIsNavBarVisible = jest.fn(() => mock_navBarVisibleFlag);
|
|
12
|
+
|
|
9
13
|
const mockIsOrientationCompatible = jest.fn(() => true);
|
|
10
14
|
|
|
11
15
|
jest.mock("react-native-safe-area-context", () => ({
|
|
12
|
-
...jest.requireActual("react-native-safe-area-context"),
|
|
13
16
|
useSafeAreaInsets: () => ({ top: 44 }),
|
|
17
|
+
useSafeAreaFrame: () => ({ x: 0, y: 0, width: 375, height: 812 }),
|
|
14
18
|
}));
|
|
15
19
|
|
|
16
20
|
jest.mock("../../RouteManager", () => ({
|
|
@@ -32,14 +36,12 @@ jest.mock(
|
|
|
32
36
|
);
|
|
33
37
|
|
|
34
38
|
jest.mock("@applicaster/zapp-react-native-utils/analyticsUtils", () => ({
|
|
35
|
-
...jest.requireActual("@applicaster/zapp-react-native-utils/analyticsUtils"),
|
|
36
39
|
useAnalytics: jest.fn(() => ({
|
|
37
40
|
sendScreenEvent: jest.fn(),
|
|
38
41
|
})),
|
|
39
42
|
}));
|
|
40
43
|
|
|
41
44
|
jest.mock("@applicaster/zapp-react-native-utils/theme", () => ({
|
|
42
|
-
...jest.requireActual("@applicaster/zapp-react-native-utils/theme"),
|
|
43
45
|
useTheme: jest.fn(() => ({
|
|
44
46
|
app_background_color: "blue",
|
|
45
47
|
})),
|
|
@@ -76,44 +78,21 @@ jest.mock(
|
|
|
76
78
|
})
|
|
77
79
|
);
|
|
78
80
|
|
|
79
|
-
jest.mock(
|
|
80
|
-
|
|
81
|
-
()
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
})
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
jest.mock(
|
|
96
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive",
|
|
97
|
-
() => ({
|
|
98
|
-
...jest.requireActual(
|
|
99
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useIsScreenActive"
|
|
100
|
-
),
|
|
101
|
-
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
102
|
-
})
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
jest.mock(
|
|
106
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute",
|
|
107
|
-
() => ({
|
|
108
|
-
...jest.requireActual(
|
|
109
|
-
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useRoute"
|
|
110
|
-
),
|
|
111
|
-
useRoute: jest.fn(() => ({
|
|
112
|
-
pathname: "/river/testId",
|
|
113
|
-
screenData: { id: "testId" },
|
|
114
|
-
})),
|
|
115
|
-
})
|
|
116
|
-
);
|
|
81
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
82
|
+
isNavBarVisible: mockIsNavBarVisible,
|
|
83
|
+
useIsScreenActive: jest.fn().mockReturnValue(true),
|
|
84
|
+
useNavigation: jest.fn(() => ({
|
|
85
|
+
canGoBack: () => false,
|
|
86
|
+
currentRoute: "/river/testId",
|
|
87
|
+
activeRiver: { id: "testId" },
|
|
88
|
+
screenData: { id: "testId" },
|
|
89
|
+
data: { screen: { id: "testId" } },
|
|
90
|
+
})),
|
|
91
|
+
useRoute: jest.fn(() => ({
|
|
92
|
+
pathname: "/river/testId",
|
|
93
|
+
screenData: { id: "testId" },
|
|
94
|
+
})),
|
|
95
|
+
}));
|
|
117
96
|
|
|
118
97
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
119
98
|
...jest.requireActual("@applicaster/zapp-react-native-utils/reactHooks"),
|
|
@@ -134,6 +113,26 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
|
134
113
|
useIsTablet: jest.fn(() => false),
|
|
135
114
|
}));
|
|
136
115
|
|
|
116
|
+
jest.mock("@applicaster/zapp-react-native-redux/hooks", () => {
|
|
117
|
+
const View = jest.requireActual("react-native").View;
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
...jest.requireActual("@applicaster/zapp-react-native-redux/hooks"),
|
|
121
|
+
usePickFromState: () => ({
|
|
122
|
+
plugins: [
|
|
123
|
+
{
|
|
124
|
+
name: "Offline Plugin",
|
|
125
|
+
identifier: "offline-experience",
|
|
126
|
+
type: "general",
|
|
127
|
+
module: {
|
|
128
|
+
OfflineFallbackScreen: ({ children }) => <View>{children}</View>, // eslint-disable-line
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
}),
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
|
|
137
136
|
const {
|
|
138
137
|
allowedOrientationsForScreen,
|
|
139
138
|
getOrientation,
|
|
@@ -153,19 +152,6 @@ const screenProps = {
|
|
|
153
152
|
|
|
154
153
|
const { Screen } = require("..");
|
|
155
154
|
|
|
156
|
-
const store = {
|
|
157
|
-
plugins: [
|
|
158
|
-
{
|
|
159
|
-
name: "Offline Plugin",
|
|
160
|
-
identifier: "offline-experience",
|
|
161
|
-
type: "general",
|
|
162
|
-
module: {
|
|
163
|
-
OfflineFallbackScreen: ({ children }) => <View>{children}</View>, // eslint-disable-line
|
|
164
|
-
},
|
|
165
|
-
},
|
|
166
|
-
],
|
|
167
|
-
};
|
|
168
|
-
|
|
169
155
|
describe("<Screen Component />", () => {
|
|
170
156
|
beforeEach(() => {
|
|
171
157
|
allowedOrientationsForScreen.mockClear();
|
|
@@ -175,22 +161,14 @@ describe("<Screen Component />", () => {
|
|
|
175
161
|
|
|
176
162
|
describe("when the navbar should show", () => {
|
|
177
163
|
it("renders correctly", () => {
|
|
178
|
-
const { toJSON } =
|
|
179
|
-
<Screen {...screenProps} />,
|
|
180
|
-
store
|
|
181
|
-
);
|
|
182
|
-
|
|
164
|
+
const { toJSON } = render(<Screen {...screenProps} />);
|
|
183
165
|
expect(toJSON()).toMatchSnapshot();
|
|
184
166
|
});
|
|
185
167
|
});
|
|
186
168
|
|
|
187
169
|
describe("when the navbar should be hidden", () => {
|
|
188
170
|
it("renders correctly", () => {
|
|
189
|
-
const { toJSON } =
|
|
190
|
-
<Screen {...screenProps} />,
|
|
191
|
-
store
|
|
192
|
-
);
|
|
193
|
-
|
|
171
|
+
const { toJSON } = render(<Screen {...screenProps} />);
|
|
194
172
|
expect(toJSON()).toMatchSnapshot();
|
|
195
173
|
});
|
|
196
174
|
});
|