@applicaster/zapp-react-native-ui-components 15.0.0-alpha.5918085834 → 15.0.0-alpha.5949018320
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.ios.ts +12 -2
- package/Components/Cell/FocusableWrapper.tsx +3 -0
- package/Components/Cell/TvOSCellComponent.tsx +5 -0
- package/Components/Focusable/FocusableTvOS.tsx +12 -2
- package/Components/Focusable/__tests__/__snapshots__/FocusableTvOS.test.tsx.snap +1 -0
- package/Components/FocusableGroup/FocusableTvOS.tsx +11 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +14 -3
- package/Components/PlayerContainer/PlayerContainer.tsx +16 -8
- package/Components/PlayerContainer/useRestrictMobilePlayback.tsx +112 -0
- package/package.json +5 -5
|
@@ -22,6 +22,7 @@ type Props = {
|
|
|
22
22
|
onFocus?: FocusManager.FocusEventCB;
|
|
23
23
|
onBlur?: FocusManager.FocusEventCB;
|
|
24
24
|
selected?: boolean;
|
|
25
|
+
skipFocusManagerRegistration?: boolean;
|
|
25
26
|
};
|
|
26
27
|
|
|
27
28
|
export class BaseFocusable<
|
|
@@ -61,10 +62,14 @@ export class BaseFocusable<
|
|
|
61
62
|
}
|
|
62
63
|
|
|
63
64
|
componentDidMount() {
|
|
64
|
-
const { id } = this.props;
|
|
65
|
+
const { id, skipFocusManagerRegistration } = this.props;
|
|
65
66
|
const component = this;
|
|
66
67
|
this.node = this.ref.current;
|
|
67
68
|
|
|
69
|
+
if (skipFocusManagerRegistration) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
68
73
|
focusManager.register({
|
|
69
74
|
id,
|
|
70
75
|
component: component,
|
|
@@ -118,7 +123,12 @@ export class BaseFocusable<
|
|
|
118
123
|
|
|
119
124
|
componentWillUnmount() {
|
|
120
125
|
this._isMounted = false;
|
|
121
|
-
const { id } = this.props;
|
|
126
|
+
const { id, skipFocusManagerRegistration } = this.props;
|
|
127
|
+
|
|
128
|
+
if (skipFocusManagerRegistration) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
122
132
|
focusManager.unregister(id, { group: this.isGroup || false });
|
|
123
133
|
}
|
|
124
134
|
|
|
@@ -10,6 +10,7 @@ type Props = {
|
|
|
10
10
|
children: (focused: boolean) => React.ReactNode;
|
|
11
11
|
onFocus: (arg1: any, index?: number) => void;
|
|
12
12
|
onBlur: Callback;
|
|
13
|
+
skipFocusManagerRegistration?: boolean;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
export const FocusableWrapper = ({
|
|
@@ -20,6 +21,7 @@ export const FocusableWrapper = ({
|
|
|
20
21
|
applyWrapper,
|
|
21
22
|
onFocus,
|
|
22
23
|
onBlur,
|
|
24
|
+
skipFocusManagerRegistration,
|
|
23
25
|
}: Props) => {
|
|
24
26
|
if (applyWrapper) {
|
|
25
27
|
return (
|
|
@@ -34,6 +36,7 @@ export const FocusableWrapper = ({
|
|
|
34
36
|
// @ts-ignore
|
|
35
37
|
offsetUpdater={noop}
|
|
36
38
|
isFocusable
|
|
39
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
37
40
|
>
|
|
38
41
|
{(focused) => children(focused)}
|
|
39
42
|
</Focusable>
|
|
@@ -80,6 +80,7 @@ type Props = {
|
|
|
80
80
|
componentsMapOffset: number;
|
|
81
81
|
applyFocusableWrapper: boolean;
|
|
82
82
|
hasFocusableInside: boolean;
|
|
83
|
+
skipFocusManagerRegistration?: boolean;
|
|
83
84
|
};
|
|
84
85
|
|
|
85
86
|
type State = {
|
|
@@ -266,6 +267,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
266
267
|
behavior,
|
|
267
268
|
applyFocusableWrapper,
|
|
268
269
|
hasFocusableInside,
|
|
270
|
+
skipFocusManagerRegistration,
|
|
269
271
|
} = this.props;
|
|
270
272
|
|
|
271
273
|
const { id } = item;
|
|
@@ -291,6 +293,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
291
293
|
onFocus={handleFocus}
|
|
292
294
|
onBlur={onBlur || this.onBlur}
|
|
293
295
|
applyWrapper={applyFocusableWrapper}
|
|
296
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
294
297
|
>
|
|
295
298
|
{(focused) => (
|
|
296
299
|
<CellWithFocusable
|
|
@@ -305,6 +308,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
305
308
|
focused={focused || this.props.focused}
|
|
306
309
|
behavior={behavior}
|
|
307
310
|
isFocusable={isFocusable}
|
|
311
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
308
312
|
/>
|
|
309
313
|
)}
|
|
310
314
|
</FocusableWrapper>
|
|
@@ -327,6 +331,7 @@ class TvOSCell extends React.Component<Props, State> {
|
|
|
327
331
|
offsetUpdater={offsetUpdater}
|
|
328
332
|
style={baseCellStyles}
|
|
329
333
|
isFocusable={isFocusable}
|
|
334
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
330
335
|
>
|
|
331
336
|
{(focused) => (
|
|
332
337
|
<FocusableCell
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
12
|
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
14
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
15
15
|
|
|
16
16
|
type Props = {
|
|
17
17
|
id: string;
|
|
@@ -39,6 +39,7 @@ type Props = {
|
|
|
39
39
|
hasReceivedFocus: () => void;
|
|
40
40
|
offsetUpdater: (arg1: string, arg2: number) => number;
|
|
41
41
|
style: ViewStyle;
|
|
42
|
+
skipFocusManagerRegistration?: boolean;
|
|
42
43
|
};
|
|
43
44
|
|
|
44
45
|
export class Focusable extends BaseFocusable<Props> {
|
|
@@ -53,6 +54,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
53
54
|
this.nextFocusableReactTags = {};
|
|
54
55
|
this.preferredFocus = this.preferredFocus.bind(this);
|
|
55
56
|
this.measureView = this.measureView.bind(this);
|
|
57
|
+
this.onRegistered = this.onRegistered.bind(this);
|
|
56
58
|
}
|
|
57
59
|
|
|
58
60
|
/**
|
|
@@ -169,6 +171,13 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
169
171
|
});
|
|
170
172
|
}
|
|
171
173
|
|
|
174
|
+
onRegistered({ nativeEvent }) {
|
|
175
|
+
const groupId = nativeEvent?.groupId;
|
|
176
|
+
const id = nativeEvent?.itemId;
|
|
177
|
+
|
|
178
|
+
emitNativeRegistered({ id, groupId, isGroup: false });
|
|
179
|
+
}
|
|
180
|
+
|
|
172
181
|
render() {
|
|
173
182
|
const {
|
|
174
183
|
children,
|
|
@@ -203,6 +212,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
203
212
|
focusable={isFocusable}
|
|
204
213
|
{...this.nextFocusableReactTags}
|
|
205
214
|
{...otherProps}
|
|
215
|
+
onRegistered={this.onRegistered}
|
|
206
216
|
>
|
|
207
217
|
{typeof children === "function" ? children(focused) : children}
|
|
208
218
|
</FocusableItemNative>
|
|
@@ -2,6 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
|
|
3
3
|
import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";
|
|
4
4
|
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
5
|
+
import { emitNativeRegistered } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
5
6
|
|
|
6
7
|
const { log_verbose } = createLogger({
|
|
7
8
|
subsystem: "General",
|
|
@@ -34,6 +35,15 @@ type Props = {
|
|
|
34
35
|
};
|
|
35
36
|
|
|
36
37
|
export class FocusableGroup extends BaseFocusable<Props> {
|
|
38
|
+
public readonly isGroup: boolean = true;
|
|
39
|
+
|
|
40
|
+
onRegistered = ({ nativeEvent }) => {
|
|
41
|
+
const groupId = nativeEvent?.groupId;
|
|
42
|
+
const id = nativeEvent?.itemId;
|
|
43
|
+
|
|
44
|
+
emitNativeRegistered({ id, groupId, isGroup: true });
|
|
45
|
+
};
|
|
46
|
+
|
|
37
47
|
render() {
|
|
38
48
|
const {
|
|
39
49
|
children,
|
|
@@ -66,6 +76,7 @@ export class FocusableGroup extends BaseFocusable<Props> {
|
|
|
66
76
|
onGroupBlur={onGroupBlur}
|
|
67
77
|
style={style}
|
|
68
78
|
{...otherProps}
|
|
79
|
+
onRegistered={this.onRegistered}
|
|
69
80
|
>
|
|
70
81
|
{children}
|
|
71
82
|
</FocusableGroupNative>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { all, equals,
|
|
1
|
+
import { all, equals, isEmpty, path, pluck, prop, values } from "ramda";
|
|
2
2
|
|
|
3
3
|
import { useEffect, useMemo } from "react";
|
|
4
4
|
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
|
|
25
25
|
import { produce } from "immer";
|
|
26
26
|
import { useLoadPipesDataDispatch } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
27
|
+
|
|
27
28
|
// types reference
|
|
28
29
|
|
|
29
30
|
declare interface CurationEntry {
|
|
@@ -35,6 +36,7 @@ type Feeds = Record<string, ZappPipesData>;
|
|
|
35
36
|
|
|
36
37
|
type LayoutPresets = PresetsMapping["presets_mappings"];
|
|
37
38
|
|
|
39
|
+
const TABS_SCREEN_TYPE = "tabs_screen";
|
|
38
40
|
const SMART_COMPONENT_TYPE = "quick-brick-smart-component";
|
|
39
41
|
const SOURCE_PATH = ["data", "source"];
|
|
40
42
|
const MAPPING_PATH = ["data", "mapping"];
|
|
@@ -53,7 +55,10 @@ export const getTransformedPreset = (
|
|
|
53
55
|
const presetComponent = layoutPresets?.[preset?.preset_name];
|
|
54
56
|
|
|
55
57
|
if (!presetComponent) {
|
|
56
|
-
logger.log_error(
|
|
58
|
+
logger.log_error(
|
|
59
|
+
`Preset "${preset?.preset_name}" missing or wrong data format`,
|
|
60
|
+
{ entry: preset }
|
|
61
|
+
);
|
|
57
62
|
|
|
58
63
|
return;
|
|
59
64
|
}
|
|
@@ -131,10 +136,16 @@ export const useCurationAPI = (
|
|
|
131
136
|
);
|
|
132
137
|
|
|
133
138
|
const { pathname } = useRoute();
|
|
134
|
-
const [entryContext] = ZappPipesEntryContext.useZappPipesContext(pathname);
|
|
135
139
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
136
140
|
const [screenContext] = ZappPipesScreenContext.useZappPipesContext();
|
|
137
141
|
|
|
142
|
+
const isNestedScreen = screenContext?.type === TABS_SCREEN_TYPE;
|
|
143
|
+
|
|
144
|
+
const [entryContext] = ZappPipesEntryContext.useZappPipesContext(
|
|
145
|
+
pathname,
|
|
146
|
+
isNestedScreen
|
|
147
|
+
);
|
|
148
|
+
|
|
138
149
|
const urlsMap = useMemo<{ [key: string]: string }>(() => {
|
|
139
150
|
const map = {};
|
|
140
151
|
|
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
PlayerNativeSendCommand,
|
|
62
62
|
} from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerNativeCommand";
|
|
63
63
|
import { useAppData } from "@applicaster/zapp-react-native-redux";
|
|
64
|
+
import { useRestrictMobilePlayback } from "./useRestrictMobilePlayback";
|
|
64
65
|
|
|
65
66
|
type Props = {
|
|
66
67
|
Player: React.ComponentType<any>;
|
|
@@ -264,7 +265,21 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
264
265
|
|
|
265
266
|
showNavBar(true);
|
|
266
267
|
navigator.goBack();
|
|
267
|
-
}, [isModal,
|
|
268
|
+
}, [isModal, state.playerId, showNavBar, navigator]);
|
|
269
|
+
|
|
270
|
+
const pluginConfiguration = React.useMemo(() => {
|
|
271
|
+
return (
|
|
272
|
+
playerManager.getPluginConfiguration() ||
|
|
273
|
+
R.prop("__plugin_configuration", Player)
|
|
274
|
+
);
|
|
275
|
+
}, [playerManager.isRegistered()]);
|
|
276
|
+
|
|
277
|
+
useRestrictMobilePlayback({
|
|
278
|
+
player,
|
|
279
|
+
entry: item,
|
|
280
|
+
pluginConfiguration,
|
|
281
|
+
close,
|
|
282
|
+
});
|
|
268
283
|
|
|
269
284
|
const playEntry = (entry) => navigator.replaceTop(entry, { mode });
|
|
270
285
|
|
|
@@ -456,13 +471,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
456
471
|
}
|
|
457
472
|
}, []);
|
|
458
473
|
|
|
459
|
-
const pluginConfiguration = React.useMemo(() => {
|
|
460
|
-
return (
|
|
461
|
-
playerManager.getPluginConfiguration() ||
|
|
462
|
-
R.prop("__plugin_configuration", Player)
|
|
463
|
-
);
|
|
464
|
-
}, [playerManager.isRegistered()]);
|
|
465
|
-
|
|
466
474
|
const disableMiniPlayer = React.useMemo(() => {
|
|
467
475
|
return pluginConfiguration?.disable_mini_player_when_inline;
|
|
468
476
|
}, [pluginConfiguration]);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
|
|
2
|
+
import NetInfo from "@react-native-community/netinfo";
|
|
3
|
+
|
|
4
|
+
import { useEffect, useMemo, useRef } from "react";
|
|
5
|
+
import { showAlertDialog } from "@applicaster/zapp-react-native-utils/alertUtils";
|
|
6
|
+
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
7
|
+
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
8
|
+
import { log_info } from "./logger";
|
|
9
|
+
|
|
10
|
+
export const useRestrictMobilePlayback = ({
|
|
11
|
+
player,
|
|
12
|
+
entry,
|
|
13
|
+
pluginConfiguration,
|
|
14
|
+
close,
|
|
15
|
+
}: {
|
|
16
|
+
player?: Player;
|
|
17
|
+
entry?: ZappEntry;
|
|
18
|
+
pluginConfiguration?: Record<string, string>;
|
|
19
|
+
close: () => void;
|
|
20
|
+
}) => {
|
|
21
|
+
const dialogVisibleRef = useRef(false);
|
|
22
|
+
|
|
23
|
+
const theme = useTheme();
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
return () => {
|
|
27
|
+
if (isTV()) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
dialogVisibleRef.current = false;
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
34
|
+
|
|
35
|
+
const isConnectionRestricted = useMemo(() => {
|
|
36
|
+
if (isTV()) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return player && entry?.extensions?.connection_restricted;
|
|
41
|
+
}, [player, entry]);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (!isConnectionRestricted) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return player.addListener({
|
|
49
|
+
id: "restrictMobilePlaybackListener",
|
|
50
|
+
listener: {
|
|
51
|
+
onVideoProgress: () => {
|
|
52
|
+
if (dialogVisibleRef.current) {
|
|
53
|
+
player.pause();
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
onPlayerResume: () => {
|
|
57
|
+
if (dialogVisibleRef.current) {
|
|
58
|
+
player.pause();
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}, [isConnectionRestricted, player]);
|
|
64
|
+
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!isConnectionRestricted) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const stopPlayer = () => {
|
|
71
|
+
log_info(
|
|
72
|
+
"Stopping player due to mobile restriction, connection_restricted: true"
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
player.pause();
|
|
76
|
+
|
|
77
|
+
dialogVisibleRef.current = true;
|
|
78
|
+
|
|
79
|
+
showAlertDialog({
|
|
80
|
+
title:
|
|
81
|
+
pluginConfiguration?.mobile_connection_restricted_alert_title ||
|
|
82
|
+
"N/A",
|
|
83
|
+
message:
|
|
84
|
+
pluginConfiguration?.mobile_connection_restricted_alert_message ||
|
|
85
|
+
"N/A",
|
|
86
|
+
okButtonText: theme.ok_button || "OK",
|
|
87
|
+
completion: () => {
|
|
88
|
+
dialogVisibleRef.current = false;
|
|
89
|
+
|
|
90
|
+
close();
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return NetInfo.addEventListener((state) => {
|
|
96
|
+
if (state.type === "cellular") {
|
|
97
|
+
if (dialogVisibleRef.current) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
stopPlayer();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
}, [
|
|
105
|
+
close,
|
|
106
|
+
entry.extensions.connection_restricted,
|
|
107
|
+
pluginConfiguration,
|
|
108
|
+
player,
|
|
109
|
+
theme.ok_button,
|
|
110
|
+
isConnectionRestricted,
|
|
111
|
+
]);
|
|
112
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "15.0.0-alpha.
|
|
3
|
+
"version": "15.0.0-alpha.5949018320",
|
|
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",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "15.0.0-alpha.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "15.0.0-alpha.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "15.0.0-alpha.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "15.0.0-alpha.5949018320",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "15.0.0-alpha.5949018320",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "15.0.0-alpha.5949018320",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.5949018320",
|
|
35
35
|
"fast-json-stable-stringify": "^2.1.0",
|
|
36
36
|
"promise": "^8.3.0",
|
|
37
37
|
"url": "^0.11.0",
|