import { JoinRule } from 'matrix-js-sdk'; import { AvatarFallback, AvatarImage, color } from 'folds'; import { Icon, Icons } from '../icons'; import React, { ComponentProps, ReactEventHandler, ReactNode, forwardRef, useEffect, useState } from 'react'; import { Blurhash } from 'react-blurhash'; import * as css from './RoomAvatar.css'; import { joinRuleToIconSrc } from '../../utils/room'; import colorMXID from '../../../util/colorMXID'; import { useAuthenticatedMediaUrl } from '../../hooks/useAuthenticatedMediaUrl'; import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { cacheAvatar, isAvatarCached, pruneAvatarCache } from '../../utils/avatarCache'; import { getCachedAuthenticatedMediaUrl, isAuthenticatedMediaUrl, } from '../../utils/authenticatedMediaCache'; import { getMediaBlurHash, getMediaDimensions, rememberMediaBlurHash, } from '../../state/mediaDimensionCache'; type RoomAvatarProps = { roomId: string; src?: string; alt?: string; renderFallback: () => ReactNode; }; export function RoomAvatar({ roomId, src, alt, renderFallback }: RoomAvatarProps) { const [error, setError] = useState(false); const useAuthentication = useMediaAuthentication(); const authenticatedSrc = useAuthenticatedMediaUrl(src, useAuthentication); const blurHash = getMediaBlurHash(src ?? ''); const dims = getMediaDimensions(src ?? ''); const blobCached = !!src && (!useAuthentication || !isAuthenticatedMediaUrl(src) || !!getCachedAuthenticatedMediaUrl(src)); const [loaded, setLoaded] = useState(() => isAvatarCached(src) || blobCached); useEffect(() => { if ( authenticatedSrc && (isAvatarCached(src) || (src && (!useAuthentication || !isAuthenticatedMediaUrl(src) || getCachedAuthenticatedMediaUrl(src)))) ) { setLoaded(true); } }, [authenticatedSrc, src, useAuthentication]); const handleLoad: ReactEventHandler = (evt) => { evt.currentTarget.setAttribute('data-image-loaded', 'true'); setLoaded(true); cacheAvatar(src); pruneAvatarCache(); rememberMediaBlurHash(src ?? '', evt.currentTarget); }; if (!src || error) { return ( {renderFallback()} ); } if (authenticatedSrc && loaded) { return ( setError(true)} onLoad={handleLoad} draggable={false} data-image-loaded="true" /> ); } const blurResolutionX = 32; const blurResolutionY = dims?.w && dims?.h && dims.w > 0 ? Math.max(1, Math.round(blurResolutionX * (dims.h / dims.w))) : 32; return (
{renderFallback()} {blurHash && (
)} {authenticatedSrc && ( setError(true)} onLoad={handleLoad} draggable={false} /> )}
); } export const RoomIcon = forwardRef< SVGSVGElement, Omit, 'src'> & { joinRule: JoinRule; space?: boolean; } >(({ joinRule, space, ...props }, ref) => ( ));