@applicaster/quick-brick-player 14.0.0-rc.9 → 15.0.0-alpha.1001559563

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 (28) hide show
  1. package/package.json +6 -11
  2. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +25 -81
  3. package/src/Player/AudioLayer/Layout/Controls/index.tsx +8 -18
  4. package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +119 -119
  5. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +5 -38
  6. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +3 -8
  7. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +5 -9
  8. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +22 -72
  9. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +1 -58
  10. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +0 -33
  11. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +6 -18
  12. package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +1 -1
  13. package/src/Player/PlayerModal/GestureAnimatedScrollView.ts +7 -0
  14. package/src/Player/PlayerModal/PlayerModal.tsx +109 -0
  15. package/src/Player/PlayerModal/VideoPlayerModal.tsx +271 -0
  16. package/src/Player/PlayerModal/consts/index.ts +34 -0
  17. package/src/Player/PlayerModal/context/index.ts +6 -0
  18. package/src/Player/PlayerModal/hooks/index.ts +193 -0
  19. package/src/Player/PlayerModal/index.ts +3 -0
  20. package/src/Player/PlayerModal/index.web.ts +5 -0
  21. package/src/Player/PlayerModal/styles.ts +104 -0
  22. package/src/Player/PlayerView/GenericTVPlayerView.tsx +42 -0
  23. package/src/Player/PlayerView/TVPlayerView.tsx +26 -0
  24. package/src/Player/PlayerView/TvOSPlayerView.tsx +51 -0
  25. package/src/Player/PlayerView/types.ts +42 -0
  26. package/src/Player/index.tsx +187 -190
  27. package/src/QuickBrickPlayer.tsx +16 -10
  28. /package/src/Player/AudioLayer/Layout/{Debug → DebugComponent}/index.tsx +0 -0
@@ -4,7 +4,6 @@ import {
4
4
  useSafeAreaFrame,
5
5
  useSafeAreaInsets,
6
6
  } from "react-native-safe-area-context";
7
- import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
7
 
9
8
  import { MOBILE, NAVBAR_HEIGHT } from "./const";
10
9
  import { TransportInfo } from "./TransportInfo";
@@ -12,13 +11,12 @@ import { PlayerImage } from "./PlayerImage";
12
11
  import { Controls } from "./Controls";
13
12
 
14
13
  import { useMobileLayoutImageSize, useTransportInfoHeight } from "./hooks";
15
- import { DockedControls } from "./DockedControls";
16
14
  import { DEBUG, withDebug } from "./debug";
17
15
  import {
18
16
  BottomDebugSquare,
19
17
  LeftDebugSquare,
20
18
  RightDebugSquare,
21
- } from "./Debug/index";
19
+ } from "./DebugComponent";
22
20
 
23
21
  import { Props } from "./types";
24
22
 
