[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 { LIKE_STICKER_ID } from './helpers/mediaDimensions';
|
||||||
import { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';
|
import { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';
|
||||||
import useMedia from '../../hooks/useMedia';
|
import useMedia from '../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
|
|
||||||
import AnimatedSticker from './AnimatedSticker';
|
import AnimatedSticker from './AnimatedSticker';
|
||||||
@ -51,7 +51,7 @@ const AnimatedEmoji: FC<OwnProps> = ({
|
|||||||
ApiMediaFormat.BlobUrl,
|
ApiMediaFormat.BlobUrl,
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
);
|
);
|
||||||
const { transitionClassNames } = useTransitionForMedia(previewBlobUrl, 'slow');
|
const transitionClassNames = useMediaTransition(previewBlobUrl);
|
||||||
|
|
||||||
const mediaData = useMedia(localMediaHash, !isIntersecting, ApiMediaFormat.Lottie, lastSyncTime);
|
const mediaData = useMedia(localMediaHash, !isIntersecting, ApiMediaFormat.Lottie, lastSyncTime);
|
||||||
const isMediaLoaded = Boolean(mediaData);
|
const isMediaLoaded = Boolean(mediaData);
|
||||||
|
|||||||
@ -18,7 +18,7 @@ import { getFirstLetters } from '../../util/textFormat';
|
|||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import renderText from './helpers/renderText';
|
import renderText from './helpers/renderText';
|
||||||
import useMedia from '../../hooks/useMedia';
|
import useMedia from '../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
|
import useShowTransition from '../../hooks/useShowTransition';
|
||||||
import useLang from '../../hooks/useLang';
|
import useLang from '../../hooks/useLang';
|
||||||
|
|
||||||
import './Avatar.scss';
|
import './Avatar.scss';
|
||||||
@ -59,7 +59,8 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const blobUrl = useMedia(imageHash, false, ApiMediaFormat.BlobUrl, lastSyncTime);
|
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();
|
const lang = useLang();
|
||||||
|
|
||||||
@ -71,8 +72,10 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
content = <i className="icon-avatar-deleted-account" />;
|
content = <i className="icon-avatar-deleted-account" />;
|
||||||
} else if (isReplies) {
|
} else if (isReplies) {
|
||||||
content = <i className="icon-reply-filled" />;
|
content = <i className="icon-reply-filled" />;
|
||||||
} else if (shouldRenderFullMedia) {
|
} else if (blobUrl) {
|
||||||
content = <img src={blobUrl} className={`${transitionClassNames} avatar-media`} alt="" decoding="async" />;
|
content = (
|
||||||
|
<img src={blobUrl} className={buildClassName('avatar-media', transitionClassNames)} alt="" decoding="async" />
|
||||||
|
);
|
||||||
} else if (user) {
|
} else if (user) {
|
||||||
const userFullName = getUserFullName(user);
|
const userFullName = getUserFullName(user);
|
||||||
content = userFullName ? getFirstLetters(userFullName, 2) : undefined;
|
content = userFullName ? getFirstLetters(userFullName, 2) : undefined;
|
||||||
@ -93,14 +96,15 @@ const Avatar: FC<OwnProps> = ({
|
|||||||
isReplies && 'replies-bot-account',
|
isReplies && 'replies-bot-account',
|
||||||
withOnlineStatus && isOnline && 'online',
|
withOnlineStatus && isOnline && 'online',
|
||||||
onClick && 'interactive',
|
onClick && 'interactive',
|
||||||
(!isSavedMessages && !shouldRenderFullMedia) && 'no-photo',
|
(!isSavedMessages && !blobUrl) && 'no-photo',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const hasImage = Boolean(isSavedMessages || blobUrl);
|
||||||
const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
|
const handleClick = useCallback((e: ReactMouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
onClick(e, isSavedMessages || shouldRenderFullMedia);
|
onClick(e, hasImage);
|
||||||
}
|
}
|
||||||
}, [onClick, isSavedMessages, shouldRenderFullMedia]);
|
}, [onClick, hasImage]);
|
||||||
|
|
||||||
const senderId = (user || chat) && (user || chat)!.id;
|
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 React, { FC, memo, useRef } from '../../lib/teact/teact';
|
||||||
|
|
||||||
import useShowTransition from '../../hooks/useShowTransition';
|
import useShowTransition from '../../hooks/useShowTransition';
|
||||||
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { formatMediaDateTime, formatPastTimeShort } from '../../util/dateFormat';
|
import { formatMediaDateTime, formatPastTimeShort } from '../../util/dateFormat';
|
||||||
import { getColorFromExtension, getFileSizeString } from './helpers/documentInfo';
|
import { getColorFromExtension, getFileSizeString } from './helpers/documentInfo';
|
||||||
@ -63,16 +63,15 @@ const File: FC<OwnProps> = ({
|
|||||||
elementRef = ref;
|
elementRef = ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const transitionClassNames = useMediaTransition(previewData);
|
||||||
const {
|
const {
|
||||||
shouldRender: shouldSpinnerRender,
|
shouldRender: shouldSpinnerRender,
|
||||||
transitionClassNames: spinnerClassNames,
|
transitionClassNames: spinnerClassNames,
|
||||||
} = useShowTransition(isTransferring, undefined, true);
|
} = useShowTransition(isTransferring, undefined, true);
|
||||||
|
|
||||||
const color = getColorFromExtension(extension);
|
const color = getColorFromExtension(extension);
|
||||||
const sizeString = getFileSizeString(size);
|
const sizeString = getFileSizeString(size);
|
||||||
|
|
||||||
const {
|
|
||||||
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
|
|
||||||
} = useTransitionForMedia(previewData, 'slow');
|
|
||||||
const { width, height } = getDocumentThumbnailDimensions(smaller);
|
const { width, height } = getDocumentThumbnailDimensions(smaller);
|
||||||
|
|
||||||
const fullClassName = buildClassName(
|
const fullClassName = buildClassName(
|
||||||
@ -93,24 +92,20 @@ const File: FC<OwnProps> = ({
|
|||||||
<div className="file-icon-container" onClick={isUploading ? undefined : onClick}>
|
<div className="file-icon-container" onClick={isUploading ? undefined : onClick}>
|
||||||
{thumbnailDataUri || previewData ? (
|
{thumbnailDataUri || previewData ? (
|
||||||
<div className="file-preview media-inner">
|
<div className="file-preview media-inner">
|
||||||
{shouldRenderThumb && (
|
<img
|
||||||
<img
|
src={thumbnailDataUri}
|
||||||
src={thumbnailDataUri}
|
width={width}
|
||||||
width={width}
|
height={height}
|
||||||
height={height}
|
className="thumbnail"
|
||||||
className="thumbnail"
|
alt=""
|
||||||
alt=""
|
/>
|
||||||
/>
|
<img
|
||||||
)}
|
src={previewData}
|
||||||
{shouldRenderFullMedia && (
|
className={buildClassName('full-media', transitionClassNames)}
|
||||||
<img
|
width={width}
|
||||||
src={previewData}
|
height={height}
|
||||||
className={`full-media ${transitionClassNames}`}
|
alt=""
|
||||||
width={width}
|
/>
|
||||||
height={height}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className={`file-icon ${color}`}>
|
<div className={`file-icon ${color}`}>
|
||||||
|
|||||||
@ -8,8 +8,9 @@ import {
|
|||||||
getMessageMediaThumbDataUri,
|
getMessageMediaThumbDataUri,
|
||||||
getMessageVideo,
|
getMessageVideo,
|
||||||
} from '../../modules/helpers';
|
} from '../../modules/helpers';
|
||||||
|
import buildClassName from '../../util/buildClassName';
|
||||||
import useMedia from '../../hooks/useMedia';
|
import useMedia from '../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../hooks/useMediaTransition';
|
||||||
|
|
||||||
import './Media.scss';
|
import './Media.scss';
|
||||||
|
|
||||||
@ -26,20 +27,14 @@ const Media: FC<OwnProps> = ({ message, idPrefix = 'shared-media', onClick }) =>
|
|||||||
|
|
||||||
const thumbDataUri = getMessageMediaThumbDataUri(message);
|
const thumbDataUri = getMessageMediaThumbDataUri(message);
|
||||||
const mediaBlobUrl = useMedia(getMessageMediaHash(message, 'pictogram'));
|
const mediaBlobUrl = useMedia(getMessageMediaHash(message, 'pictogram'));
|
||||||
const {
|
const transitionClassNames = useMediaTransition(mediaBlobUrl);
|
||||||
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
|
|
||||||
} = useTransitionForMedia(mediaBlobUrl, 'slow');
|
|
||||||
|
|
||||||
const video = getMessageVideo(message);
|
const video = getMessageVideo(message);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={`${idPrefix}${message.id}`} className="Media scroll-item" onClick={onClick ? handleClick : undefined}>
|
<div id={`${idPrefix}${message.id}`} className="Media scroll-item" onClick={onClick ? handleClick : undefined}>
|
||||||
{shouldRenderThumb && (
|
<img src={thumbDataUri} alt="" />
|
||||||
<img src={thumbDataUri} alt="" />
|
<img src={mediaBlobUrl} className={buildClassName('full-media', transitionClassNames)} alt="" />
|
||||||
)}
|
|
||||||
{shouldRenderFullMedia && (
|
|
||||||
<img src={mediaBlobUrl} className={`${transitionClassNames} full-media`} alt="" />
|
|
||||||
)}
|
|
||||||
{video && <span className="video-duration">{video.isGif ? 'GIF' : formatMediaDuration(video.duration)}</span>}
|
{video && <span className="video-duration">{video.isGif ? 'GIF' : formatMediaDuration(video.duration)}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { ApiMediaFormat, ApiSticker } from '../../api/types';
|
|||||||
|
|
||||||
import { useIsIntersecting, ObserveFn } from '../../hooks/useIntersectionObserver';
|
import { useIsIntersecting, ObserveFn } from '../../hooks/useIntersectionObserver';
|
||||||
import useMedia from '../../hooks/useMedia';
|
import useMedia from '../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
|
import useShowTransition from '../../hooks/useShowTransition';
|
||||||
import useFlag from '../../hooks/useFlag';
|
import useFlag from '../../hooks/useFlag';
|
||||||
import buildClassName from '../../util/buildClassName';
|
import buildClassName from '../../util/buildClassName';
|
||||||
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
import { preventMessageInputBlurWithBubbling } from '../middle/helpers/preventMessageInputBlur';
|
||||||
@ -48,11 +48,12 @@ const StickerButton: FC<OwnProps> = ({
|
|||||||
const [isAnimationLoaded, markLoaded, unmarkLoaded] = useFlag(Boolean(lottieData));
|
const [isAnimationLoaded, markLoaded, unmarkLoaded] = useFlag(Boolean(lottieData));
|
||||||
const canAnimatedPlay = isAnimationLoaded && shouldPlay;
|
const canAnimatedPlay = isAnimationLoaded && shouldPlay;
|
||||||
|
|
||||||
const {
|
const { transitionClassNames: previewTransitionClassNames } = useShowTransition(
|
||||||
shouldRenderThumb,
|
Boolean(previewBlobUrl || canAnimatedPlay),
|
||||||
shouldRenderFullMedia: shouldRenderPreview,
|
undefined,
|
||||||
transitionClassNames: previewTransitionClassNames,
|
undefined,
|
||||||
} = useTransitionForMedia(previewBlobUrl || canAnimatedPlay, 'slow');
|
'slow',
|
||||||
|
);
|
||||||
|
|
||||||
// To avoid flickering
|
// To avoid flickering
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -82,7 +83,7 @@ const StickerButton: FC<OwnProps> = ({
|
|||||||
className,
|
className,
|
||||||
);
|
);
|
||||||
|
|
||||||
const style = shouldRenderThumb && thumbDataUri ? `background-image: url('${thumbDataUri}');` : '';
|
const style = thumbDataUri ? `background-image: url('${thumbDataUri}');` : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -95,7 +96,7 @@ const StickerButton: FC<OwnProps> = ({
|
|||||||
onMouseDown={preventMessageInputBlurWithBubbling}
|
onMouseDown={preventMessageInputBlurWithBubbling}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{shouldRenderPreview && !canAnimatedPlay && (
|
{!canAnimatedPlay && (
|
||||||
// eslint-disable-next-line jsx-a11y/alt-text
|
// eslint-disable-next-line jsx-a11y/alt-text
|
||||||
<img src={previewBlobUrl} className={previewTransitionClassNames} />
|
<img src={previewBlobUrl} className={previewTransitionClassNames} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import { ThemeKey, UPLOADING_WALLPAPER_SLUG } from '../../../types';
|
|||||||
import { CUSTOM_BG_CACHE_NAME } from '../../../config';
|
import { CUSTOM_BG_CACHE_NAME } from '../../../config';
|
||||||
import * as cacheApi from '../../../util/cacheApi';
|
import * as cacheApi from '../../../util/cacheApi';
|
||||||
import { fetchBlob } from '../../../util/files';
|
import { fetchBlob } from '../../../util/files';
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import useMedia from '../../../hooks/useMedia';
|
import useMedia from '../../../hooks/useMedia';
|
||||||
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
||||||
@ -37,9 +36,12 @@ const WallpaperTile: FC<OwnProps> = ({
|
|||||||
const localBlobUrl = document.previewBlobUrl;
|
const localBlobUrl = document.previewBlobUrl;
|
||||||
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`);
|
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`);
|
||||||
const thumbRef = useCanvasBlur(document.thumbnail?.dataUri, Boolean(previewBlobUrl), true);
|
const thumbRef = useCanvasBlur(document.thumbnail?.dataUri, Boolean(previewBlobUrl), true);
|
||||||
const {
|
const { transitionClassNames } = useShowTransition(
|
||||||
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
|
Boolean(previewBlobUrl || localBlobUrl),
|
||||||
} = useTransitionForMedia(previewBlobUrl || localBlobUrl, 'slow');
|
undefined,
|
||||||
|
undefined,
|
||||||
|
'slow',
|
||||||
|
);
|
||||||
const [isLoadAllowed, setIsLoadAllowed] = useState(false);
|
const [isLoadAllowed, setIsLoadAllowed] = useState(false);
|
||||||
const {
|
const {
|
||||||
mediaData: fullMedia, loadProgress,
|
mediaData: fullMedia, loadProgress,
|
||||||
@ -85,19 +87,15 @@ const WallpaperTile: FC<OwnProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div className={className} onClick={handleClick}>
|
<div className={className} onClick={handleClick}>
|
||||||
<div className="media-inner">
|
<div className="media-inner">
|
||||||
{shouldRenderThumb && (
|
<canvas
|
||||||
<canvas
|
ref={thumbRef}
|
||||||
ref={thumbRef}
|
className="thumbnail"
|
||||||
className="thumbnail"
|
/>
|
||||||
/>
|
<img
|
||||||
)}
|
src={previewBlobUrl || localBlobUrl}
|
||||||
{shouldRenderFullMedia && (
|
className={buildClassName('full-media', transitionClassNames)}
|
||||||
<img
|
alt=""
|
||||||
src={previewBlobUrl || localBlobUrl}
|
/>
|
||||||
className={`full-media ${transitionClassNames}`}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{shouldRenderSpinner && (
|
{shouldRenderSpinner && (
|
||||||
<div className={buildClassName('spinner-container', spinnerClassNames)}>
|
<div className={buildClassName('spinner-container', spinnerClassNames)}>
|
||||||
<ProgressSpinner progress={loadProgress} onClick={handleClick} />
|
<ProgressSpinner progress={loadProgress} onClick={handleClick} />
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
|||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import windowSize from '../../../util/windowSize';
|
import windowSize from '../../../util/windowSize';
|
||||||
import { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver';
|
import { ObserveFn, useOnIntersect } from '../../../hooks/useIntersectionObserver';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
import useLang from '../../../hooks/useLang';
|
import useLang from '../../../hooks/useLang';
|
||||||
|
|
||||||
import EmojiButton from './EmojiButton';
|
import EmojiButton from './EmojiButton';
|
||||||
@ -31,7 +31,7 @@ const EmojiCategory: FC<OwnProps> = ({
|
|||||||
|
|
||||||
useOnIntersect(ref, observeIntersection);
|
useOnIntersect(ref, observeIntersection);
|
||||||
|
|
||||||
const { transitionClassNames } = useShowTransition(shouldRender, undefined, undefined, 'slow');
|
const transitionClassNames = useMediaTransition(shouldRender);
|
||||||
|
|
||||||
const lang = useLang();
|
const lang = useLang();
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { STICKER_SIZE_PICKER } from '../../../config';
|
|||||||
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
import { IS_SINGLE_COLUMN_LAYOUT } from '../../../util/environment';
|
||||||
import windowSize from '../../../util/windowSize';
|
import windowSize from '../../../util/windowSize';
|
||||||
import StickerButton from '../../common/StickerButton';
|
import StickerButton from '../../common/StickerButton';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
@ -39,7 +39,7 @@ const StickerSet: FC<OwnProps> = ({
|
|||||||
|
|
||||||
useOnIntersect(ref, observeIntersection);
|
useOnIntersect(ref, observeIntersection);
|
||||||
|
|
||||||
const { transitionClassNames } = useShowTransition(shouldRender, undefined, undefined, 'slow');
|
const transitionClassNames = useMediaTransition(shouldRender);
|
||||||
|
|
||||||
const stickersPerRow = IS_SINGLE_COLUMN_LAYOUT
|
const stickersPerRow = IS_SINGLE_COLUMN_LAYOUT
|
||||||
? Math.floor((windowSize.get().width - MOBILE_CONTAINER_PADDING) / (STICKER_SIZE_PICKER + STICKER_MARGIN))
|
? 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 { ApiStickerSet } from '../../../api/types';
|
||||||
|
|
||||||
|
import { getFirstLetters } from '../../../util/textFormat';
|
||||||
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
import useMedia from '../../../hooks/useMedia';
|
import useMedia from '../../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
import { getFirstLetters } from '../../../util/textFormat';
|
|
||||||
|
|
||||||
type OwnProps = {
|
type OwnProps = {
|
||||||
stickerSet: ApiStickerSet;
|
stickerSet: ApiStickerSet;
|
||||||
@ -19,14 +21,18 @@ const StickerSetCover: FC<OwnProps> = ({ stickerSet, observeIntersection }) => {
|
|||||||
const isIntersecting = useIsIntersecting(ref, observeIntersection);
|
const isIntersecting = useIsIntersecting(ref, observeIntersection);
|
||||||
|
|
||||||
const mediaData = useMedia(stickerSet.hasThumbnail && `stickerSet${stickerSet.id}`, !isIntersecting);
|
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 (
|
return (
|
||||||
<div ref={ref} className="sticker-set-cover">
|
<div ref={ref} className="sticker-set-cover">
|
||||||
{!shouldRenderFullMedia && getFirstLetters(stickerSet.title, 2)}
|
{firstLetters}
|
||||||
{shouldRenderFullMedia && (
|
<img src={mediaData} className={transitionClassNames} alt="" />
|
||||||
<img src={mediaData} className={transitionClassNames} alt="" />
|
|
||||||
)}
|
|
||||||
</div>
|
</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 { ApiMediaFormat, ApiStickerSet } from '../../../api/types';
|
||||||
|
|
||||||
import { STICKER_SIZE_PICKER_HEADER } from '../../../config';
|
import { STICKER_SIZE_PICKER_HEADER } from '../../../config';
|
||||||
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
import useMedia from '../../../hooks/useMedia';
|
import useMedia from '../../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
import { getFirstLetters } from '../../../util/textFormat';
|
import { getFirstLetters } from '../../../util/textFormat';
|
||||||
|
|
||||||
import AnimatedSticker from '../../common/AnimatedSticker';
|
import AnimatedSticker from '../../common/AnimatedSticker';
|
||||||
@ -28,12 +30,18 @@ const StickerSetCoverAnimated: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const mediaHash = `stickerSet${stickerSet.id}`;
|
const mediaHash = `stickerSet${stickerSet.id}`;
|
||||||
const lottieData = useMedia(mediaHash, !isIntersecting, ApiMediaFormat.Lottie);
|
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 (
|
return (
|
||||||
<div ref={ref} className="sticker-set-cover">
|
<div ref={ref} className="sticker-set-cover">
|
||||||
{!shouldRenderFullMedia && getFirstLetters(stickerSet.title, 2)}
|
{firstLetters}
|
||||||
{shouldRenderFullMedia && lottieData && (
|
{lottieData && (
|
||||||
<AnimatedSticker
|
<AnimatedSticker
|
||||||
id={mediaHash}
|
id={mediaHash}
|
||||||
size={size}
|
size={size}
|
||||||
|
|||||||
@ -4,8 +4,9 @@ import {
|
|||||||
ApiBotInlineMediaResult, ApiBotInlineResult, ApiPhoto, ApiThumbnail, ApiWebDocument,
|
ApiBotInlineMediaResult, ApiBotInlineResult, ApiPhoto, ApiThumbnail, ApiWebDocument,
|
||||||
} from '../../../../api/types';
|
} from '../../../../api/types';
|
||||||
|
|
||||||
|
import buildClassName from '../../../../util/buildClassName';
|
||||||
import useMedia from '../../../../hooks/useMedia';
|
import useMedia from '../../../../hooks/useMedia';
|
||||||
import useTransitionForMedia from '../../../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../../../hooks/useMediaTransition';
|
||||||
|
|
||||||
import BaseResult from './BaseResult';
|
import BaseResult from './BaseResult';
|
||||||
|
|
||||||
@ -38,9 +39,7 @@ const MediaResult: FC<OwnProps> = ({
|
|||||||
|
|
||||||
const thumbnailDataUrl = useMedia(webThumbnail ? `webDocument:${webThumbnail.url}` : undefined);
|
const thumbnailDataUrl = useMedia(webThumbnail ? `webDocument:${webThumbnail.url}` : undefined);
|
||||||
const mediaBlobUrl = useMedia(photo && `photo${photo.id}?size=m`);
|
const mediaBlobUrl = useMedia(photo && `photo${photo.id}?size=m`);
|
||||||
const {
|
const transitionClassNames = useMediaTransition(mediaBlobUrl);
|
||||||
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
|
|
||||||
} = useTransitionForMedia(mediaBlobUrl, 'slow');
|
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
onClick(inlineResult);
|
onClick(inlineResult);
|
||||||
@ -49,12 +48,8 @@ const MediaResult: FC<OwnProps> = ({
|
|||||||
if (isForGallery) {
|
if (isForGallery) {
|
||||||
return (
|
return (
|
||||||
<div className="MediaResult chat-item-clickable" onClick={handleClick}>
|
<div className="MediaResult chat-item-clickable" onClick={handleClick}>
|
||||||
{shouldRenderThumb && (
|
<img src={(photo?.thumbnail?.dataUri) || thumbnailDataUrl} alt="" />
|
||||||
<img src={(photo?.thumbnail?.dataUri) || thumbnailDataUrl} alt="" />
|
<img src={mediaBlobUrl} className={buildClassName('full-media', transitionClassNames)} alt="" />
|
||||||
)}
|
|
||||||
{shouldRenderFullMedia && (
|
|
||||||
<img src={mediaBlobUrl} className={`${transitionClassNames} full-media`} alt="" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -64,8 +59,8 @@ const MediaResult: FC<OwnProps> = ({
|
|||||||
return (
|
return (
|
||||||
<BaseResult
|
<BaseResult
|
||||||
focus={focus}
|
focus={focus}
|
||||||
thumbUrl={shouldRenderFullMedia ? mediaBlobUrl : (thumbnail?.dataUri || thumbnailDataUrl)}
|
thumbUrl={mediaBlobUrl || (thumbnail?.dataUri || thumbnailDataUrl)}
|
||||||
transitionClassNames={shouldRenderFullMedia ? transitionClassNames : undefined}
|
transitionClassNames={transitionClassNames}
|
||||||
title={title}
|
title={title}
|
||||||
description={description}
|
description={description}
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
|
|||||||
@ -15,7 +15,6 @@ import {
|
|||||||
} from '../../../modules/helpers';
|
} from '../../../modules/helpers';
|
||||||
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useShowTransition from '../../../hooks/useShowTransition';
|
||||||
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
|
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
|
||||||
import usePrevious from '../../../hooks/usePrevious';
|
import usePrevious from '../../../hooks/usePrevious';
|
||||||
@ -24,6 +23,7 @@ import getCustomAppendixBg from './helpers/getCustomAppendixBg';
|
|||||||
import { calculateMediaDimensions } from './helpers/mediaDimensions';
|
import { calculateMediaDimensions } from './helpers/mediaDimensions';
|
||||||
|
|
||||||
import ProgressSpinner from '../../ui/ProgressSpinner';
|
import ProgressSpinner from '../../ui/ProgressSpinner';
|
||||||
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
|
|
||||||
export type OwnProps = {
|
export type OwnProps = {
|
||||||
id?: string;
|
id?: string;
|
||||||
@ -92,13 +92,12 @@ const Photo: FC<OwnProps> = ({
|
|||||||
shouldLoad && !fullMediaData,
|
shouldLoad && !fullMediaData,
|
||||||
);
|
);
|
||||||
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
|
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
|
||||||
|
|
||||||
|
const transitionClassNames = useMediaTransition(fullMediaData);
|
||||||
const {
|
const {
|
||||||
shouldRender: shouldRenderSpinner,
|
shouldRender: shouldRenderSpinner,
|
||||||
transitionClassNames: spinnerClassNames,
|
transitionClassNames: spinnerClassNames,
|
||||||
} = useShowTransition(isTransferring, undefined, wasLoadDisabled, 'slow');
|
} = useShowTransition(isTransferring, undefined, wasLoadDisabled, 'slow');
|
||||||
const {
|
|
||||||
shouldRenderThumb, shouldRenderFullMedia, transitionClassNames,
|
|
||||||
} = useTransitionForMedia(fullMediaData, 'slow');
|
|
||||||
|
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
if (isUploading) {
|
if (isUploading) {
|
||||||
@ -152,23 +151,19 @@ const Photo: FC<OwnProps> = ({
|
|||||||
style={style}
|
style={style}
|
||||||
onClick={isUploading ? undefined : handleClick}
|
onClick={isUploading ? undefined : handleClick}
|
||||||
>
|
>
|
||||||
{shouldRenderThumb && (
|
<canvas
|
||||||
<canvas
|
ref={thumbRef}
|
||||||
ref={thumbRef}
|
className="thumbnail"
|
||||||
className="thumbnail"
|
// @ts-ignore teact feature
|
||||||
// @ts-ignore teact feature
|
style={`width: ${width}px; height: ${height}px`}
|
||||||
style={`width: ${width}px; height: ${height}px`}
|
/>
|
||||||
/>
|
<img
|
||||||
)}
|
src={fullMediaData}
|
||||||
{shouldRenderFullMedia && (
|
className={`full-media ${transitionClassNames}`}
|
||||||
<img
|
width={width}
|
||||||
src={fullMediaData}
|
height={height}
|
||||||
className={`full-media ${transitionClassNames}`}
|
alt=""
|
||||||
width={width}
|
/>
|
||||||
height={height}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{shouldRenderSpinner && (
|
{shouldRenderSpinner && (
|
||||||
<div className={`media-loading ${spinnerClassNames}`}>
|
<div className={`media-loading ${spinnerClassNames}`}>
|
||||||
<ProgressSpinner progress={transferProgress} onClick={isUploading ? handleClick : undefined} />
|
<ProgressSpinner progress={transferProgress} onClick={isUploading ? handleClick : undefined} />
|
||||||
|
|||||||
@ -10,22 +10,22 @@ import { getDispatch } from '../../../lib/teact/teactn';
|
|||||||
import { ApiMediaFormat, ApiMessage } from '../../../api/types';
|
import { ApiMediaFormat, ApiMessage } from '../../../api/types';
|
||||||
|
|
||||||
import { ROUND_VIDEO_DIMENSIONS_PX } from '../../common/helpers/mediaDimensions';
|
import { ROUND_VIDEO_DIMENSIONS_PX } from '../../common/helpers/mediaDimensions';
|
||||||
import { formatMediaDuration } from '../../../util/dateFormat';
|
|
||||||
import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';
|
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 { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useShowTransition from '../../../hooks/useShowTransition';
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
import usePrevious from '../../../hooks/usePrevious';
|
import usePrevious from '../../../hooks/usePrevious';
|
||||||
import useBuffering from '../../../hooks/useBuffering';
|
import useBuffering from '../../../hooks/useBuffering';
|
||||||
import buildClassName from '../../../util/buildClassName';
|
|
||||||
import { stopCurrentAudio } from '../../../util/audioPlayer';
|
|
||||||
import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';
|
import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';
|
||||||
import useVideoCleanup from '../../../hooks/useVideoCleanup';
|
import useVideoCleanup from '../../../hooks/useVideoCleanup';
|
||||||
import usePauseOnInactive from './hooks/usePauseOnInactive';
|
import usePauseOnInactive from './hooks/usePauseOnInactive';
|
||||||
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
|
import useBlurredMediaThumbRef from './hooks/useBlurredMediaThumbRef';
|
||||||
import safePlay from '../../../util/safePlay';
|
|
||||||
import { fastRaf } from '../../../util/schedulers';
|
|
||||||
|
|
||||||
import ProgressSpinner from '../../ui/ProgressSpinner';
|
import ProgressSpinner from '../../ui/ProgressSpinner';
|
||||||
|
|
||||||
@ -91,11 +91,12 @@ const RoundVideo: FC<OwnProps> = ({
|
|||||||
const { isBuffered, bufferingHandlers } = useBuffering();
|
const { isBuffered, bufferingHandlers } = useBuffering();
|
||||||
const isTransferring = (isLoadAllowed && !isBuffered) || isDownloading;
|
const isTransferring = (isLoadAllowed && !isBuffered) || isDownloading;
|
||||||
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
|
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
|
||||||
|
|
||||||
|
const transitionClassNames = useMediaTransition(mediaData);
|
||||||
const {
|
const {
|
||||||
shouldRender: shouldSpinnerRender,
|
shouldRender: shouldSpinnerRender,
|
||||||
transitionClassNames: spinnerClassNames,
|
transitionClassNames: spinnerClassNames,
|
||||||
} = useShowTransition(isTransferring || !isBuffered, undefined, wasLoadDisabled);
|
} = useShowTransition(isTransferring || !isBuffered, undefined, wasLoadDisabled);
|
||||||
const { shouldRenderThumb, transitionClassNames } = useTransitionForMedia(mediaData, 'slow');
|
|
||||||
|
|
||||||
const [isActivated, setIsActivated] = useState<boolean>(false);
|
const [isActivated, setIsActivated] = useState<boolean>(false);
|
||||||
const [progress, setProgress] = useState<number>(0);
|
const [progress, setProgress] = useState<number>(0);
|
||||||
@ -206,16 +207,14 @@ const RoundVideo: FC<OwnProps> = ({
|
|||||||
className="RoundVideo media-inner"
|
className="RoundVideo media-inner"
|
||||||
onClick={handleClick}
|
onClick={handleClick}
|
||||||
>
|
>
|
||||||
{(shouldRenderThumb || mediaData) && (
|
<div className="thumbnail-wrapper">
|
||||||
<div className="thumbnail-wrapper">
|
<canvas
|
||||||
<canvas
|
ref={thumbRef}
|
||||||
ref={thumbRef}
|
className="thumbnail"
|
||||||
className="thumbnail"
|
// @ts-ignore teact feature
|
||||||
// @ts-ignore teact feature
|
style={`width: ${ROUND_VIDEO_DIMENSIONS_PX}px; height: ${ROUND_VIDEO_DIMENSIONS_PX}px`}
|
||||||
style={`width: ${ROUND_VIDEO_DIMENSIONS_PX}px; height: ${ROUND_VIDEO_DIMENSIONS_PX}px`}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{mediaData && (
|
{mediaData && (
|
||||||
<div className="video-wrapper">
|
<div className="video-wrapper">
|
||||||
{/* eslint-disable-next-line jsx-a11y/media-has-caption */}
|
{/* 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 { MEMOJI_STICKER_ID } from '../../../config';
|
||||||
import { getStickerDimensions } from '../../common/helpers/mediaDimensions';
|
import { getStickerDimensions } from '../../common/helpers/mediaDimensions';
|
||||||
import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';
|
import { getMessageMediaFormat, getMessageMediaHash } from '../../../modules/helpers';
|
||||||
import useMedia from '../../../hooks/useMedia';
|
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
|
||||||
import buildClassName from '../../../util/buildClassName';
|
import buildClassName from '../../../util/buildClassName';
|
||||||
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObserver';
|
||||||
|
import useMedia from '../../../hooks/useMedia';
|
||||||
|
import useMediaTransition from '../../../hooks/useMediaTransition';
|
||||||
import useFlag from '../../../hooks/useFlag';
|
import useFlag from '../../../hooks/useFlag';
|
||||||
import useWebpThumbnail from '../../../hooks/useWebpThumbnail';
|
import useWebpThumbnail from '../../../hooks/useWebpThumbnail';
|
||||||
|
|
||||||
@ -52,7 +52,7 @@ const Sticker: FC<OwnProps> = ({
|
|||||||
const isMediaLoaded = Boolean(mediaData);
|
const isMediaLoaded = Boolean(mediaData);
|
||||||
const [isAnimationLoaded, markAnimationLoaded] = useFlag(isMediaLoaded);
|
const [isAnimationLoaded, markAnimationLoaded] = useFlag(isMediaLoaded);
|
||||||
const isMediaReady = isAnimated ? isAnimationLoaded : isMediaLoaded;
|
const isMediaReady = isAnimated ? isAnimationLoaded : isMediaLoaded;
|
||||||
const { shouldRenderFullMedia, transitionClassNames } = useTransitionForMedia(isMediaReady, 'slow');
|
const transitionClassNames = useMediaTransition(isMediaReady);
|
||||||
|
|
||||||
const { width, height } = getStickerDimensions(sticker);
|
const { width, height } = getStickerDimensions(sticker);
|
||||||
const thumbClassName = buildClassName('thumbnail', !thumbDataUri && 'empty');
|
const thumbClassName = buildClassName('thumbnail', !thumbDataUri && 'empty');
|
||||||
@ -74,7 +74,7 @@ const Sticker: FC<OwnProps> = ({
|
|||||||
className={thumbClassName}
|
className={thumbClassName}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!isAnimated && shouldRenderFullMedia && (
|
{!isAnimated && (
|
||||||
<img
|
<img
|
||||||
id={`sticker-${message.id}`}
|
id={`sticker-${message.id}`}
|
||||||
src={mediaData as string}
|
src={mediaData as string}
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import { ObserveFn, useIsIntersecting } from '../../../hooks/useIntersectionObse
|
|||||||
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
|
||||||
import useMedia from '../../../hooks/useMedia';
|
import useMedia from '../../../hooks/useMedia';
|
||||||
import useShowTransition from '../../../hooks/useShowTransition';
|
import useShowTransition from '../../../hooks/useShowTransition';
|
||||||
import useTransitionForMedia from '../../../hooks/useTransitionForMedia';
|
|
||||||
import usePrevious from '../../../hooks/usePrevious';
|
import usePrevious from '../../../hooks/usePrevious';
|
||||||
import useBuffering from '../../../hooks/useBuffering';
|
import useBuffering from '../../../hooks/useBuffering';
|
||||||
import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';
|
import useHeavyAnimationCheckForVideo from '../../../hooks/useHeavyAnimationCheckForVideo';
|
||||||
@ -81,11 +80,12 @@ const Video: FC<OwnProps> = ({
|
|||||||
getMessageMediaFormat(message, 'pictogram'),
|
getMessageMediaFormat(message, 'pictogram'),
|
||||||
lastSyncTime,
|
lastSyncTime,
|
||||||
);
|
);
|
||||||
const {
|
const { transitionClassNames: previewClassNames } = useShowTransition(
|
||||||
shouldRenderThumb,
|
Boolean(previewBlobUrl),
|
||||||
shouldRenderFullMedia: shouldRenderPreview,
|
undefined,
|
||||||
transitionClassNames: previewClassNames,
|
undefined,
|
||||||
} = useTransitionForMedia(previewBlobUrl, 'slow');
|
'slow',
|
||||||
|
);
|
||||||
|
|
||||||
const { mediaData, loadProgress } = useMediaWithLoadProgress(
|
const { mediaData, loadProgress } = useMediaWithLoadProgress(
|
||||||
getMessageMediaHash(message, 'inline'),
|
getMessageMediaHash(message, 'inline'),
|
||||||
@ -163,23 +163,19 @@ const Video: FC<OwnProps> = ({
|
|||||||
style={style}
|
style={style}
|
||||||
onClick={isUploading ? undefined : handleClick}
|
onClick={isUploading ? undefined : handleClick}
|
||||||
>
|
>
|
||||||
{shouldRenderThumb && (
|
<canvas
|
||||||
<canvas
|
ref={thumbRef}
|
||||||
ref={thumbRef}
|
className="thumbnail"
|
||||||
className="thumbnail"
|
// @ts-ignore teact feature
|
||||||
// @ts-ignore teact feature
|
style={`width: ${width}px; height: ${height}px;`}
|
||||||
style={`width: ${width}px; height: ${height}px;`}
|
/>
|
||||||
/>
|
<img
|
||||||
)}
|
src={previewBlobUrl}
|
||||||
{shouldRenderPreview && (
|
className={buildClassName('thumbnail', previewClassNames)}
|
||||||
<img
|
// @ts-ignore teact feature
|
||||||
src={previewBlobUrl}
|
style={`width: ${width}px; height: ${height}px;`}
|
||||||
className={buildClassName('thumbnail', previewClassNames)}
|
alt=""
|
||||||
// @ts-ignore teact feature
|
/>
|
||||||
style={`width: ${width}px; height: ${height}px;`}
|
|
||||||
alt=""
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isInline && (
|
{isInline && (
|
||||||
<video
|
<video
|
||||||
ref={videoRef}
|
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