@applicaster/quick-brick-player 13.0.0-rc.99 → 13.0.0

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 (34) hide show
  1. package/package.json +6 -7
  2. package/src/Player/AudioLayer/AudioDescription.tsx +109 -68
  3. package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +81 -189
  4. package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +23 -5
  5. package/src/Player/AudioLayer/Layout/Controls/index.tsx +24 -49
  6. package/src/Player/AudioLayer/Layout/Controls/utils.ts +2 -2
  7. package/src/Player/AudioLayer/Layout/DockedControls/index.tsx +38 -19
  8. package/src/Player/AudioLayer/Layout/MobileLayout.tsx +4 -13
  9. package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +39 -40
  10. package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +6 -22
  11. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +1 -0
  12. package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +99 -0
  13. package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +37 -20
  14. package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +19 -0
  15. package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +101 -105
  16. package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +2 -11
  17. package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +19 -5
  18. package/src/Player/AudioLayer/Layout/const.ts +4 -0
  19. package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +1 -1
  20. package/src/Player/AudioLayer/Layout/utils.ts +7 -0
  21. package/src/Player/AudioLayer/SleepTimerManager.ts +22 -11
  22. package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +66 -0
  23. package/src/Player/AudioLayer/components/SleepTimerModalHeader/index.ts +1 -0
  24. package/src/Player/AudioLayer/useSleepTimerModal.ts +109 -0
  25. package/src/Player/Const/sleepTimerOptions.ts +7 -5
  26. package/src/Player/Utils/index.tsx +6 -0
  27. package/src/Player/hooks/useIsCasting.tsx +57 -0
  28. package/src/Player/index.tsx +84 -37
  29. package/src/QuickBrickPlayer.tsx +3 -0
  30. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
  31. package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
  32. package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
  33. package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
  34. package/src/utils/utils.ts +0 -25
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ import { ModalHeader } from "@applicaster/zapp-react-native-ui-components/Components/ModalComponent/Header";
3
+ import { isNil } from "lodash";
4
+
5
+ const formatTime = (milliseconds: number) => {
6
+ const totalSeconds = Math.floor(milliseconds / 1000);
7
+ const hours = Math.floor(totalSeconds / 3600);
8
+ const minutes = Math.floor((totalSeconds % 3600) / 60);
9
+ const seconds = totalSeconds % 60;
10
+
11
+ if (milliseconds < 3600000) {
12
+ return `${minutes.toString().padStart(2, "0")}:${seconds
13
+ .toString()
14
+ .padStart(2, "0")}`;
15
+ }
16
+
17
+ return `${hours.toString().padStart(2, "0")}:${minutes
18
+ .toString()
19
+ .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
20
+ };
21
+
22
+ export const SleepTimerModalHeader = ({
23
+ summary,
24
+ ...props
25
+ }: {
26
+ summary?: string;
27
+ }) => {
28
+ const sleepTimerDate = +summary;
29
+
30
+ const [timeLeft, setTimeLeft] = React.useState(
31
+ sleepTimerDate !== 0 ? sleepTimerDate - Date.now() : 0
32
+ );
33
+
34
+ const showCounter = React.useMemo(() => sleepTimerDate > 0, [sleepTimerDate]);
35
+
36
+ React.useLayoutEffect(() => {
37
+ if (showCounter && sleepTimerDate !== 0) {
38
+ setTimeLeft(sleepTimerDate - Date.now());
39
+
40
+ const intervalId = setInterval(() => {
41
+ setTimeLeft(() => {
42
+ const newTimeLeft = sleepTimerDate - Date.now();
43
+
44
+ if (newTimeLeft <= 0) {
45
+ clearInterval(intervalId);
46
+
47
+ return 0;
48
+ } else {
49
+ return newTimeLeft;
50
+ }
51
+ });
52
+ }, 1000);
53
+
54
+ return () => clearInterval(intervalId);
55
+ } else {
56
+ setTimeLeft(0);
57
+ }
58
+ }, [sleepTimerDate, showCounter]);
59
+
60
+ return (
61
+ <ModalHeader
62
+ summary={!isNil(summary) ? formatTime(timeLeft) : summary}
63
+ {...(props as any)}
64
+ />
65
+ );
66
+ };
@@ -0,0 +1 @@
1
+ export * from "./SleepTimerModalHeader";
@@ -0,0 +1,109 @@
1
+ import { usePlayerState } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayerState";
2
+ import { useCallback, useEffect, useMemo, useState } from "react";
3
+ import {
4
+ SLEEP_TIMER_OFF,
5
+ SleepTimerController,
6
+ SleepTimerState,
7
+ } from "./SleepTimerManager";
8
+
9
+ import { openBottomSheetModal } from "@applicaster/zapp-react-native-utils/modalState";
10
+
11
+ import { SleepTimerModalHeader } from "./components/SleepTimerModalHeader";
12
+ import { getSleepTimerOptions } from "../Const/sleepTimerOptions";
13
+ import {
14
+ getBottomSheetModalLabelProps,
15
+ getBottomSheetModalIconProps,
16
+ getBottomSheetModalItemProps,
17
+ getBottomSheetModalSelectedItemIcon,
18
+ selectSleepTitle,
19
+ selectSleepOffLabel,
20
+ } from "../Utils";
21
+
22
+ export const useSleepTimerModal = (player, configuration) => {
23
+ const playerState = usePlayerState("audio-player-sleep-timer-modal");
24
+
25
+ const title = configuration(selectSleepTitle);
26
+ const offLabel = configuration(selectSleepOffLabel);
27
+
28
+ const [sleepTimerManager, setSleepTimerManager] =
29
+ useState<SleepTimerController | null>(null);
30
+
31
+ const [sleepTimerState, setSleepTimerState] = useState<SleepTimerState>(
32
+ new SleepTimerState(SLEEP_TIMER_OFF, 0)
33
+ );
34
+
35
+ useEffect(() => {
36
+ if (player) {
37
+ setSleepTimerManager(new SleepTimerController(player));
38
+ } else {
39
+ setSleepTimerManager(null);
40
+ }
41
+ }, [player]);
42
+
43
+ useEffect(() => {
44
+ if (playerState?.isLive) {
45
+ // Resetting a sleep timer when audio content is live (Timer not supported on live video)
46
+ sleepTimerManager.setSleepTimer(SLEEP_TIMER_OFF).catch();
47
+ }
48
+ }, [playerState?.isLive]);
49
+
50
+ useEffect(() => {
51
+ if (!playerState.isReadyToPlay) {
52
+ return;
53
+ }
54
+
55
+ void sleepTimerManager?.loadSleep();
56
+ }, [playerState.isReadyToPlay, sleepTimerManager]);
57
+
58
+ useEffect(() => {
59
+ const sleepSubscription =
60
+ sleepTimerManager?.sleepTimerState$.subscribe(setSleepTimerState);
61
+
62
+ return () => {
63
+ sleepSubscription?.unsubscribe();
64
+ };
65
+ }, [sleepTimerManager]);
66
+
67
+ const onSleepSelect = useCallback(
68
+ async (item) => {
69
+ await sleepTimerManager?.setSleepTimer(item);
70
+ },
71
+ [sleepTimerManager]
72
+ );
73
+
74
+ const onSleepButtonPress = useCallback(() => {
75
+ const timerDate = sleepTimerState.timerDate;
76
+
77
+ const timerRemaining =
78
+ timerDate !== 0 && +timerDate > Date.now() ? timerDate : null;
79
+
80
+ openBottomSheetModal({
81
+ modalBottomSheetContentProps: {
82
+ headerComponent: SleepTimerModalHeader,
83
+ items: getSleepTimerOptions(offLabel, timerRemaining),
84
+ onPress: onSleepSelect,
85
+ title,
86
+ summary: timerRemaining,
87
+ itemProps: getBottomSheetModalItemProps,
88
+ iconProps: getBottomSheetModalIconProps,
89
+ labelProps: getBottomSheetModalLabelProps,
90
+ getSelectedItemIcon: getBottomSheetModalSelectedItemIcon,
91
+ },
92
+ options: {
93
+ supportedOrientations: [
94
+ "portrait",
95
+ "landscape",
96
+ "portrait-upside-down",
97
+ ],
98
+ },
99
+ });
100
+ }, [sleepTimerState.timerDate, sleepTimerState.timer, title, onSleepSelect]);
101
+
102
+ return useMemo(
103
+ () => ({
104
+ onSleepButtonPress,
105
+ sleepTimerState,
106
+ }),
107
+ [onSleepButtonPress, sleepTimerState]
108
+ );
109
+ };
@@ -28,12 +28,14 @@ const createTimerOptions = (value) => {
28
28
  };
29
29
  };
30
30
 
31
- export const getSleepTimerOptions = (configuration) => {
31
+ export const getSleepTimerOptions = (offLabel, sleepTimerValue) => {
32
32
  return [
33
- {
34
- label: configuration["playback_sleep_off_label"],
35
- value: 0,
36
- },
33
+ sleepTimerValue
34
+ ? {
35
+ label: offLabel,
36
+ value: 0,
37
+ }
38
+ : null,
37
39
  ...[5, 10, 15, 30, 45, 60, 120].map(createTimerOptions),
38
40
  ];
39
41
  };
@@ -116,3 +116,9 @@ export const getBottomSheetModalSelectedItemIcon = (theme) =>
116
116
 
117
117
  export const getBottomSheetModalDefaultItemIcon = (theme) =>
118
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?.includes?.("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
 
@@ -823,7 +859,7 @@ export default class VideoPlayer extends React.Component<
823
859
  ),
824
860
  };
825
861
 
826
- if (!isAppleTV()) {
862
+ if (!isTvOS) {
827
863
  // TODO: Move to RN method and remove from props.
828
864
  // Causes tvOS bug: native player passes rate on fast seek,
829
865
  // RN returns it and it breaks playback.
@@ -995,11 +1031,14 @@ export default class VideoPlayer extends React.Component<
995
1031
  const backgroundImageKey =
996
1032
  this.getPluginConfiguration()?.player_preview_image_key;
997
1033
 
1034
+ const shouldRenderNativePlayer =
1035
+ !this.props.isCasting || this.supportNativeCast;
1036
+
998
1037
  const renderMobilePlayer = () => {
999
1038
  return isFullScreenAudioPlayer && isAudioItem ? (
1000
1039
  // Ensure the View remains in the native hierarchy for proper rendering and interaction
1001
1040
  <View collapsable={false} style={containerStyle}>
1002
- {!castAction?.state?.connected || supportNativeCast ? (
1041
+ {shouldRenderNativePlayer ? (
1003
1042
  <this.props.PlayerComponent
1004
1043
  ref={this._assignRoot}
1005
1044
  {...nativeEvents}
@@ -1051,7 +1090,7 @@ export default class VideoPlayer extends React.Component<
1051
1090
  />
1052
1091
  ) : null}
1053
1092
 
1054
- {!castAction?.state?.connected || supportNativeCast ? (
1093
+ {shouldRenderNativePlayer ? (
1055
1094
  <AnimationComponent
1056
1095
  animationType={ComponentAnimationType.player}
1057
1096
  additionalData={{
@@ -1073,7 +1112,7 @@ export default class VideoPlayer extends React.Component<
1073
1112
  pluginConfiguration={this.getPluginConfiguration()}
1074
1113
  controller={this.props.controller}
1075
1114
  >
1076
- {this.childrenWithPlayNext()}
1115
+ {this.props.children}
1077
1116
  </this.props.PlayerComponent>
1078
1117
  </AnimationComponent>
1079
1118
  ) : null}
@@ -1102,6 +1141,14 @@ export default class VideoPlayer extends React.Component<
1102
1141
  const renderTVPlayer = () => {
1103
1142
  return (
1104
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
+
1105
1152
  <this.props.PlayerComponent
1106
1153
  ref={this._assignRoot}
1107
1154
  {...nativeEvents}
@@ -1111,11 +1158,11 @@ export default class VideoPlayer extends React.Component<
1111
1158
  pluginConfiguration={this.getPluginConfiguration()}
1112
1159
  controller={this.props.controller}
1113
1160
  >
1114
- {this.childrenWithPlayNext()}
1161
+ {!isInlineTV && this.childrenWithExtensions()}
1115
1162
  </this.props.PlayerComponent>
1116
1163
 
1117
1164
  {renderTransportControls(this.takeParentStyle)}
1118
- {!isTvOSPlatform() && (
1165
+ {!isTvOS && (
1119
1166
  <PlayNextOverlay
1120
1167
  item={entry}
1121
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}
@@ -1,3 +0,0 @@
1
- import LinearGradient from "react-native-linear-gradient";
2
-
3
- export default LinearGradient;
@@ -1,3 +0,0 @@
1
- const WebLinearGradient = require("react-native-web-linear-gradient").default;
2
-
3
- export default WebLinearGradient;
@@ -1 +0,0 @@
1
- export { default } from "./LinearGradientProxy";