@applicaster/quick-brick-player 12.0.0-rc.5 → 12.0.0-rc.50

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.
@@ -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 = {
@@ -24,27 +23,30 @@ type LayoutProps = {
24
23
  isBuffering: boolean;
25
24
  };
26
25
  value: GetValue;
26
+ sleepTimerDate: number;
27
+ playbackSpeedName: string;
28
+ playbackSleepName: string;
27
29
  configuration: { [key: string]: any };
28
30
  onPlaybackButtonPress: () => void;
29
31
  onRewindButtonPress: () => void;
30
32
  onForwardButtonPress: () => void;
33
+ onSpeedButtonPress: () => void;
34
+ onSleepButtonPress: () => void;
31
35
  onCloseVideoModal: () => void;
36
+ cancelSleepTimer: () => void;
32
37
  onPlayerSeek: (targetTime: number) => void;
33
38
  onSkipStart: () => void;
34
39
  onSkipLive: () => void;
35
40
  maximiseVideoModal: () => void;
36
41
  dimensions: Dimensions;
42
+ defaultDimensions: Dimensions;
37
43
  playNextData: PlayNextData;
44
+ title: string | number;
45
+ summary: string | number;
38
46
  };
39
47
 
40
48
  export default function Layout(
41
49
  props: LayoutProps
42
50
  ): React.ReactElement<LayoutProps> {
43
- const { layoutState } = props;
44
-
45
- if (layoutState.docked) {
46
- return <DockedLayout {...props} />;
47
- }
48
-
49
51
  return <DefaultLayout {...props} />;
50
52
  }
@@ -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,6 +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 { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
40
+ import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
41
+ import {
42
+ AnimationComponent,
43
+ ComponentAnimationType,
44
+ } from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation";
39
45
 
40
46
  const RNPlayerManager = {
41
47
  QuickBrickPlayerPlugin: isApplePlatform()
@@ -55,6 +61,7 @@ const styles = StyleSheet.create({
55
61
  position: "absolute",
56
62
  zIndex: 1,
57
63
  },
64
+ playerSize: { width: "100%", height: "100%" },
58
65
  });
59
66
 
60
67
  const logger = createLogger({
@@ -87,7 +94,7 @@ export default class VideoPlayer extends React.Component<
87
94
  // TODO: Can be deleted, on controller logic
88
95
  paused: false,
89
96
  piped: false,
90
- rate: 1,
97
+ rate: 1.0,
91
98
  // TODO: Hack for analytics, must br removed
92
99
  resume: null,
93
100
 
@@ -368,6 +375,10 @@ export default class VideoPlayer extends React.Component<
368
375
  }
369
376
  };
370
377
 
378
+ setPlaybackRate = (rate = 1.0) => {
379
+ this.setState({ rate });
380
+ };
381
+
371
382
  getCurrentTime = () => {
372
383
  return this.state.currentTime;
373
384
  };
@@ -551,6 +562,26 @@ export default class VideoPlayer extends React.Component<
551
562
  this.props.listener?.onPlayerDetached?.(nativeEvent);
552
563
  };
