signal-desktop/ts/components/CallingDeviceSelection.tsx

196 lines
5.1 KiB
TypeScript
Raw Normal View History

2023-01-03 19:55:46 +00:00
// Copyright 2020 Signal Messenger, LLC
2020-10-30 20:34:04 +00:00
// SPDX-License-Identifier: AGPL-3.0-only
2020-08-27 00:03:42 +00:00
import * as React from 'react';
2023-01-09 18:38:57 +00:00
import type { AudioDevice } from '@signalapp/ringrtc';
2020-08-27 00:03:42 +00:00
import type { Option } from './Select';
import { Modal } from './Modal';
import { Select } from './Select';
import type { LocalizerType } from '../types/Util';
import type {
2020-08-27 00:03:42 +00:00
ChangeIODevicePayloadType,
MediaDeviceSettings,
} from '../types/Calling';
import { CallingDeviceType } from '../types/Calling';
import { Theme } from '../util/theme';
2020-08-27 00:03:42 +00:00
export type Props = MediaDeviceSettings & {
changeIODevice: (payload: ChangeIODevicePayloadType) => void;
i18n: LocalizerType;
toggleSettings: () => void;
};
function localizeDefault(i18n: LocalizerType, deviceLabel: string): string {
return deviceLabel.toLowerCase().startsWith('default')
? deviceLabel.replace(
/default/i,
2023-03-30 00:03:25 +00:00
i18n('icu:callingDeviceSelection__select--default')
)
: deviceLabel;
}
2020-08-27 00:03:42 +00:00
function renderAudioOptions(
devices: Array<AudioDevice>,
i18n: LocalizerType
): Array<Option> {
2020-08-27 00:03:42 +00:00
if (!devices.length) {
return [
{
text: i18n('icu:callingDeviceSelection__select--no-device'),
value: '',
},
];
2020-08-27 00:03:42 +00:00
}
return devices.map(device => {
return {
text: localizeDefault(i18n, device.name),
value: device.index,
};
});
2020-08-27 00:03:42 +00:00
}
function renderVideoOptions(
devices: Array<MediaDeviceInfo>,
i18n: LocalizerType
): Array<Option> {
2020-08-27 00:03:42 +00:00
if (!devices.length) {
return [
{
text: i18n('icu:callingDeviceSelection__select--no-device'),
value: '',
},
];
2020-08-27 00:03:42 +00:00
}
return devices.map((device: MediaDeviceInfo) => {
return {
text: localizeDefault(i18n, device.label),
value: device.deviceId,
};
});
2020-08-27 00:03:42 +00:00
}
function createAudioChangeHandler(
devices: Array<AudioDevice>,
changeIODevice: (payload: ChangeIODevicePayloadType) => void,
type: CallingDeviceType.SPEAKER | CallingDeviceType.MICROPHONE
) {
return (value: string): void => {
2020-08-27 00:03:42 +00:00
changeIODevice({
type,
selectedDevice: devices[Number(value)],
2020-08-27 00:03:42 +00:00
});
};
}
function createCameraChangeHandler(
changeIODevice: (payload: ChangeIODevicePayloadType) => void
) {
return (value: string): void => {
2020-08-27 00:03:42 +00:00
changeIODevice({
type: CallingDeviceType.CAMERA,
selectedDevice: value,
2020-08-27 00:03:42 +00:00
});
};
}
2022-11-18 00:45:19 +00:00
export function CallingDeviceSelection({
2020-08-27 00:03:42 +00:00
availableCameras,
availableMicrophones,
availableSpeakers,
changeIODevice,
i18n,
selectedCamera,
selectedMicrophone,
selectedSpeaker,
toggleSettings,
2022-11-18 00:45:19 +00:00
}: Props): JSX.Element {
2020-08-27 00:03:42 +00:00
const selectedMicrophoneIndex = selectedMicrophone
? selectedMicrophone.index
: undefined;
const selectedSpeakerIndex = selectedSpeaker
? selectedSpeaker.index
: undefined;
return (
2022-09-27 20:24:21 +00:00
<Modal
modalName="CallingDeviceSelection"
i18n={i18n}
theme={Theme.Dark}
onClose={toggleSettings}
>
2020-08-27 00:03:42 +00:00
<div className="module-calling-device-selection">
<button
2020-09-12 00:46:52 +00:00
type="button"
2020-08-27 00:03:42 +00:00
className="module-calling-device-selection__close-button"
onClick={toggleSettings}
tabIndex={0}
2023-03-30 00:03:25 +00:00
aria-label={i18n('icu:close')}
2020-08-27 00:03:42 +00:00
/>
</div>
<h1 className="module-calling-device-selection__title">
2023-03-30 00:03:25 +00:00
{i18n('icu:callingDeviceSelection__settings')}
2020-08-27 00:03:42 +00:00
</h1>
2020-09-12 00:46:52 +00:00
<label htmlFor="video" className="module-calling-device-selection__label">
2023-03-30 00:03:25 +00:00
{i18n('icu:callingDeviceSelection__label--video')}
2020-08-27 00:03:42 +00:00
</label>
<div className="module-calling-device-selection__select">
<Select
2020-08-27 00:03:42 +00:00
disabled={!availableCameras.length}
id="camera"
name="camera"
2020-08-27 00:03:42 +00:00
onChange={createCameraChangeHandler(changeIODevice)}
options={renderVideoOptions(availableCameras, i18n)}
2020-08-27 00:03:42 +00:00
value={selectedCamera}
/>
2020-08-27 00:03:42 +00:00
</div>
2020-09-12 00:46:52 +00:00
<label
htmlFor="audio-input"
className="module-calling-device-selection__label"
>
2023-03-30 00:03:25 +00:00
{i18n('icu:callingDeviceSelection__label--audio-input')}
2020-08-27 00:03:42 +00:00
</label>
<div className="module-calling-device-selection__select">
<Select
2020-08-27 00:03:42 +00:00
disabled={!availableMicrophones.length}
id="audio-input"
2020-08-27 00:03:42 +00:00
name="audio-input"
onChange={createAudioChangeHandler(
availableMicrophones,
changeIODevice,
CallingDeviceType.MICROPHONE
)}
options={renderAudioOptions(availableMicrophones, i18n)}
2020-08-27 00:03:42 +00:00
value={selectedMicrophoneIndex}
/>
2020-08-27 00:03:42 +00:00
</div>
2020-09-12 00:46:52 +00:00
<label
htmlFor="audio-output"
className="module-calling-device-selection__label"
>
2023-03-30 00:03:25 +00:00
{i18n('icu:callingDeviceSelection__label--audio-output')}
2020-08-27 00:03:42 +00:00
</label>
<div className="module-calling-device-selection__select">
<Select
2020-08-27 00:03:42 +00:00
disabled={!availableSpeakers.length}
id="audio-output"
2020-08-27 00:03:42 +00:00
name="audio-output"
onChange={createAudioChangeHandler(
availableSpeakers,
changeIODevice,
CallingDeviceType.SPEAKER
)}
options={renderAudioOptions(availableSpeakers, i18n)}
2020-08-27 00:03:42 +00:00
value={selectedSpeakerIndex}
/>
2020-08-27 00:03:42 +00:00
</div>
</Modal>
2020-08-27 00:03:42 +00:00
);
2022-11-18 00:45:19 +00:00
}