fix(reactions) fix reactions bugs
* Fix: removed web actions from common middlewares * Fixed raise hand sound Fix sound to play on raise not lower and work on keyboard shortcut as well * Fixed reaction keyboard shortcuts Register shortcuts only when there's more than one participant * Enforce reactions feature flag on reaction received * Disable reactions by default on native * Enable reactions on native by default * Sort props alphabetically * Created isreactionsEnabled function * Remove unused imports * Fix. No longer show toolbox on reactions and jibri On message received don't show toolbox for jibri * Fix isReactionsEnabled function for native On native check for flag and config option as well
This commit is contained in:
parent
aa06e89807
commit
5367d43c26
|
@ -15,8 +15,3 @@ export const API_ID = parseURLParams(window.location).jitsi_meet_external_api_id
|
|||
* The payload name for the datachannel/endpoint text message event
|
||||
*/
|
||||
export const ENDPOINT_TEXT_MESSAGE_NAME = 'endpoint-text-message';
|
||||
|
||||
/**
|
||||
* The payload name for the datachannel/endpoint reaction event
|
||||
*/
|
||||
export const ENDPOINT_REACTION_NAME = 'endpoint-reaction';
|
||||
|
|
|
@ -6,6 +6,7 @@ import UIEvents from '../../../../service/UI/UIEvents';
|
|||
import { toggleE2EE } from '../../e2ee/actions';
|
||||
import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications';
|
||||
import { CALLING, INVITED } from '../../presence-status';
|
||||
import { RAISE_HAND_SOUND_ID } from '../../reactions/constants';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../app';
|
||||
import {
|
||||
CONFERENCE_WILL_JOIN,
|
||||
|
@ -495,6 +496,7 @@ function _raiseHandUpdated({ dispatch, getState }, conference, participantId, ne
|
|||
},
|
||||
titleKey: 'notify.raisedHand'
|
||||
}, NOTIFICATION_TIMEOUT));
|
||||
dispatch(playSound(RAISE_HAND_SOUND_ID));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { ENDPOINT_REACTION_NAME } from '../../../modules/API/constants';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import {
|
||||
CONFERENCE_JOINED,
|
||||
|
@ -25,14 +22,13 @@ import { openDisplayNamePrompt } from '../display-name';
|
|||
import { resetNbUnreadPollsMessages } from '../polls/actions';
|
||||
import { ADD_REACTION_MESSAGE } from '../reactions/actionTypes';
|
||||
import { pushReactions } from '../reactions/actions.any';
|
||||
import { getReactionMessageFromBuffer } from '../reactions/functions.any';
|
||||
import { ENDPOINT_REACTION_NAME } from '../reactions/constants';
|
||||
import { getReactionMessageFromBuffer, isReactionsEnabled } from '../reactions/functions.any';
|
||||
import { endpointMessageReceived } from '../subtitles';
|
||||
import { showToolbox } from '../toolbox/actions';
|
||||
import {
|
||||
hideToolbox,
|
||||
setToolboxTimeout,
|
||||
setToolboxVisible
|
||||
} from '../toolbox/actions.web';
|
||||
showToolbox
|
||||
} from '../toolbox/actions';
|
||||
|
||||
|
||||
import { ADD_MESSAGE, SEND_MESSAGE, OPEN_CHAT, CLOSE_CHAT, SET_IS_POLL_TAB_FOCUSED } from './actionTypes';
|
||||
import { addMessage, clearMessages } from './actions';
|
||||
|
@ -255,20 +251,19 @@ function _addChatMsgListener(conference, store) {
|
|||
conference.on(
|
||||
JitsiConferenceEvents.ENDPOINT_MESSAGE_RECEIVED,
|
||||
(...args) => {
|
||||
const state = store.getState();
|
||||
|
||||
if (!isReactionsEnabled(state)) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.dispatch(endpointMessageReceived(...args));
|
||||
|
||||
if (args && args.length >= 2) {
|
||||
const [ { _id }, eventData ] = args;
|
||||
|
||||
if (eventData.name === ENDPOINT_REACTION_NAME) {
|
||||
batch(() => {
|
||||
store.dispatch(setToolboxVisible(true));
|
||||
store.dispatch(setToolboxTimeout(
|
||||
() => store.dispatch(hideToolbox()),
|
||||
5000)
|
||||
);
|
||||
store.dispatch(pushReactions(eventData.reactions));
|
||||
});
|
||||
|
||||
_handleReceivedMessage(store, {
|
||||
id: _id,
|
||||
|
@ -318,7 +313,7 @@ function _handleReceivedMessage({ dispatch, getState },
|
|||
// Logic for all platforms:
|
||||
const state = getState();
|
||||
const { isOpen: isChatOpen } = state['features/chat'];
|
||||
const { disableIncomingMessageSound } = state['features/base/config'];
|
||||
const { disableIncomingMessageSound, iAmRecorder } = state['features/base/config'];
|
||||
const { soundsIncomingMessage: soundEnabled } = state['features/base/settings'];
|
||||
|
||||
if (!disableIncomingMessageSound && soundEnabled && shouldPlaySound && !isChatOpen) {
|
||||
|
@ -356,8 +351,11 @@ function _handleReceivedMessage({ dispatch, getState },
|
|||
ts: timestamp
|
||||
});
|
||||
|
||||
if (!iAmRecorder) {
|
||||
dispatch(showToolbox(4000));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,11 +11,10 @@ import {
|
|||
import { translate } from '../../../base/i18n';
|
||||
import { getLocalParticipant, getParticipantCount, participantUpdated } from '../../../base/participants';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { playSound } from '../../../base/sounds';
|
||||
import { dockToolbox } from '../../../toolbox/actions.web';
|
||||
import { addReactionToBuffer } from '../../actions.any';
|
||||
import { toggleReactionsMenuVisibility } from '../../actions.web';
|
||||
import { RAISE_HAND_SOUND_ID, REACTIONS } from '../../constants';
|
||||
import { REACTIONS } from '../../constants';
|
||||
|
||||
import ReactionButton from './ReactionButton';
|
||||
|
||||
|
@ -54,12 +53,7 @@ type Props = {
|
|||
/**
|
||||
* Whether or not it's displayed in the overflow menu.
|
||||
*/
|
||||
overflowMenu: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not reaction sounds are enabled.
|
||||
*/
|
||||
_reactionSounds: boolean
|
||||
overflowMenu: boolean
|
||||
};
|
||||
|
||||
declare var APP: Object;
|
||||
|
@ -112,16 +106,13 @@ class ReactionsMenu extends Component<Props> {
|
|||
* @returns {void}
|
||||
*/
|
||||
_onToolbarToggleRaiseHand() {
|
||||
const { dispatch, _raisedHand, _reactionSounds } = this.props;
|
||||
const { dispatch, _raisedHand } = this.props;
|
||||
|
||||
sendAnalytics(createToolbarEvent(
|
||||
'raise.hand',
|
||||
{ enable: !_raisedHand }));
|
||||
this._doToggleRaiseHand();
|
||||
dispatch(toggleReactionsMenuVisibility());
|
||||
if (_reactionSounds && _raisedHand) {
|
||||
dispatch(playSound(RAISE_HAND_SOUND_ID));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -223,13 +214,11 @@ class ReactionsMenu extends Component<Props> {
|
|||
*/
|
||||
function mapStateToProps(state) {
|
||||
const localParticipant = getLocalParticipant(state);
|
||||
const { soundsReactions } = state['features/base/settings'];
|
||||
|
||||
return {
|
||||
_localParticipantID: localParticipant.id,
|
||||
_raisedHand: localParticipant.raisedHand,
|
||||
_participantCount: getParticipantCount(state),
|
||||
_reactionSounds: soundsReactions
|
||||
_participantCount: getParticipantCount(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,11 @@ import {
|
|||
SILENCE_SOUND_FILES
|
||||
} from './sounds';
|
||||
|
||||
/**
|
||||
* The payload name for the datachannel/endpoint reaction event
|
||||
*/
|
||||
export const ENDPOINT_REACTION_NAME = 'endpoint-reaction';
|
||||
|
||||
/**
|
||||
* The audio ID prefix of the audio element for which the {@link playAudio} action is
|
||||
* triggered when a new laugh reaction is received.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { getFeatureFlag, REACTIONS_ENABLED } from '../base/flags';
|
||||
import { getLocalParticipant } from '../base/participants';
|
||||
import { extractFqnFromPath } from '../dynamic-branding/functions';
|
||||
|
||||
|
@ -142,3 +143,19 @@ export function getReactionsSoundsThresholds(reactions: Array<string>) {
|
|||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the reactions are enabled.
|
||||
*
|
||||
* @param {Object} state - The Redux state object.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isReactionsEnabled(state: Object) {
|
||||
const { enableReactions } = state['features/base/config'];
|
||||
|
||||
if (navigator.product === 'ReactNative') {
|
||||
return enableReactions && getFeatureFlag(state, REACTIONS_ENABLED, true);
|
||||
}
|
||||
|
||||
return enableReactions;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import { batch } from 'react-redux';
|
||||
|
||||
import { ENDPOINT_REACTION_NAME } from '../../../modules/API/constants';
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import { MiddlewareRegistry } from '../base/redux';
|
||||
import { updateSettings } from '../base/settings';
|
||||
|
@ -17,6 +16,7 @@ import {
|
|||
PUSH_REACTIONS,
|
||||
SHOW_SOUNDS_NOTIFICATION
|
||||
} from './actionTypes';
|
||||
import { displayReactionSoundsNotification } from './actions';
|
||||
import {
|
||||
addReactionsToChat,
|
||||
flushReactionBuffer,
|
||||
|
@ -24,8 +24,7 @@ import {
|
|||
sendReactions,
|
||||
setReactionQueue
|
||||
} from './actions.any';
|
||||
import { displayReactionSoundsNotification } from './actions.web';
|
||||
import { RAISE_HAND_SOUND_ID, REACTIONS, SOUNDS_THRESHOLDS } from './constants';
|
||||
import { ENDPOINT_REACTION_NAME, RAISE_HAND_SOUND_ID, REACTIONS, SOUNDS_THRESHOLDS } from './constants';
|
||||
import {
|
||||
getReactionMessageFromBuffer,
|
||||
getReactionsSoundsThresholds,
|
||||
|
@ -128,7 +127,7 @@ MiddlewareRegistry.register(store => next => action => {
|
|||
const reactions = action.reactions;
|
||||
|
||||
batch(() => {
|
||||
if (!notificationDisplayed && soundsReactions) {
|
||||
if (!notificationDisplayed && soundsReactions && displayReactionSoundsNotification) {
|
||||
dispatch(displayReactionSoundsNotification());
|
||||
}
|
||||
if (soundsReactions) {
|
||||
|
|
|
@ -5,13 +5,13 @@ import { Divider } from 'react-native-paper';
|
|||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
|
||||
import { getFeatureFlag, REACTIONS_ENABLED } from '../../../base/flags';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
import { SharedDocumentButton } from '../../../etherpad';
|
||||
import { AudioRouteButton } from '../../../mobile/audio-mode';
|
||||
import { ParticipantsPaneButton } from '../../../participants-pane/components/native';
|
||||
import { ReactionMenu } from '../../../reactions/components';
|
||||
import { isReactionsEnabled } from '../../../reactions/functions.any';
|
||||
import { LiveStreamButton, RecordButton } from '../../../recording';
|
||||
import SecurityDialogButton from '../../../security/components/security-dialog/SecurityDialogButton';
|
||||
import { SharedVideoButton } from '../../../shared-video/components';
|
||||
|
@ -205,7 +205,7 @@ function _mapStateToProps(state) {
|
|||
_bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
|
||||
_isOpen: isDialogOpen(state, OverflowMenu_),
|
||||
_width: state['features/base/responsive-ui'].clientWidth,
|
||||
_reactionsEnabled: getFeatureFlag(state, REACTIONS_ENABLED, true)
|
||||
_reactionsEnabled: isReactionsEnabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@ import React from 'react';
|
|||
import { SafeAreaView, View } from 'react-native';
|
||||
|
||||
import { ColorSchemeRegistry } from '../../../base/color-scheme';
|
||||
import { getFeatureFlag, REACTIONS_ENABLED } from '../../../base/flags';
|
||||
import { connect } from '../../../base/redux';
|
||||
import { StyleType } from '../../../base/styles';
|
||||
import { ChatButton } from '../../../chat';
|
||||
import { ParticipantsPaneButton } from '../../../participants-pane/components/native';
|
||||
import { ReactionsMenuButton } from '../../../reactions/components';
|
||||
import { isReactionsEnabled } from '../../../reactions/functions.any';
|
||||
import { TileViewButton } from '../../../video-layout';
|
||||
import { isToolboxVisible, getMovableButtons } from '../../functions.native';
|
||||
import AudioMuteButton from '../AudioMuteButton';
|
||||
|
@ -133,7 +133,7 @@ function _mapStateToProps(state: Object): Object {
|
|||
_styles: ColorSchemeRegistry.get(state, 'Toolbox'),
|
||||
_visible: isToolboxVisible(state),
|
||||
_width: state['features/base/responsive-ui'].clientWidth,
|
||||
_reactionsEnabled: getFeatureFlag(state, REACTIONS_ENABLED, false)
|
||||
_reactionsEnabled: isReactionsEnabled(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { translate } from '../../../base/i18n';
|
|||
import JitsiMeetJS from '../../../base/lib-jitsi-meet';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantCount,
|
||||
haveParticipantWithScreenSharingFeature,
|
||||
raiseHand
|
||||
} from '../../../base/participants';
|
||||
|
@ -41,6 +42,7 @@ import { getParticipantsPaneOpen } from '../../../participants-pane/functions';
|
|||
import { addReactionToBuffer } from '../../../reactions/actions.any';
|
||||
import { ReactionsMenuButton } from '../../../reactions/components';
|
||||
import { REACTIONS } from '../../../reactions/constants';
|
||||
import { isReactionsEnabled } from '../../../reactions/functions.any';
|
||||
import {
|
||||
LiveStreamButton,
|
||||
RecordButton
|
||||
|
@ -152,10 +154,6 @@ type Props = {
|
|||
*/
|
||||
_isProfileDisabled: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the tile view is enabled.
|
||||
*/
|
||||
_tileViewEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the current meeting belongs to a JaaS user.
|
||||
|
@ -177,6 +175,11 @@ type Props = {
|
|||
*/
|
||||
_overflowMenuVisible: boolean,
|
||||
|
||||
/**
|
||||
* Number of participants in the conference.
|
||||
*/
|
||||
_participantCount: number,
|
||||
|
||||
/**
|
||||
* Whether or not the participants pane is open.
|
||||
*/
|
||||
|
@ -187,6 +190,11 @@ type Props = {
|
|||
*/
|
||||
_raisedHand: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not reactions feature is enabled.
|
||||
*/
|
||||
_reactionsEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the local participant is screenSharing.
|
||||
*/
|
||||
|
@ -197,6 +205,11 @@ type Props = {
|
|||
*/
|
||||
_sharingVideo: boolean,
|
||||
|
||||
/**
|
||||
* Whether or not the tile view is enabled.
|
||||
*/
|
||||
_tileViewEnabled: boolean,
|
||||
|
||||
/**
|
||||
* The enabled buttons.
|
||||
*/
|
||||
|
@ -212,11 +225,6 @@ type Props = {
|
|||
*/
|
||||
_virtualSource: Object,
|
||||
|
||||
/**
|
||||
* Whether or not reactions feature is enabled.
|
||||
*/
|
||||
_reactionsEnabled: boolean,
|
||||
|
||||
/**
|
||||
* Invoked to active other features of the app.
|
||||
*/
|
||||
|
@ -235,12 +243,16 @@ type Props = {
|
|||
|
||||
declare var APP: Object;
|
||||
|
||||
type State = {
|
||||
reactionsShortcutsRegistered: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the conference toolbox on React/Web.
|
||||
*
|
||||
* @extends Component
|
||||
*/
|
||||
class Toolbox extends Component<Props> {
|
||||
class Toolbox extends Component<Props, State> {
|
||||
/**
|
||||
* Initializes a new {@code Toolbox} instance.
|
||||
*
|
||||
|
@ -250,6 +262,10 @@ class Toolbox extends Component<Props> {
|
|||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
reactionsShortcutsRegistered: false
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once per instance.
|
||||
this._onMouseOut = this._onMouseOut.bind(this);
|
||||
this._onMouseOver = this._onMouseOver.bind(this);
|
||||
|
@ -279,7 +295,7 @@ class Toolbox extends Component<Props> {
|
|||
* @returns {void}
|
||||
*/
|
||||
componentDidMount() {
|
||||
const { _toolbarButtons, t, dispatch, _reactionsEnabled } = this.props;
|
||||
const { _toolbarButtons, t, dispatch, _reactionsEnabled, _participantCount } = this.props;
|
||||
const KEYBOARD_SHORTCUTS = [
|
||||
isToolbarButtonEnabled('videoquality', _toolbarButtons) && {
|
||||
character: 'A',
|
||||
|
@ -328,7 +344,7 @@ class Toolbox extends Component<Props> {
|
|||
}
|
||||
});
|
||||
|
||||
if (_reactionsEnabled) {
|
||||
if (_reactionsEnabled && _participantCount > 1) {
|
||||
const REACTION_SHORTCUTS = Object.keys(REACTIONS).map(key => {
|
||||
const onShortcutSendReaction = () => {
|
||||
dispatch(addReactionToBuffer(key));
|
||||
|
@ -373,6 +389,41 @@ class Toolbox extends Component<Props> {
|
|||
this._onSetOverflowVisible(false);
|
||||
this.props.dispatch(setToolbarHovered(false));
|
||||
}
|
||||
|
||||
if (!this.state.reactionsShortcutsRegistered
|
||||
&& (prevProps._reactionsEnabled !== this.props._reactionsEnabled
|
||||
|| prevProps._participantCount !== this.props._participantCount)) {
|
||||
if (this.props._reactionsEnabled && this.props._participantCount > 1) {
|
||||
// eslint-disable-next-line react/no-did-update-set-state
|
||||
this.setState({
|
||||
reactionsShortcutsRegistered: true
|
||||
});
|
||||
const REACTION_SHORTCUTS = Object.keys(REACTIONS).map(key => {
|
||||
const onShortcutSendReaction = () => {
|
||||
this.props.dispatch(addReactionToBuffer(key));
|
||||
sendAnalytics(createShortcutEvent(
|
||||
`reaction.${key}`
|
||||
));
|
||||
};
|
||||
|
||||
return {
|
||||
character: REACTIONS[key].shortcutChar,
|
||||
exec: onShortcutSendReaction,
|
||||
helpDescription: this.props.t(`toolbar.reaction${key.charAt(0).toUpperCase()}${key.slice(1)}`),
|
||||
altKey: true
|
||||
};
|
||||
});
|
||||
|
||||
REACTION_SHORTCUTS.forEach(shortcut => {
|
||||
APP.keyboardshortcut.registerShortcut(
|
||||
shortcut.character,
|
||||
null,
|
||||
shortcut.exec,
|
||||
shortcut.helpDescription,
|
||||
shortcut.altKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -385,7 +436,7 @@ class Toolbox extends Component<Props> {
|
|||
[ 'A', 'C', 'D', 'R', 'S' ].forEach(letter =>
|
||||
APP.keyboardshortcut.unregisterShortcut(letter));
|
||||
|
||||
if (this.props._reactionsEnabled) {
|
||||
if (this.props._reactionsEnabled && this.state.reactionsShortcutsRegistered) {
|
||||
Object.keys(REACTIONS).map(key => REACTIONS[key].shortcutChar)
|
||||
.forEach(letter =>
|
||||
APP.keyboardshortcut.unregisterShortcut(letter, true));
|
||||
|
@ -1262,7 +1313,6 @@ function _mapStateToProps(state, ownProps) {
|
|||
const localParticipant = getLocalParticipant(state);
|
||||
const localVideo = getLocalVideoTrack(state['features/base/tracks']);
|
||||
const { clientWidth } = state['features/base/responsive-ui'];
|
||||
const { enableReactions } = state['features/base/config'];
|
||||
|
||||
let desktopSharingDisabledTooltipKey;
|
||||
|
||||
|
@ -1285,29 +1335,30 @@ function _mapStateToProps(state, ownProps) {
|
|||
}
|
||||
|
||||
return {
|
||||
_backgroundType: state['features/virtual-background'].backgroundType,
|
||||
_chatOpen: state['features/chat'].isOpen,
|
||||
_clientWidth: clientWidth,
|
||||
_conference: conference,
|
||||
_desktopSharingEnabled: desktopSharingEnabled,
|
||||
_backgroundType: state['features/virtual-background'].backgroundType,
|
||||
_virtualSource: state['features/virtual-background'].virtualSource,
|
||||
_desktopSharingDisabledTooltipKey: desktopSharingDisabledTooltipKey,
|
||||
_dialog: Boolean(state['features/base/dialog'].component),
|
||||
_feedbackConfigured: Boolean(callStatsID),
|
||||
_fullScreen: fullScreen,
|
||||
_isProfileDisabled: Boolean(state['features/base/config'].disableProfile),
|
||||
_isMobile: isMobileBrowser(),
|
||||
_isVpaasMeeting: isVpaasMeeting(state),
|
||||
_fullScreen: fullScreen,
|
||||
_tileViewEnabled: shouldDisplayTileView(state),
|
||||
_localParticipantID: localParticipant?.id,
|
||||
_localVideo: localVideo,
|
||||
_overflowMenuVisible: overflowMenuVisible,
|
||||
_participantCount: getParticipantCount(state),
|
||||
_participantsPaneOpen: getParticipantsPaneOpen(state),
|
||||
_raisedHand: localParticipant?.raisedHand,
|
||||
_reactionsEnabled: isReactionsEnabled(state),
|
||||
_screenSharing: isScreenVideoShared(state),
|
||||
_tileViewEnabled: shouldDisplayTileView(state),
|
||||
_toolbarButtons: toolbarButtons,
|
||||
_visible: isToolboxVisible(state),
|
||||
_reactionsEnabled: enableReactions
|
||||
_virtualSource: state['features/virtual-background'].virtualSource,
|
||||
_visible: isToolboxVisible(state)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue