@applicaster/zapp-react-native-ui-components 11.0.0-rc.99 → 12.0.0-alpha.5643066061
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 +1 -1
- package/Components/Cell/Cell.tsx +5 -13
- package/Components/Cell/{CellWithFocusable.js → CellWithFocusable.tsx} +13 -11
- package/Components/Cell/TvOSCellComponent.tsx +12 -10
- package/Components/FastImage/index.ios.js +3 -0
- package/Components/Focusable/FocusableTvOS.tsx +4 -1
- package/Components/FocusableCell/{index.js → index.tsx} +8 -5
- package/Components/FocusableGroup/FocusableTvOS.tsx +2 -2
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +13 -8
- package/Components/HandlePlayable/HandlePlayable.tsx +2 -2
- package/Components/HookRenderer/HookRenderer.tsx +9 -6
- package/Components/Layout/TV/__tests__/__snapshots__/index.test.tsx.snap +1 -1
- package/Components/Layout/TV/index.tsx +9 -13
- package/Components/Layout/index.tsx +9 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +3 -1
- package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +22 -19
- package/Components/MasterCell/DefaultComponents/SecondaryImage/Image.tsx +1 -0
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/Image.test.tsx +4 -1
- package/Components/MasterCell/DefaultComponents/SecondaryImage/__tests__/__snapshots__/Image.test.tsx.snap +2 -0
- package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -3
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/CollapsibleTextContainer.tsx +9 -3
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/__snapshots__/index.test.tsx.snap +7 -1
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/__tests__/index.test.tsx +12 -4
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +23 -9
- package/Components/MasterCell/hoc/withAsyncRender.tsx +8 -4
- package/Components/MasterCell/hooks/useAsyncRendering/MasterCellAsyncRenderManager.ts +12 -6
- package/Components/MasterCell/hooks/useAsyncRendering/__tests__/MasterCellAsyncRenderManager.test.ts +21 -0
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +15 -13
- package/Components/MasterCell/utils/index.ts +143 -19
- package/Components/PlayerContainer/PlayerContainer.tsx +10 -6
- package/Components/River/ComponentsMap/ComponentsMap.tsx +4 -1
- package/Components/River/River.tsx +3 -4
- package/Components/River/TV/River.tsx +9 -4
- package/Components/River/__tests__/__snapshots__/componentsMap.test.js.snap +1 -0
- package/Components/River/index.tsx +3 -1
- package/Components/Screen/__tests__/Screen.test.tsx +6 -3
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
- package/Components/Screen/index.tsx +12 -44
- package/Components/Screen/navigationHandler.ts +1 -1
- package/Components/Spinner/SpinnerComponent.tsx +6 -2
- package/Components/VideoLive/LiveImageManager.ts +24 -9
- package/Components/VideoLive/PlayerLiveImageComponent.tsx +23 -1
- package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +74 -0
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +47 -0
- package/Components/VideoLive/__tests__/utils.test.ts +109 -0
- package/Components/VideoLive/utils.ts +40 -0
- package/Components/VideoModal/PlayerDetails.tsx +42 -6
- package/Components/VideoModal/PlayerWrapper.tsx +32 -29
- package/Components/VideoModal/VideoModal.tsx +20 -17
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +21 -9
- package/Components/VideoModal/__tests__/__snapshots__/PlayerDetails.test.tsx.snap +14 -24
- package/Contexts/InteractionManagerContext/index.ts +0 -2
- package/Contexts/ScreenContext/index.tsx +118 -0
- package/package.json +5 -5
package/Components/MasterCell/SharedUI/CollapsibleTextContainer/CollapsibleTextContainer.tsx
CHANGED
|
@@ -5,14 +5,20 @@ import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/he
|
|
|
5
5
|
|
|
6
6
|
type Props = {
|
|
7
7
|
style: ViewStyle;
|
|
8
|
-
label
|
|
8
|
+
label?: string;
|
|
9
9
|
children: React.ReactChild;
|
|
10
|
+
backgroundColor?: string;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export const CollapsibleTextContainer = ({
|
|
13
|
+
export const CollapsibleTextContainer = ({
|
|
14
|
+
children,
|
|
15
|
+
style,
|
|
16
|
+
label,
|
|
17
|
+
backgroundColor,
|
|
18
|
+
}: Props) => {
|
|
13
19
|
if (isNilOrEmpty(label)) {
|
|
14
20
|
return null;
|
|
15
21
|
}
|
|
16
22
|
|
|
17
|
-
return <View style={style}>{children}</View>;
|
|
23
|
+
return <View style={{ ...style, backgroundColor }}>{children}</View>;
|
|
18
24
|
};
|
|
@@ -7,7 +7,11 @@ import { CollapsibleTextContainer } from "../CollapsibleTextContainer";
|
|
|
7
7
|
describe("CollapsibleTextContainer", () => {
|
|
8
8
|
it("render container+children when label is presented", () => {
|
|
9
9
|
const renderer = ReactTestRenderer.create(
|
|
10
|
-
<CollapsibleTextContainer
|
|
10
|
+
<CollapsibleTextContainer
|
|
11
|
+
backgroundColor="#000000"
|
|
12
|
+
label={"label"}
|
|
13
|
+
style={{}}
|
|
14
|
+
>
|
|
11
15
|
<View />
|
|
12
16
|
</CollapsibleTextContainer>
|
|
13
17
|
);
|
|
@@ -20,7 +24,7 @@ describe("CollapsibleTextContainer", () => {
|
|
|
20
24
|
|
|
21
25
|
it("render nothing when label is empty", () => {
|
|
22
26
|
const renderer = ReactTestRenderer.create(
|
|
23
|
-
<CollapsibleTextContainer label={""}>
|
|
27
|
+
<CollapsibleTextContainer backgroundColor="#000000" label={""} style={{}}>
|
|
24
28
|
<View />
|
|
25
29
|
</CollapsibleTextContainer>
|
|
26
30
|
);
|
|
@@ -31,7 +35,7 @@ describe("CollapsibleTextContainer", () => {
|
|
|
31
35
|
|
|
32
36
|
it("render nothing when label is not passed", () => {
|
|
33
37
|
const renderer = ReactTestRenderer.create(
|
|
34
|
-
<CollapsibleTextContainer>
|
|
38
|
+
<CollapsibleTextContainer backgroundColor="#000000" label={""} style={{}}>
|
|
35
39
|
<View />
|
|
36
40
|
</CollapsibleTextContainer>
|
|
37
41
|
);
|
|
@@ -42,7 +46,11 @@ describe("CollapsibleTextContainer", () => {
|
|
|
42
46
|
|
|
43
47
|
it("render nothing when label is undefined", () => {
|
|
44
48
|
const renderer = ReactTestRenderer.create(
|
|
45
|
-
<CollapsibleTextContainer
|
|
49
|
+
<CollapsibleTextContainer
|
|
50
|
+
backgroundColor="#000000"
|
|
51
|
+
label={undefined}
|
|
52
|
+
style={{}}
|
|
53
|
+
>
|
|
46
54
|
<View />
|
|
47
55
|
</CollapsibleTextContainer>
|
|
48
56
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { path } from "ramda";
|
|
1
|
+
import { path, pathOr } from "ramda";
|
|
2
2
|
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
3
3
|
import {
|
|
4
4
|
getKeyForLabel,
|
|
@@ -34,17 +34,31 @@ export const CollapsibleTextContainer = ({
|
|
|
34
34
|
borderRadius: toNumberWithDefaultZero(getValue("corner_radius")),
|
|
35
35
|
...additionalStyles,
|
|
36
36
|
},
|
|
37
|
-
data:
|
|
37
|
+
data: [
|
|
38
|
+
...(customData || [
|
|
39
|
+
{
|
|
40
|
+
func: (data, args) =>
|
|
41
|
+
isNilOrEmpty(args) ? undefined : path(args, data),
|
|
42
|
+
args: getKeyForLabel(
|
|
43
|
+
getValue("data_key"),
|
|
44
|
+
getValue("custom_data_key")
|
|
45
|
+
),
|
|
46
|
+
propName: "label",
|
|
47
|
+
},
|
|
48
|
+
]),
|
|
38
49
|
{
|
|
39
|
-
func: (data
|
|
40
|
-
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
50
|
+
func: (data) => {
|
|
51
|
+
const value = getValue("background_color");
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
// check if value is a reference to an extension
|
|
54
|
+
if (value.startsWith("extensions")) {
|
|
55
|
+
return pathOr(value, value.split("."), data);
|
|
56
|
+
} else {
|
|
57
|
+
// return default value
|
|
58
|
+
return additionalStyles.backgroundColor;
|
|
59
|
+
}
|
|
45
60
|
},
|
|
46
|
-
|
|
47
|
-
propName: "label",
|
|
61
|
+
propName: "backgroundColor",
|
|
48
62
|
},
|
|
49
63
|
],
|
|
50
64
|
elements,
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
3
3
|
|
|
4
4
|
type withAsyncRenderHOCProps = {
|
|
5
|
-
emitAsyncElementRegistrate?: () => void;
|
|
5
|
+
emitAsyncElementRegistrate?: () => (() => void) | void;
|
|
6
6
|
emitAsyncElementLayout?: () => void;
|
|
7
7
|
};
|
|
8
8
|
|
|
@@ -15,12 +15,16 @@ export const withAsyncRenderHOC: withAsyncRenderHOCT = (Component) => {
|
|
|
15
15
|
const { emitAsyncElementRegistrate = noop, emitAsyncElementLayout = noop } =
|
|
16
16
|
props;
|
|
17
17
|
|
|
18
|
-
React.
|
|
19
|
-
emitAsyncElementRegistrate
|
|
18
|
+
React.useEffect(() => {
|
|
19
|
+
if (props.emitAsyncElementRegistrate) {
|
|
20
|
+
return emitAsyncElementRegistrate();
|
|
21
|
+
}
|
|
20
22
|
}, []);
|
|
21
23
|
|
|
22
24
|
const onAsyncRender = React.useCallback(() => {
|
|
23
|
-
emitAsyncElementLayout
|
|
25
|
+
if (props.emitAsyncElementLayout) {
|
|
26
|
+
emitAsyncElementLayout();
|
|
27
|
+
}
|
|
24
28
|
}, [emitAsyncElementLayout]);
|
|
25
29
|
|
|
26
30
|
return <Component {...props} onAsyncRender={onAsyncRender} />;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { ReplaySubject } from "rxjs";
|
|
2
2
|
import { map } from "rxjs/operators";
|
|
3
3
|
|
|
4
|
-
const subjectBuilder = () => new ReplaySubject();
|
|
5
|
-
|
|
6
4
|
export class MasterCellAsyncRenderManager {
|
|
7
|
-
readonly asyncElementRegistrate$:
|
|
8
|
-
readonly asyncElementLayout$:
|
|
5
|
+
readonly asyncElementRegistrate$: ReplaySubject<any>;
|
|
6
|
+
readonly asyncElementLayout$: ReplaySubject<any>;
|
|
9
7
|
private asyncElementRegistrationCount: number;
|
|
10
8
|
readonly notifyAllAsyncElementsRendered: () => void;
|
|
11
9
|
|
|
12
10
|
constructor(notifyAllAsyncElementsRendered: () => void) {
|
|
13
|
-
this.asyncElementRegistrate$ =
|
|
14
|
-
this.asyncElementLayout$ =
|
|
11
|
+
this.asyncElementRegistrate$ = new ReplaySubject();
|
|
12
|
+
this.asyncElementLayout$ = new ReplaySubject();
|
|
15
13
|
this.asyncElementRegistrationCount = 0;
|
|
16
14
|
|
|
17
15
|
this.notifyAllAsyncElementsRendered = notifyAllAsyncElementsRendered;
|
|
@@ -19,12 +17,20 @@ export class MasterCellAsyncRenderManager {
|
|
|
19
17
|
|
|
20
18
|
public emitAsyncElementRegistrate = () => {
|
|
21
19
|
this.asyncElementRegistrate$.next();
|
|
20
|
+
|
|
21
|
+
return this.decrementAsyncElementRegistrationCount;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
public emitAsyncElementLayout = () => {
|
|
25
25
|
this.asyncElementLayout$.next();
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
public decrementAsyncElementRegistrationCount = () => {
|
|
29
|
+
if (this.asyncElementRegistrationCount > 0) {
|
|
30
|
+
this.asyncElementRegistrationCount -= 1;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
28
34
|
public onCellLayout = () => {
|
|
29
35
|
if (this.asyncElementRegistrationCount === 0) {
|
|
30
36
|
// cell was rendered but no async registrations were occured
|
package/Components/MasterCell/hooks/useAsyncRendering/__tests__/MasterCellAsyncRenderManager.test.ts
CHANGED
|
@@ -55,4 +55,25 @@ describe("MasterCellAsyncRenderManager", () => {
|
|
|
55
55
|
|
|
56
56
|
expect(callback).toBeCalled();
|
|
57
57
|
});
|
|
58
|
+
|
|
59
|
+
it("should return decrementAsyncElementRegistrationCount, call decrementAsyncElementRegistrationCount should decrement count", () => {
|
|
60
|
+
// setup
|
|
61
|
+
const callback = jest.fn();
|
|
62
|
+
const manager = new MasterCellAsyncRenderManager(callback);
|
|
63
|
+
|
|
64
|
+
// run
|
|
65
|
+
manager.start();
|
|
66
|
+
|
|
67
|
+
// verify
|
|
68
|
+
expect(callback).not.toBeCalled();
|
|
69
|
+
|
|
70
|
+
const unsubscribe = manager.emitAsyncElementRegistrate();
|
|
71
|
+
|
|
72
|
+
expect(manager.asyncElementRegistrationCount).toBe(1);
|
|
73
|
+
expect(unsubscribe).toBe(manager.decrementAsyncElementRegistrationCount);
|
|
74
|
+
|
|
75
|
+
unsubscribe();
|
|
76
|
+
|
|
77
|
+
expect(manager.asyncElementRegistrationCount).toBe(0);
|
|
78
|
+
});
|
|
58
79
|
});
|
|
@@ -48,18 +48,16 @@ const initialDimensions = () => ({
|
|
|
48
48
|
export const useAsyncRendering = (viewRef: React.RefObject<View>): Return => {
|
|
49
49
|
const [dimensions, setDimensions] = React.useState(initialDimensions());
|
|
50
50
|
|
|
51
|
-
const managerRef = React.useRef(
|
|
52
|
-
|
|
53
|
-
if (!managerRef.current) {
|
|
54
|
-
managerRef.current = new MasterCellAsyncRenderManager(() => {
|
|
51
|
+
const managerRef = React.useRef(
|
|
52
|
+
new MasterCellAsyncRenderManager(() => {
|
|
55
53
|
measure(viewRef?.current, ({ width, height }) => {
|
|
56
54
|
setDimensions({
|
|
57
55
|
width,
|
|
58
56
|
height,
|
|
59
57
|
});
|
|
60
58
|
});
|
|
61
|
-
})
|
|
62
|
-
|
|
59
|
+
})
|
|
60
|
+
);
|
|
63
61
|
|
|
64
62
|
React.useEffect(() => {
|
|
65
63
|
return managerRef.current.start();
|
|
@@ -69,11 +67,15 @@ export const useAsyncRendering = (viewRef: React.RefObject<View>): Return => {
|
|
|
69
67
|
setDimensions(initialDimensions());
|
|
70
68
|
}, []);
|
|
71
69
|
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
return React.useMemo(
|
|
71
|
+
() => ({
|
|
72
|
+
emitAsyncElementRegistrate:
|
|
73
|
+
managerRef.current?.emitAsyncElementRegistrate,
|
|
74
|
+
emitAsyncElementLayout: managerRef.current.emitAsyncElementLayout,
|
|
75
|
+
dimensions,
|
|
76
|
+
onCellLayout: managerRef.current.onCellLayout,
|
|
77
|
+
resetDimensions,
|
|
78
|
+
}),
|
|
79
|
+
[dimensions, resetDimensions]
|
|
80
|
+
);
|
|
79
81
|
};
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import React, { useMemo } from "react";
|
|
1
|
+
import React, { useEffect, useMemo } from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
5
|
|
|
6
6
|
import { masterCellLogger } from "../logger";
|
|
7
|
+
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
8
|
+
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
9
|
+
import { PushTopicManager } from "@applicaster/zapp-react-native-bridge/PushNotifications/PushTopicManager";
|
|
10
|
+
import { StorageMultiSelectProvider } from "@applicaster/zapp-react-native-bridge/ZappStorage/StorageMultiSelectProvider";
|
|
11
|
+
import { getCellState } from "../../Cell/utils";
|
|
7
12
|
|
|
8
13
|
const hasElementSpecificViewType = (viewType) => (element) => {
|
|
9
14
|
if (R.isNil(element)) {
|
|
@@ -192,30 +197,149 @@ export const getFocusedButtonId = (focusable) => {
|
|
|
192
197
|
};
|
|
193
198
|
|
|
194
199
|
export const isSelected = (id: string | number, behavior?: Behavior) => {
|
|
195
|
-
if (behavior
|
|
200
|
+
if (!behavior) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (behavior?.selection_source === "now_playing") {
|
|
205
|
+
const player = playerManager.getActivePlayer();
|
|
206
|
+
|
|
207
|
+
if (player?.entry?.id === id) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (behavior?.select_mode === "single") {
|
|
196
213
|
return behavior.current_selection === id;
|
|
197
214
|
}
|
|
198
215
|
|
|
199
|
-
|
|
216
|
+
if (behavior?.select_mode === "multi") {
|
|
217
|
+
// TODO: Use generic resolver source
|
|
218
|
+
|
|
219
|
+
if (behavior.selection_source === "@{push/topics}") {
|
|
220
|
+
const tags = PushTopicManager.getInstance().getRegisteredTags();
|
|
221
|
+
|
|
222
|
+
return tags.includes(String(id));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (Array.isArray(behavior.current_selection)) {
|
|
226
|
+
return behavior.current_selection.includes(id);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const currentSelection = String(behavior.current_selection);
|
|
230
|
+
|
|
231
|
+
if (currentSelection?.startsWith("@{ctx/")) {
|
|
232
|
+
const keyWithoutCtx = currentSelection.substring(
|
|
233
|
+
"@{ctx/".length,
|
|
234
|
+
currentSelection.length - 1
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
const selectedItems =
|
|
238
|
+
StorageMultiSelectProvider.getProvider(
|
|
239
|
+
keyWithoutCtx
|
|
240
|
+
)?.getSelectedItems();
|
|
241
|
+
|
|
242
|
+
return selectedItems?.includes(String(id));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
200
246
|
return false;
|
|
201
247
|
};
|
|
202
248
|
|
|
203
|
-
export const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
:
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
249
|
+
export const useBehaviorUpdate = (behavior: Behavior) => {
|
|
250
|
+
const [lastUpdate, setLastUpdate] = React.useState(null);
|
|
251
|
+
|
|
252
|
+
const player = usePlayer();
|
|
253
|
+
|
|
254
|
+
const triggerUpdate = () => {
|
|
255
|
+
setLastUpdate(Date.now());
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// TODO: Create generic RX to state update
|
|
259
|
+
useEffect(() => {
|
|
260
|
+
// TODO: Use generic resolver source
|
|
261
|
+
if (!behavior) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const currentSelection = String(behavior.current_selection);
|
|
266
|
+
|
|
267
|
+
if (currentSelection?.startsWith("@{ctx/")) {
|
|
268
|
+
const keyWithoutCtx = currentSelection.substring(
|
|
269
|
+
"@{ctx/".length,
|
|
270
|
+
currentSelection.length - 1
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
if (keyWithoutCtx) {
|
|
274
|
+
const subscription = StorageMultiSelectProvider.getProvider(
|
|
275
|
+
keyWithoutCtx
|
|
276
|
+
)
|
|
277
|
+
.getObservable()
|
|
278
|
+
.subscribe(() => {
|
|
279
|
+
triggerUpdate();
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
return () => {
|
|
283
|
+
subscription.unsubscribe();
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}, [behavior]);
|
|
288
|
+
|
|
289
|
+
useEffect(() => {
|
|
290
|
+
if (!behavior) {
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (behavior?.selection_source === "@{push/topics}") {
|
|
295
|
+
const subscription = PushTopicManager.getInstance()
|
|
296
|
+
.getEntryObservable()
|
|
297
|
+
.subscribe(() => {
|
|
298
|
+
triggerUpdate();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
return () => {
|
|
302
|
+
subscription.unsubscribe();
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
}, [behavior]);
|
|
306
|
+
|
|
307
|
+
useEffect(() => {
|
|
308
|
+
if (!behavior) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (behavior?.selection_source === "now_playing" && player) {
|
|
313
|
+
const subscription = player.getEntryObservable().subscribe(() => {
|
|
314
|
+
triggerUpdate();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
return () => {
|
|
318
|
+
subscription.unsubscribe();
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}, [behavior, player]);
|
|
322
|
+
|
|
323
|
+
return lastUpdate;
|
|
324
|
+
};
|
|
325
|
+
|
|
326
|
+
export const useCellState = ({
|
|
327
|
+
id,
|
|
328
|
+
behavior,
|
|
329
|
+
focused,
|
|
330
|
+
}: {
|
|
331
|
+
id: string | number;
|
|
332
|
+
behavior: Behavior;
|
|
333
|
+
focused: boolean;
|
|
334
|
+
}): CellState => {
|
|
335
|
+
const lastUpdate = useBehaviorUpdate(behavior);
|
|
336
|
+
|
|
337
|
+
const _isSelected = useMemo(
|
|
338
|
+
() => isSelected(id, behavior),
|
|
339
|
+
[behavior, id, lastUpdate]
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
return getCellState({ focused, selected: _isSelected });
|
|
219
343
|
};
|
|
220
344
|
|
|
221
345
|
export const hasFocusableInsideBuilder = (elementsBuilder) => (item) => {
|
|
@@ -35,7 +35,10 @@ import {
|
|
|
35
35
|
log_warning,
|
|
36
36
|
} from "./logger";
|
|
37
37
|
import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
useSetNavbarState,
|
|
40
|
+
useTargetScreenData,
|
|
41
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks/screen";
|
|
39
42
|
import {
|
|
40
43
|
PlayerContainerContext,
|
|
41
44
|
PlayerContainerContextProvider,
|
|
@@ -228,6 +231,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
228
231
|
const { appData } = usePickFromState(["appData"]);
|
|
229
232
|
const prevItemId = usePrevious(item?.id);
|
|
230
233
|
const screenData = useTargetScreenData(item);
|
|
234
|
+
const { setVisible: showNavBar } = useSetNavbarState();
|
|
231
235
|
|
|
232
236
|
const playerEvent = (event, ...args) => {
|
|
233
237
|
playerManager.invokeHandler(event, ...args);
|
|
@@ -242,8 +246,8 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
242
246
|
}
|
|
243
247
|
|
|
244
248
|
navigator.goBack();
|
|
245
|
-
|
|
246
|
-
}, [isModal, navigator]);
|
|
249
|
+
showNavBar(true);
|
|
250
|
+
}, [isModal, navigator.goBack, showNavBar]);
|
|
247
251
|
|
|
248
252
|
const playEntry = (entry) => navigator.replaceTop(entry, { mode });
|
|
249
253
|
|
|
@@ -478,7 +482,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
478
482
|
playerEvent("source_changed", { item });
|
|
479
483
|
|
|
480
484
|
if (!isModal) {
|
|
481
|
-
|
|
485
|
+
showNavBar(false);
|
|
482
486
|
}
|
|
483
487
|
|
|
484
488
|
if (!Player) {
|
|
@@ -489,10 +493,10 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
489
493
|
playerEvent("player_did_close");
|
|
490
494
|
|
|
491
495
|
if (!isModal) {
|
|
492
|
-
|
|
496
|
+
showNavBar(true);
|
|
493
497
|
}
|
|
494
498
|
};
|
|
495
|
-
}, []);
|
|
499
|
+
}, [showNavBar, /* added as suggested: */ item?.id, isModal, Player]);
|
|
496
500
|
|
|
497
501
|
useEffect(() => {
|
|
498
502
|
if (prevItemId && !R.equals(prevItemId, item?.id)) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { View, FlatList, StyleSheet } from "react-native";
|
|
3
|
+
import { View, FlatList, StyleSheet, Platform } from "react-native";
|
|
4
4
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
5
5
|
import { RiverItem } from "../RiverItem";
|
|
6
6
|
import { RiverFooter } from "../RiverFooter";
|
|
@@ -208,6 +208,9 @@ function ComponentsMapComponent(props: Props) {
|
|
|
208
208
|
>
|
|
209
209
|
<ViewportTracker>
|
|
210
210
|
<FlatList
|
|
211
|
+
// Fix for WebView rerender crashes on Android API 28+
|
|
212
|
+
// https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
|
|
213
|
+
overScrollMode={Platform.OS === "android" ? "never" : "auto"}
|
|
211
214
|
scrollIndicatorInsets={scrollIndicatorInsets}
|
|
212
215
|
extraData={feed}
|
|
213
216
|
onLayout={handleOnLayout}
|
|
@@ -12,9 +12,6 @@ type Props = ZappScreenProps & {
|
|
|
12
12
|
feedUrl?: string;
|
|
13
13
|
isInsideContainer?: boolean;
|
|
14
14
|
screenData: {};
|
|
15
|
-
setScreenTitle: (string) => void;
|
|
16
|
-
setScreenSummary: (string) => void;
|
|
17
|
-
setIsScreenWrappedInContainer: (any) => void;
|
|
18
15
|
groupId: string;
|
|
19
16
|
scrollViewExtraProps: (
|
|
20
17
|
| import("react-native").ScrollViewProps
|
|
@@ -52,7 +49,9 @@ export class RiverComponent extends React.Component<Props, State> {
|
|
|
52
49
|
|
|
53
50
|
componentDidUpdate(prevProps) {
|
|
54
51
|
const {
|
|
55
|
-
|
|
52
|
+
screenContext: {
|
|
53
|
+
navBar: { setTitle: setScreenTitle, setSummary: setScreenSummary },
|
|
54
|
+
},
|
|
56
55
|
isInsideContainer,
|
|
57
56
|
} = this.props;
|
|
58
57
|
|
|
@@ -5,7 +5,6 @@ import { Text } from "react-native";
|
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
|
|
7
7
|
import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
8
|
-
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
|
|
9
8
|
import {
|
|
10
9
|
useFeedLoader,
|
|
11
10
|
useLayoutVersion,
|
|
@@ -17,6 +16,10 @@ import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
|
17
16
|
import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
18
17
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
19
18
|
import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
19
|
+
import {
|
|
20
|
+
useNavbarState,
|
|
21
|
+
useSetNavbarState,
|
|
22
|
+
} from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
20
23
|
|
|
21
24
|
type Props = {
|
|
22
25
|
screenId: string;
|
|
@@ -43,8 +46,10 @@ export const River = (props: Props) => {
|
|
|
43
46
|
extraOffset,
|
|
44
47
|
} = props;
|
|
45
48
|
|
|
46
|
-
const {
|
|
47
|
-
|
|
49
|
+
const { title: screenTitle, summary: screenSummary } = useNavbarState();
|
|
50
|
+
|
|
51
|
+
const { setTitle: setScreenTitle, setSummary: setScreenSummary } =
|
|
52
|
+
useSetNavbarState();
|
|
48
53
|
|
|
49
54
|
const navigationPluginData = useNavigationPluginData();
|
|
50
55
|
|
|
@@ -92,7 +97,7 @@ export const River = (props: Props) => {
|
|
|
92
97
|
setScreenTitle(stringOrEmpty(screenData?.title));
|
|
93
98
|
setScreenSummary(stringOrEmpty(screenData?.summary));
|
|
94
99
|
}
|
|
95
|
-
}, [feedData, screenData]);
|
|
100
|
+
}, [feedData, screenData, screenTitle, screenSummary]);
|
|
96
101
|
|
|
97
102
|
React.useEffect(() => {
|
|
98
103
|
if (
|
|
@@ -60,6 +60,7 @@ exports[`componentsMap renders renders components map correctly 1`] = `
|
|
|
60
60
|
onScroll={[Function]}
|
|
61
61
|
onScrollBeginDrag={[Function]}
|
|
62
62
|
onScrollEndDrag={[Function]}
|
|
63
|
+
overScrollMode="auto"
|
|
63
64
|
refreshControl={null}
|
|
64
65
|
removeClippedSubviews={true}
|
|
65
66
|
renderItem={[Function]}
|
|
@@ -7,6 +7,7 @@ import { ContainerContext } from "../../Contexts";
|
|
|
7
7
|
import { RiverComponent } from "./River";
|
|
8
8
|
import { withDimensionsProvider } from "@applicaster/zapp-react-native-utils/dimensionsProvider";
|
|
9
9
|
import { WithRiverFeedLoader } from "../../Decorators/RiverFeedLoader";
|
|
10
|
+
import { withScreenContext } from "../../Contexts/ScreenContext";
|
|
10
11
|
|
|
11
12
|
const reduxConnector = connectToStore(R.pick(["rivers", "appData"]));
|
|
12
13
|
|
|
@@ -16,5 +17,6 @@ export const River = R.compose(
|
|
|
16
17
|
WithRiverFeedLoader,
|
|
17
18
|
withNavigator,
|
|
18
19
|
withDimensionsProvider,
|
|
19
|
-
ContainerContext.withConsumer
|
|
20
|
+
ContainerContext.withConsumer,
|
|
21
|
+
withScreenContext
|
|
20
22
|
)(RiverComponent);
|
|
@@ -53,6 +53,9 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
|
|
|
53
53
|
useCurrentScreenData: jest.fn(() => ({
|
|
54
54
|
id: "testId",
|
|
55
55
|
})),
|
|
56
|
+
useNavbarState: jest.fn(() => ({
|
|
57
|
+
visible: jest.fn(() => mock_navBarVisibleFlag),
|
|
58
|
+
})),
|
|
56
59
|
}));
|
|
57
60
|
|
|
58
61
|
const {
|
|
@@ -67,11 +70,11 @@ const navBarProps = { nav_items: [] };
|
|
|
67
70
|
const screenData = {};
|
|
68
71
|
|
|
69
72
|
jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
canGoBack: () => false,
|
|
73
|
+
useRoute: jest.fn(() => ({
|
|
74
|
+
pathname: "/river/testId",
|
|
73
75
|
})),
|
|
74
76
|
useNavigation: jest.fn(() => ({
|
|
77
|
+
canGoBack: () => false,
|
|
75
78
|
currentRoute: "/river/testId",
|
|
76
79
|
data: { screen: { id: "testId" } },
|
|
77
80
|
})),
|