@applicaster/zapp-react-native-ui-components 12.0.0-alpha.4757075613 → 12.0.0-alpha.4837064762

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.
Files changed (44) hide show
  1. package/Components/BaseFocusable/index.tsx +1 -1
  2. package/Components/Cell/Cell.tsx +5 -1
  3. package/Components/Cell/CellWithFocusable.tsx +17 -5
  4. package/Components/FocusableGroup/index.tsx +1 -0
  5. package/Components/HandlePlayable/HandlePlayable.tsx +3 -0
  6. package/Components/Layout/TV/ScreenLayoutContextProvider.tsx +2 -2
  7. package/Components/Layout/TV/index.tsx +124 -25
  8. package/Components/MasterCell/DefaultComponents/Image/Image.ios.tsx +5 -3
  9. package/Components/MasterCell/DefaultComponents/LiveImage/index.tsx +14 -1
  10. package/Components/MasterCell/DefaultComponents/__tests__/image.test.js +1 -1
  11. package/Components/MasterCell/utils/index.ts +16 -5
  12. package/Components/PlayerContainer/PlayerContainer.tsx +17 -3
  13. package/Components/PlayerImageBackground/index.tsx +34 -8
  14. package/Components/River/ComponentsMap/ComponentsMap.tsx +85 -22
  15. package/Components/River/__tests__/componentsMap.test.js +6 -0
  16. package/Components/Screen/TV/index.web.tsx +151 -0
  17. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +4 -0
  18. package/Components/Screen/index.tsx +35 -24
  19. package/Components/ScreenResolver/index.tsx +3 -1
  20. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +20 -5
  21. package/Components/VideoLive/__tests__/__snapshots__/PlayerLiveImageComponent.test.tsx.snap +0 -5
  22. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  23. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +342 -0
  24. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +151 -0
  25. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  26. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
  27. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  28. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  29. package/Components/VideoModal/PlayerWrapper.tsx +64 -41
  30. package/Components/VideoModal/VideoModal.tsx +8 -25
  31. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +6 -1
  32. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +151 -119
  33. package/Components/VideoModal/utils.ts +3 -3
  34. package/Components/Viewport/ViewportTracker/ViewportTracker.tsx +1 -1
  35. package/Components/Viewport/ViewportTracker/index.tsx +1 -0
  36. package/Components/Viewport/utils.js +1 -1
  37. package/Contexts/MenuToggleContext/{index.js → index.ts} +16 -0
  38. package/Contexts/ScreenContext/__tests__/__snapshots__/index.test.tsx.snap +3 -0
  39. package/Contexts/ScreenContext/__tests__/index.test.tsx +27 -0
  40. package/Contexts/ScreenContext/index.tsx +94 -25
  41. package/Contexts/ZappPipesContext/ZappPipesEntryContext.ts +1 -1
  42. package/package.json +5 -5
  43. package/Components/VideoModal/hooks/usePosition.ts +0 -50
  44. /package/Contexts/{index.js → index.ts} +0 -0
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import * as R from "ramda";
3
- import { View, FlatList, StyleSheet, Platform } from "react-native";
3
+ import { View, StyleSheet, Platform, Animated, 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 { useScreenScrollStore } from "@applicaster/zapp-react-native-utils/screenState";
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 scrollIndicatorInsets = { right: 1 };
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,67 @@ function ComponentsMapComponent(props: Props) {
194
198
  []
195
199
  );
196
200
 
197
- const onScrollFlatList = React.useCallback(
198
- ({ nativeEvent }, isScrollingDone = false) => {
199
- const {
200
- contentOffset: { y },
201
- } = nativeEvent;
201
+ const navBarStore = useScreenContextV2()._navBarStore;
202
202
 
203
- useScreenScrollStore.setState({
204
- scrollingVelocity: isScrollingDone ? 0 : 1,
205
- scrollPosition: y,
206
- });
207
- },
208
- []
203
+ const scrollY = navBarStore(
204
+ useShallow(({ scrollYAnimated }) => scrollYAnimated)
209
205
  );
210
206
 
211
- const onMomentumScrollEnd = React.useCallback(
212
- ({ nativeEvent }) => {
213
- onScrollFlatList({ nativeEvent }, true);
214
- },
215
- [onScrollFlatList]
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 = 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 = 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
+ }, []);
217
262
 
218
263
  if (shouldShowLoadingError) {
219
264
  return <RiverError />;
@@ -230,6 +275,9 @@ function ComponentsMapComponent(props: Props) {
230
275
  >
231
276
  <ViewportTracker>
232
277
  <FlatList
278
+ ref={(ref) => {
279
+ flatListRef.current = ref;
280
+ }}
233
281
  // Fix for WebView rerender crashes on Android API 28+
234
282
  // https://github.com/react-native-webview/react-native-webview/issues/1915#issuecomment-964035468
235
283
  overScrollMode={Platform.OS === "android" ? "never" : "auto"}
@@ -249,8 +297,23 @@ function ComponentsMapComponent(props: Props) {
249
297
  }
250
298
  ListFooterComponent={renderFooter}
251
299
  refreshControl={refreshControl}
252
- onScroll={onScrollFlatList}
253
- onMomentumScrollEnd={onMomentumScrollEnd}
300
+ onScrollBeginDrag={onScrollBeginDrag}
301
+ onScroll={Animated.event(
302
+ [
303
+ {
304
+ nativeEvent: {
305
+ contentOffset: {
306
+ y: scrollY,
307
+ },
308
+ },
309
+ },
310
+ ],
311
+ {
312
+ useNativeDriver: false,
313
+ }
314
+ )}
315
+ onMomentumScrollEnd={_onMomentumScrollEnd}
316
+ onScrollEndDrag={_onScrollEndDrag}
254
317
  scrollEventThrottle={16}
255
318
  {...scrollViewExtraProps}
256
319
  />
@@ -6,6 +6,12 @@ import configureStore from "redux-mock-store";
6
6
 
7
7
  import * as themeUtils from "@applicaster/zapp-react-native-utils/theme";
8
8
 
9
+ // silences the errors related to React-native-gesture-handler in tests
10
+ jest.mock(
11
+ "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation",
12
+ () => () => null
13
+ );
14
+
9
15
  jest.mock("react-native-safe-area-context", () => ({
10
16
  useSafeAreaInsets: () => ({ top: 50 }),
11
17
  }));
@@ -0,0 +1,151 @@
1
+ import * as React from "react";
2
+ import { last, pathOr } from "ramda";
3
+ import { ScreenResolver } from "../../ScreenResolver";
4
+ import {
5
+ getNavigationProps,
6
+ getPathAttributes,
7
+ resolveNavigationPlugin,
8
+ } from "@applicaster/zapp-react-native-utils/navigationUtils";
9
+ import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
10
+ import { NavBarContainer } from "../../Layout/TV/NavBarContainer";
11
+ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
12
+ import { usePickFromState } from "@applicaster/zapp-react-native-redux/hooks";
13
+
14
+ type Components = {
15
+ NavBar: React.ComponentType<any>;
16
+ Background: React.ComponentType<any>;
17
+ };
18
+
19
+ type Props = {
20
+ route: string;
21
+ Components: Components;
22
+ };
23
+
24
+ const isPlayer = (routeState): boolean => {
25
+ const pluginType = pathOr(
26
+ "unknown_plugin_type",
27
+ ["state", "screen", "plugin_type"],
28
+ routeState
29
+ );
30
+
31
+ return pluginType === "player";
32
+ };
33
+
34
+ const getActiveRiver = ({
35
+ screenId,
36
+ screenType,
37
+ routeState,
38
+ rivers,
39
+ fallbackActiveRiver,
40
+ }) => {
41
+ if (rivers[screenId]) {
42
+ // river presents
43
+ return screenType === "hooks"
44
+ ? routeState?.state?.entry?.payload
45
+ : routeState?.state?.screen;
46
+ }
47
+
48
+ // screenId is not presented into rivers, use fallback instead
49
+ return fallbackActiveRiver;
50
+ };
51
+
52
+ const getNavigations = ({
53
+ screenId,
54
+ screenType,
55
+ routeState,
56
+ rivers,
57
+ fallbackNavigations,
58
+ }) => {
59
+ if (rivers[screenId]) {
60
+ // river presents
61
+ return screenType === "hooks"
62
+ ? routeState?.state?.entry?.payload.navigations
63
+ : routeState?.state?.screen?.navigations;
64
+ }
65
+
66
+ // screenId is not presented into rivers, use fallback instead
67
+ return fallbackNavigations;
68
+ };
69
+
70
+ export const Screen = (props: Props) => {
71
+ if (!props.route) {
72
+ throw new Error("Required props route is missing");
73
+ }
74
+
75
+ const navigator = useNavigation();
76
+ const { plugins = [], rivers = [] } = usePickFromState(["plugins", "rivers"]);
77
+
78
+ const pathAttributes = getPathAttributes({ pathname: props.route });
79
+ const routeState = navigator.getStackForPathname(props.route);
80
+
81
+ const { screenType, screenId } = last(pathAttributes);
82
+
83
+ // console.log("debug_2", "Screen", {
84
+ // screenType,
85
+ // routeState,
86
+ // route: props.route,
87
+ // navigator,
88
+ // });
89
+
90
+ const activeRiver = getActiveRiver({
91
+ screenId,
92
+ screenType,
93
+ routeState,
94
+ rivers,
95
+ fallbackActiveRiver: navigator.activeRiver,
96
+ });
97
+
98
+ const navigationProps = getNavigationProps({
99
+ navigator: {
100
+ // @ts-ignore
101
+ activeRiver,
102
+ // @ts-ignore
103
+ screenTitle: routeState.state.entry?.title || routeState.screen?.name,
104
+ },
105
+ category: "menu",
106
+ });
107
+
108
+ const navigations = getNavigations({
109
+ screenId,
110
+ screenType,
111
+ routeState,
112
+ rivers,
113
+ fallbackNavigations: navigator.activeRiver.navigations,
114
+ });
115
+
116
+ const menuPlugin = resolveNavigationPlugin({
117
+ category: "menu",
118
+ navigations,
119
+ plugins,
120
+ }) as QuickBrickPlugin;
121
+
122
+ const NavBar = (props.Components.NavBar ||
123
+ menuPlugin.module) as React.ComponentType<any>;
124
+
125
+ const isNavBarVisible = !isPlayer(routeState);
126
+
127
+ const screenData =
128
+ screenType === "hooks"
129
+ ? routeState?.state?.entry
130
+ : routeState?.state?.screen;
131
+
132
+ return (
133
+ <>
134
+ <NavBarContainer isVisible={isNavBarVisible} onReady={noop}>
135
+ <NavBar
136
+ groupId={props.route}
137
+ isVisible={isNavBarVisible}
138
+ menuPlugin={menuPlugin}
139
+ navigationProps={navigationProps}
140
+ // Maybe activeRiver?
141
+ />
142
+ </NavBarContainer>
143
+ <ScreenResolver
144
+ screenType={screenType}
145
+ screenId={screenId}
146
+ screenData={screenData}
147
+ groupId={props.route}
148
+ />
149
+ </>
150
+ );
151
+ };
@@ -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 { getNavigationPropsV2 } from "@applicaster/zapp-react-native-utils/navigationUtils";
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
- setToggleMenu: () => void;
56
- setCloseMenu: () => void;
58
+ pathname: unknown;
59
+ screenData: unknown;
57
60
  };
58
61
 
59
- export function Screen({ setToggleMenu, setCloseMenu }: Props) {
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 routeData = useRoute();
76
+ const { screenData, pathname } = useRoute();
74
77
 
75
78
  const currentRiver = useScreenData(
76
- getScreenId(routeData.screenData, navigation.activeRiver)
79
+ getScreenId(screenData, navigation.activeRiver)
77
80
  );
78
81
 
79
82
  const { title } = useNavbarState();
80
83
 
81
- const navBarProps = React.useMemo(
82
- () => ({
83
- ...getNavigationPropsV2({
84
- currentRiver,
85
- title,
86
- category: "nav_bar",
87
- }),
88
- setToggleMenu,
89
- setCloseMenu,
90
- }),
91
- [currentRiver, setCloseMenu, setToggleMenu]
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 ? */}
@@ -32,12 +32,13 @@ type Props = {
32
32
  nextFocusLeft?: React.Ref<any>;
33
33
  nextFocusUp?: React.Ref<any>;
34
34
  };
35
+ groupId?: string;
35
36
  };
36
37
 
37
38
  export function ScreenResolverComponent(props: Props) {
38
39
  useScreenAnalytics(props);
39
40
 
40
- const { screenType, screenId, screenData } = props;
41
+ const { screenType, screenId, screenData, groupId } = props;
41
42
 
42
43
  const { hookPlugin } = screenData || {};
43
44
 
@@ -81,6 +82,7 @@ export function ScreenResolverComponent(props: Props) {
81
82
  item={screenData}
82
83
  mode={mode === "PIP" ? "PIP" : "FULLSCREEN"}
83
84
  isModal={false}
85
+ groupId={groupId}
84
86
  />
85
87
  );
86
88
  }
@@ -7,6 +7,10 @@ import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
7
7
  import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
8
8
 
9
9
  import { PlayerLiveImage } from "../PlayerLiveImageComponent";
10
+ import * as useNavigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
11
+
12
+ import { Provider } from "react-redux";
13
+ import configureStore from "redux-mock-store";
10
14
 
11
15
  const seekTo = jest.fn();
12
16
 
@@ -19,14 +23,25 @@ jest.mock(
19
23
  })
20
24
  );
