@applicaster/zapp-react-native-ui-components 12.0.0-alpha.9262886003 → 12.0.0-alpha.9433151351

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 (29) hide show
  1. package/Components/Cell/Cell.tsx +2 -2
  2. package/Components/Cell/CellWithFocusable.tsx +21 -14
  3. package/Components/Cell/TvOSCellComponent.tsx +2 -2
  4. package/Components/FocusableCell/index.tsx +7 -7
  5. package/Components/Image/utils/index.ts +21 -11
  6. package/Components/MasterCell/DefaultComponents/Toggle.tsx +5 -1
  7. package/Components/PlayerContainer/PlayerContainer.tsx +62 -29
  8. package/Components/PlayerImageBackground/index.tsx +34 -8
  9. package/Components/River/__tests__/componentsMap.test.js +7 -0
  10. package/Components/Screen/__tests__/Screen.test.tsx +5 -1
  11. package/Components/Screen/__tests__/__snapshots__/Screen.test.tsx.snap +10 -2
  12. package/Components/Screen/index.tsx +14 -12
  13. package/Components/Tabs/TV/styles.ts +1 -1
  14. package/Components/VideoLive/__tests__/PlayerLiveImageComponent.test.tsx +25 -5
  15. package/Components/VideoModal/ModalAnimation/AnimatedPlayerModalWrapper.tsx +78 -0
  16. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.tsx +322 -0
  17. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.tsx +144 -0
  18. package/Components/VideoModal/ModalAnimation/AnimationComponent.tsx +438 -0
  19. package/Components/VideoModal/ModalAnimation/ModalAnimationContext.tsx +143 -0
  20. package/Components/VideoModal/ModalAnimation/index.ts +15 -0
  21. package/Components/VideoModal/ModalAnimation/utils.ts +299 -0
  22. package/Components/VideoModal/PlayerWrapper.tsx +64 -41
  23. package/Components/VideoModal/VideoModal.tsx +8 -25
  24. package/Components/VideoModal/__tests__/PlayerWrapper.test.tsx +6 -1
  25. package/Components/VideoModal/__tests__/__snapshots__/PlayerWrapper.test.tsx.snap +151 -119
  26. package/Components/VideoModal/utils.ts +3 -3
  27. package/Decorators/ComponentsMapWrapper/withComponentsMapProvider.tsx +7 -2
  28. package/package.json +5 -5
  29. package/Components/VideoModal/hooks/usePosition.ts +0 -50
@@ -202,7 +202,7 @@ export class CellComponent extends React.Component<Props> {
202
202
  groupId,
203
203
  isFocusable = true,
204
204
  skipFocusManagerRegistration,
205
- behavior
205
+ behavior,
206
206
  } = this.props;
207
207
 
208
208
  const { id } = item;
@@ -263,7 +263,7 @@ export class CellComponent extends React.Component<Props> {
263
263
  item,
264
264
  focused: this.isCellFocused(focused),
265
265
  scrollTo: this.scrollToIndex(event),
266
- behavior
266
+ behavior,
267
267
  }}
268
268
  />
269
269
  );
@@ -35,18 +35,18 @@ const useCellFocusedState = (groupId: string, id: string) => {
35
35
  };
36
36
 
37
37
  type Props = {
38
- item: ZappEntry,
39
- CellRenderer: React.ComponentType<{ item: Object, state: string }>,
40
- id: string,
41
- groupId: string,
42
- onFocus: Function,
43
- index: number,
44
- scrollTo: Function,
45
- preferredFocus?: boolean,
46
- skipFocusManagerRegistration?: boolean,
47
- isFocusable?: boolean,
48
- behavior: Behavior,
49
- selected?: boolean,
38
+ item: ZappEntry;
39
+ CellRenderer: React.ComponentType<{ item: Object; state: string }>;
40
+ id: string;
41
+ groupId: string;
42
+ onFocus: Function;
43
+ index: number;
44
+ scrollTo: Function;
45
+ preferredFocus?: boolean;
46
+ skipFocusManagerRegistration?: boolean;
47
+ isFocusable?: boolean;
48
+ behavior: Behavior;
49
+ selected?: boolean;
50
50
  };
51
51
 
