@applicaster/quick-brick-player 13.0.0-rc.111 → 13.0.0-rc.112
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 +5 -5
- package/src/Player/AudioLayer/AudioDescription.tsx +109 -68
- package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +23 -5
- package/src/Player/AudioLayer/Layout/Controls/index.tsx +4 -0
- package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +19 -10
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +32 -21
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +3 -0
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +74 -75
- package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +15 -2
- package/src/Player/AudioLayer/Layout/const.ts +4 -0
- package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +1 -1
- package/src/Player/AudioLayer/Layout/utils.ts +7 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "13.0.0-rc.
|
|
3
|
+
"version": "13.0.0-rc.112",
|
|
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.
|
|
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.
|
|
41
|
-
"@applicaster/zapp-react-native-ui-components": "13.0.0-rc.
|
|
42
|
-
"@applicaster/zapp-react-native-utils": "13.0.0-rc.
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "13.0.0-rc.112",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "13.0.0-rc.112",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "13.0.0-rc.112",
|
|
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
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
|
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
|
-
{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { StyleSheet, View
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
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
|
|
108
|
-
|
|
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
|
|
138
|
-
{
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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(
|
|
66
|
-
|
|
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(
|
|
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);
|