@applicaster/zapp-react-native-ui-components 15.0.0-rc.99 → 15.1.0-alpha.4285753931
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/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 +13 -31
- 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 +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/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/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
|
@@ -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
|
};
|
|
@@ -6,7 +6,12 @@ import {
|
|
|
6
6
|
} from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
7
7
|
import { useHookAnalytics } from "@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks";
|
|
8
8
|
import { useSetNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
import { componentsLogger } from "../../Helpers/logger";
|
|
11
|
+
|
|
12
|
+
const logger = componentsLogger.addSubsystem("HookRenderer");
|
|
13
|
+
|
|
14
|
+
const HOOK_PRESENTATION_TYPE = "Hook";
|
|
10
15
|
|
|
11
16
|
type Props = {
|
|
12
17
|
focused?: boolean;
|
|
@@ -15,20 +20,17 @@ type Props = {
|
|
|
15
20
|
callback: hookCallback;
|
|
16
21
|
};
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
const {
|
|
20
|
-
|
|
21
|
-
screenData: { payload, hookPlugin },
|
|
22
|
-
callback,
|
|
23
|
-
} = props;
|
|
24
|
-
|
|
25
|
-
const { setVisible: showNavBar } = useSetNavbarState();
|
|
23
|
+
const HookRenderer = (props: Props) => {
|
|
24
|
+
const { focused, screenData, callback } = props;
|
|
25
|
+
const { payload, hookPlugin } = screenData;
|
|
26
26
|
|
|
27
27
|
const {
|
|
28
28
|
module: { Component: HookComponent, presentFullScreen },
|
|
29
29
|
configuration,
|
|
30
30
|
} = hookPlugin;
|
|
31
31
|
|
|
32
|
+
const { setVisible: showNavBar } = useSetNavbarState();
|
|
33
|
+
|
|
32
34
|
useHookAnalytics(props);
|
|
33
35
|
|
|
34
36
|
const isNavBarVisible = useIsNavBarVisible();
|
|
@@ -63,8 +65,36 @@ export const HookRenderer = (props: Props) => {
|
|
|
63
65
|
hookPlugin,
|
|
64
66
|
focused,
|
|
65
67
|
parentFocus,
|
|
66
|
-
presentationType:
|
|
68
|
+
presentationType: HOOK_PRESENTATION_TYPE,
|
|
67
69
|
}}
|
|
68
70
|
/>
|
|
69
71
|
);
|
|
70
72
|
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Guard component to prevent rendering HookRenderer when screenData or hookPlugin is missing. This is to avoid potential crashes due to missing data.
|
|
76
|
+
*/
|
|
77
|
+
const HookRendererGuard = (props: Props) => {
|
|
78
|
+
React.useEffect(() => {
|
|
79
|
+
if (!props.screenData) {
|
|
80
|
+
logger.error(
|
|
81
|
+
"HookRenderer received no screenData, screen cannot be rendered"
|
|
82
|
+
);
|
|
83
|
+
} else if (!props.screenData.hookPlugin) {
|
|
84
|
+
logger.error(
|
|
85
|
+
"HookRenderer received screenData with no hookPlugin, screen cannot be rendered",
|
|
86
|
+
{
|
|
87
|
+
screenData: props.screenData,
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}, [props.screenData]);
|
|
92
|
+
|
|
93
|
+
if (!props.screenData || !props.screenData.hookPlugin) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return <HookRenderer {...props} />;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export { HookRendererGuard as HookRenderer };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
import { render } from "@testing-library/react-native";
|
|
4
|
+
import { HookRenderer } from "..";
|
|
5
|
+
|
|
6
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactUtils", () => ({
|
|
7
|
+
isTV: jest.fn(() => false),
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
11
|
+
useBackHandler: jest.fn(),
|
|
12
|
+
useIsNavBarVisible: jest.fn(() => true),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
jest.mock(
|
|
16
|
+
"@applicaster/zapp-react-native-utils/analyticsUtils/helpers/hooks",
|
|
17
|
+
() => ({
|
|
18
|
+
useHookAnalytics: jest.fn(),
|
|
19
|
+
})
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks", () => ({
|
|
23
|
+
useSetNavbarState: jest.fn(() => ({
|
|
24
|
+
setVisible: jest.fn(),
|
|
25
|
+
})),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
describe("HookRenderer", () => {
|
|
29
|
+
it("returns null when hookPlugin is missing", () => {
|
|
30
|
+
const { toJSON } = render(
|
|
31
|
+
<HookRenderer callback={jest.fn()} screenData={{ payload: {} } as any} />
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(toJSON()).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("passes Hook presentationType to rendered hook component", () => {
|
|
38
|
+
const HookComponent = (props) => (
|
|
39
|
+
<View testID="hook-component" {...props} />
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const { getByTestId } = render(
|
|
43
|
+
<HookRenderer
|
|
44
|
+
callback={jest.fn()}
|
|
45
|
+
screenData={{
|
|
46
|
+
payload: { foo: "bar" },
|
|
47
|
+
hookPlugin: {
|
|
48
|
+
module: {
|
|
49
|
+
Component: HookComponent,
|
|
50
|
+
presentFullScreen: false,
|
|
51
|
+
},
|
|
52
|
+
configuration: {},
|
|
53
|
+
},
|
|
54
|
+
}}
|
|
55
|
+
/>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(getByTestId("hook-component").props.presentationType).toBe("Hook");
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
3
|
+
|
|
4
|
+
const styles = StyleSheet.create({
|
|
5
|
+
row: { flexDirection: "row" },
|
|
6
|
+
basis: {
|
|
7
|
+
maxWidth: "100%",
|
|
8
|
+
flexBasis: "100%",
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
type Props = {
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Constrains its child to exactly the available parent width.
|
|
18
|
+
*
|
|
19
|
+
* UI components such as Hero and List render their items inside a parent
|
|
20
|
+
* `ScrollView` (e.g. when wrapped by tabs). A child placed directly in a
|
|
21
|
+
* scroll container can size itself to its own content rather than to the
|
|
22
|
+
* viewport, which causes items to be measured at a stale width and resize
|
|
23
|
+
* unexpectedly after layout changes such as device rotation.
|
|
24
|
+
*
|
|
25
|
+
* Wrapping the content in a `flexDirection: "row"` parent with a
|
|
26
|
+
* `flexBasis: "100%"` / `maxWidth: "100%"` child forces the child to
|
|
27
|
+
* re-derive its width from the parent on every layout pass instead of
|
|
28
|
+
* caching a measured pixel width, keeping it full-width and stable.
|
|
29
|
+
*
|
|
30
|
+
* @param children - The content to render at full parent width.
|
|
31
|
+
*/
|
|
32
|
+
export function FullWidthRow({ children }: Props) {
|
|
33
|
+
return (
|
|
34
|
+
<View style={styles.row}>
|
|
35
|
+
<View style={styles.basis}>{children}</View>
|
|
36
|
+
</View>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
routeIsPlayerScreen,
|
|
19
19
|
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
20
20
|
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
21
|
-
import {
|
|
21
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
22
22
|
import { NavBarContainer } from "./NavBarContainer";
|
|
23
23
|
|
|
24
24
|
type ComponentsExtraProps = {
|
|
@@ -111,7 +111,11 @@ export const ScreenContainer = React.memo(function ScreenContainer({
|
|
|
111
111
|
const { activeRiver } = navigator;
|
|
112
112
|
const { title, visible } = useNavbarState();
|
|
113
113
|
|
|
114
|
-
const plugins =
|
|
114
|
+
const { plugins = [] } = usePickFromState([
|
|
115
|
+
"appState",
|
|
116
|
+
"remoteConfigurations",
|
|
117
|
+
"plugins",
|
|
118
|
+
]);
|
|
115
119
|
|
|
116
120
|
const navigationProps = getNavigationProps({
|
|
117
121
|
navigator,
|
|
@@ -129,6 +133,11 @@ export const ScreenContainer = React.memo(function ScreenContainer({
|
|
|
129
133
|
[]
|
|
130
134
|
);
|
|
131
135
|
|
|
136
|
+
// We need to render menu first and then proceed with screen content,
|
|
137
|
+
// otherwise screen will stay black until everything is loaded and screen
|
|
138
|
+
// rendering put huge load the CPU pushing rendering even further.
|
|
139
|
+
// With this approach, menu will be rendered immediately and screen content
|
|
140
|
+
// will be rendered after paint, which makes it more responsive and prevents black screen.
|
|
132
141
|
const [navBarReady, setNavBarReady] = React.useState(false);
|
|
133
142
|
|
|
134
143
|
const navBarContainer = (
|
|
@@ -2,13 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Layout TV renders 1`] = `
|
|
4
4
|
<View
|
|
5
|
-
backgroundColor="#000000"
|
|
6
5
|
testID="background-component"
|
|
7
6
|
>
|
|
8
7
|
<View
|
|
9
8
|
excludeFromFocusSearching={true}
|
|
10
9
|
id="/river/A1234"
|
|
11
10
|
preferredFocus={true}
|
|
11
|
+
style={
|
|
12
|
+
{
|
|
13
|
+
"flex": 1,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
12
16
|
>
|
|
13
17
|
<View
|
|
14
18
|
Components={
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import {
|
|
2
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
3
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
4
4
|
|
|
5
5
|
import { LayoutContainer } from "./LayoutContainer";
|
|
@@ -9,8 +9,6 @@ import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
|
9
9
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
10
10
|
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
11
11
|
import { ScreenContextProvider } from "../../../Contexts/ScreenContext";
|
|
12
|
-
import { LayoutBackground } from "./LayoutBackground";
|
|
13
|
-
import { selectAppReady } from "@applicaster/zapp-react-native-redux";
|
|
14
12
|
|
|
15
13
|
type Components = {
|
|
16
14
|
NavBar: React.ComponentType<any>;
|
|
@@ -30,7 +28,9 @@ type Props = {
|
|
|
30
28
|
const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
31
29
|
const navigator = useNavigation();
|
|
32
30
|
|
|
33
|
-
const appReady =
|
|
31
|
+
const { appState: { appReady = false } = {} } = usePickFromState([
|
|
32
|
+
"appState",
|
|
33
|
+
]);
|
|
34
34
|
|
|
35
35
|
if (!appReady) {
|
|
36
36
|
return null;
|
|
@@ -39,7 +39,7 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
39
39
|
return (
|
|
40
40
|
<LayoutContainer>
|
|
41
41
|
<ScreenLayoutContextProvider>
|
|
42
|
-
<
|
|
42
|
+
<Components.Background>
|
|
43
43
|
<ScreenDataContext.Provider value={navigator.data}>
|
|
44
44
|
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
45
45
|
<ScreenContextProvider pathname={navigator.currentRoute}>
|
|
@@ -52,7 +52,7 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
52
52
|
</ScreenContextProvider>
|
|
53
53
|
</PathnameContext.Provider>
|
|
54
54
|
</ScreenDataContext.Provider>
|
|
55
|
-
</
|
|
55
|
+
</Components.Background>
|
|
56
56
|
</ScreenLayoutContextProvider>
|
|
57
57
|
</LayoutContainer>
|
|
58
58
|
);
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { pathOr } from "ramda";
|
|
2
3
|
|
|
3
|
-
import {
|
|
4
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
5
|
|
|
5
6
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
6
7
|
import { StackNavigator } from "../../Navigator";
|
|
7
|
-
import { LayoutBackground } from "./LayoutBackground";
|
|
8
|
-
import { selectAppReady } from "@applicaster/zapp-react-native-redux";
|
|
9
8
|
|
|
10
9
|
type Components = {
|
|
11
10
|
NavBar: React.ComponentType<any>;
|
|
@@ -17,7 +16,8 @@ type Props = {
|
|
|
17
16
|
};
|
|
18
17
|
|
|
19
18
|
const Layout = ({ Components }: Props) => {
|
|
20
|
-
const
|
|
19
|
+
const { appState } = usePickFromState(["appState"]);
|
|
20
|
+
const appReady = pathOr(false, ["appReady"], appState);
|
|
21
21
|
|
|
22
22
|
if (!appReady) {
|
|
23
23
|
return null;
|
|
@@ -25,9 +25,9 @@ const Layout = ({ Components }: Props) => {
|
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
27
|
<ScreenLayoutContextProvider>
|
|
28
|
-
<
|
|
28
|
+
<Components.Background>
|
|
29
29
|
<StackNavigator Components={Components} />
|
|
30
|
-
</
|
|
30
|
+
</Components.Background>
|
|
31
31
|
</ScreenLayoutContextProvider>
|
|
32
32
|
);
|
|
33
33
|
};
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
|
|
4
4
|
import { findPluginByIdentifier } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
5
|
-
import {
|
|
5
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
6
6
|
import {
|
|
7
7
|
inflateString,
|
|
8
8
|
objectToReadableString,
|
|
@@ -40,7 +40,7 @@ export async function inflateUrl(url) {
|
|
|
40
40
|
|
|
41
41
|
export function LinkHandler(props: Props) {
|
|
42
42
|
const screenData = props?.screenData;
|
|
43
|
-
const plugins =
|
|
43
|
+
const { plugins } = usePickFromState(["rivers", "plugins"]);
|
|
44
44
|
|
|
45
45
|
const ScreenPlugin = findPluginByIdentifier(
|
|
46
46
|
WEBVIEW_SCREEN_IDENTIFIER,
|
|
@@ -135,11 +135,17 @@ export const BorderContainerView = (props: Props) => {
|
|
|
135
135
|
|
|
136
136
|
const isImageOnlyCell = useMemo(
|
|
137
137
|
() =>
|
|
138
|
-
|
|
138
|
+
!hasFocusableInside(entry) &&
|
|
139
139
|
!hasTextLabels &&
|
|
140
|
-
|
|
141
|
-
!
|
|
142
|
-
[
|
|
140
|
+
state === "focused" &&
|
|
141
|
+
!isMeasurement?.measuringInProgress,
|
|
142
|
+
[
|
|
143
|
+
hasFocusableInside,
|
|
144
|
+
entry,
|
|
145
|
+
hasTextLabels,
|
|
146
|
+
state,
|
|
147
|
+
isMeasurement?.measuringInProgress,
|
|
148
|
+
]
|
|
143
149
|
);
|
|
144
150
|
|
|
145
151
|
useEffect(() => {
|
|
@@ -32,7 +32,6 @@ export default function Image({
|
|
|
32
32
|
placeholderImage,
|
|
33
33
|
entry,
|
|
34
34
|
withDimensions,
|
|
35
|
-
source: sourceProp,
|
|
36
35
|
...otherProps
|
|
37
36
|
}: Props) {
|
|
38
37
|
const [showDefault, setShowDefault] = React.useState(false);
|
|
@@ -49,10 +48,7 @@ export default function Image({
|
|
|
49
48
|
entry,
|
|
50
49
|
showDefault,
|
|
51
50
|
placeholderImage: placeholderImage || "",
|
|
52
|
-
otherProps
|
|
53
|
-
source: sourceProp,
|
|
54
|
-
state: otherProps.state,
|
|
55
|
-
},
|
|
51
|
+
otherProps,
|
|
56
52
|
});
|
|
57
53
|
|
|
58
54
|
const onError = React.useCallback(() => {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Image as RnImage, ImageStyle } from "react-native";
|
|
3
|
+
import { equals, omit } from "ramda";
|
|
3
4
|
|
|
4
5
|
import { useImageSource } from "./hooks";
|
|
5
|
-
import { equals } from "@applicaster/zapp-react-native-utils/utils";
|
|
6
6
|
|
|
7
7
|
type Source = {
|
|
8
8
|
uri: string;
|
|
@@ -25,19 +25,11 @@ function Image({
|
|
|
25
25
|
placeholderImage,
|
|
26
26
|
entry,
|
|
27
27
|
withDimensions,
|
|
28
|
-
source: sourceProp,
|
|
29
28
|
...otherProps
|
|
30
29
|
}: Props) {
|
|
31
30
|
const [error, setErrorState] = React.useState(null);
|
|
32
31
|
|
|
33
|
-
const source = useImageSource({
|
|
34
|
-
uri,
|
|
35
|
-
entry,
|
|
36
|
-
otherProps: {
|
|
37
|
-
source: sourceProp,
|
|
38
|
-
state: otherProps.state,
|
|
39
|
-
},
|
|
40
|
-
});
|
|
32
|
+
const source = useImageSource({ uri, entry, otherProps });
|
|
41
33
|
|
|
42
34
|
React.useEffect(() => {
|
|
43
35
|
// reset error state on URI change as the error is referencing previous uri
|
|
@@ -57,7 +49,7 @@ function Image({
|
|
|
57
49
|
onError={React.useCallback(() => setErrorState(true), [])}
|
|
58
50
|
// as we have defaults as "" for placeholder image, we need to pass undefined to source to not throw warnings
|
|
59
51
|
source={_source?.uri ? _source : undefined}
|
|
60
|
-
{...otherProps}
|
|
52
|
+
{...omit(["source"], otherProps)}
|
|
61
53
|
/>
|
|
62
54
|
);
|
|
63
55
|
}
|
|
@@ -23,17 +23,9 @@ function Image({
|
|
|
23
23
|
placeholderImage,
|
|
24
24
|
entry,
|
|
25
25
|
withDimensions,
|
|
26
|
-
source: sourceProp,
|
|
27
26
|
...otherProps
|
|
28
27
|
}: Props) {
|
|
29
|
-
const source = useImageSource({
|
|
30
|
-
uri,
|
|
31
|
-
entry,
|
|
32
|
-
otherProps: {
|
|
33
|
-
source: sourceProp,
|
|
34
|
-
state: otherProps.state,
|
|
35
|
-
},
|
|
36
|
-
});
|
|
28
|
+
const source = useImageSource({ uri, entry, otherProps });
|
|
37
29
|
|
|
38
30
|
const updatedSource = source ? withDimensions(source) : { uri: "" };
|
|
39
31
|
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
+
import { path } from "ramda";
|
|
2
3
|
|
|
3
4
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
5
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
6
|
import { extractAsset } from "./utils";
|
|
6
7
|
|
|
7
8
|
type Return = { uri: string } | null;
|
|
8
|
-
type Source = { context?: string; uri?: string } | null | undefined;
|
|
9
9
|
|
|
10
|
-
const getSourceContext = (source
|
|
11
|
-
const getSourceUri = (source
|
|
10
|
+
const getSourceContext = path(["source", "context"]);
|
|
11
|
+
const getSourceUri = path(["source", "uri"]);
|
|
12
|
+
const getState = path(["state"]);
|
|
12
13
|
|
|
13
|
-
export const useImageSource = ({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
otherProps: { source, state: uriState },
|
|
17
|
-
}): Return => {
|
|
18
|
-
const uriContext = getSourceContext(source);
|
|
14
|
+
export const useImageSource = ({ uri, entry, otherProps }): Return => {
|
|
15
|
+
const uriContext = getSourceContext(otherProps);
|
|
16
|
+
const uriState = getState(otherProps);
|
|
19
17
|
|
|
20
18
|
const action = useActions(uriContext);
|
|
21
19
|
|
|
@@ -40,7 +38,7 @@ export const useImageSource = ({
|
|
|
40
38
|
return { uri };
|
|
41
39
|
}
|
|
42
40
|
|
|
43
|
-
const uriFromSource = getSourceUri(
|
|
41
|
+
const uriFromSource = getSourceUri(otherProps);
|
|
44
42
|
|
|
45
43
|
if (uriFromSource) {
|
|
46
44
|
return { uri: uriFromSource };
|
|
@@ -49,7 +47,7 @@ export const useImageSource = ({
|
|
|
49
47
|
return null;
|
|
50
48
|
};
|
|
51
49
|
|
|
52
|
-
const getSource = (uri, showDefault, placeholderImage,
|
|
50
|
+
const getSource = (uri, showDefault, placeholderImage, otherProps) => {
|
|
53
51
|
const placeholderName = placeholderImage || "";
|
|
54
52
|
|
|
55
53
|
const defaultPath = {
|
|
@@ -62,7 +60,7 @@ const getSource = (uri, showDefault, placeholderImage, source) => {
|
|
|
62
60
|
return { uri };
|
|
63
61
|
}
|
|
64
62
|
|
|
65
|
-
const uriFromSource = getSourceUri(
|
|
63
|
+
const uriFromSource = getSourceUri(otherProps);
|
|
66
64
|
|
|
67
65
|
if (uriFromSource) {
|
|
68
66
|
return { uri: uriFromSource };
|
|
@@ -76,9 +74,10 @@ export const useImageSourceWithDefault = ({
|
|
|
76
74
|
entry,
|
|
77
75
|
showDefault,
|
|
78
76
|
placeholderImage,
|
|
79
|
-
otherProps
|
|
77
|
+
otherProps,
|
|
80
78
|
}): Return => {
|
|
81
|
-
const uriContext = getSourceContext(
|
|
79
|
+
const uriContext = getSourceContext(otherProps);
|
|
80
|
+
const uriState = getState(otherProps);
|
|
82
81
|
|
|
83
82
|
const action = useActions(uriContext);
|
|
84
83
|
|
|
@@ -99,5 +98,5 @@ export const useImageSourceWithDefault = ({
|
|
|
99
98
|
return extractAsset(!isTV(), entryStateLocal.asset, uriState);
|
|
100
99
|
}
|
|
101
100
|
|
|
102
|
-
return getSource(uri, showDefault, placeholderImage,
|
|
101
|
+
return getSource(uri, showDefault, placeholderImage, otherProps);
|
|
103
102
|
};
|