Animated Icon: Fix progressive loading animation

This commit is contained in:
Alexander Zinchuk 2023-08-16 15:27:33 +02:00
parent f41a12a4d8
commit 8755f9db6d
2 changed files with 28 additions and 9 deletions

View File

@ -2,6 +2,10 @@
position: relative; position: relative;
display: block !important; display: block !important;
:global(.AnimatedSticker.not-shown) {
display: block;
}
} }
.preview { .preview {
@ -10,4 +14,8 @@
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
&:global(.closing) {
transition-delay: 150ms;
}
} }

View File

@ -1,6 +1,7 @@
import React, { memo } from '../../lib/teact/teact'; import React, { memo } from '../../lib/teact/teact';
import type { OwnProps as AnimatedIconProps } from './AnimatedIcon'; import type { OwnProps as AnimatedIconProps } from './AnimatedIcon';
import AnimatedIcon from './AnimatedIcon';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import buildStyle from '../../util/buildStyle'; import buildStyle from '../../util/buildStyle';
@ -9,14 +10,14 @@ import useLastCallback from '../../hooks/useLastCallback';
import useMediaTransition from '../../hooks/useMediaTransition'; import useMediaTransition from '../../hooks/useMediaTransition';
import useFlag from '../../hooks/useFlag'; import useFlag from '../../hooks/useFlag';
import AnimatedIcon from './AnimatedIcon';
import styles from './AnimatedIconWithPreview.module.scss'; import styles from './AnimatedIconWithPreview.module.scss';
type OwnProps = type OwnProps =
Partial<AnimatedIconProps> Partial<AnimatedIconProps>
& { previewUrl?: string; thumbDataUri?: string; noPreviewTransition?: boolean }; & { previewUrl?: string; thumbDataUri?: string; noPreviewTransition?: boolean };
const ANIMATION_DURATION = 300;
const loadedPreviewUrls = new Set(); const loadedPreviewUrls = new Set();
function AnimatedIconWithPreview(props: OwnProps) { function AnimatedIconWithPreview(props: OwnProps) {
@ -24,36 +25,46 @@ function AnimatedIconWithPreview(props: OwnProps) {
previewUrl, thumbDataUri, className, ...otherProps previewUrl, thumbDataUri, className, ...otherProps
} = props; } = props;
const [isPreviewLoaded, markPreviewLoaded] = useFlag(Boolean(thumbDataUri) || loadedPreviewUrls.has(previewUrl)); const [isThumbOpen, , unmarkThumbOpen] = useFlag(Boolean(thumbDataUri));
const transitionClassNames = useMediaTransition(isPreviewLoaded); const thumbClassNames = useMediaTransition(isThumbOpen);
const [isPreviewOpen, markPreviewOpen, unmarkPreviewOpen] = useFlag(loadedPreviewUrls.has(previewUrl));
const previewClassNames = useMediaTransition(isPreviewOpen);
const [isAnimationReady, markAnimationReady] = useFlag(false); const [isAnimationReady, markAnimationReady] = useFlag(false);
const handlePreviewLoad = useLastCallback(() => { const handlePreviewLoad = useLastCallback(() => {
markPreviewLoaded(); markPreviewOpen();
loadedPreviewUrls.add(previewUrl); loadedPreviewUrls.add(previewUrl);
}); });
const handleAnimationReady = useLastCallback(() => {
unmarkThumbOpen();
unmarkPreviewOpen();
setTimeout(markAnimationReady, ANIMATION_DURATION);
});
const { size } = props; const { size } = props;
return ( return (
<div <div
className={buildClassName(className, styles.root, transitionClassNames)} className={buildClassName(className, styles.root)}
style={buildStyle(size !== undefined && `width: ${size}px; height: ${size}px;`)} style={buildStyle(size !== undefined && `width: ${size}px; height: ${size}px;`)}
> >
{thumbDataUri && !isAnimationReady && ( {thumbDataUri && !isAnimationReady && (
// eslint-disable-next-line jsx-a11y/alt-text // eslint-disable-next-line jsx-a11y/alt-text
<img src={thumbDataUri} className={styles.preview} /> <img src={thumbDataUri} className={buildClassName(styles.preview, thumbClassNames)} />
)} )}
{previewUrl && !isAnimationReady && ( {previewUrl && !isAnimationReady && (
// eslint-disable-next-line jsx-a11y/alt-text // eslint-disable-next-line jsx-a11y/alt-text
<img <img
src={previewUrl} src={previewUrl}
className={styles.preview} className={buildClassName(styles.preview, previewClassNames)}
onLoad={handlePreviewLoad} onLoad={handlePreviewLoad}
/> />
)} )}
{/* eslint-disable-next-line react/jsx-props-no-spreading */} {/* eslint-disable-next-line react/jsx-props-no-spreading */}
<AnimatedIcon {...otherProps} onLoad={markAnimationReady} noTransition /> <AnimatedIcon {...otherProps} onLoad={handleAnimationReady} />
</div> </div>
); );
} }