From 1c6577f4db3d2fa1bcfe1eef2c990981b31432d6 Mon Sep 17 00:00:00 2001 From: Max Franke Date: Wed, 8 Jun 2022 16:42:41 -0300 Subject: [PATCH 1/3] feat(audio): unify audio buttons Move device selection dropdown to microphone button Move option 'leave audio' to an option within the dropdown Remove the audio exit button when device !== mobile --- .../audio/audio-controls/component.jsx | 94 ++--------- .../input-stream-live-selector/component.jsx | 152 +++++++++++++++--- .../input-stream-live-selector/styles.js | 55 ++++++- 3 files changed, 193 insertions(+), 108 deletions(-) diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx index f42e44b1d2..5f9a252525 100755 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx @@ -6,7 +6,6 @@ import withShortcutHelper from '/imports/ui/components/shortcut-help/service'; import InputStreamLiveSelectorContainer from './input-stream-live-selector/container'; import MutedAlert from '/imports/ui/components/muted-alert/component'; import Styled from './styles'; -import Settings from '/imports/ui/services/settings'; const intlMessages = defineMessages({ joinAudio: { @@ -46,9 +45,7 @@ const propTypes = { class AudioControls extends PureComponent { constructor(props) { super(props); - this.renderLeaveButtonWithoutLiveStreamSelector = this - .renderLeaveButtonWithoutLiveStreamSelector.bind(this); - + this.renderButtonsAndStreamSelector = this.renderButtonsAndStreamSelector.bind(this); this.renderJoinLeaveButton = this.renderJoinLeaveButton.bind(this); } @@ -78,49 +75,20 @@ class AudioControls extends PureComponent { ); } - static renderLeaveButtonWithLiveStreamSelector(props) { - const { handleLeaveAudio } = props; - return ( - - ); - } - - renderLeaveButtonWithoutLiveStreamSelector() { + renderButtonsAndStreamSelector(_enableDynamicDeviceSelection) { const { - handleJoinAudio, - handleLeaveAudio, - disable, - inAudio, - listenOnly, - intl, - shortcuts, + handleLeaveAudio, handleToggleMuteMicrophone, muted, disable, talking, } = this.props; - let joinIcon = 'no_audio'; - if (inAudio) { - if (listenOnly) { - joinIcon = 'listen'; - } else { - joinIcon = 'volume_level_2'; - } - } - return ( - ); } @@ -138,16 +106,10 @@ class AudioControls extends PureComponent { enableDynamicAudioDeviceSelection = true; } - const _enableDynamicDeviceSelection = enableDynamicAudioDeviceSelection - && !isMobile; + const _enableDynamicDeviceSelection = enableDynamicAudioDeviceSelection && !isMobile; if (inAudio) { - if (_enableDynamicDeviceSelection) { - return AudioControls.renderLeaveButtonWithLiveStreamSelector(this - .props); - } - - return this.renderLeaveButtonWithoutLiveStreamSelector(); + return this.renderButtonsAndStreamSelector(_enableDynamicDeviceSelection); } return this.renderJoinButton(); @@ -155,13 +117,8 @@ class AudioControls extends PureComponent { render() { const { - handleToggleMuteMicrophone, showMute, muted, - disable, - talking, - intl, - shortcuts, isVoiceUser, listenOnly, inputStream, @@ -169,30 +126,6 @@ class AudioControls extends PureComponent { isPresenter, } = this.props; - const label = muted ? intl.formatMessage(intlMessages.unmuteAudio) - : intl.formatMessage(intlMessages.muteAudio); - - const { animations } = Settings.application; - - const toggleMuteBtn = ( - - ); - const MUTE_ALERT_CONFIG = Meteor.settings.public.app.mutedAlert; const { enabled: muteAlertEnabled } = MUTE_ALERT_CONFIG; @@ -204,7 +137,6 @@ class AudioControls extends PureComponent { }} /> ) : null} - {showMute && isVoiceUser ? toggleMuteBtn : null} { this.renderJoinLeaveButton() } diff --git a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/input-stream-live-selector/component.jsx b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/input-stream-live-selector/component.jsx index 16be3f8bf1..a5c6a25770 100644 --- a/bigbluebutton-html5/imports/ui/components/audio/audio-controls/input-stream-live-selector/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/audio/audio-controls/input-stream-live-selector/component.jsx @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import logger from '/imports/startup/client/logger'; import Auth from '/imports/ui/services/auth'; +import Settings from '/imports/ui/services/settings'; import { defineMessages, injectIntl } from 'react-intl'; import PropTypes from 'prop-types'; import Button from '/imports/ui/components/common/button/component'; @@ -39,6 +40,14 @@ const intlMessages = defineMessages({ id: 'app.audio.speakers', description: 'Output audio dropdown item label', }, + muteAudio: { + id: 'app.actionsBar.muteLabel', + description: 'Mute audio button label', + }, + unmuteAudio: { + id: 'app.actionsBar.unmuteLabel', + description: 'Unmute audio button label', + }, }); const propTypes = { @@ -53,6 +62,15 @@ const propTypes = { currentOutputDeviceId: PropTypes.string.isRequired, isListenOnly: PropTypes.bool.isRequired, isAudioConnected: PropTypes.bool.isRequired, + _enableDynamicDeviceSelection: PropTypes.bool.isRequired, + handleToggleMuteMicrophone: PropTypes.func.isRequired, + muted: PropTypes.bool.isRequired, + disable: PropTypes.bool.isRequired, + talking: PropTypes.bool, +}; + +const defaultProps = { + talking: false, }; class InputStreamLiveSelector extends Component { @@ -67,6 +85,10 @@ class InputStreamLiveSelector extends Component { super(props); this.updateDeviceList = this.updateDeviceList.bind(this); this.renderDeviceList = this.renderDeviceList.bind(this); + this.renderListenOnlyButton = this.renderListenOnlyButton.bind(this); + this.renderMuteToggleButton = this.renderMuteToggleButton.bind(this); + this.renderButtonsWithSelectorDevice = this.renderButtonsWithSelectorDevice.bind(this); + this.renderButtonsWithoutSelectorDevice = this.renderButtonsWithoutSelectorDevice.bind(this); this.state = { audioInputDevices: null, audioOutputDevices: null, @@ -206,8 +228,7 @@ class InputStreamLiveSelector extends Component { }); } - renderDeviceList(deviceKind, list, callback, title, currentDeviceId, - renderSeparator = true) { + renderDeviceList(deviceKind, list, callback, title, currentDeviceId) { const { intl, } = this.props; @@ -216,20 +237,18 @@ class InputStreamLiveSelector extends Component { { key: `audioDeviceList-${deviceKind}`, label: title, + iconRight: (deviceKind === 'audioinput') ? 'unmute' : 'volume_level_2', disabled: true, - dividerTop: (!renderSeparator), + divider: true, }, ]; - const customStyles = { fontWeight: 'bold' }; - const disableDeviceStyles = { pointerEvents: 'none' }; - const deviceList = (listLength > 0) ? list.map((device) => ( { key: `${device.deviceId}-${deviceKind}`, label: InputStreamLiveSelector.truncateDeviceName(device.label), - customStyles: (device.deviceId === currentDeviceId) ? customStyles : null, + customStyles: (device.deviceId === currentDeviceId) && Styled.SelectedLabel, iconRight: (device.deviceId === currentDeviceId) ? 'check' : null, onClick: () => this.onDeviceListClick(device.deviceId, deviceKind, callback), } @@ -240,13 +259,77 @@ class InputStreamLiveSelector extends Component { label: listLength < 0 ? intl.formatMessage(intlMessages.loading) : intl.formatMessage(intlMessages.noDeviceFound), - customStyles: disableDeviceStyles, }, ]; return listTitle.concat(deviceList); } - render() { + renderMuteToggleButton() { + const { + intl, + shortcuts, + handleToggleMuteMicrophone, + muted, + disable, + talking, + } = this.props; + + const label = muted ? intl.formatMessage(intlMessages.unmuteAudio) + : intl.formatMessage(intlMessages.muteAudio); + + const { animations } = Settings.application; + + return ( + { + e.stopPropagation(); + handleToggleMuteMicrophone(); + }} + disabled={disable} + hideLabel + label={label} + aria-label={label} + color={!muted ? 'primary' : 'default'} + ghost={muted} + icon={muted ? 'mute' : 'unmute'} + size="lg" + circle + accessKey={shortcuts.togglemute} + talking={talking || undefined} + animations={animations} + data-test="toggleMicrophoneButton" + /> + ); + } + + renderListenOnlyButton() { + const { + handleLeaveAudio, + intl, + shortcuts, + isListenOnly, + } = this.props; + + return ( +