@applicaster/zapp-react-native-ui-components 15.0.0-rc.98 → 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 +15 -0
- 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 +1 -15
- 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/events/index.ts +2 -0
- package/events/scrollEndReached.ts +15 -0
- 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
|
@@ -5,6 +5,8 @@ import {
|
|
|
5
5
|
StyleSheet,
|
|
6
6
|
} from "react-native";
|
|
7
7
|
import * as R from "ramda";
|
|
8
|
+
import { path } from "@applicaster/zapp-react-native-utils/utils";
|
|
9
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
8
10
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
9
11
|
import { useLocalizedStrings } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
10
12
|
import { useAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
@@ -62,9 +64,13 @@ export const usePullToRefresh = (
|
|
|
62
64
|
|
|
63
65
|
const [refreshing, setRefreshing] = React.useState(false);
|
|
64
66
|
|
|
65
|
-
const feeds: string[] =
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
const feeds: string[] = React.useMemo(
|
|
68
|
+
() =>
|
|
69
|
+
(riverComponents || [])
|
|
70
|
+
.map((riverComponent) => path(["data", "source"], riverComponent))
|
|
71
|
+
.filter((feed) => !isNilOrEmpty(feed)),
|
|
72
|
+
[riverComponents]
|
|
73
|
+
);
|
|
68
74
|
|
|
69
75
|
const feedsLength = feeds.length;
|
|
70
76
|
|
|
@@ -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={
|
|
@@ -137,6 +132,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
137
132
|
keyExtractor={[Function]}
|
|
138
133
|
maxToRenderPerBatch={10}
|
|
139
134
|
onContentSizeChange={[Function]}
|
|
135
|
+
onEndReached={[Function]}
|
|
140
136
|
onLayout={[Function]}
|
|
141
137
|
onMomentumScrollBegin={[Function]}
|
|
142
138
|
onMomentumScrollEnd={[Function]}
|
|
@@ -165,11 +161,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
165
161
|
>
|
|
166
162
|
<View
|
|
167
163
|
onLayout={[Function]}
|
|
168
|
-
style={
|
|
169
|
-
{
|
|
170
|
-
"flex": 1,
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
164
|
>
|
|
174
165
|
<View />
|
|
175
166
|
</View>
|
|
@@ -181,11 +172,6 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
181
172
|
>
|
|
182
173
|
<View
|
|
183
174
|
onLayout={[Function]}
|
|
184
|
-
style={
|
|
185
|
-
{
|
|
186
|
-
"flex": 1,
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
175
|
/>
|
|
190
176
|
</View>
|
|
191
177
|
<View
|
|
@@ -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
|
});
|