52
52
  export function CellWithFocusable(props: Props) {
@@ -62,11 +62,18 @@ export function CellWithFocusable(props: Props) {
62
62
  skipFocusManagerRegistration,
63
63
  isFocusable,
64
64
  behavior,
65
- selected
65
+ selected,
66
66
  } = props;
67
67
 
68
68
  const isFocused = useCellFocusedState(groupId, id);
69
- const state = useCellState({ id: item.id, behavior, focused: isFocused, selected });
69
+
70
+ const state = useCellState({
71
+ id: item.id,
72
+ behavior,
73
+ focused: isFocused,
74
+ selected,
75
+ });
76
+
70
77
  const [focusedButtonId, setFocusedButtonId] = React.useState(undefined);
71
78
 
72
79
  // for horizontal scrolling
@@ -249,7 +249,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
249
249
  hasReceivedFocus,
250
250
  groupId,
251
251
  isFocusable,
252
- behavior
252
+ behavior,
253
253
  } = this.props;
254
254
 
255
255
  const { id } = item;
@@ -310,7 +310,7 @@ export class TvOSCellComponent extends React.Component<Props, State> {
310
310
  item,
311
311
  focused: this.props.focused || selectedCell || focused,
312
312
  scrollTo: this.scrollTo,
313
- behavior
313
+ behavior,
314
314
  }}
315
315
  />
316
316
  );
@@ -3,12 +3,12 @@ import { Platform } from "react-native";
3
3
  import { useCellState } from "../MasterCell/utils";
4
4
 
5
5
  type Props = {
6
- index: number,
7
- item: ZappEntry,
8
- focused: boolean,
9
- scrollTo?: (index: number) => void,
10
- CellRenderer: React.ComponentType<{ item: Object, state: string }>,
11
- behavior: Behavior
6
+ index: number;
7
+ item: ZappEntry;
8
+ focused: boolean;
9
+ scrollTo?: (index: number) => void;
10
+ CellRenderer: React.ComponentType<{ item: Object; state: string }>;
11
+ behavior: Behavior;
12
12
  };
13
13
 
14
14
  const isAndroid = Platform.OS === "android";
@@ -20,7 +20,7 @@ export function FocusableCell(props: Props) {
20
20
  CellRenderer,
21
21
  focused,
22
22
  scrollTo = null,
23
- behavior
23
+ behavior,
24
24
  } = props;
25
25
 
26
26
  const state = useCellState({ id: item.id, behavior, focused });
@@ -1,19 +1,29 @@
1
+ import FastImage, { Source } from "@applicaster/react-native-fast-image";
1
2
  import { useMemo } from "react";
3
+ import { ImageRequireSource } from "react-native";
2
4
 
