[Perf] Reduce DOM manipulations when loading media

This commit is contained in:
Alexander Zinchuk 2021-11-05 21:57:35 +03:00
parent 334d41d53f
commit 7a6734037a
17 changed files with 160 additions and 197 deletions

View File

@ -7,7 +7,7 @@ import { ApiMediaFormat, ApiSticker } from '../../api/types';
import { LIKE_STICKER_ID } from './helpers/mediaDimensions';
import { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';
import useMedia from '../../hooks/useMedia';
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
import useMediaTransition from '../../hooks/useMediaTransition';
import useFlag from '../../hooks/useFlag';
import AnimatedSticker from './AnimatedSticker';
@ -51,7 +51,7 @@ const AnimatedEmoji: FC<OwnProps> = ({
ApiMediaFormat.BlobUrl,
lastSyncTime,
);
const { transitionClassNames } = useTransitionForMedia(previewBlobUrl, 'slow');
const transitionClassNames = useMediaTransition(previewBlobUrl);
const mediaData = useMedia(localMediaHash, !isIntersecting, ApiMediaFormat.Lottie, lastSyncTime);
const isMediaLoaded = Boolean(mediaData);

View File

@ -18,7 +18,7 @@ import { getFirstLetters } from '../../util/textFormat';
import buildClassName from '../../util/buildClassName';
import renderText from './helpers/renderText';
import useMedia from '../../hooks/useMedia';
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
import useShowTransition from '../../hooks/useShowTransition';
import useLang from '../../hooks/useLang';
import './Avatar.scss';
@ -59,7 +59,8 @@ const Avatar: FC<OwnProps> = ({
}
const blobUrl = useMedia(imageHash, false, ApiMediaFormat.BlobUrl, lastSyncTime);
const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(blobUrl, 'slow');
const hasBlobUrl = Boolean(blobUrl);
const { transitionClassNames } = useShowTransition(hasBlobUrl, undefined, hasBlobUrl, 'slow');
const lang = useLang();
@ -71,8 +72,10 @@ const Avatar: FC<OwnProps> = ({
content = <i className="icon-avatar-deleted-account" />;
} else if (isReplies) {
content = <i className="icon-reply-filled" />;
} else if (shouldRenderFullMedia) {
content = <img src={blobUrl} className={`${transitionClassNames} avatar-media`} alt="" decoding="async" />;
} else if (blobUrl) {
content = (
<img src={blobUrl} className={buildClassName('avatar-media', transitionClassNames)} alt="" decoding="async" />
);
} else if (user) {
const userFullName = getUserFullName(user);
content = userFullName ? getFirstLetters(userFullName, 2) : undefined;
@ -93,14 +96,15 @@ const Avatar: FC<OwnProps> = ({
isReplies && 'replies-bot-account',
withOnlineStatus && isOnline && 'online',
onClick && 'interactive',
(!isSavedMessages && !shouldRenderFullMedia) && 'no-photo',
(!isSavedMessages && !blobUrl) && 'no-photo',
);
const hasImage = Boolean(isSavedMessages || blobUrl);
const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
if (onClick) {
onClick(e, isSavedMessages || shouldRenderFullMedia);
onClick(e, hasImage);
}
}, [onClick, isSavedMessages, shouldRenderFullMedia]);
}, [onClick, hasImage]);
const senderId = (user || chat) && (user || chat)!.id;

View File

@ -2,7 +2,7 @@ import { RefObject } from 'react';
import React, { FC, memo, useRef } from '../../lib/teact/teact';
import useShowTransition from '../../hooks/useShowTransition';
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
import useMediaTransition from '../../hooks/useMediaTransition';
import buildClassName from '../../util/buildClassName';
import { formatMediaDateTime, formatPastTimeShort } from '../../util/dateFormat';
import { getColorFromExtension, getFileSizeString } from './helpers/documentInfo';
@ -63,16 +63,15 @@ const File: FC<OwnProps> = ({
elementRef = ref;
}
const transitionClassNames = useMediaTransition(previewData);
const {
shouldRender: shouldSpinnerRender,
transitionClassNames: spinnerClassNames,
} = useShowTransition(isTransferring, undefined, true);
const color = getColorFromExtension(extension);
const sizeString = getFileSizeString(size);
const {
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
} = useTransitionForMedia(previewData, 'slow');
const { width, height } = getDocumentThumbnailDimensions(smaller);
const fullClassName = buildClassName(
@ -93,24 +92,20 @@ const File: FC<OwnProps> = ({
<div className="file-icon-container" onClick={isUploading ? undefined : onClick}>
{thumbnailDataUri || previewData ? (
<div className="file-preview media-inner">
{shouldRenderThumb && (
<img
src={thumbnailDataUri}
width={width}
height={height}
className="thumbnail"
alt=""
/>
)}
{shouldRenderFullMedia && (
<img
src={previewData}
className={`full-media ${transitionClassNames}`}
width={width}
height={height}
alt=""
/>
)}
<img
src={thumbnailDataUri}
width={width}
height={height}
className="thumbnail"
alt=""
/>
<img
src={previewData}
className={buildClassName('full-media', transitionClassNames)}
width={width}
height={height}
alt=""
/>
</div>
) : (
<div className={`file-icon ${color}`}>

View File

@ -8,8 +8,9 @@ import {
getMessageMediaThumbDataUri,
getMessageVideo,
} from '../../modules/helpers';
import buildClassName from '../../util/buildClassName';
import useMedia from '../../hooks/useMedia';
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
import useMediaTransition from '../../hooks/useMediaTransition';
import './Media.scss';
@ -26,20 +27,14 @@ const Media: FC<OwnProps> = ({ message, idPrefix = 'shared-media', onClick }) =>
const thumbDataUri = getMessageMediaThumbDataUri(message);
const mediaBlobUrl = useMedia(getMessageMediaHash(message, 'pictogram'));
const {
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
} = useTransitionForMedia(mediaBlobUrl, 'slow');
const transitionClassNames = useMediaTransition(mediaBlobUrl);
const video = getMessageVideo(message);
return (
<div id={`${idPrefix}${message.id}`} className="Media scroll-item" onClick={onClick ? handleClick : undefined}>
{shouldRenderThumb && (
<img src={thumbDataUri} alt="" />
)}
{shouldRenderFullMedia && (
<img src={mediaBlobUrl} className={`${transitionClassNames} full-media`} alt="" />
)}
<img src={thumbDataUri} alt="" />
<img src={mediaBlobUrl} className={buildClassName('full-media', transitionClassNames)} alt="" />
{video && <span className="video-duration">{video.isGif ? 'GIF' : formatMediaDuration(video.duration)}</span>}
</div>
);

View File

@ -7,7 +7,7 @@ import { ApiMediaFormat, ApiSticker } from '../../api/types';
import { useIsIntersecting, ObserveFn } from '../../hooks/useIntersectionObserver';
import useMedia from '../../hooks/useMedia';
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
import useShowTransition from '../../hooks/useShowTransition';
import useFlag from '../../hooks/useFlag';
import buildClassName from '../../util/buildClassName';
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
@ -48,11 +48,12 @@ const StickerButton: FC<OwnProps> = ({
const [isAnimationLoaded, markLoaded, unmarkLoaded] = useFlag(Boolean(lottieData));
const canAnimatedPlay = isAnimationLoaded && shouldPlay;
const {
shouldRenderThumb,
shouldRenderFullMedia: shouldRenderPreview,
transitionClassNames: previewTransitionClassNames,
} = useTransitionForMedia(previewBlobUrl || canAnimatedPlay, 'slow');
const { transitionClassNames: previewTransitionClassNames } = useShowTransition(
Boolean(previewBlobUrl || canAnimatedPlay),
undefined,
undefined,
'slow',
);
// To avoid flickering
useEffect(() => {
@ -82,7 +83,7 @@ const StickerButton: FC<OwnProps> = ({
className,
);
const style = shouldRenderThumb && thumbDataUri ? `background-image: url('${thumbDataUri}');` : '';
const style = thumbDataUri ? `background-image: url('${thumbDataUri}');` : '';
return (
<div
@ -95,7 +96,7 @@ const StickerButton: FC<OwnProps> = ({
onMouseDown={preventMessageInputBlurWithBubbling}
onClick={handleClick}
>
{shouldRenderPreview && !canAnimatedPlay && (
{!canAnimatedPlay && (
// eslint-disable-next-line jsx-a11y/alt-text
<img src={previewBlobUrl} className={previewTransitionClassNames} />
)}

View File

@ -7,7 +7,6 @@ import { ThemeKey, UPLOADING_WALLPAPER_SLUG } from '../../../types';
import { CUSTOM_BG_CACHE_NAME } from '../../../config';
import * as cacheApi from '../../../util/cacheApi';
import { fetchBlob } from '../../../util/files';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import buildClassName from '../../../util/buildClassName';
import useMedia from '../../../hooks/useMedia';
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
@ -37,9 +36,12 @@ const WallpaperTile: FC<OwnProps> = ({
const localBlobUrl = document.previewBlobUrl;
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`);
const thumbRef = useCanvasBlur(document.thumbnail?.dataUri, Boolean(previewBlobUrl), true);
const {
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
} = useTransitionForMedia(previewBlobUrl || localBlobUrl, 'slow');
const { transitionClassNames } = useShowTransition(
Boolean(previewBlobUrl || localBlobUrl),
undefined,
undefined,
'slow',
);
const [isLoadAllowed, setIsLoadAllowed] = useState(false);
const {
mediaData: fullMedia, loadProgress,
@ -85,19 +87,15 @@ const WallpaperTile: FC<OwnProps> = ({
return (
<div className={className} onClick={handleClick}>
<div className="media-inner">
{shouldRenderThumb && (
<canvas
ref={thumbRef}
className="thumbnail"
/>
)}
{shouldRenderFullMedia && (
<img
src={previewBlobUrl || localBlobUrl}
className={`full-media ${transitionClassNames}`}
alt=""
/>
)}
<canvas
ref={thumbRef}
className="thumbnail"
/>
<img
src={previewBlobUrl || localBlobUrl}
className={buildClassName('full-media', transitionClassNames)}
alt=""
/>
{shouldRenderSpinner && (
<div className={buildClassName('spinner-container', spinnerClassNames)}>
<ProgressSpinner progress={loadProgress} onClick={handleClick} />

View File

@ -4,7 +4,7 @@ import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import buildClassName from '../../../util/buildClassName';
import windowSize from '../../../util/windowSize';
import { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver';
import useShowTransition from '../../../hooks/useShowTransition';
import useMediaTransition from '../../../hooks/useMediaTransition';
import useLang from '../../../hooks/useLang';
import EmojiButton from './EmojiButton';
@ -31,7 +31,7 @@ const EmojiCategory: FC<OwnProps> = ({
useOnIntersect(ref, observeIntersection);
const { transitionClassNames } = useShowTransition(shouldRender, undefined, undefined, 'slow');
const transitionClassNames = useMediaTransition(shouldRender);
const lang = useLang();

View File

@ -8,7 +8,7 @@ import { STICKER_SIZE_PICKER } from '../../../config';
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
import windowSize from '../../../util/windowSize';
import StickerButton from '../../common/StickerButton';
import useShowTransition from '../../../hooks/useShowTransition';
import useMediaTransition from '../../../hooks/useMediaTransition';
import buildClassName from '../../../util/buildClassName';
type OwnProps = {
@ -39,7 +39,7 @@ const StickerSet: FC<OwnProps> = ({
useOnIntersect(ref, observeIntersection);
const { transitionClassNames } = useShowTransition(shouldRender, undefined, undefined, 'slow');
const transitionClassNames = useMediaTransition(shouldRender);
const stickersPerRow = IS_SINGLE_COLUMN_LAYOUT
? Math.floor((windowSize.get().width - MOBILE_CONTAINER_PADDING) / (STICKER_SIZE_PICKER + STICKER_MARGIN))

View File

@ -1,11 +1,13 @@
import React, { FC, memo, useRef } from '../../../lib/teact/teact';
import React, {
FC, memo, useMemo, useRef,
} from '../../../lib/teact/teact';
import { ApiStickerSet } from '../../../api/types';
import { getFirstLetters } from '../../../util/textFormat';
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMedia from '../../../hooks/useMedia';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import { getFirstLetters } from '../../../util/textFormat';
import useMediaTransition from '../../../hooks/useMediaTransition';
type OwnProps = {
stickerSet: ApiStickerSet;
@ -19,14 +21,18 @@ const StickerSetCover: FC<OwnProps> = ({ stickerSet, observeIntersection }) => {
const isIntersecting = useIsIntersecting(ref, observeIntersection);
const mediaData = useMedia(stickerSet.hasThumbnail && `stickerSet${stickerSet.id}`, !isIntersecting);
const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(mediaData, 'slow');
const transitionClassNames = useMediaTransition(mediaData);
const firstLetters = useMemo(() => {
if (mediaData) return undefined;
return getFirstLetters(stickerSet.title, 2);
}, [mediaData, stickerSet.title]);
return (
<div ref={ref} className="sticker-set-cover">
{!shouldRenderFullMedia && getFirstLetters(stickerSet.title, 2)}
{shouldRenderFullMedia && (
<img src={mediaData} className={transitionClassNames} alt="" />
)}
{firstLetters}
<img src={mediaData} className={transitionClassNames} alt="" />
</div>
);
};

View File

@ -1,11 +1,13 @@
import React, { FC, memo, useRef } from '../../../lib/teact/teact';
import React, {
FC, memo, useMemo, useRef,
} from '../../../lib/teact/teact';
import { ApiMediaFormat, ApiStickerSet } from '../../../api/types';
import { STICKER_SIZE_PICKER_HEADER } from '../../../config';
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMedia from '../../../hooks/useMedia';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import useMediaTransition from '../../../hooks/useMediaTransition';
import { getFirstLetters } from '../../../util/textFormat';
import AnimatedSticker from '../../common/AnimatedSticker';
@ -28,12 +30,18 @@ const StickerSetCoverAnimated: FC<OwnProps> = ({
const mediaHash = `stickerSet${stickerSet.id}`;
const lottieData = useMedia(mediaHash, !isIntersecting, ApiMediaFormat.Lottie);
const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(lottieData, 'slow');
const transitionClassNames = useMediaTransition(lottieData);
const firstLetters = useMemo(() => {
if (lottieData) return undefined;
return getFirstLetters(stickerSet.title, 2);
}, [lottieData, stickerSet.title]);
return (
<div ref={ref} className="sticker-set-cover">
{!shouldRenderFullMedia && getFirstLetters(stickerSet.title, 2)}
{shouldRenderFullMedia && lottieData && (
{firstLetters}
{lottieData && (
<AnimatedSticker
id={mediaHash}
size={size}

View File

@ -4,8 +4,9 @@ import {
ApiBotInlineMediaResult, ApiBotInlineResult, ApiPhoto, ApiThumbnail, ApiWebDocument,
} from '../../../../api/types';
import buildClassName from '../../../../util/buildClassName';
import useMedia from '../../../../hooks/useMedia';
import useTransitionForMedia from '../../../../hooks/useTransitionForMedia';
import useMediaTransition from '../../../../hooks/useMediaTransition';
import BaseResult from './BaseResult';
@ -38,9 +39,7 @@ const MediaResult: FC<OwnProps> = ({
const thumbnailDataUrl = useMedia(webThumbnail ? `webDocument:${webThumbnail.url}` : undefined);
const mediaBlobUrl = useMedia(photo && `photo${photo.id}?size=m`);
const {
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
} = useTransitionForMedia(mediaBlobUrl, 'slow');
const transitionClassNames = useMediaTransition(mediaBlobUrl);
const handleClick = useCallback(() => {
onClick(inlineResult);
@ -49,12 +48,8 @@ const MediaResult: FC<OwnProps> = ({
if (isForGallery) {
return (
<div className="MediaResult chat-item-clickable" onClick={handleClick}>
{shouldRenderThumb && (
<img src={(photo?.thumbnail?.dataUri) || thumbnailDataUrl} alt="" />
)}
{shouldRenderFullMedia && (
<img src={mediaBlobUrl} className={`${transitionClassNames} full-media`} alt="" />
)}
<img src={(photo?.thumbnail?.dataUri) || thumbnailDataUrl} alt="" />
<img src={mediaBlobUrl} className={buildClassName('full-media', transitionClassNames)} alt="" />
</div>
);
}
@ -64,8 +59,8 @@ const MediaResult: FC<OwnProps> = ({
return (
<BaseResult
focus={focus}
thumbUrl={shouldRenderFullMedia ? mediaBlobUrl : (thumbnail?.dataUri || thumbnailDataUrl)}
transitionClassNames={shouldRenderFullMedia ? transitionClassNames : undefined}
thumbUrl={mediaBlobUrl || (thumbnail?.dataUri || thumbnailDataUrl)}
transitionClassNames={transitionClassNames}
title={title}
description={description}
onClick={handleClick}

View File

@ -15,7 +15,6 @@ import {
} from '../../../modules/helpers';
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import useShowTransition from '../../../hooks/useShowTransition';
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
import usePrevious from '../../../hooks/usePrevious';
@ -24,6 +23,7 @@ import getCustomAppendixBg from './helpers/getCustomAppendixBg';
import { calculateMediaDimensions } from './helpers/mediaDimensions';
import ProgressSpinner from '../../ui/ProgressSpinner';
import useMediaTransition from '../../../hooks/useMediaTransition';
export type OwnProps = {
id?: string;
@ -92,13 +92,12 @@ const Photo: FC<OwnProps> = ({
shouldLoad && !fullMediaData,
);
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
const transitionClassNames = useMediaTransition(fullMediaData);
const {
shouldRender: shouldRenderSpinner,
transitionClassNames: spinnerClassNames,
} = useShowTransition(isTransferring, undefined, wasLoadDisabled, 'slow');
const {
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
} = useTransitionForMedia(fullMediaData, 'slow');
const handleClick = useCallback(() => {
if (isUploading) {
@ -152,23 +151,19 @@ const Photo: FC<OwnProps> = ({
style={style}
onClick={isUploading ? undefined : handleClick}
>
{shouldRenderThumb && (
<canvas
ref={thumbRef}
className="thumbnail"
// @ts-ignore teact feature
style={`width: ${width}px; height: ${height}px`}
/>
)}
{shouldRenderFullMedia && (
<img
src={fullMediaData}
className={`full-media ${transitionClassNames}`}
width={width}
height={height}
alt=""
/>
)}
<canvas
ref={thumbRef}
className="thumbnail"
// @ts-ignore teact feature
style={`width: ${width}px; height: ${height}px`}
/>
<img
src={fullMediaData}
className={`full-media ${transitionClassNames}`}
width={width}
height={height}
alt=""
/>
{shouldRenderSpinner && (
<div className={`media-loading ${spinnerClassNames}`}>
<ProgressSpinner progress={transferProgress} onClick={isUploading ? handleClick : undefined} />

View File

@ -10,22 +10,22 @@ import { getDispatch } from '../../../lib/teact/teactn';
import { ApiMediaFormat, ApiMessage } from '../../../api/types';
import { ROUND_VIDEO_DIMENSIONS_PX } from '../../common/helpers/mediaDimensions';
import { formatMediaDuration } from '../../../util/dateFormat';
import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';
import { formatMediaDuration } from '../../../util/dateFormat';
import buildClassName from '../../../util/buildClassName';
import { stopCurrentAudio } from '../../../util/audioPlayer';
import safePlay from '../../../util/safePlay';
import { fastRaf } from '../../../util/schedulers';
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
import useShowTransition from '../../../hooks/useShowTransition';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import useMediaTransition from '../../../hooks/useMediaTransition';
import usePrevious from '../../../hooks/usePrevious';
import useBuffering from '../../../hooks/useBuffering';
import buildClassName from '../../../util/buildClassName';
import { stopCurrentAudio } from '../../../util/audioPlayer';
import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';
import useVideoCleanup from '../../../hooks/useVideoCleanup';
import usePauseOnInactive from './hooks/usePauseOnInactive';
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
import safePlay from '../../../util/safePlay';
import { fastRaf } from '../../../util/schedulers';
import ProgressSpinner from '../../ui/ProgressSpinner';
@ -91,11 +91,12 @@ const RoundVideo: FC<OwnProps> = ({
const { isBuffered, bufferingHandlers } = useBuffering();
const isTransferring = (isLoadAllowed && !isBuffered) || isDownloading;
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
const transitionClassNames = useMediaTransition(mediaData);
const {
shouldRender: shouldSpinnerRender,
transitionClassNames: spinnerClassNames,
} = useShowTransition(isTransferring || !isBuffered, undefined, wasLoadDisabled);
const { shouldRenderThumb, transitionClassNames } = useTransitionForMedia(mediaData, 'slow');
const [isActivated, setIsActivated] = useState<boolean>(false);
const [progress, setProgress] = useState<number>(0);
@ -206,16 +207,14 @@ const RoundVideo: FC<OwnProps> = ({
className="RoundVideo media-inner"
onClick={handleClick}
>
{(shouldRenderThumb || mediaData) && (
<div className="thumbnail-wrapper">
<canvas
ref={thumbRef}
className="thumbnail"
// @ts-ignore teact feature
style={`width: ${ROUND_VIDEO_DIMENSIONS_PX}px; height: ${ROUND_VIDEO_DIMENSIONS_PX}px`}
/>
</div>
)}
<div className="thumbnail-wrapper">
<canvas
ref={thumbRef}
className="thumbnail"
// @ts-ignore teact feature
style={`width: ${ROUND_VIDEO_DIMENSIONS_PX}px; height: ${ROUND_VIDEO_DIMENSIONS_PX}px`}
/>
</div>
{mediaData && (
<div className="video-wrapper">
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}

View File

@ -5,10 +5,10 @@ import { ApiMessage } from '../../../api/types';
import { MEMOJI_STICKER_ID } from '../../../config';
import { getStickerDimensions } from '../../common/helpers/mediaDimensions';
import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';
import useMedia from '../../../hooks/useMedia';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import buildClassName from '../../../util/buildClassName';
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
import useMedia from '../../../hooks/useMedia';
import useMediaTransition from '../../../hooks/useMediaTransition';
import useFlag from '../../../hooks/useFlag';
import useWebpThumbnail from '../../../hooks/useWebpThumbnail';
@ -52,7 +52,7 @@ const Sticker: FC<OwnProps> = ({
const isMediaLoaded = Boolean(mediaData);
const [isAnimationLoaded, markAnimationLoaded] = useFlag(isMediaLoaded);
const isMediaReady = isAnimated ? isAnimationLoaded : isMediaLoaded;
const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(isMediaReady, 'slow');
const transitionClassNames = useMediaTransition(isMediaReady);
const { width, height } = getStickerDimensions(sticker);
const thumbClassName = buildClassName('thumbnail', !thumbDataUri && 'empty');
@ -74,7 +74,7 @@ const Sticker: FC<OwnProps> = ({
className={thumbClassName}
/>
)}
{!isAnimated && shouldRenderFullMedia && (
{!isAnimated && (
<img
id={`sticker-${message.id}`}
src={mediaData as string}

View File

@ -22,7 +22,6 @@ import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObse
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
import useMedia from '../../../hooks/useMedia';
import useShowTransition from '../../../hooks/useShowTransition';
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
import usePrevious from '../../../hooks/usePrevious';
import useBuffering from '../../../hooks/useBuffering';
import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';
@ -81,11 +80,12 @@ const Video: FC<OwnProps> = ({
getMessageMediaFormat(message, 'pictogram'),
lastSyncTime,
);
const {
shouldRenderThumb,
shouldRenderFullMedia: shouldRenderPreview,
transitionClassNames: previewClassNames,
} = useTransitionForMedia(previewBlobUrl, 'slow');
const { transitionClassNames: previewClassNames } = useShowTransition(
Boolean(previewBlobUrl),
undefined,
undefined,
'slow',
);
const { mediaData, loadProgress } = useMediaWithLoadProgress(
getMessageMediaHash(message, 'inline'),
@ -163,23 +163,19 @@ const Video: FC<OwnProps> = ({
style={style}
onClick={isUploading ? undefined : handleClick}
>
{shouldRenderThumb && (
<canvas
ref={thumbRef}
className="thumbnail"
// @ts-ignore teact feature
style={`width: ${width}px; height: ${height}px;`}
/>
)}
{shouldRenderPreview && (
<img
src={previewBlobUrl}
className={buildClassName('thumbnail', previewClassNames)}
// @ts-ignore teact feature
style={`width: ${width}px; height: ${height}px;`}
alt=""
/>
)}
<canvas
ref={thumbRef}
className="thumbnail"
// @ts-ignore teact feature
style={`width: ${width}px; height: ${height}px;`}
/>
<img
src={previewBlobUrl}
className={buildClassName('thumbnail', previewClassNames)}
// @ts-ignore teact feature
style={`width: ${width}px; height: ${height}px;`}
alt=""
/>
{isInline && (
<video
ref={videoRef}

View File

@ -0,0 +1,8 @@
import useShowTransition from './useShowTransition';
export default function useMediaTransition(mediaData?: any) {
const isMediaReady = Boolean(mediaData);
const { transitionClassNames } = useShowTransition(isMediaReady, undefined, isMediaReady, 'slow');
return transitionClassNames;
}

View File

@ -1,37 +0,0 @@
import { useEffect, useRef, useState } from '../lib/teact/teact';
import useShowTransition from './useShowTransition';
const SPEED = {
fast: 200,
slow: 350,
};
export default (mediaData?: any, speed: keyof typeof SPEED = 'fast', noAnimate = false) => {
const isMediaLoaded = Boolean(mediaData);
const willAnimate = !useRef(isMediaLoaded).current && !noAnimate;
const [shouldRenderThumb, setShouldRenderThumb] = useState(!isMediaLoaded);
const {
shouldRender: shouldRenderFullMedia,
transitionClassNames,
} = useShowTransition(isMediaLoaded, undefined, !willAnimate, speed);
useEffect(() => {
if (shouldRenderFullMedia) {
if (willAnimate) {
setTimeout(() => {
setShouldRenderThumb(false);
}, SPEED[speed]);
} else {
setShouldRenderThumb(false);
}
}
}, [willAnimate, shouldRenderFullMedia, speed]);
return {
shouldRenderThumb,
shouldRenderFullMedia,
transitionClassNames,
};
};