@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4337072244 → 12.0.0-alpha.4342066143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Components/BaseFocusable/index.tsx +1 -1
- package/Components/Cell/Cell.tsx +5 -5
- package/Components/Cell/CellWithFocusable.tsx +5 -17
- package/Components/FocusableGroup/index.tsx +0 -1
- package/Components/HandlePlayable/HandlePlayable.tsx +0 -3
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/TransitionOverlay.tsx +64 -0
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +50 -10
- package/Components/Layout/TV/__tests__/index.test.tsx +74 -18
- package/Components/Layout/TV/index.tsx +105 -43
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +80 -109
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +1 -4
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +1 -4
- package/Components/PlayerContainer/PlayerContainer.tsx +1 -3
- package/Components/River/ComponentsMap/ComponentsMap.tsx +6 -0
- package/Components/River/RefreshControl.tsx +2 -2
- package/Components/River/TV/River.tsx +23 -0
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/ScreenResolver/index.tsx +1 -3
- package/Components/Transitioner/Scene.tsx +24 -19
- package/Components/Transitioner/Transitioner.tsx +9 -2
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +3 -0
- package/Components/VideoModal/PlayerDetails.tsx +3 -3
- package/Components/VideoModal/PlayerWrapper.tsx +69 -62
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Contexts/ScreenDataContext/index.ts +3 -0
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/package.json +5 -5
- package/Components/Screen/TV/hooks/index.ts +0 -3
- package/Components/Screen/TV/hooks/useInitialFocus.ts +0 -67
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +0 -22
- package/Components/Screen/TV/index.web.tsx +0 -174
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import * as R from "ramda";
|
|
3
3
|
import { View } from "react-native";
|
|
4
4
|
|
|
5
5
|
import { Focusable } from "@applicaster/zapp-react-native-ui-components/Components/Focusable";
|
|
@@ -105,8 +105,8 @@ export class CellComponent extends React.Component<Props> {
|
|
|
105
105
|
onPress(item, index);
|
|
106
106
|
} else {
|
|
107
107
|
const { item, navigator, component, appData } = this.props;
|
|
108
|
-
const itemTargetScreen = path(["screen_type"], item);
|
|
109
|
-
const componentTargetScreen = path(["data", "target"], component);
|
|
108
|
+
const itemTargetScreen = R.path(["screen_type"], item);
|
|
109
|
+
const componentTargetScreen = R.path(["data", "target"], component);
|
|
110
110
|
const itemType = getItemType(item, appData?.layoutVersion);
|
|
111
111
|
|
|
112
112
|
sendSelectCellEvent(item, component, item.title, index);
|
|
@@ -116,7 +116,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
116
116
|
componentTargetScreen &&
|
|
117
117
|
!itemTargetScreen
|
|
118
118
|
) {
|
|
119
|
-
navigator.push(merge(item, { screen_type: componentTargetScreen }));
|
|
119
|
+
navigator.push(R.merge(item, { screen_type: componentTargetScreen }));
|
|
120
120
|
|
|
121
121
|
return;
|
|
122
122
|
}
|
|
@@ -207,7 +207,7 @@ export class CellComponent extends React.Component<Props> {
|
|
|
207
207
|
|
|
208
208
|
const { id } = item;
|
|
209
209
|
|
|
210
|
-
const focusableId = join("-", [component?.id, id, index]);
|
|
210
|
+
const focusableId = R.join("-", [component?.id, id, index]);
|
|
211
211
|
|
|
212
212
|
const handleFocus = (focusable, mouse) => {
|
|
213
213
|
const focusFn = onFocus || noop;
|
|
@@ -6,20 +6,12 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
6
6
|
import { isAppleTV } from "../../Helpers/Platform";
|
|
7
7
|
import { useCellState } from "../MasterCell/utils";
|
|
8
8
|
|
|
9
|
-
const useCellFocusedState = (
|
|
10
|
-
skipFocusManagerRegistration: boolean,
|
|
11
|
-
groupId: string,
|
|
12
|
-
id: string
|
|
13
|
-
) => {
|
|
9
|
+
const useCellFocusedState = (groupId: string, id: string) => {
|
|
14
10
|
const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
|
|
15
11
|
|
|
16
12
|
React.useEffect(() => {
|
|
17
|
-
const isGroupItemFocused = () =>
|
|
18
|
-
|
|
19
|
-
const isFocused = focusManager.isGroupItemFocused(groupId, id);
|
|
20
|
-
setCurrentCellFocused(isFocused);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
13
|
+
const isGroupItemFocused = () =>
|
|
14
|
+
setCurrentCellFocused(focusManager.isGroupItemFocused(groupId, id));
|
|
23
15
|
|
|
24
16
|
const handler = () => {
|
|
25
17
|
// tvOS hack for properly checking focus
|
|
@@ -37,7 +29,7 @@ const useCellFocusedState = (
|
|
|
37
29
|
return () => {
|
|
38
30
|
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
|
|
39
31
|
};
|
|
40
|
-
}, [groupId
|
|
32
|
+
}, [groupId]);
|
|
41
33
|
|
|
42
34
|
return currentCellFocused;
|
|
43
35
|
};
|
|
@@ -73,11 +65,7 @@ export function CellWithFocusable(props: Props) {
|
|
|
73
65
|
selected,
|
|
74
66
|
} = props;
|
|
75
67
|
|
|
76
|
-
const isFocused = useCellFocusedState(
|
|
77
|
-
skipFocusManagerRegistration,
|
|
78
|
-
groupId,
|
|
79
|
-
id
|
|
80
|
-
);
|
|
68
|
+
const isFocused = useCellFocusedState(groupId, id);
|
|
81
69
|
|
|
82
70
|
const state = useCellState({
|
|
83
71
|
id: item.id,
|
|
@@ -19,7 +19,6 @@ type Props = {
|
|
|
19
19
|
modalHeight?: number;
|
|
20
20
|
modalWidth?: number;
|
|
21
21
|
mode: VideoModalMode;
|
|
22
|
-
groupId?: string;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
@@ -94,7 +93,6 @@ export function HandlePlayable({
|
|
|
94
93
|
modalHeight,
|
|
95
94
|
modalWidth,
|
|
96
95
|
mode,
|
|
97
|
-
groupId,
|
|
98
96
|
}: Props): React.ReactElement | null {
|
|
99
97
|
const state = usePickFromState();
|
|
100
98
|
|
|
@@ -169,7 +167,6 @@ export function HandlePlayable({
|
|
|
169
167
|
isModal={isModal}
|
|
170
168
|
mode={mode}
|
|
171
169
|
disableCastAction={playerModuleProperties?.disableCastAction}
|
|
172
|
-
groupId={groupId}
|
|
173
170
|
/>
|
|
174
171
|
);
|
|
175
172
|
}
|
|
@@ -60,7 +60,7 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
60
60
|
initialState
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
const
|
|
63
|
+
const screeenLayoutValue = React.useMemo(
|
|
64
64
|
() => ({
|
|
65
65
|
...screenLayout,
|
|
66
66
|
setScreenLayout,
|
|
@@ -69,7 +69,7 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
69
69
|
);
|
|
70
70
|
|
|
71
71
|
return (
|
|
72
|
-
<ScreenLayoutContext.Provider value={
|
|
72
|
+
<ScreenLayoutContext.Provider value={screeenLayoutValue}>
|
|
73
73
|
{props.children}
|
|
74
74
|
</ScreenLayoutContext.Provider>
|
|
75
75
|
);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View, StyleSheet } from "react-native";
|
|
3
|
+
import { useCurrentScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
4
|
+
import { ifEmptyUseFallback } from "@applicaster/zapp-react-native-utils/cellUtils";
|
|
5
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
6
|
+
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
7
|
+
import { Spinner } from "@applicaster/zapp-react-native-ui-components/Components/Spinner";
|
|
8
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
9
|
+
|
|
10
|
+
import { useScreenConfiguration } from "../../River/useScreenConfiguration";
|
|
11
|
+
|
|
12
|
+
const styles = StyleSheet.create({
|
|
13
|
+
container: {
|
|
14
|
+
position: "absolute",
|
|
15
|
+
top: 0,
|
|
16
|
+
left: 0,
|
|
17
|
+
right: 0,
|
|
18
|
+
bottom: 0,
|
|
19
|
+
|
|
20
|
+
alignItems: "center",
|
|
21
|
+
justifyContent: "center",
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const TransitionOverlay = () => {
|
|
26
|
+
const screen = useCurrentScreenData();
|
|
27
|
+
|
|
28
|
+
const { backgroundColor: screenBackgroundColor } = useScreenConfiguration(
|
|
29
|
+
screen?.id
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const theme = useTheme();
|
|
33
|
+
|
|
34
|
+
const themeBackgroundColor = React.useMemo(
|
|
35
|
+
() => theme.app_background_color,
|
|
36
|
+
[theme.app_background_color]
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const backgroundColor = ifEmptyUseFallback(
|
|
40
|
+
screenBackgroundColor,
|
|
41
|
+
themeBackgroundColor
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const {
|
|
45
|
+
appState: { isTransitioning },
|
|
46
|
+
} = usePickFromState(["appState"]);
|
|
47
|
+
|
|
48
|
+
if (!isWeb() || !isTransitioning) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<View
|
|
54
|
+
style={[
|
|
55
|
+
styles.container,
|
|
56
|
+
{
|
|
57
|
+
backgroundColor,
|
|
58
|
+
},
|
|
59
|
+
]}
|
|
60
|
+
>
|
|
61
|
+
<Spinner size={"large"} />
|
|
62
|
+
</View>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
@@ -2,18 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Layout TV renders 1`] = `
|
|
4
4
|
<View
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
style={
|
|
6
|
+
Object {
|
|
7
|
+
"flex": 1,
|
|
8
|
+
"height": 1080,
|
|
9
|
+
"width": 1920,
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
testID="layout-container"
|
|
8
13
|
>
|
|
9
14
|
<View
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
backgroundImageUrl="http://applicaster.com"
|
|
16
|
+
testID="background-component"
|
|
17
|
+
>
|
|
18
|
+
<View
|
|
19
|
+
style={
|
|
20
|
+
Array [
|
|
21
|
+
Object {
|
|
22
|
+
"position": "absolute",
|
|
23
|
+
"top": 0,
|
|
24
|
+
"width": 1920,
|
|
25
|
+
"zIndex": 10,
|
|
26
|
+
},
|
|
27
|
+
Object {
|
|
28
|
+
"maxHeight": 10,
|
|
29
|
+
},
|
|
30
|
+
]
|
|
14
31
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
32
|
+
testID="nav-bar-container"
|
|
33
|
+
>
|
|
34
|
+
<View
|
|
35
|
+
isVisible={true}
|
|
36
|
+
menuPlugin={
|
|
37
|
+
Object {
|
|
38
|
+
"module": [Function],
|
|
39
|
+
"name": "resolved-menu-plug",
|
|
40
|
+
"type": "menu",
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
navigationProps={
|
|
44
|
+
Object {
|
|
45
|
+
"assets": undefined,
|
|
46
|
+
"home": undefined,
|
|
47
|
+
"nav_items": undefined,
|
|
48
|
+
"rules": undefined,
|
|
49
|
+
"selected": undefined,
|
|
50
|
+
"styles": undefined,
|
|
51
|
+
"title": "",
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
testID="nav-bar-component"
|
|
55
|
+
/>
|
|
56
|
+
</View>
|
|
57
|
+
</View>
|
|
18
58
|
</View>
|
|
19
59
|
`;
|
|
@@ -1,48 +1,79 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import * as R from "ramda";
|
|
3
3
|
import { View } from "react-native";
|
|
4
4
|
import { render } from "@testing-library/react-native";
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
|
+
import { createStore } from "redux";
|
|
6
7
|
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
7
|
-
import configureStore from "redux-mock-store";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
|
|
10
10
|
|
|
11
|
-
jest.mock("
|
|
12
|
-
|
|
11
|
+
jest.mock("@applicaster/quick-brick-core/App/ActionSetters", () => ({
|
|
12
|
+
useRiverInitialState: () => ({}),
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
|
+
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen");
|
|
16
|
+
|
|
15
17
|
const Layout = require("..").default;
|
|
16
18
|
|
|
17
|
-
const
|
|
19
|
+
const ResolvedMenuPlug = () => <View testID="resolved-menu-plug" />;
|
|
20
|
+
|
|
21
|
+
const plugins = [
|
|
22
|
+
{
|
|
23
|
+
module: ResolvedMenuPlug,
|
|
24
|
+
type: "menu",
|
|
25
|
+
name: "resolved-menu-plug",
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const bgImage = "http://applicaster.com";
|
|
30
|
+
const isNavBarVisible = true;
|
|
31
|
+
|
|
32
|
+
const store = createStore(() => ({
|
|
18
33
|
appState: { appReady: true },
|
|
19
|
-
}
|
|
34
|
+
remoteConfigurations: { sdkAssets: { bgImage } },
|
|
35
|
+
plugins,
|
|
36
|
+
}));
|
|
20
37
|
|
|
21
38
|
describe("Layout TV", () => {
|
|
39
|
+
const themes = {
|
|
40
|
+
myTheme: { screen_margin_top: 10, screen_margin_bottom: 10 },
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const selectedThemeId = "myTheme";
|
|
44
|
+
|
|
22
45
|
const navigator = {
|
|
46
|
+
activeRiver: {
|
|
47
|
+
navigations: [{ category: "menu", navigation_type: "menu" }],
|
|
48
|
+
},
|
|
49
|
+
canGoBack: () => false,
|
|
23
50
|
currentRoute: "/river/A1234",
|
|
24
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
],
|
|
51
|
+
screenData: {
|
|
52
|
+
navigations: [{ category: "menu", navigation_type: "menu" }],
|
|
53
|
+
},
|
|
54
|
+
isNavBarVisible: isNavBarVisible,
|
|
30
55
|
};
|
|
31
56
|
|
|
32
57
|
const wrapper = ({ children }) => (
|
|
33
|
-
<Provider store={
|
|
58
|
+
<Provider store={store}>
|
|
34
59
|
<NavigationContext.Provider value={navigator}>
|
|
35
|
-
{
|
|
60
|
+
<ThemeContext.Provider value={{ themes, selectedThemeId }}>
|
|
61
|
+
{children}
|
|
62
|
+
</ThemeContext.Provider>
|
|
36
63
|
</NavigationContext.Provider>
|
|
37
64
|
</Provider>
|
|
38
65
|
);
|
|
39
66
|
|
|
67
|
+
const Screen = (props) => (
|
|
68
|
+
<View testID="screen-component" {...R.omit(["children"])(props)} />
|
|
69
|
+
);
|
|
70
|
+
|
|
40
71
|
const NavBar = (props) => (
|
|
41
|
-
<View testID="nav-bar-component" {...
|
|
72
|
+
<View testID="nav-bar-component" {...R.omit(["children"])(props)} />
|
|
42
73
|
);
|
|
43
74
|
|
|
44
75
|
const Background = (props: Record<any, any>) => (
|
|
45
|
-
<View testID="background-component" {...
|
|
76
|
+
<View testID="background-component" {...R.omit(["children"])(props)}>
|
|
46
77
|
{props.children}
|
|
47
78
|
</View>
|
|
48
79
|
);
|
|
@@ -53,8 +84,33 @@ describe("Layout TV", () => {
|
|
|
53
84
|
};
|
|
54
85
|
|
|
55
86
|
it("renders", () => {
|
|
56
|
-
const { toJSON } = render(
|
|
87
|
+
const { toJSON } = render(
|
|
88
|
+
<Layout Components={Components}>
|
|
89
|
+
<Screen />
|
|
90
|
+
</Layout>,
|
|
91
|
+
{ wrapper }
|
|
92
|
+
);
|
|
57
93
|
|
|
58
94
|
expect(toJSON()).toMatchSnapshot();
|
|
59
95
|
});
|
|
96
|
+
|
|
97
|
+
describe("props passed to background component", () => {
|
|
98
|
+
it("passes correct props", () => {
|
|
99
|
+
const { getByTestId } = render(
|
|
100
|
+
<Layout
|
|
101
|
+
Components={Components}
|
|
102
|
+
ComponentsExtraProps={{
|
|
103
|
+
Background: { testProp: true },
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<Screen />
|
|
107
|
+
</Layout>,
|
|
108
|
+
{ wrapper }
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const bgComponent = getByTestId("background-component");
|
|
112
|
+
expect(bgComponent.props.backgroundImageUrl).toBe(bgImage);
|
|
113
|
+
expect(bgComponent.props.testProp).toBe(true);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
60
116
|
});
|
|
@@ -1,69 +1,131 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import * as R from "ramda";
|
|
3
3
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
-
import {
|
|
5
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getNavigationProps,
|
|
9
|
+
resolveNavigationPlugin,
|
|
10
|
+
routeIsPlayerScreen,
|
|
11
|
+
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
12
|
+
|
|
13
|
+
import { getBackgroundImageUrl } from "../utils";
|
|
14
|
+
import { LayoutContainer } from "./LayoutContainer";
|
|
15
|
+
import { NavBarContainer } from "./NavBarContainer";
|
|
16
|
+
import { ScreenContainer } from "./ScreenContainer";
|
|
17
|
+
import { TransitionOverlay } from "./TransitionOverlay";
|
|
6
18
|
|
|
7
19
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
20
|
+
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
8
21
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
export const ScreenDataContext = React.createContext(null);
|
|
22
|
+
import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
23
|
+
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
13
24
|
|
|
14
25
|
type Components = {
|
|
15
26
|
NavBar: React.ComponentType<any>;
|
|
16
27
|
Background: React.ComponentType<any>;
|
|
17
28
|
};
|
|
18
29
|
|
|
30
|
+
type ComponentsExtraProps = {
|
|
31
|
+
Background?: Record<string, any>;
|
|
32
|
+
NavBar?: Record<string, any>;
|
|
33
|
+
};
|
|
34
|
+
|
|
19
35
|
type Props = {
|
|
20
36
|
Components: Components;
|
|
37
|
+
ComponentsExtraProps?: ComponentsExtraProps;
|
|
38
|
+
children: React.ReactNode;
|
|
21
39
|
};
|
|
22
40
|
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
41
|
+
const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
42
|
+
const navigator = useNavigation();
|
|
43
|
+
const theme = useTheme();
|
|
44
|
+
const { title, visible } = useNavbarState();
|
|
45
|
+
const { activeRiver, currentRoute } = navigator;
|
|
46
|
+
|
|
47
|
+
const {
|
|
48
|
+
appState: { appReady = false } = {},
|
|
49
|
+
remoteConfigurations,
|
|
50
|
+
plugins = [],
|
|
51
|
+
} = usePickFromState(["appState", "remoteConfigurations", "plugins"]);
|
|
52
|
+
|
|
53
|
+
const navigationProps = getNavigationProps({
|
|
54
|
+
navigator,
|
|
55
|
+
title,
|
|
56
|
+
category: "menu",
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const backgroundColor = React.useMemo(() => theme.app_background_color, []);
|
|
60
|
+
|
|
61
|
+
const backgroundImageUrl = React.useMemo(
|
|
62
|
+
() => getBackgroundImageUrl(remoteConfigurations),
|
|
63
|
+
[remoteConfigurations]
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const menuPlugin = React.useMemo(
|
|
67
|
+
() =>
|
|
68
|
+
resolveNavigationPlugin({
|
|
69
|
+
category: "menu",
|
|
70
|
+
navigations: activeRiver?.navigations,
|
|
71
|
+
plugins,
|
|
72
|
+
}) as QuickBrickPlugin,
|
|
73
|
+
[]
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const NavBar = React.useMemo(
|
|
77
|
+
() => Components.NavBar || (menuPlugin.module as React.ComponentType<any>),
|
|
78
|
+
[]
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const [navBarReady, setNavBarReady] = React.useState(false);
|
|
82
|
+
|
|
83
|
+
const navBarContainer = (
|
|
84
|
+
<NavBarContainer isVisible={visible} onReady={setNavBarReady}>
|
|
85
|
+
<NavBar
|
|
86
|
+
ref={ComponentsExtraProps?.NavBar?.ref}
|
|
87
|
+
isVisible={visible && !routeIsPlayerScreen(currentRoute)}
|
|
88
|
+
menuPlugin={menuPlugin}
|
|
89
|
+
navigationProps={navigationProps}
|
|
90
|
+
{...R.omit(["ref"])(ComponentsExtraProps?.NavBar)}
|
|
91
|
+
/>
|
|
92
|
+
</NavBarContainer>
|
|
93
|
+
);
|
|
54
94
|
|
|
55
|
-
const
|
|
56
|
-
const { appState } = usePickFromState(["appState"]);
|
|
57
|
-
const appReady = pathOr(false, ["appReady"], appState);
|
|
95
|
+
const isTVOS = isApplePlatform();
|
|
58
96
|
|
|
59
97
|
if (!appReady) {
|
|
60
98
|
return null;
|
|
61
99
|
}
|
|
62
100
|
|
|
63
101
|
return (
|
|
64
|
-
<
|
|
65
|
-
<
|
|
66
|
-
|
|
102
|
+
<LayoutContainer>
|
|
103
|
+
<ScreenLayoutContextProvider>
|
|
104
|
+
<Components.Background
|
|
105
|
+
backgroundColor={backgroundColor}
|
|
106
|
+
backgroundImageUrl={backgroundImageUrl}
|
|
107
|
+
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
108
|
+
>
|
|
109
|
+
<ScreenDataContext.Provider value={navigator.data}>
|
|
110
|
+
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
111
|
+
{!isTVOS ? navBarContainer : null}
|
|
112
|
+
{navBarReady ? (
|
|
113
|
+
/**
|
|
114
|
+
Need to re-mount this component on each navigation event
|
|
115
|
+
It's a hack to work around the fact that we don't support
|
|
116
|
+
correct screen rendering in our navigator (shared currentRoute state)
|
|
117
|
+
**/
|
|
118
|
+
<ScreenContainer>{children}</ScreenContainer>
|
|
119
|
+
) : null}
|
|
120
|
+
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
121
|
+
focus manager works correctly to focus nav bar items first **/}
|
|
122
|
+
{isTVOS ? navBarContainer : null}
|
|
123
|
+
</PathnameContext.Provider>
|
|
124
|
+
</ScreenDataContext.Provider>
|
|
125
|
+
<TransitionOverlay />
|
|
126
|
+
</Components.Background>
|
|
127
|
+
</ScreenLayoutContextProvider>
|
|
128
|
+
</LayoutContainer>
|
|
67
129
|
);
|
|
68
130
|
};
|
|
69
131
|
|