3
- export const useImageSource = (source) => {
5
+ function getSourceCache(cache: Source["cache"]) {
6
+ return cache || FastImage.cacheControl.web;
7
+ }
8
+
9
+ export const useImageSource = (source?: Source | ImageRequireSource) => {
4
10
  return useMemo(() => {
5
- if (typeof source === "number") {
6
- return source;
11
+ if (source) {
12
+ if (typeof source === "number") {
13
+ return source;
14
+ }
15
+
16
+ return {
17
+ uri: source.uri,
18
+ headers: source.headers,
19
+ priority: source.priority,
20
+ cache: getSourceCache(source?.cache),
21
+ maxWidth: source.maxWidth,
22
+ maxHeight: source.maxHeight,
23
+ };
7
24
  }
8
25
 
9
- return {
10
- uri: source.uri,
11
- headers: source.headers,
12
- priority: source.priority,
13
- cache: source.cache,
14
- maxWidth: source.maxWidth,
15
- maxHeight: source.maxHeight,
16
- };
26
+ return undefined;
17
27
  }, [
18
28
  ...(typeof source === "object"
19
29
  ? [
@@ -23,7 +23,11 @@ export const Toggle = (props: Props) => {
23
23
  iosBackgroundColor,
24
24
  } = style;
25
25
 
26
- const isSelected = React.useMemo(() => (cellState === "selected"), [item?.id, cellState]);
26
+ const isSelected = React.useMemo(
27
+ () => cellState === "selected",
28
+ [item?.id, cellState]
29
+ );
30
+
27
31
  const actionContext = useActions(action?.identifier);
28
32
 
29
33
  const [actionState, setActionState] = useState(
@@ -54,6 +54,8 @@ 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 { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
58
+
57
59
  type Props = {
58
60
  Player: React.ComponentType<any>;
59
61
  PlayerLoadingView?: React.ComponentType<any>; // 👀 we are not receiving this prop
@@ -145,34 +147,36 @@ const renderApplePlayer = ({
145
147
  }) => {
146
148
  const { title, summary } = item || {};
147
149
 
148
- if (!isApplePlatform()) {
150
+ if (!isApplePlatform() || !player) {
151
+ return null;
152
+ }
153
+
154
+ // TODO: Check if it is not breaking default player logic on tvos
155
+ // Also if needs to add on tvos brightcove player for QB player
156
+ if (player.supportsNativeControls()) {
157
+ return null;
158
+ }
159
+
160
+ if (isAudioContent) {
161
+ return (
162
+ <AudioPlayer
163
+ audio_item={item}
164
+ plugin_configuration={pluginConfiguration}
165
+ />
166
+ );
167
+ }
168
+
169
+ if (!playNextData && player.isPaused() && player.isAd() === false) {
149
170
  return null;
150
171
  }
151
172
 
152
173
  return (
153
- <>
154
- {!playNextData && (
155
- <>
156
- {!isAudioContent &&
157
- !!player?.isPaused() &&
158
- !!player?.isAd() === false && (
159
- <ProgramInfo
160
- title={title}
161
- subtitle={summary}
162
- plugin_configuration={pluginConfiguration}
163
- videoStyle={videoStyle}
164
- />
165
- )}
166
- </>
167
- )}
168
-
169
- {isAudioContent && (
170
- <AudioPlayer
171
- audio_item={item}
172
- plugin_configuration={pluginConfiguration}
173
- />
174
- )}
175
- </>
174
+ <ProgramInfo
175
+ title={title}
176
+ subtitle={summary}
177
+ plugin_configuration={pluginConfiguration}
178
+ videoStyle={videoStyle}
179
+ />
176
180
  );
177
181
  };
178
182
 
@@ -339,6 +343,18 @@ const PlayerContainerComponent = (props: Props) => {
339
343
  }
340
344
  }, [item?.id, item?.extensions?.resumeTime, player]);
341
345
 
346
+ const onVideoFullscreenPlayerWillPresent = React.useCallback(() => {
347
+ playerManager.invokeHandler("toggleFullscreen", {
348
+ fullscreen: true,
349
+ });
350
+ }, []);
351
+
352
+ const onVideoFullscreenPlayerWillDismiss = React.useCallback(() => {
353
+ playerManager.invokeHandler("toggleFullscreen", {
354
+ fullscreen: false,
355
+ });
356
+ }, []);
357
+
342
358
  // Util methods
343
359
  const toggleFullscreen = (event) => {
344
360
  const { fullscreen = false } = event || {};
@@ -381,17 +397,27 @@ const PlayerContainerComponent = (props: Props) => {
381
397
  id: playerContainerId,
382
398
  listener: {
383
399
  onVideoEnd,
384
- onError: onError,
385
- onLoad: onLoad,
400
+ onError,
401
+ onLoad,
386
402
  onPlayerClose: close,
387
403
  onPlayerDetached: close,
404
+ onVideoFullscreenPlayerWillDismiss,
405
+ onVideoFullscreenPlayerWillPresent,
388
406
  },
389
407
  });
390
408
 
391
409
  return () => {
392
410
  player.removeListener(playerContainerId);
393
411
  };
394
- }, [player, onVideoEnd]);
412
+ }, [
413
+ player,
414
+ onVideoEnd,
415
+ onError,
416
+ onLoad,
417
+ close,
418
+ onVideoFullscreenPlayerWillDismiss,
419
+ onVideoFullscreenPlayerWillPresent,
420
+ ]);
395
421
 
396
422
  useEffect(() => {
397
423
  // TODO: We should not use playerManager here to connect buttons to player container
@@ -580,6 +606,9 @@ const PlayerContainerComponent = (props: Props) => {
580
606
  pluginConfiguration,
581
607
  };
582
608
 
609
+ const { isActiveGesture, startComponentsAnimation } =
610
+ useModalAnimationContext();
611
+
583
612
  return (
584
613
  <PlayerStateContext.Provider value={value}>
585
614
  <PlayerContainerContextProvider
@@ -621,9 +650,13 @@ const PlayerContainerComponent = (props: Props) => {
621
650
  }}
622
651
  focused={isInlineTV ? true : undefined}
623
652
  autoplay={true}
624
- controls={isAppleTV() && !isInlineTV}
653
+ controls={false}
625
654
  disableCastAction={disableCastAction}
626
- docked={navigator.isVideoModalDocked()}
655
+ docked={
656
+ navigator.isVideoModalDocked() &&
657
+ !startComponentsAnimation &&
658
+ !isActiveGesture
659
+ }
627
660
  entry={item}
628
661
  fullscreen={mode === VideoModalMode.FULLSCREEN}
629
662
  inline={inline}
@@ -1,38 +1,64 @@
1
1
  import React, { PropsWithChildren } from "react";
2
- import { ImageBackground } from "react-native";
2
+ import { ImageBackground, View } from "react-native";
3
3
 
4
4
  import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
+ import {
6
+ AnimationComponent,
7
+ ComponentAnimationType,
8
+ useModalAnimationContext,
9
+ PlayerAnimationStateEnum,
10
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
5
11
 
6
12
  type Props = PropsWithChildren<{
7
13
  entry: ZappEntry;
8
14
  style?: { [K: string]: any };
9
15
  imageStyle?: { [K: string]: any };
10
16
  imageKey?: string;
17
+ defaultImageDimensions?: { [K: string]: any };
11
18
  }>;
12
19
 
20
+ const imageSize = { width: "100%", height: "100%" };
21
+
13
22
  const PlayerImageBackgroundComponent = ({
14
23
  entry,
15
24
  children,
16
25
  style,
17
26
  imageStyle,
18
27
  imageKey,
28
+ defaultImageDimensions,
19
29
  }: Props) => {
20
30
  const source = React.useMemo(
21
31
  () => ({ uri: imageSrcFromMediaItem(entry, imageKey) }),
22
32
  [imageKey, entry]
23
33
  );
24
34
 
35
+ const { playerAnimationState } = useModalAnimationContext();
36
+
25
37
  if (!source) return <>{children}</>;
26
38
 
27
39
  return (
28
- <ImageBackground
29
- resizeMode="cover"
30
- style={style}
31
- imageStyle={imageStyle}
32
- source={source}
40
+ <View
41
+ style={
42
+ playerAnimationState === PlayerAnimationStateEnum.maximaze
43
+ ? defaultImageDimensions
44
+ : style
45
+ }
33
46
  >
34
- {children}
35
- </ImageBackground>
47
+ <AnimationComponent
48
+ style={style}
49
+ animationType={ComponentAnimationType.player}
50
+ additionalData={defaultImageDimensions}
51
+ >
52
+ <ImageBackground
53
+ resizeMode="cover"
54
+ style={imageSize}
55
+ imageStyle={imageStyle}
56
+ source={source}
57
+ >
58
+ {children}
59
+ </ImageBackground>
60
+ </AnimationComponent>
61
+ </View>
36
62
  );
37
63
  };
38
64
 
@@ -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
  }));
@@ -83,6 +89,7 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
83
89
  useNavigation: jest.fn(() => ({ currentRoute: "/river/A1234" })),
84
90
  useRoute: jest.fn(() => ({ pathname: "/river/A1234", screenData })),
85
91
  useProfilerLogging: jest.fn(),
92
+ useIsScreenActive: jest.fn().mockReturnValue(true),
86
93
  }));
87
94
 
88
95
  jest.mock("@applicaster/zapp-react-native-utils/reactHooks/screen", () => ({
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { View } from "react-native";
3
- import { create, act } from "react-test-renderer";
3
+ import { act, create } from "react-test-renderer";
4
4
 
5
5
  const Mocked_RouteManager = jest.fn((props) => (
6
6
  <View testID="routeManager" {...props} />
@@ -69,12 +69,16 @@ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation", () => ({
69
69
  isNavBarVisible: mockIsNavBarVisible,
70
70
  useRoute: jest.fn(() => ({
71
71
  pathname: "/river/testId",
72
+ screenData: { id: "testId" },
72
73
  })),
73
74
  useNavigation: jest.fn(() => ({
74
75
  canGoBack: () => false,
75
76
  currentRoute: "/river/testId",
77
+ activeRiver: { id: "testId" },
78
+ screenData: { id: "testId" },
76
79
  data: { screen: { id: "testId" } },
77
80
  })),
81
+ useIsScreenActive: jest.fn().mockReturnValue(true),
78
82
  }));
79
83
 
80
84
  jest.mock("@applicaster/zapp-react-native-redux/hooks", () => ({
@@ -19,7 +19,11 @@ exports[`<Screen Component /> when the navbar should be hidden renders correctly
19
19
  <View>
20
20
  <View
21
21
  pathname="/river/testId"
22
- screenData={Object {}}
22
+ screenData={
23
+ Object {
24
+ "id": "testId",
25
+ }
26
+ }
23
27
  testID="routeManager"
24
28
  />
25
29
  </View>
@@ -45,7 +49,11 @@ exports[`<Screen Component /> when the navbar should show renders correctly 1`]
45
49
  <View>
46
50
  <View
47
51
  pathname="/river/testId"
48
- screenData={Object {}}
52
+ screenData={
53
+ Object {
54
+ "id": "testId",
55
+ }
56
+ }
49
57
  testID="routeManager"
50
58
  />
51
59
  </View>
@@ -23,6 +23,17 @@ import { RouteManager } from "../RouteManager";
23
23
  import { useScreenConfiguration } from "../River/useScreenConfiguration";
24
24
  import { useScreenOrientationHandler } from "./orientationHandler";
25
25
 
26
+ const getScreenId = (
27
+ screenData: LegacyNavigationScreenData,
28
+ fallbackRiver: ZappRiver
29
+ ) => {
30
+ return screenData?.targetScreen
31
+ ? screenData?.targetScreen?.id ?? fallbackRiver.id
32
+ : "screen_id" in screenData
33
+ ? screenData.screen_id
34
+ : fallbackRiver.id;
35
+ };
36
+
26
37
  function colorIsNotTransparent(color) {
27
38
  const layers = R.compose(
28
39
  R.map(R.trim),
@@ -41,17 +52,11 @@ function isValidColor(string) {
41
52
  }
42
53
 
43
54
  type Props = {
44
- pathname: string;
45
- screenData: Record<string, any>;
46
55
  setToggleMenu: () => void;
47
56
  setCloseMenu: () => void;
48
57
  };
49
58
 
50
- export function Screen({
51
- setToggleMenu,
52
- setCloseMenu,
53
- screenData: _screenData,
54
- }: Props) {
59
+ export function Screen({ setToggleMenu, setCloseMenu }: Props) {
55
60
  const theme = useTheme<BaseThemePropertiesMobile>();
56
61
  const navigation = useNavigation();
57
62
  const { plugins } = usePickFromState(["plugins"]);
@@ -68,10 +73,7 @@ export function Screen({
68
73
  const routeData = useRoute();
69
74
 
70
75
  const currentRiver = useScreenData(
71
- (routeData.screenData as ZappRiver)?.targetScreen
72
- ? (routeData.screenData as ZappRiver)?.targetScreen?.id ??
73
- navigation.activeRiver.id
74
- : (routeData.screenData as ZappRiver)?.screen_id
76
+ getScreenId(routeData.screenData, navigation.activeRiver)
75
77
  );
76
78
 
77
79
  const { title } = useNavbarState();
@@ -137,7 +139,7 @@ export function Screen({
137
139
 
138
140
  <OfflineFallbackScreen screenData={screenData}>
139
141
  {/* @TODO RouteManager doesn't use props, can they be removed ? */}
140
- <RouteManager pathname={pathname} screenData={_screenData} />
142
+ <RouteManager pathname={pathname} screenData={screenData} />
141
143
  </OfflineFallbackScreen>
142
144
  </View>
143
145
  </ScreenContextProvider>
@@ -78,7 +78,7 @@ export const getStyles = (config): Partial<TVTabsStyles> => {
78
78
  },
79
79
  tvos: {
80
80
  marginTop: -1,
81
- }
81
+ },
82
82
  }),
83
83
  },
84
84
  tabsBackground: {
@@ -4,8 +4,13 @@ import { render } from "@testing-library/react-native";
4
4
  import * as PlayerFactory from "@applicaster/zapp-react-native-utils/appUtils/playerManager/playerFactory";
5
5
  import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
6
6
  import { ThemeContext } from "@applicaster/zapp-react-native-utils/theme";
7
+ import * as navigationHooks from "@applicaster/zapp-react-native-utils/reactHooks/navigation";
7
8
 
8
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";
9
14
 
10
15
  const seekTo = jest.fn();
11
16
 
@@ -18,12 +23,25 @@ jest.mock(
18
23
  })
19
24
  );
20
25
 
26
+ jest
27
+ .spyOn(useNavigationHooks, "useNavigation")
28
+ .mockImplementation(() => ({ videoModalState: { visible: false } }));
29
+
30
+ jest.mock("@applicaster/zapp-react-native-utils/reactHooks/navigation");
31
+
32
+ const mockStore = configureStore();
33
+
34
+ const store = mockStore({ appData: {} });
35
+
21
36
  const Wrapper = ({ children }: { children: React.ReactChildren }) => (
22
- <ThemeContext.Provider
23
- value={{ themes: { myTheme: {} }, selectedThemeId: "myTheme" }}
24
- >
25
- {children}
26
- </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>
27
45
  );
28
46
 
29
47
  describe("PlayerLiveImageComponent", () => {
@@ -46,6 +64,8 @@ describe("PlayerLiveImageComponent", () => {
46
64
  controller: new Player({}),
47
65
  Component: () => null,
48
66
  }));
67
+
68
+ jest.spyOn(navigationHooks, "useIsScreenActive").mockReturnValue(true);
49
69
  });
50
70
 
51
71
  it("should render correctly with default props", () => {
@@ -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
+ };