553
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
+
554
585
  onPiPEnter = () => {
555
586
  this.setState({ piped: true });
556
587
  this.props.openPiP();
@@ -755,7 +786,6 @@ export default class VideoPlayer extends React.Component<
755
786
  render() {
756
787
  const {
757
788
  castAction,
758
- controls,
759
789
  docked,
760
790
  entry,
761
791
  fullscreen,
@@ -767,7 +797,8 @@ export default class VideoPlayer extends React.Component<
767
797
  style,
768
798
  } = this.props;
769
799
 
770
- const { audioTrackId, keyEvent, paused, seek, textTrackId } = this.state;
800
+ const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
801
+ this.state;
771
802
 
772
803
  const isAudioItem =
773
804
  entry?.content?.type?.includes?.("audio") ||
@@ -812,17 +843,31 @@ export default class VideoPlayer extends React.Component<
812
843
  const liveCatchUpEnabled =
813
844
  this.props.pluginConfiguration?.liveCatchUpEnabled;
814
845
 
815
- const hideNativeControls = isTV()
816
- ? { controls: !this.getPlayNextData() }
817
- : {};
846
+ // TODO: Get screen data more reliable way useCurrentScreenData
847
+ const screenData = getTargetScreenDataFromEntry(this.props.playableItem);
848
+
849
+ const isInlineTV = screenData?.ui_components?.length > 0 && isTV();
818
850
 
819
- const platformSpecificProps = isApplePlatform()
851
+ let platformSpecificProps: any = isApplePlatform()
820
852
  ? {
821
- ...hideNativeControls,
822
853
  resizeMode: nativeResizeMode,
823
854
  }
824
855
  : {};
825
856
 
857
+ const supportsNativeControls =
858
+ !!this.props.controller?.supportsNativeControls?.();
859
+
860
+ const controls = isAppleTV()
861
+ ? supportsNativeControls && !isInlineTV && !this.getPlayNextData()
862
+ : supportsNativeControls && !this.getPlayNextData();
863
+
864
+ const shouldUseNativeControls = controls && !docked;
865
+
866
+ platformSpecificProps = {
867
+ ...platformSpecificProps,
868
+ controls: shouldUseNativeControls,
869
+ };
870
+
826
871
  const pictureInPictureEnabled =
827
872
  this.props.pluginConfiguration?.pictureInPictureEnabled;
828
873
 
@@ -830,7 +875,6 @@ export default class VideoPlayer extends React.Component<
830
875
  entry, // Must be passed first in list
831
876
  ...platformSpecificProps,
832
877
  audioTrackId,
833
- controls,
834
878
  docked,
835
879
  enableAutoAudioTrackSelection,
836
880
  fullscreen, // TODO: Check fullscreen params not crash
@@ -839,6 +883,7 @@ export default class VideoPlayer extends React.Component<
839
883
  nowPlayingEnabled,
840
884
  paused,
841
885
  seek,
886
+ rate,
842
887
  textTrackId,
843
888
  liveSeekingEnabled,
844
889
  liveCatchUpEnabled,
@@ -884,22 +929,17 @@ export default class VideoPlayer extends React.Component<
884
929
  onVideoEnd: this.onVideoEnd, // complete
885
930
  onVideoError: this.onVideoError, // error
886
931
  onVideoProgress: this.onVideoProgress,
887
- onVideoFullscreenPlayerDidDismiss: this.unHandledEvent(
888
- "onVideoFullscreenPlayerDidPresent"
889
- ),
890
- onVideoFullscreenPlayerDidPresent: this.unHandledEvent(
891
- "onVideoFullscreenPlayerDidPresent"
892
- ),
893
- onVideoFullscreenPlayerWillDismiss: this.unHandledEvent(
894
- "onVideoFullscreenPlayerWillDismiss"
895
- ),
896
- onVideoFullscreenPlayerWillPresent: this.unHandledEvent(
897
- "onVideoFullscreenPlayerWillPresent"
898
- ),
932
+ onVideoFullscreenPlayerDidDismiss: this.onVideoFullscreenPlayerDidDismiss,
933
+ onVideoFullscreenPlayerDidPresent: this.onVideoFullscreenPlayerDidPresent,
934
+ onVideoFullscreenPlayerWillDismiss:
935
+ this.onVideoFullscreenPlayerWillDismiss,
936
+ onVideoFullscreenPlayerWillPresent:
937
+ this.onVideoFullscreenPlayerWillPresent,
899
938
  onVideoLoad: this.onVideoLoad,
900
939
  onVideoLoadStart: this.unHandledEvent("onVideoLoadStart"),
901
940
  onVideoBuffer: this.onVideoBuffer,
902
941
  onPlaybackStalled: this.onPlaybackStalled,
942
+ onPlayerClose: this.onPlayerClose,
903
943
  onPlayerAttached: this.onPlayerAttached,
904
944
  onPlayerDetached: this.onPlayerDetached,
905
945
  };
@@ -973,7 +1013,7 @@ export default class VideoPlayer extends React.Component<
973
1013
  !needToShowPlayNextOverlay &&
974
1014
  this.props.mode !== "PIP";
975
1015
 
976
- if (controls === true) {
1016
+ if (shouldUseNativeControls) {
977
1017
  return null;
978
1018
  }
979
1019
 
@@ -1005,10 +1045,12 @@ export default class VideoPlayer extends React.Component<
1005
1045
  inline,
1006
1046
  docked,
1007
1047
  isModal,
1048
+ pip: this.state.piped,
1008
1049
  layoutState: {
1009
1050
  inline,
1010
1051
  docked,
1011
1052
  isModal,
1053
+ pip: this.state.piped,
1012
1054
  },
1013
1055
  configuration: this.getPluginConfiguration(),
1014
1056
  fullscreen: fullscreen,
@@ -1031,22 +1073,7 @@ export default class VideoPlayer extends React.Component<
1031
1073
  {...nativeProps}
1032
1074
  />
1033
1075
  )}
