@applicaster/quick-brick-player 12.0.0-alpha.7725319213 → 12.0.0-alpha.7921075302

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.
@@ -4,14 +4,17 @@ import * as React from "react";
4
4
  import { StyleSheet, View } from "react-native";
5
5
  import LinearGradient from "../LinearGradient";
6
6
  import { getDominantColor, getPalettes } from "../../../utils/utils";
7
+ import { useEffect } from "react";
7
8
 
8
9
  type MagicBGProps = {
9
10
  children: React.ReactNode;
10
11
  image: string;
12
+ fallbackUrl?: string;
11
13
  defaultColor: string;
14
+ colors: string[]; // Updated to type string[] as it holds hex values
12
15
  };
13
16
 
14
- const colors = {
17
+ const defaultColors = {
15
18
  overlay: "rgba(0, 0, 0, 0.35)",
16
19
  defaultGradientStart: "rgba(0, 0, 0, 0.25)",
17
20
  defaultGradientEnd: "rgba(0, 0, 0, 0)",
@@ -23,7 +26,7 @@ const styles = StyleSheet.create({
23
26
  },
24
27
  fullScreenOverlay: {
25
28
  ...StyleSheet.absoluteFillObject,
26
- backgroundColor: colors.overlay,
29
+ backgroundColor: defaultColors.overlay,
27
30
  },
28
31
  gradientOverlay: {
29
32
  position: "absolute",
@@ -34,47 +37,81 @@ const styles = StyleSheet.create({
34
37
  },
35
38
  });
36
39
 
40
+ const fetchPaletteAndDominantColor = async (imageUrl: string) => {
41
+ const palette = await getPalettes(imageUrl);
42
+
43
+ const colors = palette.map(
44
+ (color: { r: number; g: number; b: number }) =>
45
+ `rgb(${color.r}, ${color.g}, ${color.b})`
46
+ );
47
+
48
+ const dominant = await getDominantColor(imageUrl);
49
+ const dominantColor = `rgb(${dominant.r}, ${dominant.g}, ${dominant.b})`;
50
+
51
+ return { gradientColors: colors.slice(0, 2), dominantColor };
52
+ };
53
+
37
54
  export const MagicBG: React.FC<MagicBGProps> = ({
38
55
  children,
39
56
  image,
57
+ fallbackUrl = "",
58
+ colors = [],
40
59
  defaultColor,
41
60
  }) => {
42
61
  const [dominantColor, setDominantColor] =
43
62
  React.useState<string>(defaultColor);
44
63
 
45
64
  const [gradientColors, setGradientColors] = React.useState<string[]>([
46
- colors.defaultGradientStart,
47
- colors.defaultGradientEnd,
65
+ defaultColors.defaultGradientStart,
66
+ defaultColors.defaultGradientEnd,
48
67
  ]);
49
68
 
50
- React.useEffect(() => {
69
+ useEffect(() => {
51
70
  const fetchColors = async () => {
52
- if (image) {
71
+ // Check if colors are provided and not empty
72
+ 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
76
+ } else if (image) {
77
+ // If no colors, try fetching from image
53
78
  try {
54
- const palette = await getPalettes(image);
55
-
56
- const colors = palette.map(
57
- (color: { r: number; g: number; b: number }) =>
58
- `rgb(${color.r}, ${color.g}, ${color.b})`
59
- );
60
-
61
- setGradientColors(colors.slice(0, 2));
79
+ const { gradientColors, dominantColor } =
80
+ await fetchPaletteAndDominantColor(image);
62
81
 
63
- const dominant = await getDominantColor(image);
64
- setDominantColor(`rgb(${dominant.r}, ${dominant.g}, ${dominant.b})`);
82
+ setGradientColors(gradientColors);
83
+ setDominantColor(dominantColor);
65
84
  } catch (error) {
66
- setGradientColors([
67
- colors.defaultGradientStart,
68
- colors.defaultGradientEnd,
69
- ]);
85
+ // If image fetch fails, try fallback URL
86
+ try {
87
+ const { gradientColors, dominantColor } =
88
+ await fetchPaletteAndDominantColor(fallbackUrl);
70
89
 
71
- setDominantColor(defaultColor);
90
+ setGradientColors(gradientColors);
91
+ setDominantColor(dominantColor);
92
+ } catch {
93
+ // If everything fails, use default color
94
+ setGradientColors([
95
+ defaultColors.defaultGradientStart,
96
+ defaultColors.defaultGradientEnd,
97
+ ]);
98
+
99
+ setDominantColor(defaultColor);
100
+ }
72
101
  }
102
+ } else {
103
+ // If no image or colors, use default color
104
+ setGradientColors([
105
+ defaultColors.defaultGradientStart,
106
+ defaultColors.defaultGradientEnd,
107
+ ]);
108
+
109
+ setDominantColor(defaultColor);
73
110
  }
74
111
  };
75
112
 
76
113
  fetchColors();
77
- }, [image, defaultColor]);
114
+ }, []);
78
115
 
79
116
  return (
80
117
  <View style={[styles.container, { backgroundColor: dominantColor }]}>
@@ -0,0 +1,33 @@
1
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
2
+ import { parseJsonIfNeeded } from "@applicaster/zapp-react-native-utils/functionUtils";
3
+
4
+ export const NAMESPACE = "audio-player";
5
+
6
+ export async function loadItemsFromStorage(key: string) {
7
+ const storedItems = await localStorage.getItem(key, NAMESPACE);
8
+
9
+ return parseJsonIfNeeded(storedItems) || null;
10
+ }
11
+
12
+ export const hasDatePassed = (timestamp: number) => {
13
+ // Get the current date and time
14
+ const currentDate = new Date();
15
+
16
+ // Compare the current date's timestamp with the given timestamp
17
+ return currentDate.getTime() > timestamp;
18
+ };
19
+
20
+ export const formatSpeed = (value: number) => {
21
+ let formattedValue = value.toString();
22
+
23
+ // If the value ends with ".0", remove it
24
+ if (formattedValue.endsWith(".0")) {
25
+ formattedValue = formattedValue.slice(0, -2);
26
+ }
27
+
28
+ // Replace "." with "_"
29
+ formattedValue = formattedValue.replace(".", "_");
30
+
31
+ // Return the formatted string with "speed_" prefix
32
+ return `speed_${formattedValue}`;
33
+ };
@@ -1,3 +1,5 @@
1
+ import queryString from "query-string";
2
+
1
3
  export const toTypeString = (obj) => {
2
4
  switch (typeof obj) {
3
5
  case "object":
@@ -19,3 +21,24 @@ export const stringsOnlyObject = (obj) => {
19
21
 
20
22
  return strObj;
21
23
  };
24
+
25
+ export const getLiveUrl = (url: string) => {
26
+ // Use the replace method with a regular expression to replace all instances of subClass with livePage
27
+ return url.replace(new RegExp("subClass", "g"), "livePage");
28
+ };
29
+
30
+ export const addQueryParam = (
31
+ baseUrl: string,
32
+ paramName: string,
33
+ paramValue: string | number
34
+ ) => {
35
+ const [urlWithoutQuery, query] = baseUrl.split("?");
36
+
37
+ const parsedQuery = queryString.parse(query);
38
+
39
+ parsedQuery[paramName] = paramValue.toString();
40
+
41
+ const updatedQueryString = queryString.stringify(parsedQuery);
42
+
43
+ return `${urlWithoutQuery}?${updatedQueryString}`;
44
+ };
@@ -1,3 +1 @@
1
- export * from "./AssetsHelper";
2
-
3
1
  export * from "./Utils";
@@ -36,10 +36,12 @@ 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
- import {
40
- getTargetScreenDataFromEntry
41
- } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
39
+ import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
42
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";
43
45
 
44
46
  const RNPlayerManager = {
45
47
  QuickBrickPlayerPlugin: isApplePlatform()
@@ -59,6 +61,7 @@ const styles = StyleSheet.create({
59
61
  position: "absolute",
60
62
  zIndex: 1,
61
63
  },
64
+ playerSize: { width: "100%", height: "100%" },
62
65
  });
63
66
 
64
67
  const logger = createLogger({
@@ -91,7 +94,7 @@ export default class VideoPlayer extends React.Component<
91
94
  // TODO: Can be deleted, on controller logic
92
95
  paused: false,
93
96
  piped: false,
94
- rate: 1,
97
+ rate: 1.0,
95
98
  // TODO: Hack for analytics, must br removed
96
99
  resume: null,
97
100
 
@@ -372,6 +375,10 @@ export default class VideoPlayer extends React.Component<
372
375
  }
373
376
  };
374
377
 
378
+ setPlaybackRate = (rate = 1.0) => {
379
+ this.setState({ rate });
380
+ };
381
+
375
382
  getCurrentTime = () => {
376
383
  return this.state.currentTime;
377
384
  };
@@ -555,6 +562,26 @@ export default class VideoPlayer extends React.Component<
555
562
  this.props.listener?.onPlayerDetached?.(nativeEvent);
556
563
  };
557
564
 
565
+ onVideoFullscreenPlayerDidDismiss = () => {
566
+ this.props.listener?.onVideoFullscreenPlayerDidDismiss?.();
567
+ };
568
+
569
+ onVideoFullscreenPlayerDidPresent = () => {
570
+ this.props.listener?.onVideoFullscreenPlayerDidPresent?.();
571
+ };
572
+
573
+ onVideoFullscreenPlayerWillDismiss = () => {
574
+ this.props.listener?.onVideoFullscreenPlayerWillDismiss?.();
575
+ };
576
+
577
+ onVideoFullscreenPlayerWillPresent = () => {
578
+ this.props.listener?.onVideoFullscreenPlayerWillPresent?.();
579
+ };
580
+
581
+ onPlayerClose = () => {
582
+ this.props.listener?.onPlayerClose?.();
583
+ };
584
+
558
585
  onPiPEnter = () => {
559
586
  this.setState({ piped: true });
560
587
  this.props.openPiP();
@@ -758,7 +785,6 @@ export default class VideoPlayer extends React.Component<
758
785
 
759
786
  render() {
760
787
  const {
761
- castAction,
762
788
  docked,
763
789
  entry,
764
790
  fullscreen,
@@ -768,9 +794,14 @@ export default class VideoPlayer extends React.Component<
768
794
  isTabletPortrait,
769
795
  muted,
770
796
  style,
797
+ castAction,
798
+ controller,
771
799
  } = this.props;
772
800
 
773
- const { audioTrackId, keyEvent, paused, seek, textTrackId } = this.state;
801
+ const supportNativeCast = controller.supportNativeCast();
802
+
803
+ const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
804
+ this.state;
774
805
 
775
806
  const isAudioItem =
776
807
  entry?.content?.type?.includes?.("audio") ||
@@ -822,26 +853,25 @@ export default class VideoPlayer extends React.Component<
822
853
 
823
854
  let platformSpecificProps: any = isApplePlatform()
824
855
  ? {
825
- resizeMode: nativeResizeMode,
826
- } : {};
856
+ resizeMode: nativeResizeMode,
857
+ }
858
+ : {};
827
859
 
828
- const supportsNativeControls = !!this.props.controller?.supportsNativeControls?.();
860
+ const supportsNativeControls =
861
+ !!this.props.controller?.supportsNativeControls?.();
829
862
 
830
863
  const controls = isAppleTV()
831
- ? supportsNativeControls && isInlineTV && !this.getPlayNextData()
864
+ ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
832
865
  : supportsNativeControls && !this.getPlayNextData();
833
866
 
867
+ const shouldUseNativeControls =
868
+ controls && !docked && !castAction?.state?.connected;
869
+
834
870
  platformSpecificProps = {
835
871
  ...platformSpecificProps,
836
- controls
872
+ controls: shouldUseNativeControls,
837
873
  };
838
874
 
839
- console.log("Anton Player render2 ", {
840
- platformSpecificProps,
841
- isNotInlineTv: !isInlineTV,
842
- hasNoPlayNextData: !this.getPlayNextData()
843
- });
844
-
845
875
  const pictureInPictureEnabled =
846
876
  this.props.pluginConfiguration?.pictureInPictureEnabled;
847
877
 
@@ -857,6 +887,7 @@ export default class VideoPlayer extends React.Component<
857
887
  nowPlayingEnabled,
858
888
  paused,
859
889
  seek,
890
+ rate,
860
891
  textTrackId,
861
892
  liveSeekingEnabled,
862
893
  liveCatchUpEnabled,
@@ -902,22 +933,17 @@ export default class VideoPlayer extends React.Component<
902
933
  onVideoEnd: this.onVideoEnd, // complete
903
934
  onVideoError: this.onVideoError, // error
904
935
  onVideoProgress: this.onVideoProgress,
905
- onVideoFullscreenPlayerDidDismiss: this.unHandledEvent(
906
- "onVideoFullscreenPlayerDidPresent"
907
- ),
908
- onVideoFullscreenPlayerDidPresent: this.unHandledEvent(
909
- "onVideoFullscreenPlayerDidPresent"
910
- ),
911
- onVideoFullscreenPlayerWillDismiss: this.unHandledEvent(
912
- "onVideoFullscreenPlayerWillDismiss"
913
- ),
914
- onVideoFullscreenPlayerWillPresent: this.unHandledEvent(
915
- "onVideoFullscreenPlayerWillPresent"
916
- ),
936
+ onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
937
+ onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
938
+ onVideoFullscreenPlayerWillDismiss:
939
+ this.onVideoFullscreenPlayerWillDismiss,
940
+ onVideoFullscreenPlayerWillPresent:
941
+ this.onVideoFullscreenPlayerWillPresent,
917
942
  onVideoLoad: this.onVideoLoad,
918
943
  onVideoLoadStart: this.unHandledEvent("onVideoLoadStart"),
919
944
  onVideoBuffer: this.onVideoBuffer,
920
945
  onPlaybackStalled: this.onPlaybackStalled,
946
+ onPlayerClose: this.onPlayerClose,
921
947
  onPlayerAttached: this.onPlayerAttached,
922
948
  onPlayerDetached: this.onPlayerDetached,
923
949
  };
@@ -976,8 +1002,6 @@ export default class VideoPlayer extends React.Component<
976
1002
  ? styles.playerContainerTransparent
977
1003
  : styles.playerContainerBlack;
978
1004
 
979
- console.log("Anton Player render", {screenData, props: this.props, nativeProps});
980
-
981
1005
  const isInline = () => {
982
1006
  if (isTV()) {
983
1007
  return inline;
@@ -993,7 +1017,7 @@ export default class VideoPlayer extends React.Component<
993
1017
  !needToShowPlayNextOverlay &&
994
1018
  this.props.mode !== "PIP";
995
1019
 
996
- if (controls === true) {
1020
+ if (shouldUseNativeControls) {
997
1021
  return null;
998
1022
  }
999
1023
 
@@ -1046,29 +1070,14 @@ export default class VideoPlayer extends React.Component<
1046
1070
  const renderMobilePlayer = () => {
1047
1071
  return isFullScreenAudioPlayer && isAudioItem ? (
1048
1072
  <View style={containerStyle}>
1049
- {!castAction?.state?.connected && (
1073
+ {(!castAction?.state?.connected || supportNativeCast) && (
1050
1074
  <this.props.PlayerComponent
1051
1075
  ref={this._assignRoot}
1052
1076
  {...nativeEvents}
1053
1077
  {...nativeProps}
1054
1078
  />
1055
1079
  )}
1056
- <AudioPlayerWrapper {...sharedWrapperViewProps}>
1057
- <View>
1058
- {
1059
- <PlayNextOverlay
1060
- item={entry}
1061
- playerIsDocked={docked}
1062
- pluginConfiguration={this.getPluginConfiguration()}
1063
- playerId={this.props.playerId}
1064
- playNextData={this.getPlayNextData()}
1065
- setNextVideoPreloadThresholdPercentage={
1066
- this.props.setNextVideoPreloadThresholdPercentage
1067
- }
1068
- />
1069
- }
1070
- </View>
1071
- </AudioPlayerWrapper>
1080
+ <AudioPlayerWrapper {...sharedWrapperViewProps} />
1072
1081
  </View>
1073
1082
  ) : (
1074
1083
  <PlayerWrapper {...sharedWrapperViewProps}>
@@ -1083,11 +1092,24 @@ export default class VideoPlayer extends React.Component<
1083
1092
  <View style={styles.container}>
1084
1093
  <View style={[playerContainerStyles, playerDimensions]}>
1085
1094
  {isAudioItem && (
1086
- <AudioPlayer
1087
- style={playerDimensions}
1088
- audio_item={entry}
1089
- plugin_configuration={this.getPluginConfiguration()}
1090
- />
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>
1091
1113
  )}
1092
1114
 
1093
1115
  {shouldRenderBackground && (
@@ -1099,18 +1121,28 @@ export default class VideoPlayer extends React.Component<
1099
1121
  />
1100
1122
  )}
1101
1123
 
1102
- {!castAction?.state?.connected && (
1103
- <this.props.PlayerComponent
1104
- ref={this._assignRoot}
1105
- {...nativeEvents}
1106
- {...nativeProps}
1107
- listener={this.props.listener}
1124
+ {(!castAction?.state?.connected || supportNativeCast) && (
1125
+ <AnimationComponent
1126
+ animationType={ComponentAnimationType.player}
1127
+ additionalData={playerDimensions}
1108
1128
  style={getStyle(playerDimensions)}
1109
- pluginConfiguration={this.getPluginConfiguration()}
1110
- controller={this.props.controller}
1111
1129
  >
1112
- {this.childrenWithPlayNext()}
1113
- </this.props.PlayerComponent>
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>
1114
1146
  )}
1115
1147
  </View>
1116
1148