TelegramPWA/src/components/left/settings/WallpaperTile.tsx
2021-11-05 22:03:12 +03:00

110 lines
3.3 KiB
TypeScript

import React, {
FC, memo, useCallback, useEffect, useState, useRef,
} from '../../../lib/teact/teact';
import { ApiWallpaper } from '../../../api/types';
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 buildClassName from '../../../util/buildClassName';
import useMedia from '../../../hooks/useMedia';
import useMediaWithLoadProgress from '../../../hooks/useMediaWithLoadProgress';
import useShowTransition from '../../../hooks/useShowTransition';
import usePrevious from '../../../hooks/usePrevious';
import useCanvasBlur from '../../../hooks/useCanvasBlur';
import ProgressSpinner from '../../ui/ProgressSpinner';
import './WallpaperTile.scss';
type OwnProps = {
wallpaper: ApiWallpaper;
theme: ThemeKey;
isSelected: boolean;
onClick: (slug: string) => void;
};
const WallpaperTile: FC<OwnProps> = ({
wallpaper,
theme,
isSelected,
onClick,
}) => {
const { slug, document } = wallpaper;
const localMediaHash = `wallpaper${document.id!}`;
const localBlobUrl = document.previewBlobUrl;
const previewBlobUrl = useMedia(`${localMediaHash}?size=m`);
const thumbRef = useCanvasBlur(document.thumbnail?.dataUri, Boolean(previewBlobUrl), true);
const { transitionClassNames } = useShowTransition(
Boolean(previewBlobUrl || localBlobUrl),
undefined,
undefined,
'slow',
);
const [isLoadAllowed, setIsLoadAllowed] = useState(false);
const {
mediaData: fullMedia, loadProgress,
} = useMediaWithLoadProgress(localMediaHash, !isLoadAllowed);
const wasLoadDisabled = usePrevious(isLoadAllowed) === false;
const { shouldRender: shouldRenderSpinner, transitionClassNames: spinnerClassNames } = useShowTransition(
(isLoadAllowed && !fullMedia) || slug === UPLOADING_WALLPAPER_SLUG,
undefined,
wasLoadDisabled,
'slow',
);
// To prevent triggering of the effect for useCallback
const cacheKeyRef = useRef<string>();
cacheKeyRef.current = theme;
const handleSelect = useCallback(() => {
(async () => {
const blob = await fetchBlob(fullMedia!);
await cacheApi.save(CUSTOM_BG_CACHE_NAME, cacheKeyRef.current!, blob);
onClick(slug);
})();
}, [fullMedia, onClick, slug]);
useEffect(() => {
if (fullMedia) {
handleSelect();
}
}, [fullMedia, handleSelect]);
const handleClick = useCallback(() => {
if (fullMedia) {
handleSelect();
} else {
setIsLoadAllowed((isAllowed) => !isAllowed);
}
}, [fullMedia, handleSelect]);
const className = buildClassName(
'WallpaperTile',
isSelected && 'selected',
);
return (
<div className={className} onClick={handleClick}>
<div className="media-inner">
<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} />
</div>
)}
</div>
</div>
);
};
export default memo(WallpaperTile);