Audio Player: Support 2X speed and mute; Audio: Fix width on mobile (#1533)
This commit is contained in:
parent
dedefe87ca
commit
d6e1665e4e
@ -258,14 +258,14 @@ const Audio: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const isOwn = isOwnMessage(message);
|
const isOwn = isOwnMessage(message);
|
||||||
const renderedWaveform = useMemo(
|
const renderedWaveform = useMemo(
|
||||||
() => voice && renderWaveform(
|
() => origin === AudioOrigin.Inline && voice && renderWaveform(
|
||||||
voice,
|
voice,
|
||||||
(isMediaUnread && !isOwn) ? 1 : playProgress,
|
(isMediaUnread && !isOwn) ? 1 : playProgress,
|
||||||
isOwn,
|
isOwn,
|
||||||
theme,
|
theme,
|
||||||
seekerRef,
|
seekerRef,
|
||||||
),
|
),
|
||||||
[voice, isMediaUnread, isOwn, playProgress, theme],
|
[origin, voice, isMediaUnread, isOwn, playProgress, theme],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fullClassName = buildClassName(
|
const fullClassName = buildClassName(
|
||||||
|
|||||||
@ -105,6 +105,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.playback-button {
|
||||||
|
&.applied {
|
||||||
|
--color-text-secondary: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.playback-button-inner {
|
||||||
|
transition: 0.2s color ease-in-out;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: bold;
|
||||||
|
border: 2px solid;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
padding: 0.15rem 0.25rem;
|
||||||
|
font-variant-numeric: tabular-nums;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import {
|
|||||||
ApiAudio, ApiChat, ApiMessage, ApiUser,
|
ApiAudio, ApiChat, ApiMessage, ApiUser,
|
||||||
} from '../../api/types';
|
} from '../../api/types';
|
||||||
|
|
||||||
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT } from '../../util/environment';
|
import { IS_IOS, IS_SINGLE_COLUMN_LAYOUT, IS_TOUCH_ENV } from '../../util/environment';
|
||||||
|
|
||||||
import * as mediaLoader from '../../util/mediaLoader';
|
import * as mediaLoader from '../../util/mediaLoader';
|
||||||
import {
|
import {
|
||||||
getMediaDuration, getMessageContent, getMessageMediaHash, getSenderTitle,
|
getMediaDuration, getMessageContent, getMessageMediaHash, getSenderTitle,
|
||||||
@ -39,9 +40,19 @@ type StateProps = {
|
|||||||
sender?: ApiChat | ApiUser;
|
sender?: ApiChat | ApiUser;
|
||||||
chat?: ApiChat;
|
chat?: ApiChat;
|
||||||
volume: number;
|
volume: number;
|
||||||
|
playbackRate: number;
|
||||||
|
isMuted: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DispatchProps = Pick<GlobalActions, 'focusMessage' | 'closeAudioPlayer' | 'setAudioPlayerVolume'>;
|
type DispatchProps = Pick<GlobalActions, (
|
||||||
|
'focusMessage' |
|
||||||
|
'closeAudioPlayer' |
|
||||||
|
'setAudioPlayerVolume' |
|
||||||
|
'setAudioPlayerPlaybackRate' |
|
||||||
|
'setAudioPlayerMuted'
|
||||||
|
)>;
|
||||||
|
|
||||||
|
const FAST_PLAYBACK_RATE = 1.8;
|
||||||
|
|
||||||
const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
||||||
message,
|
message,
|
||||||
@ -51,19 +62,32 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
sender,
|
sender,
|
||||||
chat,
|
chat,
|
||||||
volume,
|
volume,
|
||||||
|
playbackRate,
|
||||||
|
isMuted,
|
||||||
setAudioPlayerVolume,
|
setAudioPlayerVolume,
|
||||||
|
setAudioPlayerPlaybackRate,
|
||||||
|
setAudioPlayerMuted,
|
||||||
focusMessage,
|
focusMessage,
|
||||||
closeAudioPlayer,
|
closeAudioPlayer,
|
||||||
}) => {
|
}) => {
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
const { audio, voice } = getMessageContent(message);
|
const { audio, voice, video } = getMessageContent(message);
|
||||||
const isVoice = Boolean(voice);
|
const isVoice = Boolean(voice || video);
|
||||||
const senderName = sender ? getSenderTitle(lang, sender) : undefined;
|
const senderName = sender ? getSenderTitle(lang, sender) : undefined;
|
||||||
const mediaData = mediaLoader.getFromMemory(getMessageMediaHash(message, 'inline')!) as (string | undefined);
|
const mediaData = mediaLoader.getFromMemory(getMessageMediaHash(message, 'inline')!) as (string | undefined);
|
||||||
const mediaMetadata = useMessageMediaMetadata(message, sender, chat);
|
const mediaMetadata = useMessageMediaMetadata(message, sender, chat);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
playPause, stop, isPlaying, requestNextTrack, requestPreviousTrack, isFirst, isLast, setVolume,
|
playPause,
|
||||||
|
stop,
|
||||||
|
isPlaying,
|
||||||
|
requestNextTrack,
|
||||||
|
requestPreviousTrack,
|
||||||
|
isFirst,
|
||||||
|
isLast,
|
||||||
|
setVolume,
|
||||||
|
toggleMuted,
|
||||||
|
setPlaybackRate,
|
||||||
} = useAudioPlayer(
|
} = useAudioPlayer(
|
||||||
makeTrackId(message),
|
makeTrackId(message),
|
||||||
getMediaDuration(message)!,
|
getMediaDuration(message)!,
|
||||||
@ -94,15 +118,33 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
|
|
||||||
const handleVolumeChange = useCallback((value: number) => {
|
const handleVolumeChange = useCallback((value: number) => {
|
||||||
setAudioPlayerVolume({ volume: value / 100 });
|
setAudioPlayerVolume({ volume: value / 100 });
|
||||||
|
setAudioPlayerMuted({ isMuted: false });
|
||||||
|
|
||||||
setVolume(value / 100);
|
setVolume(value / 100);
|
||||||
}, [setAudioPlayerVolume, setVolume]);
|
}, [setAudioPlayerMuted, setAudioPlayerVolume, setVolume]);
|
||||||
|
|
||||||
|
const handleVolumeClick = useCallback(() => {
|
||||||
|
if (IS_TOUCH_ENV && !IS_IOS) return;
|
||||||
|
toggleMuted();
|
||||||
|
setAudioPlayerMuted({ isMuted: !isMuted });
|
||||||
|
}, [isMuted, setAudioPlayerMuted, toggleMuted]);
|
||||||
|
|
||||||
|
const handlePlaybackClick = useCallback(() => {
|
||||||
|
if (playbackRate === 1) {
|
||||||
|
setPlaybackRate(FAST_PLAYBACK_RATE);
|
||||||
|
setAudioPlayerPlaybackRate({ playbackRate: FAST_PLAYBACK_RATE });
|
||||||
|
} else {
|
||||||
|
setPlaybackRate(1);
|
||||||
|
setAudioPlayerPlaybackRate({ playbackRate: 1 });
|
||||||
|
}
|
||||||
|
}, [playbackRate, setAudioPlayerPlaybackRate, setPlaybackRate]);
|
||||||
|
|
||||||
const volumeIcon = useMemo(() => {
|
const volumeIcon = useMemo(() => {
|
||||||
if (volume === 0) return 'icon-muted';
|
if (volume === 0 || isMuted) return 'icon-muted';
|
||||||
if (volume < 0.3) return 'icon-volume-1';
|
if (volume < 0.3) return 'icon-volume-1';
|
||||||
if (volume < 0.6) return 'icon-volume-2';
|
if (volume < 0.6) return 'icon-volume-2';
|
||||||
return 'icon-volume-3';
|
return 'icon-volume-3';
|
||||||
}, [volume]);
|
}, [volume, isMuted]);
|
||||||
|
|
||||||
if (noUi) {
|
if (noUi) {
|
||||||
return undefined;
|
return undefined;
|
||||||
@ -152,22 +194,39 @@ const AudioPlayer: FC<OwnProps & StateProps & DispatchProps> = ({
|
|||||||
<RippleEffect />
|
<RippleEffect />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!IS_IOS && (
|
<Button
|
||||||
|
round
|
||||||
|
className="player-button volume-button"
|
||||||
|
color="translucent"
|
||||||
|
size="smaller"
|
||||||
|
ariaLabel="Volume"
|
||||||
|
withClickPropagation
|
||||||
|
>
|
||||||
|
<i className={volumeIcon} onClick={handleVolumeClick} />
|
||||||
|
{!IS_IOS && (
|
||||||
|
<>
|
||||||
|
<div className="volume-slider-spacer" />
|
||||||
|
<div className="volume-slider">
|
||||||
|
<RangeSlider value={isMuted ? 0 : volume * 100} onChange={handleVolumeChange} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{isVoice && (
|
||||||
<Button
|
<Button
|
||||||
round
|
round
|
||||||
className="player-button volume-button"
|
className={buildClassName('playback-button', playbackRate !== 1 && 'applied')}
|
||||||
color="translucent"
|
color="translucent"
|
||||||
size="smaller"
|
size="smaller"
|
||||||
ariaLabel="Volume"
|
ariaLabel="Playback Rate"
|
||||||
withClickPropagation
|
ripple={!IS_SINGLE_COLUMN_LAYOUT}
|
||||||
|
onClick={handlePlaybackClick}
|
||||||
>
|
>
|
||||||
<i className={volumeIcon} />
|
<span className="playback-button-inner">2Х</span>
|
||||||
<div className="volume-slider-spacer" />
|
|
||||||
<div className="volume-slider">
|
|
||||||
<RangeSlider value={volume * 100} onChange={handleVolumeChange} />
|
|
||||||
</div>
|
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
round
|
round
|
||||||
className="player-close"
|
className="player-close"
|
||||||
@ -208,13 +267,18 @@ export default withGlobal<OwnProps>(
|
|||||||
(global, { message }): StateProps => {
|
(global, { message }): StateProps => {
|
||||||
const sender = selectSender(global, message);
|
const sender = selectSender(global, message);
|
||||||
const chat = selectChat(global, message.chatId);
|
const chat = selectChat(global, message.chatId);
|
||||||
const { volume } = global.audioPlayer;
|
const { volume, playbackRate, isMuted } = global.audioPlayer;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sender,
|
sender,
|
||||||
chat,
|
chat,
|
||||||
volume,
|
volume,
|
||||||
|
playbackRate,
|
||||||
|
isMuted,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
(setGlobal, actions): DispatchProps => pick(actions, ['focusMessage', 'closeAudioPlayer', 'setAudioPlayerVolume']),
|
(setGlobal, actions): DispatchProps => pick(
|
||||||
|
actions,
|
||||||
|
['focusMessage', 'closeAudioPlayer', 'setAudioPlayerVolume', 'setAudioPlayerPlaybackRate', 'setAudioPlayerMuted'],
|
||||||
|
),
|
||||||
)(AudioPlayer);
|
)(AudioPlayer);
|
||||||
|
|||||||
@ -337,6 +337,10 @@
|
|||||||
min-width: 20rem;
|
min-width: 20rem;
|
||||||
padding: .5rem .5rem .8125rem !important;
|
padding: .5rem .5rem .8125rem !important;
|
||||||
|
|
||||||
|
@media (max-width: 600px) {
|
||||||
|
min-width: 17rem;
|
||||||
|
}
|
||||||
|
|
||||||
.Audio + .text-content {
|
.Audio + .text-content {
|
||||||
margin-top: .25rem;
|
margin-top: .25rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,6 +61,7 @@ export const TOP_CHAT_MESSAGES_PRELOAD_LIMIT = 20;
|
|||||||
export const ALL_CHATS_PRELOAD_DISABLED = false;
|
export const ALL_CHATS_PRELOAD_DISABLED = false;
|
||||||
|
|
||||||
export const DEFAULT_VOLUME = 1;
|
export const DEFAULT_VOLUME = 1;
|
||||||
|
export const DEFAULT_PLAYBACK_RATE = 1;
|
||||||
|
|
||||||
export const ANIMATION_LEVEL_MIN = 0;
|
export const ANIMATION_LEVEL_MIN = 0;
|
||||||
export const ANIMATION_LEVEL_MED = 1;
|
export const ANIMATION_LEVEL_MED = 1;
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
|
MIN_SCREEN_WIDTH_FOR_STATIC_RIGHT_COLUMN,
|
||||||
GLOBAL_STATE_CACHE_USER_LIST_LIMIT,
|
GLOBAL_STATE_CACHE_USER_LIST_LIMIT,
|
||||||
DEFAULT_VOLUME,
|
DEFAULT_VOLUME,
|
||||||
|
DEFAULT_PLAYBACK_RATE,
|
||||||
} from '../config';
|
} from '../config';
|
||||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';
|
import { IS_SINGLE_COLUMN_LAYOUT } from '../util/environment';
|
||||||
import { ANIMATION_END_EVENT, ANIMATION_START_EVENT } from '../hooks/useHeavyAnimationCheck';
|
import { ANIMATION_END_EVENT, ANIMATION_START_EVENT } from '../hooks/useHeavyAnimationCheck';
|
||||||
@ -137,6 +138,9 @@ function readCache(initialState: GlobalState): GlobalState {
|
|||||||
if (cached.audioPlayer.volume === undefined) {
|
if (cached.audioPlayer.volume === undefined) {
|
||||||
cached.audioPlayer.volume = DEFAULT_VOLUME;
|
cached.audioPlayer.volume = DEFAULT_VOLUME;
|
||||||
}
|
}
|
||||||
|
if (cached.audioPlayer.playbackRate === undefined) {
|
||||||
|
cached.audioPlayer.playbackRate = DEFAULT_PLAYBACK_RATE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const newState = {
|
const newState = {
|
||||||
@ -185,6 +189,8 @@ function updateCache() {
|
|||||||
]),
|
]),
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
volume: global.audioPlayer.volume,
|
volume: global.audioPlayer.volume,
|
||||||
|
playbackRate: global.audioPlayer.playbackRate,
|
||||||
|
isMuted: global.audioPlayer.isMuted,
|
||||||
},
|
},
|
||||||
isChatInfoShown: reduceShowChatInfo(global),
|
isChatInfoShown: reduceShowChatInfo(global),
|
||||||
users: reduceUsers(global),
|
users: reduceUsers(global),
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { NewChatMembersProgress } from '../types';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ANIMATION_LEVEL_DEFAULT, DARK_THEME_PATTERN_COLOR, DEFAULT_MESSAGE_TEXT_SIZE_PX, DEFAULT_PATTERN_COLOR,
|
ANIMATION_LEVEL_DEFAULT, DARK_THEME_PATTERN_COLOR, DEFAULT_MESSAGE_TEXT_SIZE_PX, DEFAULT_PATTERN_COLOR,
|
||||||
|
DEFAULT_PLAYBACK_RATE,
|
||||||
DEFAULT_VOLUME,
|
DEFAULT_VOLUME,
|
||||||
IOS_DEFAULT_MESSAGE_TEXT_SIZE_PX, MACOS_DEFAULT_MESSAGE_TEXT_SIZE_PX,
|
IOS_DEFAULT_MESSAGE_TEXT_SIZE_PX, MACOS_DEFAULT_MESSAGE_TEXT_SIZE_PX,
|
||||||
} from '../config';
|
} from '../config';
|
||||||
@ -113,6 +114,8 @@ export const INITIAL_STATE: GlobalState = {
|
|||||||
|
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
volume: DEFAULT_VOLUME,
|
volume: DEFAULT_VOLUME,
|
||||||
|
playbackRate: DEFAULT_PLAYBACK_RATE,
|
||||||
|
isMuted: false,
|
||||||
},
|
},
|
||||||
|
|
||||||
forwardMessages: {},
|
forwardMessages: {},
|
||||||
|
|||||||
@ -329,6 +329,8 @@ export type GlobalState = {
|
|||||||
threadId?: number;
|
threadId?: number;
|
||||||
origin?: AudioOrigin;
|
origin?: AudioOrigin;
|
||||||
volume: number;
|
volume: number;
|
||||||
|
playbackRate: number;
|
||||||
|
isMuted: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
topPeers: {
|
topPeers: {
|
||||||
@ -503,7 +505,7 @@ export type ActionTypes = (
|
|||||||
'loadFullUser' | 'openUserInfo' | 'loadNearestCountry' | 'loadTopUsers' | 'loadContactList' |
|
'loadFullUser' | 'openUserInfo' | 'loadNearestCountry' | 'loadTopUsers' | 'loadContactList' |
|
||||||
'loadCurrentUser' | 'updateProfile' | 'checkUsername' | 'addContact' | 'updateContact' |
|
'loadCurrentUser' | 'updateProfile' | 'checkUsername' | 'addContact' | 'updateContact' |
|
||||||
'deleteUser' | 'loadUser' | 'setUserSearchQuery' |
|
'deleteUser' | 'loadUser' | 'setUserSearchQuery' |
|
||||||
// Channel / groups creation
|
// chat creation
|
||||||
'createChannel' | 'createGroupChat' | 'resetChatCreation' |
|
'createChannel' | 'createGroupChat' | 'resetChatCreation' |
|
||||||
// settings
|
// settings
|
||||||
'setSettingOption' | 'loadPasswordInfo' | 'clearTwoFaError' |
|
'setSettingOption' | 'loadPasswordInfo' | 'clearTwoFaError' |
|
||||||
@ -514,7 +516,8 @@ export type ActionTypes = (
|
|||||||
'updateWebNotificationSettings' | 'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' |
|
'updateWebNotificationSettings' | 'loadLanguages' | 'loadPrivacySettings' | 'setPrivacyVisibility' |
|
||||||
'setPrivacySettings' | 'loadNotificationExceptions' | 'setThemeSettings' | 'updateIsOnline' |
|
'setPrivacySettings' | 'loadNotificationExceptions' | 'setThemeSettings' | 'updateIsOnline' |
|
||||||
'loadContentSettings' | 'updateContentSettings' |
|
'loadContentSettings' | 'updateContentSettings' |
|
||||||
// Stickers & GIFs
|
'loadCountryList' | 'ensureTimeFormat' |
|
||||||
|
// stickers & GIFs
|
||||||
'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' |
|
'loadStickerSets' | 'loadAddedStickers' | 'loadRecentStickers' | 'loadFavoriteStickers' | 'loadFeaturedStickers' |
|
||||||
'loadStickers' | 'setStickerSearchQuery' | 'loadSavedGifs' | 'setGifSearchQuery' | 'searchMoreGifs' |
|
'loadStickers' | 'setStickerSearchQuery' | 'loadSavedGifs' | 'setGifSearchQuery' | 'searchMoreGifs' |
|
||||||
'faveSticker' | 'unfaveSticker' | 'toggleStickerSet' | 'loadAnimatedEmojis' |
|
'faveSticker' | 'unfaveSticker' | 'toggleStickerSet' | 'loadAnimatedEmojis' |
|
||||||
@ -524,12 +527,14 @@ export type ActionTypes = (
|
|||||||
'clickInlineButton' | 'sendBotCommand' | 'loadTopInlineBots' | 'queryInlineBot' | 'sendInlineBotResult' |
|
'clickInlineButton' | 'sendBotCommand' | 'loadTopInlineBots' | 'queryInlineBot' | 'sendInlineBotResult' |
|
||||||
'resetInlineBot' | 'restartBot' | 'startBot' |
|
'resetInlineBot' | 'restartBot' | 'startBot' |
|
||||||
// media viewer & audio player
|
// media viewer & audio player
|
||||||
'openMediaViewer' | 'closeMediaViewer' | 'openAudioPlayer' | 'setAudioPlayerVolume' | 'closeAudioPlayer' |
|
'openMediaViewer' | 'closeMediaViewer' |
|
||||||
|
'openAudioPlayer' | 'setAudioPlayerVolume' | 'setAudioPlayerPlaybackRate' |
|
||||||
|
'setAudioPlayerMuted' | 'closeAudioPlayer' |
|
||||||
// misc
|
// misc
|
||||||
'openPollModal' | 'closePollModal' | 'loadWebPagePreview' | 'clearWebPagePreview' |
|
'openPollModal' | 'closePollModal' |
|
||||||
'loadWallpapers' | 'uploadWallpaper' | 'setDeviceToken' | 'deleteDeviceToken' |
|
'loadWebPagePreview' | 'clearWebPagePreview' | 'loadWallpapers' | 'uploadWallpaper' |
|
||||||
|
'setDeviceToken' | 'deleteDeviceToken' |
|
||||||
'checkVersionNotification' | 'createServiceNotification' |
|
'checkVersionNotification' | 'createServiceNotification' |
|
||||||
'loadCountryList' | 'ensureTimeFormat' |
|
|
||||||
// payment
|
// payment
|
||||||
'openPaymentModal' | 'closePaymentModal' | 'addPaymentError' |
|
'openPaymentModal' | 'closePaymentModal' | 'addPaymentError' |
|
||||||
'validateRequestedInfo' | 'setPaymentStep' | 'sendPaymentForm' | 'getPaymentForm' | 'getReceipt' |
|
'validateRequestedInfo' | 'setPaymentStep' | 'sendPaymentForm' | 'getPaymentForm' | 'getReceipt' |
|
||||||
|
|||||||
@ -49,12 +49,18 @@ export default (
|
|||||||
controllerRef.current = register(trackId, trackType, origin, (eventName, e) => {
|
controllerRef.current = register(trackId, trackType, origin, (eventName, e) => {
|
||||||
switch (eventName) {
|
switch (eventName) {
|
||||||
case 'onPlay': {
|
case 'onPlay': {
|
||||||
const { setVolume, proxy } = controllerRef.current!;
|
const {
|
||||||
|
setVolume, setPlaybackRate, toggleMuted, proxy,
|
||||||
|
} = controllerRef.current!;
|
||||||
setIsPlaying(true);
|
setIsPlaying(true);
|
||||||
|
|
||||||
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
|
registerMediaSession(metadata, makeMediaHandlers(controllerRef));
|
||||||
setPlaybackState('playing');
|
setPlaybackState('playing');
|
||||||
setVolume(getGlobal().audioPlayer.volume);
|
setVolume(getGlobal().audioPlayer.volume);
|
||||||
|
toggleMuted(!!getGlobal().audioPlayer.isMuted);
|
||||||
|
if (trackType === 'voice') {
|
||||||
|
setPlaybackRate(getGlobal().audioPlayer.playbackRate);
|
||||||
|
}
|
||||||
|
|
||||||
setPositionState({
|
setPositionState({
|
||||||
duration: proxy.duration || 0,
|
duration: proxy.duration || 0,
|
||||||
@ -63,6 +69,15 @@ export default (
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'onRateChange': {
|
||||||
|
const { proxy } = controllerRef.current!;
|
||||||
|
setPositionState({
|
||||||
|
duration: proxy.duration || 0,
|
||||||
|
playbackRate: proxy.playbackRate,
|
||||||
|
position: proxy.currentTime,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'onPause':
|
case 'onPause':
|
||||||
setIsPlaying(false);
|
setIsPlaying(false);
|
||||||
setPlaybackState('paused');
|
setPlaybackState('paused');
|
||||||
@ -111,6 +126,8 @@ export default (
|
|||||||
isLast,
|
isLast,
|
||||||
requestNextTrack,
|
requestNextTrack,
|
||||||
requestPreviousTrack,
|
requestPreviousTrack,
|
||||||
|
setPlaybackRate,
|
||||||
|
toggleMuted,
|
||||||
} = controllerRef.current!;
|
} = controllerRef.current!;
|
||||||
const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
|
const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
|
||||||
|
|
||||||
@ -179,6 +196,8 @@ export default (
|
|||||||
requestPreviousTrack,
|
requestPreviousTrack,
|
||||||
isFirst: isFirst(),
|
isFirst: isFirst(),
|
||||||
isLast: isLast(),
|
isLast: isLast(),
|
||||||
|
setPlaybackRate,
|
||||||
|
toggleMuted,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -170,7 +170,7 @@ addReducer('closeMediaViewer', (global) => {
|
|||||||
|
|
||||||
addReducer('openAudioPlayer', (global, actions, payload) => {
|
addReducer('openAudioPlayer', (global, actions, payload) => {
|
||||||
const {
|
const {
|
||||||
chatId, threadId, messageId, origin, volume,
|
chatId, threadId, messageId, origin, volume, playbackRate, isMuted,
|
||||||
} = payload!;
|
} = payload!;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -181,6 +181,8 @@ addReducer('openAudioPlayer', (global, actions, payload) => {
|
|||||||
messageId,
|
messageId,
|
||||||
origin,
|
origin,
|
||||||
volume: volume || global.audioPlayer.volume,
|
volume: volume || global.audioPlayer.volume,
|
||||||
|
playbackRate: playbackRate || global.audioPlayer.playbackRate,
|
||||||
|
isMuted: isMuted || global.audioPlayer.isMuted,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -199,11 +201,41 @@ addReducer('setAudioPlayerVolume', (global, actions, payload) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addReducer('setAudioPlayerPlaybackRate', (global, actions, payload) => {
|
||||||
|
const {
|
||||||
|
playbackRate,
|
||||||
|
} = payload!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
audioPlayer: {
|
||||||
|
...global.audioPlayer,
|
||||||
|
playbackRate,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
addReducer('setAudioPlayerMuted', (global, actions, payload) => {
|
||||||
|
const {
|
||||||
|
isMuted,
|
||||||
|
} = payload!;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...global,
|
||||||
|
audioPlayer: {
|
||||||
|
...global.audioPlayer,
|
||||||
|
isMuted,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
addReducer('closeAudioPlayer', (global) => {
|
addReducer('closeAudioPlayer', (global) => {
|
||||||
return {
|
return {
|
||||||
...global,
|
...global,
|
||||||
audioPlayer: {
|
audioPlayer: {
|
||||||
volume: global.audioPlayer.volume, // Preserve only volume for the next play
|
volume: global.audioPlayer.volume,
|
||||||
|
playbackRate: global.audioPlayer.playbackRate,
|
||||||
|
isMuted: global.audioPlayer.isMuted,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@ -211,6 +211,21 @@ export function register(
|
|||||||
setVolume(volume: number) {
|
setVolume(volume: number) {
|
||||||
if (currentTrackId === trackId) {
|
if (currentTrackId === trackId) {
|
||||||
audio.volume = volume;
|
audio.volume = volume;
|
||||||
|
audio.muted = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setPlaybackRate(rate: number) {
|
||||||
|
if (currentTrackId === trackId) {
|
||||||
|
audio.playbackRate = rate;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
toggleMuted(muted?: boolean) {
|
||||||
|
if (muted === undefined) {
|
||||||
|
audio.muted = !audio.muted;
|
||||||
|
} else {
|
||||||
|
audio.muted = muted;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user