@applicaster/quick-brick-player 13.0.0-rc.14 → 13.0.0-rc.141

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.
Files changed (49) hide show
  1. package/package.json +27 -14
  2. package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
  3. package/src/Player/AudioLayer/AudioDescription.tsx +107 -68
  4. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +142 -295
  5. package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +45 -0
  6. package/src/Player/AudioLayer/Layout/Controls/index.tsx +291 -0
  7. package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +9 -27
  8. package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
  9. package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +77 -81
  10. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +222 -0
  11. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +82 -0
  12. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +16 -0
  13. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +1 -0
  14. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +99 -0
  15. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +112 -0
  16. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +36 -0
  17. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +212 -0
  18. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +215 -0
  19. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +128 -0
  20. package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
  21. package/src/Player/AudioLayer/Layout/const.ts +26 -0
  22. package/src/Player/AudioLayer/Layout/debug.ts +6 -0
  23. package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
  24. package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
  25. package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
  26. package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
  27. package/src/Player/AudioLayer/Layout/index.tsx +21 -48
  28. package/src/Player/AudioLayer/Layout/types.ts +7 -0
  29. package/src/Player/AudioLayer/Layout/utils.ts +7 -0
  30. package/src/Player/AudioLayer/SleepTimerManager.ts +130 -0
  31. package/src/Player/AudioLayer/SpeedManager.ts +52 -0
  32. package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +66 -0
  33. package/src/Player/AudioLayer/components/SleepTimerModalHeader/index.ts +1 -0
  34. package/src/Player/AudioLayer/useSleepTimerModal.ts +109 -0
  35. package/src/Player/AudioLayer/utils.ts +27 -0
  36. package/src/Player/Const/sleepTimerOptions.ts +41 -0
  37. package/src/Player/Const/speedOptions.ts +4 -0
  38. package/src/Player/Utils/Utils.ts +0 -5
  39. package/src/Player/Utils/index.tsx +123 -0
  40. package/src/Player/hooks/useIsCasting.tsx +57 -0
  41. package/src/Player/index.tsx +111 -52
  42. package/src/QuickBrickPlayer.tsx +3 -0
  43. package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
  44. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
  45. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
  46. package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
  47. package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
  48. package/src/Player/Helpers/VideoResizeMode.ts +0 -7
  49. package/src/utils/utils.ts +0 -25
@@ -1,11 +1,6 @@
1
1
  import queryString from "query-string";
2
2
  import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
3
3
 
