bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/audio/audio-controls/component.jsx
prlanzarin 141c553b17 fix(audio): review device selection in mobile endpoints
Mobile users have no way to change I/O devices after joining audio.
The removal of the audio options chevron in mobile browsers was supposed
to be replaced by something else - in this case, by the dedicated
leave/join audio button. That didn't happen, leave/join audio button
retained the old behavior.

Review device selection in mobile endpoints via two UI/UX changes:
  - Restore the device selection chevron/icon in mobile endpoints
  - Override the leave/join button action in mobile endpoints so that it
    opens the device selection contextual menu, which also includes the
    "Leave audio" option. This retains the old behavior (leaving audio)
    while also providing an way for users to change devices mid-call in
    mobile browsers.
2024-04-30 14:29:53 -03:00

180 lines
4.6 KiB
JavaScript
Executable File

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import deviceInfo from '/imports/utils/deviceInfo';
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 Button from '/imports/ui/components/common/button/component';
import AudioModalContainer from '../audio-modal/container';
const intlMessages = defineMessages({
joinAudio: {
id: 'app.audio.joinAudio',
description: 'Join audio button label',
},
leaveAudio: {
id: 'app.audio.leaveAudio',
description: 'Leave audio button label',
},
muteAudio: {
id: 'app.actionsBar.muteLabel',
description: 'Mute audio button label',
},
unmuteAudio: {
id: 'app.actionsBar.unmuteLabel',
description: 'Unmute audio button label',
},
});
const propTypes = {
shortcuts: PropTypes.objectOf(PropTypes.string).isRequired,
handleToggleMuteMicrophone: PropTypes.func.isRequired,
handleLeaveAudio: PropTypes.func.isRequired,
disable: PropTypes.bool.isRequired,
muted: PropTypes.bool.isRequired,
showMute: PropTypes.bool.isRequired,
inAudio: PropTypes.bool.isRequired,
listenOnly: PropTypes.bool.isRequired,
intl: PropTypes.shape({
formatMessage: PropTypes.func.isRequired,
}).isRequired,
talking: PropTypes.bool.isRequired,
};
class AudioControls extends PureComponent {
constructor(props) {
super(props);
this.state = {
isAudioModalOpen: false,
};
this.renderButtonsAndStreamSelector = this.renderButtonsAndStreamSelector.bind(this);
this.renderJoinLeaveButton = this.renderJoinLeaveButton.bind(this);
this.setAudioModalIsOpen = this.setAudioModalIsOpen.bind(this);
}
renderJoinButton() {
const {
disable,
intl,
shortcuts,
joinListenOnly,
isConnected
} = this.props;
return (
<Button
onClick={() => this.handleJoinAudio(joinListenOnly, isConnected)}
disabled={disable}
hideLabel
aria-label={intl.formatMessage(intlMessages.joinAudio)}
label={intl.formatMessage(intlMessages.joinAudio)}
data-test="joinAudio"
color="default"
ghost
icon="no_audio"
size="lg"
circle
accessKey={shortcuts.joinaudio}
/>
);
}
renderButtonsAndStreamSelector(_enableDynamicDeviceSelection) {
const {
handleLeaveAudio, handleToggleMuteMicrophone, muted, disable, talking,
} = this.props;
const { isMobile } = deviceInfo;
return (
<InputStreamLiveSelectorContainer {...{
handleLeaveAudio,
handleToggleMuteMicrophone,
muted,
disable,
talking,
isMobile,
_enableDynamicDeviceSelection,
}}
/>
);
}
renderJoinLeaveButton() {
const {
inAudio,
} = this.props;
let { enableDynamicAudioDeviceSelection } = Meteor.settings.public.app;
if (typeof enableDynamicAudioDeviceSelection === 'undefined') {
enableDynamicAudioDeviceSelection = true;
}
if (inAudio) {
return this.renderButtonsAndStreamSelector(enableDynamicAudioDeviceSelection);
}
return this.renderJoinButton();
}
handleJoinAudio(joinListenOnly, isConnected) {
(isConnected()
? joinListenOnly()
: this.setAudioModalIsOpen(true)
)}
setAudioModalIsOpen(value) {
this.setState({ isAudioModalOpen: value })
}
render() {
const {
showMute,
muted,
isVoiceUser,
listenOnly,
inputStream,
isViewer,
isPresenter,
} = this.props;
const { isAudioModalOpen } = this.state;
const MUTE_ALERT_CONFIG = Meteor.settings.public.app.mutedAlert;
const { enabled: muteAlertEnabled } = MUTE_ALERT_CONFIG;
return (
<Styled.Container>
{isVoiceUser && inputStream && muteAlertEnabled && !listenOnly && muted && showMute ? (
<MutedAlert {...{
muted, inputStream, isViewer, isPresenter,
}}
/>
) : null}
{
this.renderJoinLeaveButton()
}
{
isAudioModalOpen ? <AudioModalContainer
{...{
priority: "low",
setIsOpen: this.setAudioModalIsOpen,
isOpen: isAudioModalOpen
}}
/> : null
}
</Styled.Container>
);
}
}
AudioControls.propTypes = propTypes;
export default withShortcutHelper(injectIntl(AudioControls), ['joinAudio',
'leaveAudio', 'toggleMute']);