@applicaster/quick-brick-player 13.0.0-rc.10 → 13.0.0-rc.100
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 -13
- package/src/CellPlayer/Assets/AssetsComponent.tsx +17 -3
- package/src/Player/AudioLayer/AudioDescription.tsx +5 -7
- package/src/Player/AudioLayer/AudioPlayerWrapper.tsx +136 -181
- package/src/Player/AudioLayer/Layout/Controls/VerticalGutter.tsx +27 -0
- package/src/Player/AudioLayer/Layout/Controls/index.tsx +316 -0
- package/src/Player/AudioLayer/Layout/{defaultLayoutsConts.ts → Controls/utils.ts} +7 -25
- package/src/Player/AudioLayer/Layout/Debug/index.tsx +55 -0
- package/src/Player/AudioLayer/Layout/{DockedLayout.tsx → DockedControls/index.tsx} +44 -67
- package/src/Player/AudioLayer/Layout/MobileLayout.tsx +231 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/AnimatedImage.tsx +83 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/FlexImage.tsx +25 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/index.tsx +101 -0
- package/src/Player/AudioLayer/Layout/PlayerImage/styles.ts +26 -0
- package/src/Player/AudioLayer/Layout/TabletLandscapeLayout.tsx +216 -0
- package/src/Player/AudioLayer/Layout/TabletPortraitLayout.tsx +224 -0
- package/src/Player/AudioLayer/Layout/TransportInfo/index.tsx +114 -0
- package/src/Player/AudioLayer/Layout/VerticalGutter/index.tsx +8 -0
- package/src/Player/AudioLayer/Layout/const.ts +22 -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/MagicBG/index.tsx +1 -1
- package/src/Player/AudioLayer/SleepTimerManager.ts +119 -0
- package/src/Player/AudioLayer/SpeedManager.ts +52 -0
- package/src/Player/AudioLayer/utils.ts +27 -0
- package/src/Player/Const/sleepTimerOptions.ts +39 -0
- package/src/Player/Const/speedOptions.ts +4 -0
- package/src/Player/Utils/Utils.ts +0 -5
- package/src/Player/Utils/index.tsx +117 -0
- package/src/Player/index.tsx +31 -19
- package/src/Player/AudioLayer/Layout/DefaultLayout.tsx +0 -452
- package/src/Player/Helpers/VideoResizeMode.ts +0 -7
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
3
|
+
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
4
|
+
import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
|
|
5
|
+
import { hasDatePassed, NAMESPACE } from "./utils";
|
|
6
|
+
|
|
7
|
+
const { log_debug, log_error } = createLogger({
|
|
8
|
+
subsystem: "Player",
|
|
9
|
+
category: "SleepTimerManager",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type SleepTimer = {
|
|
13
|
+
label: string;
|
|
14
|
+
// interval in minutes for UI at the moment when timer was first started
|
|
15
|
+
value: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const SLEEP_TIMER_OFF: SleepTimer = {
|
|
19
|
+
label: "playback_sleep_off_label",
|
|
20
|
+
value: 0,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export class SleepTimerState {
|
|
24
|
+
constructor(
|
|
25
|
+
public timer: SleepTimer,
|
|
26
|
+
public timerDate: number
|
|
27
|
+
) {}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const SLEEP_PREFERENCE_KEY = "sleep";
|
|
31
|
+
|
|
32
|
+
export class SleepTimerController {
|
|
33
|
+
private sleepTimerStateSubject = new BehaviorSubject<SleepTimerState>(
|
|
34
|
+
new SleepTimerState(SLEEP_TIMER_OFF, 0)
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
constructor(private player: Player) {}
|
|
38
|
+
|
|
39
|
+
get sleepTimerState$() {
|
|
40
|
+
return this.sleepTimerStateSubject.asObservable();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private async scheduleSleep(sleepDate): Promise<boolean> {
|
|
44
|
+
log_debug(`Setting sleep interval to ${sleepDate}`);
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
this.player.cancelSleepTimer?.();
|
|
48
|
+
this.player.startSleepTimer?.(sleepDate);
|
|
49
|
+
|
|
50
|
+
return true;
|
|
51
|
+
} catch (e) {
|
|
52
|
+
log_error("Failed to start sleep timer", { error: e.message });
|
|
53
|
+
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async setSleepTimer(item: SleepTimer) {
|
|
59
|
+
// User has selected Off state
|
|
60
|
+
if (item.value === 0) {
|
|
61
|
+
log_debug("Cancelling sleep timer");
|
|
62
|
+
this.player.cancelSleepTimer?.();
|
|
63
|
+
|
|
64
|
+
return this.onTimerExpired();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
log_debug(`Starting sleep timer in ${item.value} minutes`);
|
|
68
|
+
|
|
69
|
+
const futureSleepDate = Date.now() + item.value * 60000;
|
|
70
|
+
|
|
71
|
+
if (await this.scheduleSleep(futureSleepDate)) {
|
|
72
|
+
await localStorage.setItem(
|
|
73
|
+
SLEEP_PREFERENCE_KEY,
|
|
74
|
+
{ ...item, futureSleepDate },
|
|
75
|
+
NAMESPACE
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
this.sleepTimerStateSubject.next(
|
|
79
|
+
new SleepTimerState(item, futureSleepDate)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async onTimerExpired() {
|
|
85
|
+
await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
|
|
86
|
+
|
|
87
|
+
this.sleepTimerStateSubject.next(new SleepTimerState(SLEEP_TIMER_OFF, 0));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async loadSleep() {
|
|
91
|
+
const sleep = await localStorage.getItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
|
|
92
|
+
|
|
93
|
+
if (!sleep) return;
|
|
94
|
+
|
|
95
|
+
const { futureSleepDate, ...rest } = sleep;
|
|
96
|
+
|
|
97
|
+
if (!futureSleepDate || hasDatePassed(futureSleepDate)) {
|
|
98
|
+
log_debug("Sleep date has already passed");
|
|
99
|
+
await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
|
|
100
|
+
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (await this.scheduleSleep(futureSleepDate)) {
|
|
105
|
+
log_debug(`Sleep state restored, will go to sleep at ${futureSleepDate}`);
|
|
106
|
+
|
|
107
|
+
this.sleepTimerStateSubject.next(
|
|
108
|
+
new SleepTimerState(rest as SleepTimer, futureSleepDate)
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Will be called if user closed the player explicitly.
|
|
114
|
+
// TODO: check if it will be called on Android when we need.
|
|
115
|
+
// Probably we will have to handle it on native instead.
|
|
116
|
+
public static async onPlayerDestroy() {
|
|
117
|
+
await localStorage.removeItem(SLEEP_PREFERENCE_KEY, NAMESPACE);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BehaviorSubject } from "rxjs";
|
|
2
|
+
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
3
|
+
import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
4
|
+
import { Player } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/player";
|
|
5
|
+
import { NAMESPACE } from "./utils";
|
|
6
|
+
|
|
7
|
+
const { log_debug } = createLogger({
|
|
8
|
+
subsystem: "Player",
|
|
9
|
+
category: "PlaybackSpeedManager",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type PlaybackSpeed = {
|
|
13
|
+
asset: string;
|
|
14
|
+
value: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const SPEED_PREFERENCE_KEY = "speed";
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_SPEED: PlaybackSpeed = {
|
|
20
|
+
asset: "speed_1",
|
|
21
|
+
value: 1.0,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// todo: should not be applied to live streams
|
|
25
|
+
export class SpeedController {
|
|
26
|
+
private playbackSpeedSubject = new BehaviorSubject<PlaybackSpeed>(
|
|
27
|
+
DEFAULT_SPEED
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
constructor(private player: Player) {}
|
|
31
|
+
|
|
32
|
+
get playbackSpeed$() {
|
|
33
|
+
return this.playbackSpeedSubject.asObservable();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async loadSpeed() {
|
|
37
|
+
const speed = await localStorage.getItem(SPEED_PREFERENCE_KEY, NAMESPACE);
|
|
38
|
+
|
|
39
|
+
// checking for value in case we will pull empty or broken object
|
|
40
|
+
if (speed && speed.value) {
|
|
41
|
+
this.playbackSpeedSubject.next(speed);
|
|
42
|
+
this.player.setPlaybackRate?.(speed.value);
|
|
43
|
+
log_debug(`Speed loaded: ${speed}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async setPlaybackSpeed(speed: PlaybackSpeed) {
|
|
48
|
+
await localStorage.setItem(SPEED_PREFERENCE_KEY, speed, NAMESPACE);
|
|
49
|
+
this.playbackSpeedSubject.next(speed);
|
|
50
|
+
this.player.setPlaybackRate?.(speed.value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
|
|
2
|
+
import {
|
|
3
|
+
PlayerAnimationStateEnum,
|
|
4
|
+
PlayerAnimationStateT,
|
|
5
|
+
} from "@applicaster/zapp-react-native-ui-components/Components/VideoModal/ModalAnimation/ModalAnimationContext";
|
|
2
6
|
import { parseJsonIfNeeded } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
7
|
+
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
3
8
|
|
|
4
9
|
export const NAMESPACE = "audio-player";
|
|
5
10
|
|
|
@@ -31,3 +36,25 @@ export const formatSpeed = (value: number) => {
|
|
|
31
36
|
// Return the formatted string with "speed_" prefix
|
|
32
37
|
return `speed_${formattedValue}`;
|
|
33
38
|
};
|
|
39
|
+
|
|
40
|
+
export const calculateBorderRadius = (
|
|
41
|
+
docked: boolean,
|
|
42
|
+
startComponentsAnimation: boolean,
|
|
43
|
+
isActiveGesture: boolean,
|
|
44
|
+
playerAnimationState: PlayerAnimationStateT,
|
|
45
|
+
configuration: Record<string, any>
|
|
46
|
+
): number => {
|
|
47
|
+
const shouldRemoveBorderRadius =
|
|
48
|
+
(startComponentsAnimation &&
|
|
49
|
+
isActiveGesture &&
|
|
50
|
+
playerAnimationState !== PlayerAnimationStateEnum.maximize) ||
|
|
51
|
+
docked;
|
|
52
|
+
|
|
53
|
+
if (shouldRemoveBorderRadius) {
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return toNumberWithDefaultZero(
|
|
58
|
+
configuration.audio_player_artwork_border_radius
|
|
59
|
+
);
|
|
60
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { toDayJSLocaleMap } from "@applicaster/zapp-react-native-utils/appUtils/localizationsHelper";
|
|
2
|
+
import { dayjs } from "@applicaster/zapp-react-native-utils/dateUtils";
|
|
3
|
+
import { getUILanguage } from "@applicaster/zapp-react-native-utils/localizationUtils";
|
|
4
|
+
|
|
5
|
+
const createTimerOptions = (value) => {
|
|
6
|
+
let label = "";
|
|
7
|
+
|
|
8
|
+
const str = dayjs
|
|
9
|
+
.duration(value, "minute")
|
|
10
|
+
.locale(toDayJSLocaleMap(getUILanguage()))
|
|
11
|
+
.humanize();
|
|
12
|
+
|
|
13
|
+
if (value === 60) {
|
|
14
|
+
/** Skipping prefix "an"/"un"/"una" for 1 hour */
|
|
15
|
+
|
|
16
|
+
if (str.includes(" ")) {
|
|
17
|
+
label = `1 ${str.split(" ")[1]}`; // Combine "1" with second part of the string
|
|
18
|
+
} else {
|
|
19
|
+
label = `1 ${str}`; // Use dayjs provided translation
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
label = str;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
label,
|
|
27
|
+
value,
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const getSleepTimerOptions = (configuration) => {
|
|
32
|
+
return [
|
|
33
|
+
{
|
|
34
|
+
label: configuration["playback_sleep_off_label"],
|
|
35
|
+
value: 0,
|
|
36
|
+
},
|
|
37
|
+
...[5, 10, 15, 30, 45, 60, 120].map(createTimerOptions),
|
|
38
|
+
];
|
|
39
|
+
};
|
|
@@ -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,118 @@
|
|
|
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;
|
package/src/Player/index.tsx
CHANGED
|
@@ -721,7 +721,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
721
721
|
|
|
722
722
|
const isAudioItem =
|
|
723
723
|
entry?.content?.type?.includes?.("audio") ||
|
|
724
|
-
entry?.type?.value
|
|
724
|
+
entry?.type?.value?.includes?.("audio");
|
|
725
725
|
|
|
726
726
|
const getStyle = (dimensions) => {
|
|
727
727
|
const generalStyles = isAudioItem ? styles.audio : styles.video;
|
|
@@ -791,8 +791,13 @@ export default class VideoPlayer extends React.Component<
|
|
|
791
791
|
controls: shouldUseNativeControls,
|
|
792
792
|
};
|
|
793
793
|
|
|
794
|
+
const isFullScreenAudioPlayer =
|
|
795
|
+
this.getPluginConfiguration()?.["full_screen_audio_player"] || false;
|
|
796
|
+
|
|
797
|
+
const isAudioPlayer = isFullScreenAudioPlayer && isAudioItem;
|
|
798
|
+
|
|
794
799
|
const pictureInPictureEnabled =
|
|
795
|
-
this.props.pluginConfiguration?.pictureInPictureEnabled;
|
|
800
|
+
this.props.pluginConfiguration?.pictureInPictureEnabled && !isAudioPlayer;
|
|
796
801
|
|
|
797
802
|
const nativeProps = {
|
|
798
803
|
entry, // Must be passed first in list
|
|
@@ -806,7 +811,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
806
811
|
nowPlayingEnabled,
|
|
807
812
|
paused,
|
|
808
813
|
seek,
|
|
809
|
-
rate,
|
|
810
814
|
textTrackId,
|
|
811
815
|
liveSeekingEnabled,
|
|
812
816
|
liveCatchUpEnabled,
|
|
@@ -817,7 +821,14 @@ export default class VideoPlayer extends React.Component<
|
|
|
817
821
|
accessibilityProps: getAllAccessibilityProps(
|
|
818
822
|
this.getPluginConfiguration()
|
|
819
823
|
),
|
|
820
|
-
};
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
if (!isAppleTV()) {
|
|
827
|
+
// TODO: Move to RN method and remove from props.
|
|
828
|
+
// Causes tvOS bug: native player passes rate on fast seek,
|
|
829
|
+
// RN returns it and it breaks playback.
|
|
830
|
+
nativeProps.rate = rate;
|
|
831
|
+
}
|
|
821
832
|
|
|
822
833
|
if (
|
|
823
834
|
this.isReactNativeMethodsSupported() &&
|
|
@@ -918,8 +929,8 @@ export default class VideoPlayer extends React.Component<
|
|
|
918
929
|
const playerContainerStyles = isApplePlatform()
|
|
919
930
|
? styles.playerContainerBlack
|
|
920
931
|
: isTV() && isAudioItem
|
|
921
|
-
|
|
922
|
-
|
|
932
|
+
? styles.playerContainerTransparent
|
|
933
|
+
: styles.playerContainerBlack;
|
|
923
934
|
|
|
924
935
|
const isInline = () => {
|
|
925
936
|
if (isTV()) {
|
|
@@ -960,9 +971,6 @@ export default class VideoPlayer extends React.Component<
|
|
|
960
971
|
) : null;
|
|
961
972
|
};
|
|
962
973
|
|
|
963
|
-
const isFullScreenAudioPlayer =
|
|
964
|
-
this.getPluginConfiguration()?.["full_screen_audio_player"] || false;
|
|
965
|
-
|
|
966
974
|
const sharedWrapperViewProps = {
|
|
967
975
|
style,
|
|
968
976
|
entry,
|
|
@@ -989,15 +997,16 @@ export default class VideoPlayer extends React.Component<
|
|
|
989
997
|
|
|
990
998
|
const renderMobilePlayer = () => {
|
|
991
999
|
return isFullScreenAudioPlayer && isAudioItem ? (
|
|
992
|
-
|
|
993
|
-
|
|
1000
|
+
// Ensure the View remains in the native hierarchy for proper rendering and interaction
|
|
1001
|
+
<View collapsable={false} style={containerStyle}>
|
|
1002
|
+
{!castAction?.state?.connected || supportNativeCast ? (
|
|
994
1003
|
<this.props.PlayerComponent
|
|
995
1004
|
ref={this._assignRoot}
|
|
996
1005
|
{...nativeEvents}
|
|
997
1006
|
{...nativeProps}
|
|
998
1007
|
listener={this.props.listener}
|
|
999
1008
|
/>
|
|
1000
|
-
)}
|
|
1009
|
+
) : null}
|
|
1001
1010
|
<AudioPlayerWrapper {...sharedWrapperViewProps} />
|
|
1002
1011
|
</View>
|
|
1003
1012
|
) : (
|
|
@@ -1012,7 +1021,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1012
1021
|
return (
|
|
1013
1022
|
<View style={styles.container}>
|
|
1014
1023
|
<View style={[playerContainerStyles, playerDimensions]}>
|
|
1015
|
-
{isAudioItem
|
|
1024
|
+
{isAudioItem ? (
|
|
1016
1025
|
<AnimationComponent
|
|
1017
1026
|
animationType={ComponentAnimationType.player}
|
|
1018
1027
|
additionalData={{
|
|
@@ -1031,21 +1040,24 @@ export default class VideoPlayer extends React.Component<
|
|
|
1031
1040
|
plugin_configuration={this.getPluginConfiguration()}
|
|
1032
1041
|
/>
|
|
1033
1042
|
</AnimationComponent>
|
|
1034
|
-
)}
|
|
1043
|
+
) : null}
|
|
1035
1044
|
|
|
1036
|
-
{shouldRenderBackground
|
|
1045
|
+
{shouldRenderBackground ? (
|
|
1037
1046
|
<PlayerImageBackground
|
|
1038
1047
|
imageKey={backgroundImageKey}
|
|
1039
1048
|
configuration={this.getPluginConfiguration()}
|
|
1040
1049
|
entry={entry}
|
|
1041
1050
|
style={getBackgroundImageStyle(playerDimensions)}
|
|
1042
1051
|
/>
|
|
1043
|
-
)}
|
|
1052
|
+
) : null}
|
|
1044
1053
|
|
|
1045
|
-
{
|
|
1054
|
+
{!castAction?.state?.connected || supportNativeCast ? (
|
|
1046
1055
|
<AnimationComponent
|
|
1047
1056
|
animationType={ComponentAnimationType.player}
|
|
1048
|
-
additionalData={
|
|
1057
|
+
additionalData={{
|
|
1058
|
+
...playerDimensions,
|
|
1059
|
+
disableAnimatedComponent: isAudioItem,
|
|
1060
|
+
}}
|
|
1049
1061
|
style={getStyle(playerDimensions)}
|
|
1050
1062
|
>
|
|
1051
1063
|
<this.props.PlayerComponent
|
|
@@ -1064,7 +1076,7 @@ export default class VideoPlayer extends React.Component<
|
|
|
1064
1076
|
{this.childrenWithPlayNext()}
|
|
1065
1077
|
</this.props.PlayerComponent>
|
|
1066
1078
|
</AnimationComponent>
|
|
1067
|
-
)}
|
|
1079
|
+
) : null}
|
|
1068
1080
|
</View>
|
|
1069
1081
|
|
|
1070
1082
|
{renderTransportControls(playerDimensions)}
|