4
- export const getLiveUrl = (url: string) => {
5
- // Use the replace method with a regular expression to replace all instances of subClass with livePage
6
- return url.replace(new RegExp("subClass", "g"), "livePage");
7
- };
8
-
9
4
  export const addQueryParam = (
10
5
  baseUrl: string,
11
6
  paramName: string,
@@ -1 +1,124 @@
1
+ import { platformSelect } from "@applicaster/zapp-react-native-utils/reactUtils";
2
+
1
3
  export * from "./Utils";
4
+
5
+ export const getBottomSheetModalIconProps = (theme) => ({
6
+ height: theme["audio_modal_bottom_sheet_item_icon_height"],
7
+ width: theme["audio_modal_bottom_sheet_item_icon_width"],
8
+ marginBottom: theme["audio_modal_bottom_sheet_item_icon_margin_bottom"],
9
+ marginLeft: theme["audio_modal_bottom_sheet_item_icon_margin_left"],
10
+ marginRight: theme["audio_modal_bottom_sheet_item_icon_margin_right"],
11
+ marginTop: theme["audio_modal_bottom_sheet_item_icon_margin_top"],
12
+ flavour: theme["modal_bottom_sheet_item_icon_flavour"],
13
+ });
14
+
15
+ export const getBottomSheetModalLabelProps = (theme, width: number) => {
16
+ const {
17
+ audio_modal_bottom_sheet_item_label_android_letter_spacing,
18
+ audio_modal_bottom_sheet_item_label_ios_letter_spacing,
19
+ audio_modal_bottom_sheet_item_label_family_ios_font_selector,
20
+ audio_modal_bottom_sheet_item_label_family_android_font_selector,
21
+ audio_modal_bottom_sheet_item_label_focus_font_color,
22
+ audio_modal_bottom_sheet_item_label_font_color,
23
+ audio_modal_bottom_sheet_item_label_selected_font_color,
24
+ audio_modal_bottom_sheet_item_label_hover_selected_font_color,
25
+ audio_modal_bottom_sheet_item_label_font_size,
26
+ audio_modal_bottom_sheet_item_label_line_height,
27
+ audio_modal_bottom_sheet_item_label_margin_bottom,
28
+ audio_modal_bottom_sheet_item_label_margin_top,
29
+ audio_modal_bottom_sheet_item_label_margin_left,
30
+ audio_modal_bottom_sheet_item_label_margin_right,
31
+ audio_modal_bottom_sheet_item_label_transform,
32
+ audio_modal_bottom_sheet_item_icon_width,
33
+ audio_modal_bottom_sheet_item_icon_margin_left,
34
+ audio_modal_bottom_sheet_item_icon_margin_right,
35
+ audio_modal_bottom_sheet_item_margin_left,
36
+ audio_modal_bottom_sheet_item_margin_right,
37
+ audio_modal_bottom_sheet_item_padding_left,
38
+ audio_modal_bottom_sheet_item_padding_right,
39
+ } = theme;
40
+
41
+ const maxWidth =
42
+ width -
43
+ (audio_modal_bottom_sheet_item_icon_width +
44
+ audio_modal_bottom_sheet_item_icon_margin_left +
45
+ audio_modal_bottom_sheet_item_icon_margin_right +
46
+ audio_modal_bottom_sheet_item_margin_left +
47
+ audio_modal_bottom_sheet_item_margin_right +
48
+ audio_modal_bottom_sheet_item_padding_left +
49
+ audio_modal_bottom_sheet_item_padding_right);
50
+
51
+ return {
52
+ fontFamily: platformSelect({
53
+ ios: audio_modal_bottom_sheet_item_label_family_ios_font_selector,
54
+ android: audio_modal_bottom_sheet_item_label_family_android_font_selector,
55
+ }),
56
+ letterSpacing: platformSelect({
57
+ ios: audio_modal_bottom_sheet_item_label_ios_letter_spacing,
58
+ android: audio_modal_bottom_sheet_item_label_android_letter_spacing,
59
+ }),
60
+ fontSize: audio_modal_bottom_sheet_item_label_font_size,
61
+ color: audio_modal_bottom_sheet_item_label_font_color,
62
+ focusColor: audio_modal_bottom_sheet_item_label_focus_font_color,
63
+ hoverSelectedColor:
64
+ audio_modal_bottom_sheet_item_label_hover_selected_font_color,
65
+ selectedColor: audio_modal_bottom_sheet_item_label_selected_font_color,
66
+ lineHeight: audio_modal_bottom_sheet_item_label_line_height,
67
+ marginBottom: audio_modal_bottom_sheet_item_label_margin_bottom,
68
+ marginTop: audio_modal_bottom_sheet_item_label_margin_top,
69
+ marginLeft: audio_modal_bottom_sheet_item_label_margin_left,
70
+ marginRight: audio_modal_bottom_sheet_item_label_margin_right,
71
+ transform: audio_modal_bottom_sheet_item_label_transform,
72
+ maxWidth,
73
+ };
74
+ };
75
+
76
+ export const getBottomSheetModalItemProps = (theme, width: number) => {
77
+ const {
78
+ audio_modal_bottom_sheet_item_background_color,
79
+ audio_modal_bottom_sheet_item_focus_background_color,
80
+ audio_modal_bottom_sheet_item_selected_background_color,
81
+ audio_modal_bottom_sheet_item_focused_selected_background_color,
82
+ audio_modal_bottom_sheet_item_corner_radius,
83
+ audio_modal_bottom_sheet_item_margin_bottom,
84
+ audio_modal_bottom_sheet_item_margin_left,
85
+ audio_modal_bottom_sheet_item_margin_right,
86
+ audio_modal_bottom_sheet_item_margin_top,
87
+ audio_modal_bottom_sheet_item_padding_bottom,
88
+ audio_modal_bottom_sheet_item_padding_left,
89
+ audio_modal_bottom_sheet_item_padding_right,
90
+ audio_modal_bottom_sheet_item_padding_top,
91
+ } = theme;
92
+
93
+ return {
94
+ backgroundColor: audio_modal_bottom_sheet_item_background_color,
95
+ focusedBackgroundColor:
96
+ audio_modal_bottom_sheet_item_focus_background_color,
97
+ selectedBackgroundColor:
98
+ audio_modal_bottom_sheet_item_selected_background_color,
99
+ focusedSelectedBackgroundColor:
100
+ audio_modal_bottom_sheet_item_focused_selected_background_color,
101
+ borderRadius: audio_modal_bottom_sheet_item_corner_radius,
102
+ marginBottom: audio_modal_bottom_sheet_item_margin_bottom,
103
+ marginTop: audio_modal_bottom_sheet_item_margin_top,
104
+ marginLeft: audio_modal_bottom_sheet_item_margin_left,
105
+ marginRight: audio_modal_bottom_sheet_item_margin_right,
106
+ paddingTop: audio_modal_bottom_sheet_item_padding_top,
107
+ paddingBottom: audio_modal_bottom_sheet_item_padding_bottom,
108
+ paddingRight: audio_modal_bottom_sheet_item_padding_right,
109
+ paddingLeft: audio_modal_bottom_sheet_item_padding_left,
110
+ maxWidth: width,
111
+ };
112
+ };
113
+
114
+ export const getBottomSheetModalSelectedItemIcon = (theme) =>
115
+ theme["audio_modal_bottom_sheet_item_selected_icon"] || null;
116
+
117
+ export const getBottomSheetModalDefaultItemIcon = (theme) =>
118
+ theme["audio_modal_bottom_sheet_item_default_icon"] || null;
119
+
120
+ export const selectSleepTitle = (configuration) =>
121
+ configuration.playback_sleep_title;
122
+
123
+ export const selectSleepOffLabel = (configuration) =>
124
+ configuration.playback_sleep_off_label;
@@ -0,0 +1,57 @@
1
+ import React from "react";
2
+ import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
3
+ import { useAppState } from "@applicaster/zapp-react-native-utils/reactHooks/app";
4
+ import { isApplePlatform } from "@applicaster/zapp-react-native-utils/reactUtils";
5
+
6
+ const CHROMECAST_IDENTIFIER = "quick-brick-chromecast-action";
7
+
8
+ const fakeEntry: any = {
9
+ title: "Chromecast use is casting fake entry",
10
+ id: "quick-brick-use-is-casting-fake-entry",
11
+ };
12
+
13
+ /**
14
+ * Returns the cast action state connection status, does not update when app is in background on Apple platforms
15
+ * On other platforms, it continues to check the cast action state even when the app is in background
16
+ */
17
+ export const useIsCasting = () => {
18
+ const actionContext = useActions(CHROMECAST_IDENTIFIER);
19
+ const appState = useAppState();
20
+ const isAppInForeground = appState === "active";
21
+ const shouldOnlyUpdateInForeground = isApplePlatform();
22
+
23
+ const [castActionState, setCastActionState] = React.useState(
24
+ !actionContext ? null : actionContext.initialEntryState(fakeEntry)
25
+ );
26
+
27
+ React.useEffect(() => {
28
+ if (!shouldOnlyUpdateInForeground || isAppInForeground) {
29
+ if (actionContext && castActionState === null) {
30
+ setCastActionState(actionContext.initialEntryState(fakeEntry));
31
+ }
32
+ }
33
+ }, [
34
+ actionContext,
35
+ setCastActionState,
36
+ isAppInForeground,
37
+ shouldOnlyUpdateInForeground,
38
+ ]);
39
+
40
+ React.useEffect(() => {
41
+ if (typeof actionContext?.addListener === "function") {
42
+ return actionContext?.addListener(String(fakeEntry.id), (state) => {
43
+ // Only check foreground state on Apple platforms
44
+ if (!shouldOnlyUpdateInForeground || isAppInForeground) {
45
+ setCastActionState(state);
46
+ }
47
+ });
48
+ }
49
+ }, [
50
+ setCastActionState,
51
+ actionContext,
52
+ isAppInForeground,
53
+ shouldOnlyUpdateInForeground,
54
+ ]);
55
+
56
+ return !!castActionState?.connected;
57
+ };
@@ -4,6 +4,8 @@
4
4
  import React from "react";
5
5
  import * as R from "ramda";
6
6
 
7
+ import { flatten } from "@applicaster/zapp-react-native-utils/utils";
8
+
7
9
  import { findNodeHandle, StyleSheet, View } from "react-native";
8
10
  import TransportControlsMobile from "@applicaster/quick-brick-mobile-transport-controls";
9
11
  import TransportControlsTV from "@applicaster/quick-brick-tv-transport-controls";
@@ -31,7 +33,6 @@ import { playerManager } from "@applicaster/zapp-react-native-utils/appUtils";
31
33
  import { getAllAccessibilityProps } from "@applicaster/zapp-react-native-utils/configurationUtils";
32
34
  import { PlayNextData } from "@applicaster/zapp-react-native-ui-components/Components/PlayerContainer/PlayerContainer";
33
35
  import { getTargetScreenDataFromEntry } from "@applicaster/zapp-react-native-utils/reactHooks/screen/useTargetScreenData";
34
- import { isAppleTV } from "@applicaster/zapp-react-native-ui-components/Helpers/Platform";
35
36
  import {
36
37
  AnimationComponent,
37
38
  ComponentAnimationType,
@@ -40,6 +41,10 @@ import { PlayerAnalyticsManager } from "@applicaster/zapp-react-native-utils/ana
40
41
  import { PlayerAnalyticsTrackerI } from "@applicaster/zapp-react-native-utils/analyticsUtils/playerAnalyticsTracker";
41
42
 
42
43
  import { RNPlayerManager } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/nativePlayerManager";
44
+ import {
45
+ isAudioItem as isAudioItemUtil,
46
+ isInlineTV as isInlineTVUtil,
47
+ } from "@applicaster/zapp-react-native-utils/playerUtils";
43
48
 
44
49
  const styles = StyleSheet.create({
45
50
  container: { flex: 1 },
@@ -50,6 +55,7 @@ const styles = StyleSheet.create({
50
55
  position: "absolute",
51
56
  zIndex: 1,
52
57
  },
58
+ audioPlayerSize: { width: "100%", height: "100%" },
53
59
  playerSize: { width: "100%", height: "100%" },
54
60
  });
55
61
 
@@ -58,6 +64,10 @@ const logger = createLogger({
58
64
  subsystem: Subsystem,
59
65
  });
60
66
 
67
+ const isTvOS = isTvOSPlatform();
68
+
69
+ const AUDIO_PLAYER_NATIVE_ID = "audio-player-view";
70
+
61
71
  export default class VideoPlayer extends React.Component<
62
72
  QuickBrickPlayer.PlayerProps,
63
73
  QuickBrickPlayer.NativePlayerState
@@ -74,6 +84,7 @@ export default class VideoPlayer extends React.Component<
74
84
  state: QuickBrickPlayer.NativePlayerState = {
75
85
  audioTrackId: null,
76
86
  textTrackId: null,
87
+ isCasting: this.props.isCasting,
77
88
 
78
89
  // TODO: Can be deleted, on controller logic
79
90
  isAd: false,
@@ -92,6 +103,8 @@ export default class VideoPlayer extends React.Component<
92
103
  // Player state
93
104
  currentTime: 0,
94
105
  duration: 0,
106
+
107
+ nativePlayerIsReady: false,
95
108
  };
96
109
 
97
110
  private _tracker: PlayerAnalyticsTrackerI;
@@ -487,6 +500,9 @@ export default class VideoPlayer extends React.Component<
487
500
 
488
501
  onVideoFullscreenPlayerDidPresent = () => {
489
502
  this.props.listener?.onVideoFullscreenPlayerDidPresent?.();
503
+
504
+ // we have to have a signal that player is ready, in order to show audio_player(for example)
505
+ this.setState({ nativePlayerIsReady: true });
490
506
  };
491
507
 
492
508
  onVideoFullscreenPlayerWillDismiss = () => {
@@ -672,32 +688,57 @@ export default class VideoPlayer extends React.Component<
672
688
  }
673
689
  };
674
690
 
675
- childrenWithPlayNext = () => {
676
- if (!isTvOSPlatform() || !this.getPlayNextData()) {
677
- return this.props.children;
691
+ childrenWithExtensions = () => {
692
+ const { docked, entry, children } = this.props;
693
+
694
+ if (!isTvOS) {
695
+ return children;
678
696
  }
679
697
 
680
- // tvos only
681
- const { docked, entry } = this.props;
682
-
683
- const children = R.pathOr([], "children", this.props);
684
-
685
- return [
686
- ...children,
687
- <PlayNextOverlay
688
- key="play-next-overlay"
689
- item={entry}
690
- playerIsDocked={docked}
691
- pluginConfiguration={this.getPluginConfiguration()}
692
- playerId={this.props.playerId}
693
- playNextData={this.getPlayNextData()}
694
- setNextVideoPreloadThresholdPercentage={
695
- this.props.setNextVideoPreloadThresholdPercentage
696
- }
697
- />,
698
- ];
698
+ const output = [];
699
+
700
+ // audio-player
701
+ if (isAudioItemUtil(entry)) {
702
+ const { nativePlayerIsReady } = this.state;
703
+
704
+ // we have to wait ready status of native player view, before showing audio_player
705
+ if (nativePlayerIsReady) {
706
+ output.push(
707
+ <View nativeID={AUDIO_PLAYER_NATIVE_ID} key={AUDIO_PLAYER_NATIVE_ID}>
708
+ {children}
709
+ </View>
710
+ );
711
+ }
712
+ } else {
713
+ output.push(children);
714
+ }
715
+ // audio-player
716
+
717
+ // play-next
718
+ if (this.getPlayNextData()) {
719
+ output.push(
720
+ <PlayNextOverlay
721
+ key="play-next-overlay"
722
+ item={entry}
723
+ playerIsDocked={docked}
724
+ pluginConfiguration={this.getPluginConfiguration()}
725
+ playerId={this.props.playerId}
726
+ playNextData={this.getPlayNextData()}
727
+ setNextVideoPreloadThresholdPercentage={
728
+ this.props.setNextVideoPreloadThresholdPercentage
729
+ }
730
+ />
731
+ );
732
+ }
733
+ // play-next
734
+
735
+ return flatten(output); // prevent possible case with nested array
699
736
  };
700
737
 
738
+ get supportNativeCast() {
739
+ return this.props.controller.supportNativeCast();
740
+ }
741
+
701
742
  render() {
702
743
  const {
703
744
  docked,
@@ -710,18 +751,13 @@ export default class VideoPlayer extends React.Component<
710
751
  muted,
711
752
  style,
712
753
  castAction,
713
- controller,
714
754
  startComponentsAnimation,
715
755
  } = this.props;
716
756
 
717
- const supportNativeCast = controller.supportNativeCast();
718
-
719
757
  const { audioTrackId, keyEvent, paused, seek, textTrackId, rate } =
720
758
  this.state;
721
759
 
722
- const isAudioItem =
723
- entry?.content?.type?.includes?.("audio") ||
724
- entry?.type?.value === "audio";
760
+ const isAudioItem = isAudioItemUtil(entry);
725
761
 
726
762
  const getStyle = (dimensions) => {
727
763
  const generalStyles = isAudioItem ? styles.audio : styles.video;
@@ -765,7 +801,7 @@ export default class VideoPlayer extends React.Component<
765
801
  // TODO: Get screen data more reliable way useCurrentScreenData
766
802
  const screenData = getTargetScreenDataFromEntry(this.props.playableItem);
767
803
 
768
- const isInlineTV = screenData?.ui_components?.length > 0 && isTV();
804
+ const isInlineTV = isInlineTVUtil(screenData);
769
805
 
770
806
  let platformSpecificProps: any = isApplePlatform()
771
807
  ? {
@@ -776,7 +812,7 @@ export default class VideoPlayer extends React.Component<
776
812
  const supportsNativeControls =
777
813
  !!this.props.controller?.supportsNativeControls?.();
778
814
 
779
- const controls = isAppleTV()
815
+ const controls = isTvOS
780
816
  ? (supportsNativeControls && !isInlineTV) || !!this.getPlayNextData()
781
817
  : supportsNativeControls && !this.getPlayNextData();
782
818
 
@@ -791,8 +827,13 @@ export default class VideoPlayer extends React.Component<
791
827
  controls: shouldUseNativeControls,
792
828
  };
793
829
 
830
+ const isFullScreenAudioPlayer =
831
+ this.getPluginConfiguration()?.["full_screen_audio_player"] || false;
832
+
833
+ const isAudioPlayer = isFullScreenAudioPlayer && isAudioItem;
834
+
794
835
  const pictureInPictureEnabled =
795
- this.props.pluginConfiguration?.pictureInPictureEnabled;
836
+ this.props.pluginConfiguration?.pictureInPictureEnabled && !isAudioPlayer;
796
837
 
797
838
  const nativeProps = {
798
839
  entry, // Must be passed first in list
@@ -806,7 +847,6 @@ export default class VideoPlayer extends React.Component<
806
847
  nowPlayingEnabled,
807
848
  paused,
808
849
  seek,
809
- rate,
810
850
  textTrackId,
811
851
  liveSeekingEnabled,
812
852
  liveCatchUpEnabled,
@@ -817,7 +857,14 @@ export default class VideoPlayer extends React.Component<
817
857
  accessibilityProps: getAllAccessibilityProps(
818
858
  this.getPluginConfiguration()
819
859
  ),
820
- }; // rate temporary removed, because of bug with subtitles
860
+ };
861
+
862
+ if (!isTvOS) {
863
+ // TODO: Move to RN method and remove from props.
864
+ // Causes tvOS bug: native player passes rate on fast seek,
865
+ // RN returns it and it breaks playback.
866
+ nativeProps.rate = rate;
867
+ }
821
868
 
822
869
  if (
823
870
  this.isReactNativeMethodsSupported() &&
@@ -918,8 +965,8 @@ export default class VideoPlayer extends React.Component<
918
965
  const playerContainerStyles = isApplePlatform()
919
966
  ? styles.playerContainerBlack
920
967
  : isTV() && isAudioItem
921
- ? styles.playerContainerTransparent
922
- : styles.playerContainerBlack;
968
+ ? styles.playerContainerTransparent
969
+ : styles.playerContainerBlack;
923
970
 
924
971
  const isInline = () => {
925
972
  if (isTV()) {
@@ -960,9 +1007,6 @@ export default class VideoPlayer extends React.Component<
960
1007
  ) : null;
961
1008
  };
962
1009
 
963
- const isFullScreenAudioPlayer =
964
- this.getPluginConfiguration()?.["full_screen_audio_player"] || false;
965
-
966
1010
  const sharedWrapperViewProps = {
967
1011
  style,
968
1012
  entry,
@@ -987,17 +1031,21 @@ export default class VideoPlayer extends React.Component<
987
1031
  const backgroundImageKey =
988
1032
  this.getPluginConfiguration()?.player_preview_image_key;
989
1033
 
1034
+ const shouldRenderNativePlayer =
1035
+ !this.props.isCasting || this.supportNativeCast;
1036
+
990
1037
  const renderMobilePlayer = () => {
991
1038
  return isFullScreenAudioPlayer && isAudioItem ? (
992
- <View style={containerStyle}>
993
- {(!castAction?.state?.connected || supportNativeCast) && (
1039
+ // Ensure the View remains in the native hierarchy for proper rendering and interaction
1040
+ <View collapsable={false} style={containerStyle}>
1041
+ {shouldRenderNativePlayer ? (
994
1042
  <this.props.PlayerComponent
995
1043
  ref={this._assignRoot}
996
1044
  {...nativeEvents}
997
1045
  {...nativeProps}
998
1046
  listener={this.props.listener}
999
1047
  />
1000
- )}
1048
+ ) : null}
1001
1049
  <AudioPlayerWrapper {...sharedWrapperViewProps} />
1002
1050
  </View>
1003
1051
  ) : (
@@ -1012,7 +1060,7 @@ export default class VideoPlayer extends React.Component<
1012
1060
  return (
1013
1061
  <View style={styles.container}>
1014
1062
  <View style={[playerContainerStyles, playerDimensions]}>
1015
- {isAudioItem && (
1063
+ {isAudioItem ? (
1016
1064
  <AnimationComponent
1017
1065
  animationType={ComponentAnimationType.player}
1018
1066
  additionalData={{
@@ -1031,21 +1079,24 @@ export default class VideoPlayer extends React.Component<
1031
1079
  plugin_configuration={this.getPluginConfiguration()}
1032
1080
  />
1033
1081
  </AnimationComponent>
1034
- )}
1082
+ ) : null}
1035
1083
 
1036
- {shouldRenderBackground && (
1084
+ {shouldRenderBackground ? (
1037
1085
  <PlayerImageBackground
1038
1086
  imageKey={backgroundImageKey}
1039
1087
  configuration={this.getPluginConfiguration()}
1040
1088
  entry={entry}
1041
1089
  style={getBackgroundImageStyle(playerDimensions)}
1042
1090
  />
1043
- )}
1091
+ ) : null}
1044
1092
 
1045
- {(!castAction?.state?.connected || supportNativeCast) && (
1093
+ {shouldRenderNativePlayer ? (
1046
1094
  <AnimationComponent
1047
1095
  animationType={ComponentAnimationType.player}
1048
- additionalData={playerDimensions}
1096
+ additionalData={{
1097
+ ...playerDimensions,
1098
+ disableAnimatedComponent: isAudioItem,
1099
+ }}
1049
1100
  style={getStyle(playerDimensions)}
1050
1101
  >
1051
1102
  <this.props.PlayerComponent
@@ -1061,10 +1112,10 @@ export default class VideoPlayer extends React.Component<
1061
1112
  pluginConfiguration={this.getPluginConfiguration()}
1062
1113
  controller={this.props.controller}
1063
1114
  >
1064
- {this.childrenWithPlayNext()}
1115
+ {this.props.children}
1065
1116
  </this.props.PlayerComponent>
1066
1117
  </AnimationComponent>
1067
- )}
1118
+ ) : null}
1068
1119
  </View>
1069
1120
 
1070
1121
  {renderTransportControls(playerDimensions)}
@@ -1090,6 +1141,14 @@ export default class VideoPlayer extends React.Component<
1090
1141
  const renderTVPlayer = () => {
1091
1142
  return (
1092
1143
  <View style={this.takeParentStyle} testID={"player-view"}>
1144
+ {isAudioItem && (isInlineTV || !isTvOS) ? (
1145
+ <AudioPlayer
1146
+ style={getStyle(styles.audioPlayerSize)}
1147
+ audio_item={entry}
1148
+ plugin_configuration={this.getPluginConfiguration()}
1149
+ />
1150
+ ) : null}
1151
+
1093
1152
  <this.props.PlayerComponent
1094
1153
  ref={this._assignRoot}
1095
1154
  {...nativeEvents}
@@ -1099,11 +1158,11 @@ export default class VideoPlayer extends React.Component<
1099
1158
  pluginConfiguration={this.getPluginConfiguration()}
1100
1159
  controller={this.props.controller}
1101
1160
  >
1102
- {this.childrenWithPlayNext()}
1161
+ {!isInlineTV && this.childrenWithExtensions()}
1103
1162
  </this.props.PlayerComponent>
1104
1163
 
1105
1164
  {renderTransportControls(this.takeParentStyle)}
1106
- {!isTvOSPlatform() && (
1165
+ {!isTvOS && (
1107
1166
  <PlayNextOverlay
1108
1167
  item={entry}
1109
1168
  playerIsDocked={docked}
@@ -5,6 +5,7 @@ import Player from "./Player";
5
5
  import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
6
6
  import { isWeb } from "@applicaster/zapp-react-native-utils/reactUtils";
7
7
  import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
8
+ import { useIsCasting } from "./Player/hooks/useIsCasting";
8
9
 
9
10
  const CHROMECAST_IDENTIFIER = "quick-brick-chromecast-action";
10
11
 
@@ -24,6 +25,7 @@ const QuickBrickPlayerComponent = (
24
25
  }, [props.PlayerComponent]);
25
26
 
26
27
  const castAction = useActions(CHROMECAST_IDENTIFIER);
28
+ const isCasting = useIsCasting();
27
29
 
28
30
  const isModal = Boolean(props?.isModal);
29
31
  const isScreenDisabled = !controller?.isFullScreenSupported() || !isModal;
@@ -48,6 +50,7 @@ const QuickBrickPlayerComponent = (
48
50
  {...props}
49
51
  ref={ref}
50
52
  castAction={!props?.disableCastAction && castAction}
53
+ isCasting={isCasting}
51
54
  PlayerComponent={props.PlayerComponent}
52
55
  openPiP={openPiP}
53
56
  closePiP={closePiP}