@applicaster/zapp-react-native-ui-components 12.0.0-alpha.8417280639 → 12.0.0-alpha.8690239043
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/Layout/TV/index.tsx +12 -9
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +2 -0
- package/Components/MasterCell/DefaultComponents/DynamicBadge.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
- package/Components/MasterCell/DefaultComponents/ImageContainer/index.tsx +5 -1
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +14 -2
- package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
- package/Components/MasterCell/DefaultComponents/__tests__/text.test.tsx +24 -9
- package/Components/MasterCell/SharedUI/CollapsibleTextContainer/index.ts +1 -3
- package/Components/MasterCell/hooks/useAsyncRendering/index.ts +1 -1
- package/Components/MeasurmentsPortal/BasicMeasurementsPortal.tsx +11 -7
- package/Components/MeasurmentsPortal/MeasurementsPortal.tsx +10 -1
- package/Components/PlayerContainer/PlayerContainer.tsx +9 -5
- package/Components/River/ComponentsMap/ComponentsMap.tsx +92 -22
- package/Components/River/RefreshControl.tsx +55 -1
- package/Components/RouteManager/index.tsx +2 -2
- package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
- package/Components/Screen/index.tsx +35 -24
- package/Components/Transitioner/Scene.tsx +24 -19
- package/Components/Transitioner/Transitioner.tsx +9 -2
- package/Components/Transitioner/__tests__/__snapshots__/Scene.test.js.snap +6 -2
- package/Components/Transitioner/__tests__/__snapshots__/transitioner.test.js.snap +1 -0
- package/Components/VideoLive/LiveImageManager.ts +3 -0
- 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/VideoModal/ModalAnimation/ModalAnimationContext.tsx +13 -2
- package/Components/VideoModal/PlayerWrapper.tsx +67 -60
- package/Components/VideoModal/VideoModal.tsx +19 -19
- package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +7 -0
- 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/Contexts/ScreenDataContext/index.ts +3 -0
- package/events/index.ts +1 -0
- 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) {
|
|
@@ -20,6 +20,7 @@ import { ScreenLayoutContextProvider } from "./ScreenLayoutContextProvider";
|
|
|
20
20
|
import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
|
|
21
21
|
import { PathnameContext } from "../../../Contexts/PathnameContext";
|
|
22
22
|
import { useNavbarState } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useScreenContext";
|
|
23
|
+
import { ScreenDataContext } from "../../../Contexts/ScreenDataContext";
|
|
23
24
|
|
|
24
25
|
type Components = {
|
|
25
26
|
NavBar: React.ComponentType<any>;
|
|
@@ -105,20 +106,22 @@ const Layout = ({ Components, ComponentsExtraProps, children }: Props) => {
|
|
|
105
106
|
backgroundImageUrl={backgroundImageUrl}
|
|
106
107
|
{...R.omit(["ref"])(ComponentsExtraProps?.Background)}
|
|
107
108
|
>
|
|
108
|
-
{
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
<ScreenDataContext.Provider value={navigator.data}>
|
|
110
|
+
<PathnameContext.Provider value={navigator.currentRoute}>
|
|
111
|
+
{!isTVOS ? navBarContainer : null}
|
|
112
|
+
{navBarReady ? (
|
|
113
|
+
/**
|
|
111
114
|
Need to re-mount this component on each navigation event
|
|
112
115
|
It's a hack to work around the fact that we don't support
|
|
113
116
|
correct screen rendering in our navigator (shared currentRoute state)
|
|
114
117
|
**/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
) : null}
|
|
119
|
-
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
118
|
+
<ScreenContainer>{children}</ScreenContainer>
|
|
119
|
+
) : null}
|
|
120
|
+
{/** Render NavBarContainer over ScreenContainer to let tvOS native
|
|
120
121
|
focus manager works correctly to focus nav bar items first **/}
|
|
121
|
-
|
|
122
|
+
{isTVOS ? navBarContainer : null}
|
|
123
|
+
</PathnameContext.Provider>
|
|
124
|
+
</ScreenDataContext.Provider>
|
|
122
125
|
<TransitionOverlay />
|
|
123
126
|
</Components.Background>
|
|
124
127
|
</ScreenLayoutContextProvider>
|
|
@@ -25,6 +25,7 @@ type Props = {
|
|
|
25
25
|
testID?: string;
|
|
26
26
|
accessibilityLabel?: string;
|
|
27
27
|
cellUUID?: string;
|
|
28
|
+
extraProps?: Record<string, any>;
|
|
28
29
|
};
|
|
29
30
|
|
|
30
31
|
function isStringAsset(asset) {
|
|
@@ -108,6 +109,7 @@ export function ActionButton(props: Props) {
|
|
|
108
109
|
flavour={flavour}
|
|
109
110
|
asset={getAssetValue(asset, flavour)}
|
|
110
111
|
cellUUID={cellUUID}
|
|
112
|
+
{...(props?.extraProps ?? {})}
|
|
111
113
|
/>
|
|
112
114
|
)}
|
|
113
115
|
</TouchableOpacity>
|
|
@@ -4,6 +4,7 @@ import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerM
|
|
|
4
4
|
|
|
5
5
|
type DynamicBadgeProps = {
|
|
6
6
|
cellUUID?: string;
|
|
7
|
+
uri?: string;
|
|
7
8
|
};
|
|
8
9
|
|
|
9
10
|
const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
|
|
@@ -12,11 +13,12 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
|
|
|
12
13
|
// TODO: Initial value should depends on player state (playing or not)
|
|
13
14
|
const [showImage, setShowImage] = React.useState(true);
|
|
14
15
|
const player = usePlayer(playerId);
|
|
16
|
+
const uri = props?.uri;
|
|
15
17
|
|
|
16
18
|
React.useEffect(() => {
|
|
17
19
|
if (playerId && player) {
|
|
18
20
|
return player.addListener({
|
|
19
|
-
id:
|
|
21
|
+
id: `dynamic-badges-${uri}`,
|
|
20
22
|
listener: {
|
|
21
23
|
onPlayerClose: () => {
|
|
22
24
|
setShowImage(true);
|
|
@@ -35,7 +37,7 @@ const DynamicBadgeComponent = (props: DynamicBadgeProps) => {
|
|
|
35
37
|
} else {
|
|
36
38
|
setShowImage(true);
|
|
37
39
|
}
|
|
38
|
-
}, [player]);
|
|
40
|
+
}, [player, uri]);
|
|
39
41
|
|
|
40
42
|
if (!showImage) {
|
|
41
43
|
return null;
|
|
@@ -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
|
);
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { isVideoPreviewEnabled } from "@applicaster/zapp-react-native-ui-components/Components/MasterCell/utils";
|
|
3
3
|
import { LiveImage } from "../LiveImage";
|
|
4
4
|
import PureImage from "../Image";
|
|
5
|
+
import { useIsScreenActive } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
5
6
|
|
|
6
7
|
type Props = {
|
|
7
8
|
enable_video_preview: boolean;
|
|
@@ -9,7 +10,10 @@ type Props = {
|
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
export const ImageContainer = (props: Props) => {
|
|
12
|
-
const
|
|
13
|
+
const isActive = useIsScreenActive();
|
|
14
|
+
|
|
15
|
+
const Component =
|
|
16
|
+
isVideoPreviewEnabled(props) && isActive ? LiveImage : PureImage;
|
|
13
17
|
|
|
14
18
|
return <Component {...props} />;
|
|
15
19
|
};
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Text } from "react-native";
|
|
3
3
|
import { omit } from "ramda";
|
|
4
|
-
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
5
4
|
import {
|
|
6
5
|
textTransform,
|
|
7
6
|
dateFormat,
|
|
@@ -9,6 +8,9 @@ import {
|
|
|
9
8
|
|
|
10
9
|
import { useTextLabel, withFocusedStyles } from "./hooks";
|
|
11
10
|
import { withScaledLineHeight } from "./utils";
|
|
11
|
+
import { toNumber } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
12
|
+
import { MeasurementPortalContext } from "../../../MeasurmentsPortal";
|
|
13
|
+
import { isNilOrEmpty } from "@applicaster/zapp-react-native-utils/reactUtils/helpers";
|
|
12
14
|
|
|
13
15
|
type Props = {
|
|
14
16
|
style: any;
|
|
@@ -32,14 +34,24 @@ const _Text = ({
|
|
|
32
34
|
...otherProps
|
|
33
35
|
}: Props) => {
|
|
34
36
|
const _label = useTextLabel({ label, entry });
|
|
37
|
+
const isMeasurement = React.useContext(MeasurementPortalContext);
|
|
35
38
|
|
|
36
39
|
if (isNilOrEmpty(_label)) {
|
|
37
40
|
return null;
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
// set maximum possible height for the text in case of measurement
|
|
44
|
+
const height =
|
|
45
|
+
isMeasurement && otherProps.numberOfLines && style.lineHeight
|
|
46
|
+
? toNumber(otherProps.numberOfLines) * toNumber(style.lineHeight)
|
|
47
|
+
: undefined;
|
|
48
|
+
|
|
40
49
|
return (
|
|
41
50
|
<Text
|
|
42
|
-
style={
|
|
51
|
+
style={[
|
|
52
|
+
withScaledLineHeight(withFocusedStyles({ style, otherProps })),
|
|
53
|
+
{ height },
|
|
54
|
+
]}
|
|
43
55
|
{...withoutLabel(otherProps)}
|
|
44
56
|
>
|
|
45
57
|
{dateTransformEnabled
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import
|
|
2
|
+
import RN from "react-native";
|
|
3
3
|
import { Provider } from "react-redux";
|
|
4
4
|
import TestRenderer from "react-test-renderer";
|
|
5
|
-
import
|
|
6
|
-
import CustomText from "../Text";
|
|
5
|
+
import configureStoreFn from "redux-mock-store";
|
|
7
6
|
|
|
8
|
-
const
|
|
7
|
+
const mockUseIsRTL = jest.fn(() => true);
|
|
8
|
+
const mockGetIsRTL = jest.fn(() => true);
|
|
9
|
+
const mockUseLocalizedStrings = jest.fn(() => ({}));
|
|
10
|
+
const mockGetUILanguage = jest.fn(() => "he-HE");
|
|
11
|
+
|
|
12
|
+
jest.mock("@applicaster/zapp-react-native-utils/localizationUtils", () => ({
|
|
13
|
+
useIsRTL: mockUseIsRTL,
|
|
14
|
+
getIsRTL: mockGetIsRTL,
|
|
15
|
+
useLocalizedStrings: mockUseLocalizedStrings,
|
|
16
|
+
getUILanguage: mockGetUILanguage,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
const CustomText = require("../Text").default;
|
|
20
|
+
const mockStore = configureStoreFn();
|
|
9
21
|
|
|
10
22
|
const defaultProps = {
|
|
11
23
|
entry: {},
|
|
@@ -22,7 +34,7 @@ const getRenderedText = (label: string, store: any) => {
|
|
|
22
34
|
</Provider>
|
|
23
35
|
);
|
|
24
36
|
|
|
25
|
-
return testRenderer.root.findByType(Text).props.children;
|
|
37
|
+
return testRenderer.root.findByType(RN.Text).props.children;
|
|
26
38
|
};
|
|
27
39
|
|
|
28
40
|
describe("RTL app: Hebrew text contains english word", () => {
|
|
@@ -34,7 +46,7 @@ describe("RTL app: Hebrew text contains english word", () => {
|
|
|
34
46
|
remoteConfigurations: { localizations: { he: {} } },
|
|
35
47
|
appData: {
|
|
36
48
|
languageCode: "he",
|
|
37
|
-
countryCode: "
|
|
49
|
+
countryCode: "IL",
|
|
38
50
|
},
|
|
39
51
|
});
|
|
40
52
|
|
|
@@ -47,18 +59,22 @@ describe("RTL app: Hebrew text contains english word", () => {
|
|
|
47
59
|
|
|
48
60
|
it("Hebrew text contains not first english word", () => {
|
|
49
61
|
const renderedText = getRenderedText(textWithNotFirstEnglishWord, store);
|
|
50
|
-
|
|
51
62
|
expect(renderedText).toEqual(textWithNotFirstEnglishWord);
|
|
52
63
|
});
|
|
53
64
|
|
|
54
65
|
it("Hebrew text doesn't contain english word", () => {
|
|
55
66
|
const renderedText = getRenderedText(textWithoutEnglishWord, store);
|
|
56
|
-
|
|
57
67
|
expect(renderedText).toEqual(textWithoutEnglishWord);
|
|
58
68
|
});
|
|
59
69
|
});
|
|
60
70
|
|
|
61
71
|
describe("LTR app: English text", () => {
|
|
72
|
+
beforeAll(() => {
|
|
73
|
+
mockUseIsRTL.mockReturnValue(false);
|
|
74
|
+
mockGetIsRTL.mockReturnValue(false);
|
|
75
|
+
mockGetUILanguage.mockReturnValue("en-US");
|
|
76
|
+
});
|
|
77
|
+
|
|
62
78
|
const englishText = "Test sentence";
|
|
63
79
|
|
|
64
80
|
const store = mockStore({
|
|
@@ -71,7 +87,6 @@ describe("LTR app: English text", () => {
|
|
|
71
87
|
|
|
72
88
|
it("English text", () => {
|
|
73
89
|
const renderedText = getRenderedText(englishText, store);
|
|
74
|
-
|
|
75
90
|
expect(renderedText).toEqual(englishText);
|
|
76
91
|
});
|
|
77
92
|
});
|
|
@@ -51,9 +51,7 @@ export const CollapsibleTextContainer = ({
|
|
|
51
51
|
func: (data) => {
|
|
52
52
|
return getColorFromData({
|
|
53
53
|
data,
|
|
54
|
-
|
|
55
|
-
key: "background_color",
|
|
56
|
-
defaultColor: additionalStyles.backgroundColor,
|
|
54
|
+
valueFromLayout: additionalStyles.backgroundColor,
|
|
57
55
|
});
|
|
58
56
|
},
|
|
59
57
|
propName: "backgroundColor",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { View, StyleSheet } from "react-native";
|
|
3
|
+
import { MeasurementPortalContext } from "./MeasurementsPortal";
|
|
3
4
|
|
|
4
5
|
type Props = {
|
|
5
6
|
Component: React.ElementType;
|
|
@@ -19,13 +20,16 @@ const _MeasurementsPortal = (
|
|
|
19
20
|
{ Component, onLayout, componentProps, containerStyle }: Props,
|
|
20
21
|
ref
|
|
21
22
|
) => (
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
// hack for cell to determine if cell is in measurement mode
|
|
24
|
+
<MeasurementPortalContext.Provider value={{}}>
|
|
25
|
+
<View
|
|
26
|
+
onLayout={onLayout}
|
|
27
|
+
style={[styles.container, containerStyle]}
|
|
28
|
+
ref={ref}
|
|
29
|
+
>
|
|
30
|
+
<Component {...componentProps} />
|
|
31
|
+
</View>
|
|
32
|
+
</MeasurementPortalContext.Provider>
|
|
29
33
|
);
|
|
30
34
|
|
|
31
35
|
export const MeasurementsPortal = React.forwardRef(_MeasurementsPortal);
|
|
@@ -35,7 +35,16 @@ const MeasurementsPortal = ({ Component, onLayout, componentProps }: Props) => {
|
|
|
35
35
|
);
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
type MeasurementPortalContextType = {
|
|
39
|
+
measureComponent?: (
|
|
40
|
+
comp: React.ElementType,
|
|
41
|
+
props: Record<any, any>
|
|
42
|
+
) => Promise<any>;
|
|
43
|
+
measuringInProgress?: boolean;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const MeasurementPortalContext =
|
|
47
|
+
React.createContext<null | MeasurementPortalContextType>(null);
|
|
39
48
|
|
|
40
49
|
const MeasurementsPortalContextProvider = ({ children }) => {
|
|
41
50
|
const Component = React.useRef(View);
|
|
@@ -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
|
|
@@ -668,6 +671,7 @@ const PlayerContainerComponent = (props: Props) => {
|
|
|
668
671
|
setNextVideoPreloadThresholdPercentage={
|
|
669
672
|
setNextVideoPreloadThresholdPercentage
|
|
670
673
|
}
|
|
674
|
+
startComponentsAnimation={startComponentsAnimation}
|
|
671
675
|
>
|
|
672
676
|
{renderApplePlayer(applePlayerProps)}
|
|
673
677
|
</Player>
|
|
@@ -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,87 @@ 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
|
+
} else {
|
|
275
|
+
if (y <= 0) {
|
|
276
|
+
scrollY.setValue(0);
|
|
277
|
+
} else if (y + height > contentHeight) {
|
|
278
|
+
scrollY.setValue(contentHeight - height);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}, []);
|
|
217
282
|
|
|
218
283
|
if (shouldShowLoadingError) {
|
|
219
284
|
return <RiverError />;
|
|
@@ -230,6 +295,9 @@ function ComponentsMapComponent(props: Props) {
|
|
|
230
295
|
>
|
|
231
296
|
<ViewportTracker>
|
|
232
297
|
<FlatList
|
|
298
|
+
ref={(ref) => {
|
|
299
|
+
flatListRef.current = ref;
|
|
300
|
+
}}
|
|
233
301
|
// Fix for WebView rerender crashes on Android API 28+
|
|
234
302
|
// https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
|
|
235
303
|
overScrollMode={Platform.OS === "android" ? "never" : "auto"}
|
|
@@ -249,8 +317,10 @@ function ComponentsMapComponent(props: Props) {
|
|
|
249
317
|
}
|
|
250
318
|
ListFooterComponent={renderFooter}
|
|
251
319
|
refreshControl={refreshControl}
|
|
252
|
-
|
|
253
|
-
|
|
320
|
+
onScrollBeginDrag={onScrollBeginDrag}
|
|
321
|
+
onScroll={onScroll}
|
|
322
|
+
onMomentumScrollEnd={_onMomentumScrollEnd}
|
|
323
|
+
onScrollEndDrag={_onScrollEndDrag}
|
|
254
324
|
scrollEventThrottle={16}
|
|
255
325
|
{...scrollViewExtraProps}
|
|
256
326
|
/>
|