@@ -56,6 +54,7 @@ const mobileStyles = ({
56
54
  imageSize,
57
55
  }): ViewStyle => ({
58
56
  height: screenHeight - topInset - bottomInset,
57
+ width: "100%",
59
58
 
60
59
  opacity: imageSize ? 1 : 0, // hide content until imageSize is calculated
61
60
 
@@ -77,11 +76,8 @@ export function MobileLayout({
77
76
  onSkipStart,
78
77
  onSkipLive,
79
78
  onSpeedButtonPress,
80
- onCloseVideoModal,
81
79
  playbackSpeedName,
82
80
  configuration,
83
- dimensions,
84
- playNextData,
85
81
  title,
86
82
  summary,
87
83
  }: Props) {
@@ -89,12 +85,10 @@ export function MobileLayout({
89
85
 
90
86
  const { bottom: bottomInset, top: topInset } = useSafeAreaInsets();
91
87
  const { height: screenHeight } = useSafeAreaFrame();
92
- const { progressBarHeight } = useModalAnimationContext();
93
88
 
94
89
  const { imageSize } = useMobileLayoutImageSize();
95
90
 
96
- const { height: transportInfoHeight, onLayout: onTransportInfoLayout } =
97
- useTransportInfoHeight();
91
+ const { onLayout: onTransportInfoLayout } = useTransportInfoHeight();
98
92
 
99
93
  const controlsContainerHeight = React.useMemo(() => {
100
94
  return (
@@ -108,10 +102,6 @@ export function MobileLayout({
108
102
  );
109
103
  }, [screenHeight, topInset, imageSize, bottomInset]);
110
104
 
111
- const verticalOffsetForImage = React.useMemo(() => {
112
- return transportInfoHeight + MOBILE.MARGIN_TOP - progressBarHeight;
113
- }, [transportInfoHeight, progressBarHeight]);
114
-
115
105
  return (
116
106
  <View
117
107
  style={[
@@ -163,19 +153,9 @@ export function MobileLayout({
163
153
  >
164
154
  <PlayerImage
165
155
  entry={entry}
166
- layoutState={layoutState}
167
- playerState={playerState}
168
- value={value}
169
- configuration={configuration}
170
- onPlayerSeek={onPlayerSeek}
171
- onCloseVideoModal={onCloseVideoModal}
172
- dimensions={dimensions}
173
- playNextData={playNextData}
174
- title={title}
175
- summary={summary}
176
- docked={docked}
156
+ docked={false}
177
157
  imageWidth={imageSize}
178
- verticalOffset={verticalOffsetForImage}
158
+ configuration={configuration}
179
159
  />
180
160
  </View>
181
161
  {/* PlayerImage */}
@@ -204,19 +184,6 @@ export function MobileLayout({
204
184
  />
205
185
  </View>
206
186
  </View>
207
-
208
- <DockedControls
209
- entry={entry}
210
- layoutState={layoutState}
211
- playerState={playerState}
212
- value={value}
213
- dimensions={dimensions}
214
- onCloseVideoModal={onCloseVideoModal}
215
- onPlayerSeek={onPlayerSeek}
216
- playNextData={playNextData}
217
- title={title}
218
- summary={summary}
219
- />
220
187
  </View>
221
188
  );
222
189
  }
@@ -1,7 +1,6 @@
1
1
  import React, { PropsWithChildren } from "react";
2
2
  import { Image, Animated, StyleSheet, ImageStyle } from "react-native";
3
3
 
4
- import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
5
4
  import {
6
5
  useModalAnimationContext,
7
6
  PlayerAnimationStateEnum,
@@ -9,6 +8,7 @@ import {
9
8
  DURATION_TO_MAXIMIZE,
10
9
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
11
10
  import { PlayerAnimationStateT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/ModalAnimationContext";
11
+ import { useBackgroundImage } from "@applicaster/zapp-react-native-utils/audioPlayerUtils";
12
12
 
13
13
  import { useChangePlayerState } from "./hooks";
14
14
 
@@ -30,10 +30,7 @@ type Props = PropsWithChildren<{
30
30
  export const AnimatedImage = ({ entry, style, imageWidth, docked }: Props) => {
31
31
  const heightAnim = React.useRef(new Animated.Value(imageWidth)).current;
32
32
 
33
- const source = React.useMemo(
34
- () => ({ uri: imageSrcFromMediaItem(entry, undefined) }),
35
- [entry]
36
- );
33
+ const backgroundImageSource = useBackgroundImage(entry);
37
34
 
38
35
  const { minimisedHeight } = useModalAnimationContext();
39
36
 
@@ -70,8 +67,6 @@ export const AnimatedImage = ({ entry, style, imageWidth, docked }: Props) => {
70
67
  };
71
68
  }, [changePlayerState$, minimisedHeight, imageWidth]);
72
69
 
73
- if (!source) return null;
74
-
75
70
  return (
76
71
  <Animated.View
77
72
  style={[
@@ -81,7 +76,7 @@ export const AnimatedImage = ({ entry, style, imageWidth, docked }: Props) => {
81
76
  },
82
77
  ]}
83
78
  >
84
- <Image resizeMode="cover" style={style} source={source} />
79
+ <Image resizeMode="cover" style={style} source={backgroundImageSource} />
85
80
  </Animated.View>
86
81
  );
87
82
  };
@@ -1,7 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { Image, ImageStyle } from "react-native";
3
-
4
- import { imageSrcFromMediaItem } from "@applicaster/zapp-react-native-utils/configurationUtils";
3
+ import { useBackgroundImage } from "@applicaster/zapp-react-native-utils/audioPlayerUtils";
5
4
 
6
5
  type Props = {
7
6
  entry: ZappEntry;
@@ -9,12 +8,9 @@ type Props = {
9
8
  };
10
9
 
11
10
  export const FlexImage = ({ entry, style }: Props) => {
12
- const source = React.useMemo(
13
- () => ({ uri: imageSrcFromMediaItem(entry, undefined) }),
14
- [entry]
15
- );
11
+ const backgroundImageSource = useBackgroundImage(entry);
16
12
 
17
- if (!source) return null;
18
-
19
- return <Image resizeMode="cover" style={style} source={source} />;
13
+ return (
14
+ <Image resizeMode="cover" style={style} source={backgroundImageSource} />
15
+ );
20
16
  };
@@ -1,11 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { LayoutChangeEvent, View } from "react-native";
3
3
 
4
- import {
5
- AnimationComponent,
6
- ComponentAnimationType,
7
- useModalAnimationContext,
8
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
9
4
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
10
5
  import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
11
6
 
@@ -13,100 +8,55 @@ import { AnimatedImage } from "./AnimatedImage";
13
8
  import { FlexImage } from "./FlexImage";
14
9
 
15
10
  import { styles } from "./styles";
16
- import { calculateBorderRadius } from "../../utils";
17
- import { PlayNextData } from "../types";
11
+ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
18
12
 
19
13
  type Props = {
20
14
  entry: ZappEntry;
21
- layoutState: QuickBrickPlayer.LayoutState;
22
- playerState: QuickBrickPlayer.PlayerState;
23
- value: GetValue;
24
15
  configuration: QuickBrickPlayer.AudioPlayerProps["configuration"];
25
- dimensions: QuickBrickPlayer.AudioPlayerProps["dimensions"];
26
- onCloseVideoModal: Callback;
27
- onPlayerSeek: (targetTime: number) => void;
28
- playNextData: PlayNextData;
29
- title: string | number;
30
- summary: string | number;
31
16
  docked: boolean;
32
17
  imageWidth?: Option<number>;
33
- verticalOffset: number;
34
18
  onLayoutImage?: (event: LayoutChangeEvent) => void;
35
19
  };
36
20
 
37
21
  export const PlayerImage = (props: Props) => {
38
22
  const {
39
23
  entry,
40
- dimensions,
41
24
  docked,
42
- verticalOffset,
43
25
  imageWidth,
44
26
  configuration,
45
27
  onLayoutImage = noop,
46
28
  } = props;
47
29
 
48
- const {
49
- isActiveGesture,
50
- startComponentsAnimation,
51
- playerAnimationState,
52
- minimisedHeight,
53
- } = useModalAnimationContext();
54
-
55
30
  const isShadowEnabled = toBooleanWithDefaultTrue(
56
31
  configuration?.audio_player_artwork_shadow_enabled
57
32
  );
58
33
 
59
34
  const shouldShowShadow = !docked && isShadowEnabled;
60
35
 
61
- const borderRadius = calculateBorderRadius(
62
- docked,
63
- startComponentsAnimation,
64
- isActiveGesture,
65
- playerAnimationState,
66
- configuration
36
+ const borderRadius = toNumberWithDefaultZero(
37
+ configuration.audio_player_artwork_border_radius
67
38
  );
68
39
 
69
40
  return (
70
- <AnimationComponent
71
- animationType={ComponentAnimationType.moveUpComponent}
72
- additionalData={{
73
- marginTop: verticalOffset,
74
- }}
75
- style={styles.flex}
76
- >
77
- <AnimationComponent
78
- animationType={ComponentAnimationType.moveComponentHorizontal}
79
- additionalData={{
80
- // we move image horiontally to this value due artwork is centered
81
- moveValue: (dimensions.width - minimisedHeight) / 2,
82
- }}
83
- style={styles.alignItemsCenter}
41
+ <View style={styles.alignItemsCenter}>
42
+ <View
43
+ onLayout={onLayoutImage}
44
+ style={[shouldShowShadow ? styles.shadow : undefined, { borderRadius }]}
84
45
  >
85
- <View
86
- onLayout={onLayoutImage}
87
- style={[
88
- shouldShowShadow ? styles.shadow : undefined,
89
- { borderRadius },
90
- ]}
91
- >
92
- {!imageWidth ? (
93
- <View style={[styles.defaultImageWrapperView, { borderRadius }]}>
94
- <FlexImage
95
- entry={entry}
96
- style={styles.backgroundImageContainer}
97
- />
98
- </View>
99
- ) : (
100
- // we have imageSize here and now we could animate resizing of this image
101
- <AnimatedImage
102
- entry={entry}
103
- style={[styles.backgroundImageContainer, { borderRadius }]}
104
- imageWidth={imageWidth}
105
- docked={docked}
106
- />
107
- )}
108
- </View>
109
- </AnimationComponent>
110
- </AnimationComponent>
46
+ {!imageWidth ? (
47
+ <View style={[styles.defaultImageWrapperView, { borderRadius }]}>
48
+ <FlexImage entry={entry} style={styles.backgroundImageContainer} />
49
+ </View>
50
+ ) : (
51
+ // we have imageSize here and now we could animate resizing of this image
52
+ <AnimatedImage
53
+ entry={entry}
54
+ style={[styles.backgroundImageContainer, { borderRadius }]}
55
+ imageWidth={imageWidth}
56
+ docked={docked}
57
+ />
58
+ )}
59
+ </View>
60
+ </View>
111
61
  );
112
62
  };
@@ -1,25 +1,16 @@
1
1
  import * as React from "react";
2
2
  import { StyleSheet, View } from "react-native";
3
- import {
4
- useSafeAreaFrame,
5
- useSafeAreaInsets,
6
- } from "react-native-safe-area-context";
7
- import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
- import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
3
+ import { useSafeAreaFrame } from "react-native-safe-area-context";
9
4
 
10
5
  import { TransportInfo } from "./TransportInfo";
11
6
  import { PlayerImage } from "./PlayerImage";
12
7
  import { Controls } from "./Controls";
13
8
 
14
- import { DockedControls } from "./DockedControls";
15
9
  import { withDebug } from "./debug";
16
10
 
17
11
  import { Props } from "./types";
18
12
  import { isSmallTabletHeight as getIsSmallTabletHeight } from "./utils";
19
13
  import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "./const";
20
- import { FlexImage } from "./PlayerImage/FlexImage";
21
-
22
- const isIOS = isApplePlatform();
23
14
 
24
15
  const MIN_WIDTH = TABLET_LANDSCAPE.MIN_WIDTH; // Minimum width for the audio player container
25
16
  const MAX_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL; // Maximum spacing for the audio player container
@@ -70,22 +61,6 @@ const styles = StyleSheet.create({
70
61
  },
71
62
  });
72
63
 
73
- const isTabletWithHomeButton = (bottomInset: number): boolean =>
74
- bottomInset === 0;
75
-
76
- const withAdditionalOffset = ({ progressBarHeight, bottomInset }) => {
77
- if (isIOS && isTabletWithHomeButton(bottomInset)) {
78
- return progressBarHeight === 0 ? 8 : progressBarHeight + 2;
79
- }
80
-
81
- if (isIOS && !isTabletWithHomeButton(bottomInset)) {
82
- return progressBarHeight === 0 ? 4 : 1;
83
- }
84
-
85
- // android
86
- return progressBarHeight === 0 ? 4 : 0.5;
87
- };
88
-
89
64
  export function TabletLandscapeLayout({
90
65
  entry,
91
66
  layoutState,
@@ -98,21 +73,16 @@ export function TabletLandscapeLayout({
98
73
  onSkipStart,
99
74
  onSkipLive,
100
75
  onSpeedButtonPress,
101
- onCloseVideoModal,
102
76
  playbackSpeedName,
103
77
  configuration,
104
- dimensions,
105
- playNextData,
106
78
  title,
107
79
  summary,
108
80
  }: Props) {
109
81
  const [imageWidth, setImageWidth] = React.useState(0);
110
82
  const { docked } = layoutState;
111
83
 
112
- const { bottom: bottomInset } = useSafeAreaInsets();
113
84
  const { height: screenHeight } = useSafeAreaFrame();
114
85
  const isSmallScreen = getIsSmallTabletHeight(screenHeight);
115
- const { progressBarHeight } = useModalAnimationContext();
116
86
 
117
87
  const onLayoutImage = React.useCallback((e) => {
118
88
  setImageWidth(e.nativeEvent.layout.width);
@@ -151,20 +121,7 @@ export function TabletLandscapeLayout({
151
121
  <PlayerImage
152
122
  docked={false}
153
123
  entry={entry}
154
- layoutState={layoutState}
155
- playerState={playerState}
156
- value={value}
157
124
  configuration={configuration}
158
- onPlayerSeek={onPlayerSeek}
159
- onCloseVideoModal={onCloseVideoModal}
160
- dimensions={dimensions}
161
- playNextData={playNextData}
162
- title={title}
163
- summary={summary}
164
- verticalOffset={withAdditionalOffset({
165
- progressBarHeight,
166
- bottomInset,
167
- })}
168
125
  onLayoutImage={onLayoutImage}
169
126
  />
170
127
  ) : null}
@@ -193,20 +150,6 @@ export function TabletLandscapeLayout({
193
150
  </View>
194
151
  </View>
195
152
  </View>
196
-
197
- <DockedControls
198
- ImageComponent={<FlexImage entry={entry} style={styles.flex} />}
199
- entry={entry}
200
- layoutState={layoutState}
201
- playerState={playerState}
202
- value={value}
203
- dimensions={dimensions}
204
- onCloseVideoModal={onCloseVideoModal}
205
- onPlayerSeek={onPlayerSeek}
206
- playNextData={playNextData}
207
- title={title}
208
- summary={summary}
209
- />
210
153
  </View>
211
154
  );
212
155
  }
@@ -4,8 +4,6 @@ import {
4
4
  useSafeAreaFrame,
5
5
  useSafeAreaInsets,
6
6
  } from "react-native-safe-area-context";
7
- import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
- import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
9
7
 
10
8
  import { withDebug } from "./debug";
11
9
  import { TABLET_PORTRAIT } from "./const";
@@ -15,7 +13,6 @@ import { PlayerImage } from "./PlayerImage";
15
13
  import { Controls } from "./Controls";
16
14
 
17
15
  import { useTabletLayoutImageSize } from "./hooks";
18
- import { DockedControls } from "./DockedControls";
19
16
  import { VerticalGutter } from "./VerticalGutter";
20
17
 
21
18
  import { Props } from "./types";
@@ -82,11 +79,8 @@ export function TabletPortraitLayout({
82
79
  onSkipStart,
83
80
  onSkipLive,
84
81
  onSpeedButtonPress,
85
- onCloseVideoModal,
86
82
  playbackSpeedName,
87
83
  configuration,
88
- dimensions,
89
- playNextData,
90
84
  title,
91
85
  summary,
92
86
  }: Props) {
@@ -94,7 +88,6 @@ export function TabletPortraitLayout({
94
88
 
95
89
  const { bottom: bottomInset, top: topInset } = useSafeAreaInsets();
96
90
  const { height: screenHeight } = useSafeAreaFrame();
97
- const { progressBarHeight } = useModalAnimationContext();
98
91
 
99
92
  const {
100
93
  imageSize,
@@ -153,21 +146,9 @@ export function TabletPortraitLayout({
153
146
  >
154
147
  <PlayerImage
155
148
  entry={entry}
156
- layoutState={layoutState}
157
- playerState={playerState}
158
- value={value}
159
149
  configuration={configuration}
160
- onPlayerSeek={onPlayerSeek}
161
- onCloseVideoModal={onCloseVideoModal}
162
- dimensions={dimensions}
163
- playNextData={playNextData}
164
- title={title}
165
- summary={summary}
166
150
  docked={docked}
167
151
  imageWidth={imageSize}
168
- verticalOffset={
169
- toNumberWithDefaultZero(topOffset) - progressBarHeight
170
- }
171
152
  />
172
153
  </View>
173
154
 
@@ -196,20 +177,6 @@ export function TabletPortraitLayout({
196
177
  </View>
197
178
  </View>
198
179
  </View>
199
- {/* PlayerImage */}
200
-
201
- <DockedControls
202
- entry={entry}
203
- layoutState={layoutState}
204
- playerState={playerState}
205
- value={value}
206
- dimensions={dimensions}
207
- onCloseVideoModal={onCloseVideoModal}
208
- onPlayerSeek={onPlayerSeek}
209
- playNextData={playNextData}
210
- title={title}
211
- summary={summary}
212
- />
213
180
  </View>
214
181
  );
215
182
  }
@@ -1,14 +1,10 @@
1
1
  import * as React from "react";
2
- import { compose, map, propOr, split, take, trim } from "ramda";
3
2
  import { LayoutChangeEvent, StyleSheet, View } from "react-native";
4
3
 
5
4
  import { TransportInfo as MobileTransportInfo } from "@applicaster/quick-brick-mobile-transport-controls";
6
5
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
7
6
  import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
8
- import {
9
- AnimationComponent,
10
- ComponentAnimationType,
11
- } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
7
+
12
8
  import { toPositiveNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
13
9
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
14
10
 
@@ -16,6 +12,7 @@ import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "../const";
16
12
  import { withDebug } from "../debug";
17
13
  import { useSafeAreaFrame } from "react-native-safe-area-context";
18
14
  import { isSmallTabletHeight } from "../utils";
15
+ import { getPlayerActionButtons } from "@applicaster/zapp-react-native-utils/playerUtils";
19
16
 
20
17
  const styles = StyleSheet.create({
21
18
  container: {
@@ -85,14 +82,8 @@ export const TransportInfo = ({
85
82
  );
86
83
 
87
84
  const actionButtons = React.useMemo(
88
- () =>
89
- compose(
90
- take(2),
91
- map(trim),
92
- split(","),
93
- propOr("", "player_action_buttons")
94
- )(configuration),
95
- [configuration.player_action_buttons]
85
+ () => getPlayerActionButtons(configuration),
86
+ [configuration]
96
87
  );
97
88
 
98
89
  return (
@@ -110,10 +101,7 @@ export const TransportInfo = ({
110
101
  ]}
111
102
  onLayout={handleLayout}
112
103
  >
113
- <AnimationComponent
114
- animationType={ComponentAnimationType.componentFade}
115
- style={styles.animatedContainer}
116
- >
104
+ <View style={styles.animatedContainer}>
117
105
  <MobileTransportInfo
118
106
  content={entry}
119
107
  value={value}
@@ -122,7 +110,7 @@ export const TransportInfo = ({
122
110
  layoutState={layoutState}
123
111
  actionButtons={actionButtons}
124
112
  />
125
- </AnimationComponent>
113
+ </View>
126
114
  </View>
127
115
  );
128
116
  };
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { ModalHeader } from "@applicaster/zapp-react-native-ui-components/Components/ModalComponent/Header";
3
- import { isNil } from "lodash";
3
+ import { isNil } from "@applicaster/zapp-react-native-utils/utils";
4
4
 
5
5
  const formatTime = (milliseconds: number) => {
6
6
  const totalSeconds = Math.floor(milliseconds / 1000);
@@ -0,0 +1,7 @@
1
+ import { Animated } from "react-native";
2
+ import { createNativeWrapper } from "react-native-gesture-handler";
3
+
4
+ export const GestureAnimatedScrollView = createNativeWrapper(
5
+ Animated.ScrollView,
6
+ {}
7
+ );
@@ -0,0 +1,109 @@
1
+ import React, { ReactElement } from "react";
2
+
3
+ import { Animated, Pressable } from "react-native";
4
+ import { PanGestureHandler } from "react-native-gesture-handler";
5
+ import { useStyles } from "./styles";
6
+ import { useVideoModalState } from "./hooks";
7
+ import { MODAL_COLLAPSE_START, MODAL_RADIUS, SCREEN_HEIGHT } from "./consts";
8
+ import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
9
+
10
+ type AnimatedModalProps = {
11
+ content?: ReactElement;
12
+ collapsedContent?: ReactElement;
13
+ };
14
+
15
+ export function AnimatedModal({
16
+ content,
17
+ collapsedContent,
18
+ }: AnimatedModalProps) {
19
+ const translateYRef = useModalAnimationContext().yTranslate;
20
+
21
+ const {
22
+ translateY,
23
+ collapsed,
24
+ collapsedHeight,
25
+ gestureHandlerProps,
26
+ expand,
27
+ } = useVideoModalState(translateYRef);
28
+
29
+ const styles = useStyles({ height: collapsedHeight, type: "audio" });
30
+
31
+ // Interpolated opacities for smooth cross-fade
32
+ const collapsedOpacity = translateY.interpolate({
33
+ inputRange: [MODAL_COLLAPSE_START, SCREEN_HEIGHT - collapsedHeight],
34
+ outputRange: [0, 1],
35
+ extrapolate: "clamp",
36
+ });
37
+
38
+ const expandedOpacity = translateY.interpolate({
39
+ inputRange: [0, SCREEN_HEIGHT - collapsedHeight],
40
+ outputRange: [1, 0],
41
+ extrapolate: "clamp",
42
+ });
43
+
44
+ const borderTopRadiusAnimated = translateY.interpolate({
45
+ inputRange: [0, SCREEN_HEIGHT - collapsedHeight],
46
+ outputRange: [MODAL_RADIUS, 0],
47
+ extrapolate: "clamp",
48
+ });
49
+
50
+ return (
51
+ <PanGestureHandler {...gestureHandlerProps}>
52
+ <Animated.View
53
+ pointerEvents={"auto"}
54
+ style={[
55
+ styles.modalWrapper,
56
+ {
57
+ borderTopLeftRadius: borderTopRadiusAnimated,
58
+ borderTopRightRadius: borderTopRadiusAnimated,
59
+ transform: [{ translateY }],
60
+ height: SCREEN_HEIGHT,
61
+ },
62
+ ]}
63
+ >
64
+ <Animated.View
65
+ style={[
66
+ styles.modal,
67
+ {
68
+ borderTopLeftRadius: borderTopRadiusAnimated,
69
+ borderTopRightRadius: borderTopRadiusAnimated,
70
+ height: SCREEN_HEIGHT,
71
+ },
72
+ ]}
73
+ >
74
+ {/* Expanded Content (fades in) */}
75
+ <Animated.View
76
+ pointerEvents={!collapsed ? "auto" : "none"}
77
+ style={styles.modalContent}
78
+ >
79
+ <Animated.View
80
+ pointerEvents={!collapsed ? "auto" : "none"}
81
+ style={[
82
+ styles.expandedContentContainer,
83
+ { opacity: expandedOpacity },
84
+ ]}
85
+ >
86
+ {content}
87
+ </Animated.View>
88
+ </Animated.View>
89
+ {/* Collapsed Bar (fades out) */}
90
+ <Animated.View
91
+ pointerEvents={collapsed ? "box-none" : "none"}
92
+ style={[
93
+ styles.collapsedBarContainer,
94
+ { opacity: collapsedOpacity },
95
+ ]}
96
+ >
97
+ <Pressable
98
+ testID="collapsedBarWrapper"
99
+ onPress={expand}
100
+ style={styles.collapsedBarWrapper}
101
+ >
102
+ {collapsedContent}
103
+ </Pressable>
104
+ </Animated.View>
105
+ </Animated.View>
106
+ </Animated.View>
107
+ </PanGestureHandler>
108
+ );
109
+ }