@applicaster/zapp-react-native-utils 14.0.0-alpha.4111088201 → 14.0.0-alpha.4385101226
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 +1 -1
- package/analyticsUtils/AnalyticsEvents/helper.ts +81 -0
- package/analyticsUtils/AnalyticsEvents/sendOnClickEvent.ts +14 -4
- package/analyticsUtils/__tests__/analyticsUtils.test.js +14 -0
- package/analyticsUtils/events.ts +8 -0
- package/appUtils/HooksManager/Hook.ts +4 -4
- package/appUtils/HooksManager/index.ts +11 -1
- package/appUtils/accessibilityManager/index.ts +5 -5
- package/appUtils/focusManager/treeDataStructure/Tree/index.js +1 -1
- package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +0 -15
- package/appUtils/playerManager/useChapterMarker.tsx +0 -1
- package/appUtils/playerManager/usePlayerControllerSetup.tsx +16 -0
- package/arrayUtils/index.ts +1 -1
- package/componentsUtils/__tests__/isTabsScreen.test.ts +38 -0
- package/componentsUtils/index.ts +4 -1
- package/configurationUtils/__tests__/manifestKeyParser.test.ts +547 -0
- package/configurationUtils/manifestKeyParser.ts +57 -32
- package/focusManager/FocusManager.ts +26 -16
- package/focusManager/Tree.ts +25 -21
- package/focusManager/__tests__/FocusManager.test.ts +50 -8
- package/index.d.ts +0 -9
- package/manifestUtils/defaultManifestConfigurations/player.js +8 -0
- package/navigationUtils/__tests__/mapContentTypesToRivers.test.ts +130 -0
- package/navigationUtils/index.ts +6 -4
- package/package.json +2 -3
- package/playerUtils/getPlayerActionButtons.ts +1 -1
- package/playerUtils/index.ts +51 -0
- package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +3 -1
- package/reactHooks/feed/useBatchLoading.ts +9 -7
- package/reactHooks/feed/useFeedLoader.tsx +12 -8
- package/reactHooks/feed/usePipesCacheReset.ts +3 -3
- package/reactHooks/flatList/useSequentialRenderItem.tsx +3 -3
- package/reactHooks/layout/__tests__/index.test.tsx +3 -1
- package/reactHooks/layout/isTablet/index.ts +12 -5
- package/reactHooks/layout/useDimensions/__tests__/useDimensions.test.ts +34 -36
- package/reactHooks/layout/useDimensions/useDimensions.ts +2 -3
- package/reactHooks/layout/useLayoutVersion.ts +5 -5
- package/reactHooks/navigation/index.ts +7 -5
- package/reactHooks/navigation/useIsScreenActive.ts +9 -5
- package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +4 -0
- package/reactHooks/screen/useScreenContext.ts +1 -1
- package/reactHooks/state/__tests__/ZStoreProvider.test.tsx +2 -1
- package/reactHooks/state/useRivers.ts +7 -8
- package/riverComponetsMeasurementProvider/index.tsx +1 -1
- package/services/js2native.ts +1 -0
- package/time/BackgroundTimer.ts +6 -4
- package/utils/index.ts +5 -0
|
@@ -176,18 +176,30 @@ class FocusManager {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
registerFocusable(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
isFocusableCell
|
|
183
|
-
|
|
184
|
-
|
|
179
|
+
registerFocusable({
|
|
180
|
+
touchableRef,
|
|
181
|
+
parentFocusableRef,
|
|
182
|
+
isFocusableCell,
|
|
183
|
+
parentFocusableId,
|
|
184
|
+
}: {
|
|
185
|
+
touchableRef: FocusManager.TouchableReactRef;
|
|
186
|
+
parentFocusableRef: FocusManager.TouchableReactRef;
|
|
187
|
+
isFocusableCell: boolean;
|
|
188
|
+
parentFocusableId: string;
|
|
189
|
+
}) {
|
|
190
|
+
const focusableId = getFocusableId(touchableRef);
|
|
191
|
+
|
|
185
192
|
const focusableComponent = FocusManager.findFocusable(focusableId);
|
|
186
193
|
|
|
187
|
-
if (!focusableComponent &&
|
|
188
|
-
this.focusableComponents.push(
|
|
194
|
+
if (!focusableComponent && touchableRef) {
|
|
195
|
+
this.focusableComponents.push(touchableRef);
|
|
189
196
|
|
|
190
|
-
this.tree.add(
|
|
197
|
+
this.tree.add(
|
|
198
|
+
touchableRef,
|
|
199
|
+
parentFocusableRef,
|
|
200
|
+
isFocusableCell,
|
|
201
|
+
parentFocusableId
|
|
202
|
+
);
|
|
191
203
|
} else {
|
|
192
204
|
logger.warning("Focusable component already registered", {
|
|
193
205
|
id: focusableId,
|
|
@@ -243,12 +255,10 @@ class FocusManager {
|
|
|
243
255
|
}
|
|
244
256
|
|
|
245
257
|
blurPrevious(options?: FocusManager.Android.CallbackOptions) {
|
|
246
|
-
|
|
247
|
-
FocusManager.instance.prevFocused
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
);
|
|
251
|
-
}
|
|
258
|
+
FocusManager.instance.prevFocused?.onBlur?.(
|
|
259
|
+
FocusManager.instance.prevFocused,
|
|
260
|
+
options ?? {} // Adding fallback to avoid potential regression caused by #7509
|
|
261
|
+
);
|
|
252
262
|
}
|
|
253
263
|
|
|
254
264
|
onDisableFocusChange = (id) => {
|
|
@@ -269,7 +279,7 @@ class FocusManager {
|
|
|
269
279
|
|
|
270
280
|
if (nextFocus) {
|
|
271
281
|
// HACK: hack to fix the hack below
|
|
272
|
-
// HACK: putting call to the end of the event loop so the next component has a
|
|
282
|
+
// HACK: putting call to the end of the event loop so the next component has a chance to be registered
|
|
273
283
|
setTimeout(() => {
|
|
274
284
|
FocusManager.instance.setFocus(nextFocus, {
|
|
275
285
|
direction: "down",
|
package/focusManager/Tree.ts
CHANGED
|
@@ -8,37 +8,41 @@ export class Tree {
|
|
|
8
8
|
this.tree = focusManagerTree;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
add(
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
add(
|
|
12
|
+
touchableRef: FocusManager.TouchableReactRef,
|
|
13
|
+
parentFocusableRef: FocusManager.TouchableReactRef,
|
|
14
|
+
isFocusableCell: boolean,
|
|
15
|
+
parentFocusableId: string
|
|
16
|
+
) {
|
|
17
|
+
const focusableId = getFocusableId(touchableRef);
|
|
18
|
+
const parentId = getFocusableId(parentFocusableRef) || parentFocusableId;
|
|
14
19
|
const focusableComponentInTree = this.find(focusableId);
|
|
15
20
|
|
|
16
21
|
// update node if it already exists
|
|
17
22
|
if (focusableComponentInTree) {
|
|
18
|
-
focusableComponentInTree.updateNode(
|
|
23
|
+
focusableComponentInTree.updateNode(touchableRef);
|
|
19
24
|
}
|
|
20
25
|
|
|
21
|
-
if (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
if (!this.find(parentId)) {
|
|
27
|
+
// create temporary node to the root of the tree
|
|
28
|
+
this.tree.push(new TreeNode(null, parentId, null, isFocusableCell));
|
|
29
|
+
}
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
const parentNode = this.find(parentId);
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
if (parentNode) {
|
|
34
|
+
if (focusableComponentInTree) {
|
|
35
|
+
focusableComponentInTree.isFocusableCell = isFocusableCell;
|
|
36
|
+
focusableComponentInTree.parentId = parentNode.id;
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
parentNode.addChild(focusableComponentInTree);
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
40
|
+
// remove root object from the list
|
|
41
|
+
this.tree = this.tree.filter(
|
|
42
|
+
(node) => node !== focusableComponentInTree
|
|
43
|
+
);
|
|
44
|
+
} else {
|
|
45
|
+
parentNode.addChild(touchableRef, focusableId, isFocusableCell);
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { focusManager } from "../FocusManager";
|
|
2
2
|
|
|
3
|
+
const isFocusableCell = true;
|
|
4
|
+
const parentFocusableId = "parentFocusableId";
|
|
5
|
+
|
|
3
6
|
const group = {
|
|
4
7
|
current: {
|
|
5
8
|
props: {
|
|
@@ -62,13 +65,47 @@ jest.useFakeTimers();
|
|
|
62
65
|
|
|
63
66
|
describe("FocusManager", () => {
|
|
64
67
|
beforeAll(() => {
|
|
65
|
-
focusManager.registerFocusable(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
focusManager.registerFocusable({
|
|
69
|
+
touchableRef: group,
|
|
70
|
+
parentFocusableRef: { current: null },
|
|
71
|
+
isFocusableCell,
|
|
72
|
+
parentFocusableId,
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
focusManager.registerFocusable({
|
|
76
|
+
touchableRef: child1,
|
|
77
|
+
parentFocusableRef: group,
|
|
78
|
+
isFocusableCell,
|
|
79
|
+
parentFocusableId,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
focusManager.registerFocusable({
|
|
83
|
+
touchableRef: child2,
|
|
84
|
+
parentFocusableRef: group,
|
|
85
|
+
isFocusableCell,
|
|
86
|
+
parentFocusableId,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
focusManager.registerFocusable({
|
|
90
|
+
touchableRef: child3,
|
|
91
|
+
parentFocusableRef: child2,
|
|
92
|
+
isFocusableCell,
|
|
93
|
+
parentFocusableId,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
focusManager.registerFocusable({
|
|
97
|
+
touchableRef: child4,
|
|
98
|
+
parentFocusableRef: child2,
|
|
99
|
+
isFocusableCell,
|
|
100
|
+
parentFocusableId,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
focusManager.registerFocusable({
|
|
104
|
+
touchableRef: child5,
|
|
105
|
+
parentFocusableRef: child2,
|
|
106
|
+
isFocusableCell,
|
|
107
|
+
parentFocusableId,
|
|
108
|
+
});
|
|
72
109
|
});
|
|
73
110
|
|
|
74
111
|
it("focusManager should be defined", () => {
|
|
@@ -199,7 +236,12 @@ describe("FocusManager", () => {
|
|
|
199
236
|
});
|
|
200
237
|
|
|
201
238
|
it("focusManager registerFocusable should register", () => {
|
|
202
|
-
focusManager.registerFocusable(
|
|
239
|
+
focusManager.registerFocusable({
|
|
240
|
+
touchableRef: child5,
|
|
241
|
+
parentFocusableRef: child2,
|
|
242
|
+
isFocusableCell,
|
|
243
|
+
parentFocusableId,
|
|
244
|
+
});
|
|
203
245
|
|
|
204
246
|
expect(
|
|
205
247
|
focusManager.isFocusableChildOf(child5.current.props.id, child2)
|
package/index.d.ts
CHANGED
|
@@ -137,12 +137,3 @@ declare type AccessibilityState = {
|
|
|
137
137
|
reduceMotionEnabled: boolean;
|
|
138
138
|
boldTextEnabled: boolean;
|
|
139
139
|
};
|
|
140
|
-
|
|
141
|
-
declare type AccessibilityProps = {
|
|
142
|
-
accessibilityLabel?: string;
|
|
143
|
-
accessibilityHint?: string;
|
|
144
|
-
"aria-label"?: string;
|
|
145
|
-
"aria-description"?: string;
|
|
146
|
-
accessibilityRole?: string;
|
|
147
|
-
"aria-role"?: string;
|
|
148
|
-
};
|
|
@@ -2985,6 +2985,14 @@ function getPlayerConfiguration({ platform, version }) {
|
|
|
2985
2985
|
type: "uploader",
|
|
2986
2986
|
default: "",
|
|
2987
2987
|
},
|
|
2988
|
+
{
|
|
2989
|
+
key: "audio_player_background_image_overlay",
|
|
2990
|
+
label: "Background Image Overlay",
|
|
2991
|
+
label_tooltip:
|
|
2992
|
+
"Add a semi-transparent color overlay to improve text readability over the background image.",
|
|
2993
|
+
type: "color_picker_rgba",
|
|
2994
|
+
initial_value: "rgba(17, 17, 17, 0.5)",
|
|
2995
|
+
},
|
|
2988
2996
|
{
|
|
2989
2997
|
type: "text_input",
|
|
2990
2998
|
label: "Item Image Key",
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { mapContentTypesToRivers } from "../index";
|
|
2
|
+
|
|
3
|
+
describe("mapContentTypesToRivers", () => {
|
|
4
|
+
it("should return the correct content types mapped to rivers", () => {
|
|
5
|
+
const state = {
|
|
6
|
+
rivers: {
|
|
7
|
+
"river-1": {
|
|
8
|
+
plugin_type: "river",
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
contentTypes: {
|
|
12
|
+
"content-type-1": {
|
|
13
|
+
screen_id: "river-1",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const result = mapContentTypesToRivers(state);
|
|
19
|
+
|
|
20
|
+
expect(result).toEqual({
|
|
21
|
+
"content-type-1": {
|
|
22
|
+
screenType: "river",
|
|
23
|
+
screen_id: "river-1",
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return null if contentTypes is undefined", () => {
|
|
29
|
+
const state = {
|
|
30
|
+
rivers: {
|
|
31
|
+
"river-1": {
|
|
32
|
+
plugin_type: "river",
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
// contentTypes is missing
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const result = mapContentTypesToRivers(state);
|
|
39
|
+
|
|
40
|
+
expect(result).toBeNull();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("should skip content types whose screen does not exist in rivers", () => {
|
|
44
|
+
const state = {
|
|
45
|
+
rivers: {
|
|
46
|
+
"river-1": {
|
|
47
|
+
plugin_type: "river",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
contentTypes: {
|
|
51
|
+
"content-type-1": {
|
|
52
|
+
screen_id: "river-1",
|
|
53
|
+
},
|
|
54
|
+
"content-type-2": {
|
|
55
|
+
screen_id: "river-2", // river-2 does not exist
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const result = mapContentTypesToRivers(state);
|
|
61
|
+
|
|
62
|
+
expect(result).toEqual({
|
|
63
|
+
"content-type-1": {
|
|
64
|
+
screenType: "river",
|
|
65
|
+
screen_id: "river-1",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// result is not null, but may be undefined for missing keys
|
|
70
|
+
expect(result && result["content-type-2"]).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("should use 'type' if 'plugin_type' is not present in river", () => {
|
|
74
|
+
const state = {
|
|
75
|
+
rivers: {
|
|
76
|
+
"river-1": {
|
|
77
|
+
type: "custom-type",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
contentTypes: {
|
|
81
|
+
"content-type-1": {
|
|
82
|
+
screen_id: "river-1",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const result = mapContentTypesToRivers(state);
|
|
88
|
+
|
|
89
|
+
expect(result).toEqual({
|
|
90
|
+
"content-type-1": {
|
|
91
|
+
screenType: "custom-type",
|
|
92
|
+
screen_id: "river-1",
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should skip content types if neither plugin_type nor type is present in river", () => {
|
|
98
|
+
const state = {
|
|
99
|
+
rivers: {
|
|
100
|
+
"river-1": {
|
|
101
|
+
// no plugin_type or type
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
contentTypes: {
|
|
105
|
+
"content-type-1": {
|
|
106
|
+
screen_id: "river-1",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const result = mapContentTypesToRivers(state);
|
|
112
|
+
|
|
113
|
+
expect(result).toEqual({});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should handle empty contentTypes object", () => {
|
|
117
|
+
const state = {
|
|
118
|
+
rivers: {
|
|
119
|
+
"river-1": {
|
|
120
|
+
plugin_type: "river",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
contentTypes: {},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const result = mapContentTypesToRivers(state);
|
|
127
|
+
|
|
128
|
+
expect(result).toEqual({});
|
|
129
|
+
});
|
|
130
|
+
});
|
package/navigationUtils/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
isPlayable,
|
|
14
14
|
isV2River,
|
|
15
15
|
} from "./itemTypeMatchers";
|
|
16
|
+
import { RootState } from "@applicaster/zapp-react-native-redux/store";
|
|
16
17
|
|
|
17
18
|
type PathAttribute = {
|
|
18
19
|
screenType: string;
|
|
@@ -377,10 +378,11 @@ export const usesVideoModal = (
|
|
|
377
378
|
return targetScreenConfiguration?.styles?.use_video_modal;
|
|
378
379
|
};
|
|
379
380
|
|
|
380
|
-
export const mapContentTypesToRivers = (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
381
|
+
export const mapContentTypesToRivers = (
|
|
382
|
+
state: Partial<RootState>
|
|
383
|
+
): ZappContentTypesMapped | null => {
|
|
384
|
+
const { rivers, contentTypes } = state;
|
|
385
|
+
|
|
384
386
|
if (!contentTypes) {
|
|
385
387
|
return null;
|
|
386
388
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-utils",
|
|
3
|
-
"version": "14.0.0-alpha.
|
|
3
|
+
"version": "14.0.0-alpha.4385101226",
|
|
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": "14.0.0-alpha.
|
|
30
|
+
"@applicaster/applicaster-types": "14.0.0-alpha.4385101226",
|
|
31
31
|
"buffer": "^5.2.1",
|
|
32
32
|
"camelize": "^1.0.0",
|
|
33
33
|
"dayjs": "^1.11.10",
|
|
@@ -38,7 +38,6 @@
|
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"@applicaster/zapp-pipes-v2-client": "*",
|
|
40
40
|
"@react-native-community/netinfo": "*",
|
|
41
|
-
"immer": "*",
|
|
42
41
|
"react": "*",
|
|
43
42
|
"react-native": "*",
|
|
44
43
|
"uglify-js": "*",
|
package/playerUtils/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { isFilledArray } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
|
5
5
|
import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
6
6
|
|
|
7
7
|
import { getBoolFromConfigValue } from "../configurationUtils";
|
|
8
|
+
import { Dimensions } from "react-native";
|
|
8
9
|
|
|
9
10
|
export { getPlayerActionButtons } from "./getPlayerActionButtons";
|
|
10
11
|
|
|
@@ -97,3 +98,53 @@ export const isAudioItem = (item: Option<ZappEntry>) => {
|
|
|
97
98
|
export const isInlineTV = (screenData) => {
|
|
98
99
|
return isTV() && isFilledArray(screenData?.ui_components);
|
|
99
100
|
};
|
|
101
|
+
|
|
102
|
+
const isPercentage = (value: string | number): boolean => {
|
|
103
|
+
if (typeof value === "string") {
|
|
104
|
+
return value.includes("%");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return false;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getPercentageOf = (percent: string, value: number) => {
|
|
111
|
+
const percentageValue = parseFloat(percent.replace("%", ""));
|
|
112
|
+
|
|
113
|
+
if (isNaN(percentageValue)) {
|
|
114
|
+
return value;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return (value * percentageValue) / 100;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
type DimensionsT = {
|
|
121
|
+
width: number | string;
|
|
122
|
+
height: number | string | undefined;
|
|
123
|
+
aspectRatio?: number;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export const getTabletWidth = (
|
|
127
|
+
tablet_landscape_sidebar_width,
|
|
128
|
+
dimensions: DimensionsT
|
|
129
|
+
) => {
|
|
130
|
+
const { width: SCREEN_WIDTH } = Dimensions.get("screen");
|
|
131
|
+
|
|
132
|
+
const { width } = dimensions;
|
|
133
|
+
let widthValue = Number(width);
|
|
134
|
+
|
|
135
|
+
if (isPercentage(width)) {
|
|
136
|
+
widthValue = getPercentageOf(width.toString(), SCREEN_WIDTH);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const sidebarWidth = Number(tablet_landscape_sidebar_width?.replace("%", ""));
|
|
140
|
+
|
|
141
|
+
if (tablet_landscape_sidebar_width?.includes("%")) {
|
|
142
|
+
return widthValue * (1 - sidebarWidth / 100);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (Number.isNaN(sidebarWidth)) {
|
|
146
|
+
return widthValue * 0.65;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return widthValue - sidebarWidth;
|
|
150
|
+
};
|
|
@@ -23,7 +23,9 @@ jest.mock(
|
|
|
23
23
|
|
|
24
24
|
jest.useFakeTimers();
|
|
25
25
|
|
|
26
|
-
jest.mock(
|
|
26
|
+
jest.mock(
|
|
27
|
+
"@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation"
|
|
28
|
+
);
|
|
27
29
|
|
|
28
30
|
const mockStore = configureStore();
|
|
29
31
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { complement, compose, isNil, map, min, prop, take, uniq } from "ramda";
|
|
2
|
-
import { useDispatch } from "react-redux";
|
|
3
2
|
import * as React from "react";
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
ZappPipes,
|
|
5
|
+
useAppDispatch,
|
|
6
|
+
useZappPipesFeed,
|
|
7
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
6
8
|
import { isNilOrEmpty } from "../../reactUtils/helpers";
|
|
7
9
|
import { ZappPipesSearchContext } from "@applicaster/zapp-react-native-ui-components/Contexts";
|
|
8
10
|
import {
|
|
@@ -10,7 +12,7 @@ import {
|
|
|
10
12
|
getSearchContext,
|
|
11
13
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
12
14
|
import { isGallery } from "@applicaster/zapp-react-native-utils/componentsUtils";
|
|
13
|
-
import { useScreenContext } from "../screen
|
|
15
|
+
import { useScreenContext } from "../screen";
|
|
14
16
|
|
|
15
17
|
type Options = {
|
|
16
18
|
initialBatchSize?: number;
|
|
@@ -63,7 +65,7 @@ export const useBatchLoading = (
|
|
|
63
65
|
componentsToRender: { data?: ZappDataSource; component_type: string }[],
|
|
64
66
|
options: Options
|
|
65
67
|
) => {
|
|
66
|
-
const dispatch =
|
|
68
|
+
const dispatch = useAppDispatch();
|
|
67
69
|
const { screen: screenContext, entry: entryContext } = useScreenContext();
|
|
68
70
|
const [searchContext] = ZappPipesSearchContext.useZappPipesContext();
|
|
69
71
|
const [hasEverBeenReady, setHasEverBeenReady] = React.useState(false);
|
|
@@ -118,7 +120,7 @@ export const useBatchLoading = (
|
|
|
118
120
|
[]
|
|
119
121
|
);
|
|
120
122
|
|
|
121
|
-
const feeds =
|
|
123
|
+
const feeds = useZappPipesFeed(feedUrls);
|
|
122
124
|
|
|
123
125
|
// dispatch loadPipesData for each feed that is not loaded
|
|
124
126
|
const runBatchLoading = React.useCallback(() => {
|
|
@@ -139,7 +141,7 @@ export const useBatchLoading = (
|
|
|
139
141
|
if (mappedFeedUrl) {
|
|
140
142
|
// 4. load data
|
|
141
143
|
return dispatch(
|
|
142
|
-
loadPipesData(mappedFeedUrl, { riverId: options.riverId })
|
|
144
|
+
ZappPipes.loadPipesData(mappedFeedUrl, { riverId: options.riverId })
|
|
143
145
|
);
|
|
144
146
|
}
|
|
145
147
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import React, { useEffect } from "react";
|
|
2
|
-
import { useDispatch } from "react-redux";
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import {
|
|
4
|
+
ZappPipes,
|
|
5
|
+
useAppDispatch,
|
|
6
|
+
useZappPipesFeed,
|
|
7
|
+
} from "@applicaster/zapp-react-native-redux";
|
|
6
8
|
|
|
7
9
|
import { reactHooksLogger } from "../logger";
|
|
8
10
|
import { shouldDispatchData, useIsInitialRender } from "../utils";
|
|
@@ -49,7 +51,7 @@ export const useFeedLoader = ({
|
|
|
49
51
|
}, []);
|
|
50
52
|
|
|
51
53
|
const isInitialRender = useIsInitialRender();
|
|
52
|
-
const dispatch =
|
|
54
|
+
const dispatch = useAppDispatch();
|
|
53
55
|
const { screenData } = useRoute();
|
|
54
56
|
|
|
55
57
|
const callableFeedUrl = useInflatedUrl({ feedUrl, mapping });
|
|
@@ -64,7 +66,7 @@ export const useFeedLoader = ({
|
|
|
64
66
|
(silentRefresh = true, callback) => {
|
|
65
67
|
if (callableFeedUrl) {
|
|
66
68
|
dispatch(
|
|
67
|
-
loadPipesData(callableFeedUrl, {
|
|
69
|
+
ZappPipes.loadPipesData(callableFeedUrl, {
|
|
68
70
|
clearCache: true,
|
|
69
71
|
silentRefresh,
|
|
70
72
|
callback,
|
|
@@ -82,7 +84,7 @@ export const useFeedLoader = ({
|
|
|
82
84
|
|
|
83
85
|
if (nextFeed) {
|
|
84
86
|
dispatch(
|
|
85
|
-
loadPipesData(nextFeed, {
|
|
87
|
+
ZappPipes.loadPipesData(nextFeed, {
|
|
86
88
|
silentRefresh: true,
|
|
87
89
|
parentFeed: callableFeedUrl,
|
|
88
90
|
riverId,
|
|
@@ -98,7 +100,7 @@ export const useFeedLoader = ({
|
|
|
98
100
|
) {
|
|
99
101
|
if (callableFeedUrl && !pipesOptions.skipLoading) {
|
|
100
102
|
dispatch(
|
|
101
|
-
loadPipesData(callableFeedUrl, {
|
|
103
|
+
ZappPipes.loadPipesData(callableFeedUrl, {
|
|
102
104
|
...pipesOptions,
|
|
103
105
|
clearCache: true,
|
|
104
106
|
riverId,
|
|
@@ -131,7 +133,9 @@ export const useFeedLoader = ({
|
|
|
131
133
|
// Reload feed when feedUrl changes, unless skipLoading is true
|
|
132
134
|
useEffect(() => {
|
|
133
135
|
if (!isInitialRender && callableFeedUrl && !pipesOptions.skipLoading) {
|
|
134
|
-
dispatch(
|
|
136
|
+
dispatch(
|
|
137
|
+
ZappPipes.loadPipesData(callableFeedUrl, { ...pipesOptions, riverId })
|
|
138
|
+
);
|
|
135
139
|
}
|
|
136
140
|
}, [callableFeedUrl]);
|
|
137
141
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { useDispatch } from "react-redux";
|
|
3
2
|
|
|
4
3
|
import { getDatasourceUrl } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/getDatasourceUrl";
|
|
5
4
|
import { usePipesContexts } from "@applicaster/zapp-react-native-ui-components/Decorators/RiverFeedLoader/utils/usePipesContexts";
|
|
6
5
|
import { clearPipesData } from "@applicaster/zapp-react-native-redux/ZappPipes";
|
|
7
6
|
|
|
8
|
-
import { useRoute } from "../navigation
|
|
7
|
+
import { useRoute } from "../navigation";
|
|
8
|
+
import { useAppDispatch } from "@applicaster/zapp-react-native-redux";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* reset river components cache when screen is unmounted
|
|
@@ -13,7 +13,7 @@ import { useRoute } from "../navigation/useRoute";
|
|
|
13
13
|
* @param {Array} riverComponents list of UI components
|
|
14
14
|
*/
|
|
15
15
|
export const usePipesCacheReset = (riverId, riverComponents) => {
|
|
16
|
-
const dispatch =
|
|
16
|
+
const dispatch = useAppDispatch();
|
|
17
17
|
const { screenData, pathname } = useRoute();
|
|
18
18
|
const pipesContexts = usePipesContexts(riverId, pathname);
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { View } from "react-native";
|
|
3
|
+
import { View, ViewStyle } from "react-native";
|
|
4
4
|
|
|
5
5
|
import { platformSelect } from "../../reactUtils";
|
|
6
6
|
|
|
@@ -49,13 +49,13 @@ export const useSequentialRenderItem = (data: Data) => {
|
|
|
49
49
|
const readyToDisplay =
|
|
50
50
|
index === 0 ? true : arePreviousComponentsReady(index);
|
|
51
51
|
|
|
52
|
-
const displayStyle = {
|
|
52
|
+
const displayStyle: ViewStyle = {
|
|
53
53
|
display: readyToDisplay ? "flex" : "none",
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
const readyStyle = {
|
|
57
57
|
visibility: readyToDisplay ? "visible" : "hidden",
|
|
58
|
-
};
|
|
58
|
+
} as ViewStyle;
|
|
59
59
|
|
|
60
60
|
const style = platformSelect({
|
|
61
61
|
tvos: readyStyle,
|
|
@@ -42,15 +42,17 @@ jest.mock("react-native-safe-area-context", () => ({
|
|
|
42
42
|
}));
|
|
43
43
|
|
|
44
44
|
jest.mock("../../../reactUtils", () => ({
|
|
45
|
+
...jest.requireActual("../../../reactUtils"),
|
|
45
46
|
platformSelect: jest.fn((specs) => specs[platform] || specs.default),
|
|
46
47
|
isTV: jest.fn(() => mock_tv_flag),
|
|
47
48
|
}));
|
|
48
49
|
|
|
49
50
|
jest.mock("../../navigation", () => ({
|
|
50
|
-
useNavigation: () => null,
|
|
51
51
|
useIsScreenActive: () => true,
|
|
52
52
|
}));
|
|
53
53
|
|
|
54
|
+
jest.mock("../../navigation/useNavigation");
|
|
55
|
+
|
|
54
56
|
const { Dimensions } = require("react-native");
|
|
55
57
|
const { useDimensions } = require("..");
|
|
56
58
|
|