21
25
 
26
+ jest
27
+ .spyOn(useNavigationHooks, "useNavigation")
28
+ .mockImplementation(() => ({ videoModalState: { visible: false } }));
29
+
22
30
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
23
31
 
32
+ const mockStore = configureStore();
33
+
34
+ const store = mockStore({ appData: {} });
35
+
24
36
  const Wrapper = ({ children }: { children: React.ReactChildren }) => (
25
- <ThemeContext.Provider
26
- value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
27
- >
28
- {children}
29
- </ThemeContext.Provider>
37
+ /* @ts-ignore */
38
+ <Provider store={store}>
39
+ <ThemeContext.Provider
40
+ value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
41
+ >
42
+ {children}
43
+ </ThemeContext.Provider>
44
+ </Provider>
30
45
  );
31
46
 
32
47
  describe("PlayerLiveImageComponent", () => {
@@ -30,11 +30,6 @@ exports[`PlayerLiveImageComponent should render correctly with default props 1`]
30
30
  playerId="player1"
31
31
  resizeMode="cover"
32
32
  screenConfig={Object {}}
33
- source={
34
- Object {
35
- "uri": "",
36
- }
37
- }
38
33
  style={Object {}}
39
34
  />
40
35
  </View>
@@ -0,0 +1,78 @@
1
+ import React from "react";
2
+ import { Animated, ViewStyle } from "react-native";
3
+
4
+ import {
5
+ useModalAnimationContext,
6
+ PlayerAnimationStateEnum,
7
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
+ import { useDimensions } from "@applicaster/zapp-react-native-utils/reactHooks";
9
+
10
+ type Props = {
11
+ style: ViewStyle[];
12
+ children: React.ReactNode;
13
+ };
14
+
15
+ export const AnimatedPlayerModalWrapper = (props: Props) => {
16
+ const {
17
+ playerAnimationState,
18
+ animatedValues: { lastScrollY, dragScrollY, translateYOffset },
19
+ modalSnapPoints,
20
+ setStartComponentsAnimation,
21
+ lastScrollYValue,
22
+ } = useModalAnimationContext();
23
+
24
+ const { height: screenHeight } = useDimensions("screen", {
25
+ deviceInfo: true,
26
+ });
27
+
28
+ const interpolateConfig: Animated.InterpolationConfigType = React.useMemo(
29
+ () => ({
30
+ inputRange: modalSnapPoints,
31
+ outputRange: modalSnapPoints,
32
+ extrapolate: "clamp",
33
+ }),
34
+ [modalSnapPoints]
35
+ );
36
+
37
+ let translateY;
38
+
39
+ if (playerAnimationState === PlayerAnimationStateEnum.drag_player) {
40
+ translateY = translateYOffset.interpolate(interpolateConfig);
41
+ } else {
42
+ const reverseLastScrollY = Animated.multiply(
43
+ new Animated.Value(-1),
44
+ lastScrollY
45
+ );
46
+
47
+ translateY = Animated.add(
48
+ translateYOffset,
49
+ Animated.add(dragScrollY, reverseLastScrollY)
50
+ ).interpolate(interpolateConfig);
51
+ }
52
+
53
+ React.useEffect(() => {
54
+ const translateYListener = translateY.addListener(({ value }) => {
55
+ const preparedValue = Math.round(
56
+ Math.abs(value) - lastScrollYValue.current
57
+ );
58
+
59
+ (playerAnimationState === PlayerAnimationStateEnum.minimize ||
60
+ playerAnimationState === PlayerAnimationStateEnum.maximaze) &&
61
+ setStartComponentsAnimation(
62
+ preparedValue >= Math.round((screenHeight * 10) / 100)
63
+ );
64
+ });
65
+
66
+ return () => {
67
+ translateYListener && translateY.removeListener(translateYListener);
68
+ };
69
+ }, [playerAnimationState]);
70
+
71
+ return (
72
+ <Animated.View
73
+ style={[props.style, { transform: [{ translateY: translateY }] }]}
74
+ >
75
+ {props.children}
76
+ </Animated.View>
77
+ );
78
+ };