@applicaster/quick-brick-player 13.0.0-rc.111 → 13.0.0-rc.113

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": "13.0.0-rc.111",
3
+ "version": "13.0.0-rc.113",
4
4
  "description": "Quick Brick Player",
5
5
  "main": "./src/index.ts",
6
6
  "types": "index.d.ts",
@@ -35,11 +35,11 @@
35
35
  },
36
36
  "homepage": "https://github.com/applicaster/quickbrick#readme",
37
37
  "dependencies": {
38
- "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.111",
38
+ "@applicaster/quick-brick-mobile-transport-controls": "13.0.0-rc.112",
39
39
  "@applicaster/quick-brick-tv-transport-controls": "13.0.0-rc.56",
40
- "@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.111",
41
- "@applicaster/zapp-react-native-ui-components": "13.0.0-rc.111",
42
- "@applicaster/zapp-react-native-utils": "13.0.0-rc.111",
40
+ "@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.113",
41
+ "@applicaster/zapp-react-native-ui-components": "13.0.0-rc.113",
42
+ "@applicaster/zapp-react-native-utils": "13.0.0-rc.113",
43
43
  "query-string": "7.1.3",
44
44
  "react-native-web-linear-gradient": "1.1.2",
45
45
  "shaka-player": "4.3.5",
@@ -1,5 +1,5 @@
1
1
  import React from "react";
2
- import { Text, TextStyle } from "react-native";
2
+ import { StyleSheet, Text, TextStyle, View } from "react-native";
3
3
  import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
4
4
 
5
5
  type AudioDescriptionProps = {
@@ -10,84 +10,125 @@ type AudioDescriptionProps = {
10
10
  docked: boolean;
11
11
  isModal: boolean;
12
12
  };
13
+ maxWidth?: number;
13
14
  value: GetValue;
14
15
  };
15
16
 
16
- const titleStyles = (value: GetValue, prefix: string): TextStyle => ({
17
- textAlign: "left",
18
- color: value(`${prefix}title_color`),
19
- alignSelf: "center",
20
- paddingBottom: 5,
21
- lineHeight:
22
- Number(
23
- platformSelect({
24
- ios: value(`${prefix}title_lineheight_ios`),
25
- android: value(`${prefix}title_lineheight_android`),
26
- })
27
- ) || 18,
28
- letterSpacing:
29
- Number(
30
- platformSelect({
31
- ios: value(`${prefix}title_letterspacing_ios`),
32
- android: value(`${prefix}title_letterspacing_android`),
33
- })
34
- ) || 0,
35
- fontSize:
36
- Number(
37
- platformSelect({
38
- ios: value(`${prefix}title_fontsize_ios`),
39
- android: value(`${prefix}title_fontsize_android`),
40
- })
41
- ) || 16,
42
- fontFamily: platformSelect({
43
- ios: value(`${prefix}title_font_ios`),
44
- android: value(`${prefix}title_font_android`),
45
- }),
46
- });
17
+ const TITLE_PADDING_BOTTOM = 5;
18
+ const TITLE_LINES = 2;
19
+ const SUBTITLE_LINES = 1;
47
20
 
48
- const summaryStyles = (value: GetValue, prefix: string): TextStyle => ({
49
- textAlign: "left",
50
- color: value(`${prefix}subtitle_color`),
51
- alignSelf: "center",
52
- lineHeight:
53
- Number(
54
- platformSelect({
55
- ios: value(`${prefix}subtitle_lineheight_ios`),
56
- android: value(`${prefix}subtitle_lineheight_android`),
57
- })
58
- ) || 18,
59
- letterSpacing:
60
- Number(
61
- platformSelect({
62
- ios: value(`${prefix}subtitle_letterspacing_ios`),
63
- android: value(`${prefix}subtitle_letterspacing_android`),
64
- })
65
- ) || 0,
66
- fontSize:
67
- Number(
68
- platformSelect({
69
- ios: value(`${prefix}subtitle_fontsize_ios`),
70
- android: value(`${prefix}subtitle_fontsize_android`),
71
- })
72
- ) || 13,
73
- fontFamily: platformSelect({
74
- ios: value(`${prefix}subtitle_font_ios`),
75
- android: value(`${prefix}subtitle_font_android`),
76
- }),
21
+ const styles = StyleSheet.create({
22
+ wrapper: {
23
+ width: "100%",
24
+ alignSelf: "center",
25
+ alignItems: "center",
26
+ justifyContent: "center",
27
+ },
28
+ titleText: {
29
+ textAlign: "center",
30
+ alignSelf: "center",
31
+ paddingBottom: TITLE_PADDING_BOTTOM,
32
+ },
33
+ summaryText: {
34
+ textAlign: "left",
35
+ alignSelf: "center",
36
+ },
77
37
  });
78
38
 
39
+ const getTitleStyles = (value: GetValue, prefix: string) =>
40
+ ({
41
+ color: value(`${prefix}title_color`),
42
+ lineHeight:
43
+ Number(
44
+ platformSelect({
45
+ ios: value(`${prefix}title_lineheight_ios`),
46
+ android: value(`${prefix}title_lineheight_android`),
47
+ })
48
+ ) || 18,
49
+ letterSpacing:
50
+ Number(
51
+ platformSelect({
52
+ ios: value(`${prefix}title_letterspacing_ios`),
53
+ android: value(`${prefix}title_letterspacing_android`),
54
+ })
55
+ ) || 0,
56
+ fontSize:
57
+ Number(
58
+ platformSelect({
59
+ ios: value(`${prefix}title_fontsize_ios`),
60
+ android: value(`${prefix}title_fontsize_android`),
61
+ })
62
+ ) || 16,
63
+ fontFamily: platformSelect({
64
+ ios: value(`${prefix}title_font_ios`),
65
+ android: value(`${prefix}title_font_android`),
66
+ }),
67
+ }) as const;
68
+
69
+ const getSummaryStyles = (value: GetValue, prefix: string): TextStyle =>
70
+ ({
71
+ color: value(`${prefix}subtitle_color`),
72
+ lineHeight:
73
+ Number(
74
+ platformSelect({
75
+ ios: value(`${prefix}subtitle_lineheight_ios`),
76
+ android: value(`${prefix}subtitle_lineheight_android`),
77
+ })
78
+ ) || 18,
79
+ letterSpacing:
80
+ Number(
81
+ platformSelect({
82
+ ios: value(`${prefix}subtitle_letterspacing_ios`),
83
+ android: value(`${prefix}subtitle_letterspacing_android`),
84
+ })
85
+ ) || 0,
86
+ fontSize:
87
+ Number(
88
+ platformSelect({
89
+ ios: value(`${prefix}subtitle_fontsize_ios`),
90
+ android: value(`${prefix}subtitle_fontsize_android`),
91
+ })
92
+ ) || 13,
93
+ fontFamily: platformSelect({
94
+ ios: value(`${prefix}subtitle_font_ios`),
95
+ android: value(`${prefix}subtitle_font_android`),
96
+ }),
97
+ }) as const;
98
+
99
+ const getHeight = (titleLineHeight: number, subtitleLineHeight) =>
100
+ titleLineHeight * TITLE_LINES + subtitleLineHeight + TITLE_PADDING_BOTTOM;
101
+
79
102
  export const AudioDescription = (props: AudioDescriptionProps) => {
80
- const { title, summary, layoutState, value } = props;
103
+ const { title, summary, layoutState, value, maxWidth } = props;
81
104
  const prefix = layoutState.docked ? "docked_player_" : "";
82
105
 
106
+ const summaryStyles = getSummaryStyles(value, prefix);
107
+ const titleStyles = getTitleStyles(value, prefix);
108
+
109
+ const height = getHeight(titleStyles.lineHeight, summaryStyles.lineHeight);
110
+
83
111
  return (
84
- <>
85
- <Text style={titleStyles(value, prefix)} numberOfLines={2}>
112
+ <View
113
+ style={[
114
+ styles.wrapper,
115
+ {
116
+ maxWidth,
117
+ height,
118
+ },
119
+ ]}
120
+ >
121
+ <Text style={[styles.titleText, titleStyles]} numberOfLines={TITLE_LINES}>
86
122
  {title}
87
123
  </Text>
88
- <Text style={summaryStyles(value, prefix)} numberOfLines={1}>
89
- {summary}
90
- </Text>
91
- </>
124
+ {summary ? (
125
+ <Text
126
+ style={[styles.summaryText, summaryStyles]}
127
+ numberOfLines={SUBTITLE_LINES}
128
+ >
129
+ {summary}
130
+ </Text>
131
+ ) : null}
132
+ </View>
92
133
  );
93
134
  };
@@ -3,25 +3,43 @@ import { View, StyleSheet } from "react-native";
3
3
 
4
4
  import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
5
5
 
6
- import { TABLET_VERTICAL_SEPARATOR_HEIGHT } from "../const";
6
+ import {
7
+ TABLET_VERTICAL_SEPARATOR_HEIGHT,
8
+ TABLET_VERTICAL_SEPARATOR_HEIGHT_S,
9
+ } from "../const";
7
10
 
8
11
  import { withDebug } from "../debug";
12
+ import { useSafeAreaFrame } from "react-native-safe-area-context";
13
+ import { isSmallTabletHeight } from "../utils";
9
14
 
10
15
  const styles = StyleSheet.create({
11
16
  flexingHeight: {
12
17
  flex: 1,
13
-
14
18
  ...withDebug({ backgroundColor: "red" }),
15
19
  },
16
20
  fixedHeight: {
17
21
  height: TABLET_VERTICAL_SEPARATOR_HEIGHT,
18
-
22
+ ...withDebug({ backgroundColor: "red" }),
23
+ },
24
+ fixedHeightSmall: {
25
+ height: TABLET_VERTICAL_SEPARATOR_HEIGHT_S,
19
26
  ...withDebug({ backgroundColor: "red" }),
20
27
  },
21
28
  });
22
29
 
23
30
  export const VerticalGutter = () => {
24
31
  const isTablet = useIsTablet();
25
-
26
- return <View style={isTablet ? styles.fixedHeight : styles.flexingHeight} />;
32
+ const { height } = useSafeAreaFrame();
33
+
34
+ return (
35
+ <View
36
+ style={
37
+ isTablet
38
+ ? isSmallTabletHeight(height)
39
+ ? styles.fixedHeightSmall
40
+ : styles.fixedHeight
41
+ : styles.flexingHeight
42
+ }
43
+ />
44
+ );
27
45
  };
@@ -79,6 +79,8 @@ type Props = {
79
79
  onSpeedButtonPress: Callback;
80
80
  onSleepButtonPress: Callback;
81
81
 
82
+ maxWidth?: number;
83
+
82
84
  docked: boolean;
83
85
  };
84
86
 
@@ -104,6 +106,7 @@ export const Controls = (props: Props) => {
104
106
  onSkipLive,
105
107
  onSpeedButtonPress,
106
108
  onSleepButtonPress,
109
+ maxWidth = 320,
107
110
 
108
111
  docked,
109
112
  } = props;
@@ -270,6 +273,7 @@ export const Controls = (props: Props) => {
270
273
  summary={summary}
271
274
  value={value}
272
275
  layoutState={layoutState}
276
+ maxWidth={maxWidth}
273
277
  />
274
278
 
275
279
  <VerticalGutter />
@@ -36,6 +36,7 @@ type Props = {
36
36
  playNextData: PlayNextData;
37
37
  title: string | number;
38
38
  summary: string | number;
39
+ ImageComponent?: React.ReactNode;
39
40
  };
40
41
 
41
42
  const styles = StyleSheet.create({
@@ -52,6 +53,7 @@ const styles = StyleSheet.create({
52
53
  touchableArea: {
53
54
  flexShrink: 1,
54
55
  flex: 1,
56
+ flexDirection: "row",
55
57
  alignSelf: "stretch",
56
58
  },
57
59
  contentInfo: {
@@ -94,7 +96,7 @@ const playerDimensionsStyle = (
94
96
  minimisedHeight: number,
95
97
  addPadding: boolean
96
98
  ): ViewStyle => ({
97
- paddingLeft: addPadding ? toNumberWithDefault(100, minimisedHeight) : 0,
99
+ width: addPadding ? toNumberWithDefault(100, minimisedHeight) : 0,
98
100
  });
99
101
 
100
102
  const animatedContainerStyle = (
@@ -186,6 +188,7 @@ export const DockedControls = (props: Props) => {
186
188
  playNextData,
187
189
  title,
188
190
  summary,
191
+ ImageComponent,
189
192
  } = props;
190
193
 
191
194
  const isTablet = useIsTablet();
@@ -243,15 +246,21 @@ export const DockedControls = (props: Props) => {
243
246
  )}
244
247
  />
245
248
  <TouchableWithoutFeedback onPress={maximazeVideoModal}>
246
- <View
247
- style={[
248
- styles.touchableArea,
249
- playerDimensionsStyle(
250
- minimisedHeight,
251
- isActiveGesture || layoutState.docked
252
- ),
253
- ]}
254
- >
249
+ <View style={styles.touchableArea}>
250
+ {isActiveGesture || layoutState.docked ? (
251
+ <View
252
+ style={{ width: toNumberWithDefault(100, minimisedHeight) }}
253
+ >
254
+ {ImageComponent || null}
255
+ </View>
256
+ ) : (
257
+ <View
258
+ style={playerDimensionsStyle(
259
+ minimisedHeight,
260
+ isActiveGesture || layoutState.docked
261
+ )}
262
+ />
263
+ )}
255
264
  <View style={[styles.contentInfo, backgroundColorStyle(value)]}>
256
265
  <ContentInfo
257
266
  content={{ ...entry, title, summary }}
@@ -12,6 +12,7 @@ import { FlexImage } from "./FlexImage";
12
12
  import { styles } from "./styles";
13
13
  import { calculateBorderRadius } from "../../utils";
14
14
  import { PlayNextData } from "../types";
15
+ import { LayoutChangeEvent, View } from "react-native";
15
16
 
16
17
  type Props = {
17
18
  entry: ZappEntry;
@@ -26,8 +27,9 @@ type Props = {
26
27
  title: string | number;
27
28
  summary: string | number;
28
29
  docked: boolean;
29
- imageWidth: Option<number>;
30
+ imageWidth?: Option<number>;
30
31
  verticalOffset: number;
32
+ onLayoutImage: (event: LayoutChangeEvent) => void;
31
33
  };
32
34
 
33
35
  export const PlayerImage = (props: Props) => {
@@ -35,9 +37,10 @@ export const PlayerImage = (props: Props) => {
35
37
  entry,
36
38
  dimensions,
37
39
  docked,
38
- imageWidth,
39
40
  verticalOffset,
41
+ imageWidth,
40
42
  configuration,
43
+ onLayoutImage,
41
44
  } = props;
42
45
 
43
46
  const {
@@ -76,25 +79,33 @@ export const PlayerImage = (props: Props) => {
76
79
  }}
77
80
  style={styles.alignItemsCenter}
78
81
  >
79
- {!imageWidth ? (
80
- // we render image with flex until we get size of this image
81
- <FlexImage
82
- entry={entry}
83
- style={styles.backgroundImageContainer}
84
- imageStyle={{ borderRadius }}
85
- />
86
- ) : null}
87
-
88
- {imageWidth ? (
89
- // we have imageSize here and now we could animate resizing of this image
90
- <AnimatedImage
91
- entry={entry}
92
- style={styles.backgroundImageContainer}
93
- imageStyle={{ borderRadius }}
94
- imageWidth={imageWidth}
95
- wrapperViewStyle={shouldShowShadow ? styles.shadow : undefined}
96
- />
97
- ) : null}
82
+ <View onLayout={onLayoutImage}>
83
+ {!imageWidth ? (
84
+ <View
85
+ style={[
86
+ styles.defaultImageWrapperView,
87
+ shouldShowShadow ? styles.shadow : undefined,
88
+ {
89
+ borderRadius,
90
+ },
91
+ ]}
92
+ >
93
+ <FlexImage
94
+ entry={entry}
95
+ style={styles.backgroundImageContainer}
96
+ />
97
+ </View>
98
+ ) : (
99
+ // we have imageSize here and now we could animate resizing of this image
100
+ <AnimatedImage
101
+ entry={entry}
102
+ style={styles.backgroundImageContainer}
103
+ imageStyle={{ borderRadius }}
104
+ imageWidth={imageWidth}
105
+ wrapperViewStyle={shouldShowShadow ? styles.shadow : undefined}
106
+ />
107
+ )}
108
+ </View>
98
109
  </AnimationComponent>
99
110
  </AnimationComponent>
100
111
  );
@@ -16,6 +16,9 @@ export const styles = StyleSheet.create({
16
16
  flex: {
17
17
  flex: 1,
18
18
  },
19
+ defaultImageWrapperView: {
20
+ overflow: "hidden",
21
+ },
19
22
  shadow: {
20
23
  shadowColor: SHADOW_COLOR,
21
24
  shadowOffset: { width: 0, height: 24 },
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { StyleSheet, View, ViewStyle } from "react-native";
2
+ import { StyleSheet, View } from "react-native";
3
3
  import {
4
4
  useSafeAreaFrame,
5
5
  useSafeAreaInsets,
@@ -7,22 +7,30 @@ import {
7
7
  import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
8
8
  import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
9
9
 
10
- import { TABLET_LANDSCAPE } from "./const";
11
10
  import { TransportInfo } from "./TransportInfo";
12
11
  import { PlayerImage } from "./PlayerImage";
13
12
  import { Controls } from "./Controls";
14
13
 
15
- import { useTabletLayoutImageSize, useTransportInfoHeight } from "./hooks";
16
14
  import { DockedControls } from "./DockedControls";
17
15
  import { withDebug } from "./debug";
18
16
 
19
17
  import { Props } from "./types";
18
+ import { isSmallTabletHeight as getIsSmallTabletHeight } from "./utils";
19
+ import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "./const";
20
+ import { FlexImage } from "./PlayerImage/FlexImage";
20
21
 
21
22
  const isIOS = isApplePlatform();
22
23
 
24
+ const MIN_WIDTH = TABLET_LANDSCAPE.MIN_WIDTH; // Minimum width for the audio player container
25
+ const MAX_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL; // Maximum spacing for the audio player container
26
+ const MIN_SPACING = TABLET_LANDSCAPE.MARGIN_VERTICAL_S; // Minimum spacing for the audio player container
27
+ const transportInfoHeight = NAVBAR_HEIGHT;
28
+
23
29
  const styles = StyleSheet.create({
24
30
  container: {
25
31
  flex: 1,
32
+ alignItems: "center",
33
+ height: "100%",
26
34
  ...withDebug({
27
35
  borderWidth: 2,
28
36
  borderColor: "magenta",
@@ -32,30 +40,30 @@ const styles = StyleSheet.create({
32
40
  flex: 1,
33
41
  },
34
42
  audioPlayerContainer: {
35
- flex: 1,
36
- maxHeight: TABLET_LANDSCAPE.MAX_HEIGHT,
37
43
  flexDirection: "column",
38
44
  alignItems: "center",
45
+ minWidth: MIN_WIDTH,
39
46
 
40
47
  ...withDebug({
41
48
  borderWidth: 2,
42
49
  borderColor: "blue",
43
50
  }),
44
51
  },
45
- });
46
-
47
- const tabletStyles = ({
48
- screenHeight,
49
- topInset,
50
- bottomInset,
51
- imageSize,
52
- }): ViewStyle => ({
53
- alignItems: "center",
54
-
55
- height: screenHeight - topInset - bottomInset,
56
- paddingBottom: TABLET_LANDSCAPE.MARGIN_VERTICAL,
57
-
58
- opacity: imageSize ? 1 : 0, // hide content until imageSize is calculated
52
+ audioPlayerContainerPaddings: {
53
+ paddingBottom: MAX_SPACING,
54
+ paddingTop: MAX_SPACING,
55
+ },
56
+ // For small screens, we reduce the padding to fit better
57
+ audioPlayerContainerPaddingsSmall: {
58
+ paddingBottom: MIN_SPACING,
59
+ paddingTop: MIN_SPACING,
60
+ },
61
+ controlsContainer: { flexGrow: 0, alignSelf: "stretch" },
62
+ // eslint-disable-next-line react-native/no-color-literals
63
+ debugYellow: {
64
+ borderWidth: 2,
65
+ borderColor: "yellow",
66
+ },
59
67
  });
60
68
 
61
69
  const isTabletWithHomeButton = (bottomInset: number): boolean =>
@@ -98,83 +106,73 @@ export function TabletLandscapeLayout({
98
106
  title,
99
107
  summary,
100
108
  }: Props) {
109
+ const [imageWidth, setImageWidth] = React.useState(0);
101
110
  const { docked } = layoutState;
102
111
 
103
- const { bottom: bottomInset, top: topInset } = useSafeAreaInsets();
112
+ const { bottom: bottomInset } = useSafeAreaInsets();
104
113
  const { height: screenHeight } = useSafeAreaFrame();
114
+ const isSmallScreen = getIsSmallTabletHeight(screenHeight);
105
115
  const { progressBarHeight } = useModalAnimationContext();
106
116
 
107
- const { imageSize, onLayout } = useTabletLayoutImageSize({
108
- isPortraitMode: false,
109
- });
110
-
111
- const { height: transportInfoHeight, onLayout: onTransportInfoLayout } =
112
- useTransportInfoHeight();
117
+ const onLayoutImage = React.useCallback((e) => {
118
+ setImageWidth(e.nativeEvent.layout.width);
119
+ }, []);
113
120
 
114
121
  return (
115
- <View
116
- style={[
117
- styles.container,
118
- tabletStyles({
119
- screenHeight,
120
- topInset,
121
- bottomInset,
122
- imageSize,
123
- }),
124
- ]}
125
- >
122
+ <View style={styles.container}>
126
123
  {/* TransportInfo */}
127
124
  <TransportInfo
128
125
  entry={entry}
129
126
  layoutState={layoutState}
130
127
  value={value}
131
128
  configuration={configuration}
132
- onLayout={onTransportInfoLayout}
133
129
  />
134
130
 
135
131
  {/* TransportInfo */}
136
132
 
137
- <View style={styles.audioPlayerContainer}>
138
- {/* PlayerImage */}
139
- <View
140
- style={[
141
- styles.flex,
142
- withDebug({
143
- borderWidth: 2,
144
- borderColor: "yellow",
145
- }),
146
- ]}
147
- onLayout={onLayout}
148
- >
149
- <PlayerImage
150
- entry={entry}
151
- layoutState={layoutState}
152
- playerState={playerState}
153
- value={value}
154
- configuration={configuration}
155
- onPlayerSeek={onPlayerSeek}
156
- onCloseVideoModal={onCloseVideoModal}
157
- dimensions={dimensions}
158
- playNextData={playNextData}
159
- title={title}
160
- summary={summary}
161
- docked={docked}
162
- imageWidth={imageSize}
163
- verticalOffset={
164
- transportInfoHeight +
165
- topInset +
166
- withAdditionalOffset({ progressBarHeight, bottomInset })
167
- }
168
- />
133
+ <View
134
+ style={[
135
+ styles.audioPlayerContainer,
136
+ {
137
+ marginTop: isSmallScreen
138
+ ? -TABLET_LANDSCAPE.MARGIN_VERTICAL_S
139
+ : -TABLET_LANDSCAPE.MARGIN_VERTICAL,
140
+ height: screenHeight - transportInfoHeight,
141
+ },
142
+ isSmallScreen
143
+ ? styles.audioPlayerContainerPaddingsSmall
144
+ : styles.audioPlayerContainerPaddings,
145
+ ]}
146
+ >
147
+ {/* PlayerImage non-docked */}
148
+ <View style={[styles.flex, withDebug(styles.debugYellow)]}>
149
+ {!docked ? (
150
+ <PlayerImage
151
+ docked={false}
152
+ entry={entry}
153
+ layoutState={layoutState}
154
+ playerState={playerState}
155
+ value={value}
156
+ configuration={configuration}
157
+ onPlayerSeek={onPlayerSeek}
158
+ onCloseVideoModal={onCloseVideoModal}
159
+ dimensions={dimensions}
160
+ playNextData={playNextData}
161
+ title={title}
162
+ summary={summary}
163
+ verticalOffset={withAdditionalOffset({
164
+ progressBarHeight,
165
+ bottomInset,
166
+ })}
167
+ onLayoutImage={onLayoutImage}
168
+ />
169
+ ) : null}
169
170
  </View>
170
171
  {/* PlayerImage */}
171
172
 
172
- <View
173
- style={{
174
- maxWidth: imageSize,
175
- }}
176
- >
173
+ <View style={styles.controlsContainer}>
177
174
  <Controls
175
+ maxWidth={imageWidth}
178
176
  entry={entry}
179
177
  layoutState={layoutState}
180
178
  playerState={playerState}
@@ -199,6 +197,7 @@ export function TabletLandscapeLayout({
199
197
  </View>
200
198
 
201
199
  <DockedControls
200
+ ImageComponent={<FlexImage entry={entry} style={styles.flex} />}
202
201
  entry={entry}
203
202
  layoutState={layoutState}
204
203
  playerState={playerState}
@@ -14,6 +14,8 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
14
14
 
15
15
  import { NAVBAR_HEIGHT, TABLET_LANDSCAPE } from "../const";
16
16
  import { withDebug } from "../debug";
17
+ import { useSafeAreaFrame } from "react-native-safe-area-context";
18
+ import { isSmallTabletHeight } from "../utils";
17
19
 
18
20
  const styles = StyleSheet.create({
19
21
  container: {
@@ -52,6 +54,7 @@ export const TransportInfo = ({
52
54
  onLayout = noop,
53
55
  }: Props) => {
54
56
  const isTablet = useIsTablet();
57
+ const safeAreaFrame = useSafeAreaFrame();
55
58
  const languageData = useLanguageData("audio-player");
56
59
 
57
60
  const [marginBottom, setMarginBottom] = React.useState(0);
@@ -62,8 +65,18 @@ export const TransportInfo = ({
62
65
  event?.nativeEvent?.layout?.height
63
66
  );
64
67
 
65
- const minHeight = Math.min(height, TABLET_LANDSCAPE.MARGIN_VERTICAL);
66
- setMarginBottom(TABLET_LANDSCAPE.MARGIN_VERTICAL - minHeight);
68
+ const minHeight = Math.min(
69
+ height,
70
+ isTablet && isSmallTabletHeight(safeAreaFrame.height)
71
+ ? TABLET_LANDSCAPE.MARGIN_VERTICAL_S
72
+ : TABLET_LANDSCAPE.MARGIN_VERTICAL
73
+ );
74
+
75
+ setMarginBottom(
76
+ (isTablet && isSmallTabletHeight(safeAreaFrame.height)
77
+ ? TABLET_LANDSCAPE.MARGIN_VERTICAL_S
78
+ : TABLET_LANDSCAPE.MARGIN_VERTICAL) - minHeight
79
+ );
67
80
 
68
81
  // pass layoutChangeEvent to upper level
69
82
  onLayout(event);
@@ -2,9 +2,13 @@ export const PADDING_HORIZONTAL = 15;
2
2
 
3
3
  export const TABLET_VERTICAL_SEPARATOR_HEIGHT = 32;
4
4
 
5
+ export const TABLET_VERTICAL_SEPARATOR_HEIGHT_S = 16;
6
+
5
7
  export const TABLET_LANDSCAPE = {
6
8
  MARGIN_VERTICAL: 80, // gap between safe-area edge and audio-player container
9
+ MARGIN_VERTICAL_S: 60, // gap between safe-area edge and audio-player container
7
10
  MAX_HEIGHT: 750,
11
+ MIN_WIDTH: 320, // Minimum width for the audio player container
8
12
  };
9
13
 
10
14
  export const TABLET_PORTRAIT = {
@@ -19,7 +19,7 @@ const builder = () => {
19
19
  };
20
20
 
21
21
  export const useTransportInfoHeight = () => {
22
- const [height, setHeight] = React.useState(undefined);
22
+ const [height, setHeight] = React.useState(0);
23
23
 
24
24
  const layoutRef = useRefWithInitialValue<ReturnType<typeof builder>>(builder);
25
25
 
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Checks whether the screen height is matches with our threshold for small tablets.
3
+ * @param height screen height
4
+ * @returns boolean indicating if the height is less than 800 pixels
5
+ */
6
+ export const isSmallTabletHeight = (height: number): boolean =>
7
+ !(height >= 800);