@applicaster/quick-brick-player 12.0.0-alpha.9531194637 → 12.0.0-alpha.9709055278
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 +75 -67
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +185 -72
- package/src/Player/AudioLayer/Layout/DockedLayout.tsx +62 -17
- package/src/Player/AudioLayer/Layout/defaultLayoutsConts.ts +2 -0
- package/src/Player/AudioLayer/Layout/index.tsx +1 -7
- package/src/Player/Utils/Utils.ts +7 -21
- package/src/Player/index.tsx +51 -34
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-player",
|
|
3
|
-
"version": "12.0.0-alpha.
|
|
3
|
+
"version": "12.0.0-alpha.9709055278",
|
|
4
4
|
"description": "Quick Brick Player",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@applicaster/quick-brick-mobile-transport-controls": "12.0.0-
|
|
39
|
+
"@applicaster/quick-brick-mobile-transport-controls": "12.0.0-alpha.9709055278",
|
|
40
40
|
"@applicaster/quick-brick-tv-transport-controls": "11.0.0-rc.133",
|
|
41
|
-
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.
|
|
42
|
-
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.
|
|
43
|
-
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.
|
|
41
|
+
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.9709055278",
|
|
42
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.9709055278",
|
|
43
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.9709055278",
|
|
44
44
|
"keymirror": "^0.1.1",
|
|
45
45
|
"query-string": "7.1.3",
|
|
46
46
|
"react-native-web-linear-gradient": "1.1.2",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
import { ViewStyle, View
|
|
2
|
+
import { ViewStyle, View } from "react-native";
|
|
3
3
|
|
|
4
4
|
import { SafeAreaView, Edge } from "react-native-safe-area-context";
|
|
5
5
|
import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
|
|
@@ -26,6 +26,12 @@ import {
|
|
|
26
26
|
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
27
27
|
import { addQueryParam, getLiveUrl } from "../Utils";
|
|
28
28
|
import { useTitleSummaryOverlay } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerTitleSummaryOverlay";
|
|
29
|
+
import {
|
|
30
|
+
AnimationComponent,
|
|
31
|
+
ComponentAnimationType,
|
|
32
|
+
AnimatedScrollModal,
|
|
33
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
34
|
+
import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
|
|
29
35
|
|
|
30
36
|
const { log_debug } = createLogger({
|
|
31
37
|
subsystem: "UIComponent",
|
|
@@ -68,29 +74,20 @@ export const defaultAspectRatioWidth = (height: number): number =>
|
|
|
68
74
|
(height / 9) * 16;
|
|
69
75
|
|
|
70
76
|
const Styles = {
|
|
71
|
-
mainContainer: (
|
|
77
|
+
mainContainer: (style: ViewStyle) => {
|
|
72
78
|
const combinedStyle: ViewStyle = {
|
|
73
79
|
flex: 1,
|
|
74
80
|
};
|
|
75
81
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
style
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return { ...combinedStyle, ...style };
|
|
82
|
-
},
|
|
83
|
-
playerContainer: (docked: boolean, style: ViewStyle) => {
|
|
84
|
-
const combinedStyle: ViewStyle = {
|
|
85
|
-
flex: 1,
|
|
82
|
+
return {
|
|
83
|
+
...combinedStyle,
|
|
84
|
+
...style,
|
|
86
85
|
};
|
|
87
|
-
|
|
88
|
-
if (docked) {
|
|
89
|
-
combinedStyle.height = style.height;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return combinedStyle;
|
|
93
86
|
},
|
|
87
|
+
playerContainer: {
|
|
88
|
+
flex: 1,
|
|
89
|
+
},
|
|
90
|
+
paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
|
|
94
91
|
|
|
95
92
|
controlsMobile: {
|
|
96
93
|
height: 50,
|
|
@@ -168,6 +165,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
168
165
|
|
|
169
166
|
const [sleepTimerDate, setSleepTimerDate] = useState(0);
|
|
170
167
|
|
|
168
|
+
const [defaultDimensions, setDefaultDimensions] =
|
|
169
|
+
React.useState<Dimensions>(undefined);
|
|
170
|
+
|
|
171
171
|
const [dimensions, setDimensions] = React.useState<Dimensions>({
|
|
172
172
|
width: 0,
|
|
173
173
|
height: 0,
|
|
@@ -181,9 +181,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
181
181
|
const { width, height } = event.nativeEvent.layout;
|
|
182
182
|
|
|
183
183
|
setDimensions({
|
|
184
|
-
width
|
|
184
|
+
width,
|
|
185
185
|
height,
|
|
186
186
|
});
|
|
187
|
+
|
|
188
|
+
if (!defaultDimensions) setDefaultDimensions({ width, height });
|
|
187
189
|
};
|
|
188
190
|
|
|
189
191
|
const cancelSleepTimer = async () => {
|
|
@@ -292,7 +294,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
292
294
|
playerState.isPaused ? player?.play() : player.pause();
|
|
293
295
|
}, [playerState, player]);
|
|
294
296
|
|
|
295
|
-
const seekDuration = Number(value("seek_duration"));
|
|
297
|
+
const seekDuration = Number(value("seek_duration")) ?? 10;
|
|
296
298
|
|
|
297
299
|
const onRewindButtonPress = React.useCallback(() => {
|
|
298
300
|
player?.rewind(seekDuration);
|
|
@@ -375,58 +377,64 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
375
377
|
player?.seekTo(0);
|
|
376
378
|
}, [player]);
|
|
377
379
|
|
|
378
|
-
const edges = React.useMemo<Edge[]>(
|
|
379
|
-
() => (docked ? [] : ["right", "left", "top"]),
|
|
380
|
-
[docked]
|
|
381
|
-
);
|
|
380
|
+
const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
|
|
382
381
|
|
|
383
|
-
const ContainerView =
|
|
382
|
+
const ContainerView = SafeAreaView;
|
|
384
383
|
|
|
385
384
|
const MainContent = React.useMemo(() => {
|
|
386
385
|
return (
|
|
387
|
-
<ContainerView style={Styles.mainContainer(
|
|
388
|
-
<
|
|
389
|
-
|
|
390
|
-
|
|
386
|
+
<ContainerView style={Styles.mainContainer(style)} edges={edges}>
|
|
387
|
+
<AnimationComponent
|
|
388
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
389
|
+
additionalData={{ saveArea: true }}
|
|
391
390
|
>
|
|
392
|
-
<
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
391
|
+
<AnimatedScrollModal>
|
|
392
|
+
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
393
|
+
<Layout
|
|
394
|
+
entry={entry}
|
|
395
|
+
playerState={playerState}
|
|
396
|
+
layoutState={layoutState}
|
|
397
|
+
value={value}
|
|
398
|
+
onPlaybackButtonPress={onPlaybackButtonPress}
|
|
399
|
+
onRewindButtonPress={onRewindButtonPress}
|
|
400
|
+
onForwardButtonPress={onForwardButtonPress}
|
|
401
|
+
onPlayerSeek={onPlayerSeek}
|
|
402
|
+
onSkipStart={onSkipStart}
|
|
403
|
+
onSpeedButtonPress={onSpeedButtonPress}
|
|
404
|
+
onSleepButtonPress={onSleepButtonPress}
|
|
405
|
+
playbackSpeedName={formatSpeed(playbackSpeed.value)}
|
|
406
|
+
playbackSleepName={
|
|
407
|
+
sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
|
|
408
|
+
}
|
|
409
|
+
sleepTimerDate={sleepTimerDate}
|
|
410
|
+
cancelSleepTimer={cancelSleepTimer}
|
|
411
|
+
onSkipLive={onSkipLive}
|
|
412
|
+
onCloseVideoModal={onCloseVideoModal}
|
|
413
|
+
maximiseVideoModal={maximiseVideoModal}
|
|
414
|
+
configuration={configuration}
|
|
415
|
+
dimensions={dimensions}
|
|
416
|
+
playNextData={playNextData}
|
|
417
|
+
title={title}
|
|
418
|
+
summary={summary}
|
|
419
|
+
defaultDimensions={defaultDimensions}
|
|
420
|
+
/>
|
|
421
|
+
<View style={Styles.paddingHorizontal}>
|
|
422
|
+
{children}
|
|
423
|
+
<AnimationComponent
|
|
424
|
+
animationType={ComponentAnimationType.componentFade}
|
|
425
|
+
>
|
|
426
|
+
<PlayerDetails
|
|
427
|
+
configuration={configuration}
|
|
428
|
+
style={Styles.playerDetails}
|
|
429
|
+
entry={entry}
|
|
430
|
+
isTabletLandscape={isTabletLandscape}
|
|
431
|
+
isAudioPlayer={true}
|
|
432
|
+
/>
|
|
433
|
+
</AnimationComponent>
|
|
434
|
+
</View>
|
|
435
|
+
</View>
|
|
436
|
+
</AnimatedScrollModal>
|
|
437
|
+
</AnimationComponent>
|
|
430
438
|
</ContainerView>
|
|
431
439
|
);
|
|
432
440
|
}, [
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
// DefaultLayout.tsx
|
|
2
|
+
|
|
1
3
|
import * as React from "react";
|
|
2
4
|
import * as R from "ramda";
|
|
3
5
|
import { View } from "react-native";
|
|
6
|
+
import dayjs from "dayjs";
|
|
7
|
+
import utc from "dayjs/plugin/utc";
|
|
4
8
|
|
|
5
9
|
import {
|
|
6
10
|
ProgressBar,
|
|
@@ -18,13 +22,24 @@ import {
|
|
|
18
22
|
rewindButton,
|
|
19
23
|
skipToStartButton,
|
|
20
24
|
skipToLiveButton,
|
|
25
|
+
PADDING_HORIZONTAL,
|
|
21
26
|
speedButton,
|
|
22
27
|
sleepButton,
|
|
23
28
|
} from "./defaultLayoutsConts";
|
|
24
29
|
import { AudioDescription } from "../AudioDescription";
|
|
25
30
|
import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
|
|
26
31
|
import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
|
|
32
|
+
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
27
33
|
import { useEffect, useMemo, useState } from "react";
|
|
34
|
+
import {
|
|
35
|
+
useModalAnimationContext,
|
|
36
|
+
AnimationComponent,
|
|
37
|
+
ComponentAnimationType,
|
|
38
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
39
|
+
import DockedLayout from "./DockedLayout";
|
|
40
|
+
import { isValidDate } from "../../Utils";
|
|
41
|
+
|
|
42
|
+
dayjs.extend(utc);
|
|
28
43
|
|
|
29
44
|
type Dimensions = {
|
|
30
45
|
width: number;
|
|
@@ -60,22 +75,29 @@ type LayoutProps = {
|
|
|
60
75
|
onPlayerSeek: (targetTime: number) => void;
|
|
61
76
|
onSkipLive: () => void;
|
|
62
77
|
onSkipStart: () => void;
|
|
78
|
+
onCloseVideoModal: () => void;
|
|
79
|
+
maximiseVideoModal: () => void;
|
|
63
80
|
dimensions: Dimensions;
|
|
81
|
+
playNextData: PlayNextData;
|
|
64
82
|
title: string | number;
|
|
65
83
|
summary: string | number;
|
|
84
|
+
defaultDimensions: Dimensions;
|
|
66
85
|
};
|
|
67
86
|
|
|
68
87
|
const Styles = {
|
|
69
88
|
container: { flex: 1 },
|
|
70
|
-
tabletContainer: (isPortraitMode) => ({
|
|
89
|
+
tabletContainer: (isPortraitMode: boolean) => ({
|
|
71
90
|
flex: 1,
|
|
72
91
|
alignItems: "center",
|
|
73
92
|
justifyContent: isPortraitMode ? "center" : "flex-start",
|
|
74
93
|
}),
|
|
75
|
-
|
|
76
|
-
width:
|
|
94
|
+
playerImageWrapper: {
|
|
95
|
+
width: "100%",
|
|
77
96
|
maxHeight: 750,
|
|
78
97
|
marginTop: 80,
|
|
98
|
+
},
|
|
99
|
+
tabletLayout: {
|
|
100
|
+
width: 463,
|
|
79
101
|
marginBottom: 80,
|
|
80
102
|
},
|
|
81
103
|
controls: (isTablet: boolean, isLiveShowFullControls: boolean) => ({
|
|
@@ -84,24 +106,31 @@ const Styles = {
|
|
|
84
106
|
justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
|
|
85
107
|
}),
|
|
86
108
|
backgroundImageContainer: (dimensions: Dimensions, isTablet: boolean) => {
|
|
109
|
+
const mobileValue = dimensions.width
|
|
110
|
+
? dimensions.width - PADDING_HORIZONTAL * 2
|
|
111
|
+
: 330;
|
|
112
|
+
|
|
87
113
|
return {
|
|
88
|
-
width: isTablet ? 463 :
|
|
89
|
-
height: isTablet ? 463 :
|
|
114
|
+
width: isTablet ? 463 : mobileValue,
|
|
115
|
+
height: isTablet ? 463 : mobileValue,
|
|
90
116
|
};
|
|
91
117
|
},
|
|
92
|
-
backgroundImageContainerImageStyle: (
|
|
93
|
-
|
|
118
|
+
backgroundImageContainerImageStyle: (
|
|
119
|
+
isTablet: boolean,
|
|
120
|
+
docked: boolean,
|
|
121
|
+
startComponentsAnimation: boolean,
|
|
122
|
+
isActiveGesture: boolean
|
|
123
|
+
) => ({
|
|
124
|
+
borderRadius:
|
|
125
|
+
(startComponentsAnimation && isActiveGesture) || docked
|
|
126
|
+
? 0
|
|
127
|
+
: isTablet
|
|
128
|
+
? 24
|
|
129
|
+
: 10,
|
|
94
130
|
}),
|
|
95
|
-
playerContainer: (docked: boolean, style) => {
|
|
96
|
-
const combinedStyle = {
|
|
97
|
-
flex: 1,
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
if (docked) {
|
|
101
|
-
combinedStyle["height"] = style.height;
|
|
102
|
-
}
|
|
103
131
|
|
|
104
|
-
|
|
132
|
+
paddingHorizontal: {
|
|
133
|
+
paddingHorizontal: PADDING_HORIZONTAL,
|
|
105
134
|
},
|
|
106
135
|
|
|
107
136
|
controlsMobile: {
|
|
@@ -115,6 +144,12 @@ const Styles = {
|
|
|
115
144
|
separator: {
|
|
116
145
|
height: 20,
|
|
117
146
|
},
|
|
147
|
+
flexDirectionRow: {
|
|
148
|
+
flexDirection: "row",
|
|
149
|
+
},
|
|
150
|
+
alignItemsCenter: {
|
|
151
|
+
alignItems: "center",
|
|
152
|
+
},
|
|
118
153
|
};
|
|
119
154
|
|
|
120
155
|
export default function DefaultLayout(props: LayoutProps) {
|
|
@@ -139,12 +174,14 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
139
174
|
sleepTimerDate,
|
|
140
175
|
title,
|
|
141
176
|
summary,
|
|
177
|
+
defaultDimensions,
|
|
142
178
|
} = props;
|
|
143
179
|
|
|
144
180
|
const isTablet = useIsTablet();
|
|
145
181
|
const { width, height } = dimensions;
|
|
146
182
|
const isPortraitMode = width < height;
|
|
147
183
|
const isLiveContent = playerState.isLive;
|
|
184
|
+
const docked = layoutState.docked;
|
|
148
185
|
|
|
149
186
|
const languageData = useLanguageData("audio-player");
|
|
150
187
|
|
|
@@ -160,8 +197,35 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
160
197
|
|
|
161
198
|
let showFullControls = !controller?.isAd();
|
|
162
199
|
|
|
200
|
+
// Safely access and validate start_time and end_time
|
|
201
|
+
const startTime = entry.extensions?.start_time;
|
|
202
|
+
const endTime = entry.extensions?.end_time;
|
|
203
|
+
|
|
204
|
+
const hasValidStartTime = isValidDate(startTime);
|
|
205
|
+
const hasValidEndTime = isValidDate(endTime);
|
|
206
|
+
|
|
207
|
+
// Abstracted condition
|
|
208
|
+
const isDateBasedLiveContent =
|
|
209
|
+
isLiveContent && hasValidStartTime && hasValidEndTime;
|
|
210
|
+
|
|
211
|
+
// Determine if progress bar should be shown
|
|
212
|
+
const needsToShowProgressBar =
|
|
213
|
+
(isLiveContent &&
|
|
214
|
+
(Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
|
|
215
|
+
!isLiveContent;
|
|
216
|
+
|
|
217
|
+
// Convert valid date strings to timestamps
|
|
218
|
+
const startTimestamp = hasValidStartTime
|
|
219
|
+
? dayjs.utc(startTime!).valueOf()
|
|
220
|
+
: undefined;
|
|
221
|
+
|
|
222
|
+
const endTimestamp = hasValidEndTime
|
|
223
|
+
? dayjs.utc(endTime!).valueOf()
|
|
224
|
+
: undefined;
|
|
225
|
+
|
|
163
226
|
if (isLiveContent) {
|
|
164
227
|
const seekEnabled = Boolean(value("liveSeekingEnabled"));
|
|
228
|
+
|
|
165
229
|
showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
|
|
166
230
|
}
|
|
167
231
|
|
|
@@ -191,12 +255,14 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
191
255
|
|
|
192
256
|
const rewind = rewindButton({
|
|
193
257
|
isTablet,
|
|
194
|
-
onPress: controller?.
|
|
258
|
+
onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
|
|
195
259
|
});
|
|
196
260
|
|
|
197
261
|
const forward = forwardButton({
|
|
198
262
|
isTablet,
|
|
199
|
-
onPress: controller?.
|
|
263
|
+
onPress: controller?.hasSeekableDuration?.()
|
|
264
|
+
? onForwardButtonPress
|
|
265
|
+
: null,
|
|
200
266
|
});
|
|
201
267
|
|
|
202
268
|
const speed = speedButton({
|
|
@@ -278,10 +344,15 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
278
344
|
|
|
279
345
|
const Separator = () => <View style={Styles.separator} />;
|
|
280
346
|
|
|
281
|
-
const
|
|
347
|
+
const defaultImageDimensions = React.useMemo(
|
|
348
|
+
() =>
|
|
349
|
+
defaultDimensions &&
|
|
350
|
+
Styles.backgroundImageContainer(defaultDimensions, isTablet),
|
|
351
|
+
[defaultDimensions, isTablet]
|
|
352
|
+
);
|
|
282
353
|
|
|
283
|
-
const
|
|
284
|
-
(
|
|
354
|
+
const { isActiveGesture, startComponentsAnimation } =
|
|
355
|
+
useModalAnimationContext();
|
|
285
356
|
|
|
286
357
|
return (
|
|
287
358
|
<View
|
|
@@ -289,65 +360,107 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
289
360
|
isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
|
|
290
361
|
}
|
|
291
362
|
>
|
|
292
|
-
<
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
363
|
+
<AnimationComponent animationType={ComponentAnimationType.componentFade}>
|
|
364
|
+
<TransportInfo
|
|
365
|
+
content={entry}
|
|
366
|
+
value={value}
|
|
367
|
+
visible={true}
|
|
368
|
+
languageData={languageData}
|
|
369
|
+
layoutState={layoutState}
|
|
370
|
+
actionButtons={actionButtons}
|
|
371
|
+
/>
|
|
372
|
+
</AnimationComponent>
|
|
373
|
+
<AnimationComponent
|
|
374
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
375
|
+
style={isTablet ? Styles.playerImageWrapper : undefined}
|
|
304
376
|
>
|
|
305
|
-
<
|
|
377
|
+
<AnimationComponent
|
|
378
|
+
animationType={ComponentAnimationType.moveComponentHorizontal}
|
|
379
|
+
additionalData={{
|
|
380
|
+
disableAnimatedComponent: !isTablet,
|
|
381
|
+
moveValue: (dimensions.width - 463) / 2,
|
|
382
|
+
extraAnimation: !isTablet
|
|
383
|
+
? {
|
|
384
|
+
[ComponentAnimationType.audioPlayerPaddingHorizontal]: {
|
|
385
|
+
style: Styles.paddingHorizontal,
|
|
386
|
+
},
|
|
387
|
+
}
|
|
388
|
+
: null,
|
|
389
|
+
}}
|
|
390
|
+
style={isTablet ? Styles.alignItemsCenter : undefined}
|
|
391
|
+
>
|
|
306
392
|
<PlayerImageBackground
|
|
307
393
|
entry={entry}
|
|
308
394
|
style={Styles.backgroundImageContainer(dimensions, isTablet)}
|
|
309
|
-
imageStyle={Styles.backgroundImageContainerImageStyle(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
395
|
+
imageStyle={Styles.backgroundImageContainerImageStyle(
|
|
396
|
+
isTablet,
|
|
397
|
+
docked,
|
|
398
|
+
startComponentsAnimation,
|
|
399
|
+
isActiveGesture
|
|
400
|
+
)}
|
|
401
|
+
defaultImageDimensions={defaultImageDimensions}
|
|
316
402
|
/>
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
403
|
+
</AnimationComponent>
|
|
404
|
+
|
|
405
|
+
<DockedLayout {...props} />
|
|
406
|
+
</AnimationComponent>
|
|
407
|
+
<View
|
|
408
|
+
style={[
|
|
409
|
+
Styles.paddingHorizontal,
|
|
410
|
+
isTablet ? Styles.tabletLayout : undefined,
|
|
411
|
+
]}
|
|
412
|
+
>
|
|
413
|
+
{!docked && (
|
|
414
|
+
<AnimationComponent
|
|
415
|
+
animationType={ComponentAnimationType.componentFade}
|
|
416
|
+
>
|
|
417
|
+
<AudioDescription
|
|
418
|
+
title={title}
|
|
419
|
+
summary={summary}
|
|
420
|
+
value={value}
|
|
421
|
+
layoutState={layoutState}
|
|
422
|
+
/>
|
|
423
|
+
<Separator />
|
|
424
|
+
{needsToShowProgressBar && (
|
|
425
|
+
<View>
|
|
426
|
+
<ProgressBar
|
|
427
|
+
content={entry}
|
|
334
428
|
value={value}
|
|
335
|
-
|
|
429
|
+
visible={true}
|
|
430
|
+
layoutState={layoutState}
|
|
431
|
+
onPlayerSeek={onPlayerSeek}
|
|
432
|
+
playerState={playerState}
|
|
433
|
+
disableFullscreen={true}
|
|
434
|
+
sliderStyle={2}
|
|
435
|
+
startTimestamp={startTimestamp}
|
|
436
|
+
endTimestamp={endTimestamp}
|
|
437
|
+
isDateBasedLiveContent={isDateBasedLiveContent}
|
|
336
438
|
/>
|
|
337
|
-
)}
|
|
338
439
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
440
|
+
{showCounter && timeLeft >= 0 && (
|
|
441
|
+
<CountDown
|
|
442
|
+
timeLeft={timeLeft}
|
|
443
|
+
value={value}
|
|
444
|
+
title={sleepTitle}
|
|
445
|
+
/>
|
|
446
|
+
)}
|
|
447
|
+
|
|
448
|
+
<Separator />
|
|
449
|
+
</View>
|
|
450
|
+
)}
|
|
451
|
+
<Controls
|
|
452
|
+
value={value}
|
|
453
|
+
visible={true}
|
|
454
|
+
keepAlive={null}
|
|
455
|
+
buttons={controlButtons}
|
|
456
|
+
style={Styles.controls(
|
|
457
|
+
isTablet,
|
|
458
|
+
isLiveContent && showFullControls
|
|
459
|
+
)}
|
|
460
|
+
playerState={playerState}
|
|
461
|
+
/>
|
|
462
|
+
</AnimationComponent>
|
|
463
|
+
)}
|
|
351
464
|
</View>
|
|
352
465
|
</View>
|
|
353
466
|
);
|
|
@@ -15,8 +15,13 @@ import {
|
|
|
15
15
|
Button,
|
|
16
16
|
} from "@applicaster/quick-brick-mobile-transport-controls";
|
|
17
17
|
|
|
18
|
-
import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
|
|
19
18
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
19
|
+
import {
|
|
20
|
+
useModalAnimationContext,
|
|
21
|
+
AnimationComponent,
|
|
22
|
+
ComponentAnimationType,
|
|
23
|
+
PlayerAnimationStateEnum,
|
|
24
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
20
25
|
|
|
21
26
|
type Dimensions = {
|
|
22
27
|
width: number;
|
|
@@ -104,14 +109,26 @@ const backgroundColorStyle = (value: GetValue): ViewStyle => ({
|
|
|
104
109
|
backgroundColor: value("docked_player_background_color"),
|
|
105
110
|
});
|
|
106
111
|
|
|
107
|
-
const playerDimensionsStyle = (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
112
|
+
const playerDimensionsStyle = (
|
|
113
|
+
minimisedHeight: number,
|
|
114
|
+
addPadding: boolean
|
|
115
|
+
): ViewStyle => ({
|
|
116
|
+
paddingLeft: addPadding ? minimisedHeight || 100 : 0,
|
|
111
117
|
});
|
|
112
118
|
|
|
113
|
-
const
|
|
114
|
-
|
|
119
|
+
const animatedContainerStyle = (docked: boolean): ViewStyle => ({
|
|
120
|
+
top: docked ? 2 : null,
|
|
121
|
+
position: "absolute",
|
|
122
|
+
width: "100%",
|
|
123
|
+
zIndex: docked ? 1 : -1,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const backgroundImageStyle = (
|
|
127
|
+
dimensions: Dimensions,
|
|
128
|
+
minimisedHeight: number,
|
|
129
|
+
isActiveGesture: boolean
|
|
130
|
+
): ViewStyle => ({
|
|
131
|
+
height: isActiveGesture ? minimisedHeight : dimensions.height,
|
|
115
132
|
aspectRatio: 1,
|
|
116
133
|
position: "absolute",
|
|
117
134
|
});
|
|
@@ -193,7 +210,6 @@ export default function DockedLayout(props: LayoutProps) {
|
|
|
193
210
|
dimensions,
|
|
194
211
|
entry,
|
|
195
212
|
onCloseVideoModal,
|
|
196
|
-
maximiseVideoModal,
|
|
197
213
|
onPlayerSeek,
|
|
198
214
|
playerState,
|
|
199
215
|
configuration,
|
|
@@ -207,9 +223,29 @@ export default function DockedLayout(props: LayoutProps) {
|
|
|
207
223
|
const visible = true;
|
|
208
224
|
const liveButton = Boolean(value("live_badge_enabled"));
|
|
209
225
|
|
|
226
|
+
const {
|
|
227
|
+
isActiveGesture,
|
|
228
|
+
setPlayerAnimationState,
|
|
229
|
+
startComponentsAnimation,
|
|
230
|
+
minimisedHeight,
|
|
231
|
+
} = useModalAnimationContext();
|
|
232
|
+
|
|
233
|
+
const maximazeVideoModal = React.useCallback(
|
|
234
|
+
() => setPlayerAnimationState(PlayerAnimationStateEnum.maximaze),
|
|
235
|
+
[]
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
if (!layoutState.docked && !startComponentsAnimation) return null;
|
|
239
|
+
|
|
210
240
|
return (
|
|
211
|
-
<
|
|
212
|
-
{
|
|
241
|
+
<AnimationComponent
|
|
242
|
+
animationType={ComponentAnimationType.componentAppears}
|
|
243
|
+
style={[
|
|
244
|
+
styles.container,
|
|
245
|
+
animatedContainerStyle(isActiveGesture || layoutState.docked),
|
|
246
|
+
]}
|
|
247
|
+
>
|
|
248
|
+
{!playerState.isLive && layoutState.docked && (
|
|
213
249
|
<ProgressBar
|
|
214
250
|
content={entry}
|
|
215
251
|
value={value}
|
|
@@ -217,18 +253,27 @@ export default function DockedLayout(props: LayoutProps) {
|
|
|
217
253
|
layoutState={layoutState}
|
|
218
254
|
onPlayerSeek={onPlayerSeek}
|
|
219
255
|
playerState={playerState}
|
|
256
|
+
docked
|
|
220
257
|
/>
|
|
221
258
|
)}
|
|
222
259
|
|
|
223
260
|
<View style={styles.content}>
|
|
224
|
-
<
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
261
|
+
<View
|
|
262
|
+
style={backgroundImageStyle(
|
|
263
|
+
dimensions,
|
|
264
|
+
minimisedHeight,
|
|
265
|
+
isActiveGesture
|
|
266
|
+
)}
|
|
228
267
|
/>
|
|
229
|
-
<TouchableWithoutFeedback onPress={
|
|
268
|
+
<TouchableWithoutFeedback onPress={maximazeVideoModal}>
|
|
230
269
|
<View
|
|
231
|
-
style={[
|
|
270
|
+
style={[
|
|
271
|
+
styles.touchableArea,
|
|
272
|
+
playerDimensionsStyle(
|
|
273
|
+
minimisedHeight,
|
|
274
|
+
isActiveGesture || layoutState.docked
|
|
275
|
+
),
|
|
276
|
+
]}
|
|
232
277
|
>
|
|
233
278
|
<View
|
|
234
279
|
style={[
|
|
@@ -272,6 +317,6 @@ export default function DockedLayout(props: LayoutProps) {
|
|
|
272
317
|
/>
|
|
273
318
|
</View>
|
|
274
319
|
</View>
|
|
275
|
-
</
|
|
320
|
+
</AnimationComponent>
|
|
276
321
|
);
|
|
277
322
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import DefaultLayout from "./DefaultLayout";
|
|
3
|
-
import DockedLayout from "./DockedLayout";
|
|
4
3
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
5
4
|
|
|
6
5
|
type Dimensions = {
|
|
@@ -40,6 +39,7 @@ type LayoutProps = {
|
|
|
40
39
|
onSkipLive: () => void;
|
|
41
40
|
maximiseVideoModal: () => void;
|
|
42
41
|
dimensions: Dimensions;
|
|
42
|
+
defaultDimensions: Dimensions;
|
|
43
43
|
playNextData: PlayNextData;
|
|
44
44
|
title: string | number;
|
|
45
45
|
summary: string | number;
|
|
@@ -48,11 +48,5 @@ type LayoutProps = {
|
|
|
48
48
|
export default function Layout(
|
|
49
49
|
props: LayoutProps
|
|
50
50
|
): React.ReactElement<LayoutProps> {
|
|
51
|
-
const { layoutState } = props;
|
|
52
|
-
|
|
53
|
-
if (layoutState.docked) {
|
|
54
|
-
return <DockedLayout {...props} />;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
51
|
return <DefaultLayout {...props} />;
|
|
58
52
|
}
|
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
import queryString from "query-string";
|
|
2
|
+
import dayjs from "dayjs";
|
|
3
|
+
import utc from "dayjs/plugin/utc";
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
switch (typeof obj) {
|
|
5
|
-
case "object":
|
|
6
|
-
return obj instanceof Date ? obj.toISOString() : JSON.stringify(obj); // object, null
|
|
7
|
-
case "undefined":
|
|
8
|
-
return "";
|
|
9
|
-
default:
|
|
10
|
-
// boolean, number, string
|
|
11
|
-
return obj.toString();
|
|
12
|
-
}
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export const stringsOnlyObject = (obj) => {
|
|
16
|
-
const strObj = {};
|
|
17
|
-
|
|
18
|
-
Object.keys(obj).forEach((x) => {
|
|
19
|
-
strObj[x] = toTypeString(obj[x]);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
return strObj;
|
|
23
|
-
};
|
|
5
|
+
dayjs.extend(utc);
|
|
24
6
|
|
|
25
7
|
export const getLiveUrl = (url: string) => {
|
|
26
8
|
// Use the replace method with a regular expression to replace all instances of subClass with livePage
|
|
@@ -42,3 +24,7 @@ export const addQueryParam = (
|
|
|
42
24
|
|
|
43
25
|
return `${urlWithoutQuery}?${updatedQueryString}`;
|
|
44
26
|
};
|
|
27
|
+
|
|
28
|
+
export const isValidDate = (dateString: string) => {
|
|
29
|
+
return dateString && dayjs.utc(dateString).isValid();
|
|
30
|
+
};
|
package/src/Player/index.tsx
CHANGED
|
@@ -38,6 +38,10 @@ import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/c
|
|
|
38
38
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
39
39
|
import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
|
|
40
40
|
import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
|
|
41
|
+
import {
|
|
42
|
+
AnimationComponent,
|
|
43
|
+
ComponentAnimationType,
|
|
44
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
41
45
|
|
|
42
46
|
const RNPlayerManager = {
|
|
43
47
|
QuickBrickPlayerPlugin: isApplePlatform()
|
|
@@ -57,6 +61,7 @@ const styles = StyleSheet.create({
|
|
|
57
61
|
position: "absolute",
|
|
58
62
|
zIndex: 1,
|
|
59
63
|
},
|
|
64
|
+
playerSize: { width: "100%", height: "100%" },
|
|
60
65
|
});
|
|
61
66
|
|
|
62
67
|
const logger = createLogger({
|
|
@@ -780,7 +785,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
780
785
|
|
|
781
786
|
render() {
|
|
782
787
|
const {
|
|
783
|
-
castAction,
|
|
784
788
|
docked,
|
|
785
789
|
entry,
|
|
786
790
|
fullscreen,
|
|
@@ -790,8 +794,12 @@ export default class VideoPlayer extends React.Component<
|
|
|
790
794
|
isTabletPortrait,
|
|
791
795
|
muted,
|
|
792
796
|
style,
|
|
797
|
+
castAction,
|
|
798
|
+
controller,
|
|
793
799
|
} = this.props;
|
|
794
800
|
|
|
801
|
+
const supportNativeCast = controller.supportNativeCast();
|
|
802
|
+
|
|
795
803
|
const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
|
|
796
804
|
this.state;
|
|
797
805
|
|
|
@@ -856,7 +864,8 @@ export default class VideoPlayer extends React.Component<
|
|
|
856
864
|
? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
|
|
857
865
|
: supportsNativeControls && !this.getPlayNextData();
|
|
858
866
|
|
|
859
|
-
const shouldUseNativeControls =
|
|
867
|
+
const shouldUseNativeControls =
|
|
868
|
+
controls && !docked && !castAction?.state?.connected;
|
|
860
869
|
|
|
861
870
|
platformSpecificProps = {
|
|
862
871
|
...platformSpecificProps,
|
|
@@ -1061,29 +1070,14 @@ export default class VideoPlayer extends React.Component<
|
|
|
1061
1070
|
const renderMobilePlayer = () => {
|
|
1062
1071
|
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
1063
1072
|
<View style={containerStyle}>
|
|
1064
|
-
{!castAction?.state?.connected && (
|
|
1073
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1065
1074
|
<this.props.PlayerComponent
|
|
1066
1075
|
ref={this._assignRoot}
|
|
1067
1076
|
{...nativeEvents}
|
|
1068
1077
|
{...nativeProps}
|
|
1069
1078
|
/>
|
|
1070
1079
|
)}
|
|
1071
|
-
<AudioPlayerWrapper {...sharedWrapperViewProps}
|
|
1072
|
-
<View>
|
|
1073
|
-
{
|
|
1074
|
-
<PlayNextOverlay
|
|
1075
|
-
item={entry}
|
|
1076
|
-
playerIsDocked={docked}
|
|
1077
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1078
|
-
playerId={this.props.playerId}
|
|
1079
|
-
playNextData={this.getPlayNextData()}
|
|
1080
|
-
setNextVideoPreloadThresholdPercentage={
|
|
1081
|
-
this.props.setNextVideoPreloadThresholdPercentage
|
|
1082
|
-
}
|
|
1083
|
-
/>
|
|
1084
|
-
}
|
|
1085
|
-
</View>
|
|
1086
|
-
</AudioPlayerWrapper>
|
|
1080
|
+
<AudioPlayerWrapper {...sharedWrapperViewProps} />
|
|
1087
1081
|
</View>
|
|
1088
1082
|
) : (
|
|
1089
1083
|
<PlayerWrapper {...sharedWrapperViewProps}>
|
|
@@ -1098,11 +1092,24 @@ export default class VideoPlayer extends React.Component<
|
|
|
1098
1092
|
<View style={styles.container}>
|
|
1099
1093
|
<View style={[playerContainerStyles, playerDimensions]}>
|
|
1100
1094
|
{isAudioItem && (
|
|
1101
|
-
<
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1095
|
+
<AnimationComponent
|
|
1096
|
+
animationType={ComponentAnimationType.player}
|
|
1097
|
+
additionalData={{
|
|
1098
|
+
...playerDimensions,
|
|
1099
|
+
inlineAudioPlayer: true,
|
|
1100
|
+
}}
|
|
1101
|
+
style={getStyle(playerDimensions)}
|
|
1102
|
+
>
|
|
1103
|
+
<AudioPlayer
|
|
1104
|
+
style={
|
|
1105
|
+
isTV()
|
|
1106
|
+
? getStyle(playerDimensions)
|
|
1107
|
+
: styles.playerSize
|
|
1108
|
+
}
|
|
1109
|
+
audio_item={entry}
|
|
1110
|
+
plugin_configuration={this.getPluginConfiguration()}
|
|
1111
|
+
/>
|
|
1112
|
+
</AnimationComponent>
|
|
1106
1113
|
)}
|
|
1107
1114
|
|
|
1108
1115
|
{shouldRenderBackground && (
|
|
@@ -1114,18 +1121,28 @@ export default class VideoPlayer extends React.Component<
|
|
|
1114
1121
|
/>
|
|
1115
1122
|
)}
|
|
1116
1123
|
|
|
1117
|
-
{!castAction?.state?.connected && (
|
|
1118
|
-
<
|
|
1119
|
-
|
|
1120
|
-
{
|
|
1121
|
-
{...nativeProps}
|
|
1122
|
-
listener={this.props.listener}
|
|
1124
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1125
|
+
<AnimationComponent
|
|
1126
|
+
animationType={ComponentAnimationType.player}
|
|
1127
|
+
additionalData={playerDimensions}
|
|
1123
1128
|
style={getStyle(playerDimensions)}
|
|
1124
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1125
|
-
controller={this.props.controller}
|
|
1126
1129
|
>
|
|
1127
|
-
|
|
1128
|
-
|
|
1130
|
+
<this.props.PlayerComponent
|
|
1131
|
+
ref={this._assignRoot}
|
|
1132
|
+
{...nativeEvents}
|
|
1133
|
+
{...nativeProps}
|
|
1134
|
+
listener={this.props.listener}
|
|
1135
|
+
style={
|
|
1136
|
+
isTV()
|
|
1137
|
+
? getStyle(playerDimensions)
|
|
1138
|
+
: styles.playerSize
|
|
1139
|
+
}
|
|
1140
|
+
pluginConfiguration={this.getPluginConfiguration()}
|
|
1141
|
+
controller={this.props.controller}
|
|
1142
|
+
>
|
|
1143
|
+
{this.childrenWithPlayNext()}
|
|
1144
|
+
</this.props.PlayerComponent>
|
|
1145
|
+
</AnimationComponent>
|
|
1129
1146
|
)}
|
|
1130
1147
|
</View>
|
|
1131
1148
|
|