@applicaster/zapp-react-native-utils 15.0.0-alpha.3564377339 → 15.0.0-alpha.3564837831
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/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
- package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +3 -0
- package/appUtils/focusManager/index.ios.ts +38 -4
- package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
- package/appUtils/focusManagerAux/utils/utils.ios.ts +161 -11
- package/manifestUtils/defaultManifestConfigurations/player.js +21 -10
- package/package.json +2 -2
- package/reactHooks/navigation/index.ts +4 -0
- package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +1 -1
- package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +1 -1
- package/searchUtils/const.ts +7 -0
- package/searchUtils/index.ts +3 -0
- package/testUtils/index.tsx +1 -1
- package/utils/__tests__/mergeRight.test.ts +48 -0
- package/utils/index.ts +3 -0
- package/utils/mergeRight.ts +5 -0
|
@@ -1,11 +1,31 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
2
|
+
import { QUICK_BRICK_CONTENT } from "@applicaster/quick-brick-core/const";
|
|
3
|
+
import { isNil, isEmpty } from "@applicaster/zapp-react-native-utils/utils";
|
|
4
|
+
import { isNotNil } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
4
5
|
|
|
5
6
|
let riverFocusData = {};
|
|
6
7
|
let initialyPresentedScreenFocused = false;
|
|
7
8
|
|
|
8
9
|
export const riverFocusManager = (function () {
|
|
10
|
+
/**
|
|
11
|
+
* Create unique key that will be used for save focused group data inside specific screen
|
|
12
|
+
* @param {{ screenId: string, isInsideContainer: boolean }}
|
|
13
|
+
* screenId Unique Id of the screen from layout.json
|
|
14
|
+
* isInsideContainer If this screen a screen picker child
|
|
15
|
+
*
|
|
16
|
+
*/
|
|
17
|
+
function screenFocusableGroupId({
|
|
18
|
+
screenId,
|
|
19
|
+
isInsideContainer,
|
|
20
|
+
}: {
|
|
21
|
+
screenId: string;
|
|
22
|
+
isInsideContainer: Option<boolean>;
|
|
23
|
+
}) {
|
|
24
|
+
return `${QUICK_BRICK_CONTENT}-${screenId}${
|
|
25
|
+
isNil(isInsideContainer) ? "" : "-isInsideContainer"
|
|
26
|
+
}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
9
29
|
function setScreenFocusableData({
|
|
10
30
|
screenFocusableGroupId,
|
|
11
31
|
groupId,
|
|
@@ -78,8 +98,8 @@ export const riverFocusManager = (function () {
|
|
|
78
98
|
}) {
|
|
79
99
|
// Check if screen should be focused
|
|
80
100
|
const shouldFocus =
|
|
81
|
-
(initialyPresentedScreenFocused === false &&
|
|
82
|
-
|
|
101
|
+
(initialyPresentedScreenFocused === false && isEmpty(riverFocusData)) ||
|
|
102
|
+
isNotNil(riverFocusData[screenFocusableGroupId]) ||
|
|
83
103
|
isDeepLink;
|
|
84
104
|
|
|
85
105
|
// TODO: Uncommit it to start fixing bug where selection wrong item
|
|
@@ -118,19 +138,6 @@ export const riverFocusManager = (function () {
|
|
|
118
138
|
}
|
|
119
139
|
}
|
|
120
140
|
|
|
121
|
-
/**
|
|
122
|
-
* Create unique key that will be used for save focused group data inside specific screen
|
|
123
|
-
* @param {{ screenId: string, isInsideContainer: boolean }}
|
|
124
|
-
* screenId Unique Id of the screen from layout.json
|
|
125
|
-
* isInsideContainer If this screen a screen picker child
|
|
126
|
-
*
|
|
127
|
-
*/
|
|
128
|
-
function screenFocusableGroupId({ screenId, isInsideContainer }) {
|
|
129
|
-
return `RiverFocusableGroup-${screenId}${
|
|
130
|
-
R.isNil(isInsideContainer) ? "" : "-isInsideContainer"
|
|
131
|
-
}`;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
141
|
return {
|
|
135
142
|
setScreenFocusableData,
|
|
136
143
|
clearAllScreensData,
|
|
@@ -71,6 +71,9 @@ exports[`focusManagerIOS should be defined 1`] = `
|
|
|
71
71
|
"invokeHandler": [Function],
|
|
72
72
|
"isChildOf": [Function],
|
|
73
73
|
"isFocusOn": [Function],
|
|
74
|
+
"isFocusOnContent": [Function],
|
|
75
|
+
"isFocusOnMenu": [Function],
|
|
76
|
+
"isFocusOnTabsScreen": [Function],
|
|
74
77
|
"isGroupItemFocused": [Function],
|
|
75
78
|
"moveFocus": [Function],
|
|
76
79
|
"on": [Function],
|
|
@@ -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
|
+
isPartOfTabsScreen,
|
|
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";
|
|
@@ -13,6 +17,7 @@ import { findChild } from "./utils";
|
|
|
13
17
|
import {
|
|
14
18
|
emitRegistered,
|
|
15
19
|
emitUnregistered,
|
|
20
|
+
emitWillFocused,
|
|
16
21
|
} from "../focusManagerAux/utils/utils.ios";
|
|
17
22
|
|
|
18
23
|
const { FocusableManagerModule } = NativeModules;
|
|
@@ -194,9 +199,9 @@ export const focusManager = (function () {
|
|
|
194
199
|
registerItem(id, component);
|
|
195
200
|
}
|
|
196
201
|
|
|
197
|
-
const
|
|
202
|
+
const groupId = component?.props?.groupId;
|
|
198
203
|
|
|
199
|
-
emitRegistered({ id,
|
|
204
|
+
emitRegistered({ id, groupId, isGroup });
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
function unregister(id, { group = false } = {}) {
|
|
@@ -279,12 +284,16 @@ export const focusManager = (function () {
|
|
|
279
284
|
function setFocus(
|
|
280
285
|
id: string,
|
|
281
286
|
direction?: FocusManager.IOS.Direction,
|
|
282
|
-
options?: Partial<{
|
|
287
|
+
options?: Partial<{
|
|
288
|
+
groupFocusedChanged: boolean;
|
|
289
|
+
}>,
|
|
283
290
|
callback?: any
|
|
284
291
|
) {
|
|
285
292
|
blur(direction);
|
|
286
293
|
currentFocus = id;
|
|
287
294
|
|
|
295
|
+
emitWillFocused(id);
|
|
296
|
+
|
|
288
297
|
// Extract groupFocusedChanged with a default value of false
|
|
289
298
|
let groupFocusedChanged = false;
|
|
290
299
|
|
|
@@ -418,6 +427,28 @@ export const focusManager = (function () {
|
|
|
418
427
|
return id && isCurrentFocusOn(id, currentFocusNode);
|
|
419
428
|
}
|
|
420
429
|
|
|
430
|
+
function isFocusOnMenu(): boolean {
|
|
431
|
+
const currentFocusable = getCurrentFocus();
|
|
432
|
+
|
|
433
|
+
return isPartOfMenu(focusableTree, currentFocusable?.props?.id);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function isFocusOnContent(): boolean {
|
|
437
|
+
const currentFocusable = getCurrentFocus();
|
|
438
|
+
|
|
439
|
+
return isPartOfContent(focusableTree, currentFocusable?.props?.id);
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function isFocusOnTabsScreen(tabsScreenContainerId: string): boolean {
|
|
443
|
+
const currentFocusable = getCurrentFocus();
|
|
444
|
+
|
|
445
|
+
return isPartOfTabsScreen(
|
|
446
|
+
focusableTree,
|
|
447
|
+
tabsScreenContainerId,
|
|
448
|
+
currentFocusable?.props?.id
|
|
449
|
+
);
|
|
450
|
+
}
|
|
451
|
+
|
|
421
452
|
function isChildOf(childId, parentId): boolean {
|
|
422
453
|
return isChildOfUtils(focusableTree, childId, parentId);
|
|
423
454
|
}
|
|
@@ -444,6 +475,9 @@ export const focusManager = (function () {
|
|
|
444
475
|
isGroupItemFocused,
|
|
445
476
|
getPreferredFocusChild,
|
|
446
477
|
isFocusOn,
|
|
478
|
+
isFocusOnMenu,
|
|
479
|
+
isFocusOnContent,
|
|
480
|
+
isFocusOnTabsScreen,
|
|
447
481
|
isChildOf,
|
|
448
482
|
};
|
|
449
483
|
})();
|
|
@@ -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 isPartOfTabsScreen = (
|
|
13
|
+
focusableTree,
|
|
14
|
+
tabsScreenContainerId,
|
|
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 === tabsScreenContainerId) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return isPartOfTabsScreen(
|
|
40
|
+
focusableTree,
|
|
41
|
+
tabsScreenContainerId,
|
|
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
|
+
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ReplaySubject, Subject } from "rxjs";
|
|
2
|
-
import { filter, switchMap, take } from "rxjs/operators";
|
|
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 = {
|
|
@@ -11,13 +13,23 @@ type RegistrationEvent = {
|
|
|
11
13
|
|
|
12
14
|
let focusableViewRegistrationSubject$ = new Subject<{
|
|
13
15
|
id: FocusableID;
|
|
14
|
-
|
|
16
|
+
groupId: FocusableID;
|
|
15
17
|
}>();
|
|
16
18
|
|
|
17
19
|
let focusableGroupRegistrationSubject$ = new ReplaySubject<{
|
|
18
20
|
id: FocusableID;
|
|
19
21
|
}>();
|
|
20
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
|
+
|
|
21
33
|
const isFocusableButton = (id: Option<FocusableID>): boolean =>
|
|
22
34
|
id && id.includes?.(BUTTON_PREFIX);
|
|
23
35
|
|
|
@@ -41,35 +53,90 @@ export const resetFocusableRegistration = () => {
|
|
|
41
53
|
focusableGroupRegistrationSubject$.complete();
|
|
42
54
|
}
|
|
43
55
|
|
|
56
|
+
if (!focusableNativeViewRegistrationSubject$.closed) {
|
|
57
|
+
focusableNativeViewRegistrationSubject$.complete();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!focusableNativeGroupRegistrationSubject$.closed) {
|
|
61
|
+
focusableNativeGroupRegistrationSubject$.complete();
|
|
62
|
+
}
|
|
63
|
+
|
|
44
64
|
focusableViewRegistrationSubject$ = new Subject<{
|
|
45
65
|
id: FocusableID;
|
|
46
|
-
|
|
66
|
+
groupId: FocusableID;
|
|
47
67
|
}>();
|
|
48
68
|
|
|
49
69
|
focusableGroupRegistrationSubject$ = new ReplaySubject<{
|
|
50
70
|
id: FocusableID;
|
|
51
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
|
+
);
|
|
52
107
|
};
|
|
53
108
|
|
|
54
109
|
export const firstFocusableViewRegistrationFactory = () =>
|
|
55
110
|
focusableViewRegistrationSubject$.pipe(
|
|
56
111
|
take(1), // we care about only first FocusableView registration
|
|
57
|
-
switchMap((
|
|
58
|
-
// start waiting registration of its parent
|
|
112
|
+
switchMap((focusableView) =>
|
|
113
|
+
// start waiting registration of its parent FocusableGroup
|
|
59
114
|
focusableGroupRegistrationSubject$.pipe(
|
|
60
|
-
filter((
|
|
115
|
+
filter((focusableGroup) => focusableGroup.id === focusableView.groupId),
|
|
116
|
+
take(1),
|
|
117
|
+
map((focusableGroup) => ({
|
|
118
|
+
focusableView,
|
|
119
|
+
focusableGroup,
|
|
120
|
+
}))
|
|
61
121
|
)
|
|
62
122
|
),
|
|
63
|
-
|
|
123
|
+
// start waiting registration for FocusableNativeView and its parent FocusableNativeGroup
|
|
124
|
+
switchMap(({ focusableView, focusableGroup }) =>
|
|
125
|
+
focusableNativeViewRegistration({
|
|
126
|
+
focusableView,
|
|
127
|
+
focusableGroup,
|
|
128
|
+
})
|
|
129
|
+
)
|
|
64
130
|
);
|
|
65
131
|
|
|
132
|
+
// registration on RN level(into RN focusManager)
|
|
66
133
|
export const emitRegistered = ({
|
|
67
134
|
id,
|
|
68
|
-
|
|
135
|
+
groupId,
|
|
69
136
|
isGroup,
|
|
70
137
|
}: {
|
|
71
138
|
id: Option<FocusableID>;
|
|
72
|
-
|
|
139
|
+
groupId: Option<FocusableID>;
|
|
73
140
|
isGroup: boolean;
|
|
74
141
|
}): void => {
|
|
75
142
|
if (isFocusableButton(id)) {
|
|
@@ -80,13 +147,96 @@ export const emitRegistered = ({
|
|
|
80
147
|
focusableGroupRegistrationSubject$.next({ id });
|
|
81
148
|
}
|
|
82
149
|
|
|
83
|
-
if (!isGroup && id &&
|
|
84
|
-
focusableViewRegistrationSubject$.next({ id,
|
|
150
|
+
if (!isGroup && id && groupId) {
|
|
151
|
+
focusableViewRegistrationSubject$.next({ id, groupId });
|
|
85
152
|
}
|
|
86
153
|
};
|
|
87
154
|
|
|
155
|
+
// unregistration on RN level(into RN focusManager)
|
|
88
156
|
export const emitUnregistered = (id: Option<FocusableID>): void => {
|
|
89
157
|
if (isFocusableButton(id)) {
|
|
90
158
|
registeredSubject$.next({ id, registered: false });
|
|
91
159
|
}
|
|
92
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
|
+
// Focusable has been focused
|
|
182
|
+
const willFocusedSubject$ = new Subject<FocusableID>();
|
|
183
|
+
const didFocusedSubject$ = new Subject<FocusableID>();
|
|
184
|
+
|
|
185
|
+
export const willFocused$ = willFocusedSubject$.asObservable();
|
|
186
|
+
|
|
187
|
+
export const didFocused$ = didFocusedSubject$.asObservable();
|
|
188
|
+
|
|
189
|
+
export const emitWillFocused = (id: FocusableID): void => {
|
|
190
|
+
willFocusedSubject$.next(id);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
export const emitDidFocused = (id: FocusableID): void => {
|
|
194
|
+
didFocusedSubject$.next(id);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const topMenuItemDidFocused$ = didFocused$.pipe(
|
|
198
|
+
filter((id) => id && isPartOfMenu(focusManager.focusableTree, id))
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
export const contentDidFocused$ = didFocused$.pipe(
|
|
202
|
+
filter((id) => {
|
|
203
|
+
const isContent = isPartOfContent(focusManager.focusableTree, id);
|
|
204
|
+
|
|
205
|
+
return id && isContent;
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
// Focusable has been focused
|
|
209
|
+
|
|
210
|
+
const createFocusableRegistry = () => {
|
|
211
|
+
const subject$ = new ReplaySubject<FocusableID | undefined>(1);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
observable$: subject$.asObservable(),
|
|
215
|
+
register: (id: FocusableID) => {
|
|
216
|
+
// save focusable_id on registration
|
|
217
|
+
subject$.next(id);
|
|
218
|
+
},
|
|
219
|
+
unregister: () => {
|
|
220
|
+
// reset focusable_id on unregistration
|
|
221
|
+
subject$.next(undefined);
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/// HOME_TOP_MENU_ITEM
|
|
227
|
+
export const HomeTopMenuItemRegistry = createFocusableRegistry();
|
|
228
|
+
|
|
229
|
+
export const homeTopMenuItemDidFocused$ = topMenuItemDidFocused$.pipe(
|
|
230
|
+
withLatestFrom(HomeTopMenuItemRegistry.observable$),
|
|
231
|
+
filter(([id, homeId]) => id === homeId)
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
/// TABS SCREEN
|
|
235
|
+
export const TabsScreenContentContainerRegistry = createFocusableRegistry();
|
|
236
|
+
|
|
237
|
+
export const TabsScreenScreenSelectorContainerRegistry =
|
|
238
|
+
createFocusableRegistry();
|
|
239
|
+
/// TABS SCREEN
|
|
240
|
+
|
|
241
|
+
/// SEARCH_INPUT
|
|
242
|
+
export const SearchInputRegistry = createFocusableRegistry();
|
|
@@ -678,6 +678,22 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
678
678
|
}
|
|
679
679
|
|
|
680
680
|
if (isMobile(platform)) {
|
|
681
|
+
localizations.fields.push(
|
|
682
|
+
{
|
|
683
|
+
type: "text_input",
|
|
684
|
+
label: "Restrict playback on mobile networks alert title",
|
|
685
|
+
key: "mobile_connection_restricted_alert_title",
|
|
686
|
+
initial_value: "Restricted Connection Type",
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
type: "text_input",
|
|
690
|
+
label: "Restrict playback on mobile networks alert message",
|
|
691
|
+
key: "mobile_connection_restricted_alert_message",
|
|
692
|
+
initial_value:
|
|
693
|
+
"This content can only be viewed over a Wi-Fi or LAN network.",
|
|
694
|
+
}
|
|
695
|
+
);
|
|
696
|
+
|
|
681
697
|
general.fields.push(
|
|
682
698
|
{
|
|
683
699
|
section: "Default Timestamp Type",
|
|
@@ -1200,40 +1216,35 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
1200
1216
|
label: "Playback Speed 0.8x",
|
|
1201
1217
|
type: "uploader",
|
|
1202
1218
|
label_tooltip: "Playback Speed 0.8x",
|
|
1203
|
-
initial_value:
|
|
1204
|
-
"data:image/png;base64,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",
|
|
1219
|
+
initial_value: null,
|
|
1205
1220
|
},
|
|
1206
1221
|
{
|
|
1207
1222
|
key: "speed_1",
|
|
1208
1223
|
label: "Playback Speed 1x",
|
|
1209
1224
|
type: "uploader",
|
|
1210
1225
|
label_tooltip: "Playback Speed 1x",
|
|
1211
|
-
initial_value:
|
|
1212
|
-
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAI4SURBVHgB7dzhcRJBGIDhT8cCkg6SDmIHsQNLiBUYKwAqUCtIC5ZACVqBdIAdxN3JMSLecXcE8Tt5npkdJlxyf97ZcLcLRAAAAAAAAAAAAAAAAAAAAAAAAADAMb2IiViv17fl4aGMq45fub68vFwFv3kVyZWwF+VhVsZ9MFrqwANmLT1SBm5mbQ37NniWl5FMifu+PHwPcY8izQwuYa/iadbeBkeTaQbfxf64P8r4GoyS7l90h89lXJfxLRgl+23Sqox35f52WX8o/8aDcTLP4EUZrzdxOUzGGbws40MJ6/X2CDIFrhdRNeyn4GjSBBb275jKVTQHEvg/d/aB69Lo+sljGR/jADvnmEUiZx242a2qr/0XzVP35bmHkeeY7Zxj3pw3hXOfwTctz90NjdzEnbccuo0kzj1w1712b+Q9cfed9+TOOnCzSrboONwZuSfuopz3SyRx9hdZJcY8RkQeELfr2D/hNimGR55a3Cr9m+5OpcZpdqvabnNq5HpBdtPx5ynjVmbwlp6ZPLm4lcA7eiLvSh23ErjFwMjp41YCd3t85vEUBG7Rc7W8Mc+27txG4B0D426kjyzwlp64y47nU0cWuDFgEeNNdF94pY0scAxfoeq5uk4Z2Yb/yOXHqUW24X/A2vKAyGk+OGfDv13vIsaBy5onZ8P/T4NXqPZEtuGfwdaG/yp+vfF+HiNsRV5tnSPNhv9kvoSlaj75f9F2zBewAAAAAAAAAAAAAAAAAAAAAAAAwHT8BNhH51wNSx95AAAAAElFTkSuQmCC",
|
|
1226
|
+
initial_value: null,
|
|
1213
1227
|
},
|
|
1214
1228
|
{
|
|
1215
1229
|
key: "speed_1_2",
|
|
1216
1230
|
label: "Playback Speed 1.2x",
|
|
1217
1231
|
type: "uploader",
|
|
1218
1232
|
label_tooltip: "Playback Speed 1.2x",
|
|
1219
|
-
initial_value:
|
|
1220
|
-
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAUjSURBVHgB7d3bUeNIFAbgA7Xv2EUCmgiWjWBNBAwRYCKYdQQrIliIYEUEw0awymDIYDQBUFC8g+eccWsulPomteTu1v9VdZlSGyP0W1KrWxciAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgPgc0Mw8Pj4u+KUt4mm5XDaUqVED5oX5gV/ea6o3vGDvaQI8Hyt+ueAir4XmbTIvNZebnAIfJWBeoCf88g/tFqjOKS/ImkbE8/FezUdBfu5o9wVsKHGHFJBs/rjIAv1E5nBHpebjX/7xI/mHK+SL8Zk/429K3G8UiNoMykItaI/UPvZ/Lic0XMmfR7wmX1GiBq/BP621slAL2j9Z60KE25KQ/6JEDdoHD9jHieD7YJ6fNe22IjpPXG5p16Bq1DT5MpyReZciv/eO5/eJEtN7E63C/Wh5myyQBU1Hu888ODi42263lx0h1Vyu1ZdDvqxd8yvTZC0uKTFDNtGm4GQhbrjc0ERUy73QVNeLxeLctAZyXcUv56R3QQkK2or+9oGHhxXtNmfXNK2Voe6SHKhdxq2muuAvUUGJCRlww+X06Ojock/7qj810+89j2fvDHUFJSZUwLIp/mPsjgsL3S7jC/mZpHdtKkOPg2VhbPYcbEuOVbs2rw35mbJROLohAdeqYRKFgF+ywlCX3GFS7010xiMwZ5rpzVSDIyEFb0WnTLWS1111fHRQU4IQ8K+0vWCvr69J9kcjYEWNHK001c5jxNIvz2XLpfdolIyEtZ/x/Pw8qIMFAdP3ExNKTXVDjl2UqruzHZgoaDdQ4RWyGuZct5/x8vJSqRGyXmYfMC88WUNMvW6nHh03q45pziG/Cdf2uU5mHbAKtzK8xfesjloz3RqyIVzRu/U+24Adwr3y7U+XfgFujOn6srUhW8K9GnJIOsuAHcMtqYfj4+O1T8gO4ZY0wOwCdgj3duhCdQ157HDFrAJ2DHdNATiELCcmrjX1QcIVswl4ynBblpB1540FC1fMImB1nFsZ3hI83JYl5LeChiuyD1jt70yt4dHCbTmGHDxckXXAKtzS8JbRw23xYMXW8hZbfb+/S5mKKVxLa7nl3a3pItiVDaGpoTs5NVf6YeW8qjuP300t3FbwKymiDLgrIJ4m3XXWfuGEwpX/p6slHTTk6AJWIzJlR5UsDDnR/tTwu7ZwGy6Vuo6qF9dTg1w6MR4eHireN3cNBwYLOcY1+MxQt5Khs661WF0/VJJZQbtrqPpquLyzvcm1h0pa1xwyjRlyjI0s29jnief0Sfl2P/r2XfuKMWDbeczRnvimdi9rTbX2ONch5N5f3hgDrgx1N8u4r/BbaaZbOzEsIRfUU3QBq0aMXEvUvKmS1m/s1+nWHdOce6gMIffeao3dyJJj10ZTp5v+beCcN0s17farsk9uHFqvFenPqAjFuPVQ813wjx/UJO+TBiRk/gz5Oxfq7w0a8AcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANif7B8Q/dOlJHI7iEJNvlcl+8tCsg5Y3R/Ldm1QuUz46aI2ud9lx+XCr1HubhOLLNdgh6eQdjn3uZNPKnIN+DP5XzQtl6ha77+Rmuw20eoOOgX5K4bcfSdWOe6Dh9yMJYobuYSUY8BDnj2Y1XMLRY4BD7lJS3LPJrTJMeAht1lK7tmENmhF/4BWdEI25C/L3qwsA1YdFj6BXcX0LOSQcu+LLvnF1g258b2XVUrmMppUcvmdfhznNlz+43Kd+2jSV0z9PFgMpokeAAAAAElFTkSuQmCC",
|
|
1233
|
+
initial_value: null,
|
|
1221
1234
|
},
|
|
1222
1235
|
{
|
|
1223
1236
|
key: "speed_1_5",
|
|
1224
1237
|
label: "Playback Speed 1.5x",
|
|
1225
1238
|
type: "uploader",
|
|
1226
1239
|
label_tooltip: "Playback Speed 1.5x",
|
|
1227
|
-
initial_value:
|
|
1228
|
-
"data:image/png;base64,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",
|
|
1240
|
+
initial_value: null,
|
|
1229
1241
|
},
|
|
1230
1242
|
{
|
|
1231
1243
|
key: "speed_2",
|
|
1232
1244
|
label: "Playback Speed 2x",
|
|
1233
1245
|
type: "uploader",
|
|
1234
1246
|
label_tooltip: "Playback Speed 2x",
|
|
1235
|
-
initial_value:
|
|
1236
|
-
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQnSURBVHgB7d2PUdRAFMfxh2MBUIGxArECjwqECjwqUCowV4FYgdABVCAdSAekg7ME35pFgnOb3ZDAvmy+n5lMGJLL3dzvkuyfZCMCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2LMnM7Hdbvd11p2ag4ODRtDLdMAa6kpnH3U61qkKrHbrp0sN/EbwiMmAfbBfdVrJMI1OZxr0leAvcwFruC7YWsY515DPBLYC1nC/6eyLTONCQz6VhXslRvg9d6pwnbX/wSyaiT1Yg6h0dhdZzZ1Xr6U9zzqHOn2QtgDW52jJhS8rAf/Q2Tqw2JWQT0JVIv/j+CnhUvaNvvZIFip7wL5+uw0sbqTdA5vINiqd/ZK2fryLbuLgtyyQhXPwYc+yTUpjhl/ne88qK1koCwGvQgs0uAtJ17duJQtlIeDQYfVWBojs6fuyUK8lP1c63hXmlOfMRZ5/newBT1WF0YJW37m8kYUy09Axgb6ABx3uSzKb7sI+vqrlqknVjsXJ9WC/HRlTpZpiG1MqZQ92zZxVYNmlJPBNpdv2z6c1cfrXjdrG1Ga/B+sX+Vln54HFV7onnUh8GytpW8O6BnVWBFrjTnJ3Xc56D/YFq1C47hCZ2mW46/y99qGlfI5QU+uhZDbbgDtt0CFJrWBeqBAWDTnSjn4jmc0y4E64oQYMF+65JPJVtU1gcTDkSLgbC71YszsHJ/QeuWuz1vK0bdfSFth2eXROTgi3FgNmFXBCuLf6xb6Xce9RSyTkuYTrzOmyWVdg6Tssu/Po0RT1z0jIjYR/YKbCdWYR8EuG23nPWsIh72IuXMd8wDnC7bx3LWkhmwzXsX7he7ZwO5+hlv6QzYbrmK0mWQjXezNyeVZW72wwEW6ktNxl9hpsc3uwfqmfZF7hOsnNmi/NVMA+3AsJh9tI24CfM9ybwP9Nhmzpzob7cEMaSbiEdoLPEWvEcH3Lg5s1c7Fy4Xss3PueoUaeKKVdeEgL1ZBmzZwsXPi+kv5eoUnoF74X+Rx9N77trArNIWQLh+hKMtOgjmVguI7/f9/h+lgyK+miuzGqwP+jjRiRkOnwN2JXh39yC1VPyFeSGQHLvwKYu3bLBd1IOwxELQP49U//28atZGahkFXJC9wcNvA+JwAAAAAAAAAAAAAAAAAAAAAAAIxWxIjvffytMW5M6e4ziO+fOTxkRNpZKjrgyGDh92oNeSOFKvbuQj9Ef8qQwrVft0hF7sEa2FpnQwdDyT78/nMoNeA7GT40RKMBv5XCFHeI9oO6VDJc5V9blBLPwWPGxcg+psbUSgx4X55uzGtNKjHgMcMcPvfItS+uxIDHDHySfdCUqVGKfkApekZSn3jWVWRrVpEB+waLIYFtSh1mqfS26FriD9U4G/KUtLlZSm9SrdM7eajnNjpd63Reem/SH2FDq35f8ateAAAAAElFTkSuQmCC",
|
|
1247
|
+
initial_value: null,
|
|
1237
1248
|
},
|
|
1238
1249
|
{
|
|
1239
1250
|
key: "sleep_timer",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "15.0.0-alpha.
|
|
3
|
+
"version": "15.0.0-alpha.3564837831",
|
|
4
4
|
"description": "Applicaster Zapp React Native utilities package",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@applicaster/applicaster-types": "15.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "15.0.0-alpha.3564837831",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { Provider } from "react-redux";
|
|
3
3
|
import { renderHook } from "@testing-library/react-hooks";
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
|
-
import thunk from "redux-thunk";
|
|
5
|
+
import { thunk } from "redux-thunk";
|
|
6
6
|
|
|
7
7
|
const mockStore = configureStore([thunk]);
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { Provider } from "react-redux";
|
|
3
3
|
import { renderHook } from "@testing-library/react-hooks";
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
|
-
import thunk from "redux-thunk";
|
|
5
|
+
import { thunk } from "redux-thunk";
|
|
6
6
|
|
|
7
7
|
const mockStore = configureStore([thunk]);
|
|
8
8
|
|
package/testUtils/index.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import React, { PropsWithChildren } from "react";
|
|
|
4
4
|
import configureStore from "redux-mock-store";
|
|
5
5
|
import { Provider } from "react-redux";
|
|
6
6
|
import { View } from "react-native";
|
|
7
|
-
import thunk from "redux-thunk";
|
|
7
|
+
import { thunk } from "redux-thunk";
|
|
8
8
|
import * as R from "ramda";
|
|
9
9
|
|
|
10
10
|
import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { mergeRight } from "../mergeRight";
|
|
2
|
+
|
|
3
|
+
describe("mergeRight", () => {
|
|
4
|
+
test("merges two objects with no overlapping keys", () => {
|
|
5
|
+
const a = { x: 1, y: 2 };
|
|
6
|
+
const b = { z: 3 };
|
|
7
|
+
|
|
8
|
+
const result = mergeRight(a, b);
|
|
9
|
+
|
|
10
|
+
expect(result).toEqual({ x: 1, y: 2, z: 3 });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("overwrites keys from the second object", () => {
|
|
14
|
+
const a = { x: 1, y: 2 };
|
|
15
|
+
const b = { y: 10, z: 3 };
|
|
16
|
+
|
|
17
|
+
const result = mergeRight(a, b);
|
|
18
|
+
|
|
19
|
+
expect(result).toEqual({ x: 1, y: 10, z: 3 });
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("does not mutate the original objects", () => {
|
|
23
|
+
const a = { x: 1 };
|
|
24
|
+
const b = { y: 2 };
|
|
25
|
+
|
|
26
|
+
const result = mergeRight(a, b);
|
|
27
|
+
|
|
28
|
+
expect(result).not.toBe(a);
|
|
29
|
+
expect(result).not.toBe(b);
|
|
30
|
+
expect(a).toEqual({ x: 1 });
|
|
31
|
+
expect(b).toEqual({ y: 2 });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("works with empty objects", () => {
|
|
35
|
+
expect(mergeRight({}, { a: 1 })).toEqual({ a: 1 });
|
|
36
|
+
expect(mergeRight({ a: 1 }, {})).toEqual({ a: 1 });
|
|
37
|
+
expect(mergeRight({}, {})).toEqual({});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("works with nested objects (shallow merge only)", () => {
|
|
41
|
+
const a = { x: { nested: 1 }, y: 2 };
|
|
42
|
+
const b = { x: { nested: 10 }, z: 3 };
|
|
43
|
+
|
|
44
|
+
const result = mergeRight(a, b);
|
|
45
|
+
|
|
46
|
+
expect(result).toEqual({ x: { nested: 10 }, y: 2, z: 3 });
|
|
47
|
+
});
|
|
48
|
+
});
|
package/utils/index.ts
CHANGED
|
@@ -18,6 +18,8 @@ export { take } from "./take";
|
|
|
18
18
|
|
|
19
19
|
export { mapAccum } from "./mapAccum";
|
|
20
20
|
|
|
21
|
+
export { mergeRight } from "./mergeRight";
|
|
22
|
+
|
|
21
23
|
export {
|
|
22
24
|
cloneDeep as clone,
|
|
23
25
|
flatten,
|
|
@@ -51,4 +53,5 @@ export {
|
|
|
51
53
|
findIndex,
|
|
52
54
|
set,
|
|
53
55
|
compact,
|
|
56
|
+
identity,
|
|
54
57
|
} from "lodash";
|