@applicaster/zapp-react-native-ui-components 12.0.0-alpha.7623722215 → 12.0.0-alpha.7921075302
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/GeneralContentScreen/utils/__tests__/useCurationAPI.test.js +13 -6
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +1 -1
- package/Components/MasterCell/DefaultComponents/BorderContainerView/index.tsx +105 -80
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +8 -5
- package/Components/River/ComponentsMap/ComponentsMap.tsx +86 -22
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
- package/Components/Screen/index.tsx +35 -24
- package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +0 -5
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +11 -4
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +9 -2
- package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +31 -40
- package/Components/Viewport/ViewportTracker/index.tsx +1 -0
- package/Components/Viewport/utils.js +1 -1
- package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
- package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
- package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
- package/Contexts/ScreenContext/index.tsx +94 -25
- package/package.json +5 -5
- /package/Contexts/{index.js → index.ts} +0 -0
|
@@ -50,7 +50,11 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
50
50
|
);
|
|
51
51
|
|
|
52
52
|
expect(transformed_preset).toBeDefined();
|
|
53
|
-
|
|
53
|
+
|
|
54
|
+
expect(transformed_preset.id).toEqual(
|
|
55
|
+
`${mockComp.id}-${mockPreset.feed_url}-0`
|
|
56
|
+
); // id was transformed
|
|
57
|
+
|
|
54
58
|
expect(transformed_preset.data.source).toEqual(mockPreset.feed_url); // source was replaced with preset feed_url.
|
|
55
59
|
});
|
|
56
60
|
});
|
|
@@ -117,7 +121,10 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
117
121
|
|
|
118
122
|
expect(Array.isArray(result)).toBe(true);
|
|
119
123
|
expect(result).toHaveLength(2);
|
|
120
|
-
|
|
124
|
+
|
|
125
|
+
expect(result[0].id).toEqual(
|
|
126
|
+
`${mockSmartComp.id}-${mockFeeds.preset_source.data.entry[0].feed_url}-0`
|
|
127
|
+
);
|
|
121
128
|
|
|
122
129
|
expect(result[0].data.source).toEqual(
|
|
123
130
|
mockFeeds.preset_source.data.entry[0].feed_url
|
|
@@ -287,7 +294,7 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
287
294
|
mockComponents[0],
|
|
288
295
|
{
|
|
289
296
|
...mockLayoutPresets.preset_one,
|
|
290
|
-
id: mockComponents[1].id
|
|
297
|
+
id: `${mockComponents[1].id}-${mockPresetEntry[0].feed_url}-1`,
|
|
291
298
|
data: { source: mockPresetEntry[0].feed_url },
|
|
292
299
|
},
|
|
293
300
|
];
|
|
@@ -344,12 +351,12 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
344
351
|
const mockTransformedComponents = [
|
|
345
352
|
{
|
|
346
353
|
...mockLayoutPresets.preset_one,
|
|
347
|
-
id: mockComponents[0].id
|
|
354
|
+
id: `${mockComponents[0].id}-${mockPresetEntry1[0].feed_url}-0`,
|
|
348
355
|
data: { source: mockPresetEntry1[0].feed_url },
|
|
349
356
|
},
|
|
350
357
|
{
|
|
351
358
|
...mockLayoutPresets.preset_one,
|
|
352
|
-
id: mockComponents[1].id
|
|
359
|
+
id: `${mockComponents[1].id}-${mockPresetEntry2[0].feed_url}-1`,
|
|
353
360
|
data: { source: mockPresetEntry2[0].feed_url },
|
|
354
361
|
},
|
|
355
362
|
];
|
|
@@ -412,7 +419,7 @@ describe("getTransformedPreset should return the passed components if smartCompo
|
|
|
412
419
|
const mockTransformedComponents = mockPresetEntry.map((preset, i) => {
|
|
413
420
|
return {
|
|
414
421
|
...mockLayoutPresets[preset.preset_name],
|
|
415
|
-
id: mockComponents[0].id
|
|
422
|
+
id: `${mockComponents[0].id}-${preset.feed_url}-${i}`,
|
|
416
423
|
data: { source: preset.feed_url },
|
|
417
424
|
};
|
|
418
425
|
});
|
|
@@ -41,7 +41,7 @@ export const getTransformedPreset = (
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const updatedPresetComponent = produce(presetComponent, (draft) => {
|
|
44
|
-
draft.id = `${componentId}
|
|
44
|
+
draft.id = `${componentId}-${preset?.feed_url}-${index}`;
|
|
45
45
|
draft.data.source = preset?.feed_url;
|
|
46
46
|
|
|
47
47
|
if (draft.ui_components) {
|
|
@@ -7,24 +7,50 @@ type BorderPosition = "inside" | "outside" | "center";
|
|
|
7
7
|
interface Props {
|
|
8
8
|
style: ImageStyle | ViewStyle;
|
|
9
9
|
borderPosition: BorderPosition;
|
|
10
|
-
borderPaddingTop: number;
|
|
11
|
-
borderPaddingRight: number;
|
|
12
|
-
borderPaddingBottom: number;
|
|
13
|
-
borderPaddingLeft: number;
|
|
14
10
|
children: React.ReactNode;
|
|
15
11
|
}
|
|
16
12
|
|
|
17
|
-
const
|
|
13
|
+
const MARGINS = [
|
|
14
|
+
"marginTop",
|
|
15
|
+
"marginBottom",
|
|
16
|
+
"marginLeft",
|
|
17
|
+
"marginRight",
|
|
18
|
+
] as const;
|
|
18
19
|
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
});
|
|
20
|
+
const PADDINGS = [
|
|
21
|
+
"paddingTop",
|
|
22
|
+
"paddingBottom",
|
|
23
|
+
"paddingLeft",
|
|
24
|
+
"paddingRight",
|
|
25
|
+
] as const;
|
|
26
26
|
|
|
27
|
-
const
|
|
27
|
+
const isPercentageValue = (value: number | string) => {
|
|
28
|
+
if (typeof value === "string" && value.endsWith("%")) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return false;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const calculateContainerSpacing = ({
|
|
36
|
+
spacingKey,
|
|
37
|
+
style,
|
|
38
|
+
additionalSpacing,
|
|
39
|
+
}: {
|
|
40
|
+
spacingKey: typeof MARGINS[number] | typeof PADDINGS[number];
|
|
41
|
+
style: ImageStyle | ViewStyle;
|
|
42
|
+
additionalSpacing: number;
|
|
43
|
+
}) => {
|
|
44
|
+
return {
|
|
45
|
+
[spacingKey]:
|
|
46
|
+
toNumberWithDefaultZero(style[spacingKey]) + additionalSpacing,
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const getContainerBorderWidth = (
|
|
51
|
+
borderPosition: BorderPosition,
|
|
52
|
+
borderWidth
|
|
53
|
+
) => {
|
|
28
54
|
switch (borderPosition) {
|
|
29
55
|
case "inside":
|
|
30
56
|
return 0;
|
|
@@ -37,103 +63,102 @@ const getBorderPadding = (borderPosition: BorderPosition, borderWidth) => {
|
|
|
37
63
|
}
|
|
38
64
|
};
|
|
39
65
|
|
|
66
|
+
const getContainerPadding = (borderPosition: BorderPosition, borderWidth) => {
|
|
67
|
+
switch (borderPosition) {
|
|
68
|
+
case "inside":
|
|
69
|
+
return borderWidth;
|
|
70
|
+
case "center":
|
|
71
|
+
return borderWidth / 2;
|
|
72
|
+
case "outside":
|
|
73
|
+
return 0;
|
|
74
|
+
default:
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
40
79
|
const InsideBorder = ({
|
|
41
80
|
style,
|
|
42
|
-
padding,
|
|
43
81
|
borderPosition,
|
|
44
82
|
}: {
|
|
45
83
|
style: ViewStyle;
|
|
46
|
-
padding: ViewStyle;
|
|
47
84
|
borderPosition: BorderPosition;
|
|
48
85
|
}) => {
|
|
49
|
-
if (
|
|
86
|
+
if (borderPosition === "outside") {
|
|
50
87
|
return null;
|
|
51
88
|
}
|
|
52
89
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const initialBorderRadius = toNumberWithDefaultZero(style.borderRadius);
|
|
57
|
-
const paddingTop = toNumberWithDefaultZero(padding.paddingTop);
|
|
58
|
-
const paddingRight = toNumberWithDefaultZero(padding.paddingRight);
|
|
59
|
-
const paddingBottom = toNumberWithDefaultZero(padding.paddingBottom);
|
|
60
|
-
const paddingLeft = toNumberWithDefaultZero(padding.paddingLeft);
|
|
61
|
-
|
|
62
|
-
const borderRadiusStyle = initialBorderRadius
|
|
63
|
-
? {
|
|
64
|
-
borderTopLeftRadius:
|
|
65
|
-
initialBorderRadius +
|
|
66
|
-
containerPadding +
|
|
67
|
-
Math.min(paddingTop, paddingLeft),
|
|
68
|
-
borderTopRightRadius:
|
|
69
|
-
initialBorderRadius +
|
|
70
|
-
containerPadding +
|
|
71
|
-
Math.min(paddingTop, paddingRight),
|
|
72
|
-
borderBottomLeftRadius:
|
|
73
|
-
initialBorderRadius +
|
|
74
|
-
containerPadding +
|
|
75
|
-
Math.min(paddingBottom, paddingLeft),
|
|
76
|
-
borderBottomRightRadius:
|
|
77
|
-
initialBorderRadius +
|
|
78
|
-
containerPadding +
|
|
79
|
-
Math.min(paddingBottom, paddingRight),
|
|
80
|
-
}
|
|
81
|
-
: {
|
|
82
|
-
borderTopLeftRadius: 0,
|
|
83
|
-
borderTopRightRadius: 0,
|
|
84
|
-
borderBottomLeftRadius: 0,
|
|
85
|
-
borderBottomRightRadius: 0,
|
|
86
|
-
};
|
|
90
|
+
const insideBorderWidth =
|
|
91
|
+
borderPosition === "center" ? style.borderWidth / 2 : style.borderWidth;
|
|
87
92
|
|
|
88
93
|
return (
|
|
89
94
|
<View
|
|
90
95
|
style={{
|
|
91
96
|
...StyleSheet.absoluteFillObject,
|
|
92
|
-
|
|
93
|
-
bottom: -containerPadding - paddingBottom,
|
|
94
|
-
left: -containerPadding - paddingLeft,
|
|
95
|
-
top: -containerPadding - paddingTop,
|
|
96
|
-
borderWidth,
|
|
97
|
+
borderWidth: insideBorderWidth,
|
|
97
98
|
borderColor: style.borderColor,
|
|
98
|
-
|
|
99
|
+
borderRadius: style.borderRadius,
|
|
99
100
|
}}
|
|
100
101
|
/>
|
|
101
102
|
);
|
|
102
103
|
};
|
|
103
104
|
|
|
104
105
|
export const BorderContainerView = (props: Props) => {
|
|
105
|
-
const {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
style,
|
|
112
|
-
children,
|
|
113
|
-
} = props;
|
|
106
|
+
const { style, children } = props;
|
|
107
|
+
// Return border position prop after re-implementing
|
|
108
|
+
const borderPosition = "outside";
|
|
109
|
+
|
|
110
|
+
const borderWidth = toNumberWithDefaultZero(style.borderWidth);
|
|
111
|
+
const spacing = getContainerPadding(borderPosition, borderWidth);
|
|
114
112
|
|
|
115
113
|
const borderStyleForMissingBorder =
|
|
116
114
|
style?.borderWidth === 0 || !style?.borderColor ? { borderRadius: 0 } : {};
|
|
117
115
|
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
116
|
+
const updatedMargins = MARGINS.reduce((acc, margin) => {
|
|
117
|
+
const marginValue = calculateContainerSpacing({
|
|
118
|
+
spacingKey: margin,
|
|
119
|
+
style,
|
|
120
|
+
additionalSpacing: spacing,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
return { ...acc, ...marginValue };
|
|
124
|
+
}, {});
|
|
125
|
+
|
|
126
|
+
const updatedPaddings = PADDINGS.reduce((acc, padding) => {
|
|
127
|
+
const paddingValue = calculateContainerSpacing({
|
|
128
|
+
spacingKey: padding,
|
|
129
|
+
style,
|
|
130
|
+
additionalSpacing: spacing,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return { ...acc, ...paddingValue };
|
|
134
|
+
}, {});
|
|
135
|
+
|
|
136
|
+
const updatedWidth = style.width
|
|
137
|
+
? isPercentageValue(style.width)
|
|
138
|
+
? style.width
|
|
139
|
+
: toNumberWithDefaultZero(style.width) - spacing * 2
|
|
140
|
+
: undefined;
|
|
141
|
+
|
|
142
|
+
const updatedHeight = style.height
|
|
143
|
+
? isPercentageValue(style.height)
|
|
144
|
+
? style.height
|
|
145
|
+
: toNumberWithDefaultZero(style.height) - spacing * 2
|
|
146
|
+
: undefined;
|
|
147
|
+
|
|
148
|
+
const containerStyle = {
|
|
149
|
+
borderWidth: getContainerBorderWidth(borderPosition, borderWidth),
|
|
150
|
+
padding: spacing,
|
|
151
|
+
...updatedMargins,
|
|
152
|
+
...updatedPaddings,
|
|
153
|
+
width: updatedWidth,
|
|
154
|
+
height: updatedHeight,
|
|
155
|
+
};
|
|
127
156
|
|
|
128
157
|
return (
|
|
129
|
-
<View
|
|
130
|
-
{...props}
|
|
131
|
-
style={[style, styles.container, borderStyleForMissingBorder]}
|
|
132
|
-
>
|
|
158
|
+
<View {...props} style={[style, containerStyle]}>
|
|
133
159
|
{children}
|
|
134
160
|
<InsideBorder
|
|
135
|
-
style={style}
|
|
136
|
-
padding={padding}
|
|
161
|
+
style={{ ...style, ...borderStyleForMissingBorder }}
|
|
137
162
|
borderPosition={borderPosition}
|
|
138
163
|
/>
|
|
139
164
|
</View>
|
|
@@ -43,14 +43,16 @@ function Image({
|
|
|
43
43
|
[source, error]
|
|
44
44
|
);
|
|
45
45
|
|
|
46
|
+
const _source = shouldRenderImg
|
|
47
|
+
? withDimensions(source)
|
|
48
|
+
: defaultPlaceHolderImage;
|
|
49
|
+
|
|
46
50
|
return (
|
|
47
51
|
// @ts-ignore
|
|
48
52
|
<MemoizedImage
|
|
49
53
|
style={style as ImageStyle}
|
|
50
54
|
onError={() => setErrorState(true)}
|
|
51
|
-
source={
|
|
52
|
-
shouldRenderImg ? withDimensions(source) : defaultPlaceHolderImage
|
|
53
|
-
}
|
|
55
|
+
source={_source?.uri ? _source : undefined}
|
|
54
56
|
{...R.omit(["source"], otherProps)}
|
|
55
57
|
/>
|
|
56
58
|
);
|
|
@@ -54,7 +54,10 @@ import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
|
54
54
|
import { usePlayNextOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayNextOverlay";
|
|
55
55
|
import { PlayNextState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/OverlayObserver/OverlaysObserver";
|
|
56
56
|
|
|
57
|
-
import {
|
|
57
|
+
import {
|
|
58
|
+
useModalAnimationContext,
|
|
59
|
+
PlayerAnimationStateEnum,
|
|
60
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
58
61
|
|
|
59
62
|
type Props = {
|
|
60
63
|
Player: React.ComponentType<any>;
|
|
@@ -231,6 +234,9 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
231
234
|
const screenData = useTargetScreenData(item);
|
|
232
235
|
const { setVisible: showNavBar } = useSetNavbarState();
|
|
233
236
|
|
|
237
|
+
const { isActiveGesture, startComponentsAnimation, setPlayerAnimationState } =
|
|
238
|
+
useModalAnimationContext();
|
|
239
|
+
|
|
234
240
|
const playerEvent = (event, ...args) => {
|
|
235
241
|
playerManager.invokeHandler(event, ...args);
|
|
236
242
|
};
|
|
@@ -448,7 +454,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
448
454
|
if (disableMiniPlayer) {
|
|
449
455
|
navigator.closeVideoModal();
|
|
450
456
|
} else {
|
|
451
|
-
|
|
457
|
+
setPlayerAnimationState(PlayerAnimationStateEnum.minimize);
|
|
452
458
|
}
|
|
453
459
|
}
|
|
454
460
|
|
|
@@ -600,9 +606,6 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
600
606
|
pluginConfiguration,
|
|
601
607
|
};
|
|
602
608
|
|
|
603
|
-
const { isActiveGesture, startComponentsAnimation } =
|
|
604
|
-
useModalAnimationContext();
|
|
605
|
-
|
|
606
609
|
return (
|
|
607
610
|
<PlayerStateContext.Provider value={value}>
|
|
608
611
|
<PlayerContainerContextProvider
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
|
-
import { View,
|
|
3
|
+
import { View, StyleSheet, Platform, FlatList } 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";
|
|
@@ -21,7 +21,8 @@ import {
|
|
|
21
21
|
import { useScreenData } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenData";
|
|
22
22
|
import { isLast } from "@applicaster/zapp-react-native-utils/arrayUtils";
|
|
23
23
|
import { withComponentsMapProvider } from "@applicaster/zapp-react-native-ui-components/Decorators/ComponentsMapWrapper";
|
|
24
|
-
import {
|
|
24
|
+
import { useScreenContextV2 } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
25
|
+
import { useShallow } from "zustand/react/shallow";
|
|
25
26
|
|
|
26
27
|
type Props = {
|
|
27
28
|
feed: ZappFeed;
|
|
@@ -41,8 +42,10 @@ const styles = StyleSheet.create({
|
|
|
41
42
|
},
|
|
42
43
|
});
|
|
43
44
|
|
|
44
|
-
const
|
|
45
|
+
const getNearestValue = (value, optionA, optionB) =>
|
|
46
|
+
Math.abs(value - optionA) < Math.abs(value - optionB) ? optionA : optionB;
|
|
45
47
|
|
|
48
|
+
const scrollIndicatorInsets = { right: 1 };
|
|
46
49
|
const keyExtractor = R.compose(String, R.prop("id"));
|
|
47
50
|
|
|
48
51
|
function ComponentsMapComponent(props: Props) {
|
|
@@ -60,6 +63,7 @@ function ComponentsMapComponent(props: Props) {
|
|
|
60
63
|
refreshingPipesV1,
|
|
61
64
|
} = props;
|
|
62
65
|
|
|
66
|
+
const flatListRef = React.useRef<FlatList | null>(null);
|
|
63
67
|
const screenConfig = useScreenConfiguration(riverId);
|
|
64
68
|
const screenData = useScreenData(riverId);
|
|
65
69
|
const pullToRefreshEnabled = screenData?.rules?.pull_to_refresh_enabled;
|
|
@@ -194,26 +198,81 @@ function ComponentsMapComponent(props: Props) {
|
|
|
194
198
|
[]
|
|
195
199
|
);
|
|
196
200
|
|
|
197
|
-
const
|
|
198
|
-
({ nativeEvent }, isScrollingDone = false) => {
|
|
199
|
-
const {
|
|
200
|
-
contentOffset: { y },
|
|
201
|
-
} = nativeEvent;
|
|
201
|
+
const navBarStore = useScreenContextV2()._navBarStore;
|
|
202
202
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
scrollPosition: y,
|
|
206
|
-
});
|
|
207
|
-
},
|
|
208
|
-
[]
|
|
203
|
+
const scrollY = navBarStore(
|
|
204
|
+
useShallow(({ scrollYAnimated }) => scrollYAnimated)
|
|
209
205
|
);
|
|
210
206
|
|
|
211
|
-
const
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
const canMomentum = React.useRef(false);
|
|
208
|
+
|
|
209
|
+
const onScrollBeginDrag = React.useCallback(() => {
|
|
210
|
+
canMomentum.current = true;
|
|
211
|
+
}, []);
|
|
212
|
+
|
|
213
|
+
/* onMomentumScrollEnd: Handling snap to expanded/collapsed state ( for navbar ) */
|
|
214
|
+
const _onMomentumScrollEnd = React.useCallback(({ nativeEvent }) => {
|
|
215
|
+
if (!canMomentum.current) return;
|
|
216
|
+
canMomentum.current = false;
|
|
217
|
+
|
|
218
|
+
const { height: headerHeight, scrollState } = navBarStore.getState();
|
|
219
|
+
|
|
220
|
+
const offsetY = Math.max(0, nativeEvent.contentOffset.y);
|
|
221
|
+
|
|
222
|
+
if (
|
|
223
|
+
!(scrollState === 0 || scrollState === -headerHeight) &&
|
|
224
|
+
flatListRef.current
|
|
225
|
+
) {
|
|
226
|
+
const offset =
|
|
227
|
+
getNearestValue(Math.round(scrollState), -headerHeight, 0) ===
|
|
228
|
+
-headerHeight
|
|
229
|
+
? Math.round(offsetY + scrollState + headerHeight)
|
|
230
|
+
: Math.round(offsetY + scrollState);
|
|
231
|
+
|
|
232
|
+
flatListRef.current.scrollToOffset({
|
|
233
|
+
animated: true,
|
|
234
|
+
offset,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}, []);
|
|
238
|
+
|
|
239
|
+
/* onScrollEnd: Handling snap to expanded/collapsed state ( for navbar ) */
|
|
240
|
+
const _onScrollEndDrag = React.useCallback(({ nativeEvent }) => {
|
|
241
|
+
const { height: headerHeight, scrollState } = navBarStore.getState();
|
|
242
|
+
|
|
243
|
+
const offsetY = Math.max(0, nativeEvent.contentOffset.y);
|
|
244
|
+
|
|
245
|
+
if (
|
|
246
|
+
!(scrollState === 0 || scrollState === -headerHeight) &&
|
|
247
|
+
flatListRef.current &&
|
|
248
|
+
nativeEvent.velocity.y === 0
|
|
249
|
+
) {
|
|
250
|
+
const offset =
|
|
251
|
+
getNearestValue(Math.round(scrollState), -headerHeight, 0) ===
|
|
252
|
+
-headerHeight
|
|
253
|
+
? Math.round(offsetY + scrollState + headerHeight)
|
|
254
|
+
: Math.round(offsetY + scrollState);
|
|
255
|
+
|
|
256
|
+
flatListRef.current.scrollToOffset({
|
|
257
|
+
animated: true,
|
|
258
|
+
offset,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}, []);
|
|
262
|
+
|
|
263
|
+
const onScroll = React.useCallback((event) => {
|
|
264
|
+
const {
|
|
265
|
+
nativeEvent: {
|
|
266
|
+
contentOffset: { y },
|
|
267
|
+
layoutMeasurement: { height },
|
|
268
|
+
contentSize: { height: contentHeight },
|
|
269
|
+
},
|
|
270
|
+
} = event;
|
|
271
|
+
|
|
272
|
+
if (y >= 0 && y + height <= contentHeight) {
|
|
273
|
+
scrollY.setValue(y);
|
|
274
|
+
}
|
|
275
|
+
}, []);
|
|
217
276
|
|
|
218
277
|
if (shouldShowLoadingError) {
|
|
219
278
|
return <RiverError />;
|
|
@@ -230,6 +289,9 @@ function ComponentsMapComponent(props: Props) {
|
|
|
230
289
|
>
|
|
231
290
|
<ViewportTracker>
|
|
232
291
|
<FlatList
|
|
292
|
+
ref={(ref) => {
|
|
293
|
+
flatListRef.current = ref;
|
|
294
|
+
}}
|
|
233
295
|
// Fix for WebView rerender crashes on Android API 28+
|
|
234
296
|
// https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
|
|
235
297
|
overScrollMode={Platform.OS === "android" ? "never" : "auto"}
|
|
@@ -249,8 +311,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
249
311
|
}
|
|
250
312
|
ListFooterComponent={renderFooter}
|
|
251
313
|
refreshControl={refreshControl}
|
|
252
|
-
|
|
253
|
-
|
|
314
|
+
onScrollBeginDrag={onScrollBeginDrag}
|
|
315
|
+
onScroll={onScroll}
|
|
316
|
+
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
317
|
+
onScrollEndDrag={_onScrollEndDrag}
|
|
254
318
|
scrollEventThrottle={16}
|
|
255
319
|
{...scrollViewExtraProps}
|
|
256
320
|
/>
|
|
@@ -11,7 +11,9 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
|
|
|
11
11
|
}
|
|
12
12
|
>
|
|
13
13
|
<View
|
|
14
|
+
hasMenu={false}
|
|
14
15
|
id="/river/testId"
|
|
16
|
+
pathname="/river/testId"
|
|
15
17
|
selected="testId"
|
|
16
18
|
testID="navBar"
|
|
17
19
|
title=""
|
|
@@ -41,7 +43,9 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
|
|
|
41
43
|
}
|
|
42
44
|
>
|
|
43
45
|
<View
|
|
46
|
+
hasMenu={false}
|
|
44
47
|
id="/river/testId"
|
|
48
|
+
pathname="/river/testId"
|
|
45
49
|
selected="testId"
|
|
46
50
|
testID="navBar"
|
|
47
51
|
title=""
|
|
@@ -6,7 +6,10 @@ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
|
|
|
6
6
|
|
|
7
7
|
import { useTheme } from "@applicaster/zapp-react-native-utils/theme";
|
|
8
8
|
import { getComponentModule } from "@applicaster/zapp-react-native-utils/pluginUtils";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
getNavigationPropsV2,
|
|
11
|
+
resolveNavigationPlugin,
|
|
12
|
+
} from "@applicaster/zapp-react-native-utils/navigationUtils";
|
|
10
13
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
11
14
|
import {
|
|
12
15
|
useDimensions,
|
|
@@ -52,11 +55,11 @@ function isValidColor(string) {
|
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
type Props = {
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
pathname: unknown;
|
|
59
|
+
screenData: unknown;
|
|
57
60
|
};
|
|
58
61
|
|
|
59
|
-
export function Screen(
|
|
62
|
+
export function Screen(_props: Props) {
|
|
60
63
|
const theme = useTheme<BaseThemePropertiesMobile>();
|
|
61
64
|
const navigation = useNavigation();
|
|
62
65
|
const { plugins } = usePickFromState(["plugins"]);
|
|
@@ -70,26 +73,38 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
70
73
|
fullDimensions: true,
|
|
71
74
|
});
|
|
72
75
|
|
|
73
|
-
const
|
|
76
|
+
const { screenData, pathname } = useRoute();
|
|
74
77
|
|
|
75
78
|
const currentRiver = useScreenData(
|
|
76
|
-
getScreenId(
|
|
79
|
+
getScreenId(screenData, navigation.activeRiver)
|
|
77
80
|
);
|
|
78
81
|
|
|
79
82
|
const { title } = useNavbarState();
|
|
80
83
|
|
|
81
|
-
const
|
|
82
|
-
(
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
84
|
+
const hasMenu =
|
|
85
|
+
resolveNavigationPlugin({
|
|
86
|
+
category: "menu",
|
|
87
|
+
navigations: currentRiver.navigations,
|
|
88
|
+
plugins,
|
|
89
|
+
})?.identifier === "quick_brick_side_menu";
|
|
90
|
+
|
|
91
|
+
const navBarProps = React.useMemo<MobileNavBarPluginProps | null>(() => {
|
|
92
|
+
const props = getNavigationPropsV2({
|
|
93
|
+
currentRiver,
|
|
94
|
+
title,
|
|
95
|
+
category: "nav_bar",
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
if (props) {
|
|
99
|
+
return {
|
|
100
|
+
...props,
|
|
101
|
+
id: pathname,
|
|
102
|
+
pathname: pathname,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return null;
|
|
107
|
+
}, [currentRiver, pathname]);
|
|
93
108
|
|
|
94
109
|
const NavBar = React.useMemo(
|
|
95
110
|
() =>
|
|
@@ -97,12 +112,10 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
97
112
|
"nav_bar",
|
|
98
113
|
currentRiver,
|
|
99
114
|
plugins
|
|
100
|
-
) as React.ComponentType<MobileNavBarPluginProps>,
|
|
115
|
+
) as React.ComponentType<MobileNavBarPluginProps & { hasMenu: boolean }>,
|
|
101
116
|
[]
|
|
102
117
|
);
|
|
103
118
|
|
|
104
|
-
const { screenData, pathname } = routeData;
|
|
105
|
-
|
|
106
119
|
const offlinePlugin = getComponentModule({
|
|
107
120
|
plugins,
|
|
108
121
|
components: {},
|
|
@@ -133,9 +146,7 @@ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
|
|
|
133
146
|
return (
|
|
134
147
|
<ScreenContextProvider pathname={pathname}>
|
|
135
148
|
<View style={style}>
|
|
136
|
-
<NavBar
|
|
137
|
-
{...{ ...(navBarProps as MobileNavBarPluginProps), id: pathname }}
|
|
138
|
-
/>
|
|
149
|
+
{navBarProps && <NavBar {...navBarProps} hasMenu={hasMenu} />}
|
|
139
150
|
|
|
140
151
|
<OfflineFallbackScreen screenData={targetScreenData}>
|
|
141
152
|
{/* @TODO RouteManager doesn't use props, can they be removed ? */}
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
TapGestureHandler,
|
|
10
10
|
GestureHandlerRootView,
|
|
11
11
|
} from "react-native-gesture-handler";
|
|
12
|
+
|
|
13
|
+
import { PlayerContainerContext } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainerContext";
|
|
12
14
|
import {
|
|
13
15
|
useModalAnimationContext,
|
|
14
16
|
PlayerAnimationStateEnum,
|
|
@@ -58,6 +60,8 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
58
60
|
setLastSnap,
|
|
59
61
|
} = useModalAnimationContext();
|
|
60
62
|
|
|
63
|
+
const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
|
|
64
|
+
|
|
61
65
|
const { maximiseVideoModal, minimiseVideoModal, videoModalState } =
|
|
62
66
|
useNavigation();
|
|
63
67
|
|
|
@@ -69,6 +73,11 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
69
73
|
playerAnimationState !== PlayerAnimationStateEnum.minimize &&
|
|
70
74
|
playerAnimationState !== PlayerAnimationStateEnum.maximaze;
|
|
71
75
|
|
|
76
|
+
const isEnablePanGesture =
|
|
77
|
+
!isLanguageOverlayVisible &&
|
|
78
|
+
isNotMinimizeMaximazeAnimation &&
|
|
79
|
+
(isMaximazedModal || isMinimizedModal);
|
|
80
|
+
|
|
72
81
|
const isAudioItem = React.useMemo(
|
|
73
82
|
() =>
|
|
74
83
|
videoModalState.item?.content?.type?.includes?.("audio") ||
|
|
@@ -290,15 +299,13 @@ export const AnimatedScrollModalComponent = ({ children }: Props) => {
|
|
|
290
299
|
>
|
|
291
300
|
<View pointerEvents="box-none">
|
|
292
301
|
<PanGestureHandler
|
|
293
|
-
enabled={
|
|
294
|
-
(isMaximazedModal || isMinimizedModal) &&
|
|
295
|
-
isNotMinimizeMaximazeAnimation
|
|
296
|
-
}
|
|
302
|
+
enabled={isEnablePanGesture}
|
|
297
303
|
ref={panHandlerRef}
|
|
298
304
|
simultaneousHandlers={[scrollRef, tapHandlerRef]}
|
|
299
305
|
shouldCancelWhenOutside={isMaximazedModal}
|
|
300
306
|
onGestureEvent={onGestureEvent}
|
|
301
307
|
onHandlerStateChange={onHandlerStateChange}
|
|
308
|
+
activeOffsetY={[-5, 5]}
|
|
302
309
|
>
|
|
303
310
|
<Animated.View>
|
|
304
311
|
<NativeViewGestureHandler
|
|
@@ -3,6 +3,8 @@ import { Animated, StyleSheet } from "react-native";
|
|
|
3
3
|
|
|
4
4
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
5
|
import { PanGestureHandler, State } from "react-native-gesture-handler";
|
|
6
|
+
|
|
7
|
+
import { PlayerContainerContext } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainerContext";
|
|
6
8
|
import {
|
|
7
9
|
useModalAnimationContext,
|
|
8
10
|
PlayerAnimationStateEnum,
|
|
@@ -35,9 +37,14 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
|
|
|
35
37
|
} = useModalAnimationContext();
|
|
36
38
|
|
|
37
39
|
const { videoModalState } = useNavigation();
|
|
40
|
+
const { isLanguageOverlayVisible } = React.useContext(PlayerContainerContext);
|
|
41
|
+
|
|
38
42
|
const isMaximazedModal = videoModalState.mode === "MAXIMIZED";
|
|
39
43
|
const isMinimizedModal = videoModalState.mode === "MINIMIZED";
|
|
40
44
|
|
|
45
|
+
const isEnablePanGesture =
|
|
46
|
+
!isLanguageOverlayVisible && (isMaximazedModal || isMinimizedModal);
|
|
47
|
+
|
|
41
48
|
const onGestureEvent = Animated.event(
|
|
42
49
|
[{ nativeEvent: { translationY: dragVideoPlayerY } }],
|
|
43
50
|
{ useNativeDriver: true }
|
|
@@ -53,7 +60,7 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
|
|
|
53
60
|
if (videoModalState.mode === "MAXIMIZED") {
|
|
54
61
|
if (translationY > 0) {
|
|
55
62
|
const endOffsetY =
|
|
56
|
-
lastSnap + preparedTranslationY + dragToss * velocityY +
|
|
63
|
+
lastSnap + preparedTranslationY + dragToss * velocityY + 200;
|
|
57
64
|
|
|
58
65
|
let destSnapPoint = modalSnapPoints[0];
|
|
59
66
|
|
|
@@ -127,7 +134,7 @@ export const AnimatedVideoPlayer = ({ children }: Props) => {
|
|
|
127
134
|
|
|
128
135
|
return (
|
|
129
136
|
<PanGestureHandler
|
|
130
|
-
enabled={
|
|
137
|
+
enabled={isEnablePanGesture}
|
|
131
138
|
shouldCancelWhenOutside={isMaximazedModal}
|
|
132
139
|
onGestureEvent={onGestureEvent}
|
|
133
140
|
onHandlerStateChange={onHandlerStateChange}
|
|
@@ -6,23 +6,23 @@ import { callOnChildren } from "../utils";
|
|
|
6
6
|
|
|
7
7
|
export function ViewportTracker(props) {
|
|
8
8
|
const viewportEvents = useViewportEventsContext();
|
|
9
|
-
const { children } = props;
|
|
10
|
-
const [width, setWidth] = React.useState(0);
|
|
11
|
-
const [height, setHeight] = React.useState(0);
|
|
12
|
-
const [offsetX, setOffsetX] = React.useState(0);
|
|
13
|
-
const [offsetY, setOffsetY] = React.useState(0);
|
|
14
9
|
const [nodeHandle, setNodeHandle] = React.useState(null);
|
|
15
10
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
const childrenRef = React.useRef(props.children);
|
|
12
|
+
|
|
13
|
+
const dimensionsRef = React.useRef({ width: 0, height: 0 });
|
|
14
|
+
const offsetRef = React.useRef({ offsetX: 0, offsetY: 0 });
|
|
15
|
+
|
|
16
|
+
const assignRef = React.useCallback((ref) => {
|
|
17
|
+
childrenRef.current?.ref?.(ref);
|
|
18
|
+
setNodeHandle(findNodeHandle(ref));
|
|
19
|
+
}, []);
|
|
23
20
|
|
|
24
21
|
const onViewportChange = React.useCallback(
|
|
25
|
-
(
|
|
22
|
+
({
|
|
23
|
+
event = { ...dimensionsRef.current, ...offsetRef.current },
|
|
24
|
+
shouldMeasureLayout = true,
|
|
25
|
+
} = {}) => {
|
|
26
26
|
if (nodeHandle && event?.width > 0 && event?.height > 0) {
|
|
27
27
|
viewportEvents?.notify?.({
|
|
28
28
|
parentHandle: nodeHandle,
|
|
@@ -36,54 +36,45 @@ export function ViewportTracker(props) {
|
|
|
36
36
|
|
|
37
37
|
const onLayout = React.useCallback(
|
|
38
38
|
(event) => {
|
|
39
|
-
callOnChildren(
|
|
40
|
-
|
|
41
|
-
setHeight(event?.nativeEvent?.layout?.height);
|
|
39
|
+
callOnChildren(childrenRef.current, "onLayout", event);
|
|
40
|
+
dimensionsRef.current = event?.nativeEvent?.layout;
|
|
42
41
|
|
|
43
|
-
onViewportChange(
|
|
44
|
-
width: event?.nativeEvent?.layout?.width,
|
|
45
|
-
height: event?.nativeEvent?.layout?.height,
|
|
46
|
-
offsetX,
|
|
47
|
-
offsetY,
|
|
48
|
-
});
|
|
42
|
+
onViewportChange();
|
|
49
43
|
},
|
|
50
|
-
[
|
|
44
|
+
[onViewportChange]
|
|
51
45
|
);
|
|
52
46
|
|
|
53
47
|
const onContentSizeChange = React.useCallback(
|
|
54
48
|
(contentWidth, contentHeight) => {
|
|
55
49
|
callOnChildren(
|
|
56
|
-
|
|
50
|
+
childrenRef.current,
|
|
57
51
|
"onContentSizeChange",
|
|
58
52
|
contentWidth,
|
|
59
53
|
contentHeight
|
|
60
54
|
);
|
|
61
55
|
|
|
62
|
-
onViewportChange(
|
|
56
|
+
onViewportChange();
|
|
63
57
|
},
|
|
64
|
-
[onViewportChange
|
|
58
|
+
[onViewportChange]
|
|
65
59
|
);
|
|
66
60
|
|
|
67
61
|
const onScroll = React.useCallback(
|
|
68
62
|
(event) => {
|
|
69
|
-
callOnChildren(
|
|
70
|
-
|
|
71
|
-
setOffsetY(event?.nativeEvent?.contentOffset?.y);
|
|
63
|
+
callOnChildren(childrenRef.current, "onScroll", event);
|
|
64
|
+
offsetRef.current = event?.nativeEvent?.contentOffset;
|
|
72
65
|
|
|
73
|
-
onViewportChange(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
height,
|
|
77
|
-
offsetX: event?.nativeEvent?.contentOffset?.x,
|
|
78
|
-
offsetY: event?.nativeEvent?.contentOffset?.y,
|
|
79
|
-
},
|
|
80
|
-
false
|
|
81
|
-
);
|
|
66
|
+
onViewportChange({
|
|
67
|
+
shouldMeasureLayout: false,
|
|
68
|
+
});
|
|
82
69
|
},
|
|
83
|
-
[onViewportChange
|
|
70
|
+
[onViewportChange]
|
|
84
71
|
);
|
|
85
72
|
|
|
86
|
-
|
|
73
|
+
React.useEffect(() => {
|
|
74
|
+
childrenRef.current = props.children;
|
|
75
|
+
}, [props.children]);
|
|
76
|
+
|
|
77
|
+
return React.cloneElement(React.Children.only(props.children), {
|
|
87
78
|
ref: assignRef,
|
|
88
79
|
onLayout,
|
|
89
80
|
onContentSizeChange,
|
|
@@ -6,6 +6,7 @@ import { ViewportEventContext, ViewportEvents } from "../ViewportEvents";
|
|
|
6
6
|
type Props = {
|
|
7
7
|
viewportEventsManager?: any;
|
|
8
8
|
children: React.ReactNode;
|
|
9
|
+
flatListRef?: any; // this ref is used to bind to children component
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export function ViewportTracker(props: Props) {
|
|
@@ -2,7 +2,7 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
export function callOnChildren(children, method, ...args) {
|
|
4
4
|
const childMethod = React.Children.only(children).props[method];
|
|
5
|
-
childMethod && childMethod(...args);
|
|
5
|
+
typeof childMethod === "function" && childMethod?.(...args);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export function isInViewport(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createContext } from "@applicaster/zapp-react-native-utils/reactUtils/createContext";
|
|
2
|
+
import React from "react";
|
|
2
3
|
|
|
3
4
|
const initialContext = { toggleMenu: {}, closeMenu: {}, openMenu: {} };
|
|
4
5
|
|
|
@@ -16,3 +17,18 @@ const stateValidator = ({ property }) =>
|
|
|
16
17
|
property === "openMenu";
|
|
17
18
|
|
|
18
19
|
export const MenuToggleContext = createContext(initialContext, stateValidator);
|
|
20
|
+
|
|
21
|
+
export type MenuToggleContextType = {
|
|
22
|
+
toggleMenu: any;
|
|
23
|
+
setToggleMenu: () => void;
|
|
24
|
+
openMenu: any;
|
|
25
|
+
setOpenMenu: () => void;
|
|
26
|
+
closeMenu: any;
|
|
27
|
+
setCloseMenu: () => void;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export const useMenuToggleContext = () => {
|
|
31
|
+
return React.useContext<MenuToggleContextType>(
|
|
32
|
+
MenuToggleContext.ReactContext
|
|
33
|
+
);
|
|
34
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { render } from "@testing-library/react-native";
|
|
2
|
+
import { ScreenContext, ScreenContextProvider, withScreenContext } from "../";
|
|
3
|
+
import React from "react";
|
|
4
|
+
|
|
5
|
+
describe("ScreenContext", () => {
|
|
6
|
+
describe("ScreneContext context", () => {
|
|
7
|
+
it("should return the context", () => {
|
|
8
|
+
expect(ScreenContext).toBeDefined();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe("ScreenContextProvider", () => {
|
|
13
|
+
it("should return the provider", () => {
|
|
14
|
+
expect(ScreenContextProvider).toBeDefined();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe("withScreenContext", () => {
|
|
19
|
+
it("should return the context", () => {
|
|
20
|
+
const Component = () => null;
|
|
21
|
+
const WrappedComponent = withScreenContext(Component);
|
|
22
|
+
const { toJSON } = render(<WrappedComponent />);
|
|
23
|
+
|
|
24
|
+
expect(toJSON()).toMatchSnapshot();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
createContext,
|
|
3
|
+
ReactNode,
|
|
4
|
+
useCallback,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
} from "react";
|
|
2
8
|
import {
|
|
3
9
|
useCurrentScreenData,
|
|
4
10
|
useNavigation,
|
|
@@ -7,27 +13,67 @@ import {
|
|
|
7
13
|
} from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
8
14
|
import { useModalNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/ModalNavigationContext";
|
|
9
15
|
import { useNestedNavigationContext } from "@applicaster/zapp-react-native-ui-components/Contexts/NestedNavigationContext";
|
|
16
|
+
import { create, StoreApi, UseBoundStore } from "zustand";
|
|
17
|
+
import { useShallow } from "zustand/react/shallow";
|
|
18
|
+
import { Animated } from "react-native";
|
|
19
|
+
|
|
20
|
+
interface NavBarStoreState {
|
|
21
|
+
visible: boolean;
|
|
22
|
+
title: string;
|
|
23
|
+
summary: string;
|
|
24
|
+
setVisible: (state: boolean) => void;
|
|
25
|
+
setTitle: (title: string) => void;
|
|
26
|
+
setSummary: (subtitle: string) => void;
|
|
27
|
+
height: number;
|
|
28
|
+
scrollState: number;
|
|
29
|
+
isOnBottomNavBar: boolean;
|
|
30
|
+
scrollYAnimated: Animated.Value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface NavBarState {
|
|
34
|
+
visible: boolean;
|
|
35
|
+
title: string;
|
|
36
|
+
summary: string;
|
|
37
|
+
setVisible: (state: boolean) => void;
|
|
38
|
+
setTitle: (title: string) => void;
|
|
39
|
+
setSummary: (subtitle: string) => void;
|
|
40
|
+
}
|
|
10
41
|
|
|
11
42
|
type ScreenContextType = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
title: string;
|
|
15
|
-
summary: string;
|
|
16
|
-
setVisible: (state: boolean) => void;
|
|
17
|
-
setTitle: (title: string) => void;
|
|
18
|
-
setSummary: (subtitle: string) => void;
|
|
19
|
-
};
|
|
43
|
+
_navBarStore: UseBoundStore<StoreApi<NavBarStoreState>>;
|
|
44
|
+
navBar: NavBarState;
|
|
20
45
|
legacyFormatScreenData: LegacyNavigationScreenData | null;
|
|
21
46
|
};
|
|
22
47
|
|
|
48
|
+
const createStore = () =>
|
|
49
|
+
create<NavBarStoreState>((set) => ({
|
|
50
|
+
title: "",
|
|
51
|
+
summary: "",
|
|
52
|
+
visible: true,
|
|
53
|
+
height: 0,
|
|
54
|
+
scrollState: 0,
|
|
55
|
+
isOnBottomNavBar: true,
|
|
56
|
+
scrollYAnimated: new Animated.Value(0),
|
|
57
|
+
setTitle(title) {
|
|
58
|
+
set({ title });
|
|
59
|
+
},
|
|
60
|
+
setSummary(summary) {
|
|
61
|
+
set({ summary });
|
|
62
|
+
},
|
|
63
|
+
setVisible(visible) {
|
|
64
|
+
set({ visible });
|
|
65
|
+
},
|
|
66
|
+
}));
|
|
67
|
+
|
|
23
68
|
export const ScreenContext = createContext<ScreenContextType>({
|
|
69
|
+
_navBarStore: createStore(),
|
|
24
70
|
navBar: {
|
|
25
71
|
visible: true,
|
|
26
72
|
title: "",
|
|
27
73
|
summary: "",
|
|
28
|
-
setVisible: (_state) =>
|
|
29
|
-
setTitle: (_title) =>
|
|
30
|
-
setSummary: (_subtitle) =>
|
|
74
|
+
setVisible: (_state) => void 0,
|
|
75
|
+
setTitle: (_title) => void 0,
|
|
76
|
+
setSummary: (_subtitle) => void 0,
|
|
31
77
|
},
|
|
32
78
|
legacyFormatScreenData: {} as LegacyNavigationScreenData,
|
|
33
79
|
});
|
|
@@ -53,9 +99,30 @@ export function ScreenContextProvider({
|
|
|
53
99
|
const isNested = useNestedNavigationContext();
|
|
54
100
|
const currentScreenScreenData = useCurrentScreenData();
|
|
55
101
|
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
102
|
+
const screenNavBarStateRef =
|
|
103
|
+
useRef<null | ReturnType<typeof createStore>>(null);
|
|
104
|
+
|
|
105
|
+
const getScreenNavBarState = useCallback(() => {
|
|
106
|
+
if (screenNavBarStateRef.current !== null) {
|
|
107
|
+
return screenNavBarStateRef.current;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const navBarState = createStore();
|
|
111
|
+
screenNavBarStateRef.current = navBarState;
|
|
112
|
+
|
|
113
|
+
return navBarState;
|
|
114
|
+
}, []);
|
|
115
|
+
|
|
116
|
+
const screenNavBarState = getScreenNavBarState()(
|
|
117
|
+
useShallow((state) => ({
|
|
118
|
+
visible: state.visible,
|
|
119
|
+
title: state.title,
|
|
120
|
+
summary: state.summary,
|
|
121
|
+
setTitle: state.setTitle,
|
|
122
|
+
setSummary: state.setSummary,
|
|
123
|
+
setVisible: state.setVisible,
|
|
124
|
+
}))
|
|
125
|
+
);
|
|
59
126
|
|
|
60
127
|
const isHook = pathname.includes("hook");
|
|
61
128
|
|
|
@@ -73,26 +140,28 @@ export function ScreenContextProvider({
|
|
|
73
140
|
const isVisible = isNavBarVisible(
|
|
74
141
|
pathname,
|
|
75
142
|
currentScreenScreenData, // what fallback should be if currentScreenData is not available?
|
|
76
|
-
|
|
143
|
+
screenNavBarState.visible,
|
|
77
144
|
canGoBack(isHook, pathname),
|
|
78
145
|
videoModalState
|
|
79
146
|
);
|
|
80
147
|
|
|
81
|
-
const navBarState = useMemo(
|
|
82
|
-
|
|
83
|
-
title:
|
|
84
|
-
summary:
|
|
148
|
+
const navBarState = useMemo(
|
|
149
|
+
() => ({
|
|
150
|
+
title: screenNavBarState.title,
|
|
151
|
+
summary: screenNavBarState.summary,
|
|
85
152
|
visible: isVisible,
|
|
86
|
-
setTitle:
|
|
87
|
-
setSummary:
|
|
88
|
-
setVisible:
|
|
89
|
-
}
|
|
90
|
-
|
|
153
|
+
setTitle: screenNavBarState.setTitle,
|
|
154
|
+
setSummary: screenNavBarState.setSummary,
|
|
155
|
+
setVisible: screenNavBarState.setVisible,
|
|
156
|
+
}),
|
|
157
|
+
[isVisible, screenNavBarState.title, screenNavBarState.summary]
|
|
158
|
+
);
|
|
91
159
|
|
|
92
160
|
return (
|
|
93
161
|
<ScreenContext.Provider
|
|
94
162
|
value={useMemo(
|
|
95
163
|
() => ({
|
|
164
|
+
_navBarStore: getScreenNavBarState(),
|
|
96
165
|
navBar: navBarState,
|
|
97
166
|
legacyFormatScreenData: routeScreenData,
|
|
98
167
|
}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.7921075302",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"redux-mock-store": "^1.5.3"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@applicaster/applicaster-types": "12.0.0-alpha.
|
|
38
|
-
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.
|
|
39
|
-
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.
|
|
40
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
37
|
+
"@applicaster/applicaster-types": "12.0.0-alpha.7921075302",
|
|
38
|
+
"@applicaster/zapp-react-native-bridge": "12.0.0-alpha.7921075302",
|
|
39
|
+
"@applicaster/zapp-react-native-redux": "12.0.0-alpha.7921075302",
|
|
40
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.7921075302",
|
|
41
41
|
"promise": "^8.3.0",
|
|
42
42
|
"react-router-native": "^5.1.2",
|
|
43
43
|
"url": "^0.11.0",
|
|
File without changes
|