@applicaster/zapp-react-native-utils 15.0.0-alpha.1627563808 → 15.0.0-alpha.1690332913
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/actionsExecutor/ActionExecutorContext.tsx +3 -6
- package/actionsExecutor/feedDecorator.ts +6 -6
- package/adsUtils/index.ts +2 -2
- package/analyticsUtils/README.md +1 -1
- package/analyticsUtils/analyticsMapper.ts +10 -2
- package/appUtils/HooksManager/index.ts +10 -10
- package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
- package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
- package/appUtils/accessibilityManager/utils.ts +25 -5
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
- package/appUtils/focusManager/index.ios.ts +43 -4
- package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
- package/appUtils/focusManagerAux/utils/index.ts +1 -1
- package/appUtils/focusManagerAux/utils/utils.ios.ts +199 -3
- package/appUtils/keyCodes/keys/keys.web.ts +1 -4
- package/appUtils/orientationHelper.ts +2 -4
- package/appUtils/platform/platformUtils.ts +1 -1
- package/appUtils/playerManager/playerNative.ts +29 -16
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
- package/focusManager/aux/index.ts +1 -1
- package/manifestUtils/defaultManifestConfigurations/player.js +37 -10
- package/manifestUtils/tvAction/container/index.js +1 -1
- package/package.json +2 -2
- package/pluginUtils/index.ts +4 -0
- package/reactHooks/advertising/index.ts +2 -2
- package/reactHooks/debugging/__tests__/index.test.js +4 -4
- package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
- package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +3 -0
- package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
- package/reactHooks/feed/useEntryScreenId.ts +2 -2
- package/reactHooks/feed/useInflatedUrl.ts +43 -17
- package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
- package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
- package/reactHooks/navigation/index.ts +11 -6
- package/reactHooks/navigation/useRoute.ts +8 -6
- package/reactHooks/resolvers/useCellResolver.ts +6 -2
- package/reactHooks/resolvers/useComponentResolver.ts +8 -2
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +11 -3
- package/reactHooks/screen/useTargetScreenData.ts +4 -2
- package/reactHooks/state/useRivers.ts +1 -1
- package/reactHooks/usePluginConfiguration.ts +2 -2
- package/searchUtils/const.ts +7 -0
- package/searchUtils/index.ts +3 -0
- package/testUtils/index.tsx +30 -21
- package/utils/__tests__/mergeRight.test.ts +48 -0
- package/utils/__tests__/selectors.test.ts +124 -0
- package/utils/index.ts +13 -0
- package/utils/mergeRight.ts +5 -0
- package/utils/path.ts +6 -3
- package/utils/pathOr.ts +5 -1
- package/utils/selectors.ts +46 -0
- package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +34 -11
- package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
|
@@ -4,7 +4,11 @@ import * as R from "ramda";
|
|
|
4
4
|
import {
|
|
5
5
|
isCurrentFocusOn,
|
|
6
6
|
isChildOf as isChildOfUtils,
|
|
7
|
-
|
|
7
|
+
isPartOfMenu,
|
|
8
|
+
isPartOfContent,
|
|
9
|
+
isPartOfTabsScreenContent,
|
|
10
|
+
} from "../focusManagerAux/utils/index.ios";
|
|
11
|
+
|
|
8
12
|
import { Tree } from "./treeDataStructure/Tree";
|
|
9
13
|
import { findFocusableNode } from "./treeDataStructure/Utils";
|
|
10
14
|
import { subscriber } from "../../functionUtils";
|
|
@@ -188,9 +192,15 @@ export const focusManager = (function () {
|
|
|
188
192
|
function register({ id, component }) {
|
|
189
193
|
const { isGroup = false } = component;
|
|
190
194
|
|
|
191
|
-
|
|
195
|
+
if (isGroup) {
|
|
196
|
+
registerGroup(id, component);
|
|
197
|
+
} else {
|
|
198
|
+
registerItem(id, component);
|
|
199
|
+
}
|
|
192
200
|
|
|
193
|
-
|
|
201
|
+
const groupId = component?.props?.groupId;
|
|
202
|
+
|
|
203
|
+
emitRegistered({ id, groupId, isGroup });
|
|
194
204
|
}
|
|
195
205
|
|
|
196
206
|
function unregister(id, { group = false } = {}) {
|
|
@@ -273,7 +283,9 @@ export const focusManager = (function () {
|
|
|
273
283
|
function setFocus(
|
|
274
284
|
id: string,
|
|
275
285
|
direction?: FocusManager.IOS.Direction,
|
|
276
|
-
options?: Partial<{
|
|
286
|
+
options?: Partial<{
|
|
287
|
+
groupFocusedChanged: boolean;
|
|
288
|
+
}>,
|
|
277
289
|
callback?: any
|
|
278
290
|
) {
|
|
279
291
|
blur(direction);
|
|
@@ -412,6 +424,30 @@ export const focusManager = (function () {
|
|
|
412
424
|
return id && isCurrentFocusOn(id, currentFocusNode);
|
|
413
425
|
}
|
|
414
426
|
|
|
427
|
+
function isFocusOnMenu(): boolean {
|
|
428
|
+
const currentFocusable = getCurrentFocus();
|
|
429
|
+
|
|
430
|
+
return isPartOfMenu(focusableTree, currentFocusable?.props?.id);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function isFocusOnContent(): boolean {
|
|
434
|
+
const currentFocusable = getCurrentFocus();
|
|
435
|
+
|
|
436
|
+
return isPartOfContent(focusableTree, currentFocusable?.props?.id);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function isFocusOnTabsScreenContent(
|
|
440
|
+
screenPickerContentContainerId: string
|
|
441
|
+
): boolean {
|
|
442
|
+
const currentFocusable = getCurrentFocus();
|
|
443
|
+
|
|
444
|
+
return isPartOfTabsScreenContent(
|
|
445
|
+
focusableTree,
|
|
446
|
+
screenPickerContentContainerId,
|
|
447
|
+
currentFocusable?.props?.id
|
|
448
|
+
);
|
|
449
|
+
}
|
|
450
|
+
|
|
415
451
|
function isChildOf(childId, parentId): boolean {
|
|
416
452
|
return isChildOfUtils(focusableTree, childId, parentId);
|
|
417
453
|
}
|
|
@@ -438,6 +474,9 @@ export const focusManager = (function () {
|
|
|
438
474
|
isGroupItemFocused,
|
|
439
475
|
getPreferredFocusChild,
|
|
440
476
|
isFocusOn,
|
|
477
|
+
isFocusOnMenu,
|
|
478
|
+
isFocusOnContent,
|
|
479
|
+
isFocusOnTabsScreenContent,
|
|
441
480
|
isChildOf,
|
|
442
481
|
};
|
|
443
482
|
})();
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { isNil, startsWith } from "@applicaster/zapp-react-native-utils/utils";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
QUICK_BRICK_CONTENT,
|
|
5
|
+
QUICK_BRICK_NAVBAR,
|
|
6
|
+
} from "@applicaster/quick-brick-core/const";
|
|
7
|
+
|
|
8
|
+
const isNavBar = (node) => startsWith(QUICK_BRICK_NAVBAR, node?.id);
|
|
9
|
+
const isContent = (node) => startsWith(QUICK_BRICK_CONTENT, node?.id);
|
|
10
|
+
const isRoot = (node) => node?.id === "root";
|
|
11
|
+
|
|
12
|
+
export const isPartOfTabsScreenContent = (
|
|
13
|
+
focusableTree,
|
|
14
|
+
screenPickerContentContainerId,
|
|
15
|
+
id
|
|
16
|
+
) => {
|
|
17
|
+
const node = focusableTree.findInTree(id);
|
|
18
|
+
|
|
19
|
+
if (isNil(node)) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (isRoot(node)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (isNavBar(node)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isContent(node)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (node?.id === screenPickerContentContainerId) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return isPartOfTabsScreenContent(
|
|
40
|
+
focusableTree,
|
|
41
|
+
screenPickerContentContainerId,
|
|
42
|
+
node.parent?.id
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const isPartOfMenu = (focusableTree, id): boolean => {
|
|
47
|
+
const node = focusableTree.findInTree(id);
|
|
48
|
+
|
|
49
|
+
if (isNil(node)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (isRoot(node)) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (isNavBar(node)) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (isContent(node)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return isPartOfMenu(focusableTree, node.parent?.id);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const isPartOfContent = (focusableTree, id) => {
|
|
69
|
+
const node = focusableTree.findInTree(id);
|
|
70
|
+
|
|
71
|
+
if (isNil(node)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (isRoot(node)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isNavBar(node)) {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (isContent(node)) {
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return isPartOfContent(focusableTree, node.parent?.id);
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const isCurrentFocusOn = (id, node) => {
|
|
91
|
+
if (!node) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (isRoot(node)) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (node?.id === id) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return isCurrentFocusOn(id, node.parent);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const isChildOf = (focusableTree, childId, parentId) => {
|
|
107
|
+
if (isNil(childId) || isNil(parentId)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const childNode = focusableTree.findInTree(childId);
|
|
112
|
+
|
|
113
|
+
if (isNil(childNode)) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (childNode.parent?.id === parentId) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return isChildOf(focusableTree, childNode.parent?.id, parentId);
|
|
122
|
+
};
|
|
@@ -102,7 +102,7 @@ export const getNavbarNode = (focusableTree) => {
|
|
|
102
102
|
|
|
103
103
|
export const waitForContent = (focusableTree) => {
|
|
104
104
|
const contentHasAnyChildren = (): boolean => {
|
|
105
|
-
const countOfChildren = pathOr(
|
|
105
|
+
const countOfChildren = pathOr<number>(
|
|
106
106
|
0,
|
|
107
107
|
["children", "length"],
|
|
108
108
|
getContentNode(focusableTree)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { ReplaySubject } from "rxjs";
|
|
2
|
-
import { filter } from "rxjs/operators";
|
|
1
|
+
import { ReplaySubject, Subject } from "rxjs";
|
|
2
|
+
import { filter, switchMap, take, withLatestFrom, map } from "rxjs/operators";
|
|
3
|
+
|
|
3
4
|
import { BUTTON_PREFIX } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/DefaultComponents/tv/TvActionButtons/const";
|
|
4
5
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
6
|
+
import { isPartOfMenu, isPartOfContent } from "./index.ios";
|
|
5
7
|
|
|
6
8
|
type FocusableID = string;
|
|
7
9
|
type RegistrationEvent = {
|
|
@@ -9,6 +11,25 @@ type RegistrationEvent = {
|
|
|
9
11
|
registered: boolean;
|
|
10
12
|
};
|
|
11
13
|
|
|
14
|
+
let focusableViewRegistrationSubject$ = new Subject<{
|
|
15
|
+
id: FocusableID;
|
|
16
|
+
groupId: FocusableID;
|
|
17
|
+
}>();
|
|
18
|
+
|
|
19
|
+
let focusableGroupRegistrationSubject$ = new ReplaySubject<{
|
|
20
|
+
id: FocusableID;
|
|
21
|
+
}>();
|
|
22
|
+
|
|
23
|
+
let focusableNativeViewRegistrationSubject$ = new Subject<{
|
|
24
|
+
id: FocusableID;
|
|
25
|
+
groupId: FocusableID;
|
|
26
|
+
}>();
|
|
27
|
+
|
|
28
|
+
let focusableNativeGroupRegistrationSubject$ = new ReplaySubject<{
|
|
29
|
+
id: FocusableID;
|
|
30
|
+
groupId: FocusableID;
|
|
31
|
+
}>();
|
|
32
|
+
|
|
12
33
|
const isFocusableButton = (id: Option<FocusableID>): boolean =>
|
|
13
34
|
id && id.includes?.(BUTTON_PREFIX);
|
|
14
35
|
|
|
@@ -22,14 +43,189 @@ export const focusableButtonsRegistration$ = (focusableGroupId: string) =>
|
|
|
22
43
|
)
|
|
23
44
|
);
|
|
24
45
|
|
|
25
|
-
export const
|
|
46
|
+
export const resetFocusableRegistration = () => {
|
|
47
|
+
// complete the old subject so subscribers are notified and resources are freed
|
|
48
|
+
if (!focusableViewRegistrationSubject$.closed) {
|
|
49
|
+
focusableViewRegistrationSubject$.complete();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!focusableGroupRegistrationSubject$.closed) {
|
|
53
|
+
focusableGroupRegistrationSubject$.complete();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!focusableNativeViewRegistrationSubject$.closed) {
|
|
57
|
+
focusableNativeViewRegistrationSubject$.complete();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!focusableNativeGroupRegistrationSubject$.closed) {
|
|
61
|
+
focusableNativeGroupRegistrationSubject$.complete();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
focusableViewRegistrationSubject$ = new Subject<{
|
|
65
|
+
id: FocusableID;
|
|
66
|
+
groupId: FocusableID;
|
|
67
|
+
}>();
|
|
68
|
+
|
|
69
|
+
focusableGroupRegistrationSubject$ = new ReplaySubject<{
|
|
70
|
+
id: FocusableID;
|
|
71
|
+
}>();
|
|
72
|
+
|
|
73
|
+
focusableNativeViewRegistrationSubject$ = new Subject<{
|
|
74
|
+
id: FocusableID;
|
|
75
|
+
groupId: FocusableID;
|
|
76
|
+
}>();
|
|
77
|
+
|
|
78
|
+
focusableNativeGroupRegistrationSubject$ = new ReplaySubject<{
|
|
79
|
+
id: FocusableID;
|
|
80
|
+
groupId: FocusableID;
|
|
81
|
+
}>();
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const focusableNativeViewRegistration = ({ focusableView, focusableGroup }) => {
|
|
85
|
+
return focusableNativeViewRegistrationSubject$.pipe(
|
|
86
|
+
filter(
|
|
87
|
+
(focusableNativeView) => focusableNativeView.id === focusableView.id
|
|
88
|
+
),
|
|
89
|
+
take(1),
|
|
90
|
+
switchMap((focusableNativeView) =>
|
|
91
|
+
// start waiting registration of its parent FocusableNativeGroup
|
|
92
|
+
focusableNativeGroupRegistrationSubject$.pipe(
|
|
93
|
+
filter(
|
|
94
|
+
(focusableNativeGroup) =>
|
|
95
|
+
focusableNativeGroup.id === focusableNativeView.groupId
|
|
96
|
+
),
|
|
97
|
+
take(1),
|
|
98
|
+
map((focusableNativeGroup) => ({
|
|
99
|
+
focusableNativeGroup,
|
|
100
|
+
focusableNativeView,
|
|
101
|
+
focusableView,
|
|
102
|
+
focusableGroup,
|
|
103
|
+
}))
|
|
104
|
+
)
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const firstFocusableViewRegistrationFactory = () =>
|
|
110
|
+
focusableViewRegistrationSubject$.pipe(
|
|
111
|
+
take(1), // we care about only first FocusableView registration
|
|
112
|
+
switchMap((focusableView) =>
|
|
113
|
+
// start waiting registration of its parent FocusableGroup
|
|
114
|
+
focusableGroupRegistrationSubject$.pipe(
|
|
115
|
+
filter((focusableGroup) => focusableGroup.id === focusableView.groupId),
|
|
116
|
+
take(1),
|
|
117
|
+
map((focusableGroup) => ({
|
|
118
|
+
focusableView,
|
|
119
|
+
focusableGroup,
|
|
120
|
+
}))
|
|
121
|
+
)
|
|
122
|
+
),
|
|
123
|
+
// start waiting registration for FocusableNativeView and its parent FocusableNativeGroup
|
|
124
|
+
switchMap(({ focusableView, focusableGroup }) =>
|
|
125
|
+
focusableNativeViewRegistration({
|
|
126
|
+
focusableView,
|
|
127
|
+
focusableGroup,
|
|
128
|
+
})
|
|
129
|
+
)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
// registration on RN level(into RN focusManager)
|
|
133
|
+
export const emitRegistered = ({
|
|
134
|
+
id,
|
|
135
|
+
groupId,
|
|
136
|
+
isGroup,
|
|
137
|
+
}: {
|
|
138
|
+
id: Option<FocusableID>;
|
|
139
|
+
groupId: Option<FocusableID>;
|
|
140
|
+
isGroup: boolean;
|
|
141
|
+
}): void => {
|
|
26
142
|
if (isFocusableButton(id)) {
|
|
27
143
|
registeredSubject$.next({ id, registered: true });
|
|
28
144
|
}
|
|
145
|
+
|
|
146
|
+
if (isGroup && id) {
|
|
147
|
+
focusableGroupRegistrationSubject$.next({ id });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (!isGroup && id && groupId) {
|
|
151
|
+
focusableViewRegistrationSubject$.next({ id, groupId });
|
|
152
|
+
}
|
|
29
153
|
};
|
|
30
154
|
|
|
155
|
+
// unregistration on RN level(into RN focusManager)
|
|
31
156
|
export const emitUnregistered = (id: Option<FocusableID>): void => {
|
|
32
157
|
if (isFocusableButton(id)) {
|
|
33
158
|
registeredSubject$.next({ id, registered: false });
|
|
34
159
|
}
|
|
35
160
|
};
|
|
161
|
+
|
|
162
|
+
// registration focusableNativeView and focusableNativeGroup
|
|
163
|
+
export const emitNativeRegistered = ({
|
|
164
|
+
id,
|
|
165
|
+
groupId,
|
|
166
|
+
isGroup,
|
|
167
|
+
}: {
|
|
168
|
+
id: Option<FocusableID>;
|
|
169
|
+
groupId: Option<FocusableID>;
|
|
170
|
+
isGroup: boolean;
|
|
171
|
+
}): void => {
|
|
172
|
+
if (!isGroup && id && groupId) {
|
|
173
|
+
focusableNativeViewRegistrationSubject$.next({ id, groupId });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (isGroup && id && groupId) {
|
|
177
|
+
focusableNativeGroupRegistrationSubject$.next({ id, groupId });
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// /////
|
|
182
|
+
|
|
183
|
+
const focusedSubject$ = new Subject<FocusableID>();
|
|
184
|
+
|
|
185
|
+
const focused$ = focusedSubject$.asObservable();
|
|
186
|
+
|
|
187
|
+
export const emitFocused = (id: FocusableID): void => {
|
|
188
|
+
focusedSubject$.next(id);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
export const topMenuItemFocused$ = focused$.pipe(
|
|
192
|
+
filter((id) => id && isPartOfMenu(focusManager.focusableTree, id))
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
export const contentFocused$ = focused$.pipe(
|
|
196
|
+
filter((id) => {
|
|
197
|
+
const isContent = isPartOfContent(focusManager.focusableTree, id);
|
|
198
|
+
|
|
199
|
+
return id && isContent;
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
const createFocusableRegistry = () => {
|
|
204
|
+
const subject$ = new ReplaySubject<FocusableID | undefined>(1);
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
observable$: subject$.asObservable(),
|
|
208
|
+
register: (id: FocusableID) => {
|
|
209
|
+
// save focusable_id on registration
|
|
210
|
+
subject$.next(id);
|
|
211
|
+
},
|
|
212
|
+
unregister: () => {
|
|
213
|
+
// reset focusable_id on unregistration
|
|
214
|
+
subject$.next(undefined);
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/// HOME_TOP_MENU_ITEM
|
|
220
|
+
export const HomeTopMenuItemRegistry = createFocusableRegistry();
|
|
221
|
+
|
|
222
|
+
export const homeTopMenuItemFocused$ = topMenuItemFocused$.pipe(
|
|
223
|
+
withLatestFrom(HomeTopMenuItemRegistry.observable$),
|
|
224
|
+
filter(([id, homeId]) => id === homeId)
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
/// SCREEN_PICKER
|
|
228
|
+
export const ScreenPickerContentContainerRegistry = createFocusableRegistry();
|
|
229
|
+
|
|
230
|
+
/// SEARCH_INPUT
|
|
231
|
+
export const SearchInputRegistry = createFocusableRegistry();
|
|
@@ -10,10 +10,7 @@ import { Platform } from "react-native";
|
|
|
10
10
|
* platformKeys[Platform.OS] should only include keys
|
|
11
11
|
* that are unique to that platform, i.e. Exit: { keyCode: 10182 }
|
|
12
12
|
*/
|
|
13
|
-
export const KEYS = Object.assign(
|
|
14
|
-
platformKeys["web"],
|
|
15
|
-
platformKeys[Platform.OS]
|
|
16
|
-
);
|
|
13
|
+
export const KEYS = Object.assign(platformKeys.web, platformKeys[Platform.OS]);
|
|
17
14
|
|
|
18
15
|
export const ARROW_KEYS = [
|
|
19
16
|
KEYS.ArrowUp,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as ReactNative from "react-native";
|
|
2
|
-
import {
|
|
2
|
+
import { useAppData } from "@applicaster/zapp-react-native-redux/hooks";
|
|
3
3
|
|
|
4
4
|
import { isTV, platformSelect } from "../reactUtils";
|
|
5
5
|
import { useIsTablet } from "../reactHooks";
|
|
@@ -184,9 +184,7 @@ export const getScreenOrientation = ({
|
|
|
184
184
|
|
|
185
185
|
export const useGetScreenOrientation = (screenData) => {
|
|
186
186
|
const isTablet = useIsTablet();
|
|
187
|
-
|
|
188
|
-
const { appData } = usePickFromState(["appData"]);
|
|
189
|
-
const isTabletPortrait = appData?.isTabletPortrait;
|
|
187
|
+
const { isTabletPortrait } = useAppData();
|
|
190
188
|
|
|
191
189
|
return getScreenOrientation({
|
|
192
190
|
screenData,
|
|
@@ -15,6 +15,22 @@ const logger = createLogger({
|
|
|
15
15
|
|
|
16
16
|
const { log_warning } = logger;
|
|
17
17
|
|
|
18
|
+
interface PlayerMethods {
|
|
19
|
+
seeking?: (position: number) => void;
|
|
20
|
+
forward?: (deltaTime: number) => void;
|
|
21
|
+
rewind?: (deltaTime: number) => void;
|
|
22
|
+
startSleepTimer?: (sleepTimestamp: number) => void;
|
|
23
|
+
selectTrack?: (
|
|
24
|
+
selected: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
|
|
25
|
+
) => void;
|
|
26
|
+
setPlaybackRate?: (rate: number) => void;
|
|
27
|
+
appStateChange?: (appState: string, previousAppState: string) => void;
|
|
28
|
+
closeNativePlayer?: () => void;
|
|
29
|
+
togglePlayPause?: () => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type PlayerComponent = ReactComponent<PlayerRefProps> & PlayerMethods;
|
|
33
|
+
|
|
18
34
|
type PlayerPlugnId = "QuickBrickPlayerPlugin" | "KalturaPlayerPlugin";
|
|
19
35
|
|
|
20
36
|
type Props = {
|
|
@@ -62,7 +78,7 @@ export class PlayerNative extends Player {
|
|
|
62
78
|
return this.playerState.contentPosition;
|
|
63
79
|
};
|
|
64
80
|
|
|
65
|
-
currentPlayerComponent = ():
|
|
81
|
+
currentPlayerComponent = (): PlayerComponent | null =>
|
|
66
82
|
this.playerComponent?.current;
|
|
67
83
|
|
|
68
84
|
getState = () => this.playerState;
|
|
@@ -121,7 +137,7 @@ export class PlayerNative extends Player {
|
|
|
121
137
|
|
|
122
138
|
this.playerState.seekPosition = newPosition;
|
|
123
139
|
|
|
124
|
-
this.currentPlayerComponent()?.
|
|
140
|
+
this.currentPlayerComponent()?.seeking?.(this.playerState.seekPosition);
|
|
125
141
|
}
|
|
126
142
|
|
|
127
143
|
this.logState(PlayerModuleFuncNames.seekTo, { position });
|
|
@@ -135,7 +151,7 @@ export class PlayerNative extends Player {
|
|
|
135
151
|
if (!this.invokeNativeFunction(PlayerModuleFuncNames.forward, deltaTime)) {
|
|
136
152
|
// Kaltura does not have yet this implementation, use legacy code
|
|
137
153
|
|
|
138
|
-
this.currentPlayerComponent()?.
|
|
154
|
+
this.currentPlayerComponent()?.forward?.(deltaTime);
|
|
139
155
|
}
|
|
140
156
|
|
|
141
157
|
this.notifyPlayHeadPositionUpdate();
|
|
@@ -151,7 +167,7 @@ export class PlayerNative extends Player {
|
|
|
151
167
|
if (!this.invokeNativeFunction(PlayerModuleFuncNames.rewind, deltaTime)) {
|
|
152
168
|
// Kaltura does not have yet this implementation, use legacy code
|
|
153
169
|
|
|
154
|
-
this.currentPlayerComponent()?.
|
|
170
|
+
this.currentPlayerComponent()?.rewind?.(deltaTime);
|
|
155
171
|
}
|
|
156
172
|
|
|
157
173
|
this.notifyPlayHeadPositionUpdate();
|
|
@@ -178,7 +194,7 @@ export class PlayerNative extends Player {
|
|
|
178
194
|
sleepTimestamp
|
|
179
195
|
)
|
|
180
196
|
) {
|
|
181
|
-
this.currentPlayerComponent()?.
|
|
197
|
+
this.currentPlayerComponent()?.startSleepTimer?.(sleepTimestamp);
|
|
182
198
|
}
|
|
183
199
|
};
|
|
184
200
|
|
|
@@ -195,11 +211,11 @@ export class PlayerNative extends Player {
|
|
|
195
211
|
selectTrack = (
|
|
196
212
|
selected: QuickBrickPlayer.TextTrack | QuickBrickPlayer.AudioTrack
|
|
197
213
|
) => {
|
|
198
|
-
this.currentPlayerComponent()?.
|
|
214
|
+
this.currentPlayerComponent()?.selectTrack?.(selected);
|
|
199
215
|
};
|
|
200
216
|
|
|
201
217
|
setPlaybackRate = (rate: number) => {
|
|
202
|
-
this.currentPlayerComponent()?.
|
|
218
|
+
this.currentPlayerComponent()?.setPlaybackRate?.(rate);
|
|
203
219
|
};
|
|
204
220
|
|
|
205
221
|
getPluginConfiguration = () => {
|
|
@@ -209,19 +225,16 @@ export class PlayerNative extends Player {
|
|
|
209
225
|
getProps = () => (this.currentPlayerComponent() as any)?.props;
|
|
210
226
|
|
|
211
227
|
appStateChange = (appState, previousAppState) => {
|
|
212
|
-
this.currentPlayerComponent()?.
|
|
213
|
-
appState,
|
|
214
|
-
previousAppState
|
|
215
|
-
);
|
|
228
|
+
this.currentPlayerComponent()?.appStateChange?.(appState, previousAppState);
|
|
216
229
|
};
|
|
217
230
|
|
|
218
231
|
closeNativePlayer = () => {
|
|
219
232
|
// TODO: Delete does not work
|
|
220
|
-
this.currentPlayerComponent()?.
|
|
233
|
+
this.currentPlayerComponent()?.closeNativePlayer?.();
|
|
221
234
|
};
|
|
222
235
|
|
|
223
236
|
togglePlayPause = () => {
|
|
224
|
-
this.currentPlayerComponent()?.
|
|
237
|
+
this.currentPlayerComponent()?.togglePlayPause?.();
|
|
225
238
|
};
|
|
226
239
|
|
|
227
240
|
onVideoLoad = (event) => {
|
|
@@ -289,19 +302,19 @@ export class PlayerNative extends Player {
|
|
|
289
302
|
isFullScreenSupported = (): boolean => {
|
|
290
303
|
const config = this.getConfig();
|
|
291
304
|
|
|
292
|
-
const disableFullScreen = config?.
|
|
305
|
+
const disableFullScreen = config?.disable_fullscreen;
|
|
293
306
|
|
|
294
307
|
if (disableFullScreen) {
|
|
295
308
|
return false;
|
|
296
309
|
}
|
|
297
310
|
|
|
298
|
-
const isFullScreenAudioPlayer = config?.
|
|
311
|
+
const isFullScreenAudioPlayer = config?.full_screen_audio_player;
|
|
299
312
|
|
|
300
313
|
return !(isFullScreenAudioPlayer && this.isAudioItem());
|
|
301
314
|
};
|
|
302
315
|
|
|
303
316
|
supportsNativeControls = (): boolean =>
|
|
304
|
-
toBooleanWithDefaultFalse(this.getConfig()?.
|
|
317
|
+
toBooleanWithDefaultFalse(this.getConfig()?.supports_native_controls);
|
|
305
318
|
|
|
306
319
|
supportNativeCast = (): boolean =>
|
|
307
320
|
toBooleanWithDefaultFalse(
|