// @flow /* eslint-disable react/jsx-no-bind, no-return-assign */ import Spinner from '@atlaskit/spinner'; import { jitsiLocalStorage } from '@jitsi/js-utils/jitsi-local-storage'; import React, { useState, useEffect } from 'react'; import uuid from 'uuid'; import { Dialog } from '../../base/dialog'; import { translate } from '../../base/i18n'; import { Icon, IconBlurBackground, IconCancelSelection } from '../../base/icons'; import { connect } from '../../base/redux'; import { Tooltip } from '../../base/tooltip'; import { toggleBackgroundEffect } from '../actions'; import { resizeImage, toDataURL } from '../functions'; import logger from '../logger'; // The limit of virtual background uploads is 24. When the number // of uploads is 25 we trigger the deleteStoredImage function to delete // the first/oldest uploaded background. const backgroundsLimit = 25; const images = [ { id: '1', src: 'images/virtual-background/background-1.jpg' }, { id: '2', src: 'images/virtual-background/background-2.jpg' }, { id: '3', src: 'images/virtual-background/background-3.jpg' }, { id: '4', src: 'images/virtual-background/background-4.jpg' } ]; type Props = { /** * Returns the selected thumbnail identifier. */ _selectedThumbnail: string, /** * The redux {@code dispatch} function. */ dispatch: Function, /** * Invoked to obtain translated strings. */ t: Function }; /** * Renders virtual background dialog. * * @returns {ReactElement} */ function VirtualBackground({ _selectedThumbnail, dispatch, t }: Props) { const localImages = jitsiLocalStorage.getItem('virtualBackgrounds'); const [ storedImages, setStoredImages ] = useState((localImages && JSON.parse(localImages)) || []); const [ loading, isloading ] = useState(false); const deleteStoredImage = image => { setStoredImages(storedImages.filter(item => item !== image)); }; /** * Updates stored images on local storage. */ useEffect(() => { try { jitsiLocalStorage.setItem('virtualBackgrounds', JSON.stringify(storedImages)); } catch (err) { // Preventing localStorage QUOTA_EXCEEDED_ERR err && deleteStoredImage(storedImages[0]); } if (storedImages.length === backgroundsLimit) { deleteStoredImage(storedImages[0]); } }, [ storedImages ]); const enableBlur = async (blurValue, selection) => { isloading(true); await dispatch( toggleBackgroundEffect({ backgroundType: 'blur', enabled: true, blurValue, selectedThumbnail: selection }) ); isloading(false); }; const removeBackground = async () => { isloading(true); await dispatch( toggleBackgroundEffect({ enabled: false, selectedThumbnail: 'none' }) ); isloading(false); }; const setUploadedImageBackground = async image => { isloading(true); await dispatch( toggleBackgroundEffect({ backgroundType: 'image', enabled: true, url: image.src, selectedThumbnail: image.id }) ); isloading(false); }; const setImageBackground = async image => { isloading(true); const url = await toDataURL(image.src); await dispatch( toggleBackgroundEffect({ backgroundType: 'image', enabled: true, url, selectedThumbnail: image.id }) ); isloading(false); }; const uploadImage = async imageFile => { const reader = new FileReader(); reader.readAsDataURL(imageFile[0]); reader.onload = async () => { const url = await resizeImage(reader.result); const uuId = uuid.v4(); isloading(true); setStoredImages([ ...storedImages, { id: uuId, src: url } ]); await dispatch( toggleBackgroundEffect({ backgroundType: 'image', enabled: true, url, selectedThumbnail: uuId }) ); isloading(false); }; reader.onerror = () => { isloading(false); logger.error('Failed to upload virtual image!'); }; }; return ( {loading ? (
{t('virtualBackground.pleaseWait')}
) : (
{t('virtualBackground.none')}
enableBlur(8, 'slight-blur') } size = { 50 } src = { IconBlurBackground } /> enableBlur(25, 'blur') } size = { 50 } src = { IconBlurBackground } /> {images.map((image, index) => ( setImageBackground(image) } onError = { event => event.target.style.display = 'none' } src = { image.src } /> ))} uploadImage(e.target.files) } type = 'file' />
{storedImages.map((image, index) => (
setUploadedImageBackground(image) } onError = { event => event.target.style.display = 'none' } src = { image.src } /> deleteStoredImage(image) } size = { 15 } src = { IconCancelSelection } />
))}
)}
); } /** * Maps (parts of) the redux state to the associated props for the * {@code VirtualBackground} component. * * @param {Object} state - The Redux state. * @private * @returns {{ * _selectedThumbnail: string * }} */ function _mapStateToProps(state): Object { return { _selectedThumbnail: state['features/virtual-background'].selectedThumbnail }; } export default translate(connect(_mapStateToProps)(VirtualBackground));