@applicaster/quick-brick-player 12.0.0-alpha.3343511343 → 12.0.0-alpha.3425259123
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 +6 -6
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +76 -67
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +177 -79
- 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/AudioLayer/MagicBG/index.tsx +47 -15
- package/src/Player/Utils/Utils.ts +9 -22
- package/src/Player/index.tsx +111 -65
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.3425259123",
|
|
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-rc.
|
|
40
|
-
"@applicaster/quick-brick-tv-transport-controls": "
|
|
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.
|
|
39
|
+
"@applicaster/quick-brick-mobile-transport-controls": "12.0.0-rc.68",
|
|
40
|
+
"@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.70",
|
|
41
|
+
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3425259123",
|
|
42
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3425259123",
|
|
43
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.3425259123",
|
|
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,13 @@ 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";
|
|
35
|
+
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
29
36
|
|
|
30
37
|
const { log_debug } = createLogger({
|
|
31
38
|
subsystem: "UIComponent",
|
|
@@ -68,29 +75,20 @@ export const defaultAspectRatioWidth = (height: number): number =>
|
|
|
68
75
|
(height / 9) * 16;
|
|
69
76
|
|
|
70
77
|
const Styles = {
|
|
71
|
-
mainContainer: (
|
|
78
|
+
mainContainer: (style: ViewStyle) => {
|
|
72
79
|
const combinedStyle: ViewStyle = {
|
|
73
80
|
flex: 1,
|
|
74
81
|
};
|
|
75
82
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
style
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return { ...combinedStyle, ...style };
|
|
82
|
-
},
|
|
83
|
-
playerContainer: (docked: boolean, style: ViewStyle) => {
|
|
84
|
-
const combinedStyle: ViewStyle = {
|
|
85
|
-
flex: 1,
|
|
83
|
+
return {
|
|
84
|
+
...combinedStyle,
|
|
85
|
+
...style,
|
|
86
86
|
};
|
|
87
|
-
|
|
88
|
-
if (docked) {
|
|
89
|
-
combinedStyle.height = style.height;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return combinedStyle;
|
|
93
87
|
},
|
|
88
|
+
playerContainer: {
|
|
89
|
+
flex: 1,
|
|
90
|
+
},
|
|
91
|
+
paddingHorizontal: { paddingTop: 0, paddingHorizontal: PADDING_HORIZONTAL },
|
|
94
92
|
|
|
95
93
|
controlsMobile: {
|
|
96
94
|
height: 50,
|
|
@@ -168,6 +166,9 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
168
166
|
|
|
169
167
|
const [sleepTimerDate, setSleepTimerDate] = useState(0);
|
|
170
168
|
|
|
169
|
+
const [defaultDimensions, setDefaultDimensions] =
|
|
170
|
+
React.useState<Dimensions>(undefined);
|
|
171
|
+
|
|
171
172
|
const [dimensions, setDimensions] = React.useState<Dimensions>({
|
|
172
173
|
width: 0,
|
|
173
174
|
height: 0,
|
|
@@ -181,9 +182,11 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
181
182
|
const { width, height } = event.nativeEvent.layout;
|
|
182
183
|
|
|
183
184
|
setDimensions({
|
|
184
|
-
width
|
|
185
|
+
width,
|
|
185
186
|
height,
|
|
186
187
|
});
|
|
188
|
+
|
|
189
|
+
if (!defaultDimensions) setDefaultDimensions({ width, height });
|
|
187
190
|
};
|
|
188
191
|
|
|
189
192
|
const cancelSleepTimer = async () => {
|
|
@@ -292,7 +295,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
292
295
|
playerState.isPaused ? player?.play() : player.pause();
|
|
293
296
|
}, [playerState, player]);
|
|
294
297
|
|
|
295
|
-
const seekDuration =
|
|
298
|
+
const seekDuration = toNumberWithDefault(10, value("seek_duration"));
|
|
296
299
|
|
|
297
300
|
const onRewindButtonPress = React.useCallback(() => {
|
|
298
301
|
player?.rewind(seekDuration);
|
|
@@ -375,58 +378,64 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
375
378
|
player?.seekTo(0);
|
|
376
379
|
}, [player]);
|
|
377
380
|
|
|
378
|
-
const edges = React.useMemo<Edge[]>(
|
|
379
|
-
() => (docked ? [] : ["right", "left", "top"]),
|
|
380
|
-
[docked]
|
|
381
|
-
);
|
|
381
|
+
const edges = React.useMemo<Edge[]>(() => ["right", "left", "top"], [docked]);
|
|
382
382
|
|
|
383
|
-
const ContainerView =
|
|
383
|
+
const ContainerView = SafeAreaView;
|
|
384
384
|
|
|
385
385
|
const MainContent = React.useMemo(() => {
|
|
386
386
|
return (
|
|
387
|
-
<ContainerView style={Styles.mainContainer(
|
|
388
|
-
<
|
|
389
|
-
|
|
390
|
-
|
|
387
|
+
<ContainerView style={Styles.mainContainer(style)} edges={edges}>
|
|
388
|
+
<AnimationComponent
|
|
389
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
390
|
+
additionalData={{ saveArea: true }}
|
|
391
391
|
>
|
|
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
|
-
|
|
392
|
+
<AnimatedScrollModal>
|
|
393
|
+
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
394
|
+
<Layout
|
|
395
|
+
entry={entry}
|
|
396
|
+
playerState={playerState}
|
|
397
|
+
layoutState={layoutState}
|
|
398
|
+
value={value}
|
|
399
|
+
onPlaybackButtonPress={onPlaybackButtonPress}
|
|
400
|
+
onRewindButtonPress={onRewindButtonPress}
|
|
401
|
+
onForwardButtonPress={onForwardButtonPress}
|
|
402
|
+
onPlayerSeek={onPlayerSeek}
|
|
403
|
+
onSkipStart={onSkipStart}
|
|
404
|
+
onSpeedButtonPress={onSpeedButtonPress}
|
|
405
|
+
onSleepButtonPress={onSleepButtonPress}
|
|
406
|
+
playbackSpeedName={formatSpeed(playbackSpeed.value)}
|
|
407
|
+
playbackSleepName={
|
|
408
|
+
sleepTimer.value === 0 ? "sleep_timer" : "sleep_timer_active"
|
|
409
|
+
}
|
|
410
|
+
sleepTimerDate={sleepTimerDate}
|
|
411
|
+
cancelSleepTimer={cancelSleepTimer}
|
|
412
|
+
onSkipLive={onSkipLive}
|
|
413
|
+
onCloseVideoModal={onCloseVideoModal}
|
|
414
|
+
maximiseVideoModal={maximiseVideoModal}
|
|
415
|
+
configuration={configuration}
|
|
416
|
+
dimensions={dimensions}
|
|
417
|
+
playNextData={playNextData}
|
|
418
|
+
title={title}
|
|
419
|
+
summary={summary}
|
|
420
|
+
defaultDimensions={defaultDimensions}
|
|
421
|
+
/>
|
|
422
|
+
<View style={Styles.paddingHorizontal}>
|
|
423
|
+
{children}
|
|
424
|
+
<AnimationComponent
|
|
425
|
+
animationType={ComponentAnimationType.componentFade}
|
|
426
|
+
>
|
|
427
|
+
<PlayerDetails
|
|
428
|
+
configuration={configuration}
|
|
429
|
+
style={Styles.playerDetails}
|
|
430
|
+
entry={entry}
|
|
431
|
+
isTabletLandscape={isTabletLandscape}
|
|
432
|
+
isAudioPlayer={true}
|
|
433
|
+
/>
|
|
434
|
+
</AnimationComponent>
|
|
435
|
+
</View>
|
|
436
|
+
</View>
|
|
437
|
+
</AnimatedScrollModal>
|
|
438
|
+
</AnimationComponent>
|
|
430
439
|
</ContainerView>
|
|
431
440
|
);
|
|
432
441
|
}, [
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import * as R from "ramda";
|
|
3
3
|
import { View } from "react-native";
|
|
4
|
+
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
ProgressBar,
|
|
@@ -18,13 +19,22 @@ import {
|
|
|
18
19
|
rewindButton,
|
|
19
20
|
skipToStartButton,
|
|
20
21
|
skipToLiveButton,
|
|
22
|
+
PADDING_HORIZONTAL,
|
|
21
23
|
speedButton,
|
|
22
24
|
sleepButton,
|
|
23
25
|
} from "./defaultLayoutsConts";
|
|
24
26
|
import { AudioDescription } from "../AudioDescription";
|
|
25
27
|
import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
|
|
26
28
|
import { useLanguageData } from "@applicaster/zapp-react-native-utils/reactHooks/player";
|
|
29
|
+
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
27
30
|
import { useEffect, useMemo, useState } from "react";
|
|
31
|
+
import {
|
|
32
|
+
useModalAnimationContext,
|
|
33
|
+
AnimationComponent,
|
|
34
|
+
ComponentAnimationType,
|
|
35
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
36
|
+
import DockedLayout from "./DockedLayout";
|
|
37
|
+
import { isValidDate } from "../../Utils";
|
|
28
38
|
|
|
29
39
|
type Dimensions = {
|
|
30
40
|
width: number;
|
|
@@ -60,22 +70,29 @@ type LayoutProps = {
|
|
|
60
70
|
onPlayerSeek: (targetTime: number) => void;
|
|
61
71
|
onSkipLive: () => void;
|
|
62
72
|
onSkipStart: () => void;
|
|
73
|
+
onCloseVideoModal: () => void;
|
|
74
|
+
maximiseVideoModal: () => void;
|
|
63
75
|
dimensions: Dimensions;
|
|
76
|
+
playNextData: PlayNextData;
|
|
64
77
|
title: string | number;
|
|
65
78
|
summary: string | number;
|
|
79
|
+
defaultDimensions: Dimensions;
|
|
66
80
|
};
|
|
67
81
|
|
|
68
82
|
const Styles = {
|
|
69
83
|
container: { flex: 1 },
|
|
70
|
-
tabletContainer: (isPortraitMode) => ({
|
|
84
|
+
tabletContainer: (isPortraitMode: boolean) => ({
|
|
71
85
|
flex: 1,
|
|
72
86
|
alignItems: "center",
|
|
73
87
|
justifyContent: isPortraitMode ? "center" : "flex-start",
|
|
74
88
|
}),
|
|
75
|
-
|
|
76
|
-
width:
|
|
89
|
+
playerImageWrapper: {
|
|
90
|
+
width: "100%",
|
|
77
91
|
maxHeight: 750,
|
|
78
92
|
marginTop: 80,
|
|
93
|
+
},
|
|
94
|
+
tabletLayout: {
|
|
95
|
+
width: 463,
|
|
79
96
|
marginBottom: 80,
|
|
80
97
|
},
|
|
81
98
|
controls: (isTablet: boolean, isLiveShowFullControls: boolean) => ({
|
|
@@ -84,24 +101,31 @@ const Styles = {
|
|
|
84
101
|
justifyContent: isLiveShowFullControls ? "space-between" : "space-evenly",
|
|
85
102
|
}),
|
|
86
103
|
backgroundImageContainer: (dimensions: Dimensions, isTablet: boolean) => {
|
|
104
|
+
const mobileValue = dimensions.width
|
|
105
|
+
? dimensions.width - PADDING_HORIZONTAL * 2
|
|
106
|
+
: 330;
|
|
107
|
+
|
|
87
108
|
return {
|
|
88
|
-
width: isTablet ? 463 :
|
|
89
|
-
height: isTablet ? 463 :
|
|
109
|
+
width: isTablet ? 463 : mobileValue,
|
|
110
|
+
height: isTablet ? 463 : mobileValue,
|
|
90
111
|
};
|
|
91
112
|
},
|
|
92
|
-
backgroundImageContainerImageStyle: (
|
|
93
|
-
|
|
113
|
+
backgroundImageContainerImageStyle: (
|
|
114
|
+
isTablet: boolean,
|
|
115
|
+
docked: boolean,
|
|
116
|
+
startComponentsAnimation: boolean,
|
|
117
|
+
isActiveGesture: boolean
|
|
118
|
+
) => ({
|
|
119
|
+
borderRadius:
|
|
120
|
+
(startComponentsAnimation && isActiveGesture) || docked
|
|
121
|
+
? 0
|
|
122
|
+
: isTablet
|
|
123
|
+
? 24
|
|
124
|
+
: 10,
|
|
94
125
|
}),
|
|
95
|
-
playerContainer: (docked: boolean, style) => {
|
|
96
|
-
const combinedStyle = {
|
|
97
|
-
flex: 1,
|
|
98
|
-
};
|
|
99
126
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return combinedStyle;
|
|
127
|
+
paddingHorizontal: {
|
|
128
|
+
paddingHorizontal: PADDING_HORIZONTAL,
|
|
105
129
|
},
|
|
106
130
|
|
|
107
131
|
controlsMobile: {
|
|
@@ -115,6 +139,12 @@ const Styles = {
|
|
|
115
139
|
separator: {
|
|
116
140
|
height: 20,
|
|
117
141
|
},
|
|
142
|
+
flexDirectionRow: {
|
|
143
|
+
flexDirection: "row",
|
|
144
|
+
},
|
|
145
|
+
alignItemsCenter: {
|
|
146
|
+
alignItems: "center",
|
|
147
|
+
},
|
|
118
148
|
};
|
|
119
149
|
|
|
120
150
|
export default function DefaultLayout(props: LayoutProps) {
|
|
@@ -139,12 +169,14 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
139
169
|
sleepTimerDate,
|
|
140
170
|
title,
|
|
141
171
|
summary,
|
|
172
|
+
defaultDimensions,
|
|
142
173
|
} = props;
|
|
143
174
|
|
|
144
175
|
const isTablet = useIsTablet();
|
|
145
176
|
const { width, height } = dimensions;
|
|
146
177
|
const isPortraitMode = width < height;
|
|
147
178
|
const isLiveContent = playerState.isLive;
|
|
179
|
+
const docked = layoutState.docked;
|
|
148
180
|
|
|
149
181
|
const languageData = useLanguageData("audio-player");
|
|
150
182
|
|
|
@@ -160,8 +192,31 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
160
192
|
|
|
161
193
|
let showFullControls = !controller?.isAd();
|
|
162
194
|
|
|
195
|
+
const startTime = entry.extensions?.live?.start_time;
|
|
196
|
+
const endTime = entry.extensions?.live?.end_time;
|
|
197
|
+
|
|
198
|
+
const hasValidStartTime = isValidDate(startTime);
|
|
199
|
+
const hasValidEndTime = isValidDate(endTime);
|
|
200
|
+
|
|
201
|
+
const isDateBasedLiveContent =
|
|
202
|
+
isLiveContent && hasValidStartTime && hasValidEndTime;
|
|
203
|
+
|
|
204
|
+
const needsToShowProgressBar =
|
|
205
|
+
(isLiveContent &&
|
|
206
|
+
(Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
|
|
207
|
+
!isLiveContent;
|
|
208
|
+
|
|
209
|
+
const startTimestamp = hasValidStartTime
|
|
210
|
+
? dayjs.utc(startTime!).valueOf()
|
|
211
|
+
: undefined;
|
|
212
|
+
|
|
213
|
+
const endTimestamp = hasValidEndTime
|
|
214
|
+
? dayjs.utc(endTime!).valueOf()
|
|
215
|
+
: undefined;
|
|
216
|
+
|
|
163
217
|
if (isLiveContent) {
|
|
164
218
|
const seekEnabled = Boolean(value("liveSeekingEnabled"));
|
|
219
|
+
|
|
165
220
|
showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
|
|
166
221
|
}
|
|
167
222
|
|
|
@@ -191,12 +246,14 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
191
246
|
|
|
192
247
|
const rewind = rewindButton({
|
|
193
248
|
isTablet,
|
|
194
|
-
onPress: controller?.
|
|
249
|
+
onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
|
|
195
250
|
});
|
|
196
251
|
|
|
197
252
|
const forward = forwardButton({
|
|
198
253
|
isTablet,
|
|
199
|
-
onPress: controller?.
|
|
254
|
+
onPress: controller?.hasSeekableDuration?.()
|
|
255
|
+
? onForwardButtonPress
|
|
256
|
+
: null,
|
|
200
257
|
});
|
|
201
258
|
|
|
202
259
|
const speed = speedButton({
|
|
@@ -225,7 +282,6 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
225
282
|
return [skipToStart, rewind, play, forward, skipToLive];
|
|
226
283
|
}
|
|
227
284
|
|
|
228
|
-
// Temporary empty button until we add sleep button. It will ensure the buttons will not break in their position
|
|
229
285
|
return [speed, rewind, play, forward, sleep];
|
|
230
286
|
}, [
|
|
231
287
|
playerState,
|
|
@@ -246,15 +302,12 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
246
302
|
|
|
247
303
|
useEffect(() => {
|
|
248
304
|
if (showCounter && sleepTimerDate !== 0) {
|
|
249
|
-
// Setting the initial timeLeft based on sleepTimerDate
|
|
250
305
|
setTimeLeft(sleepTimerDate - Date.now());
|
|
251
306
|
|
|
252
|
-
// Setting up an interval to update the remaining time every second
|
|
253
307
|
const intervalId = setInterval(() => {
|
|
254
308
|
setTimeLeft(() => {
|
|
255
309
|
const newTimeLeft = sleepTimerDate - Date.now();
|
|
256
310
|
|
|
257
|
-
// If the new remaining time is less than or equal to 0, clear the interval and trigger the cancelSleepTimer function
|
|
258
311
|
if (newTimeLeft <= 0) {
|
|
259
312
|
clearInterval(intervalId);
|
|
260
313
|
|
|
@@ -262,26 +315,28 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
262
315
|
|
|
263
316
|
return 0;
|
|
264
317
|
} else {
|
|
265
|
-
// Otherwise, update the state with the new remaining time
|
|
266
318
|
return newTimeLeft;
|
|
267
319
|
}
|
|
268
320
|
});
|
|
269
321
|
}, 1000);
|
|
270
322
|
|
|
271
|
-
// Clearing the interval when the component unmounts or dependencies change
|
|
272
323
|
return () => clearInterval(intervalId);
|
|
273
324
|
} else {
|
|
274
|
-
// Ensure the timeLeft state is set correctly if showCounter is false
|
|
275
325
|
setTimeLeft(0);
|
|
276
326
|
}
|
|
277
327
|
}, [sleepTimerDate, showCounter, cancelSleepTimer]);
|
|
278
328
|
|
|
279
329
|
const Separator = () => <View style={Styles.separator} />;
|
|
280
330
|
|
|
281
|
-
const
|
|
331
|
+
const defaultImageDimensions = React.useMemo(
|
|
332
|
+
() =>
|
|
333
|
+
defaultDimensions &&
|
|
334
|
+
Styles.backgroundImageContainer(defaultDimensions, isTablet),
|
|
335
|
+
[defaultDimensions, isTablet]
|
|
336
|
+
);
|
|
282
337
|
|
|
283
|
-
const
|
|
284
|
-
(
|
|
338
|
+
const { isActiveGesture, startComponentsAnimation } =
|
|
339
|
+
useModalAnimationContext();
|
|
285
340
|
|
|
286
341
|
return (
|
|
287
342
|
<View
|
|
@@ -289,65 +344,108 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
289
344
|
isTablet ? Styles.tabletContainer(isPortraitMode) : Styles.container
|
|
290
345
|
}
|
|
291
346
|
>
|
|
292
|
-
<
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
347
|
+
<AnimationComponent animationType={ComponentAnimationType.componentFade}>
|
|
348
|
+
<TransportInfo
|
|
349
|
+
content={entry}
|
|
350
|
+
value={value}
|
|
351
|
+
visible={true}
|
|
352
|
+
languageData={languageData}
|
|
353
|
+
layoutState={layoutState}
|
|
354
|
+
actionButtons={actionButtons}
|
|
355
|
+
/>
|
|
356
|
+
</AnimationComponent>
|
|
357
|
+
<AnimationComponent
|
|
358
|
+
animationType={ComponentAnimationType.moveUpComponent}
|
|
359
|
+
style={isTablet ? Styles.playerImageWrapper : undefined}
|
|
304
360
|
>
|
|
305
|
-
<
|
|
361
|
+
<AnimationComponent
|
|
362
|
+
animationType={ComponentAnimationType.moveComponentHorizontal}
|
|
363
|
+
additionalData={{
|
|
364
|
+
disableAnimatedComponent: !isTablet,
|
|
365
|
+
moveValue: (dimensions.width - 463) / 2,
|
|
366
|
+
extraAnimation: !isTablet
|
|
367
|
+
? {
|
|
368
|
+
[ComponentAnimationType.audioPlayerPaddingHorizontal]: {
|
|
369
|
+
style: Styles.paddingHorizontal,
|
|
370
|
+
},
|
|
371
|
+
}
|
|
372
|
+
: null,
|
|
373
|
+
}}
|
|
374
|
+
style={isTablet ? Styles.alignItemsCenter : undefined}
|
|
375
|
+
>
|
|
306
376
|
<PlayerImageBackground
|
|
307
377
|
entry={entry}
|
|
308
378
|
style={Styles.backgroundImageContainer(dimensions, isTablet)}
|
|
309
|
-
imageStyle={Styles.backgroundImageContainerImageStyle(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
379
|
+
imageStyle={Styles.backgroundImageContainerImageStyle(
|
|
380
|
+
isTablet,
|
|
381
|
+
docked,
|
|
382
|
+
startComponentsAnimation,
|
|
383
|
+
isActiveGesture
|
|
384
|
+
)}
|
|
385
|
+
defaultImageDimensions={defaultImageDimensions}
|
|
316
386
|
/>
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
387
|
+
</AnimationComponent>
|
|
388
|
+
|
|
389
|
+
<DockedLayout {...props} />
|
|
390
|
+
</AnimationComponent>
|
|
391
|
+
<View
|
|
392
|
+
style={[
|
|
393
|
+
Styles.paddingHorizontal,
|
|
394
|
+
isTablet ? Styles.tabletLayout : undefined,
|
|
395
|
+
]}
|
|
396
|
+
>
|
|
397
|
+
{!docked && (
|
|
398
|
+
<AnimationComponent
|
|
399
|
+
animationType={ComponentAnimationType.componentFade}
|
|
400
|
+
>
|
|
401
|
+
<AudioDescription
|
|
402
|
+
title={title}
|
|
403
|
+
summary={summary}
|
|
404
|
+
value={value}
|
|
405
|
+
layoutState={layoutState}
|
|
406
|
+
/>
|
|
407
|
+
<Separator />
|
|
408
|
+
{needsToShowProgressBar && (
|
|
409
|
+
<View>
|
|
410
|
+
<ProgressBar
|
|
411
|
+
content={entry}
|
|
334
412
|
value={value}
|
|
335
|
-
|
|
413
|
+
visible={true}
|
|
414
|
+
layoutState={layoutState}
|
|
415
|
+
onPlayerSeek={onPlayerSeek}
|
|
416
|
+
playerState={playerState}
|
|
417
|
+
disableFullscreen={true}
|
|
418
|
+
sliderStyle={2}
|
|
419
|
+
startTimestamp={startTimestamp}
|
|
420
|
+
endTimestamp={endTimestamp}
|
|
421
|
+
isDateBasedLiveContent={isDateBasedLiveContent}
|
|
422
|
+
onSkipLive={onSkipLive}
|
|
336
423
|
/>
|
|
337
|
-
)}
|
|
338
424
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
425
|
+
{showCounter && timeLeft >= 0 && (
|
|
426
|
+
<CountDown
|
|
427
|
+
timeLeft={timeLeft}
|
|
428
|
+
value={value}
|
|
429
|
+
title={sleepTitle}
|
|
430
|
+
/>
|
|
431
|
+
)}
|
|
432
|
+
|
|
433
|
+
<Separator />
|
|
434
|
+
</View>
|
|
435
|
+
)}
|
|
436
|
+
<Controls
|
|
437
|
+
value={value}
|
|
438
|
+
visible={true}
|
|
439
|
+
keepAlive={null}
|
|
440
|
+
buttons={controlButtons}
|
|
441
|
+
style={Styles.controls(
|
|
442
|
+
isTablet,
|
|
443
|
+
isLiveContent && showFullControls
|
|
444
|
+
)}
|
|
445
|
+
playerState={playerState}
|
|
446
|
+
/>
|
|
447
|
+
</AnimationComponent>
|
|
448
|
+
)}
|
|
351
449
|
</View>
|
|
352
450
|
</View>
|
|
353
451
|
);
|
|
@@ -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,7 +1,6 @@
|
|
|
1
|
-
// Disabling for now as lint can't recognise typescript definition here
|
|
2
1
|
/* eslint-disable react/prop-types */
|
|
3
2
|
import * as React from "react";
|
|
4
|
-
import { StyleSheet, View } from "react-native";
|
|
3
|
+
import { Animated, StyleSheet, View } from "react-native";
|
|
5
4
|
import LinearGradient from "../LinearGradient";
|
|
6
5
|
import { getDominantColor, getPalettes } from "../../../utils/utils";
|
|
7
6
|
import { useEffect } from "react";
|
|
@@ -11,7 +10,7 @@ type MagicBGProps = {
|
|
|
11
10
|
image: string;
|
|
12
11
|
fallbackUrl?: string;
|
|
13
12
|
defaultColor: string;
|
|
14
|
-
colors: string[];
|
|
13
|
+
colors: string[];
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
const defaultColors = {
|
|
@@ -66,31 +65,46 @@ export const MagicBG: React.FC<MagicBGProps> = ({
|
|
|
66
65
|
defaultColors.defaultGradientEnd,
|
|
67
66
|
]);
|
|
68
67
|
|
|
68
|
+
const [backgroundColorAnim] = React.useState(new Animated.Value(0)); // from 0 to 1
|
|
69
|
+
const [gradientOpacityAnim] = React.useState(new Animated.Value(0)); // from 0 to 1
|
|
70
|
+
|
|
69
71
|
useEffect(() => {
|
|
72
|
+
const animateColors = () => {
|
|
73
|
+
Animated.timing(backgroundColorAnim, {
|
|
74
|
+
toValue: 1,
|
|
75
|
+
duration: 500,
|
|
76
|
+
useNativeDriver: false,
|
|
77
|
+
}).start();
|
|
78
|
+
|
|
79
|
+
Animated.timing(gradientOpacityAnim, {
|
|
80
|
+
toValue: 1,
|
|
81
|
+
duration: 500,
|
|
82
|
+
useNativeDriver: false,
|
|
83
|
+
}).start();
|
|
84
|
+
};
|
|
85
|
+
|
|
70
86
|
const fetchColors = async () => {
|
|
71
|
-
// Check if colors are provided and not empty
|
|
72
87
|
if (colors && colors.length > 0) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
88
|
+
setGradientColors(colors.slice(0, 2));
|
|
89
|
+
setDominantColor(colors[0]);
|
|
90
|
+
animateColors();
|
|
76
91
|
} else if (image) {
|
|
77
|
-
// If no colors, try fetching from image
|
|
78
92
|
try {
|
|
79
93
|
const { gradientColors, dominantColor } =
|
|
80
94
|
await fetchPaletteAndDominantColor(image);
|
|
81
95
|
|
|
82
96
|
setGradientColors(gradientColors);
|
|
83
97
|
setDominantColor(dominantColor);
|
|
98
|
+
animateColors();
|
|
84
99
|
} catch (error) {
|
|
85
|
-
// If image fetch fails, try fallback URL
|
|
86
100
|
try {
|
|
87
101
|
const { gradientColors, dominantColor } =
|
|
88
102
|
await fetchPaletteAndDominantColor(fallbackUrl);
|
|
89
103
|
|
|
90
104
|
setGradientColors(gradientColors);
|
|
91
105
|
setDominantColor(dominantColor);
|
|
106
|
+
animateColors();
|
|
92
107
|
} catch {
|
|
93
|
-
// If everything fails, use default color
|
|
94
108
|
setGradientColors([
|
|
95
109
|
defaultColors.defaultGradientStart,
|
|
96
110
|
defaultColors.defaultGradientEnd,
|
|
@@ -100,7 +114,6 @@ export const MagicBG: React.FC<MagicBGProps> = ({
|
|
|
100
114
|
}
|
|
101
115
|
}
|
|
102
116
|
} else {
|
|
103
|
-
// If no image or colors, use default color
|
|
104
117
|
setGradientColors([
|
|
105
118
|
defaultColors.defaultGradientStart,
|
|
106
119
|
defaultColors.defaultGradientEnd,
|
|
@@ -111,13 +124,32 @@ export const MagicBG: React.FC<MagicBGProps> = ({
|
|
|
111
124
|
};
|
|
112
125
|
|
|
113
126
|
fetchColors();
|
|
114
|
-
}, [
|
|
127
|
+
}, []);
|
|
128
|
+
|
|
129
|
+
const interpolatedBackgroundColor = backgroundColorAnim.interpolate({
|
|
130
|
+
inputRange: [0, 1],
|
|
131
|
+
outputRange: ["black", dominantColor],
|
|
132
|
+
});
|
|
115
133
|
|
|
116
134
|
return (
|
|
117
|
-
<View
|
|
135
|
+
<Animated.View
|
|
136
|
+
style={[
|
|
137
|
+
styles.container,
|
|
138
|
+
{ backgroundColor: interpolatedBackgroundColor },
|
|
139
|
+
]}
|
|
140
|
+
>
|
|
118
141
|
<View style={styles.fullScreenOverlay} />
|
|
119
|
-
|
|
142
|
+
|
|
143
|
+
<Animated.View
|
|
144
|
+
style={[styles.gradientOverlay, { opacity: gradientOpacityAnim }]}
|
|
145
|
+
>
|
|
146
|
+
<LinearGradient
|
|
147
|
+
colors={gradientColors}
|
|
148
|
+
style={StyleSheet.absoluteFill}
|
|
149
|
+
/>
|
|
150
|
+
</Animated.View>
|
|
151
|
+
|
|
120
152
|
{children}
|
|
121
|
-
</View>
|
|
153
|
+
</Animated.View>
|
|
122
154
|
);
|
|
123
155
|
};
|
|
@@ -1,26 +1,5 @@
|
|
|
1
1
|
import queryString from "query-string";
|
|
2
|
-
|
|
3
|
-
export const toTypeString = (obj) => {
|
|
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
|
-
};
|
|
2
|
+
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
24
3
|
|
|
25
4
|
export const getLiveUrl = (url: string) => {
|
|
26
5
|
// Use the replace method with a regular expression to replace all instances of subClass with livePage
|
|
@@ -42,3 +21,11 @@ export const addQueryParam = (
|
|
|
42
21
|
|
|
43
22
|
return `${urlWithoutQuery}?${updatedQueryString}`;
|
|
44
23
|
};
|
|
24
|
+
|
|
25
|
+
export const isValidDate = (dateString: string | undefined): boolean => {
|
|
26
|
+
return (
|
|
27
|
+
typeof dateString === "string" &&
|
|
28
|
+
dateString.trim() !== "" &&
|
|
29
|
+
dayjs.utc(dateString).isValid()
|
|
30
|
+
);
|
|
31
|
+
};
|
package/src/Player/index.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import React from "react";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
|
|
7
|
-
import { findNodeHandle,
|
|
7
|
+
import { findNodeHandle, StyleSheet, View } from "react-native";
|
|
8
8
|
import TransportControlsMobile from "@applicaster/quick-brick-mobile-transport-controls";
|
|
9
9
|
import TransportControlsTV from "@applicaster/quick-brick-tv-transport-controls";
|
|
10
10
|
|
|
@@ -36,15 +36,13 @@ import { AudioPlayerWrapper } from "./AudioLayer/AudioPlayerWrapper";
|
|
|
36
36
|
import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
|
|
37
37
|
import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/configurationUtils";
|
|
38
38
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
: NativeModules.QBKalturaPlayerModule,
|
|
47
|
-
};
|
|
39
|
+
import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
|
|
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";
|
|
45
|
+
import { RNPlayerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/nativePlayerManager";
|
|
48
46
|
|
|
49
47
|
const styles = StyleSheet.create({
|
|
50
48
|
container: { flex: 1 },
|
|
@@ -55,6 +53,7 @@ const styles = StyleSheet.create({
|
|
|
55
53
|
position: "absolute",
|
|
56
54
|
zIndex: 1,
|
|
57
55
|
},
|
|
56
|
+
playerSize: { width: "100%", height: "100%" },
|
|
58
57
|
});
|
|
59
58
|
|
|
60
59
|
const logger = createLogger({
|
|
@@ -113,8 +112,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
componentWillUnmount() {
|
|
116
|
-
this.stopBackgroundPlayback();
|
|
117
|
-
|
|
118
115
|
this.playbackStarted = false;
|
|
119
116
|
this.handleAnalyticEvent(GENERAL_EVENT.session_end);
|
|
120
117
|
this.onPlayerClosed();
|
|
@@ -159,6 +156,11 @@ export default class VideoPlayer extends React.Component<
|
|
|
159
156
|
}
|
|
160
157
|
}
|
|
161
158
|
|
|
159
|
+
// For close button
|
|
160
|
+
public closeNativePlayer = () => {
|
|
161
|
+
this.stopBackgroundPlayback();
|
|
162
|
+
};
|
|
163
|
+
|
|
162
164
|
getPlayNextData = () => this.props.playNextData as PlayNextData;
|
|
163
165
|
|
|
164
166
|
/**
|
|
@@ -555,6 +557,26 @@ export default class VideoPlayer extends React.Component<
|
|
|
555
557
|
this.props.listener?.onPlayerDetached?.(nativeEvent);
|
|
556
558
|
};
|
|
557
559
|
|
|
560
|
+
onVideoFullscreenPlayerDidDismiss = () => {
|
|
561
|
+
this.props.listener?.onVideoFullscreenPlayerDidDismiss?.();
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
onVideoFullscreenPlayerDidPresent = () => {
|
|
565
|
+
this.props.listener?.onVideoFullscreenPlayerDidPresent?.();
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
onVideoFullscreenPlayerWillDismiss = () => {
|
|
569
|
+
this.props.listener?.onVideoFullscreenPlayerWillDismiss?.();
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
onVideoFullscreenPlayerWillPresent = () => {
|
|
573
|
+
this.props.listener?.onVideoFullscreenPlayerWillPresent?.();
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
onPlayerClose = () => {
|
|
577
|
+
this.props.listener?.onPlayerClose?.();
|
|
578
|
+
};
|
|
579
|
+
|
|
558
580
|
onPiPEnter = () => {
|
|
559
581
|
this.setState({ piped: true });
|
|
560
582
|
this.props.openPiP();
|
|
@@ -758,8 +780,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
758
780
|
|
|
759
781
|
render() {
|
|
760
782
|
const {
|
|
761
|
-
castAction,
|
|
762
|
-
controls,
|
|
763
783
|
docked,
|
|
764
784
|
entry,
|
|
765
785
|
fullscreen,
|
|
@@ -769,8 +789,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
769
789
|
isTabletPortrait,
|
|
770
790
|
muted,
|
|
771
791
|
style,
|
|
792
|
+
castAction,
|
|
793
|
+
controller,
|
|
794
|
+
startComponentsAnimation,
|
|
772
795
|
} = this.props;
|
|
773
796
|
|
|
797
|
+
const supportNativeCast = controller.supportNativeCast();
|
|
798
|
+
|
|
774
799
|
const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
|
|
775
800
|
this.state;
|
|
776
801
|
|
|
@@ -817,17 +842,35 @@ export default class VideoPlayer extends React.Component<
|
|
|
817
842
|
const liveCatchUpEnabled =
|
|
818
843
|
this.props.pluginConfiguration?.liveCatchUpEnabled;
|
|
819
844
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
: {};
|
|
845
|
+
// TODO: Get screen data more reliable way useCurrentScreenData
|
|
846
|
+
const screenData = getTargetScreenDataFromEntry(this.props.playableItem);
|
|
823
847
|
|
|
824
|
-
const
|
|
848
|
+
const isInlineTV = screenData?.ui_components?.length > 0 && isTV();
|
|
849
|
+
|
|
850
|
+
let platformSpecificProps: any = isApplePlatform()
|
|
825
851
|
? {
|
|
826
|
-
...hideNativeControls,
|
|
827
852
|
resizeMode: nativeResizeMode,
|
|
828
853
|
}
|
|
829
854
|
: {};
|
|
830
855
|
|
|
856
|
+
const supportsNativeControls =
|
|
857
|
+
!!this.props.controller?.supportsNativeControls?.();
|
|
858
|
+
|
|
859
|
+
const controls = isAppleTV()
|
|
860
|
+
? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
|
|
861
|
+
: supportsNativeControls && !this.getPlayNextData();
|
|
862
|
+
|
|
863
|
+
const shouldUseNativeControls =
|
|
864
|
+
controls &&
|
|
865
|
+
!startComponentsAnimation &&
|
|
866
|
+
!docked &&
|
|
867
|
+
!castAction?.state?.connected;
|
|
868
|
+
|
|
869
|
+
platformSpecificProps = {
|
|
870
|
+
...platformSpecificProps,
|
|
871
|
+
controls: shouldUseNativeControls,
|
|
872
|
+
};
|
|
873
|
+
|
|
831
874
|
const pictureInPictureEnabled =
|
|
832
875
|
this.props.pluginConfiguration?.pictureInPictureEnabled;
|
|
833
876
|
|
|
@@ -835,7 +878,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
835
878
|
entry, // Must be passed first in list
|
|
836
879
|
...platformSpecificProps,
|
|
837
880
|
audioTrackId,
|
|
838
|
-
controls,
|
|
839
881
|
docked,
|
|
840
882
|
enableAutoAudioTrackSelection,
|
|
841
883
|
fullscreen, // TODO: Check fullscreen params not crash
|
|
@@ -890,22 +932,17 @@ export default class VideoPlayer extends React.Component<
|
|
|
890
932
|
onVideoEnd: this.onVideoEnd, // complete
|
|
891
933
|
onVideoError: this.onVideoError, // error
|
|
892
934
|
onVideoProgress: this.onVideoProgress,
|
|
893
|
-
onVideoFullscreenPlayerDidDismiss: this.
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
onVideoFullscreenPlayerWillDismiss: this.unHandledEvent(
|
|
900
|
-
"onVideoFullscreenPlayerWillDismiss"
|
|
901
|
-
),
|
|
902
|
-
onVideoFullscreenPlayerWillPresent: this.unHandledEvent(
|
|
903
|
-
"onVideoFullscreenPlayerWillPresent"
|
|
904
|
-
),
|
|
935
|
+
onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
|
|
936
|
+
onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
|
|
937
|
+
onVideoFullscreenPlayerWillDismiss:
|
|
938
|
+
this.onVideoFullscreenPlayerWillDismiss,
|
|
939
|
+
onVideoFullscreenPlayerWillPresent:
|
|
940
|
+
this.onVideoFullscreenPlayerWillPresent,
|
|
905
941
|
onVideoLoad: this.onVideoLoad,
|
|
906
942
|
onVideoLoadStart: this.unHandledEvent("onVideoLoadStart"),
|
|
907
943
|
onVideoBuffer: this.onVideoBuffer,
|
|
908
944
|
onPlaybackStalled: this.onPlaybackStalled,
|
|
945
|
+
onPlayerClose: this.onPlayerClose,
|
|
909
946
|
onPlayerAttached: this.onPlayerAttached,
|
|
910
947
|
onPlayerDetached: this.onPlayerDetached,
|
|
911
948
|
};
|
|
@@ -979,7 +1016,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
979
1016
|
!needToShowPlayNextOverlay &&
|
|
980
1017
|
this.props.mode !== "PIP";
|
|
981
1018
|
|
|
982
|
-
if (
|
|
1019
|
+
if (shouldUseNativeControls) {
|
|
983
1020
|
return null;
|
|
984
1021
|
}
|
|
985
1022
|
|
|
@@ -998,6 +1035,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
998
1035
|
extraInfoText={castAction?.state?.friendlyStatus}
|
|
999
1036
|
controlsAlwaysVisible={castAction?.state?.connected}
|
|
1000
1037
|
playNextData={this.getPlayNextData()}
|
|
1038
|
+
nativeControls={!!controls}
|
|
1001
1039
|
/>
|
|
1002
1040
|
) : null;
|
|
1003
1041
|
};
|
|
@@ -1032,29 +1070,14 @@ export default class VideoPlayer extends React.Component<
|
|
|
1032
1070
|
const renderMobilePlayer = () => {
|
|
1033
1071
|
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
1034
1072
|
<View style={containerStyle}>
|
|
1035
|
-
{!castAction?.state?.connected && (
|
|
1073
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1036
1074
|
<this.props.PlayerComponent
|
|
1037
1075
|
ref={this._assignRoot}
|
|
1038
1076
|
{...nativeEvents}
|
|
1039
1077
|
{...nativeProps}
|
|
1040
1078
|
/>
|
|
1041
1079
|
)}
|
|
1042
|
-
<AudioPlayerWrapper {...sharedWrapperViewProps}
|
|
1043
|
-
<View>
|
|
1044
|
-
{
|
|
1045
|
-
<PlayNextOverlay
|
|
1046
|
-
item={entry}
|
|
1047
|
-
playerIsDocked={docked}
|
|
1048
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1049
|
-
playerId={this.props.playerId}
|
|
1050
|
-
playNextData={this.getPlayNextData()}
|
|
1051
|
-
setNextVideoPreloadThresholdPercentage={
|
|
1052
|
-
this.props.setNextVideoPreloadThresholdPercentage
|
|
1053
|
-
}
|
|
1054
|
-
/>
|
|
1055
|
-
}
|
|
1056
|
-
</View>
|
|
1057
|
-
</AudioPlayerWrapper>
|
|
1080
|
+
<AudioPlayerWrapper {...sharedWrapperViewProps} />
|
|
1058
1081
|
</View>
|
|
1059
1082
|
) : (
|
|
1060
1083
|
<PlayerWrapper {...sharedWrapperViewProps}>
|
|
@@ -1069,11 +1092,24 @@ export default class VideoPlayer extends React.Component<
|
|
|
1069
1092
|
<View style={styles.container}>
|
|
1070
1093
|
<View style={[playerContainerStyles, playerDimensions]}>
|
|
1071
1094
|
{isAudioItem && (
|
|
1072
|
-
<
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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>
|
|
1077
1113
|
)}
|
|
1078
1114
|
|
|
1079
1115
|
{shouldRenderBackground && (
|
|
@@ -1085,18 +1121,28 @@ export default class VideoPlayer extends React.Component<
|
|
|
1085
1121
|
/>
|
|
1086
1122
|
)}
|
|
1087
1123
|
|
|
1088
|
-
{!castAction?.state?.connected && (
|
|
1089
|
-
<
|
|
1090
|
-
|
|
1091
|
-
{
|
|
1092
|
-
{...nativeProps}
|
|
1093
|
-
listener={this.props.listener}
|
|
1124
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1125
|
+
<AnimationComponent
|
|
1126
|
+
animationType={ComponentAnimationType.player}
|
|
1127
|
+
additionalData={playerDimensions}
|
|
1094
1128
|
style={getStyle(playerDimensions)}
|
|
1095
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1096
|
-
controller={this.props.controller}
|
|
1097
1129
|
>
|
|
1098
|
-
|
|
1099
|
-
|
|
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>
|
|
1100
1146
|
)}
|
|
1101
1147
|
</View>
|
|
1102
1148
|
|