[Perf] Reduce DOM manipulations when loading media
This commit is contained in:
parent
334d41d53f
commit
7a6734037a
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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}`}>
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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} />
|
||||
)}
|
||||
|
||||
@ -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} />
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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} />
|
||||
|
||||
@ -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 */}
|
||||
|
||||
@ -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}
|
||||
|
||||
@ -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}
|
||||
|
||||
8
src/hooks/useMediaTransition.ts
Normal file
8
src/hooks/useMediaTransition.ts
Normal 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;
|
||||
}
|
||||
@ -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,
|
||||
};
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user