import React, { useState, useRef, useContext, useEffect } from 'react'; import { findDOMNode } from 'react-dom'; import { defineMessages, injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import Styled from './styles'; import { EFFECT_TYPES, BLUR_FILENAME, IMAGE_NAMES, getVirtualBackgroundThumbnail, isVirtualBackgroundSupported, } from '/imports/ui/services/virtual-background/service'; import { CustomVirtualBackgroundsContext } from './context'; import VirtualBgService from '/imports/ui/components/video-preview/virtual-background/service'; import logger from '/imports/startup/client/logger'; import withFileReader from '/imports/ui/components/common/file-reader/component'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import 'react-loading-skeleton/dist/skeleton.css'; import Settings from '/imports/ui/services/settings'; import { isCustomVirtualBackgroundsEnabled } from '/imports/ui/services/features'; const { MIME_TYPES_ALLOWED, MAX_FILE_SIZE } = VirtualBgService; const ENABLE_CAMERA_BRIGHTNESS = window.meetingClientSettings.public.app.enableCameraBrightness; const propTypes = { intl: PropTypes.shape({ formatMessage: PropTypes.func.isRequired, }).isRequired, handleVirtualBgSelected: PropTypes.func.isRequired, locked: PropTypes.bool.isRequired, showThumbnails: PropTypes.bool, initialVirtualBgState: PropTypes.shape({ type: PropTypes.string.isRequired, name: PropTypes.string, }), }; const intlMessages = defineMessages({ virtualBackgroundSettingsLabel: { id: 'app.videoPreview.webcamVirtualBackgroundLabel', description: 'Label for the virtual background', }, virtualBackgroundSettingsDisabledLabel: { id: 'app.videoPreview.webcamVirtualBackgroundDisabledLabel', description: 'Label for the unsupported virtual background', }, noneLabel: { id: 'app.video.virtualBackground.none', description: 'Label for no virtual background selected', }, customLabel: { id: 'app.video.virtualBackground.custom', description: 'Label for custom virtual background selected', }, removeLabel: { id: 'app.video.virtualBackground.remove', description: 'Label for remove custom virtual background', }, blurLabel: { id: 'app.video.virtualBackground.blur', description: 'Label for the blurred camera option', }, camBgAriaDesc: { id: 'app.video.virtualBackground.camBgAriaDesc', description: 'Label for virtual background button aria', }, customDesc: { id: 'app.video.virtualBackground.button.customDesc', description: 'Aria description for upload virtual background button', }, background: { id: 'app.video.virtualBackground.background', description: 'Label for the background word', }, backgroundWithIndex: { id: 'app.video.virtualBackground.backgroundWithIndex', description: 'Label for the background word indexed', }, ...IMAGE_NAMES.reduce((prev, imageName) => { const id = imageName.split('.').shift(); return { ...prev, [id]: { id: `app.video.virtualBackground.${id}`, description: `Label for the ${id} camera option`, defaultMessage: '{background} {index}', }, }; }, {}) }); const SKELETON_COUNT = 5; const VIRTUAL_BACKGROUNDS_CONFIG = window.meetingClientSettings.public.virtualBackgrounds; const ENABLE_UPLOAD = VIRTUAL_BACKGROUNDS_CONFIG.enableVirtualBackgroundUpload; const shouldEnableBackgroundUpload = () => ENABLE_UPLOAD && isCustomVirtualBackgroundsEnabled(); const VirtualBgSelector = ({ intl, handleVirtualBgSelected, locked, showThumbnails, initialVirtualBgState, isVisualEffects, readFile, }) => { const [currentVirtualBg, setCurrentVirtualBg] = useState({ ...initialVirtualBgState, }); const inputElementsRef = useRef([]); const customBgSelectorRef = useRef(null); const { dispatch, loaded, defaultSetUp, backgrounds, loadFromDB, } = useContext(CustomVirtualBackgroundsContext); const { MIME_TYPES_ALLOWED } = VirtualBgService; useEffect(() => { if (shouldEnableBackgroundUpload()) { if (!defaultSetUp) { const defaultBackgrounds = ['Blur', ...IMAGE_NAMES].map((imageName) => ({ uniqueId: imageName, custom: false, lastActivityDate: Date.now(), })); dispatch({ type: 'setDefault', backgrounds: defaultBackgrounds, }); } if (!loaded) loadFromDB(); } }, []); const _virtualBgSelected = (type, name, index, customParams) => handleVirtualBgSelected(type, name, customParams) .then(switched => { // Reset to the base NONE_TYPE effect if it failed because the expected // behaviour from upstream's method is to actually stop/reset the effect // service if it fails if (!switched) { return setCurrentVirtualBg({ type: EFFECT_TYPES.NONE_TYPE }); } setCurrentVirtualBg({ type, name }); if (!index || index < 0) return; if (!shouldEnableBackgroundUpload()) { findDOMNode(inputElementsRef.current[index]).focus(); } else { if (customParams) { dispatch({ type: 'update', background: { filename: name, uniqueId: customParams.uniqueId, data: customParams.file, custom: true, lastActivityDate: Date.now(), }, }); } else { dispatch({ type: 'update', background: { uniqueId: name, custom: false, lastActivityDate: Date.now(), }, }); } findDOMNode(inputElementsRef.current[0]).focus(); } }); const renderDropdownSelector = () => { const disabled = locked || !isVirtualBackgroundSupported(); return (