@applicaster/quick-brick-player 15.0.0-alpha.3514407021 → 15.0.0-alpha.4069571733
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/AudioPlayerWrapper.tsx +20 -8
- package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +70 -63
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +1 -6
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +5 -23
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +5 -8
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +1 -6
- package/src/Player/AudioLayer/utils.ts +1 -27
- package/src/Player/PlayerModal/PlayerModal.tsx +12 -6
- package/src/Player/PlayerModal/VideoPlayerModal.tsx +21 -24
- package/src/Player/PlayerModal/consts/index.ts +2 -19
- package/src/Player/PlayerModal/hooks/index.ts +33 -25
- package/src/Player/PlayerModal/styles.ts +4 -0
- package/src/Player/PlayerModal/utils/index.ts +29 -0
- package/src/Player/PlayerView/types.ts +1 -2
- package/src/Player/index.tsx +547 -356
- package/src/utils/dimensions.ts +29 -0
- package/src/utils/index.ts +12 -0
- package/src/utils/logger.ts +6 -0
- package/src/utils/playerHelpers.ts +11 -0
- package/src/utils/playerStyles.ts +50 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +0 -82
- package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +0 -1
- package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +0 -99
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "15.0.0-alpha.
|
|
3
|
+
"version": "15.0.0-alpha.4069571733",
|
|
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": "15.0.0-
|
|
38
|
+
"@applicaster/quick-brick-mobile-transport-controls": "15.0.0-alpha.4069571733",
|
|
39
39
|
"@applicaster/quick-brick-tv-transport-controls": "15.0.0-rc.15",
|
|
40
|
-
"@applicaster/zapp-react-native-tvos-app": "15.0.0-alpha.
|
|
41
|
-
"@applicaster/zapp-react-native-ui-components": "15.0.0-alpha.
|
|
42
|
-
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.
|
|
40
|
+
"@applicaster/zapp-react-native-tvos-app": "15.0.0-alpha.4069571733",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "15.0.0-alpha.4069571733",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.4069571733",
|
|
43
43
|
"query-string": "7.1.3",
|
|
44
44
|
"shaka-player": "4.3.5",
|
|
45
45
|
"typeface-montserrat": "^0.0.54",
|
|
@@ -61,6 +61,7 @@ type Props = {
|
|
|
61
61
|
inline: boolean;
|
|
62
62
|
docked: boolean;
|
|
63
63
|
isModal: boolean;
|
|
64
|
+
pip: boolean;
|
|
64
65
|
};
|
|
65
66
|
playNextData: PlayNextData;
|
|
66
67
|
isTabletPortrait?: boolean;
|
|
@@ -99,11 +100,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
99
100
|
);
|
|
100
101
|
|
|
101
102
|
useEffect(() => {
|
|
102
|
-
|
|
103
|
-
setSpeedManager(new SpeedController(player));
|
|
104
|
-
} else {
|
|
105
|
-
setSpeedManager(null);
|
|
106
|
-
}
|
|
103
|
+
setSpeedManager(player ? new SpeedController(player) : null);
|
|
107
104
|
}, [player]);
|
|
108
105
|
|
|
109
106
|
useEffect(() => {
|
|
@@ -217,7 +214,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
217
214
|
items: speedOptions,
|
|
218
215
|
current_selection: playbackSpeed,
|
|
219
216
|
onPress: onSpeedSelect,
|
|
220
|
-
title: configuration
|
|
217
|
+
title: configuration.playback_speed_title,
|
|
221
218
|
itemProps: getBottomSheetModalItemProps,
|
|
222
219
|
iconProps: getBottomSheetModalIconProps,
|
|
223
220
|
labelProps: getBottomSheetModalLabelProps,
|
|
@@ -233,7 +230,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
233
230
|
],
|
|
234
231
|
},
|
|
235
232
|
});
|
|
236
|
-
}, [playbackSpeed, onSpeedSelect, configuration
|
|
233
|
+
}, [playbackSpeed, onSpeedSelect, configuration.playback_speed_title]);
|
|
237
234
|
|
|
238
235
|
const onPlayerSeek = React.useCallback(
|
|
239
236
|
(targetTime: number) => {
|
|
@@ -250,13 +247,28 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
250
247
|
player?.seekTo(0);
|
|
251
248
|
}, [player]);
|
|
252
249
|
|
|
250
|
+
const layoutStateMemo = React.useMemo(
|
|
251
|
+
() => ({
|
|
252
|
+
inline: layoutState.inline,
|
|
253
|
+
docked: layoutState.docked,
|
|
254
|
+
isModal: layoutState.isModal,
|
|
255
|
+
pip: layoutState.pip,
|
|
256
|
+
}),
|
|
257
|
+
[
|
|
258
|
+
layoutState.inline,
|
|
259
|
+
layoutState.docked,
|
|
260
|
+
layoutState.isModal,
|
|
261
|
+
layoutState.pip,
|
|
262
|
+
]
|
|
263
|
+
);
|
|
264
|
+
|
|
253
265
|
return (
|
|
254
266
|
<SafeAreaView style={[style, Styles.playerContainer]} edges={edges}>
|
|
255
267
|
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
256
268
|
<Layout
|
|
257
269
|
entry={entry}
|
|
258
270
|
playerState={playerState}
|
|
259
|
-
layoutState={
|
|
271
|
+
layoutState={layoutStateMemo}
|
|
260
272
|
value={value}
|
|
261
273
|
onPlaybackButtonPress={onPlaybackButtonPress}
|
|
262
274
|
onRewindButtonPress={onRewindButtonPress}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { StyleSheet, View
|
|
3
|
-
import * as R from "ramda";
|
|
2
|
+
import { StyleSheet, View } from "react-native";
|
|
4
3
|
import {
|
|
5
4
|
useIsTablet,
|
|
6
5
|
useZStore,
|
|
@@ -16,7 +15,6 @@ import {
|
|
|
16
15
|
|
|
17
16
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
18
17
|
|
|
19
|
-
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
20
18
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
21
19
|
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/useNavigation";
|
|
22
20
|
import { getTabBarHeight } from "@applicaster/zapp-react-native-utils/reactHooks/navigation/getTabBarHeight";
|
|
@@ -27,22 +25,17 @@ import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
|
27
25
|
import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/utils";
|
|
28
26
|
import { isMenuVisible } from "@applicaster/zapp-react-native-ui-components/Components/Screen/navigationHandler";
|
|
29
27
|
import { usePlugins } from "@applicaster/zapp-react-native-redux";
|
|
28
|
+
import { partial } from "@applicaster/zapp-react-native-utils/utils";
|
|
30
29
|
|
|
31
30
|
const bottomTabBarHeight = getTabBarHeight();
|
|
32
31
|
|
|
33
32
|
type Props = {
|
|
34
33
|
entry: ZappEntry;
|
|
35
34
|
layoutState: QuickBrickPlayer.LayoutState;
|
|
36
|
-
|
|
37
|
-
value: GetValue;
|
|
38
|
-
onCloseVideoModal: () => void;
|
|
39
|
-
onPlayerSeek: (targetTime: number) => void;
|
|
35
|
+
onPlayerSeek?: (targetTime: number) => void;
|
|
40
36
|
playNextData: PlayNextData;
|
|
41
|
-
title: string | number;
|
|
42
|
-
summary: string | number;
|
|
43
37
|
ImageComponent?: React.ReactNode;
|
|
44
38
|
isActiveGesture?: boolean;
|
|
45
|
-
minimisedHeight: number;
|
|
46
39
|
aspectRatio?: number;
|
|
47
40
|
};
|
|
48
41
|
|
|
@@ -51,7 +44,6 @@ const styles = StyleSheet.create({
|
|
|
51
44
|
flex: 1,
|
|
52
45
|
flexDirection: "column",
|
|
53
46
|
alignItems: "stretch",
|
|
54
|
-
marginTop: PROGRESS_BAR_HEIGHT,
|
|
55
47
|
},
|
|
56
48
|
content: {
|
|
57
49
|
flex: 1,
|
|
@@ -94,14 +86,11 @@ const styles = StyleSheet.create({
|
|
|
94
86
|
buttons: {
|
|
95
87
|
marginVertical: 10,
|
|
96
88
|
},
|
|
89
|
+
liveMarginTop: { marginTop: 0 },
|
|
90
|
+
marginTop: { marginTop: PROGRESS_BAR_HEIGHT },
|
|
97
91
|
});
|
|
98
92
|
|
|
99
|
-
const
|
|
100
|
-
minimisedHeight: number,
|
|
101
|
-
addPadding: boolean
|
|
102
|
-
): ViewStyle => ({
|
|
103
|
-
width: addPadding ? toNumberWithDefault(100, minimisedHeight) : 0,
|
|
104
|
-
});
|
|
93
|
+
const getValue = (key: string, stylesObj: {}) => stylesObj?.[key] ?? null;
|
|
105
94
|
|
|
106
95
|
const controlButtons = (
|
|
107
96
|
live: boolean,
|
|
@@ -167,7 +156,6 @@ export const DockedControls = (props: Props) => {
|
|
|
167
156
|
onPlayerSeek = noop,
|
|
168
157
|
playNextData,
|
|
169
158
|
ImageComponent,
|
|
170
|
-
isActiveGesture = true,
|
|
171
159
|
aspectRatio,
|
|
172
160
|
} = props;
|
|
173
161
|
|
|
@@ -185,11 +173,6 @@ export const DockedControls = (props: Props) => {
|
|
|
185
173
|
const configuration = useZStore("playerConfiguration")();
|
|
186
174
|
const playerState = usePlayerState("shared-player-wrapper-docked");
|
|
187
175
|
|
|
188
|
-
const getValue = React.useCallback(
|
|
189
|
-
(key: string, stylesObj: {}) => R.propOr(null, key, stylesObj),
|
|
190
|
-
[]
|
|
191
|
-
);
|
|
192
|
-
|
|
193
176
|
const value = React.useCallback(
|
|
194
177
|
(key: string) => {
|
|
195
178
|
const retVal = getValue(key, configuration);
|
|
@@ -208,7 +191,7 @@ export const DockedControls = (props: Props) => {
|
|
|
208
191
|
|
|
209
192
|
return retVal;
|
|
210
193
|
},
|
|
211
|
-
[...Object.values(configuration), playerState.seekableDuration
|
|
194
|
+
[...Object.values(configuration), playerState.seekableDuration]
|
|
212
195
|
);
|
|
213
196
|
|
|
214
197
|
const { title, summary } = useTitleSummaryOverlay(
|
|
@@ -225,15 +208,65 @@ export const DockedControls = (props: Props) => {
|
|
|
225
208
|
|
|
226
209
|
const insets = useSafeAreaInsets();
|
|
227
210
|
|
|
211
|
+
const progresBarLayoutState = React.useMemo(
|
|
212
|
+
() => ({
|
|
213
|
+
inline: layoutState.inline,
|
|
214
|
+
docked: true,
|
|
215
|
+
isModal: layoutState.isModal,
|
|
216
|
+
pip: layoutState.pip,
|
|
217
|
+
}),
|
|
218
|
+
[layoutState.inline, layoutState.isModal, layoutState.pip]
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const _controlButtons = React.useMemo(
|
|
222
|
+
() => partial(controlButtons, playerState.isLive && liveButton),
|
|
223
|
+
[playerState.isLive, liveButton]
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const containerStyles = React.useMemo(
|
|
227
|
+
() => ({
|
|
228
|
+
height: minimisedHeight,
|
|
229
|
+
maxHeight: minimisedHeight,
|
|
230
|
+
}),
|
|
231
|
+
[minimisedHeight]
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
const imageComponentWrapperStyles = React.useMemo(
|
|
235
|
+
() => ({
|
|
236
|
+
aspectRatio: aspectRatio,
|
|
237
|
+
height: minimisedHeight,
|
|
238
|
+
}),
|
|
239
|
+
[aspectRatio, minimisedHeight]
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
const backgroundColorStyle = React.useMemo(
|
|
243
|
+
() => ({
|
|
244
|
+
backgroundColor: dockedBackgroundColor,
|
|
245
|
+
}),
|
|
246
|
+
[dockedBackgroundColor]
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
const bottomSpacerStyle = React.useMemo(() => {
|
|
250
|
+
const tabBarHeight = menuVisible ? bottomTabBarHeight : 0;
|
|
251
|
+
const safeAreaBottomInset = insets.bottom || 0;
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
height: safeAreaBottomInset + tabBarHeight,
|
|
255
|
+
};
|
|
256
|
+
}, [menuVisible, insets.bottom]);
|
|
257
|
+
|
|
258
|
+
const contentInfoContent = React.useMemo(
|
|
259
|
+
() => ({ ...entry, title, summary }),
|
|
260
|
+
[title, summary, entry]
|
|
261
|
+
);
|
|
262
|
+
|
|
228
263
|
return (
|
|
229
264
|
<>
|
|
230
265
|
<View
|
|
231
266
|
style={[
|
|
232
267
|
styles.container,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
maxHeight: minimisedHeight,
|
|
236
|
-
},
|
|
268
|
+
containerStyles,
|
|
269
|
+
playerState.isLive ? styles.liveMarginTop : styles.marginTop,
|
|
237
270
|
]}
|
|
238
271
|
>
|
|
239
272
|
{!playerState.isLive ? (
|
|
@@ -242,42 +275,23 @@ export const DockedControls = (props: Props) => {
|
|
|
242
275
|
content={entry}
|
|
243
276
|
value={value}
|
|
244
277
|
visible
|
|
245
|
-
layoutState={
|
|
278
|
+
layoutState={progresBarLayoutState}
|
|
246
279
|
onPlayerSeek={onPlayerSeek}
|
|
247
280
|
playerState={playerState}
|
|
248
|
-
startComponentsAnimation={noop}
|
|
249
281
|
docked
|
|
250
282
|
/>
|
|
251
283
|
) : null}
|
|
252
284
|
|
|
253
285
|
<View style={styles.content}>
|
|
254
286
|
<View style={styles.touchableArea}>
|
|
255
|
-
{
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
>
|
|
259
|
-
{ImageComponent || null}
|
|
260
|
-
</View>
|
|
261
|
-
) : (
|
|
262
|
-
<View
|
|
263
|
-
style={playerDimensionsStyle(
|
|
264
|
-
minimisedHeight,
|
|
265
|
-
isActiveGesture || layoutState.docked
|
|
266
|
-
)}
|
|
267
|
-
/>
|
|
268
|
-
)}
|
|
287
|
+
<View style={imageComponentWrapperStyles}>
|
|
288
|
+
{ImageComponent || null}
|
|
289
|
+
</View>
|
|
269
290
|
<View
|
|
270
291
|
testID="content-info"
|
|
271
|
-
style={[
|
|
272
|
-
styles.contentInfo,
|
|
273
|
-
{ backgroundColor: dockedBackgroundColor },
|
|
274
|
-
]}
|
|
292
|
+
style={[styles.contentInfo, backgroundColorStyle]}
|
|
275
293
|
>
|
|
276
|
-
<ContentInfo
|
|
277
|
-
content={{ ...entry, title, summary }}
|
|
278
|
-
value={value}
|
|
279
|
-
docked
|
|
280
|
-
/>
|
|
294
|
+
<ContentInfo content={contentInfoContent} value={value} docked />
|
|
281
295
|
</View>
|
|
282
296
|
</View>
|
|
283
297
|
<View
|
|
@@ -285,15 +299,13 @@ export const DockedControls = (props: Props) => {
|
|
|
285
299
|
isTablet
|
|
286
300
|
? styles.controlsContainerForTablet
|
|
287
301
|
: styles.controlsContainerForMobile,
|
|
288
|
-
|
|
302
|
+
backgroundColorStyle,
|
|
289
303
|
]}
|
|
290
304
|
>
|
|
291
305
|
<Controls
|
|
292
306
|
value={value}
|
|
293
307
|
visible
|
|
294
|
-
buttons={
|
|
295
|
-
playerState.isLive && liveButton,
|
|
296
|
-
])}
|
|
308
|
+
buttons={_controlButtons}
|
|
297
309
|
style={styles.playPauseButton}
|
|
298
310
|
playNextData={playNextData}
|
|
299
311
|
playerState={playerState}
|
|
@@ -308,12 +320,7 @@ export const DockedControls = (props: Props) => {
|
|
|
308
320
|
</View>
|
|
309
321
|
</View>
|
|
310
322
|
</View>
|
|
311
|
-
<View
|
|
312
|
-
style={{
|
|
313
|
-
height: insets.bottom + (menuVisible ? bottomTabBarHeight : 0),
|
|
314
|
-
backgroundColor: dockedBackgroundColor,
|
|
315
|
-
}}
|
|
316
|
-
/>
|
|
323
|
+
<View style={[bottomSpacerStyle, backgroundColorStyle]} />
|
|
317
324
|
</>
|
|
318
325
|
);
|
|
319
326
|
};
|
|
@@ -151,12 +151,7 @@ export function MobileLayout({
|
|
|
151
151
|
},
|
|
152
152
|
]}
|
|
153
153
|
>
|
|
154
|
-
<PlayerImage
|
|
155
|
-
entry={entry}
|
|
156
|
-
docked={false}
|
|
157
|
-
imageWidth={imageSize}
|
|
158
|
-
configuration={configuration}
|
|
159
|
-
/>
|
|
154
|
+
<PlayerImage entry={entry} configuration={configuration} />
|
|
160
155
|
</View>
|
|
161
156
|
{/* PlayerImage */}
|
|
162
157
|
|
|
@@ -4,7 +4,6 @@ import { LayoutChangeEvent, View } from "react-native";
|
|
|
4
4
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
5
5
|
import { toBooleanWithDefaultTrue } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
6
6
|
|
|
7
|
-
import { AnimatedImage } from "./AnimatedImage";
|
|
8
7
|
import { FlexImage } from "./FlexImage";
|
|
9
8
|
|
|
10
9
|
import { styles } from "./styles";
|
|
@@ -13,19 +12,12 @@ import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/nu
|
|
|
13
12
|
type Props = {
|
|
14
13
|
entry: ZappEntry;
|
|
15
14
|
configuration: QuickBrickPlayer.AudioPlayerProps["configuration"];
|
|
16
|
-
docked
|
|
17
|
-
imageWidth?: Option<number>;
|
|
15
|
+
docked?: boolean;
|
|
18
16
|
onLayoutImage?: (event: LayoutChangeEvent) => void;
|
|
19
17
|
};
|
|
20
18
|
|
|
21
19
|
export const PlayerImage = (props: Props) => {
|
|
22
|
-
const {
|
|
23
|
-
entry,
|
|
24
|
-
docked,
|
|
25
|
-
imageWidth,
|
|
26
|
-
configuration,
|
|
27
|
-
onLayoutImage = noop,
|
|
28
|
-
} = props;
|
|
20
|
+
const { entry, docked = false, configuration, onLayoutImage = noop } = props;
|
|
29
21
|
|
|
30
22
|
const isShadowEnabled = toBooleanWithDefaultTrue(
|
|
31
23
|
configuration?.audio_player_artwork_shadow_enabled
|
|
@@ -43,19 +35,9 @@ export const PlayerImage = (props: Props) => {
|
|
|
43
35
|
onLayout={onLayoutImage}
|
|
44
36
|
style={[shouldShowShadow ? styles.shadow : undefined, { borderRadius }]}
|
|
45
37
|
>
|
|
46
|
-
{
|
|
47
|
-
<
|
|
48
|
-
|
|
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
|
-
)}
|
|
38
|
+
<View style={[styles.defaultImageWrapperView, { borderRadius }]}>
|
|
39
|
+
<FlexImage entry={entry} style={styles.backgroundImageContainer} />
|
|
40
|
+
</View>
|
|
59
41
|
</View>
|
|
60
42
|
</View>
|
|
61
43
|
);
|
|
@@ -117,14 +117,11 @@ export function TabletLandscapeLayout({
|
|
|
117
117
|
<View style={[styles.flex, styles.audioPlayerContainerHeightLimit]}>
|
|
118
118
|
{/* PlayerImage non-docked */}
|
|
119
119
|
<View style={[styles.flex, withDebug(styles.debugYellow)]}>
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
onLayoutImage={onLayoutImage}
|
|
126
|
-
/>
|
|
127
|
-
) : null}
|
|
120
|
+
<PlayerImage
|
|
121
|
+
entry={entry}
|
|
122
|
+
configuration={configuration}
|
|
123
|
+
onLayoutImage={onLayoutImage}
|
|
124
|
+
/>
|
|
128
125
|
</View>
|
|
129
126
|
{/* PlayerImage */}
|
|
130
127
|
|
|
@@ -144,12 +144,7 @@ export function TabletPortraitLayout({
|
|
|
144
144
|
]}
|
|
145
145
|
onLayout={onLayout}
|
|
146
146
|
>
|
|
147
|
-
<PlayerImage
|
|
148
|
-
entry={entry}
|
|
149
|
-
configuration={configuration}
|
|
150
|
-
docked={docked}
|
|
151
|
-
imageWidth={imageSize}
|
|
152
|
-
/>
|
|
147
|
+
<PlayerImage entry={entry} configuration={configuration} />
|
|
153
148
|
</View>
|
|
154
149
|
|
|
155
150
|
<View
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
2
|
-
|
|
3
|
-
PlayerAnimationStateEnum,
|
|
4
|
-
PlayerAnimationStateT,
|
|
5
|
-
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/ModalAnimationContext";
|
|
2
|
+
|
|
6
3
|
import { parseJsonIfNeeded } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
7
|
-
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
8
4
|
|
|
9
5
|
export const NAMESPACE = "audio-player";
|
|
10
6
|
|
|
@@ -36,25 +32,3 @@ export const formatSpeed = (value: number) => {
|
|
|
36
32
|
// Return the formatted string with "speed_" prefix
|
|
37
33
|
return `speed_${formattedValue}`;
|
|
38
34
|
};
|
|
39
|
-
|
|
40
|
-
export const calculateBorderRadius = (
|
|
41
|
-
docked: boolean,
|
|
42
|
-
startComponentsAnimation: boolean,
|
|
43
|
-
isActiveGesture: boolean,
|
|
44
|
-
playerAnimationState: PlayerAnimationStateT,
|
|
45
|
-
configuration: Record<string, any>
|
|
46
|
-
): number => {
|
|
47
|
-
const shouldRemoveBorderRadius =
|
|
48
|
-
(startComponentsAnimation &&
|
|
49
|
-
isActiveGesture &&
|
|
50
|
-
playerAnimationState !== PlayerAnimationStateEnum.maximize) ||
|
|
51
|
-
docked;
|
|
52
|
-
|
|
53
|
-
if (shouldRemoveBorderRadius) {
|
|
54
|
-
return 0;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return toNumberWithDefaultZero(
|
|
58
|
-
configuration.audio_player_artwork_border_radius
|
|
59
|
-
);
|
|
60
|
-
};
|
|
@@ -4,8 +4,9 @@ import { Animated, Pressable } from "react-native";
|
|
|
4
4
|
import { PanGestureHandler } from "react-native-gesture-handler";
|
|
5
5
|
import { useStyles } from "./styles";
|
|
6
6
|
import { useVideoModalState } from "./hooks";
|
|
7
|
-
import {
|
|
7
|
+
import { MODAL_COLLAPSE_RATIO, MODAL_RADIUS } from "./consts";
|
|
8
8
|
import { useModalAnimationContext } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
9
|
+
import { getWindowHeight } from "./utils";
|
|
9
10
|
|
|
10
11
|
type AnimatedModalProps = {
|
|
11
12
|
content?: ReactElement;
|
|
@@ -28,21 +29,26 @@ export function AnimatedModal({
|
|
|
28
29
|
|
|
29
30
|
const styles = useStyles({ height: collapsedHeight, type: "audio" });
|
|
30
31
|
|
|
32
|
+
const WINDOW_HEIGHT = getWindowHeight();
|
|
33
|
+
const heightAboveMinimised = WINDOW_HEIGHT - collapsedHeight;
|
|
34
|
+
|
|
35
|
+
const MODAL_COLLAPSE_START = WINDOW_HEIGHT * MODAL_COLLAPSE_RATIO;
|
|
36
|
+
|
|
31
37
|
// Interpolated opacities for smooth cross-fade
|
|
32
38
|
const collapsedOpacity = translateY.interpolate({
|
|
33
|
-
inputRange: [MODAL_COLLAPSE_START,
|
|
39
|
+
inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
|
|
34
40
|
outputRange: [0, 1],
|
|
35
41
|
extrapolate: "clamp",
|
|
36
42
|
});
|
|
37
43
|
|
|
38
44
|
const expandedOpacity = translateY.interpolate({
|
|
39
|
-
inputRange: [0,
|
|
45
|
+
inputRange: [0, heightAboveMinimised],
|
|
40
46
|
outputRange: [1, 0],
|
|
41
47
|
extrapolate: "clamp",
|
|
42
48
|
});
|
|
43
49
|
|
|
44
50
|
const borderTopRadiusAnimated = translateY.interpolate({
|
|
45
|
-
inputRange: [0,
|
|
51
|
+
inputRange: [0, heightAboveMinimised],
|
|
46
52
|
outputRange: [MODAL_RADIUS, 0],
|
|
47
53
|
extrapolate: "clamp",
|
|
48
54
|
});
|
|
@@ -57,7 +63,7 @@ export function AnimatedModal({
|
|
|
57
63
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
58
64
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
59
65
|
transform: [{ translateY }],
|
|
60
|
-
height:
|
|
66
|
+
height: WINDOW_HEIGHT,
|
|
61
67
|
},
|
|
62
68
|
]}
|
|
63
69
|
>
|
|
@@ -67,7 +73,7 @@ export function AnimatedModal({
|
|
|
67
73
|
{
|
|
68
74
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
69
75
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
70
|
-
height:
|
|
76
|
+
height: WINDOW_HEIGHT,
|
|
71
77
|
},
|
|
72
78
|
]}
|
|
73
79
|
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { ReactElement, useRef } from "react";
|
|
1
|
+
import React, { ReactElement, useMemo, useRef } from "react";
|
|
2
2
|
|
|
3
3
|
import { Animated, Pressable, StyleSheet, ViewStyle } from "react-native";
|
|
4
4
|
import { PanGestureHandler } from "react-native-gesture-handler";
|
|
@@ -7,10 +7,8 @@ import { useConfiguration } from "@applicaster/zapp-react-native-ui-components/C
|
|
|
7
7
|
import { useVideoModalState } from "./hooks";
|
|
8
8
|
import {
|
|
9
9
|
DEFAULT_IMAGE_RATIO_VIDEO,
|
|
10
|
-
|
|
10
|
+
MODAL_COLLAPSE_RATIO,
|
|
11
11
|
MODAL_RADIUS,
|
|
12
|
-
SCREEN_HEIGHT,
|
|
13
|
-
SCREEN_WIDTH,
|
|
14
12
|
VIDEO_TRANSITION_THRESHOLD,
|
|
15
13
|
} from "./consts";
|
|
16
14
|
import { useIsTablet } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
@@ -20,6 +18,7 @@ import { PROGRESS_BAR_HEIGHT } from "@applicaster/zapp-react-native-ui-component
|
|
|
20
18
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
21
19
|
import { GestureAnimatedScrollView } from "./GestureAnimatedScrollView";
|
|
22
20
|
import { PlayerDetailsWrapperHeightContext } from "./context";
|
|
21
|
+
import { getWindowHeight, getWindowWidth } from "./utils";
|
|
23
22
|
|
|
24
23
|
const orientationStyles = StyleSheet.create({
|
|
25
24
|
landscape: { flexDirection: "row" },
|
|
@@ -46,8 +45,6 @@ type AnimatedModalProps = {
|
|
|
46
45
|
};
|
|
47
46
|
};
|
|
48
47
|
|
|
49
|
-
const height = SCREEN_HEIGHT;
|
|
50
|
-
|
|
51
48
|
export function VideoPlayerModal({
|
|
52
49
|
aspectRatio = DEFAULT_IMAGE_RATIO_VIDEO,
|
|
53
50
|
content,
|
|
@@ -62,7 +59,11 @@ export function VideoPlayerModal({
|
|
|
62
59
|
const enabled = !!modal && !fullscreen;
|
|
63
60
|
const isTablet = useIsTablet();
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
const WINDOW_WIDTH = useMemo(() => getWindowWidth(), []); // remember initial width, ignore rotation changes
|
|
63
|
+
const height = useMemo(() => getWindowHeight(), []); // remember initial height, ignore rotation changes
|
|
64
|
+
const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
|
|
65
|
+
|
|
66
|
+
let width = WINDOW_WIDTH;
|
|
66
67
|
|
|
67
68
|
if (isTablet && !isTabletPortrait) {
|
|
68
69
|
width = style?.tabletLandscapeWidth || width;
|
|
@@ -83,6 +84,8 @@ export function VideoPlayerModal({
|
|
|
83
84
|
expand,
|
|
84
85
|
} = useVideoModalState(modal ? translateYRef : dummyRef);
|
|
85
86
|
|
|
87
|
+
const heightAboveMinimised = height - collapsedHeight;
|
|
88
|
+
|
|
86
89
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
87
90
|
|
|
88
91
|
const styles = useStyles({ height: collapsedHeight });
|
|
@@ -96,7 +99,7 @@ export function VideoPlayerModal({
|
|
|
96
99
|
// Interpolated opacities for smooth cross-fade
|
|
97
100
|
const collapsedOpacity = !isFullScreenOrPIP
|
|
98
101
|
? translateY.interpolate({
|
|
99
|
-
inputRange: [MODAL_COLLAPSE_START,
|
|
102
|
+
inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
|
|
100
103
|
outputRange: [0, 1],
|
|
101
104
|
extrapolate: "clamp",
|
|
102
105
|
})
|
|
@@ -104,7 +107,7 @@ export function VideoPlayerModal({
|
|
|
104
107
|
|
|
105
108
|
const expandedOpacity = !isFullScreenOrPIP
|
|
106
109
|
? translateY.interpolate({
|
|
107
|
-
inputRange: [0,
|
|
110
|
+
inputRange: [0, heightAboveMinimised],
|
|
108
111
|
outputRange: [1, 0],
|
|
109
112
|
extrapolate: "clamp",
|
|
110
113
|
})
|
|
@@ -112,10 +115,7 @@ export function VideoPlayerModal({
|
|
|
112
115
|
|
|
113
116
|
const xPosition = !isFullScreenOrPIP
|
|
114
117
|
? translateY.interpolate({
|
|
115
|
-
inputRange: [
|
|
116
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
117
|
-
height - collapsedHeight,
|
|
118
|
-
],
|
|
118
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
119
119
|
outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
|
|
120
120
|
extrapolate: "clamp",
|
|
121
121
|
})
|
|
@@ -125,10 +125,7 @@ export function VideoPlayerModal({
|
|
|
125
125
|
|
|
126
126
|
const yPosition = !isFullScreenOrPIP
|
|
127
127
|
? translateY.interpolate({
|
|
128
|
-
inputRange: [
|
|
129
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
130
|
-
height - collapsedHeight,
|
|
131
|
-
],
|
|
128
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
132
129
|
outputRange: [
|
|
133
130
|
0,
|
|
134
131
|
isTablet && isTabletLandscape
|
|
@@ -136,8 +133,8 @@ export function VideoPlayerModal({
|
|
|
136
133
|
: -(
|
|
137
134
|
PROGRESS_BAR_HEIGHT +
|
|
138
135
|
insets.top / 2 +
|
|
139
|
-
(
|
|
140
|
-
(
|
|
136
|
+
(WINDOW_WIDTH / aspectRatio -
|
|
137
|
+
(WINDOW_WIDTH / aspectRatio) * SCALE_FACTOR) /
|
|
141
138
|
2
|
|
142
139
|
),
|
|
143
140
|
],
|
|
@@ -147,10 +144,7 @@ export function VideoPlayerModal({
|
|
|
147
144
|
|
|
148
145
|
const scalePosition = !isFullScreenOrPIP
|
|
149
146
|
? translateY.interpolate({
|
|
150
|
-
inputRange: [
|
|
151
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
152
|
-
height - collapsedHeight,
|
|
153
|
-
],
|
|
147
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
154
148
|
outputRange: [1, SCALE_FACTOR],
|
|
155
149
|
extrapolate: "clamp",
|
|
156
150
|
})
|
|
@@ -210,7 +204,10 @@ export function VideoPlayerModal({
|
|
|
210
204
|
>
|
|
211
205
|
<Animated.View
|
|
212
206
|
pointerEvents={!collapsed ? "auto" : "none"}
|
|
213
|
-
style={[
|
|
207
|
+
style={[
|
|
208
|
+
pip ? styles.modalContentPiP : styles.modalContent,
|
|
209
|
+
directionStyles(isTabletLandscape),
|
|
210
|
+
]}
|
|
214
211
|
>
|
|
215
212
|
<Animated.View
|
|
216
213
|
style={[
|