Media Message: Fix playing voice and audio after send (#4347)

This commit is contained in:
Alexander Zinchuk 2024-03-22 13:06:01 +01:00
parent c23752a28e
commit b8b8c15919
16 changed files with 102 additions and 59 deletions

View File

@ -129,6 +129,9 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
});
const handleClose = useLastCallback(() => {
if (!stop) {
return;
}
if (isPlaying) {
playPause();
}
@ -138,18 +141,26 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
});
const handleVolumeChange = useLastCallback((value: number) => {
if (!setVolume) {
return;
}
setAudioPlayerVolume({ volume: value / 100 });
setVolume(value / 100);
});
const handleVolumeClick = useLastCallback(() => {
if (IS_TOUCH_ENV && !IS_IOS) return;
if (!toggleMuted) {
return;
}
toggleMuted();
setAudioPlayerMuted({ isMuted: !isMuted });
});
const updatePlaybackRate = useLastCallback((newRate: number, isActive = true) => {
if (!setPlaybackRate) {
return;
}
const rate = PLAYBACK_RATES[newRate];
const shouldBeActive = newRate !== REGULAR_PLAYBACK_RATE && isActive;
setAudioPlayerPlaybackRate({ playbackRate: rate, isPlaybackRateActive: shouldBeActive });
@ -227,7 +238,7 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
color="translucent"
size="smaller"
className="player-button"
disabled={isFirst()}
disabled={isFirst?.()}
onClick={requestPreviousTrack}
ariaLabel="Previous track"
>
@ -251,7 +262,7 @@ const AudioPlayer: FC<OwnProps & StateProps> = ({
color="translucent"
size="smaller"
className="player-button"
disabled={isLast()}
disabled={isLast?.()}
onClick={requestNextTrack}
ariaLabel="Next track"
>

View File

@ -31,7 +31,6 @@ import {
isChatChannel,
isChatGroup,
isChatWithRepliesBot,
isLocalMessageId,
isUserId,
} from '../../global/helpers';
import {
@ -57,6 +56,7 @@ import {
import animateScroll, { isAnimatingScroll, restartCurrentScrollAnimation } from '../../util/animateScroll';
import buildClassName from '../../util/buildClassName';
import { orderBy } from '../../util/iteratees';
import { isLocalMessageId } from '../../util/messageKey';
import resetScroll from '../../util/resetScroll';
import { debounce, onTickEnd } from '../../util/schedulers';
import { groupMessages } from './helpers/groupMessages';

View File

@ -36,6 +36,7 @@ import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { getOrderedIds } from '../../../util/folderManager';
import { buildCollectionByKey, omit, pick } from '../../../util/iteratees';
import * as langProvider from '../../../util/langProvider';
import { isLocalMessageId } from '../../../util/messageKey';
import { debounce, pause, throttle } from '../../../util/schedulers';
import { extractCurrentThemeParams } from '../../../util/themeStyle';
import { callApi } from '../../../api/gramjs';
@ -45,7 +46,6 @@ import {
isChatBasicGroup,
isChatChannel,
isChatSuperGroup,
isLocalMessageId,
isUserBot,
toChannelId,
} from '../../helpers';

View File

@ -45,7 +45,7 @@ import {
unique,
} from '../../../util/iteratees';
import { translate } from '../../../util/langProvider';
import { getMessageKey } from '../../../util/messageKey';
import { getMessageKey, isLocalMessageId } from '../../../util/messageKey';
import { debounce, onTickEnd, rafPromise } from '../../../util/schedulers';
import { IS_IOS } from '../../../util/windowEnvironment';
import { callApi, cancelApiProgress } from '../../../api/gramjs';
@ -54,7 +54,6 @@ import {
getUserFullName,
isChatChannel,
isDeletedUser,
isLocalMessageId,
isMessageLocal,
isServiceNotificationMessage,
isUserBot,

View File

@ -4,9 +4,10 @@ import { MAIN_THREAD_ID } from '../../../api/types';
import { ARCHIVED_FOLDER_ID, MAX_ACTIVE_PINNED_CHATS } from '../../../config';
import { buildCollectionByKey, omit } from '../../../util/iteratees';
import { isLocalMessageId } from '../../../util/messageKey';
import { closeMessageNotifications, notifyAboutMessage } from '../../../util/notifications';
import { buildLocalMessage } from '../../../api/gramjs/apiBuilders/messages';
import { isChatChannel, isLocalMessageId } from '../../helpers';
import { isChatChannel } from '../../helpers';
import {
addActionHandler, getGlobal, setGlobal,
} from '../../index';

View File

@ -12,11 +12,11 @@ import { SERVICE_NOTIFICATIONS_USER_ID } from '../../../config';
import { areDeepEqual } from '../../../util/areDeepEqual';
import { getCurrentTabId } from '../../../util/establishMultitabRole';
import { omit, pickTruthy, unique } from '../../../util/iteratees';
import { getMessageKey } from '../../../util/messageKey';
import { getMessageKey, isLocalMessageId } from '../../../util/messageKey';
import { notifyAboutMessage } from '../../../util/notifications';
import { onTickEnd } from '../../../util/schedulers';
import {
checkIfHasUnreadReactions, getIsSavedDialog, getMessageContent, getMessageText, isActionMessage, isLocalMessageId,
checkIfHasUnreadReactions, getIsSavedDialog, getMessageContent, getMessageText, isActionMessage,
isMessageLocal, isUserId,
} from '../../helpers';
import { getMessageReplyInfo, getStoryReplyInfo } from '../../helpers/replies';

View File

@ -498,26 +498,30 @@ function omitLocalMedia(message: ApiMessage): ApiMessage {
photo, video, document, sticker,
} = message.content;
if (photo) {
photo.blobUrl = undefined;
}
if (video) {
video.blobUrl = undefined;
video.previewBlobUrl = undefined;
}
if (document) {
document.previewBlobUrl = undefined;
}
if (sticker) {
sticker.isPreloadedGlobally = undefined;
}
message.previousLocalId = undefined;
return message;
return {
...message,
content: {
...message.content,
photo: photo && {
...photo,
blobUrl: undefined,
},
video: video && {
...video,
blobUrl: undefined,
previewBlobUrl: undefined,
},
document: document && {
...document,
previewBlobUrl: undefined,
},
sticker: sticker && {
...sticker,
isPreloadedGlobally: undefined,
},
},
previousLocalId: undefined,
};
}
function reduceSettings<T extends GlobalState>(global: T): GlobalState['settings'] {

View File

@ -14,7 +14,7 @@ import type {
} from '../../api/types';
import { ApiMediaFormat } from '../../api/types';
import { getMessageKey } from '../../util/messageKey';
import { getMessageServerKey } from '../../util/messageKey';
import {
IS_OPFS_SUPPORTED,
IS_OPUS_SUPPORTED,
@ -229,8 +229,13 @@ export function getMessageMediaHash(
return undefined;
}
const messageKey = getMessageServerKey(message);
if (!messageKey) {
return undefined;
}
const mediaId = content.id;
const base = `${getMessageKey(message)}${mediaId ? `:${mediaId}` : ''}`;
const base = `${messageKey}${mediaId ? `:${mediaId}` : ''}`;
if (messageVideo) {
switch (target) {

View File

@ -11,7 +11,7 @@ import {
SUPPORTED_IMAGE_CONTENT_TYPES, SUPPORTED_VIDEO_CONTENT_TYPES, VIDEO_STICKER_MIME_TYPE,
} from '../../config';
import { areSortedArraysIntersecting, unique } from '../../util/iteratees';
import { getMessageKey } from '../../util/messageKey';
import { getMessageKey, isLocalMessageId } from '../../util/messageKey';
import { getServerTime } from '../../util/serverTime';
import { IS_OPUS_SUPPORTED } from '../../util/windowEnvironment';
import { getGlobal } from '../index';
@ -188,10 +188,6 @@ export function isMessageFailed(message: ApiMessage) {
return message.sendingState === 'messageSendingStateFailed';
}
export function isLocalMessageId(id: number) {
return !Number.isInteger(id);
}
export function isHistoryClearMessage(message: ApiMessage) {
return message.content.action && message.content.action.type === 'historyClear';
}

View File

@ -6,6 +6,7 @@ import { IS_MOCKED_CLIENT } from '../config';
import { isCacheApiSupported } from '../util/cacheApi';
import { getCurrentTabId, reestablishMasterToSelf } from '../util/establishMultitabRole';
import { cloneDeep } from '../util/iteratees';
import { isLocalMessageId } from '../util/messageKey';
import { Bundles, loadBundle } from '../util/moduleLoader';
import { parseLocationHash } from '../util/routing';
import { clearStoredSession } from '../util/sessions';
@ -13,7 +14,6 @@ import { updatePeerColors } from '../util/theme';
import { IS_MULTITAB_SUPPORTED } from '../util/windowEnvironment';
import { updateTabState } from './reducers/tabs';
import { initCache, loadCache } from './cache';
import { isLocalMessageId } from './helpers';
import {
addActionHandler, getGlobal, setGlobal,
} from './index';

View File

@ -1,6 +1,5 @@
import type { ApiMessage, ApiSponsoredMessage, ApiThreadInfo } from '../../api/types';
import type { FocusDirection, ThreadId } from '../../types';
import type { MessageKey } from '../../util/messageKey';
import type {
GlobalState, MessageList, MessageListType, TabArgs, TabThread, Thread,
} from '../types';
@ -13,9 +12,9 @@ import { getCurrentTabId } from '../../util/establishMultitabRole';
import {
areSortedArraysEqual, excludeSortedArray, omit, pick, pickTruthy, unique,
} from '../../util/iteratees';
import { isLocalMessageId, type MessageKey } from '../../util/messageKey';
import {
hasMessageTtl,
isLocalMessageId, mergeIdRanges, orderHistoryIds, orderPinnedIds,
hasMessageTtl, mergeIdRanges, orderHistoryIds, orderPinnedIds,
} from '../helpers';
import {
selectChat,

View File

@ -22,7 +22,7 @@ import {
import { getCurrentTabId } from '../../util/establishMultitabRole';
import { findLast } from '../../util/iteratees';
import { MEMO_EMPTY_ARRAY } from '../../util/memo';
import { getMessageKey } from '../../util/messageKey';
import { getMessageKey, isLocalMessageId } from '../../util/messageKey';
import { getServerTime } from '../../util/serverTime';
import { IS_TRANSLATION_SUPPORTED } from '../../util/windowEnvironment';
import {
@ -47,7 +47,6 @@ import {
isChatSuperGroup,
isCommonBoxChat,
isForwardedMessage,
isLocalMessageId,
isMessageDocumentSticker,
isMessageFailed,
isMessageLocal,

View File

@ -1,4 +1,6 @@
import { useEffect, useRef, useState } from '../lib/teact/teact';
import {
useEffect, useMemo, useRef, useState,
} from '../lib/teact/teact';
import { getActions, getGlobal } from '../global';
import type { Track, TrackId } from '../util/audioPlayer';
@ -20,7 +22,7 @@ type Handler = (e: Event) => void;
const DEFAULT_SKIP_TIME = 10;
const useAudioPlayer = (
trackId: TrackId,
trackId: TrackId | undefined,
originalDuration: number, // Sometimes incorrect for voice messages
trackType: Track['type'],
src?: string,
@ -50,6 +52,9 @@ const useAudioPlayer = (
});
useSyncEffect(() => {
if (!trackId) {
return;
}
controllerRef.current = register(trackId, trackType, (eventName, e) => {
if (noHandleEvents) {
return;
@ -141,11 +146,17 @@ const useAudioPlayer = (
requestPreviousTrack,
setPlaybackRate,
toggleMuted,
} = controllerRef.current!;
const duration = proxy.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
} = controllerRef.current ?? {};
const duration = useMemo(() => {
return proxy?.duration && Number.isFinite(proxy.duration) ? proxy.duration : originalDuration;
}, [proxy?.duration, originalDuration]);
// RAF progress
useEffect(() => {
if (!proxy) {
return;
}
if (noReset && proxy.currentTime === 0) {
return;
}
@ -156,7 +167,7 @@ const useAudioPlayer = (
// Cleanup
useEffect(() => () => {
destroy(noPlaylist);
destroy?.(noPlaylist);
}, [destroy, noPlaylist]);
// Autoplay once `src` is present
@ -166,32 +177,32 @@ const useAudioPlayer = (
}
// When paused by another player
if (proxy.src && proxy.paused) {
if (proxy?.src && proxy?.paused) {
return;
}
if (shouldPlay && src && !isPlaying) {
play(src);
play?.(src);
}
}, [shouldPlay, src, isPlaying, play, proxy.src, proxy.paused, trackType]);
}, [shouldPlay, src, isPlaying, play, proxy?.src, proxy?.paused, trackType]);
const playIfPresent = useLastCallback(() => {
if (src) {
play(src);
play?.(src);
}
});
const playPause = useLastCallback(() => {
if (isPlaying) {
pause();
pause?.();
} else {
playIfPresent();
}
});
const setTime = useLastCallback((time: number) => {
setCurrentTime(time);
if (duration) {
setCurrentTime?.(time);
if (duration && proxy) {
setPlayProgress(proxy.currentTime / duration);
}
});

View File

@ -56,6 +56,7 @@ const useBuffering = (noInitiallyBuffered = false, onTimeUpdate?: AnyToVoidFunct
});
const bufferingHandlers = {
onPLay: handleBuffering,
onLoadedData: handleBuffering,
onPlaying: handleBuffering,
onLoadStart: handleBuffering, // Needed for Safari to start

View File

@ -6,7 +6,7 @@ import { AudioOrigin, GlobalSearchContent } from '../types';
import { requestNextMutation } from '../lib/fasterdom/fasterdom';
import { selectCurrentMessageList, selectTabState } from '../global/selectors';
import { getMessageKey, parseMessageKey } from './messageKey';
import { getMessageServerKey, parseMessageKey } from './messageKey';
import { isSafariPatchInProgress, patchSafariProgressiveAudio } from './patchSafariProgressiveAudio';
import safePlay from './safePlay';
import { IS_SAFARI } from './windowEnvironment';
@ -24,6 +24,7 @@ export interface Track {
}
const tracks = new Map<TrackId, Track>();
let voiceQueue: TrackId[] = [];
let musicQueue: TrackId[] = [];
@ -331,8 +332,12 @@ function findNextInQueue(currentId: TrackId, origin = AudioOrigin.Inline, isReve
return chatAudio[index + direction];
}
export function makeTrackId(message: ApiMessage): TrackId {
return `${getMessageKey(message)}-${message.date}`;
export function makeTrackId(message: ApiMessage): TrackId | undefined {
const key = getMessageServerKey(message);
if (!key) {
return undefined;
}
return `${key}-${message.date}`;
}
function splitTrackId(trackId: TrackId) {

View File

@ -8,7 +8,15 @@ export function getMessageKey(message: ApiMessage): MessageKey {
return buildMessageKey(chatId, previousLocalId || id);
}
function buildMessageKey(chatId: string, msgId: number): MessageKey {
export function getMessageServerKey(message: ApiMessage): MessageKey | undefined {
if (isLocalMessageId(message.id)) {
return undefined;
}
const { chatId, id } = message;
return buildMessageKey(chatId, id);
}
export function buildMessageKey(chatId: string, msgId: number): MessageKey {
return `msg${chatId}-${msgId}`;
}
@ -17,3 +25,7 @@ export function parseMessageKey(key: MessageKey) {
return { chatId: match[1], messageId: Number(match[2]) };
}
export function isLocalMessageId(id: number) {
return !Number.isInteger(id);
}