@applicaster/quick-brick-player 12.0.0-alpha.3208346089 → 12.0.0-alpha.3235354579
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 +176 -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 +1 -1
- package/src/Player/Utils/Utils.ts +5 -22
- package/src/Player/index.tsx +74 -130
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.3235354579",
|
|
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.58",
|
|
40
|
+
"@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.62",
|
|
41
|
+
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3235354579",
|
|
42
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3235354579",
|
|
43
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.3235354579",
|
|
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,107 @@ 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}
|
|
336
422
|
/>
|
|
337
|
-
)}
|
|
338
423
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
424
|
+
{showCounter && timeLeft >= 0 && (
|
|
425
|
+
<CountDown
|
|
426
|
+
timeLeft={timeLeft}
|
|
427
|
+
value={value}
|
|
428
|
+
title={sleepTitle}
|
|
429
|
+
/>
|
|
430
|
+
)}
|
|
431
|
+
|
|
432
|
+
<Separator />
|
|
433
|
+
</View>
|
|
434
|
+
)}
|
|
435
|
+
<Controls
|
|
436
|
+
value={value}
|
|
437
|
+
visible={true}
|
|
438
|
+
keepAlive={null}
|
|
439
|
+
buttons={controlButtons}
|
|
440
|
+
style={Styles.controls(
|
|
441
|
+
isTablet,
|
|
442
|
+
isLiveContent && showFullControls
|
|
443
|
+
)}
|
|
444
|
+
playerState={playerState}
|
|
445
|
+
/>
|
|
446
|
+
</AnimationComponent>
|
|
447
|
+
)}
|
|
351
448
|
</View>
|
|
352
449
|
</View>
|
|
353
450
|
);
|
|
@@ -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,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,7 @@ export const addQueryParam = (
|
|
|
42
21
|
|
|
43
22
|
return `${urlWithoutQuery}?${updatedQueryString}`;
|
|
44
23
|
};
|
|
24
|
+
|
|
25
|
+
export const isValidDate = (dateString: string): boolean => {
|
|
26
|
+
return dateString.trim() !== "" && dayjs.utc(dateString).isValid();
|
|
27
|
+
};
|
package/src/Player/index.tsx
CHANGED
|
@@ -21,14 +21,8 @@ import { PlayerWrapper } from "@applicaster/zapp-react-native-ui-components/Comp
|
|
|
21
21
|
|
|
22
22
|
import { PlayNextOverlay } from "./PlayNextOverlay";
|
|
23
23
|
import { PlayerImageBackground } from "@applicaster/zapp-react-native-ui-components/Components/PlayerImageBackground";
|
|
24
|
-
import { AnalyticsTracker } from "@applicaster/zapp-react-native-utils/analyticsUtils/analyticsTracker";
|
|
25
24
|
|
|
26
|
-
import {
|
|
27
|
-
AD_EVENT,
|
|
28
|
-
GENERAL_EVENT,
|
|
29
|
-
PLAYBACK_EVENT,
|
|
30
|
-
QOS_EVENT,
|
|
31
|
-
} from "@applicaster/zapp-react-native-utils/analyticsUtils/events";
|
|
25
|
+
import { GENERAL_EVENT } from "@applicaster/zapp-react-native-utils/analyticsUtils/events";
|
|
32
26
|
import { Categories, createLogger, Subsystem } from "../logger";
|
|
33
27
|
import { parseLanguageTracks } from "@applicaster/zapp-react-native-utils/playerUtils/configurationUtils";
|
|
34
28
|
import { DEFAULT_COLORS, SEEK_TIME } from "../utils/const";
|
|
@@ -38,6 +32,12 @@ import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/c
|
|
|
38
32
|
import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
|
|
39
33
|
import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
|
|
40
34
|
import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
|
|
35
|
+
import {
|
|
36
|
+
AnimationComponent,
|
|
37
|
+
ComponentAnimationType,
|
|
38
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
39
|
+
import { PlayerAnalyticsManager } from "@applicaster/zapp-react-native-utils/analyticsUtils/PlayerAnalyticsManager";
|
|
40
|
+
import { PlayerAnalyticsTrackerI } from "@applicaster/zapp-react-native-utils/analyticsUtils/playerAnalyticsTracker";
|
|
41
41
|
|
|
42
42
|
const RNPlayerManager = {
|
|
43
43
|
QuickBrickPlayerPlugin: isApplePlatform()
|
|
@@ -57,6 +57,7 @@ const styles = StyleSheet.create({
|
|
|
57
57
|
position: "absolute",
|
|
58
58
|
zIndex: 1,
|
|
59
59
|
},
|
|
60
|
+
playerSize: { width: "100%", height: "100%" },
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
const logger = createLogger({
|
|
@@ -70,7 +71,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
70
71
|
> {
|
|
71
72
|
public static propTypes = {};
|
|
72
73
|
_root: any;
|
|
73
|
-
analyticsTracker: AnalyticsTracker;
|
|
74
74
|
playerPluginId: string;
|
|
75
75
|
takeParentStyle: Record<any, any>;
|
|
76
76
|
playbackStarted = false;
|
|
@@ -101,6 +101,17 @@ export default class VideoPlayer extends React.Component<
|
|
|
101
101
|
duration: 0,
|
|
102
102
|
};
|
|
103
103
|
|
|
104
|
+
private _tracker: PlayerAnalyticsTrackerI;
|
|
105
|
+
get analyticsTracker() {
|
|
106
|
+
if (!this._tracker) {
|
|
107
|
+
this._tracker = PlayerAnalyticsManager.getInstance().getTracker(
|
|
108
|
+
this.props.playerId
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return this._tracker;
|
|
113
|
+
}
|
|
114
|
+
|
|
104
115
|
constructor(props) {
|
|
105
116
|
super(props);
|
|
106
117
|
this.onVideoLoadCalled = false; // android
|
|
@@ -109,8 +120,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
109
120
|
? { width: "100%", flex: "1 1 auto", objectFit: "contain" }
|
|
110
121
|
: { flexBasis: "auto", flexGrow: 1, flexShrink: 1 };
|
|
111
122
|
|
|
112
|
-
const entry = this.props?.entry;
|
|
113
|
-
this.analyticsTracker = new AnalyticsTracker(entry);
|
|
114
123
|
this.playerPluginId = this.props?.playerPluginIdentifier;
|
|
115
124
|
}
|
|
116
125
|
|
|
@@ -118,7 +127,8 @@ export default class VideoPlayer extends React.Component<
|
|
|
118
127
|
this.stopBackgroundPlayback();
|
|
119
128
|
|
|
120
129
|
this.playbackStarted = false;
|
|
121
|
-
|
|
130
|
+
|
|
131
|
+
this.analyticsTracker.handleAnalyticEvent(GENERAL_EVENT.session_end);
|
|
122
132
|
this.onPlayerClosed();
|
|
123
133
|
|
|
124
134
|
if (isAndroidPlatform()) {
|
|
@@ -174,27 +184,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
174
184
|
return this.props.pluginConfiguration;
|
|
175
185
|
};
|
|
176
186
|
|
|
177
|
-
/**
|
|
178
|
-
* Handles analytic events, generates a new analytics tracker and transmits events
|
|
179
|
-
* Passes entry data, and playerState to the tracker for additional context
|
|
180
|
-
* The end result is an event formatted and passed to AnalyticsBridge.postEvent
|
|
181
|
-
* When we get the synthetic event we need to pull the data in the nativeEvent object
|
|
182
|
-
* nativeEvent contains the return value from native
|
|
183
|
-
*/
|
|
184
|
-
handleAnalyticEvent = (event, data = {}) => {
|
|
185
|
-
const entry = this.props?.entry;
|
|
186
|
-
const playerState = this.getState();
|
|
187
|
-
|
|
188
|
-
if (this.analyticsTracker?.handleAnalyticEvent) {
|
|
189
|
-
this.analyticsTracker?.handleAnalyticEvent?.(
|
|
190
|
-
event,
|
|
191
|
-
{ ...data, player_type: this.props.playerPluginIdentifier },
|
|
192
|
-
entry,
|
|
193
|
-
playerState
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
|
|
198
187
|
/**
|
|
199
188
|
* This method is for the events that have no implementation in react but are being invoked by native
|
|
200
189
|
* When we get the synthetic event we need to pull the data in the nativeEvent object
|
|
@@ -398,28 +387,16 @@ export default class VideoPlayer extends React.Component<
|
|
|
398
387
|
};
|
|
399
388
|
|
|
400
389
|
onPlayerPresented = () => {
|
|
401
|
-
this.handleAnalyticEvent(GENERAL_EVENT.player_presented);
|
|
390
|
+
this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_presented);
|
|
402
391
|
};
|
|
403
392
|
|
|
404
393
|
onPlayerClosed = () => {
|
|
405
|
-
this.handleAnalyticEvent(GENERAL_EVENT.player_closed);
|
|
406
|
-
};
|
|
407
|
-
|
|
408
|
-
onPlayerSessionEnd = () => {
|
|
409
|
-
// TODO: Implement method on native android, ios exists
|
|
410
|
-
this.handleAnalyticEvent(GENERAL_EVENT.session_end);
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
onPlayerSessionStart = () => {
|
|
414
|
-
// TODO: Implement method on native android, ios exists
|
|
415
|
-
|
|
416
|
-
this.handleAnalyticEvent(GENERAL_EVENT.session_start);
|
|
394
|
+
this.analyticsTracker?.handleAnalyticEvent(GENERAL_EVENT.player_closed);
|
|
417
395
|
};
|
|
418
396
|
|
|
419
397
|
onVideoEnd = () => {
|
|
420
398
|
this.setState({ displayOverlay: !this.state.displayOverlay }, () => {
|
|
421
399
|
if (this.state?.displayOverlay) {
|
|
422
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.complete);
|
|
423
400
|
this.props?.listener?.onVideoEnd({});
|
|
424
401
|
}
|
|
425
402
|
});
|
|
@@ -429,15 +406,12 @@ export default class VideoPlayer extends React.Component<
|
|
|
429
406
|
onVideoError = ({ nativeEvent }) => {
|
|
430
407
|
const { message } = nativeEvent;
|
|
431
408
|
|
|
432
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.error, nativeEvent);
|
|
433
|
-
|
|
434
409
|
return this.props?.listener?.onError(new Error(message));
|
|
435
410
|
};
|
|
436
411
|
|
|
437
412
|
onPlayerPause = ({ nativeEvent = null }) => {
|
|
438
413
|
this.setState({ paused: true });
|
|
439
414
|
this.props?.listener?.onPlayerPause(nativeEvent);
|
|
440
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.pause, nativeEvent);
|
|
441
415
|
};
|
|
442
416
|
|
|
443
417
|
onPlayerResume = ({ nativeEvent = null }) => {
|
|
@@ -448,98 +422,61 @@ export default class VideoPlayer extends React.Component<
|
|
|
448
422
|
|
|
449
423
|
if (isNotAnAd && !resume) {
|
|
450
424
|
this.setState({ resume: true });
|
|
451
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.play, nativeEvent);
|
|
452
425
|
}
|
|
453
426
|
};
|
|
454
427
|
|
|
455
428
|
onPlayerSeekComplete = ({ nativeEvent }) => {
|
|
456
429
|
this.props?.listener?.onPlayerSeekComplete(nativeEvent);
|
|
457
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.seek_complete, nativeEvent);
|
|
458
430
|
};
|
|
459
431
|
|
|
460
432
|
onPlayerSeekStart = ({ nativeEvent }) => {
|
|
461
433
|
this.props?.listener?.onPlayerSeekStart(nativeEvent);
|
|
462
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.seek_start, nativeEvent);
|
|
463
434
|
};
|
|
464
435
|
|
|
465
436
|
onBufferStart = ({ nativeEvent }) => {
|
|
466
437
|
this.props?.listener?.onBufferStart(nativeEvent);
|
|
467
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_start, nativeEvent);
|
|
468
438
|
};
|
|
469
439
|
|
|
470
440
|
onBufferComplete = ({ nativeEvent }) => {
|
|
471
441
|
this.props?.listener?.onBufferComplete(nativeEvent);
|
|
472
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.buffer_complete, nativeEvent);
|
|
473
|
-
};
|
|
474
|
-
|
|
475
|
-
onPlayerNext = ({ nativeEvent }) => {
|
|
476
|
-
// TODO: Implement method on native
|
|
477
|
-
|
|
478
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.next, nativeEvent);
|
|
479
|
-
};
|
|
480
|
-
|
|
481
|
-
onPlayerPrevious = ({ nativeEvent }) => {
|
|
482
|
-
// TODO: Implement method on native
|
|
483
|
-
|
|
484
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.previous, nativeEvent);
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
onPlayerStop = ({ nativeEvent }) => {
|
|
488
|
-
// TODO: Implement method on native
|
|
489
|
-
|
|
490
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.stop, nativeEvent);
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
onVideoBandwidthUpdate = ({ nativeEvent }) => {
|
|
494
|
-
// TODO: Implement method on native
|
|
495
|
-
|
|
496
|
-
this.handleAnalyticEvent(QOS_EVENT.bitrate_changed, nativeEvent);
|
|
497
442
|
};
|
|
498
443
|
|
|
499
444
|
onAdBegin = ({ nativeEvent }) => {
|
|
500
445
|
this.setState({ isAd: true });
|
|
501
|
-
this.handleAnalyticEvent(AD_EVENT.ad_start, nativeEvent);
|
|
502
446
|
this.props.listener?.onAdBegin?.(nativeEvent);
|
|
503
447
|
};
|
|
504
448
|
|
|
505
449
|
onAdBreakBegin = ({ nativeEvent }) => {
|
|
506
450
|
this.setState({ isAd: true });
|
|
507
|
-
this.handleAnalyticEvent(AD_EVENT.ad_break_start, nativeEvent);
|
|
508
451
|
this.props.listener?.onAdBreakBegin?.(nativeEvent);
|
|
509
452
|
};
|
|
510
453
|
|
|
511
454
|
onAdBreakEnd = ({ nativeEvent }) => {
|
|
512
455
|
this.setState({ isAd: false });
|
|
513
|
-
this.handleAnalyticEvent(AD_EVENT.ad_break_completed, nativeEvent);
|
|
514
456
|
this.props.listener?.onAdBreakEnd?.(nativeEvent);
|
|
515
457
|
};
|
|
516
458
|
|
|
517
459
|
onAdEnd = ({ nativeEvent }) => {
|
|
518
460
|
this.setState({ isAd: false });
|
|
519
|
-
this.handleAnalyticEvent(AD_EVENT.ad_complete, nativeEvent);
|
|
520
461
|
this.props.listener?.onAdEnd?.(nativeEvent);
|
|
521
462
|
};
|
|
522
463
|
|
|
523
464
|
onAdError = ({ nativeEvent }) => {
|
|
524
465
|
this.setState({ isAd: false });
|
|
525
|
-
this.handleAnalyticEvent(AD_EVENT.ad_error, nativeEvent);
|
|
526
466
|
this.props.listener?.onAdError?.(nativeEvent);
|
|
527
467
|
};
|
|
528
468
|
|
|
529
469
|
onAdRequest = ({ nativeEvent }) => {
|
|
530
|
-
this.handleAnalyticEvent(AD_EVENT.ad_request, nativeEvent);
|
|
531
470
|
this.props.listener?.onAdRequest?.(nativeEvent);
|
|
532
471
|
};
|
|
533
472
|
|
|
534
473
|
onAdClicked = ({ nativeEvent }) => {
|
|
535
|
-
this.handleAnalyticEvent(AD_EVENT.ad_clicked, nativeEvent);
|
|
536
474
|
// Broadcast click event
|
|
537
475
|
this.props.playerEvent("ad-clicked", nativeEvent);
|
|
538
476
|
this.props.listener?.onAdClicked?.(nativeEvent);
|
|
539
477
|
};
|
|
540
478
|
|
|
541
479
|
onAdTapped = ({ nativeEvent }) => {
|
|
542
|
-
this.handleAnalyticEvent(AD_EVENT.ad_tapped, nativeEvent);
|
|
543
480
|
// Broadcast click event
|
|
544
481
|
this.props.playerEvent("ad-tapped", nativeEvent);
|
|
545
482
|
this.props.listener?.onAdTapped?.(nativeEvent);
|
|
@@ -652,10 +589,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
652
589
|
}
|
|
653
590
|
|
|
654
591
|
if (!this.state.isAd && !this.onVideoLoadCalled) {
|
|
655
|
-
this.handleAnalyticEvent(PLAYBACK_EVENT.load_video, {
|
|
656
|
-
player_type: this.props.playerPluginIdentifier,
|
|
657
|
-
});
|
|
658
|
-
|
|
659
592
|
// TODO: Hack, needs to remove
|
|
660
593
|
this.onVideoLoadCalled = true;
|
|
661
594
|
}
|
|
@@ -780,7 +713,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
780
713
|
|
|
781
714
|
render() {
|
|
782
715
|
const {
|
|
783
|
-
castAction,
|
|
784
716
|
docked,
|
|
785
717
|
entry,
|
|
786
718
|
fullscreen,
|
|
@@ -790,8 +722,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
790
722
|
isTabletPortrait,
|
|
791
723
|
muted,
|
|
792
724
|
style,
|
|
725
|
+
castAction,
|
|
726
|
+
controller,
|
|
727
|
+
startComponentsAnimation,
|
|
793
728
|
} = this.props;
|
|
794
729
|
|
|
730
|
+
const supportNativeCast = controller.supportNativeCast();
|
|
731
|
+
|
|
795
732
|
const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
|
|
796
733
|
this.state;
|
|
797
734
|
|
|
@@ -856,7 +793,11 @@ export default class VideoPlayer extends React.Component<
|
|
|
856
793
|
? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
|
|
857
794
|
: supportsNativeControls && !this.getPlayNextData();
|
|
858
795
|
|
|
859
|
-
const shouldUseNativeControls =
|
|
796
|
+
const shouldUseNativeControls =
|
|
797
|
+
controls &&
|
|
798
|
+
!startComponentsAnimation &&
|
|
799
|
+
!docked &&
|
|
800
|
+
!castAction?.state?.connected;
|
|
860
801
|
|
|
861
802
|
platformSpecificProps = {
|
|
862
803
|
...platformSpecificProps,
|
|
@@ -915,8 +856,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
915
856
|
onPlayerResume: this.onPlayerResume, // play
|
|
916
857
|
onPlayerSeekComplete: this.onPlayerSeekComplete, // seek_complete
|
|
917
858
|
onPlayerSeekStart: this.onPlayerSeekStart, // seek_start
|
|
918
|
-
onPlayerSessionEnd: this.onPlayerSessionEnd, // session_end
|
|
919
|
-
onPlayerSessionStart: this.onPlayerSessionStart, // session_start
|
|
920
859
|
};
|
|
921
860
|
|
|
922
861
|
const lifecycleEvents = {
|
|
@@ -949,7 +888,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
949
888
|
onTimedMetadata: this.unHandledEvent("onTimedMetadata"),
|
|
950
889
|
onTracksChanged: this.onTracksChanged,
|
|
951
890
|
eventSubtitlesChange: this.unHandledEvent("eventSubtitlesChange"),
|
|
952
|
-
onVideoBandwidthUpdate: this.onVideoBandwidthUpdate,
|
|
953
891
|
};
|
|
954
892
|
|
|
955
893
|
const playerSystemEvents = {
|
|
@@ -969,9 +907,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
969
907
|
const unsupportedEvents = {
|
|
970
908
|
onBufferComplete: this.onBufferComplete, // buffer_complete
|
|
971
909
|
onBufferStart: this.onBufferStart, // buffer_start
|
|
972
|
-
onPlayerNext: this.onPlayerNext, // next
|
|
973
|
-
onPlayerPrevious: this.onPlayerPrevious, // previous
|
|
974
|
-
onPlayerStop: this.onPlayerStop, // stop
|
|
975
910
|
};
|
|
976
911
|
|
|
977
912
|
const nativeEvents = {
|
|
@@ -1027,6 +962,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1027
962
|
extraInfoText={castAction?.state?.friendlyStatus}
|
|
1028
963
|
controlsAlwaysVisible={castAction?.state?.connected}
|
|
1029
964
|
playNextData={this.getPlayNextData()}
|
|
965
|
+
nativeControls={!!controls}
|
|
1030
966
|
/>
|
|
1031
967
|
) : null;
|
|
1032
968
|
};
|
|
@@ -1061,29 +997,14 @@ export default class VideoPlayer extends React.Component<
|
|
|
1061
997
|
const renderMobilePlayer = () => {
|
|
1062
998
|
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
1063
999
|
<View style={containerStyle}>
|
|
1064
|
-
{!castAction?.state?.connected && (
|
|
1000
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1065
1001
|
<this.props.PlayerComponent
|
|
1066
1002
|
ref={this._assignRoot}
|
|
1067
1003
|
{...nativeEvents}
|
|
1068
1004
|
{...nativeProps}
|
|
1069
1005
|
/>
|
|
1070
1006
|
)}
|
|
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>
|
|
1007
|
+
<AudioPlayerWrapper {...sharedWrapperViewProps} />
|
|
1087
1008
|
</View>
|
|
1088
1009
|
) : (
|
|
1089
1010
|
<PlayerWrapper {...sharedWrapperViewProps}>
|
|
@@ -1098,11 +1019,24 @@ export default class VideoPlayer extends React.Component<
|
|
|
1098
1019
|
<View style={styles.container}>
|
|
1099
1020
|
<View style={[playerContainerStyles, playerDimensions]}>
|
|
1100
1021
|
{isAudioItem && (
|
|
1101
|
-
<
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1022
|
+
<AnimationComponent
|
|
1023
|
+
animationType={ComponentAnimationType.player}
|
|
1024
|
+
additionalData={{
|
|
1025
|
+
...playerDimensions,
|
|
1026
|
+
inlineAudioPlayer: true,
|
|
1027
|
+
}}
|
|
1028
|
+
style={getStyle(playerDimensions)}
|
|
1029
|
+
>
|
|
1030
|
+
<AudioPlayer
|
|
1031
|
+
style={
|
|
1032
|
+
isTV()
|
|
1033
|
+
? getStyle(playerDimensions)
|
|
1034
|
+
: styles.playerSize
|
|
1035
|
+
}
|
|
1036
|
+
audio_item={entry}
|
|
1037
|
+
plugin_configuration={this.getPluginConfiguration()}
|
|
1038
|
+
/>
|
|
1039
|
+
</AnimationComponent>
|
|
1106
1040
|
)}
|
|
1107
1041
|
|
|
1108
1042
|
{shouldRenderBackground && (
|
|
@@ -1114,18 +1048,28 @@ export default class VideoPlayer extends React.Component<
|
|
|
1114
1048
|
/>
|
|
1115
1049
|
)}
|
|
1116
1050
|
|
|
1117
|
-
{!castAction?.state?.connected && (
|
|
1118
|
-
<
|
|
1119
|
-
|
|
1120
|
-
{
|
|
1121
|
-
{...nativeProps}
|
|
1122
|
-
listener={this.props.listener}
|
|
1051
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1052
|
+
<AnimationComponent
|
|
1053
|
+
animationType={ComponentAnimationType.player}
|
|
1054
|
+
additionalData={playerDimensions}
|
|
1123
1055
|
style={getStyle(playerDimensions)}
|
|
1124
|
-
pluginConfiguration={this.getPluginConfiguration()}
|
|
1125
|
-
controller={this.props.controller}
|
|
1126
1056
|
>
|
|
1127
|
-
|
|
1128
|
-
|
|
1057
|
+
<this.props.PlayerComponent
|
|
1058
|
+
ref={this._assignRoot}
|
|
1059
|
+
{...nativeEvents}
|
|
1060
|
+
{...nativeProps}
|
|
1061
|
+
listener={this.props.listener}
|
|
1062
|
+
style={
|
|
1063
|
+
isTV()
|
|
1064
|
+
? getStyle(playerDimensions)
|
|
1065
|
+
: styles.playerSize
|
|
1066
|
+
}
|
|
1067
|
+
pluginConfiguration={this.getPluginConfiguration()}
|
|
1068
|
+
controller={this.props.controller}
|
|
1069
|
+
>
|
|
1070
|
+
{this.childrenWithPlayNext()}
|
|
1071
|
+
</this.props.PlayerComponent>
|
|
1072
|
+
</AnimationComponent>
|
|
1129
1073
|
)}
|
|
1130
1074
|
</View>
|
|
1131
1075
|
|