@applicaster/zapp-react-native-ui-components 12.0.0-rc.69 → 12.0.0-rc.70
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 +17 -5
- package/Components/FocusableGroup/index.tsx +1 -0
- package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
- package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +10 -50
- package/Components/Layout/TV/__tests__/index.test.tsx +18 -74
- package/Components/Layout/TV/index.tsx +9 -108
- package/Components/Layout/index.tsx +1 -9
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.android.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/tv/ButtonContainerView/index.tsx +4 -1
- package/Components/Navigator/StackNavigator.tsx +48 -0
- package/Components/Navigator/index.ts +1 -0
- package/Components/PlayerContainer/PlayerContainer.tsx +3 -1
- package/Components/River/TV/River.tsx +0 -23
- package/Components/Screen/TV/hooks/index.ts +3 -0
- package/Components/Screen/TV/hooks/useInitialFocus.ts +70 -0
- package/Components/Screen/TV/hooks/useRestoreFocus.ts +22 -0
- package/Components/Screen/TV/index.web.tsx +179 -0
- package/Components/ScreenResolver/index.tsx +3 -1
- package/Components/VideoLive/LiveImageManager.ts +15 -1
- package/Components/VideoModal/PlayerWrapper.tsx +8 -8
- package/Components/VideoModal/VideoModal.tsx +4 -4
- package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
- package/package.json +5 -5
- package/Components/Layout/TV/TransitionOverlay.tsx +0 -64
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { join, path, merge } 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 =
|
|
109
|
-
const componentTargetScreen =
|
|
108
|
+
const itemTargetScreen = path(["screen_type"], item);
|
|
109
|
+
const componentTargetScreen = 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(
|
|
119
|
+
navigator.push(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 =
|
|
210
|
+
const focusableId = join("-", [component?.id, id, index]);
|
|
211
211
|
|
|
212
212
|
const handleFocus = (focusable, mouse) => {
|
|
213
213
|
const focusFn = onFocus || noop;
|
|
@@ -6,12 +6,20 @@ 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 = (
|
|
9
|
+
const useCellFocusedState = (
|
|
10
|
+
skipFocusManagerRegistration: boolean,
|
|
11
|
+
groupId: string,
|
|
12
|
+
id: string
|
|
13
|
+
) => {
|
|
10
14
|
const [currentCellFocused, setCurrentCellFocused] = React.useState(false);
|
|
11
15
|
|
|
12
16
|
React.useEffect(() => {
|
|
13
|
-
const isGroupItemFocused = () =>
|
|
14
|
-
|
|
17
|
+
const isGroupItemFocused = () => {
|
|
18
|
+
if (!skipFocusManagerRegistration) {
|
|
19
|
+
const isFocused = focusManager.isGroupItemFocused(groupId, id);
|
|
20
|
+
setCurrentCellFocused(isFocused);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
15
23
|
|
|
16
24
|
const handler = () => {
|
|
17
25
|
// tvOS hack for properly checking focus
|
|
@@ -29,7 +37,7 @@ const useCellFocusedState = (groupId: string, id: string) => {
|
|
|
29
37
|
return () => {
|
|
30
38
|
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, handler);
|
|
31
39
|
};
|
|
32
|
-
}, [groupId]);
|
|
40
|
+
}, [groupId, skipFocusManagerRegistration]);
|
|
33
41
|
|
|
34
42
|
return currentCellFocused;
|
|
35
43
|
};
|
|
@@ -65,7 +73,11 @@ export function CellWithFocusable(props: Props) {
|
|
|
65
73
|
selected,
|
|
66
74
|
} = props;
|
|
67
75
|
|
|
68
|
-
const isFocused = useCellFocusedState(
|
|
76
|
+
const isFocused = useCellFocusedState(
|
|
77
|
+
skipFocusManagerRegistration,
|
|
78
|
+
groupId,
|
|
79
|
+
id
|
|
80
|
+
);
|
|
69
81
|
|
|
70
82
|
const state = useCellState({
|
|
71
83
|
id: item.id,
|
|
@@ -19,6 +19,7 @@ type Props = {
|
|
|
19
19
|
modalHeight?: number;
|
|
20
20
|
modalWidth?: number;
|
|
21
21
|
mode: VideoModalMode;
|
|
22
|
+
groupId?: string;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
const YOUTUBE_PLUGIN_ID = "youtube-player-qb";
|
|
@@ -93,6 +94,7 @@ export function HandlePlayable({
|
|
|
93
94
|
modalHeight,
|
|
94
95
|
modalWidth,
|
|
95
96
|
mode,
|
|
97
|
+
groupId,
|
|
96
98
|
}: Props): React.ReactElement | null {
|
|
97
99
|
const state = usePickFromState();
|
|
98
100
|
|
|
@@ -167,6 +169,7 @@ export function HandlePlayable({
|
|
|
167
169
|
isModal={isModal}
|
|
168
170
|
mode={mode}
|
|
169
171
|
disableCastAction={playerModuleProperties?.disableCastAction}
|
|
172
|
+
groupId={groupId}
|
|
170
173
|
/>
|
|
171
174
|
);
|
|
172
175
|
}
|
|
@@ -60,7 +60,7 @@ export function ScreenLayoutContextProvider(props: {
|
|
|
60
60
|
initialState
|
|
61
61
|
);
|
|
62
62
|
|
|
63
|
-
const
|
|
63
|
+
const screenLayoutValue = 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={screenLayoutValue}>
|
|
73
73
|
{props.children}
|
|
74
74
|
</ScreenLayoutContext.Provider>
|
|
75
75
|
);
|
|
@@ -2,58 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`Layout TV renders 1`] = `
|
|
4
4
|
<View
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"height": 1080,
|
|
9
|
-
"width": 1920,
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
testID="layout-container"
|
|
5
|
+
excludeFromFocusSearching={true}
|
|
6
|
+
id="/river/A1234"
|
|
7
|
+
preferredFocus={true}
|
|
13
8
|
>
|
|
14
9
|
<View
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
]
|
|
10
|
+
Components={
|
|
11
|
+
Object {
|
|
12
|
+
"Background": [Function],
|
|
13
|
+
"NavBar": [Function],
|
|
31
14
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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>
|
|
15
|
+
}
|
|
16
|
+
route="/river/A1234"
|
|
17
|
+
/>
|
|
58
18
|
</View>
|
|
59
19
|
`;
|
|
@@ -1,79 +1,48 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
2
|
+
import { omit } 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";
|
|
7
6
|
import { NavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NavigationContext";
|
|
7
|
+
import configureStore from "redux-mock-store";
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
const withoutChildren = omit(["children"]);
|
|
10
10
|
|
|
11
|
-
jest.mock("
|
|
12
|
-
|
|
11
|
+
jest.mock("../../../Screen/TV/index.web", () => ({
|
|
12
|
+
Screen: View,
|
|
13
13
|
}));
|
|
14
14
|
|
|
15
|
-
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen");
|
|
16
|
-
|
|
17
15
|
const Layout = require("..").default;
|
|
18
16
|
|
|
19
|
-
const
|
|
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(() => ({
|
|
17
|
+
const mockStore = configureStore()({
|
|
33
18
|
appState: { appReady: true },
|
|
34
|
-
|
|
35
|
-
plugins,
|
|
36
|
-
}));
|
|
19
|
+
});
|
|
37
20
|
|
|
38
21
|
describe("Layout TV", () => {
|
|
39
|
-
const themes = {
|
|
40
|
-
myTheme: { screen_margin_top: 10, screen_margin_bottom: 10 },
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const selectedThemeId = "myTheme";
|
|
44
|
-
|
|
45
22
|
const navigator = {
|
|
46
|
-
activeRiver: {
|
|
47
|
-
navigations: [{ category: "menu", navigation_type: "menu" }],
|
|
48
|
-
},
|
|
49
|
-
canGoBack: () => false,
|
|
50
23
|
currentRoute: "/river/A1234",
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
24
|
+
mainStack: [
|
|
25
|
+
{
|
|
26
|
+
route: "/river/A1234",
|
|
27
|
+
state: "state",
|
|
28
|
+
},
|
|
29
|
+
],
|
|
55
30
|
};
|
|
56
31
|
|
|
57
32
|
const wrapper = ({ children }) => (
|
|
58
|
-
<Provider store={
|
|
33
|
+
<Provider store={mockStore}>
|
|
59
34
|
<NavigationContext.Provider value={navigator}>
|
|
60
|
-
|
|
61
|
-
{children}
|
|
62
|
-
</ThemeContext.Provider>
|
|
35
|
+
{children}
|
|
63
36
|
</NavigationContext.Provider>
|
|
64
37
|
</Provider>
|
|
65
38
|
);
|
|
66
39
|
|
|
67
|
-
const Screen = (props) => (
|
|
68
|
-
<View testID="screen-component" {...R.omit(["children"])(props)} />
|
|
69
|
-
);
|
|
70
|
-
|
|
71
40
|
const NavBar = (props) => (
|
|
72
|
-
<View testID="nav-bar-component" {...
|
|
41
|
+
<View testID="nav-bar-component" {...withoutChildren(props)} />
|
|
73
42
|
);
|
|
74
43
|
|
|
75
44
|
const Background = (props: Record<any, any>) => (
|
|
76
|
-
<View testID="background-component" {...
|
|
45
|
+
<View testID="background-component" {...withoutChildren(props)}>
|
|
77
46
|
{props.children}
|
|
78
47
|
</View>
|
|
79
48
|
);
|
|
@@ -84,33 +53,8 @@ describe("Layout TV", () => {
|
|
|
84
53
|
};
|
|
85
54
|
|
|
86
55
|
it("renders", () => {
|
|
87
|
-
const { toJSON } = render(
|
|
88
|
-
<Layout Components={Components}>
|
|
89
|
-
<Screen />
|
|
90
|
-
</Layout>,
|
|
91
|
-
{ wrapper }
|
|
92
|
-
);
|
|
56
|
+
const { toJSON } = render(<Layout Components={Components} />, { wrapper });
|
|
93
57
|
|
|
94
58
|
expect(toJSON()).toMatchSnapshot();
|
|
95
59
|
});
|
|
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
|
-
});
|
|
116
60
|
});
|
|
@@ -1,131 +1,32 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import
|
|
3
|
-
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
4
|
-
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
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";
|
|
2
|
+
import { pathOr } from "ramda";
|
|
12
3
|
|
|
13
|
-
import {
|
|
14
|
-
import { LayoutContainer } from "./LayoutContainer";
|
|
15
|
-
import { NavBarContainer } from "./NavBarContainer";
|
|
16
|
-
import { ScreenContainer } from "./ScreenContainer";
|
|
17
|
-
import { TransitionOverlay } from "./TransitionOverlay";
|
|
4
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
18
5
|
|
|
19
6
|
import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
20
|
-
import {
|
|
21
|
-
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
22
|
-
import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
23
|
-
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
7
|
+
import { StackNavigator } from "../../Navigator";
|
|
24
8
|
|
|
25
9
|
type Components = {
|
|
26
10
|
NavBar: React.ComponentType<any>;
|
|
27
11
|
Background: React.ComponentType<any>;
|
|
28
12
|
};
|
|
29
13
|
|
|
30
|
-
type ComponentsExtraProps = {
|
|
31
|
-
Background?: Record<string, any>;
|
|
32
|
-
NavBar?: Record<string, any>;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
14
|
type Props = {
|
|
36
15
|
Components: Components;
|
|
37
|
-
ComponentsExtraProps?: ComponentsExtraProps;
|
|
38
|
-
children: React.ReactNode;
|
|
39
16
|
};
|
|
40
17
|
|
|
41
|
-
const Layout = ({ Components
|
|
42
|
-
const
|
|
43
|
-
const
|
|
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
|
-
);
|
|
94
|
-
|
|
95
|
-
const isTVOS = isApplePlatform();
|
|
18
|
+
const Layout = ({ Components }: Props) => {
|
|
19
|
+
const { appState } = usePickFromState(["appState"]);
|
|
20
|
+
const appReady = pathOr(false, ["appReady"], appState);
|
|
96
21
|
|
|
97
22
|
if (!appReady) {
|
|
98
23
|
return null;
|
|
99
24
|
}
|
|
100
25
|
|
|
101
26
|
return (
|
|
102
|
-
<
|
|
103
|
-
<
|
|
104
|
-
|
|
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>
|
|
27
|
+
<ScreenLayoutContextProvider>
|
|
28
|
+
<StackNavigator Components={Components} />
|
|
29
|
+
</ScreenLayoutContextProvider>
|
|
129
30
|
);
|
|
130
31
|
};
|
|
131
32
|
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
3
|
-
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
4
|
-
import { ScreenContextProvider } from "../../Contexts/ScreenContext";
|
|
5
3
|
|
|
6
4
|
import Mobile from "./Mobile";
|
|
7
5
|
import TV from "./TV";
|
|
8
6
|
|
|
9
7
|
export default function Layout(props) {
|
|
10
|
-
const { currentRoute: pathname } = useNavigation();
|
|
11
|
-
|
|
12
8
|
if (isTV()) {
|
|
13
|
-
return
|
|
14
|
-
<ScreenContextProvider pathname={pathname}>
|
|
15
|
-
<TV {...props} />
|
|
16
|
-
</ScreenContextProvider>
|
|
17
|
-
);
|
|
9
|
+
return <TV {...props} />;
|
|
18
10
|
} else {
|
|
19
11
|
return <Mobile {...props} />;
|
|
20
12
|
}
|
|
@@ -61,7 +61,10 @@ export function ButtonContainerView({
|
|
|
61
61
|
<View style={applyRTLStylesIfNeeded(style, isRTL)}>
|
|
62
62
|
{insertBetween(
|
|
63
63
|
(index) => (
|
|
64
|
-
<HorizontalSeparator
|
|
64
|
+
<HorizontalSeparator
|
|
65
|
+
key={`separator_${index}`}
|
|
66
|
+
width={horizontalGutter}
|
|
67
|
+
/>
|
|
65
68
|
),
|
|
66
69
|
cloneElementsWithIds(buttonIds, filteredChildren)
|
|
67
70
|
)}
|
|
@@ -29,7 +29,10 @@ export function ButtonContainerView({
|
|
|
29
29
|
<View style={style}>
|
|
30
30
|
{insertBetween(
|
|
31
31
|
(index) => (
|
|
32
|
-
<HorizontalSeparator
|
|
32
|
+
<HorizontalSeparator
|
|
33
|
+
key={`separator_${index}`}
|
|
34
|
+
width={horizontalGutter}
|
|
35
|
+
/>
|
|
33
36
|
),
|
|
34
37
|
filteredChildren
|
|
35
38
|
)}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { isEmpty } from "ramda";
|
|
3
|
+
|
|
4
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
5
|
+
import { getPathAttributes } from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
6
|
+
import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
|
|
7
|
+
import { ScreenDataContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ScreenDataContext";
|
|
8
|
+
import { PathnameContext } from "@applicaster/zapp-react-native-ui-components/Contexts/PathnameContext";
|
|
9
|
+
|
|
10
|
+
import { Screen } from "../Screen/TV/index.web";
|
|
11
|
+
|
|
12
|
+
type Components = {
|
|
13
|
+
NavBar: React.ComponentType<any>;
|
|
14
|
+
Background: React.ComponentType<any>;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type Props = {
|
|
18
|
+
Components: Components;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const StackNavigator = ({ Components }: Props) => {
|
|
22
|
+
const { mainStack, currentRoute } = useNavigation();
|
|
23
|
+
|
|
24
|
+
const renderScreen = ({ route, state }) => {
|
|
25
|
+
const pathAttributes = getPathAttributes({ pathname: route });
|
|
26
|
+
|
|
27
|
+
if (isEmpty(pathAttributes)) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<FocusableGroup
|
|
33
|
+
id={route}
|
|
34
|
+
preferredFocus={route === currentRoute}
|
|
35
|
+
excludeFromFocusSearching
|
|
36
|
+
key={route}
|
|
37
|
+
>
|
|
38
|
+
<ScreenDataContext.Provider value={state}>
|
|
39
|
+
<PathnameContext.Provider value={route}>
|
|
40
|
+
<Screen route={route} Components={Components} />
|
|
41
|
+
</PathnameContext.Provider>
|
|
42
|
+
</ScreenDataContext.Provider>
|
|
43
|
+
</FocusableGroup>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
return <>{mainStack.map(renderScreen)}</>;
|
|
48
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { StackNavigator } from "./StackNavigator";
|
|
@@ -68,6 +68,7 @@ type Props = {
|
|
|
68
68
|
mode?: VideoModalMode;
|
|
69
69
|
loadPipesData: (url: string, options: {}) => void;
|
|
70
70
|
disableCastAction?: boolean;
|
|
71
|
+
groupId?: string;
|
|
71
72
|
};
|
|
72
73
|
|
|
73
74
|
type ScreenStyles = ZappRiver["styles"] & {
|
|
@@ -200,6 +201,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
200
201
|
style: videoStyle,
|
|
201
202
|
mode = VideoModalMode.MAXIMIZED,
|
|
202
203
|
disableCastAction = false,
|
|
204
|
+
groupId,
|
|
203
205
|
} = props;
|
|
204
206
|
|
|
205
207
|
// Hooks
|
|
@@ -249,7 +251,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
249
251
|
return;
|
|
250
252
|
}
|
|
251
253
|
|
|
252
|
-
navigator.goBack();
|
|
253
254
|
showNavBar(true);
|
|
254
255
|
}, [isModal, navigator.goBack, showNavBar]);
|
|
255
256
|
|
|
@@ -629,6 +630,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
629
630
|
style={styles.focusableGroup}
|
|
630
631
|
preferredFocus
|
|
631
632
|
shouldUsePreferredFocus
|
|
633
|
+
groupId={groupId}
|
|
632
634
|
>
|
|
633
635
|
{/* Video player and components */}
|
|
634
636
|
<View
|
|
@@ -7,14 +7,10 @@ import * as R from "ramda";
|
|
|
7
7
|
import {
|
|
8
8
|
useFeedLoader,
|
|
9
9
|
useLayoutVersion,
|
|
10
|
-
useNavigationPluginData,
|
|
11
10
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
11
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
13
12
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
14
13
|
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
15
|
-
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
16
|
-
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
17
|
-
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
18
14
|
import {
|
|
19
15
|
useNavbarState,
|
|
20
16
|
useSetNavbarState,
|
|
@@ -51,8 +47,6 @@ export const River = (props: Props) => {
|
|
|
51
47
|
const { setTitle: setScreenTitle, setSummary: setScreenSummary } =
|
|
52
48
|
useSetNavbarState();
|
|
53
49
|
|
|
54
|
-
const navigationPluginData = useNavigationPluginData();
|
|
55
|
-
|
|
56
50
|
const rivers = useRivers();
|
|
57
51
|
const isV2 = useLayoutVersion({ isV2: true });
|
|
58
52
|
|
|
@@ -99,23 +93,6 @@ export const River = (props: Props) => {
|
|
|
99
93
|
}
|
|
100
94
|
}, [feedData, screenData, screenTitle, screenSummary]);
|
|
101
95
|
|
|
102
|
-
React.useEffect(() => {
|
|
103
|
-
if (
|
|
104
|
-
isWeb() &&
|
|
105
|
-
toBooleanWithDefaultFalse(
|
|
106
|
-
navigationPluginData?.rules?.focus_on_content
|
|
107
|
-
) &&
|
|
108
|
-
river &&
|
|
109
|
-
river.type !== "general_content"
|
|
110
|
-
) {
|
|
111
|
-
const groupId = R.pathOr("river", ["groupId"], componentsMapExtraProps);
|
|
112
|
-
|
|
113
|
-
focusManager.setupInitialFocus(groupId, true);
|
|
114
|
-
focusManager.setInitialFocus();
|
|
115
|
-
focusManager.enableAutomaticFocus();
|
|
116
|
-
}
|
|
117
|
-
}, [river, componentsMapExtraProps]);
|
|
118
|
-
|
|
119
96
|
if (!river) {
|
|
120
97
|
utilsLogger.error({
|
|
121
98
|
message: `River ${screenData.id} not found!`,
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
useNavigationPluginData,
|
|
4
|
+
useIsNavBarVisible,
|
|
5
|
+
useRoute,
|
|
6
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
7
|
+
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
8
|
+
import {
|
|
9
|
+
setFocusOnContent,
|
|
10
|
+
setFocusOnMenu,
|
|
11
|
+
} from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux";
|
|
12
|
+
|
|
13
|
+
type Return =
|
|
14
|
+
| {
|
|
15
|
+
onContent: true;
|
|
16
|
+
onMenu: false;
|
|
17
|
+
}
|
|
18
|
+
| {
|
|
19
|
+
onContent: false;
|
|
20
|
+
onMenu: true;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const getInitialFocus = (focusOnContent, isNavBarVisible): Return => {
|
|
24
|
+
if (focusOnContent) {
|
|
25
|
+
return {
|
|
26
|
+
onContent: true,
|
|
27
|
+
onMenu: false,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!focusOnContent && isNavBarVisible) {
|
|
32
|
+
// put focus on navbar
|
|
33
|
+
return {
|
|
34
|
+
onContent: false,
|
|
35
|
+
onMenu: true,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// we don't have navbar, put focus on content anyway
|
|
40
|
+
return {
|
|
41
|
+
onContent: true,
|
|
42
|
+
onMenu: false,
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const useInitialFocus = (): void => {
|
|
47
|
+
const navigationPluginData = useNavigationPluginData();
|
|
48
|
+
|
|
49
|
+
const focusOnContent = toBooleanWithDefaultFalse(
|
|
50
|
+
navigationPluginData?.rules?.focus_on_content
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const isNavBarVisible = useIsNavBarVisible();
|
|
54
|
+
|
|
55
|
+
const { pathname: currentRoute } = useRoute();
|
|
56
|
+
|
|
57
|
+
React.useEffect(() => {
|
|
58
|
+
const initialFocus = getInitialFocus(focusOnContent, isNavBarVisible);
|
|
59
|
+
|
|
60
|
+
if (initialFocus.onContent) {
|
|
61
|
+
setFocusOnContent(currentRoute);
|
|
62
|
+
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (initialFocus.onMenu) {
|
|
67
|
+
setFocusOnMenu(currentRoute);
|
|
68
|
+
}
|
|
69
|
+
}, []);
|
|
70
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { isNil } from "ramda";
|
|
3
|
+
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
4
|
+
import { usePrevious } from "@applicaster/zapp-react-native-utils/reactHooks/utils";
|
|
5
|
+
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager";
|
|
6
|
+
|
|
7
|
+
export const useRestoreFocus = (): void => {
|
|
8
|
+
const isScreenActive = useIsScreenActive();
|
|
9
|
+
const previousIsScreenActive = usePrevious(isScreenActive);
|
|
10
|
+
|
|
11
|
+
React.useEffect(() => {
|
|
12
|
+
if (isNil(previousIsScreenActive)) {
|
|
13
|
+
// it's initial mounting of the screen, do nothing here
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (!previousIsScreenActive && isScreenActive) {
|
|
18
|
+
// restore focus when we go back from next screen
|
|
19
|
+
focusManager.setInitialFocus();
|
|
20
|
+
}
|
|
21
|
+
}, [previousIsScreenActive, isScreenActive]);
|
|
22
|
+
};
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { last, pathOr } from "ramda";
|
|
3
|
+
import { View, StyleSheet } from "react-native";
|
|
4
|
+
import {
|
|
5
|
+
getNavigationProps,
|
|
6
|
+
getPathAttributes,
|
|
7
|
+
resolveNavigationPlugin,
|
|
8
|
+
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
9
|
+
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
10
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
11
|
+
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
12
|
+
import { useScreenBackgroundColor } from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
13
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
14
|
+
|
|
15
|
+
import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
|
|
16
|
+
import { ScreenResolver } from "../../ScreenResolver";
|
|
17
|
+
import { useInitialFocus, useRestoreFocus } from "./hooks";
|
|
18
|
+
|
|
19
|
+
const styles = StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
position: "absolute",
|
|
22
|
+
top: 0,
|
|
23
|
+
left: 0,
|
|
24
|
+
right: 0,
|
|
25
|
+
bottom: 0,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
type Components = {
|
|
30
|
+
NavBar: React.ComponentType<any>;
|
|
31
|
+
Background: React.ComponentType<any>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
type Props = {
|
|
35
|
+
route: string;
|
|
36
|
+
Components: Components;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getPluginType = pathOr("unknown_plugin_type", [
|
|
40
|
+
"state",
|
|
41
|
+
"screen",
|
|
42
|
+
"plugin_type",
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const isPlayerPlugin = (routeState): boolean =>
|
|
46
|
+
getPluginType(routeState) === "player";
|
|
47
|
+
|
|
48
|
+
const isLoginPlugin = (routeState): boolean =>
|
|
49
|
+
getPluginType(routeState) === "login";
|
|
50
|
+
|
|
51
|
+
const getActiveRiver = ({
|
|
52
|
+
screenId,
|
|
53
|
+
screenType,
|
|
54
|
+
routeState,
|
|
55
|
+
rivers,
|
|
56
|
+
fallbackActiveRiver,
|
|
57
|
+
}) => {
|
|
58
|
+
if (rivers[screenId]) {
|
|
59
|
+
if (screenType === "hooks") {
|
|
60
|
+
const navigations = routeState?.state?.entry?.payload?.navigations;
|
|
61
|
+
|
|
62
|
+
if (navigations) {
|
|
63
|
+
return routeState.state.entry.payload;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return routeState?.state?.screen;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// screenId is not presented into rivers, use fallback instead
|
|
71
|
+
return fallbackActiveRiver;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const getNavigations = ({
|
|
75
|
+
screenId,
|
|
76
|
+
screenType,
|
|
77
|
+
routeState,
|
|
78
|
+
rivers,
|
|
79
|
+
fallbackNavigations,
|
|
80
|
+
}) => {
|
|
81
|
+
if (rivers[screenId]) {
|
|
82
|
+
// river presents
|
|
83
|
+
if (screenType === "hooks") {
|
|
84
|
+
const navigations = routeState?.state?.entry?.payload?.navigations;
|
|
85
|
+
|
|
86
|
+
if (navigations) {
|
|
87
|
+
return navigations;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return routeState?.state?.screen?.navigations;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// screenId is not presented into rivers, use fallback instead
|
|
95
|
+
return fallbackNavigations;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const Screen = ({ route, Components }: Props) => {
|
|
99
|
+
if (isNilOrEmpty(route)) {
|
|
100
|
+
throw Error("Required props: route is missing");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const navigator = useNavigation();
|
|
104
|
+
const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
|
|
105
|
+
|
|
106
|
+
const pathAttributes = getPathAttributes({ pathname: route });
|
|
107
|
+
const routeState = navigator.getStackForPathname(route);
|
|
108
|
+
|
|
109
|
+
const { screenType, screenId } = last(pathAttributes);
|
|
110
|
+
|
|
111
|
+
const backgroundColor = useScreenBackgroundColor(screenId);
|
|
112
|
+
|
|
113
|
+
useInitialFocus();
|
|
114
|
+
useRestoreFocus();
|
|
115
|
+
|
|
116
|
+
const activeRiver = getActiveRiver({
|
|
117
|
+
screenId,
|
|
118
|
+
screenType,
|
|
119
|
+
routeState,
|
|
120
|
+
rivers,
|
|
121
|
+
fallbackActiveRiver: navigator.activeRiver,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const navigationProps = getNavigationProps({
|
|
125
|
+
navigator: {
|
|
126
|
+
// @ts-ignore
|
|
127
|
+
activeRiver,
|
|
128
|
+
// @ts-ignore
|
|
129
|
+
screenTitle: routeState.state.entry?.title || routeState.screen?.name,
|
|
130
|
+
},
|
|
131
|
+
category: "menu",
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const navigations = getNavigations({
|
|
135
|
+
screenId,
|
|
136
|
+
screenType,
|
|
137
|
+
routeState,
|
|
138
|
+
rivers,
|
|
139
|
+
fallbackNavigations: navigator.activeRiver.navigations,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
const menuPlugin = resolveNavigationPlugin({
|
|
143
|
+
category: "menu",
|
|
144
|
+
navigations,
|
|
145
|
+
plugins,
|
|
146
|
+
}) as QuickBrickPlugin;
|
|
147
|
+
|
|
148
|
+
const NavBar = (Components.NavBar ||
|
|
149
|
+
menuPlugin.module) as React.ComponentType<any>;
|
|
150
|
+
|
|
151
|
+
const isPlayer = isPlayerPlugin(routeState);
|
|
152
|
+
const isLogin = isLoginPlugin(routeState);
|
|
153
|
+
|
|
154
|
+
const isNavBarVisible = !isPlayer && !isLogin;
|
|
155
|
+
|
|
156
|
+
const screenData =
|
|
157
|
+
screenType === "hooks" || isPlayer
|
|
158
|
+
? routeState?.state?.entry
|
|
159
|
+
: routeState?.state?.screen;
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<View style={[styles.container, { backgroundColor }]}>
|
|
163
|
+
<NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
|
|
164
|
+
<NavBar
|
|
165
|
+
groupId={route}
|
|
166
|
+
isVisible={isNavBarVisible}
|
|
167
|
+
menuPlugin={menuPlugin}
|
|
168
|
+
navigationProps={navigationProps}
|
|
169
|
+
/>
|
|
170
|
+
</NavBarContainer>
|
|
171
|
+
<ScreenResolver
|
|
172
|
+
screenType={screenType}
|
|
173
|
+
screenId={screenId}
|
|
174
|
+
screenData={screenData}
|
|
175
|
+
groupId={route}
|
|
176
|
+
/>
|
|
177
|
+
</View>
|
|
178
|
+
);
|
|
179
|
+
};
|
|
@@ -32,12 +32,13 @@ type Props = {
|
|
|
32
32
|
nextFocusLeft?: React.Ref<any>;
|
|
33
33
|
nextFocusUp?: React.Ref<any>;
|
|
34
34
|
};
|
|
35
|
+
groupId?: string;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
export function ScreenResolverComponent(props: Props) {
|
|
38
39
|
useScreenAnalytics(props);
|
|
39
40
|
|
|
40
|
-
const { screenType, screenId, screenData } = props;
|
|
41
|
+
const { screenType, screenId, screenData, groupId } = props;
|
|
41
42
|
|
|
42
43
|
const { hookPlugin } = screenData || {};
|
|
43
44
|
|
|
@@ -81,6 +82,7 @@ export function ScreenResolverComponent(props: Props) {
|
|
|
81
82
|
item={screenData}
|
|
82
83
|
mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
|
|
83
84
|
isModal={false}
|
|
85
|
+
groupId={groupId}
|
|
84
86
|
/>
|
|
85
87
|
);
|
|
86
88
|
}
|
|
@@ -10,7 +10,11 @@ import { Component } from "react";
|
|
|
10
10
|
|
|
11
11
|
const { log_debug, log_info, log_error } = loggerLiveImageManager;
|
|
12
12
|
|
|
13
|
-
export type LiveImageManagerEvent =
|
|
13
|
+
export type LiveImageManagerEvent =
|
|
14
|
+
| "onEnd"
|
|
15
|
+
| "onStart"
|
|
16
|
+
| "onError"
|
|
17
|
+
| "onDestroy";
|
|
14
18
|
|
|
15
19
|
export type LiveImageManagerListenerData = {
|
|
16
20
|
id: string;
|
|
@@ -102,6 +106,16 @@ export class LiveImageManager implements PlayerLifecycleListener {
|
|
|
102
106
|
}
|
|
103
107
|
|
|
104
108
|
this.items = this.items.filter((i) => i !== item);
|
|
109
|
+
|
|
110
|
+
this.invokeListenersUpdate({
|
|
111
|
+
callbackName: "onDestroy",
|
|
112
|
+
event: {
|
|
113
|
+
item,
|
|
114
|
+
playerId: this.currentlyPlaying?.playerId,
|
|
115
|
+
primaryPlayerId: this.primaryPlayer?.playerId,
|
|
116
|
+
entry: item.getPlayer().getEntry(),
|
|
117
|
+
},
|
|
118
|
+
});
|
|
105
119
|
};
|
|
106
120
|
|
|
107
121
|
public onViewportEnter = (item: LiveImage) => {
|
|
@@ -184,8 +184,8 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
184
184
|
const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${entry?.id}`;
|
|
185
185
|
|
|
186
186
|
return (
|
|
187
|
-
<
|
|
188
|
-
<
|
|
187
|
+
<PathnameContext.Provider value={pathname}>
|
|
188
|
+
<ScreenContextProvider pathname={pathname}>
|
|
189
189
|
<WrapperView
|
|
190
190
|
edges={getEdges(isTablet, isInlineModal) as readonly Edge[]}
|
|
191
191
|
style={[
|
|
@@ -199,8 +199,8 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
199
199
|
additionalData={{ saveArea: true }}
|
|
200
200
|
style={directionStyles(isTabletLandscape)}
|
|
201
201
|
>
|
|
202
|
-
<
|
|
203
|
-
<
|
|
202
|
+
<PathnameContext.Provider value={pathname}>
|
|
203
|
+
<ScreenContextProvider pathname={pathname}>
|
|
204
204
|
<View
|
|
205
205
|
testID={`${entry?.id}-player-container`}
|
|
206
206
|
style={[
|
|
@@ -241,11 +241,11 @@ export const PlayerWrapper = (props: Props) => {
|
|
|
241
241
|
<View style={defaultStyles.playerDetails} />
|
|
242
242
|
)}
|
|
243
243
|
</AnimatedScrollModal>
|
|
244
|
-
</
|
|
245
|
-
</
|
|
244
|
+
</ScreenContextProvider>
|
|
245
|
+
</PathnameContext.Provider>
|
|
246
246
|
</AnimationComponent>
|
|
247
247
|
</WrapperView>
|
|
248
|
-
</
|
|
249
|
-
</
|
|
248
|
+
</ScreenContextProvider>
|
|
249
|
+
</PathnameContext.Provider>
|
|
250
250
|
);
|
|
251
251
|
};
|
|
@@ -129,8 +129,8 @@ const VideoModalComponent = () => {
|
|
|
129
129
|
const pathname = `${ROUTE_TYPES.VIDEO_MODAL}/${item?.id}`;
|
|
130
130
|
|
|
131
131
|
return (
|
|
132
|
-
<
|
|
133
|
-
<
|
|
132
|
+
<PathnameContext.Provider value={pathname}>
|
|
133
|
+
<ScreenContextProvider pathname={pathname}>
|
|
134
134
|
{itemIdHooksFinished === item?.id ? (
|
|
135
135
|
<AnimatedPlayerModalWrapper
|
|
136
136
|
style={[
|
|
@@ -153,8 +153,8 @@ const VideoModalComponent = () => {
|
|
|
153
153
|
<Spinner />
|
|
154
154
|
</View>
|
|
155
155
|
)}
|
|
156
|
-
</
|
|
157
|
-
</
|
|
156
|
+
</ScreenContextProvider>
|
|
157
|
+
</PathnameContext.Provider>
|
|
158
158
|
);
|
|
159
159
|
};
|
|
160
160
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "12.0.0-rc.
|
|
3
|
+
"version": "12.0.0-rc.70",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"redux-mock-store": "^1.5.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@applicaster/applicaster-types": "12.0.0-rc.
|
|
38
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-rc.
|
|
39
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-rc.
|
|
40
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-rc.
|
|
37
|
+
"@applicaster/applicaster-types": "12.0.0-rc.70",
|
|
38
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-rc.70",
|
|
39
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-rc.70",
|
|
40
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-rc.70",
|
|
41
41
|
"promise": "^8.3.0",
|
|
42
42
|
"react-router-native": "^5.1.2",
|
|
43
43
|
"url": "^0.11.0",
|
|
@@ -1,64 +0,0 @@
|
|
|
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
|
-
};
|