diff --git a/web/avatars/avatar.react.js b/web/avatars/avatar.react.js index 8bac4add9..462978706 100644 --- a/web/avatars/avatar.react.js +++ b/web/avatars/avatar.react.js @@ -1,103 +1,119 @@ // @flow import classnames from 'classnames'; import * as React from 'react'; import type { ResolvedClientAvatar, AvatarSize, } from 'lib/types/avatar-types.js'; import css from './avatar.css'; import LoadingIndicator from '../loading-indicator.react.js'; +import EncryptedMultimedia from '../media/encrypted-multimedia.react.js'; type Props = { +avatarInfo: ResolvedClientAvatar, +size: AvatarSize, +showSpinner?: boolean, }; function Avatar(props: Props): React.Node { const { avatarInfo, size, showSpinner } = props; + let loadingIndicatorSize; + if (size === 'XS') { + loadingIndicatorSize = 'small'; + } else if (size === 'S') { + loadingIndicatorSize = 'small'; + } else if (size === 'M') { + loadingIndicatorSize = 'medium'; + } else { + loadingIndicatorSize = 'large'; + } + + const loadingIndicator = React.useMemo( + () => ( +
+ +
+ ), + [loadingIndicatorSize], + ); + const containerSizeClassName = classnames({ [css.imgContainer]: avatarInfo.type === 'image', [css.xSmall]: size === 'XS', [css.small]: size === 'S', [css.medium]: size === 'M', [css.large]: size === 'L', [css.xLarge]: size === 'XL', [css.xxLarge]: size === 'XXL', }); const emojiSizeClassName = classnames({ [css.emojiContainer]: true, [css.emojiXSmall]: size === 'XS', [css.emojiSmall]: size === 'S', [css.emojiMedium]: size === 'M', [css.emojiLarge]: size === 'L', [css.emojiXLarge]: size === 'XL', [css.emojiXXLarge]: size === 'XXL', }); const emojiContainerColorStyle = React.useMemo(() => { if (avatarInfo.type === 'emoji') { return { backgroundColor: `#${avatarInfo.color}` }; } return undefined; }, [avatarInfo.color, avatarInfo.type]); const avatar = React.useMemo(() => { if (avatarInfo.type === 'image') { return ( image avatar ); + } else if (avatarInfo.type === 'encrypted_image') { + return ( + + ); } return (
{avatarInfo.emoji}
); }, [ avatarInfo.emoji, avatarInfo.type, avatarInfo.uri, + avatarInfo.blobURI, + avatarInfo.encryptionKey, + showSpinner, + loadingIndicator, containerSizeClassName, emojiContainerColorStyle, emojiSizeClassName, ]); - let loadingIndicatorSize; - if (size === 'XS') { - loadingIndicatorSize = 'small'; - } else if (size === 'S') { - loadingIndicatorSize = 'small'; - } else if (size === 'M') { - loadingIndicatorSize = 'medium'; - } else { - loadingIndicatorSize = 'large'; - } - - const loadingIndicator = React.useMemo( - () => ( -
- -
- ), - [loadingIndicatorSize], - ); - return (
{showSpinner ? loadingIndicator : null} {avatar}
); } export default Avatar; diff --git a/web/media/encrypted-multimedia.react.js b/web/media/encrypted-multimedia.react.js index b4ebc4bef..2ea2dd11f 100644 --- a/web/media/encrypted-multimedia.react.js +++ b/web/media/encrypted-multimedia.react.js @@ -1,135 +1,140 @@ // @flow import invariant from 'invariant'; import * as React from 'react'; import 'react-circular-progressbar/dist/styles.css'; import { AlertCircle as AlertCircleIcon } from 'react-feather'; import type { Shape } from 'lib/types/core.js'; import type { EncryptedMediaType } from 'lib/types/media-types.js'; import { decryptMedia } from './encryption-utils.js'; import LoadableVideo from './loadable-video.react.js'; import css from './media.css'; import LoadingIndicator from '../loading-indicator.react.js'; import type { CSSStyle } from '../types/styles'; type Props = { +blobURI: string, +encryptionKey: string, +type: EncryptedMediaType, +thumbnailBlobURI?: ?string, +thumbnailEncryptionKey?: ?string, +placeholderSrc?: ?string, +multimediaClassName?: string, +elementStyle?: ?Shape, + // if provided, this component will be shown instead of the loading indicator + +loadingIndicatorComponent?: React.Node, + // if true, the loading indicator will not be shown + +invisibleLoad?: boolean, }; function EncryptedMultimedia(props: Props): React.Node { const { blobURI, encryptionKey, placeholderSrc, elementStyle, multimediaClassName, + invisibleLoad, } = props; const [source, setSource] = React.useState(null); const videoRef = React.useRef(null); React.useEffect(() => { let isMounted = true, uriToDispose; setSource(null); const loadDecrypted = async () => { const { result } = await decryptMedia(blobURI, encryptionKey); if (!isMounted) { return; } if (result.success) { const { uri } = result; setSource({ uri }); uriToDispose = uri; } else { setSource({ error: result.reason }); } }; loadDecrypted(); return () => { isMounted = false; if (uriToDispose) { URL.revokeObjectURL(uriToDispose); } }; }, [blobURI, encryptionKey]); // we need to update the video source when the source changes // because re-rendering the element wouldn't reload parent