/* * Wire * Copyright (C) 2020 Wire Swiss GmbH * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * */ import React, {useEffect, useState} from 'react'; import {CSSObject} from '@emotion/serialize'; import {Transition} from 'react-transition-group'; import {container} from 'tsyringe'; import {InViewport} from 'Components/InViewport'; import {CSS_FILL_PARENT} from 'Util/CSSMixin'; import {AssetRemoteData} from '../../assets/AssetRemoteData'; import {AssetRepository} from '../../assets/AssetRepository'; import {AVATAR_SIZE} from '.'; export interface AvatarImageProps { assetRepository?: AssetRepository; avatarAlt: string; avatarSize: AVATAR_SIZE; backgroundColor?: string; borderRadius?: string; devicePixelRatio?: number; isGrey?: boolean; mediumPicture: AssetRemoteData; previewPicture: AssetRemoteData; } const AvatarImage: React.FunctionComponent = ({ assetRepository = container.resolve(AssetRepository), avatarAlt, avatarSize, backgroundColor = 'currentColor', borderRadius = '50%', devicePixelRatio = window.devicePixelRatio, isGrey = false, mediumPicture, previewPicture, }) => { const [avatarImage, setAvatarImage] = useState(''); const [showTransition, setShowTransition] = useState(false); const [avatarLoadingBlocked, setAvatarLoadingBlocked] = useState(false); const [isVisible, setIsVisible] = useState(false); useEffect(() => { if (!avatarLoadingBlocked && isVisible) { setAvatarLoadingBlocked(true); const isSmall = ![AVATAR_SIZE.LARGE, AVATAR_SIZE.X_LARGE].includes(avatarSize); const loadHiRes = !isSmall && devicePixelRatio > 1; const pictureResource: AssetRemoteData = loadHiRes ? mediumPicture : previewPicture; (async () => { if (pictureResource) { const isCached = pictureResource.downloadProgress() === 100; setShowTransition(!isCached && !isSmall); try { const url = await assetRepository.getObjectUrl(pictureResource); if (url) { setAvatarImage(url); } setAvatarLoadingBlocked(false); } catch (error) { console.warn('Failed to load avatar picture.', error); } } else { setAvatarLoadingBlocked(false); } })(); } }, [previewPicture, mediumPicture, avatarSize, isVisible]); const transitionImageStyles: Record = { entered: {opacity: 1, transform: 'scale(1)'}, entering: {opacity: 1, transform: 'scale(1)'}, }; return ( setIsVisible(true)}> {(state: string) => { return ( {avatarAlt} ); }} ); }; export {AvatarImage};