Calling: Device Selection
This commit is contained in:
parent
8b34294c97
commit
8ab1013f70
17 changed files with 1038 additions and 135 deletions
192
ts/components/CallingDeviceSelection.tsx
Normal file
192
ts/components/CallingDeviceSelection.tsx
Normal file
|
@ -0,0 +1,192 @@
|
|||
import * as React from 'react';
|
||||
|
||||
import { ConfirmationModal } from './ConfirmationModal';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
import {
|
||||
AudioDevice,
|
||||
CallingDeviceType,
|
||||
ChangeIODevicePayloadType,
|
||||
MediaDeviceSettings,
|
||||
} from '../types/Calling';
|
||||
|
||||
export type Props = MediaDeviceSettings & {
|
||||
changeIODevice: (payload: ChangeIODevicePayloadType) => void;
|
||||
i18n: LocalizerType;
|
||||
toggleSettings: () => void;
|
||||
};
|
||||
|
||||
function renderAudioOptions(
|
||||
devices: Array<AudioDevice>,
|
||||
i18n: LocalizerType,
|
||||
selectedDevice: AudioDevice | undefined
|
||||
): JSX.Element {
|
||||
if (!devices.length) {
|
||||
return (
|
||||
<option aria-selected={true}>
|
||||
{i18n('callingDeviceSelection__select--no-device')}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{devices.map((device: AudioDevice) => {
|
||||
const isSelected =
|
||||
selectedDevice && selectedDevice.index === device.index;
|
||||
return (
|
||||
<option
|
||||
aria-selected={isSelected}
|
||||
key={device.index}
|
||||
value={device.index}
|
||||
>
|
||||
{device.name}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function renderVideoOptions(
|
||||
devices: Array<MediaDeviceInfo>,
|
||||
i18n: LocalizerType,
|
||||
selectedCamera: string | undefined
|
||||
): JSX.Element {
|
||||
if (!devices.length) {
|
||||
return (
|
||||
<option aria-selected={true}>
|
||||
{i18n('callingDeviceSelection__select--no-device')}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{devices.map((device: MediaDeviceInfo) => {
|
||||
const isSelected = selectedCamera === device.deviceId;
|
||||
|
||||
return (
|
||||
<option
|
||||
aria-selected={isSelected}
|
||||
key={device.deviceId}
|
||||
value={device.deviceId}
|
||||
>
|
||||
{device.label}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function createAudioChangeHandler(
|
||||
devices: Array<AudioDevice>,
|
||||
changeIODevice: (payload: ChangeIODevicePayloadType) => void,
|
||||
type: CallingDeviceType.SPEAKER | CallingDeviceType.MICROPHONE
|
||||
) {
|
||||
return (ev: React.FormEvent<HTMLSelectElement>): void => {
|
||||
changeIODevice({
|
||||
type,
|
||||
selectedDevice: devices[Number(ev.currentTarget.value)],
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function createCameraChangeHandler(
|
||||
changeIODevice: (payload: ChangeIODevicePayloadType) => void
|
||||
) {
|
||||
return (ev: React.FormEvent<HTMLSelectElement>): void => {
|
||||
changeIODevice({
|
||||
type: CallingDeviceType.CAMERA,
|
||||
selectedDevice: String(ev.currentTarget.value),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export const CallingDeviceSelection = ({
|
||||
availableCameras,
|
||||
availableMicrophones,
|
||||
availableSpeakers,
|
||||
changeIODevice,
|
||||
i18n,
|
||||
selectedCamera,
|
||||
selectedMicrophone,
|
||||
selectedSpeaker,
|
||||
toggleSettings,
|
||||
}: Props): JSX.Element => {
|
||||
const selectedMicrophoneIndex = selectedMicrophone
|
||||
? selectedMicrophone.index
|
||||
: undefined;
|
||||
const selectedSpeakerIndex = selectedSpeaker
|
||||
? selectedSpeaker.index
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<ConfirmationModal actions={[]} i18n={i18n} onClose={toggleSettings}>
|
||||
<div className="module-calling-device-selection">
|
||||
<button
|
||||
className="module-calling-device-selection__close-button"
|
||||
onClick={toggleSettings}
|
||||
tabIndex={0}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h1 className="module-calling-device-selection__title">
|
||||
{i18n('callingDeviceSelection__settings')}
|
||||
</h1>
|
||||
|
||||
<label className="module-calling-device-selection__label">
|
||||
{i18n('callingDeviceSelection__label--video')}
|
||||
</label>
|
||||
<div className="module-calling-device-selection__select">
|
||||
<select
|
||||
disabled={!availableCameras.length}
|
||||
name="video"
|
||||
// tslint:disable-next-line react-a11y-no-onchange
|
||||
onChange={createCameraChangeHandler(changeIODevice)}
|
||||
value={selectedCamera}
|
||||
>
|
||||
{renderVideoOptions(availableCameras, i18n, selectedCamera)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label className="module-calling-device-selection__label">
|
||||
{i18n('callingDeviceSelection__label--audio-input')}
|
||||
</label>
|
||||
<div className="module-calling-device-selection__select">
|
||||
<select
|
||||
disabled={!availableMicrophones.length}
|
||||
name="audio-input"
|
||||
// tslint:disable-next-line react-a11y-no-onchange
|
||||
onChange={createAudioChangeHandler(
|
||||
availableMicrophones,
|
||||
changeIODevice,
|
||||
CallingDeviceType.MICROPHONE
|
||||
)}
|
||||
value={selectedMicrophoneIndex}
|
||||
>
|
||||
{renderAudioOptions(availableMicrophones, i18n, selectedMicrophone)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<label className="module-calling-device-selection__label">
|
||||
{i18n('callingDeviceSelection__label--audio-output')}
|
||||
</label>
|
||||
<div className="module-calling-device-selection__select">
|
||||
<select
|
||||
disabled={!availableSpeakers.length}
|
||||
name="audio-output"
|
||||
// tslint:disable-next-line react-a11y-no-onchange
|
||||
onChange={createAudioChangeHandler(
|
||||
availableSpeakers,
|
||||
changeIODevice,
|
||||
CallingDeviceType.SPEAKER
|
||||
)}
|
||||
value={selectedSpeakerIndex}
|
||||
>
|
||||
{renderAudioOptions(availableSpeakers, i18n, selectedSpeaker)}
|
||||
</select>
|
||||
</div>
|
||||
</ConfirmationModal>
|
||||
);
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue