@applicaster/quick-brick-player 12.0.0-alpha.3788876021 → 12.0.0-alpha.3849101242

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.3788876021",
3
+ "version": "12.0.0-alpha.3849101242",
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-alpha.3788876021",
40
- "@applicaster/quick-brick-tv-transport-controls": "11.0.0-rc.133",
41
- "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3788876021",
42
- "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3788876021",
43
- "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3788876021",
39
+ "@applicaster/quick-brick-mobile-transport-controls": "12.0.0-rc.68",
40
+ "@applicaster/quick-brick-tv-transport-controls": "12.0.0-rc.62",
41
+ "@applicaster/zapp-react-native-tvos-app": "12.0.0-alpha.3849101242",
42
+ "@applicaster/zapp-react-native-ui-components": "12.0.0-alpha.3849101242",
43
+ "@applicaster/zapp-react-native-utils": "12.0.0-alpha.3849101242",
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 = Number(value("seek_duration"));
298
+ const seekDuration = toNumberWithDefault(10, value("seek_duration"));
298
299
 
299
300
  const onRewindButtonPress = React.useCallback(() => {
300
301
  player?.rewind(seekDuration);
@@ -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,
@@ -33,6 +34,7 @@ import {
33
34
  ComponentAnimationType,
34
35
  } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
35
36
  import DockedLayout from "./DockedLayout";
37
+ import { isValidDate } from "../../Utils";
36
38
 
37
39
  type Dimensions = {
38
40
  width: number;
@@ -79,7 +81,7 @@ type LayoutProps = {
79
81
 
80
82
  const Styles = {
81
83
  container: { flex: 1 },
82
- tabletContainer: (isPortraitMode) => ({
84
+ tabletContainer: (isPortraitMode: boolean) => ({
83
85
  flex: 1,
84
86
  alignItems: "center",
85
87
  justifyContent: isPortraitMode ? "center" : "flex-start",
@@ -109,10 +111,10 @@ const Styles = {
109
111
  };
110
112
  },
111
113
  backgroundImageContainerImageStyle: (
112
- isTablet,
113
- docked,
114
- startComponentsAnimation,
115
- isActiveGesture
114
+ isTablet: boolean,
115
+ docked: boolean,
116
+ startComponentsAnimation: boolean,
117
+ isActiveGesture: boolean
116
118
  ) => ({
117
119
  borderRadius:
118
120
  (startComponentsAnimation && isActiveGesture) || docked
@@ -190,8 +192,31 @@ export default function DefaultLayout(props: LayoutProps) {
190
192
 
191
193
  let showFullControls = !controller?.isAd();
192
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
+
193
217
  if (isLiveContent) {
194
218
  const seekEnabled = Boolean(value("liveSeekingEnabled"));
219
+
195
220
  showFullControls = !!(controller?.hasSeekableDuration?.() && seekEnabled);
196
221
  }
197
222
 
@@ -221,12 +246,14 @@ export default function DefaultLayout(props: LayoutProps) {
221
246
 
222
247
  const rewind = rewindButton({
223
248
  isTablet,
224
- onPress: controller?.hasContentDuration?.() ? onRewindButtonPress : null,
249
+ onPress: controller?.hasSeekableDuration?.() ? onRewindButtonPress : null,
225
250
  });
226
251
 
227
252
  const forward = forwardButton({
228
253
  isTablet,
229
- onPress: controller?.hasContentDuration?.() ? onForwardButtonPress : null,
254
+ onPress: controller?.hasSeekableDuration?.()
255
+ ? onForwardButtonPress
256
+ : null,
230
257
  });
231
258
 
232
259
  const speed = speedButton({
@@ -255,7 +282,6 @@ export default function DefaultLayout(props: LayoutProps) {
255
282
  return [skipToStart, rewind, play, forward, skipToLive];
256
283
  }
257
284
 
258
- // Temporary empty button until we add sleep button. It will ensure the buttons will not break in their position
259
285
  return [speed, rewind, play, forward, sleep];
260
286
  }, [
261
287
  playerState,
@@ -276,15 +302,12 @@ export default function DefaultLayout(props: LayoutProps) {
276
302
 
277
303
  useEffect(() => {
278
304
  if (showCounter && sleepTimerDate !== 0) {
279
- // Setting the initial timeLeft based on sleepTimerDate
280
305
  setTimeLeft(sleepTimerDate - Date.now());
281
306
 
282
- // Setting up an interval to update the remaining time every second
283
307
  const intervalId = setInterval(() => {
284
308
  setTimeLeft(() => {
285
309
  const newTimeLeft = sleepTimerDate - Date.now();
286
310
 
287
- // If the new remaining time is less than or equal to 0, clear the interval and trigger the cancelSleepTimer function
288
311
  if (newTimeLeft <= 0) {
289
312
  clearInterval(intervalId);
290
313
 
@@ -292,36 +315,24 @@ export default function DefaultLayout(props: LayoutProps) {
292
315
 
293
316
  return 0;
294
317
  } else {
295
- // Otherwise, update the state with the new remaining time
296
318
  return newTimeLeft;
297
319
  }
298
320
  });
299
321
  }, 1000);
300
322
 
301
- // Clearing the interval when the component unmounts or dependencies changea
302
323
  return () => clearInterval(intervalId);
303
324
  } else {
304
- // Ensure the timeLeft state is set correctly if showCounter is false
305
325
  setTimeLeft(0);
306
326
  }
307
327
  }, [sleepTimerDate, showCounter, cancelSleepTimer]);
308
328
 
309
329
  const Separator = () => <View style={Styles.separator} />;
310
330
 
311
- const liveSeekingEnabled = value("liveSeekingEnabled");
312
-
313
- const startTime = entry.extensions.start_time; // October 28, 2024, at 14:27 UTC
314
- const endTime = entry.extensions.end_time; // October 28, 2024, at 16:27 UTC
315
-
316
- const needsToShowProgressBar =
317
- (isLiveContent && (liveSeekingEnabled || (startTime && endTime))) ||
318
- !isLiveContent;
319
-
320
331
  const defaultImageDimensions = React.useMemo(
321
332
  () =>
322
333
  defaultDimensions &&
323
334
  Styles.backgroundImageContainer(defaultDimensions, isTablet),
324
- [defaultDimensions]
335
+ [defaultDimensions, isTablet]
325
336
  );
326
337
 
327
338
  const { isActiveGesture, startComponentsAnimation } =
@@ -345,7 +356,7 @@ export default function DefaultLayout(props: LayoutProps) {
345
356
  </AnimationComponent>
346
357
  <AnimationComponent
347
358
  animationType={ComponentAnimationType.moveUpComponent}
348
- style={isTablet ? Styles.playerImageWrapper : null}
359
+ style={isTablet ? Styles.playerImageWrapper : undefined}
349
360
  >
350
361
  <AnimationComponent
351
362
  animationType={ComponentAnimationType.moveComponentHorizontal}
@@ -360,7 +371,7 @@ export default function DefaultLayout(props: LayoutProps) {
360
371
  }
361
372
  : null,
362
373
  }}
363
- style={isTablet ? Styles.alignItemsCenter : null}
374
+ style={isTablet ? Styles.alignItemsCenter : undefined}
364
375
  >
365
376
  <PlayerImageBackground
366
377
  entry={entry}
@@ -380,7 +391,7 @@ export default function DefaultLayout(props: LayoutProps) {
380
391
  <View
381
392
  style={[
382
393
  Styles.paddingHorizontal,
383
- isTablet ? Styles.tabletLayout : null,
394
+ isTablet ? Styles.tabletLayout : undefined,
384
395
  ]}
385
396
  >
386
397
  {!docked && (
@@ -405,9 +416,10 @@ export default function DefaultLayout(props: LayoutProps) {
405
416
  playerState={playerState}
406
417
  disableFullscreen={true}
407
418
  sliderStyle={2}
408
- startTime={startTime}
409
- endTime={endTime}
410
- isLive={isLiveContent}
419
+ startTimestamp={startTimestamp}
420
+ endTimestamp={endTimestamp}
421
+ isDateBasedLiveContent={isDateBasedLiveContent}
422
+ onSkipLive={onSkipLive}
411
423
  />
412
424
 
413
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[]; // Updated to type string[] as it holds hex values
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
- // Use provided colors for gradient and dominant color
74
- setGradientColors(colors.slice(0, 2)); // First 2 colors for gradient
75
- setDominantColor(colors[0]); // First color as dominant
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 style={[styles.container, { backgroundColor: dominantColor }]}>
135
+ <Animated.View
136
+ style={[
137
+ styles.container,
138
+ { backgroundColor: interpolatedBackgroundColor },
139
+ ]}
140
+ >
118
141
  <View style={styles.fullScreenOverlay} />
119
- <LinearGradient colors={gradientColors} style={styles.gradientOverlay} />
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
+ };
@@ -785,7 +785,6 @@ export default class VideoPlayer extends React.Component<
785
785
 
786
786
  render() {
787
787
  const {
788
- castAction,
789
788
  docked,
790
789
  entry,
791
790
  fullscreen,
@@ -795,8 +794,13 @@ export default class VideoPlayer extends React.Component<
795
794
  isTabletPortrait,
796
795
  muted,
797
796
  style,
797
+ castAction,
798
+ controller,
799
+ startComponentsAnimation,
798
800
  } = this.props;
799
801
 
802
+ const supportNativeCast = controller.supportNativeCast();
803
+
800
804
  const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
801
805
  this.state;
802
806
 
@@ -861,7 +865,11 @@ export default class VideoPlayer extends React.Component<
861
865
  ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
862
866
  : supportsNativeControls && !this.getPlayNextData();
863
867
 
864
- const shouldUseNativeControls = controls && !docked;
868
+ const shouldUseNativeControls =
869
+ controls &&
870
+ !startComponentsAnimation &&
871
+ !docked &&
872
+ !castAction?.state?.connected;
865
873
 
866
874
  platformSpecificProps = {
867
875
  ...platformSpecificProps,
@@ -1032,6 +1040,7 @@ export default class VideoPlayer extends React.Component<
1032
1040
  extraInfoText={castAction?.state?.friendlyStatus}
1033
1041
  controlsAlwaysVisible={castAction?.state?.connected}
1034
1042
  playNextData={this.getPlayNextData()}
1043
+ nativeControls={!!controls}
1035
1044
  />
1036
1045
  ) : null;
1037
1046
  };
@@ -1066,16 +1075,14 @@ export default class VideoPlayer extends React.Component<
1066
1075
  const renderMobilePlayer = () => {
1067
1076
  return isFullScreenAudioPlayer && isAudioItem ? (
1068
1077
  <View style={containerStyle}>
1069
- {!castAction?.state?.connected && (
1078
+ {(!castAction?.state?.connected || supportNativeCast) && (
1070
1079
  <this.props.PlayerComponent
1071
1080
  ref={this._assignRoot}
1072
1081
  {...nativeEvents}
1073
1082
  {...nativeProps}
1074
1083
  />
1075
1084
  )}
1076
- <AudioPlayerWrapper {...sharedWrapperViewProps}>
1077
- <></>
1078
- </AudioPlayerWrapper>
1085
+ <AudioPlayerWrapper {...sharedWrapperViewProps} />
1079
1086
  </View>
1080
1087
  ) : (
1081
1088
  <PlayerWrapper {...sharedWrapperViewProps}>
@@ -1119,7 +1126,7 @@ export default class VideoPlayer extends React.Component<
1119
1126
  />
1120
1127
  )}
1121
1128
 
1122
- {!castAction?.state?.connected && (
1129
+ {(!castAction?.state?.connected || supportNativeCast) && (
1123
1130
  <AnimationComponent
1124
1131
  animationType={ComponentAnimationType.player}
1125
1132
  additionalData={playerDimensions}