Media Viewer: Fix document preview slides (#6401)

This commit is contained in:
zubiden 2025-10-16 02:09:01 +02:00 committed by Alexander Zinchuk
parent 96901aec27
commit df263291da
8 changed files with 54 additions and 30 deletions

View File

@ -42,14 +42,16 @@ type OwnProps = {
autoLoadFileMaxSizeMb?: number; autoLoadFileMaxSizeMb?: number;
isDownloading?: boolean; isDownloading?: boolean;
shouldWarnAboutFiles?: boolean; shouldWarnAboutFiles?: boolean;
onCancelUpload?: () => void; id?: string;
onMediaClick?: () => void; onCancelUpload?: NoneToVoidFunction;
} & ({ } & ({
message: ApiMessage; message: ApiMessage;
onDateClick: (arg: ApiMessage) => void; onDateClick: (arg: ApiMessage) => void;
onMediaClick?: (messageId: number) => void;
} | { } | {
message?: ApiMessage; message?: ApiMessage;
onDateClick?: never; onDateClick?: never;
onMediaClick?: NoneToVoidFunction;
}); });
const BYTES_PER_MB = 1024 * 1024; const BYTES_PER_MB = 1024 * 1024;
@ -69,6 +71,7 @@ const Document = ({
shouldWarnAboutFiles, shouldWarnAboutFiles,
isDownloading, isDownloading,
message, message,
id,
onCancelUpload, onCancelUpload,
onMediaClick, onMediaClick,
onDateClick, onDateClick,
@ -161,7 +164,11 @@ const Document = ({
} }
if (withMediaViewer) { if (withMediaViewer) {
onMediaClick(); if (message) {
onMediaClick?.(message.id);
} else if (onMediaClick) {
(onMediaClick as NoneToVoidFunction)();
}
return; return;
} }
@ -187,6 +194,7 @@ const Document = ({
<> <>
<File <File
ref={ref} ref={ref}
id={id}
name={fileName} name={fileName}
extension={extension} extension={extension}
size={size} size={size}

View File

@ -27,6 +27,7 @@ import './File.scss';
type OwnProps = { type OwnProps = {
ref?: ElementRef<HTMLDivElement>; ref?: ElementRef<HTMLDivElement>;
id?: string;
name: string; name: string;
extension?: string; extension?: string;
size: number; size: number;
@ -48,6 +49,7 @@ type OwnProps = {
const File: FC<OwnProps> = ({ const File: FC<OwnProps> = ({
ref, ref,
id,
name, name,
size, size,
extension = '', extension = '',
@ -101,7 +103,7 @@ const File: FC<OwnProps> = ({
); );
return ( return (
<div ref={elementRef} className={fullClassName} dir={lang.isRtl ? 'rtl' : undefined}> <div id={id} ref={elementRef} className={fullClassName} dir={lang.isRtl ? 'rtl' : undefined}>
{isSelectable && ( {isSelectable && (
<div className="message-select-control no-selection"> <div className="message-select-control no-selection">
{isSelected && <Icon name="select" />} {isSelected && <Icon name="select" />}

View File

@ -18,6 +18,7 @@ import { type MediaViewerMedia, MediaViewerOrigin, type ThreadId } from '../../t
import { ANIMATION_END_DELAY } from '../../config'; import { ANIMATION_END_DELAY } from '../../config';
import { requestMutation } from '../../lib/fasterdom/fasterdom'; import { requestMutation } from '../../lib/fasterdom/fasterdom';
import { import {
getMediaSearchType,
getMessageContentIds, getMessageContentIds,
getMessagePaidMedia, isChatAdmin, getMessagePaidMedia, isChatAdmin,
} from '../../global/helpers'; } from '../../global/helpers';
@ -174,7 +175,7 @@ const MediaViewer = ({
const messageMediaIds = useMemo(() => { const messageMediaIds = useMemo(() => {
return withDynamicLoading return withDynamicLoading
? collectedMessageIds ? collectedMessageIds
: getMessageContentIds(chatMessages || {}, collectedMessageIds || [], contentType); : getMessageContentIds(chatMessages || {}, collectedMessageIds || [], contentType || 'media');
}, [chatMessages, collectedMessageIds, contentType, withDynamicLoading]); }, [chatMessages, collectedMessageIds, contentType, withDynamicLoading]);
if (isOpen && (!prevSenderId || prevSenderId !== senderId || animationKey.current === undefined)) { if (isOpen && (!prevSenderId || prevSenderId !== senderId || animationKey.current === undefined)) {
@ -353,7 +354,7 @@ const MediaViewer = ({
} }
const index = messageMediaIds?.indexOf(fromMessage.id); const index = messageMediaIds?.indexOf(fromMessage.id);
if (index === undefined) return undefined; if (index === undefined || index === -1) return undefined;
const nextIndex = index + direction; const nextIndex = index + direction;
const nextMessageId = messageMediaIds![nextIndex]; const nextMessageId = messageMediaIds![nextIndex];
const nextMessage = chatMessages?.[nextMessageId]; const nextMessage = chatMessages?.[nextMessageId];
@ -595,7 +596,8 @@ export default memo(withGlobal(
} else if (origin === MediaViewerOrigin.SharedMedia) { } else if (origin === MediaViewerOrigin.SharedMedia) {
const currentSearch = selectCurrentSharedMediaSearch(global); const currentSearch = selectCurrentSharedMediaSearch(global);
const resultsByType = currentSearch?.resultsByType; const resultsByType = currentSearch?.resultsByType;
const { foundIds } = (viewableMedia?.isGif ? resultsByType?.gif : resultsByType?.media) || {}; const contentType = viewableMedia && getMediaSearchType(viewableMedia?.media);
const { foundIds } = (contentType && resultsByType?.[contentType]) || {};
collectedMessageIds = foundIds; collectedMessageIds = foundIds;
} else if (isOriginInline || isOriginAlbum) { } else if (isOriginInline || isOriginAlbum) {
const outlyingList = selectOutlyingListByMessageId(global, chatId, threadId, messageId); const outlyingList = selectOutlyingListByMessageId(global, chatId, threadId, messageId);

View File

@ -2,7 +2,7 @@ import type {
ApiMessage, ApiPeer, ApiPeerPhotos, ApiSponsoredMessage, ApiMessage, ApiPeer, ApiPeerPhotos, ApiSponsoredMessage,
} from '../../../api/types'; } from '../../../api/types';
import type { GlobalState } from '../../../global/types'; import type { GlobalState } from '../../../global/types';
import { type MediaViewerMedia, MediaViewerOrigin } from '../../../types'; import type { MediaViewerMedia, MediaViewerOrigin } from '../../../types';
import { getMessageContent, isDocumentPhoto, isDocumentVideo } from '../../../global/helpers'; import { getMessageContent, isDocumentPhoto, isDocumentVideo } from '../../../global/helpers';
import { selectWebPageFromMessage } from '../../../global/selectors'; import { selectWebPageFromMessage } from '../../../global/selectors';
@ -28,7 +28,6 @@ export type MediaViewerItem = {
export type ViewableMedia = { export type ViewableMedia = {
media: MediaViewerMedia; media: MediaViewerMedia;
isGif?: boolean;
isSingle?: boolean; isSingle?: boolean;
}; };
@ -87,7 +86,6 @@ export default function selectViewableMedia(
const media = params.media[params.mediaIndex]; const media = params.media[params.mediaIndex];
return { return {
media, media,
isGif: media.mediaType === 'video' && media.isGif,
isSingle: params.media.length === 1, isSingle: params.media.length === 1,
}; };
} }
@ -139,7 +137,6 @@ export default function selectViewableMedia(
const { photo: extendedPhoto, video: extendedVideo } = extendedMedia; const { photo: extendedPhoto, video: extendedVideo } = extendedMedia;
return { return {
media: (extendedPhoto || extendedVideo)!, media: (extendedPhoto || extendedVideo)!,
isGif: extendedVideo?.isGif,
}; };
} }
} }
@ -149,8 +146,6 @@ export default function selectViewableMedia(
if (media) { if (media) {
return { return {
media, media,
isGif: video?.isGif,
isSingle: video?.isGif && origin !== MediaViewerOrigin.SharedMedia,
}; };
} }

View File

@ -1,13 +1,14 @@
import { useMemo } from '../../../lib/teact/teact'; import { useMemo } from '../../../lib/teact/teact';
import type { MediaViewerMedia } from '../../../types'; import type { MediaViewerMedia } from '../../../types';
import { ApiMediaFormat, type ApiMessageSearchType } from '../../../api/types'; import { ApiMediaFormat } from '../../../api/types';
import { MediaViewerOrigin } from '../../../types'; import { MediaViewerOrigin } from '../../../types';
import { import {
getMediaFileSize, getMediaFileSize,
getMediaFormat, getMediaFormat,
getMediaHash, getMediaHash,
getMediaSearchType,
getMediaThumbUri, getMediaThumbUri,
getPhotoFullDimensions, getPhotoFullDimensions,
getProfilePhotoMediaHash, getProfilePhotoMediaHash,
@ -46,7 +47,7 @@ export const useMediaProps = ({
const isFromSharedMedia = origin === MediaViewerOrigin.SharedMedia; const isFromSharedMedia = origin === MediaViewerOrigin.SharedMedia;
const isFromSearch = origin === MediaViewerOrigin.SearchResult; const isFromSearch = origin === MediaViewerOrigin.SearchResult;
const contentType: ApiMessageSearchType = isGif ? 'gif' : 'media'; const contentType = media && getMediaSearchType(media);
const getMediaOrAvatarHash = useMemo(() => (isFull?: boolean) => { const getMediaOrAvatarHash = useMemo(() => (isFull?: boolean) => {
if (!media) return undefined; if (!media) return undefined;

View File

@ -30,6 +30,7 @@ import {
getIsDownloading, getIsDownloading,
getIsSavedDialog, getIsSavedDialog,
getMessageDocument, getMessageDocument,
getMessageHtmlId,
isChatChannel, isChatChannel,
isChatGroup, isChatGroup,
isUserBot, isUserBot,
@ -903,6 +904,7 @@ const Profile = ({
(viewportIds as number[]).map((id) => messagesById[id] && ( (viewportIds as number[]).map((id) => messagesById[id] && (
<Document <Document
key={id} key={id}
id={`shared-media${getMessageHtmlId(id)}`}
document={getMessageDocument(messagesById[id])!} document={getMessageDocument(messagesById[id])!}
datetime={messagesById[id].date} datetime={messagesById[id].date}
smaller smaller
@ -912,6 +914,7 @@ const Profile = ({
onDateClick={handleMessageFocus} onDateClick={handleMessageFocus}
message={messagesById[id]} message={messagesById[id]}
shouldWarnAboutFiles={shouldWarnAboutFiles} shouldWarnAboutFiles={shouldWarnAboutFiles}
onMediaClick={handleSelectMedia}
/> />
)) ))
) : resultType === 'links' ? ( ) : resultType === 'links' ? (

View File

@ -479,7 +479,7 @@ async function searchChatMedia<T extends GlobalState>(
const loadingState = calcLoadingState(direction, limit, newFoundIds.length, currentSegment); const loadingState = calcLoadingState(direction, limit, newFoundIds.length, currentSegment);
const filteredIds = getMessageContentIds(byId, newFoundIds, 'inlineMedia'); const filteredIds = getMessageContentIds(byId, newFoundIds, 'media');
currentSegment = mergeWithChatMediaSearchSegment( currentSegment = mergeWithChatMediaSearchSegment(
filteredIds, filteredIds,
loadingState, loadingState,

View File

@ -465,8 +465,34 @@ export function getMediaTransferState(
}; };
} }
export function getMediaSearchType(media: DownloadableMedia):
Extract<ApiMessageSearchType, 'gif' | 'media' | 'documents' | 'audio' | 'voice'> | undefined {
if (media.mediaType === 'video') {
if (media.isRound) return 'voice';
return media.isGif ? 'gif' : 'media';
}
if (media.mediaType === 'audio') {
return 'audio';
}
if (media.mediaType === 'voice') {
return 'voice';
}
if (media.mediaType === 'document') {
return 'documents';
}
if (media.mediaType === 'photo') {
return 'media';
}
return undefined;
}
export function getMessageContentIds( export function getMessageContentIds(
messages: Record<number, ApiMessage>, messageIds: number[], contentType: ApiMessageSearchType | 'inlineMedia', messages: Record<number, ApiMessage>, messageIds: number[], contentType: ApiMessageSearchType,
) { ) {
let validator: (message: ApiMessage) => unknown; let validator: (message: ApiMessage) => unknown;
@ -504,19 +530,6 @@ export function getMessageContentIds(
}; };
break; break;
case 'inlineMedia':
validator = (message: ApiMessage) => {
const video = getMessageVideo(message);
const document = getMessageDocument(message);
return (
getMessagePhoto(message)
|| (video && !video.isRound && !video.isGif)
|| (document && isDocumentPhoto(document))
|| (document && isDocumentVideo(document))
);
};
break;
default: default:
return [] as Array<number>; return [] as Array<number>;
} }