@applicaster/zapp-react-native-ui-components 15.0.0-alpha.7809066324 → 15.0.0-alpha.7815563606
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/Cell/Cell.tsx +6 -0
- package/Components/Cell/TvOSCellComponent.tsx +1 -3
- 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/GeneralContentScreen/utils/useCurationAPI.ts +7 -7
- package/Components/HandlePlayable/HandlePlayable.tsx +16 -29
- package/Components/HandlePlayable/utils.ts +31 -0
- package/Components/HookRenderer/HookRenderer.tsx +40 -10
- package/Components/HookRenderer/__tests__/HookRenderer.test.tsx +60 -0
- package/Components/Layout/TV/NavBarContainer.tsx +1 -10
- package/Components/Layout/TV/__tests__/__snapshots__/NavBarContainer.test.tsx.snap +7 -12
- package/Components/Layout/TV/__tests__/__snapshots__/ScreenContainer.test.tsx.snap +7 -12
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/model.test.ts +80 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/placement.test.ts +187 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/selectors.test.ts +45 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/__tests__/style.test.ts +49 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/model.ts +47 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/placement.ts +170 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/selectors.ts +26 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/style.ts +29 -0
- package/Components/MasterCell/DefaultComponents/ActionButtonsCore/types.ts +37 -0
- package/Components/MasterCell/DefaultComponents/Button.tsx +0 -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 +33 -16
- package/Components/MasterCell/DefaultComponents/PressableView.tsx +196 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +40 -39
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +95 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +86 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/index.test.ts +141 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/hooks/__tests__/useGetImageDimensions.test.ts +7 -6
- package/Components/MasterCell/DefaultComponents/SecondaryImage/index.ts +1 -1
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +2 -6
- package/Components/MasterCell/DefaultComponents/index.ts +2 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Asset.ts +46 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Button.ts +126 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/ButtonContainerView.ts +23 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/Spacer.ts +16 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabel.ts +67 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/TextLabelsContainer.ts +32 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/PressableView.test.tsx +191 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/builders.test.ts +140 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/__tests__/index.test.ts +222 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/helpers.ts +105 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/index.ts +104 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/__tests__/insertButtons.test.ts +118 -0
- package/Components/MasterCell/DefaultComponents/mobile/MobileActionButtons/utils/index.ts +73 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/__tests__/index.test.ts +86 -0
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/index.ts +35 -48
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/__tests__/getPluginIdentifier.test.ts +115 -29
- package/Components/MasterCell/DefaultComponents/tv/TvActionButtons/utils/index.ts +39 -144
- package/Components/MasterCell/elementMapper.tsx +1 -0
- package/Components/MasterCell/hoc/__tests__/withAsyncRender.test.tsx +219 -0
- package/Components/MasterCell/hoc/withAsyncRender.tsx +9 -7
- package/Components/OfflineHandler/NotificationView/NotificationView.lg.tsx +17 -9
- package/Components/OfflineHandler/NotificationView/NotificationView.samsung.tsx +16 -8
- package/Components/OfflineHandler/NotificationView/utils.ts +34 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +1 -18
- package/Components/PreloaderWrapper/__tests__/index.test.tsx +26 -0
- package/Components/PreloaderWrapper/index.tsx +15 -0
- package/Components/River/ComponentsMap/ComponentsMap.tsx +16 -0
- package/Components/River/ComponentsMap/hooks/__tests__/useLoadingState.test.ts +1 -1
- package/Components/River/RefreshControl.tsx +36 -13
- package/Components/River/RiverItem.tsx +26 -20
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +2 -0
- package/Components/River/__tests__/componentsMap.test.js +38 -0
- package/Components/Screen/__tests__/Screen.test.tsx +1 -0
- package/Components/Screen/hooks.ts +73 -3
- package/Components/Screen/index.tsx +7 -1
- package/Components/Screen/orientationHandler.ts +7 -10
- 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 +15 -117
- 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/Tabs/TabContent.tsx +7 -4
- package/Components/TopMarginApplicator/TopMarginApplicator.ios.tsx +52 -0
- package/Components/TopMarginApplicator/TopMarginApplicator.tsx +4 -60
- package/Components/TopMarginApplicator/hooks/__tests__/useMarginTop.test.ts +130 -0
- package/Components/TopMarginApplicator/hooks/index.ts +1 -0
- package/Components/TopMarginApplicator/hooks/useMarginTop.ts +59 -0
- package/Components/TopMarginApplicator/index.tsx +11 -0
- package/Components/Transitioner/Scene.tsx +9 -15
- package/Components/VideoLive/LiveImageManager.ts +199 -54
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +31 -33
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +2 -17
- package/Components/VideoModal/hooks/__tests__/useDelayedPlayerDetails.test.ts +15 -7
- package/Components/Viewport/ViewportAware/__tests__/viewportAware.test.js +0 -2
- package/Components/Viewport/ViewportAware/index.tsx +16 -7
- package/Components/Viewport/ViewportEvents/__tests__/viewportEvents.test.js +1 -1
- package/Components/ZappUIComponent/index.tsx +12 -6
- package/Components/default-cell-renderer/viewTrees/mobile/index.ts +0 -3
- package/Components/index.js +1 -1
- package/Contexts/ScreenContext/__tests__/index.test.tsx +57 -0
- package/Contexts/ScreenContext/index.tsx +71 -19
- package/Contexts/ScreenTrackedViewPositionsContext/__tests__/index.test.tsx +1 -1
- package/Contexts/ZappHookModalContext/index.tsx +37 -61
- package/Contexts/ZappPipesContext/ZappPipesContextFactory.tsx +18 -7
- package/Contexts/index.ts +0 -2
- package/Decorators/ZappPipesDataConnector/ResolverSelector.tsx +25 -7
- package/Decorators/ZappPipesDataConnector/__tests__/ResolverSelector.test.tsx +212 -5
- package/Decorators/ZappPipesDataConnector/__tests__/UrlFeedResolver.test.tsx +39 -21
- package/Decorators/ZappPipesDataConnector/resolvers/UrlFeedResolver.tsx +18 -7
- package/events/index.ts +3 -0
- package/events/scrollEndReached.ts +15 -0
- package/package.json +5 -5
- package/Components/MasterCell/DefaultComponents/Text/utils/__tests__/withAdjustedLineHeight.test.ts +0 -46
- package/Components/MasterCell/DefaultComponents/Text/utils/index.ts +0 -21
- package/Components/PlayerContainer/ErrorDisplay/ErrorDisplay.tsx +0 -57
- package/Components/PlayerContainer/ErrorDisplay/index.ts +0 -9
- package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +0 -101
- /package/Components/HookRenderer/{index.tsx → index.ts} +0 -0
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -26,11 +26,15 @@ type Props = {
|
|
|
26
26
|
componentAnchorPointY: number;
|
|
27
27
|
headerOffset?: number;
|
|
28
28
|
extraAnchorPointYOffset?: number;
|
|
29
|
+
componentPaddingTop?: number;
|
|
29
30
|
}) => void;
|
|
30
31
|
offsetUpdater: (arg1: string, arg2: number, arg3: number) => number;
|
|
31
32
|
componentId: string;
|
|
32
33
|
component: {
|
|
33
34
|
id: string;
|
|
35
|
+
styles?: {
|
|
36
|
+
component_padding_top?: number;
|
|
37
|
+
};
|
|
34
38
|
};
|
|
35
39
|
selected?: boolean;
|
|
36
40
|
CellRenderer: React.FunctionComponent<any> & {
|
|
@@ -178,6 +182,8 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
178
182
|
componentAnchorPointY,
|
|
179
183
|
headerOffset,
|
|
180
184
|
extraAnchorPointYOffset,
|
|
185
|
+
componentPaddingTop:
|
|
186
|
+
this.props?.component?.styles?.component_padding_top,
|
|
181
187
|
});
|
|
182
188
|
}
|
|
183
189
|
}
|
|
@@ -195,7 +195,6 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
195
195
|
groupId,
|
|
196
196
|
component,
|
|
197
197
|
index,
|
|
198
|
-
componentsMapOffset,
|
|
199
198
|
} = this.props;
|
|
200
199
|
|
|
201
200
|
this.setScreenLayout(componentAnchorPointY, screenLayout);
|
|
@@ -222,8 +221,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
222
221
|
const totalOffset =
|
|
223
222
|
headerOffset +
|
|
224
223
|
toNumberWithDefaultZero(componentAnchorPointY) +
|
|
225
|
-
extraAnchorPointYOffset
|
|
226
|
-
toNumberWithDefaultZero(componentsMapOffset) +
|
|
224
|
+
extraAnchorPointYOffset +
|
|
227
225
|
componentMarginTop +
|
|
228
226
|
componentPaddingTop;
|
|
229
227
|
|
|
@@ -12,12 +12,26 @@ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
|
12
12
|
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
13
13
|
import { ScreenTrackedViewPositionsContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenTrackedViewPositionsContext";
|
|
14
14
|
import { useEventAlerts } from "./utils/useEventAlerts";
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
import {
|
|
16
|
+
selectRiverById,
|
|
17
|
+
useAppSelector,
|
|
18
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
19
|
+
import { getScreenDataSource } from "./utils/getScreenDataSource";
|
|
20
|
+
import { ScreenResolverFeedProvider } from "../ScreenResolverFeedProvider/ScreenResolverFeedProvider";
|
|
21
|
+
|
|
22
|
+
const { log_debug } = createLogger({
|
|
17
23
|
category: "ScreenContainer",
|
|
18
24
|
subsystem: "General",
|
|
19
25
|
});
|
|
20
26
|
|
|
27
|
+
/** Provides screen-feed from general-screen configuration (if defined) */
|
|
28
|
+
const useFeedData = (id) => {
|
|
29
|
+
const river = useAppSelector((state) => selectRiverById(state, id));
|
|
30
|
+
const feedData = getScreenDataSource(river);
|
|
31
|
+
|
|
32
|
+
return feedData;
|
|
33
|
+
};
|
|
34
|
+
|
|
21
35
|
export const GeneralContentScreen = ({
|
|
22
36
|
feed,
|
|
23
37
|
screenId,
|
|
@@ -54,20 +68,15 @@ export const GeneralContentScreen = ({
|
|
|
54
68
|
useEffect(() => {
|
|
55
69
|
if (!riverActionProvidersReady) {
|
|
56
70
|
if (actionsInitialStateSetters.length > 0) {
|
|
57
|
-
log_info(
|
|
58
|
-
"ScreenContainer: starting to check river action providers to initialize",
|
|
59
|
-
{ actionsInitialStateSetters }
|
|
60
|
-
);
|
|
61
|
-
|
|
62
71
|
allSettled(actionsInitialStateSetters).finally(() => {
|
|
63
|
-
|
|
72
|
+
log_debug(
|
|
64
73
|
"ScreenContainer: action provider ready, completed. Starting to present screen"
|
|
65
74
|
);
|
|
66
75
|
|
|
67
76
|
setRiverActionProvidersReady(true);
|
|
68
77
|
});
|
|
69
78
|
} else {
|
|
70
|
-
|
|
79
|
+
log_debug(
|
|
71
80
|
"ScreenContainer: no action provider to check, completed. Starting to present screen"
|
|
72
81
|
);
|
|
73
82
|
|
|
@@ -108,24 +117,26 @@ export const GeneralContentScreen = ({
|
|
|
108
117
|
if (!isReady || isNilOrEmpty(components || uiComponents)) return null;
|
|
109
118
|
|
|
110
119
|
return (
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
120
|
+
<ScreenResolverFeedProvider id={screenId} useFeedData={useFeedData}>
|
|
121
|
+
<ScreenTrackedViewPositionsContext.Provider>
|
|
122
|
+
<CellTapContext.Provider value={contextValue}>
|
|
123
|
+
<ComponentsMap
|
|
124
|
+
feed={feed}
|
|
125
|
+
riverId={screenId}
|
|
126
|
+
groupId={groupId || `general-content-screen-${screenId}`}
|
|
127
|
+
riverComponents={components || uiComponents}
|
|
128
|
+
scrollViewExtraProps={scrollViewExtraProps}
|
|
129
|
+
getStaticComponentFeed={getStaticComponentFeed}
|
|
130
|
+
extraAnchorPointYOffset={extraAnchorPointYOffset}
|
|
131
|
+
isScreenWrappedInContainer={isScreenWrappedInContainer}
|
|
132
|
+
parentFocus={parentFocus}
|
|
133
|
+
focused={focused}
|
|
134
|
+
containerHeight={containerHeight}
|
|
135
|
+
preferredFocus={preferredFocus}
|
|
136
|
+
{...componentsMapExtraProps}
|
|
137
|
+
/>
|
|
138
|
+
</CellTapContext.Provider>
|
|
139
|
+
</ScreenTrackedViewPositionsContext.Provider>
|
|
140
|
+
</ScreenResolverFeedProvider>
|
|
130
141
|
);
|
|
131
142
|
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@testing-library/react-native";
|
|
3
|
+
import { GeneralContentScreen } from "../GeneralContentScreen";
|
|
4
|
+
|
|
5
|
+
const mockUseAppSelector = jest.fn();
|
|
6
|
+
const mockSelectRiverById = jest.fn();
|
|
7
|
+
const mockProviderSpy = jest.fn();
|
|
8
|
+
|
|
9
|
+
jest.mock("../../River/ComponentsMap", () => ({
|
|
10
|
+
ComponentsMap: () => {
|
|
11
|
+
const React = require("react");
|
|
12
|
+
const { View } = require("react-native");
|
|
13
|
+
|
|
14
|
+
return <View testID="components-map" />;
|
|
15
|
+
},
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/actions", () => ({
|
|
19
|
+
useActions: jest.fn(() => jest.fn()),
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
jest.mock("../utils", () => ({
|
|
23
|
+
logger: { warn: jest.fn() },
|
|
24
|
+
whenMatchingType: jest.fn((_type, value) => value),
|
|
25
|
+
}));
|
|
26
|
+
|
|
27
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/layout", () => ({
|
|
28
|
+
useLayoutVersion: jest.fn(() => false),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
jest.mock(
|
|
32
|
+
"@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData",
|
|
33
|
+
() => ({
|
|
34
|
+
useScreenData: jest.fn(() => ({
|
|
35
|
+
ui_components: [{ id: "ui-component" }],
|
|
36
|
+
general: {},
|
|
37
|
+
})),
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
jest.mock("../utils/useCurationAPI", () => ({
|
|
42
|
+
useCurationAPI: jest.fn(() => [{ id: "curation-component" }]),
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
|
|
46
|
+
useRiverInitialState: jest.fn(() => []),
|
|
47
|
+
}));
|
|
48
|
+
|
|
49
|
+
jest.mock("../utils/useEventAlerts", () => ({
|
|
50
|
+
useEventAlerts: jest.fn(),
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
jest.mock("@applicaster/zapp-react-native-redux", () => ({
|
|
54
|
+
useAppSelector: (...args) => mockUseAppSelector(...args),
|
|
55
|
+
selectRiverById: (...args) => mockSelectRiverById(...args),
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
jest.mock("../utils/getScreenDataSource", () => ({
|
|
59
|
+
getScreenDataSource: jest.fn(() => ({
|
|
60
|
+
source: "https://feed",
|
|
61
|
+
mapping: {},
|
|
62
|
+
})),
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
jest.mock(
|
|
66
|
+
"../../ScreenResolverFeedProvider/ScreenResolverFeedProvider",
|
|
67
|
+
() => ({
|
|
68
|
+
ScreenResolverFeedProvider: ({ id, useFeedData, children }) => {
|
|
69
|
+
const React = require("react");
|
|
70
|
+
const { View } = require("react-native");
|
|
71
|
+
|
|
72
|
+
mockProviderSpy(id, useFeedData);
|
|
73
|
+
useFeedData(id);
|
|
74
|
+
|
|
75
|
+
return <View testID="screen-resolver-feed-provider">{children}</View>;
|
|
76
|
+
},
|
|
77
|
+
})
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
describe("GeneralContentScreen", () => {
|
|
81
|
+
beforeEach(() => {
|
|
82
|
+
jest.clearAllMocks();
|
|
83
|
+
mockUseAppSelector.mockImplementation((selector) => selector({}));
|
|
84
|
+
mockSelectRiverById.mockReturnValue({ id: "screen-1" });
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("wraps content with ScreenResolverFeedProvider and renders ComponentsMap", () => {
|
|
88
|
+
const { getByTestId } = render(
|
|
89
|
+
<GeneralContentScreen
|
|
90
|
+
screenId="screen-1"
|
|
91
|
+
feed={null}
|
|
92
|
+
components={[{ id: "component-1" }]}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(getByTestId("screen-resolver-feed-provider")).toBeDefined();
|
|
97
|
+
expect(getByTestId("components-map")).toBeDefined();
|
|
98
|
+
|
|
99
|
+
expect(mockProviderSpy).toHaveBeenCalledWith(
|
|
100
|
+
"screen-1",
|
|
101
|
+
expect.any(Function)
|
|
102
|
+
);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getScreenDataSource } from "../getScreenDataSource";
|
|
2
|
+
|
|
3
|
+
describe("getScreenDataSource", () => {
|
|
4
|
+
it("returns screen_feed data when present", () => {
|
|
5
|
+
const result = getScreenDataSource({
|
|
6
|
+
data: {
|
|
7
|
+
screen_feed: {
|
|
8
|
+
source: "https://feed",
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
expect(result).toEqual({ source: "https://feed" });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns undefined when screen_feed is missing", () => {
|
|
17
|
+
expect(getScreenDataSource({ data: {} })).toBeUndefined();
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { get } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
|
+
|
|
3
|
+
const lookupPath = ["data", "screen_feed"];
|
|
4
|
+
|
|
5
|
+
export const getScreenDataSource = (
|
|
6
|
+
screenData: any
|
|
7
|
+
): Option<ZappDataSource> => {
|
|
8
|
+
return get(screenData, lookupPath) as ZappDataSource | undefined;
|
|
9
|
+
};
|
|
@@ -9,10 +9,9 @@ import {
|
|
|
9
9
|
import { isEmptyOrNil } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
10
10
|
import { Categories } from "./logger";
|
|
11
11
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
12
|
-
import {
|
|
12
|
+
import { useScreenContext } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
-
ZappPipesEntryContext,
|
|
16
15
|
ZappPipesScreenContext,
|
|
17
16
|
ZappPipesSearchContext,
|
|
18
17
|
} from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
@@ -136,7 +135,6 @@ export const useCurationAPI = (
|
|
|
136
135
|
[components]
|
|
137
136
|
);
|
|
138
137
|
|
|
139
|
-
const { pathname } = useRoute();
|
|
140
138
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
141
139
|
const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
142
140
|
|
|
@@ -146,10 +144,12 @@ export const useCurationAPI = (
|
|
|
146
144
|
screenContextType === TABS_SCREEN_TYPE ||
|
|
147
145
|
screenContextType === QB_TABS_SCREEN_TYPE;
|
|
148
146
|
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
147
|
+
const screenContextData = useScreenContext();
|
|
148
|
+
|
|
149
|
+
const entryContext = ((isNestedScreen && screenContextData?.nested?.entry
|
|
150
|
+
? screenContextData?.nested?.entry
|
|
151
|
+
: (screenContextData?.entry?.payload ?? screenContextData?.entry)) ||
|
|
152
|
+
{}) as ZappEntry;
|
|
153
153
|
|
|
154
154
|
const urlsMap = useMemo<{ [key: string]: string }>(() => {
|
|
155
155
|
const map = {};
|
|
@@ -5,8 +5,6 @@ import {
|
|
|
5
5
|
usePlugins,
|
|
6
6
|
} from "@applicaster/zapp-react-native-redux/hooks";
|
|
7
7
|
import {
|
|
8
|
-
useDimensions,
|
|
9
|
-
useIsTablet as isTablet,
|
|
10
8
|
useNavigation,
|
|
11
9
|
useRivers,
|
|
12
10
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
@@ -15,8 +13,8 @@ import { BufferAnimation } from "../PlayerContainer/BufferAnimation";
|
|
|
15
13
|
import { PlayerContainer } from "../PlayerContainer";
|
|
16
14
|
import { useModalSize } from "../VideoModal/hooks";
|
|
17
15
|
import { ViewStyle } from "react-native";
|
|
18
|
-
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
19
16
|
import { findCastPlugin, getPlayer } from "./utils";
|
|
17
|
+
import { useWaitForValidOrientation } from "../Screen/hooks";
|
|
20
18
|
|
|
21
19
|
type Props = {
|
|
22
20
|
item: ZappEntry;
|
|
@@ -31,13 +29,6 @@ type PlayableComponent = {
|
|
|
31
29
|
Component: React.ComponentType<any>;
|
|
32
30
|
};
|
|
33
31
|
|
|
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
32
|
export function HandlePlayable({
|
|
42
33
|
item,
|
|
43
34
|
isModal,
|
|
@@ -97,27 +88,23 @@ export function HandlePlayable({
|
|
|
97
88
|
});
|
|
98
89
|
}, [casting]);
|
|
99
90
|
|
|
100
|
-
const { width: screenWidth, height: screenHeight } =
|
|
101
|
-
useDimensions(dimensionsContext);
|
|
102
|
-
|
|
103
91
|
const modalSize = useModalSize();
|
|
104
92
|
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
);
|
|
93
|
+
const isOrientationReady = useWaitForValidOrientation();
|
|
94
|
+
|
|
95
|
+
const style = React.useMemo(() => {
|
|
96
|
+
const isFullScreenReady =
|
|
97
|
+
mode === "PIP" || (mode === "FULLSCREEN" && isOrientationReady);
|
|
98
|
+
|
|
99
|
+
const getDimensionValue = (value: string | number) => {
|
|
100
|
+
return isModal ? value : isFullScreenReady ? "100%" : 0; // do not show player, until full screen mode is ready
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
width: getDimensionValue(modalSize.width),
|
|
105
|
+
height: getDimensionValue(modalSize.height),
|
|
106
|
+
} as ViewStyle;
|
|
107
|
+
}, [modalSize, isModal, mode, isOrientationReady]);
|
|
121
108
|
|
|
122
109
|
const Component = playable?.Component;
|
|
123
110
|
|
|
@@ -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
|
+
});
|
|
@@ -15,12 +15,6 @@ const styles = StyleSheet.create({
|
|
|
15
15
|
flex: 1,
|
|
16
16
|
width: "100%",
|
|
17
17
|
},
|
|
18
|
-
themeStyles: {
|
|
19
|
-
// limits the height of the focusable container of the TopMenuBarTV component
|
|
20
|
-
// to prevent it from being overlapped by the screen content,
|
|
21
|
-
// as it makes TopMenuBarTV unfocusable on tvOS
|
|
22
|
-
maxHeight: 1,
|
|
23
|
-
},
|
|
24
18
|
});
|
|
25
19
|
|
|
26
20
|
export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
|
|
@@ -31,10 +25,7 @@ export const NavBarContainer = ({ children, isVisible, onReady }: Props) => {
|
|
|
31
25
|
}, [onReady]);
|
|
32
26
|
|
|
33
27
|
return isVisible ? (
|
|
34
|
-
<View
|
|
35
|
-
testID="nav-bar-container"
|
|
36
|
-
style={[styles.container, styles.themeStyles]}
|
|
37
|
-
>
|
|
28
|
+
<View testID="nav-bar-container" style={styles.container}>
|
|
38
29
|
{children}
|
|
39
30
|
</View>
|
|
40
31
|
) : null;
|
|
@@ -3,18 +3,13 @@
|
|
|
3
3
|
exports[`NavBarContainer renders 1`] = `
|
|
4
4
|
<View
|
|
5
5
|
style={
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
},
|
|
14
|
-
{
|
|
15
|
-
"maxHeight": 1,
|
|
16
|
-
},
|
|
17
|
-
]
|
|
6
|
+
{
|
|
7
|
+
"flex": 1,
|
|
8
|
+
"position": "absolute",
|
|
9
|
+
"top": 0,
|
|
10
|
+
"width": "100%",
|
|
11
|
+
"zIndex": 10,
|
|
12
|
+
}
|
|
18
13
|
}
|
|
19
14
|
testID="nav-bar-container"
|
|
20
15
|
>
|
|
@@ -14,18 +14,13 @@ exports[`ScreenContainer renders 1`] = `
|
|
|
14
14
|
>
|
|
15
15
|
<View
|
|
16
16
|
style={
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"maxHeight": 1,
|
|
27
|
-
},
|
|
28
|
-
]
|
|
17
|
+
{
|
|
18
|
+
"flex": 1,
|
|
19
|
+
"position": "absolute",
|
|
20
|
+
"top": 0,
|
|
21
|
+
"width": "100%",
|
|
22
|
+
"zIndex": 10,
|
|
23
|
+
}
|
|
29
24
|
}
|
|
30
25
|
testID="nav-bar-container"
|
|
31
26
|
>
|