/* Copyright 2024 New Vector Ltd. SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial Please see LICENSE in the repository root for full details. */ import { type ChangeEvent, type FC, type ReactElement, type ReactNode, useCallback, useId, } from "react"; import { Heading, InlineField, Label, RadioControl, Separator, } from "@vector-im/compound-web"; import { Trans, useTranslation } from "react-i18next"; import { useObservableEagerState } from "observable-hooks"; import { type AudioOutputDeviceLabel, type DeviceLabel, type SelectedDevice, type MediaDevice, } from "../state/MediaDevices"; import styles from "./DeviceSelection.module.css"; interface Props { device: MediaDevice; title: string; numberedLabel: (number: number) => string; } export const DeviceSelection: FC = ({ device, title, numberedLabel, }) => { const { t } = useTranslation(); const groupId = useId(); const available = useObservableEagerState(device.available$); const selectedId = useObservableEagerState(device.selected$)?.id; const onChange = useCallback( (e: ChangeEvent) => { device.select(e.target.value); }, [device], ); // There is no need to show the menu if there is no choice that can be made. if (available.size <= 1) return null; return (
{title}
{[...available].map(([id, label]) => { let labelText: ReactNode; switch (label.type) { case "name": labelText = label.name; break; case "number": labelText = numberedLabel(label.number); break; case "default": labelText = label.name === null ? ( t("settings.devices.default") ) : ( Default{" "} ({{ name: label.name } as unknown as ReactElement}) ); break; case "speaker": labelText = t("settings.devices.loudspeaker"); break; case "earpiece": labelText = t("settings.devices.handset"); break; } return ( } > ); })}
); };