1034
- <AudioPlayerWrapper {...sharedWrapperViewProps}>
1035
- <View>
1036
- {
1037
- <PlayNextOverlay
1038
- item={entry}
1039
- playerIsDocked={docked}
1040
- pluginConfiguration={this.getPluginConfiguration()}
1041
- playerId={this.props.playerId}
1042
- playNextData={this.getPlayNextData()}
1043
- setNextVideoPreloadThresholdPercentage={
1044
- this.props.setNextVideoPreloadThresholdPercentage
1045
- }
1046
- />
1047
- }
1048
- </View>
1049
- </AudioPlayerWrapper>
1076
+ <AudioPlayerWrapper {...sharedWrapperViewProps} />
1050
1077
  </View>
1051
1078
  ) : (
1052
1079
  <PlayerWrapper {...sharedWrapperViewProps}>
@@ -1061,11 +1088,24 @@ export default class VideoPlayer extends React.Component<
1061
1088
  <View style={styles.container}>
1062
1089
  <View style={[playerContainerStyles, playerDimensions]}>
1063
1090
  {isAudioItem && (
1064
- <AudioPlayer
1065
- style={playerDimensions}
1066
- audio_item={entry}
1067
- plugin_configuration={this.getPluginConfiguration()}
1068
- />
1091
+ <AnimationComponent
1092
+ animationType={ComponentAnimationType.player}
1093
+ additionalData={{
1094
+ ...playerDimensions,
1095
+ inlineAudioPlayer: true,
1096
+ }}
1097
+ style={getStyle(playerDimensions)}
1098
+ >
1099
+ <AudioPlayer
1100
+ style={
1101
+ isTV()
1102
+ ? getStyle(playerDimensions)
1103
+ : styles.playerSize
1104
+ }
1105
+ audio_item={entry}
1106
+ plugin_configuration={this.getPluginConfiguration()}
1107
+ />
1108
+ </AnimationComponent>
1069
1109
  )}
1070
1110
 
1071
1111
  {shouldRenderBackground && (
@@ -1078,16 +1118,27 @@ export default class VideoPlayer extends React.Component<
1078
1118
  )}
1079
1119
 
1080
1120
  {!castAction?.state?.connected && (
1081
- <this.props.PlayerComponent
1082
- ref={this._assignRoot}
1083
- {...nativeEvents}
1084
- {...nativeProps}
1085
- listener={this.props.listener}
1121
+ <AnimationComponent
1122
+ animationType={ComponentAnimationType.player}
1123
+ additionalData={playerDimensions}
1086
1124
  style={getStyle(playerDimensions)}
1087
- pluginConfiguration={this.getPluginConfiguration()}
1088
1125
  >
1089
- {this.childrenWithPlayNext()}
1090
- </this.props.PlayerComponent>
1126
+ <this.props.PlayerComponent
1127
+ ref={this._assignRoot}
1128
+ {...nativeEvents}
1129
+ {...nativeProps}
1130
+ listener={this.props.listener}
1131
+ style={
1132
+ isTV()
1133
+ ? getStyle(playerDimensions)
1134
+ : styles.playerSize
1135
+ }
1136
+ pluginConfiguration={this.getPluginConfiguration()}
1137
+ controller={this.props.controller}
1138
+ >
1139
+ {this.childrenWithPlayNext()}
1140
+ </this.props.PlayerComponent>
1141
+ </AnimationComponent>
1091
1142
  )}
1092
1143
  </View>
1093
1144
 
@@ -1121,6 +1172,7 @@ export default class VideoPlayer extends React.Component<
1121
1172
  listener={this.props.listener}
1122
1173
  style={this.takeParentStyle}
1123
1174
  pluginConfiguration={this.getPluginConfiguration()}
1175
+ controller={this.props.controller}
1124
1176
  >
1125
1177
  {this.childrenWithPlayNext()}
1126
1178
  </this.props.PlayerComponent>