jiti-meet/react/features/mobile/audio-mode/components/AudioRoutePickerDialog.js

193 lines
4.6 KiB
JavaScript

// @flow
import _ from 'lodash';
import React, { Component } from 'react';
import { NativeModules } from 'react-native';
import { connect } from 'react-redux';
import { hideDialog, SimpleBottomSheet } from '../../../base/dialog';
import { translate } from '../../../base/i18n';
/**
* {@code PasswordRequiredPrompt}'s React {@code Component} prop types.
*/
type Props = {
/**
* Used for hiding the dialog when the selection was completed.
*/
dispatch: Function,
/**
* Invoked to obtain translated strings.
*/
t: Function
};
type State = {
/**
* Array of available devices.
*/
devices: Array<string>
};
const { AudioMode } = NativeModules;
/**
* Maps each device type to a display name and icon.
*/
const deviceInfoMap = {
BLUETOOTH: {
iconName: 'bluetooth',
text: 'audioDevices.bluetooth',
type: 'BLUETOOTH'
},
EARPIECE: {
iconName: 'phone-talk',
text: 'audioDevices.phone',
type: 'EARPIECE'
},
HEADPHONES: {
iconName: 'headset',
text: 'audioDevices.headphones',
type: 'HEADPHONES'
},
SPEAKER: {
iconName: 'volume',
text: 'audioDevices.speaker',
type: 'SPEAKER'
}
};
/**
* The exported React {@code Component}. {@code AudioRoutePickerDialog} is
* exported only if the {@code AudioMode} module has the capability to get / set
* audio devices.
*/
let AudioRoutePickerDialog_;
/**
* Implements a React {@code Component} which prompts the user when a password
* is required to join a conference.
*/
class AudioRoutePickerDialog extends Component<Props, State> {
state = {
/**
* Available audio devices, it will be set in
* {@link #componentWillMount()}.
*/
devices: []
};
/**
* Initializes a new {@code PasswordRequiredPrompt} instance.
*
* @param {Props} props - The read-only React {@code Component} props with
* which the new instance is to be initialized.
*/
constructor(props) {
super(props);
// Bind event handlers so they are only bound once per instance.
this._onCancel = this._onCancel.bind(this);
this._onSubmit = this._onSubmit.bind(this);
}
/**
* Initializes the device list by querying {@code AudioMode}.
*
* @inheritdoc
*/
componentWillMount() {
AudioMode.getAudioDevices().then(({ devices, selected }) => {
const audioDevices = [];
if (devices) {
for (const device of devices) {
if (deviceInfoMap[device]) {
const info = Object.assign({}, deviceInfoMap[device]);
info.selected = device === selected;
info.text = this.props.t(info.text);
audioDevices.push(info);
}
}
}
if (audioDevices) {
// Make sure devices is alphabetically sorted.
this.setState({
devices: _.sortBy(audioDevices, 'text')
});
}
});
}
/**
* Dispatches a redux action to hide this sheet.
*
* @returns {void}
*/
_hide() {
this.props.dispatch(hideDialog(AudioRoutePickerDialog_));
}
_onCancel: () => void;
/**
* Cancels the dialog by hiding it.
*
* @private
* @returns {void}
*/
_onCancel() {
this._hide();
}
_onSubmit: (?Object) => void;
/**
* Handles the selection of a device on the sheet. The selected device will
* be used by {@code AudioMode}.
*
* @param {Object} device - Object representing the selected device.
* @private
* @returns {void}
*/
_onSubmit(device) {
this._hide();
AudioMode.setAudioDevice(device.type);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
const { devices } = this.state;
if (!devices.length) {
return null;
}
return (
<SimpleBottomSheet
onCancel = { this._onCancel }
onSubmit = { this._onSubmit }
options = { devices } />
);
}
}
// Only export the dialog if we have support for getting / setting audio devices
// in AudioMode.
if (AudioMode.getAudioDevices && AudioMode.setAudioDevice) {
AudioRoutePickerDialog_ = translate(connect()(AudioRoutePickerDialog));
}
export default AudioRoutePickerDialog_;