@applicaster/quick-brick-player 15.0.0-alpha.5412418016 → 15.0.0-alpha.5830601313
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 +71 -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 +13 -6
- package/src/Player/PlayerModal/VideoPlayerModal.tsx +24 -26
- package/src/Player/PlayerModal/consts/index.ts +2 -19
- package/src/Player/PlayerModal/hooks/index.ts +32 -30
- package/src/Player/PlayerModal/styles.ts +4 -0
- package/src/Player/PlayerModal/utils/index.ts +32 -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.5830601313",
|
|
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.5830601313",
|
|
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.5830601313",
|
|
41
|
+
"@applicaster/zapp-react-native-ui-components": "15.0.0-alpha.5830601313",
|
|
42
|
+
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.5830601313",
|
|
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,12 @@ 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
|
-
|
|
101
|
-
addPadding: boolean
|
|
102
|
-
): ViewStyle => ({
|
|
103
|
-
width: addPadding ? toNumberWithDefault(100, minimisedHeight) : 0,
|
|
104
|
-
});
|
|
93
|
+
const getValue = (key: string, stylesObj: Record<string, any>) =>
|
|
94
|
+
stylesObj?.[key] ?? null;
|
|
105
95
|
|
|
106
96
|
const controlButtons = (
|
|
107
97
|
live: boolean,
|
|
@@ -167,7 +157,6 @@ export const DockedControls = (props: Props) => {
|
|
|
167
157
|
onPlayerSeek = noop,
|
|
168
158
|
playNextData,
|
|
169
159
|
ImageComponent,
|
|
170
|
-
isActiveGesture = true,
|
|
171
160
|
aspectRatio,
|
|
172
161
|
} = props;
|
|
173
162
|
|
|
@@ -185,11 +174,6 @@ export const DockedControls = (props: Props) => {
|
|
|
185
174
|
const configuration = useZStore("playerConfiguration")();
|
|
186
175
|
const playerState = usePlayerState("shared-player-wrapper-docked");
|
|
187
176
|
|
|
188
|
-
const getValue = React.useCallback(
|
|
189
|
-
(key: string, stylesObj: {}) => R.propOr(null, key, stylesObj),
|
|
190
|
-
[]
|
|
191
|
-
);
|
|
192
|
-
|
|
193
177
|
const value = React.useCallback(
|
|
194
178
|
(key: string) => {
|
|
195
179
|
const retVal = getValue(key, configuration);
|
|
@@ -208,7 +192,7 @@ export const DockedControls = (props: Props) => {
|
|
|
208
192
|
|
|
209
193
|
return retVal;
|
|
210
194
|
},
|
|
211
|
-
[...Object.values(configuration), playerState.seekableDuration
|
|
195
|
+
[...Object.values(configuration), playerState.seekableDuration]
|
|
212
196
|
);
|
|
213
197
|
|
|
214
198
|
const { title, summary } = useTitleSummaryOverlay(
|
|
@@ -225,15 +209,65 @@ export const DockedControls = (props: Props) => {
|
|
|
225
209
|
|
|
226
210
|
const insets = useSafeAreaInsets();
|
|
227
211
|
|
|
212
|
+
const progresBarLayoutState = React.useMemo(
|
|
213
|
+
() => ({
|
|
214
|
+
inline: layoutState.inline,
|
|
215
|
+
docked: true,
|
|
216
|
+
isModal: layoutState.isModal,
|
|
217
|
+
pip: layoutState.pip,
|
|
218
|
+
}),
|
|
219
|
+
[layoutState.inline, layoutState.isModal, layoutState.pip]
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
const _controlButtons = React.useMemo(
|
|
223
|
+
() => partial(controlButtons, playerState.isLive && liveButton),
|
|
224
|
+
[playerState.isLive, liveButton]
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
const containerStyles = React.useMemo(
|
|
228
|
+
() => ({
|
|
229
|
+
height: minimisedHeight,
|
|
230
|
+
maxHeight: minimisedHeight,
|
|
231
|
+
}),
|
|
232
|
+
[minimisedHeight]
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
const imageComponentWrapperStyles = React.useMemo(
|
|
236
|
+
() => ({
|
|
237
|
+
aspectRatio: aspectRatio,
|
|
238
|
+
height: minimisedHeight,
|
|
239
|
+
}),
|
|
240
|
+
[aspectRatio, minimisedHeight]
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
const backgroundColorStyle = React.useMemo(
|
|
244
|
+
() => ({
|
|
245
|
+
backgroundColor: dockedBackgroundColor,
|
|
246
|
+
}),
|
|
247
|
+
[dockedBackgroundColor]
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
const bottomSpacerStyle = React.useMemo(() => {
|
|
251
|
+
const tabBarHeight = menuVisible ? bottomTabBarHeight : 0;
|
|
252
|
+
const safeAreaBottomInset = insets.bottom || 0;
|
|
253
|
+
|
|
254
|
+
return {
|
|
255
|
+
height: safeAreaBottomInset + tabBarHeight,
|
|
256
|
+
};
|
|
257
|
+
}, [menuVisible, insets.bottom]);
|
|
258
|
+
|
|
259
|
+
const contentInfoContent = React.useMemo(
|
|
260
|
+
() => ({ ...entry, title, summary }),
|
|
261
|
+
[title, summary, entry]
|
|
262
|
+
);
|
|
263
|
+
|
|
228
264
|
return (
|
|
229
265
|
<>
|
|
230
266
|
<View
|
|
231
267
|
style={[
|
|
232
268
|
styles.container,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
maxHeight: minimisedHeight,
|
|
236
|
-
},
|
|
269
|
+
containerStyles,
|
|
270
|
+
playerState.isLive ? styles.liveMarginTop : styles.marginTop,
|
|
237
271
|
]}
|
|
238
272
|
>
|
|
239
273
|
{!playerState.isLive ? (
|
|
@@ -242,42 +276,23 @@ export const DockedControls = (props: Props) => {
|
|
|
242
276
|
content={entry}
|
|
243
277
|
value={value}
|
|
244
278
|
visible
|
|
245
|
-
layoutState={
|
|
279
|
+
layoutState={progresBarLayoutState}
|
|
246
280
|
onPlayerSeek={onPlayerSeek}
|
|
247
281
|
playerState={playerState}
|
|
248
|
-
startComponentsAnimation={noop}
|
|
249
282
|
docked
|
|
250
283
|
/>
|
|
251
284
|
) : null}
|
|
252
285
|
|
|
253
286
|
<View style={styles.content}>
|
|
254
287
|
<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
|
-
)}
|
|
288
|
+
<View style={imageComponentWrapperStyles}>
|
|
289
|
+
{ImageComponent || null}
|
|
290
|
+
</View>
|
|
269
291
|
<View
|
|
270
292
|
testID="content-info"
|
|
271
|
-
style={[
|
|
272
|
-
styles.contentInfo,
|
|
273
|
-
{ backgroundColor: dockedBackgroundColor },
|
|
274
|
-
]}
|
|
293
|
+
style={[styles.contentInfo, backgroundColorStyle]}
|
|
275
294
|
>
|
|
276
|
-
<ContentInfo
|
|
277
|
-
content={{ ...entry, title, summary }}
|
|
278
|
-
value={value}
|
|
279
|
-
docked
|
|
280
|
-
/>
|
|
295
|
+
<ContentInfo content={contentInfoContent} value={value} docked />
|
|
281
296
|
</View>
|
|
282
297
|
</View>
|
|
283
298
|
<View
|
|
@@ -285,15 +300,13 @@ export const DockedControls = (props: Props) => {
|
|
|
285
300
|
isTablet
|
|
286
301
|
? styles.controlsContainerForTablet
|
|
287
302
|
: styles.controlsContainerForMobile,
|
|
288
|
-
|
|
303
|
+
backgroundColorStyle,
|
|
289
304
|
]}
|
|
290
305
|
>
|
|
291
306
|
<Controls
|
|
292
307
|
value={value}
|
|
293
308
|
visible
|
|
294
|
-
buttons={
|
|
295
|
-
playerState.isLive && liveButton,
|
|
296
|
-
])}
|
|
309
|
+
buttons={_controlButtons}
|
|
297
310
|
style={styles.playPauseButton}
|
|
298
311
|
playNextData={playNextData}
|
|
299
312
|
playerState={playerState}
|
|
@@ -308,12 +321,7 @@ export const DockedControls = (props: Props) => {
|
|
|
308
321
|
</View>
|
|
309
322
|
</View>
|
|
310
323
|
</View>
|
|
311
|
-
<View
|
|
312
|
-
style={{
|
|
313
|
-
height: insets.bottom + (menuVisible ? bottomTabBarHeight : 0),
|
|
314
|
-
backgroundColor: dockedBackgroundColor,
|
|
315
|
-
}}
|
|
316
|
-
/>
|
|
324
|
+
<View style={[bottomSpacerStyle, backgroundColorStyle]} />
|
|
317
325
|
</>
|
|
318
326
|
);
|
|
319
327
|
};
|
|
@@ -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 { getScreenHeight, getWindowHeight } from "./utils";
|
|
9
10
|
|
|
10
11
|
type AnimatedModalProps = {
|
|
11
12
|
content?: ReactElement;
|
|
@@ -28,21 +29,27 @@ 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
|
+
const screenHeight = getScreenHeight();
|
|
35
|
+
|
|
36
|
+
const MODAL_COLLAPSE_START = WINDOW_HEIGHT * MODAL_COLLAPSE_RATIO;
|
|
37
|
+
|
|
31
38
|
// Interpolated opacities for smooth cross-fade
|
|
32
39
|
const collapsedOpacity = translateY.interpolate({
|
|
33
|
-
inputRange: [MODAL_COLLAPSE_START,
|
|
40
|
+
inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
|
|
34
41
|
outputRange: [0, 1],
|
|
35
42
|
extrapolate: "clamp",
|
|
36
43
|
});
|
|
37
44
|
|
|
38
45
|
const expandedOpacity = translateY.interpolate({
|
|
39
|
-
inputRange: [0,
|
|
46
|
+
inputRange: [0, heightAboveMinimised],
|
|
40
47
|
outputRange: [1, 0],
|
|
41
48
|
extrapolate: "clamp",
|
|
42
49
|
});
|
|
43
50
|
|
|
44
51
|
const borderTopRadiusAnimated = translateY.interpolate({
|
|
45
|
-
inputRange: [0,
|
|
52
|
+
inputRange: [0, heightAboveMinimised],
|
|
46
53
|
outputRange: [MODAL_RADIUS, 0],
|
|
47
54
|
extrapolate: "clamp",
|
|
48
55
|
});
|
|
@@ -57,7 +64,7 @@ export function AnimatedModal({
|
|
|
57
64
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
58
65
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
59
66
|
transform: [{ translateY }],
|
|
60
|
-
height:
|
|
67
|
+
height: screenHeight,
|
|
61
68
|
},
|
|
62
69
|
]}
|
|
63
70
|
>
|
|
@@ -67,7 +74,7 @@ export function AnimatedModal({
|
|
|
67
74
|
{
|
|
68
75
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
69
76
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
70
|
-
height:
|
|
77
|
+
height: screenHeight,
|
|
71
78
|
},
|
|
72
79
|
]}
|
|
73
80
|
>
|
|
@@ -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 { getScreenHeight, 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,12 @@ 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 screenHeight = useMemo(() => getScreenHeight(), []); // remember initial height, ignore rotation changes
|
|
65
|
+
const MODAL_COLLAPSE_START = height * MODAL_COLLAPSE_RATIO;
|
|
66
|
+
|
|
67
|
+
let width = WINDOW_WIDTH;
|
|
66
68
|
|
|
67
69
|
if (isTablet && !isTabletPortrait) {
|
|
68
70
|
width = style?.tabletLandscapeWidth || width;
|
|
@@ -83,6 +85,8 @@ export function VideoPlayerModal({
|
|
|
83
85
|
expand,
|
|
84
86
|
} = useVideoModalState(modal ? translateYRef : dummyRef);
|
|
85
87
|
|
|
88
|
+
const heightAboveMinimised = height - collapsedHeight;
|
|
89
|
+
|
|
86
90
|
const isTabletLandscape = !isTV() && isTablet && !isTabletPortrait;
|
|
87
91
|
|
|
88
92
|
const styles = useStyles({ height: collapsedHeight });
|
|
@@ -96,7 +100,7 @@ export function VideoPlayerModal({
|
|
|
96
100
|
// Interpolated opacities for smooth cross-fade
|
|
97
101
|
const collapsedOpacity = !isFullScreenOrPIP
|
|
98
102
|
? translateY.interpolate({
|
|
99
|
-
inputRange: [MODAL_COLLAPSE_START,
|
|
103
|
+
inputRange: [MODAL_COLLAPSE_START, heightAboveMinimised],
|
|
100
104
|
outputRange: [0, 1],
|
|
101
105
|
extrapolate: "clamp",
|
|
102
106
|
})
|
|
@@ -104,7 +108,7 @@ export function VideoPlayerModal({
|
|
|
104
108
|
|
|
105
109
|
const expandedOpacity = !isFullScreenOrPIP
|
|
106
110
|
? translateY.interpolate({
|
|
107
|
-
inputRange: [0,
|
|
111
|
+
inputRange: [0, heightAboveMinimised],
|
|
108
112
|
outputRange: [1, 0],
|
|
109
113
|
extrapolate: "clamp",
|
|
110
114
|
})
|
|
@@ -112,10 +116,7 @@ export function VideoPlayerModal({
|
|
|
112
116
|
|
|
113
117
|
const xPosition = !isFullScreenOrPIP
|
|
114
118
|
? translateY.interpolate({
|
|
115
|
-
inputRange: [
|
|
116
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
117
|
-
height - collapsedHeight,
|
|
118
|
-
],
|
|
119
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
119
120
|
outputRange: [0, -(width - width * SCALE_FACTOR) / 2],
|
|
120
121
|
extrapolate: "clamp",
|
|
121
122
|
})
|
|
@@ -125,10 +126,7 @@ export function VideoPlayerModal({
|
|
|
125
126
|
|
|
126
127
|
const yPosition = !isFullScreenOrPIP
|
|
127
128
|
? translateY.interpolate({
|
|
128
|
-
inputRange: [
|
|
129
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
130
|
-
height - collapsedHeight,
|
|
131
|
-
],
|
|
129
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
132
130
|
outputRange: [
|
|
133
131
|
0,
|
|
134
132
|
isTablet && isTabletLandscape
|
|
@@ -136,8 +134,8 @@ export function VideoPlayerModal({
|
|
|
136
134
|
: -(
|
|
137
135
|
PROGRESS_BAR_HEIGHT +
|
|
138
136
|
insets.top / 2 +
|
|
139
|
-
(
|
|
140
|
-
(
|
|
137
|
+
(WINDOW_WIDTH / aspectRatio -
|
|
138
|
+
(WINDOW_WIDTH / aspectRatio) * SCALE_FACTOR) /
|
|
141
139
|
2
|
|
142
140
|
),
|
|
143
141
|
],
|
|
@@ -147,10 +145,7 @@ export function VideoPlayerModal({
|
|
|
147
145
|
|
|
148
146
|
const scalePosition = !isFullScreenOrPIP
|
|
149
147
|
? translateY.interpolate({
|
|
150
|
-
inputRange: [
|
|
151
|
-
height * VIDEO_TRANSITION_THRESHOLD,
|
|
152
|
-
height - collapsedHeight,
|
|
153
|
-
],
|
|
148
|
+
inputRange: [height * VIDEO_TRANSITION_THRESHOLD, MODAL_COLLAPSE_START],
|
|
154
149
|
outputRange: [1, SCALE_FACTOR],
|
|
155
150
|
extrapolate: "clamp",
|
|
156
151
|
})
|
|
@@ -192,7 +187,7 @@ export function VideoPlayerModal({
|
|
|
192
187
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
193
188
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
194
189
|
transform: [{ translateY: isFullScreenOrPIP ? 0 : translateY }],
|
|
195
|
-
height:
|
|
190
|
+
height: screenHeight,
|
|
196
191
|
},
|
|
197
192
|
]}
|
|
198
193
|
>
|
|
@@ -204,13 +199,16 @@ export function VideoPlayerModal({
|
|
|
204
199
|
{
|
|
205
200
|
borderTopLeftRadius: borderTopRadiusAnimated,
|
|
206
201
|
borderTopRightRadius: borderTopRadiusAnimated,
|
|
207
|
-
height:
|
|
202
|
+
height: screenHeight,
|
|
208
203
|
},
|
|
209
204
|
]}
|
|
210
205
|
>
|
|
211
206
|
<Animated.View
|
|
212
207
|
pointerEvents={!collapsed ? "auto" : "none"}
|
|
213
|
-
style={[
|
|
208
|
+
style={[
|
|
209
|
+
pip ? styles.modalContentPiP : styles.modalContent,
|
|
210
|
+
directionStyles(isTabletLandscape),
|
|
211
|
+
]}
|
|
214
212
|
>
|
|
215
213
|
<Animated.View
|
|
216
214
|
style={[
|