@applicaster/quick-brick-player 12.0.0-alpha.4374801485 → 12.0.0-alpha.4408649484
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
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.4408649484",
|
|
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-
|
|
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.89",
|
|
40
|
+
"@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.89",
|
|
41
|
+
"@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.4408649484",
|
|
42
|
+
"@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.4408649484",
|
|
43
|
+
"@applicaster/zapp-react-native-utils": "12.0.0-alpha.4408649484",
|
|
44
44
|
"keymirror": "^0.1.1",
|
|
45
45
|
"query-string": "7.1.3",
|
|
46
46
|
"react-native-web-linear-gradient": "1.1.2",
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
AnimatedScrollModal,
|
|
33
33
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
34
34
|
import { PADDING_HORIZONTAL } from "./Layout/defaultLayoutsConts";
|
|
35
|
+
import { toNumberWithDefault } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
35
36
|
|
|
36
37
|
const { log_debug } = createLogger({
|
|
37
38
|
subsystem: "UIComponent",
|
|
@@ -294,7 +295,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
294
295
|
playerState.isPaused ? player?.play() : player.pause();
|
|
295
296
|
}, [playerState, player]);
|
|
296
297
|
|
|
297
|
-
const seekDuration =
|
|
298
|
+
const seekDuration = toNumberWithDefault(10, value("seek_duration"));
|
|
298
299
|
|
|
299
300
|
const onRewindButtonPress = React.useCallback(() => {
|
|
300
301
|
player?.rewind(seekDuration);
|
|
@@ -387,6 +388,7 @@ export const AudioPlayerWrapper: React.FC<Props> = (props: Props) => {
|
|
|
387
388
|
<AnimationComponent
|
|
388
389
|
animationType={ComponentAnimationType.moveUpComponent}
|
|
389
390
|
additionalData={{ saveArea: true }}
|
|
391
|
+
style={Styles.playerContainer}
|
|
390
392
|
>
|
|
391
393
|
<AnimatedScrollModal>
|
|
392
394
|
<View style={Styles.playerContainer} onLayout={onLayout}>
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
// DefaultLayout.tsx
|
|
2
|
-
|
|
3
1
|
import * as React from "react";
|
|
4
2
|
import * as R from "ramda";
|
|
5
3
|
import { View } from "react-native";
|
|
6
|
-
import dayjs from "
|
|
7
|
-
import utc from "dayjs/plugin/utc";
|
|
4
|
+
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
8
5
|
|
|
9
6
|
import {
|
|
10
7
|
ProgressBar,
|
|
@@ -39,8 +36,6 @@ import {
|
|
|
39
36
|
import DockedLayout from "./DockedLayout";
|
|
40
37
|
import { isValidDate } from "../../Utils";
|
|
41
38
|
|
|
42
|
-
dayjs.extend(utc);
|
|
43
|
-
|
|
44
39
|
type Dimensions = {
|
|
45
40
|
width: number;
|
|
46
41
|
height: number;
|
|
@@ -197,24 +192,20 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
197
192
|
|
|
198
193
|
let showFullControls = !controller?.isAd();
|
|
199
194
|
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
const endTime = entry.extensions?.end_time;
|
|
195
|
+
const startTime = entry.extensions?.live?.start_time;
|
|
196
|
+
const endTime = entry.extensions?.live?.end_time;
|
|
203
197
|
|
|
204
198
|
const hasValidStartTime = isValidDate(startTime);
|
|
205
199
|
const hasValidEndTime = isValidDate(endTime);
|
|
206
200
|
|
|
207
|
-
// Abstracted condition
|
|
208
201
|
const isDateBasedLiveContent =
|
|
209
202
|
isLiveContent && hasValidStartTime && hasValidEndTime;
|
|
210
203
|
|
|
211
|
-
// Determine if progress bar should be shown
|
|
212
204
|
const needsToShowProgressBar =
|
|
213
205
|
(isLiveContent &&
|
|
214
206
|
(Boolean(value("liveSeekingEnabled")) || isDateBasedLiveContent)) ||
|
|
215
207
|
!isLiveContent;
|
|
216
208
|
|
|
217
|
-
// Convert valid date strings to timestamps
|
|
218
209
|
const startTimestamp = hasValidStartTime
|
|
219
210
|
? dayjs.utc(startTime!).valueOf()
|
|
220
211
|
: undefined;
|
|
@@ -291,7 +282,6 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
291
282
|
return [skipToStart, rewind, play, forward, skipToLive];
|
|
292
283
|
}
|
|
293
284
|
|
|
294
|
-
// Temporary empty button until we add sleep button. It will ensure the buttons will not break in their position
|
|
295
285
|
return [speed, rewind, play, forward, sleep];
|
|
296
286
|
}, [
|
|
297
287
|
playerState,
|
|
@@ -312,15 +302,12 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
312
302
|
|
|
313
303
|
useEffect(() => {
|
|
314
304
|
if (showCounter && sleepTimerDate !== 0) {
|
|
315
|
-
// Setting the initial timeLeft based on sleepTimerDate
|
|
316
305
|
setTimeLeft(sleepTimerDate - Date.now());
|
|
317
306
|
|
|
318
|
-
// Setting up an interval to update the remaining time every second
|
|
319
307
|
const intervalId = setInterval(() => {
|
|
320
308
|
setTimeLeft(() => {
|
|
321
309
|
const newTimeLeft = sleepTimerDate - Date.now();
|
|
322
310
|
|
|
323
|
-
// If the new remaining time is less than or equal to 0, clear the interval and trigger the cancelSleepTimer function
|
|
324
311
|
if (newTimeLeft <= 0) {
|
|
325
312
|
clearInterval(intervalId);
|
|
326
313
|
|
|
@@ -328,16 +315,13 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
328
315
|
|
|
329
316
|
return 0;
|
|
330
317
|
} else {
|
|
331
|
-
// Otherwise, update the state with the new remaining time
|
|
332
318
|
return newTimeLeft;
|
|
333
319
|
}
|
|
334
320
|
});
|
|
335
321
|
}, 1000);
|
|
336
322
|
|
|
337
|
-
// Clearing the interval when the component unmounts or dependencies change
|
|
338
323
|
return () => clearInterval(intervalId);
|
|
339
324
|
} else {
|
|
340
|
-
// Ensure the timeLeft state is set correctly if showCounter is false
|
|
341
325
|
setTimeLeft(0);
|
|
342
326
|
}
|
|
343
327
|
}, [sleepTimerDate, showCounter, cancelSleepTimer]);
|
|
@@ -435,6 +419,7 @@ export default function DefaultLayout(props: LayoutProps) {
|
|
|
435
419
|
startTimestamp={startTimestamp}
|
|
436
420
|
endTimestamp={endTimestamp}
|
|
437
421
|
isDateBasedLiveContent={isDateBasedLiveContent}
|
|
422
|
+
onSkipLive={onSkipLive}
|
|
438
423
|
/>
|
|
439
424
|
|
|
440
425
|
{showCounter && timeLeft >= 0 && (
|
|
@@ -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,
|
|
@@ -113,11 +126,30 @@ export const MagicBG: React.FC<MagicBGProps> = ({
|
|
|
113
126
|
fetchColors();
|
|
114
127
|
}, []);
|
|
115
128
|
|
|
129
|
+
const interpolatedBackgroundColor = backgroundColorAnim.interpolate({
|
|
130
|
+
inputRange: [0, 1],
|
|
131
|
+
outputRange: ["black", dominantColor],
|
|
132
|
+
});
|
|
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,8 +1,5 @@
|
|
|
1
1
|
import queryString from "query-string";
|
|
2
|
-
import dayjs from "
|
|
3
|
-
import utc from "dayjs/plugin/utc";
|
|
4
|
-
|
|
5
|
-
dayjs.extend(utc);
|
|
2
|
+
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
6
3
|
|
|
7
4
|
export const getLiveUrl = (url: string) => {
|
|
8
5
|
// Use the replace method with a regular expression to replace all instances of subClass with livePage
|
|
@@ -25,6 +22,10 @@ export const addQueryParam = (
|
|
|
25
22
|
return `${urlWithoutQuery}?${updatedQueryString}`;
|
|
26
23
|
};
|
|
27
24
|
|
|
28
|
-
export const isValidDate = (dateString: string) => {
|
|
29
|
-
return
|
|
25
|
+
export const isValidDate = (dateString: string | undefined): boolean => {
|
|
26
|
+
return (
|
|
27
|
+
typeof dateString === "string" &&
|
|
28
|
+
dateString.trim() !== "" &&
|
|
29
|
+
dayjs.utc(dateString).isValid()
|
|
30
|
+
);
|
|
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
|
|
|
@@ -42,15 +42,7 @@ import {
|
|
|
42
42
|
AnimationComponent,
|
|
43
43
|
ComponentAnimationType,
|
|
44
44
|
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
|
|
45
|
-
|
|
46
|
-
const RNPlayerManager = {
|
|
47
|
-
QuickBrickPlayerPlugin: isApplePlatform()
|
|
48
|
-
? NativeModules.PlayerModule
|
|
49
|
-
: NativeModules.QuickBrickDefaultPlayerModule,
|
|
50
|
-
KalturaPlayerPlugin: isApplePlatform()
|
|
51
|
-
? NativeModules.KalturaPlayerModule
|
|
52
|
-
: NativeModules.QBKalturaPlayerModule,
|
|
53
|
-
};
|
|
45
|
+
import { RNPlayerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/nativePlayerManager";
|
|
54
46
|
|
|
55
47
|
const styles = StyleSheet.create({
|
|
56
48
|
container: { flex: 1 },
|
|
@@ -120,8 +112,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
120
112
|
}
|
|
121
113
|
|
|
122
114
|
componentWillUnmount() {
|
|
123
|
-
this.stopBackgroundPlayback();
|
|
124
|
-
|
|
125
115
|
this.playbackStarted = false;
|
|
126
116
|
this.handleAnalyticEvent(GENERAL_EVENT.session_end);
|
|
127
117
|
this.onPlayerClosed();
|
|
@@ -166,6 +156,11 @@ export default class VideoPlayer extends React.Component<
|
|
|
166
156
|
}
|
|
167
157
|
}
|
|
168
158
|
|
|
159
|
+
// For close button
|
|
160
|
+
public closeNativePlayer = () => {
|
|
161
|
+
this.stopBackgroundPlayback();
|
|
162
|
+
};
|
|
163
|
+
|
|
169
164
|
getPlayNextData = () => this.props.playNextData as PlayNextData;
|
|
170
165
|
|
|
171
166
|
/**
|
|
@@ -340,11 +335,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
340
335
|
}
|
|
341
336
|
};
|
|
342
337
|
|
|
343
|
-
|
|
344
|
-
* Sets either subtitle language, or audio language if we have a selected a new locale.
|
|
345
|
-
* If no locale is set it defaults to system language for audio, and leaves subtitles unaltered.
|
|
346
|
-
*/
|
|
347
|
-
setLanguage = (selected = null) => {
|
|
338
|
+
selectTrack = (selected) => {
|
|
348
339
|
const { trackType, id, language } = selected || {};
|
|
349
340
|
|
|
350
341
|
const isOff = language === "Off";
|
|
@@ -785,7 +776,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
785
776
|
|
|
786
777
|
render() {
|
|
787
778
|
const {
|
|
788
|
-
castAction,
|
|
789
779
|
docked,
|
|
790
780
|
entry,
|
|
791
781
|
fullscreen,
|
|
@@ -795,8 +785,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
795
785
|
isTabletPortrait,
|
|
796
786
|
muted,
|
|
797
787
|
style,
|
|
788
|
+
castAction,
|
|
789
|
+
controller,
|
|
790
|
+
startComponentsAnimation,
|
|
798
791
|
} = this.props;
|
|
799
792
|
|
|
793
|
+
const supportNativeCast = controller.supportNativeCast();
|
|
794
|
+
|
|
800
795
|
const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
|
|
801
796
|
this.state;
|
|
802
797
|
|
|
@@ -861,7 +856,11 @@ export default class VideoPlayer extends React.Component<
|
|
|
861
856
|
? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
|
|
862
857
|
: supportsNativeControls && !this.getPlayNextData();
|
|
863
858
|
|
|
864
|
-
const shouldUseNativeControls =
|
|
859
|
+
const shouldUseNativeControls =
|
|
860
|
+
controls &&
|
|
861
|
+
!startComponentsAnimation &&
|
|
862
|
+
!docked &&
|
|
863
|
+
!castAction?.state?.connected;
|
|
865
864
|
|
|
866
865
|
platformSpecificProps = {
|
|
867
866
|
...platformSpecificProps,
|
|
@@ -990,7 +989,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
990
989
|
...androidLifecyclePiPEvents,
|
|
991
990
|
};
|
|
992
991
|
|
|
993
|
-
const needToShowPlayNextOverlay =
|
|
992
|
+
const needToShowPlayNextOverlay =
|
|
993
|
+
isTV() && this.getPlayNextData() && !docked;
|
|
994
|
+
|
|
995
|
+
const needToShowDefaultControls = !(
|
|
996
|
+
(controls && !castAction?.state?.connected) ||
|
|
997
|
+
this.getPlayNextData()
|
|
998
|
+
);
|
|
994
999
|
|
|
995
1000
|
const playerContainerStyles = isApplePlatform()
|
|
996
1001
|
? styles.playerContainerBlack
|
|
@@ -1032,6 +1037,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1032
1037
|
extraInfoText={castAction?.state?.friendlyStatus}
|
|
1033
1038
|
controlsAlwaysVisible={castAction?.state?.connected}
|
|
1034
1039
|
playNextData={this.getPlayNextData()}
|
|
1040
|
+
needToShowDefaultControls={needToShowDefaultControls}
|
|
1035
1041
|
/>
|
|
1036
1042
|
) : null;
|
|
1037
1043
|
};
|
|
@@ -1066,7 +1072,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1066
1072
|
const renderMobilePlayer = () => {
|
|
1067
1073
|
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
1068
1074
|
<View style={containerStyle}>
|
|
1069
|
-
{!castAction?.state?.connected && (
|
|
1075
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1070
1076
|
<this.props.PlayerComponent
|
|
1071
1077
|
ref={this._assignRoot}
|
|
1072
1078
|
{...nativeEvents}
|
|
@@ -1117,7 +1123,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1117
1123
|
/>
|
|
1118
1124
|
)}
|
|
1119
1125
|
|
|
1120
|
-
{!castAction?.state?.connected && (
|
|
1126
|
+
{(!castAction?.state?.connected || supportNativeCast) && (
|
|
1121
1127
|
<AnimationComponent
|
|
1122
1128
|
animationType={ComponentAnimationType.player}
|
|
1123
1129
|
additionalData={playerDimensions}
|