@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.
- package/package.json +27 -14
- package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
- package/src/Player/AudioLayer/AudioDescription.tsx +107 -68
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +142 -295
- package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +45 -0
- package/src/Player/AudioLayer/Layout/Controls/index.tsx +291 -0
- package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +9 -27
- package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
- package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +77 -81
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +222 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +82 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +16 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/hooks/index.ts +1 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/hooks/useChangePlayerState.ts +99 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +112 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +36 -0
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +212 -0
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +215 -0
- package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +128 -0
- package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
- package/src/Player/AudioLayer/Layout/const.ts +26 -0
- package/src/Player/AudioLayer/Layout/debug.ts +6 -0
- package/src/Player/AudioLayer/Layout/hooks/index.ts +5 -0
- package/src/Player/AudioLayer/Layout/hooks/useMobileLayoutImageSize.ts +14 -0
- package/src/Player/AudioLayer/Layout/hooks/useTabletLayoutImageSize.ts +105 -0
- package/src/Player/AudioLayer/Layout/hooks/useTransportInfoHeight.ts +54 -0
- package/src/Player/AudioLayer/Layout/index.tsx +21 -48
- package/src/Player/AudioLayer/Layout/types.ts +7 -0
- package/src/Player/AudioLayer/Layout/utils.ts +7 -0
- package/src/Player/AudioLayer/SleepTimerManager.ts +130 -0
- package/src/Player/AudioLayer/SpeedManager.ts +52 -0
- package/src/Player/AudioLayer/components/SleepTimerModalHeader/SleepTimerModalHeader.tsx +66 -0
- package/src/Player/AudioLayer/components/SleepTimerModalHeader/index.ts +1 -0
- package/src/Player/AudioLayer/useSleepTimerModal.ts +109 -0
- package/src/Player/AudioLayer/utils.ts +27 -0
- package/src/Player/Const/sleepTimerOptions.ts +41 -0
- package/src/Player/Const/speedOptions.ts +4 -0
- package/src/Player/Utils/Utils.ts +0 -5
- package/src/Player/Utils/index.tsx +123 -0
- package/src/Player/hooks/useIsCasting.tsx +57 -0
- package/src/Player/index.tsx +111 -52
- package/src/QuickBrickPlayer.tsx +3 -0
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
- package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.ts +0 -3
- package/src/Player/AudioLayer/LinearGradient/LinearGradientProxy.web.ts +0 -3
- package/src/Player/AudioLayer/LinearGradient/index.ts +0 -1
- package/src/Player/AudioLayer/MagicBG/index.tsx +0 -155
- package/src/Player/Helpers/VideoResizeMode.ts +0 -7
- 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
|
+
};
|
package/src/Player/index.tsx
CHANGED
|
@@ -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
|
-
|
|
676
|
-
|
|
677
|
-
|
|
691
|
+
childrenWithExtensions = () => {
|
|
692
|
+
const { docked, entry, children } = this.props;
|
|
693
|
+
|
|
694
|
+
if (!isTvOS) {
|
|
695
|
+
return children;
|
|
678
696
|
}
|
|
679
697
|
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
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
|
|
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 =
|
|
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
|
-
};
|
|
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
|
-
|
|
922
|
-
|
|
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
|
-
|
|
993
|
-
|
|
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
|
-
{
|
|
1093
|
+
{shouldRenderNativePlayer ? (
|
|
1046
1094
|
<AnimationComponent
|
|
1047
1095
|
animationType={ComponentAnimationType.player}
|
|
1048
|
-
additionalData={
|
|
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.
|
|
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.
|
|
1161
|
+
{!isInlineTV && this.childrenWithExtensions()}
|
|
1103
1162
|
</this.props.PlayerComponent>
|
|
1104
1163
|
|
|
1105
1164
|
{renderTransportControls(this.takeParentStyle)}
|
|
1106
|
-
{!
|
|
1165
|
+
{!isTvOS && (
|
|
1107
1166
|
<PlayNextOverlay
|
|
1108
1167
|
item={entry}
|
|
1109
1168
|
playerIsDocked={docked}
|
package/src/QuickBrickPlayer.tsx
CHANGED
|
@@ -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}
|