@applicaster/quick-brick-player 14.0.0-alpha.1355728993 → 14.0.0-alpha.1428720541

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/quick-brick-player",
3
- "version": "14.0.0-alpha.1355728993",
3
+ "version": "14.0.0-alpha.1428720541",
4
4
  "description": "Quick Brick Player",
5
5
  "main": "./src/index.ts",
6
6
  "types": "index.d.ts",
@@ -35,13 +35,12 @@
35
35
  },
36
36
  "homepage": "https://github.com/applicaster/quickbrick#readme",
37
37
  "dependencies": {
38
- "@applicaster/quick-brick-mobile-transport-controls": "14.0.0-alpha.1355728993",
39
- "@applicaster/quick-brick-tv-transport-controls": "14.0.0-rc.7",
40
- "@applicaster/zapp-react-native-tvos-app": "14.0.0-alpha.1355728993",
41
- "@applicaster/zapp-react-native-ui-components": "14.0.0-alpha.1355728993",
42
- "@applicaster/zapp-react-native-utils": "14.0.0-alpha.1355728993",
38
+ "@applicaster/quick-brick-mobile-transport-controls": "14.0.0-rc.40",
39
+ "@applicaster/quick-brick-tv-transport-controls": "14.0.0-rc.37",
40
+ "@applicaster/zapp-react-native-tvos-app": "14.0.0-alpha.1428720541",
41
+ "@applicaster/zapp-react-native-ui-components": "14.0.0-alpha.1428720541",
42
+ "@applicaster/zapp-react-native-utils": "14.0.0-alpha.1428720541",
43
43
  "query-string": "7.1.3",
44
- "react-native-web-linear-gradient": "1.1.2",
45
44
  "shaka-player": "4.3.5",
46
45
  "typeface-montserrat": "^0.0.54",
47
46
  "video.js": "7.14.3",
@@ -58,15 +57,11 @@
58
57
  "@applicaster/zapp-react-native-tvos-ui-components": "*",
59
58
  "@babel/runtime": "*",
60
59
  "@react-native-community/netinfo": "*",
61
- "immer": "*",
62
60
  "react": "*",
63
61
  "react-native": "*",
64
62
  "react-native-fs": "*",
65
- "react-native-gesture-handler": "*",
66
63
  "react-native-linear-gradient": "*",
67
- "react-native-safe-area-context": "*",
68
64
  "react-native-svg": "*",
69
- "react-native-web": "*",
70
65
  "react-native-webview": "*",
71
66
  "uglify-js": "*",
72
67
  "validate-color": "*",
@@ -23,6 +23,7 @@ import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/app
23
23
  import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
24
24
  import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/utils";
25
25
  import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
26
+ import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
26
27
 
27
28
  const bottomTabBarHeight = getTabBarHeight();
28
29
 
@@ -47,7 +48,7 @@ const styles = StyleSheet.create({
47
48
  flex: 1,
48
49
  flexDirection: "column",
49
50
  alignItems: "stretch",
50
- marginTop: 3, // from plugins/mobile-transport-controls/src/ProgressBar/layouts/DockedLayout.tsx
51
+ marginTop: PROGRESS_BAR_HEIGHT,
51
52
  },
52
53
  content: {
53
54
  flex: 1,
@@ -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";
@@ -17,7 +16,7 @@ import {
17
16
  BottomDebugSquare,
18
17
  LeftDebugSquare,
19
18
  RightDebugSquare,
20
- } from "./Debug/index";
19
+ } from "./DebugComponent";
21
20
 
22
21
  import { Props } from "./types";
23
22
 
@@ -79,8 +78,6 @@ export function MobileLayout({
79
78
  onSpeedButtonPress,
80
79
  playbackSpeedName,
81
80
  configuration,
82
- dimensions,
83
- playNextData,
84
81
  title,
85
82
  summary,
86
83
  }: Props) {
@@ -88,12 +85,10 @@ export function MobileLayout({
88
85
 
89
86
  const { bottom: bottomInset, top: topInset } = useSafeAreaInsets();
90
87
  const { height: screenHeight } = useSafeAreaFrame();
91
- const { progressBarHeight } = useModalAnimationContext();
92
88
 
93
89
  const { imageSize } = useMobileLayoutImageSize();
94
90
 
95
- const { height: transportInfoHeight, onLayout: onTransportInfoLayout } =
96
- useTransportInfoHeight();
91
+ const { onLayout: onTransportInfoLayout } = useTransportInfoHeight();
97
92
 
98
93
  const controlsContainerHeight = React.useMemo(() => {
99
94
  return (
@@ -107,10 +102,6 @@ export function MobileLayout({
107
102
  );
108
103
  }, [screenHeight, topInset, imageSize, bottomInset]);
109
104
 
110
- const verticalOffsetForImage = React.useMemo(() => {
111
- return transportInfoHeight + MOBILE.MARGIN_TOP - progressBarHeight;
112
- }, [transportInfoHeight, progressBarHeight]);
113
-
114
105
  return (
115
106
  <View
116
107
  style={[
@@ -162,18 +153,9 @@ export function MobileLayout({
162
153
  >
163
154
  <PlayerImage
164
155
  entry={entry}
165
- layoutState={layoutState}
166
- playerState={playerState}
167
- value={value}
168
- configuration={configuration}
169
- onPlayerSeek={onPlayerSeek}
170
- dimensions={dimensions}
171
- playNextData={playNextData}
172
- title={title}
173
- summary={summary}
174
- docked={docked}
156
+ docked={false}
175
157
  imageWidth={imageSize}
176
- verticalOffset={verticalOffsetForImage}
158
+ configuration={configuration}
177
159
  />
178
160
  </View>
179
161
  {/* PlayerImage */}
@@ -1,7 +1,16 @@
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";
4
+ import {
5
+ useModalAnimationContext,
6
+ PlayerAnimationStateEnum,
7
+ DURATION_TO_MINIMIZE,
8
+ DURATION_TO_MAXIMIZE,
9
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
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
+
13
+ import { useChangePlayerState } from "./hooks";
5
14
 
6
15
  const styles = StyleSheet.create({
7
16
  container: {
@@ -15,17 +24,48 @@ type Props = PropsWithChildren<{
15
24
  entry: ZappEntry;
16
25
  style?: ImageStyle | ImageStyle[];
17
26
  imageWidth: number;
27
+ docked: boolean;
18
28
  }>;
19
29
 
20
- export const AnimatedImage = ({ entry, style, imageWidth }: Props) => {
30
+ export const AnimatedImage = ({ entry, style, imageWidth, docked }: Props) => {
21
31
  const heightAnim = React.useRef(new Animated.Value(imageWidth)).current;
22
32
 
23
- const source = React.useMemo(
24
- () => ({ uri: imageSrcFromMediaItem(entry, undefined) }),
25
- [entry]
26
- );
33
+ const backgroundImageSource = useBackgroundImage(entry);
34
+
35
+ const { minimisedHeight } = useModalAnimationContext();
36
+
37
+ const changePlayerState$ = useChangePlayerState({ docked });
38
+
39
+ React.useEffect(() => {
40
+ const subscription = changePlayerState$.subscribe({
41
+ next: (nextPlayerState: PlayerAnimationStateT) => {
42
+ if (nextPlayerState === PlayerAnimationStateEnum.minimize) {
43
+ Animated.timing(heightAnim, {
44
+ toValue: minimisedHeight,
45
+ duration: DURATION_TO_MINIMIZE,
46
+ useNativeDriver: false, // width/height can't use native driver
47
+ }).start();
48
+ }
49
+
50
+ if (nextPlayerState === PlayerAnimationStateEnum.maximize) {
51
+ Animated.timing(heightAnim, {
52
+ toValue: imageWidth,
53
+ duration: DURATION_TO_MAXIMIZE,
54
+ useNativeDriver: false, // width/height can't use native driver
55
+ }).start();
56
+ }
57
+
58
+ if (nextPlayerState === PlayerAnimationStateEnum.appear_as_docked) {
59
+ // minimize image immediatly
60
+ heightAnim.setValue(minimisedHeight);
61
+ }
62
+ },
63
+ });
27
64
 
28
- if (!source) return null;
65
+ return () => {
66
+ subscription.unsubscribe();
67
+ };
68
+ }, [changePlayerState$, minimisedHeight, imageWidth]);
29
69
 
30
70
  return (
31
71
  <Animated.View
@@ -36,7 +76,7 @@ export const AnimatedImage = ({ entry, style, imageWidth }: Props) => {
36
76
  },
37
77
  ]}
38
78
  >
39
- <Image resizeMode="cover" style={style} source={source} />
79
+ <Image resizeMode="cover" style={style} source={backgroundImageSource} />
40
80
  </Animated.View>
41
81
  );
42
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
  };
@@ -53,6 +53,7 @@ export const PlayerImage = (props: Props) => {
53
53
  entry={entry}
54
54
  style={[styles.backgroundImageContainer, { borderRadius }]}
55
55
  imageWidth={imageWidth}
56
+ docked={docked}
56
57
  />
57
58
  )}
58
59
  </View>
@@ -1,11 +1,6 @@
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";
@@ -17,8 +12,6 @@ import { Props } from "./types";
17
12
  import { isSmallTabletHeight as getIsSmallTabletHeight } from "./utils";
18
13
  import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "./const";
19
14
 
20
- const isIOS = isApplePlatform();
21
-
22
15
  const MIN_WIDTH = TABLET_LANDSCAPE.MIN_WIDTH; // Minimum width for the audio player container
23
16
  const MAX_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL; // Maximum spacing for the audio player container
24
17
  const MIN_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL_S; // Minimum spacing for the audio player container
@@ -68,22 +61,6 @@ const styles = StyleSheet.create({
68
61
  },
69
62
  });
70
63
 
71
- const isTabletWithHomeButton = (bottomInset: number): boolean =>
72
- bottomInset === 0;
73
-
74
- const withAdditionalOffset = ({ progressBarHeight, bottomInset }) => {
75
- if (isIOS && isTabletWithHomeButton(bottomInset)) {
76
- return progressBarHeight === 0 ? 8 : progressBarHeight + 2;
77
- }
78
-
79
- if (isIOS && !isTabletWithHomeButton(bottomInset)) {
80
- return progressBarHeight === 0 ? 4 : 1;
81
- }
82
-
83
- // android
84
- return progressBarHeight === 0 ? 4 : 0.5;
85
- };
86
-
87
64
  export function TabletLandscapeLayout({
88
65
  entry,
89
66
  layoutState,
@@ -96,21 +73,16 @@ export function TabletLandscapeLayout({
96
73
  onSkipStart,
97
74
  onSkipLive,
98
75
  onSpeedButtonPress,
99
- onCloseVideoModal,
100
76
  playbackSpeedName,
101
77
  configuration,
102
- dimensions,
103
- playNextData,
104
78
  title,
105
79
  summary,
106
80
  }: Props) {
107
81
  const [imageWidth, setImageWidth] = React.useState(0);
108
82
  const { docked } = layoutState;
109
83
 
110
- const { bottom: bottomInset } = useSafeAreaInsets();
111
84
  const { height: screenHeight } = useSafeAreaFrame();
112
85
  const isSmallScreen = getIsSmallTabletHeight(screenHeight);
113
- const { progressBarHeight } = useModalAnimationContext();
114
86
 
115
87
  const onLayoutImage = React.useCallback((e) => {
116
88
  setImageWidth(e.nativeEvent.layout.width);
@@ -149,20 +121,7 @@ export function TabletLandscapeLayout({
149
121
  <PlayerImage
150
122
  docked={false}
151
123
  entry={entry}
152
- layoutState={layoutState}
153
- playerState={playerState}
154
- value={value}
155
124
  configuration={configuration}
156
- onPlayerSeek={onPlayerSeek}
157
- onCloseVideoModal={onCloseVideoModal}
158
- dimensions={dimensions}
159
- playNextData={playNextData}
160
- title={title}
161
- summary={summary}
162
- verticalOffset={withAdditionalOffset({
163
- progressBarHeight,
164
- bottomInset,
165
- })}
166
125
  onLayoutImage={onLayoutImage}
167
126
  />
168
127
  ) : null}
@@ -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,5 +1,4 @@
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";
@@ -13,6 +12,7 @@ import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "../const";
13
12
  import { withDebug } from "../debug";
14
13
  import { useSafeAreaFrame } from "react-native-safe-area-context";
15
14
  import { isSmallTabletHeight } from "../utils";
15
+ import { getPlayerActionButtons } from "@applicaster/zapp-react-native-utils/playerUtils";
16
16
 
17
17
  const styles = StyleSheet.create({
18
18
  container: {
@@ -82,14 +82,8 @@ export const TransportInfo = ({
82
82
  );
83
83
 
84
84
  const actionButtons = React.useMemo(
85
- () =>
86
- compose(
87
- take(2),
88
- map(trim),
89
- split(","),
90
- propOr("", "player_action_buttons")
91
- )(configuration),
92
- [configuration.player_action_buttons]
85
+ () => getPlayerActionButtons(configuration),
86
+ [configuration]
93
87
  );
94
88
 
95
89
  return (
@@ -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);
@@ -96,9 +96,7 @@ export function AnimatedModal({
96
96
  >
97
97
  <Pressable
98
98
  testID="collapsedBarWrapper"
99
- onPress={() => {
100
- expand();
101
- }}
99
+ onPress={expand}
102
100
  style={styles.collapsedBarWrapper}
103
101
  >
104
102
  {collapsedContent}
@@ -11,6 +11,7 @@ import {
11
11
  MODAL_RADIUS,
12
12
  SCREEN_HEIGHT,
13
13
  SCREEN_WIDTH,
14
+ VIDEO_TRANSITION_THRESHOLD,
14
15
  } from "./consts";
15
16
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
16
17
  import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils";
@@ -31,14 +32,15 @@ const directionStyles = (isLandscape: boolean): ViewStyle => {
31
32
  type AnimatedModalProps = {
32
33
  enabled?: boolean;
33
34
  pip?: boolean;
35
+ fullscreen?: boolean;
34
36
  content?: (
35
- opacity: Animated.Value | Animated.AnimatedInterpolation
37
+ opacity: Animated.Value | Animated.AnimatedInterpolation<number>
36
38
  ) => ReactElement;
37
39
  collapsedContent?: (
38
- opacity: Animated.Value | Animated.AnimatedInterpolation
40
+ opacity: Animated.Value | Animated.AnimatedInterpolation<number>
39
41
  ) => ReactElement;
40
42
  extraContent?: (
41
- opacity: Animated.Value | Animated.AnimatedInterpolation
43
+ opacity: Animated.Value | Animated.AnimatedInterpolation<number>
42
44
  ) => ReactElement;
43
45
  aspectRatio?: number;
44
46
  isTabletPortrait?: boolean;
@@ -49,6 +51,8 @@ type AnimatedModalProps = {
49
51
  };
50
52
  };
51
53
 
54
+ const height = SCREEN_HEIGHT;
55
+
52
56
  export function VideoPlayerModal({
53
57
  enabled = true,
54
58
  aspectRatio = DEFAULT_IMAGE_RATIO_VIDEO,
@@ -58,15 +62,14 @@ export function VideoPlayerModal({
58
62
  isTabletPortrait,
59
63
  style,
60
64
  pip = false,
65
+ fullscreen = false,
61
66
  }: AnimatedModalProps) {
62
67
  const isTablet = useIsTablet();
63
68
 
64
69
  let width = SCREEN_WIDTH;
65
- let height = SCREEN_HEIGHT;
66
70
 
67
71
  if (isTablet && !isTabletPortrait) {
68
72
  width = style?.tabletLandscapeWidth || width;
69
- height = SCREEN_HEIGHT; // Keep height consistent for landscape
70
73
  }
71
74
 
72
75
  const { minimised_height: minimisedHeight } = useConfiguration();
@@ -88,69 +91,80 @@ export function VideoPlayerModal({
88
91
 
89
92
  const SCALE_FACTOR = 1 / (width / aspectRatio / minimisedHeight); // Scale factor for expanded content
90
93
 
91
- const VIDEO_TRANSITION_THRESHOLD = 0.5; // Threshold for video transition
92
-
93
94
  const insets = useSafeAreaInsets();
94
95
 
96
+ const isFullScreenOrPIP = fullscreen || pip;
97
+
95
98
  // Interpolated opacities for smooth cross-fade
96
- const collapsedOpacity = translateY.interpolate({
97
- inputRange: [MODAL_COLLAPSE_START, height - collapsedHeight],
98
- outputRange: [0, 1],
99
- extrapolate: "clamp",
100
- });
101
-
102
- const expandedOpacity = translateY.interpolate({
103
- inputRange: [0, height - collapsedHeight],
104
- outputRange: [1, 0],
105
- extrapolate: "clamp",
106
- });
107
-
108
- const xPosition = translateY.interpolate({
109
- inputRange: [height * VIDEO_TRANSITION_THRESHOLD, height - collapsedHeight],
110
- outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
111
- extrapolate: "clamp",
112
- });
99
+ const collapsedOpacity = !isFullScreenOrPIP
100
+ ? translateY.interpolate({
101
+ inputRange: [MODAL_COLLAPSE_START, height - collapsedHeight],
102
+ outputRange: [0, 1],
103
+ extrapolate: "clamp",
104
+ })
105
+ : new Animated.Value(0);
106
+
107
+ const expandedOpacity = !isFullScreenOrPIP
108
+ ? translateY.interpolate({
109
+ inputRange: [0, height - collapsedHeight],
110
+ outputRange: [1, 0],
111
+ extrapolate: "clamp",
112
+ })
113
+ : new Animated.Value(1);
114
+
115
+ const xPosition = !isFullScreenOrPIP
116
+ ? translateY.interpolate({
117
+ inputRange: [
118
+ height * VIDEO_TRANSITION_THRESHOLD,
119
+ height - collapsedHeight,
120
+ ],
121
+ outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
122
+ extrapolate: "clamp",
123
+ })
124
+ : new Animated.Value(0);
113
125
 
114
126
  const vidHeight = width / aspectRatio;
115
127
 
116
- const yPosition = translateY.interpolate({
117
- inputRange: [height * VIDEO_TRANSITION_THRESHOLD, height - collapsedHeight],
118
- outputRange: [
119
- 0,
120
- isTablet && isTabletLandscape
121
- ? -(
122
- (-PROGRESS_BAR_HEIGHT + SCREEN_HEIGHT - vidHeight * SCALE_FACTOR) /
123
- 2
124
- )
125
- : -(
126
- PROGRESS_BAR_HEIGHT +
127
- insets.top / 2 +
128
- (SCREEN_WIDTH / aspectRatio -
129
- (SCREEN_WIDTH / aspectRatio) * SCALE_FACTOR) /
130
- 2
131
- ),
132
- ],
133
- extrapolate: "clamp",
134
- });
135
-
136
- const scalePosition = translateY.interpolate({
137
- inputRange: [
138
- SCREEN_HEIGHT * VIDEO_TRANSITION_THRESHOLD,
139
- SCREEN_HEIGHT - collapsedHeight,
140
- ],
141
- outputRange: [1, SCALE_FACTOR],
142
- extrapolate: "clamp",
143
- });
144
-
145
- const borderTopRadiusAnimated = translateY.interpolate({
146
- inputRange: [0, SCREEN_HEIGHT - collapsedHeight],
147
- outputRange: [MODAL_RADIUS, 0],
148
- extrapolate: "clamp",
149
- });
150
-
151
- if (pip) {
152
- return content(new Animated.Value(1));
153
- }
128
+ const yPosition = !isFullScreenOrPIP
129
+ ? translateY.interpolate({
130
+ inputRange: [
131
+ height * VIDEO_TRANSITION_THRESHOLD,
132
+ height - collapsedHeight,
133
+ ],
134
+ outputRange: [
135
+ 0,
136
+ isTablet && isTabletLandscape
137
+ ? -((-PROGRESS_BAR_HEIGHT + height - vidHeight * SCALE_FACTOR) / 2)
138
+ : -(
139
+ PROGRESS_BAR_HEIGHT +
140
+ insets.top / 2 +
141
+ (SCREEN_WIDTH / aspectRatio -
142
+ (SCREEN_WIDTH / aspectRatio) * SCALE_FACTOR) /
143
+ 2
144
+ ),
145
+ ],
146
+ extrapolate: "clamp",
147
+ })
148
+ : new Animated.Value(0);
149
+
150
+ const scalePosition = !isFullScreenOrPIP
151
+ ? translateY.interpolate({
152
+ inputRange: [
153
+ height * VIDEO_TRANSITION_THRESHOLD,
154
+ height - collapsedHeight,
155
+ ],
156
+ outputRange: [1, SCALE_FACTOR],
157
+ extrapolate: "clamp",
158
+ })
159
+ : new Animated.Value(1);
160
+
161
+ const borderTopRadiusAnimated = !isFullScreenOrPIP
162
+ ? translateY.interpolate({
163
+ inputRange: [0, height - collapsedHeight],
164
+ outputRange: [MODAL_RADIUS, 0],
165
+ extrapolate: "clamp",
166
+ })
167
+ : new Animated.Value(0);
154
168
 
155
169
  return (
156
170
  <PanGestureHandler
@@ -165,8 +179,8 @@ export function VideoPlayerModal({
165
179
  {
166
180
  borderTopLeftRadius: borderTopRadiusAnimated,
167
181
  borderTopRightRadius: borderTopRadiusAnimated,
168
- transform: [{ translateY }],
169
- height: SCREEN_HEIGHT,
182
+ transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
183
+ height: height,
170
184
  },
171
185
  ]}
172
186
  >
@@ -178,7 +192,7 @@ export function VideoPlayerModal({
178
192
  {
179
193
  borderTopLeftRadius: borderTopRadiusAnimated,
180
194
  borderTopRightRadius: borderTopRadiusAnimated,
181
- height: SCREEN_HEIGHT,
195
+ height: height,
182
196
  },
183
197
  ]}
184
198
  >
@@ -216,23 +230,23 @@ export function VideoPlayerModal({
216
230
  ) : null}
217
231
  </Animated.View>
218
232
 
219
- <Animated.View
220
- pointerEvents={collapsed ? "box-none" : "none"}
221
- style={[
222
- styles.collapsedBarContainer,
223
- { opacity: collapsedOpacity },
224
- ]}
225
- >
226
- <Pressable
227
- testID="collapsedBarWrapper"
228
- onPress={() => {
229
- expand();
230
- }}
231
- style={styles.collapsedBarWrapper}
233
+ {!isFullScreenOrPIP ? (
234
+ <Animated.View
235
+ pointerEvents={collapsed ? "box-none" : "none"}
236
+ style={[
237
+ styles.collapsedBarContainer,
238
+ { opacity: collapsedOpacity },
239
+ ]}
232
240
  >
233
- {collapsedContent}
234
- </Pressable>
235
- </Animated.View>
241
+ <Pressable
242
+ testID="collapsedBarWrapper"
243
+ onPress={expand}
244
+ style={styles.collapsedBarWrapper}
245
+ >
246
+ {collapsedContent}
247
+ </Pressable>
248
+ </Animated.View>
249
+ ) : null}
236
250
  </Animated.View>
237
251
  </Animated.View>
238
252
  </PanGestureHandler>
@@ -1,15 +1,29 @@
1
- import { Dimensions } from "react-native";
1
+ import { isAndroidTablet } from "@applicaster/zapp-react-native-utils/reactHooks/layout/isTablet";
2
+ import {
3
+ isAndroidPlatform,
4
+ isAndroidVersionAtLeast,
5
+ } from "@applicaster/zapp-react-native-utils/reactUtils";
6
+ import { Dimensions, StatusBar } from "react-native";
2
7
 
3
8
  export const DOCKED_PROGRESSBAR_HEIGHT = 3; // Height of the docked progress bar plugins/mobile-transport-controls/src/ProgressBar/layouts/DockedLayout.tsx
4
9
 
5
- export const { width: SCREEN_WIDTH, height: SCREEN_HEIGHT } =
6
- Dimensions.get("window");
10
+ export const VIDEO_TRANSITION_THRESHOLD = 0.5; // Threshold for video transition
11
+
12
+ const windowDimensions = Dimensions.get("window");
13
+
14
+ const isOldAndroidDevice =
15
+ isAndroidPlatform() && !isAndroidVersionAtLeast(35) && !isAndroidTablet();
16
+
17
+ export const SCREEN_WIDTH = windowDimensions.width;
18
+
19
+ export const SCREEN_HEIGHT =
20
+ windowDimensions.height + (isOldAndroidDevice ? StatusBar.currentHeight : 0);
7
21
 
8
22
  export const MODAL_COLLAPSE_START = SCREEN_HEIGHT * 0.7; // 70% of screen height
9
23
 
10
- export const DRAG_TO_COLLAPSE = 0.3; // 30% to collapse
24
+ export const DRAG_TO_COLLAPSE = 0.02; // 2% to collapse
11
25
 
12
- export const DRAG_TO_EXPAND = 0.3; // 30% to expand
26
+ export const DRAG_TO_EXPAND = 0.02; // 2% to expand
13
27
 
14
28
  export const DEFAULT_IMAGE_RATIO_VIDEO = 16 / 9; // Default aspect ratio for video
15
29
 
@@ -92,7 +92,7 @@ export const useVideoModalState = (
92
92
  // Collapse
93
93
  Animated.timing(translateY, {
94
94
  toValue: SCREEN_HEIGHT - collapsedHeight,
95
- duration: 250,
95
+ duration: ANIMATION_DURATION,
96
96
  useNativeDriver: true,
97
97
  }).start(() => {
98
98
  minimiseVideoModal();
@@ -102,7 +102,7 @@ export const useVideoModalState = (
102
102
  // Expand
103
103
  Animated.timing(translateY, {
104
104
  toValue: 0,
105
- duration: 250,
105
+ duration: ANIMATION_DURATION,
106
106
  useNativeDriver: true,
107
107
  }).start(() => {
108
108
  maximiseVideoModal();
@@ -80,6 +80,7 @@ export const useStyles = ({ height }: { height: number }) => {
80
80
  flex: 0,
81
81
  },
82
82
  extraContentScrollView: {
83
+ width: "100%",
83
84
  backgroundColor: BG_COLOR_DEFAULT_TRANSPARENT,
84
85
  },
85
86
  collapsedBarContainer: {
@@ -13,11 +13,10 @@ export const GenericTVPlayerView: React.FC<GenericTVPlayerViewProps> = ({
13
13
  audioPlayerProps,
14
14
  transportControls,
15
15
  entry,
16
- inline,
17
16
  }) => {
18
17
  return (
19
18
  <>
20
- {type === "audio" && inline ? (
19
+ {type === "audio" ? (
21
20
  <AudioPlayer
22
21
  audio_item={entry}
23
22
  plugin_configuration={pluginConfiguration}
@@ -1036,6 +1036,7 @@ export default class VideoPlayer extends React.Component<
1036
1036
  isTabletPortrait={isTabletPortrait}
1037
1037
  aspectRatio={aspectRatio}
1038
1038
  pip={this.state.piped}
1039
+ fullscreen={fullscreen}
1039
1040
  style={{
1040
1041
  tabletLandscapeWidth: getTabletWidth(
1041
1042
  this.getPluginConfiguration().tablet_landscape_sidebar_width,