Annotate the default device with a label
This commit is contained in:
@@ -155,6 +155,7 @@
|
|||||||
"camera": "Camera",
|
"camera": "Camera",
|
||||||
"camera_numbered": "Camera {{n}}",
|
"camera_numbered": "Camera {{n}}",
|
||||||
"default": "Default",
|
"default": "Default",
|
||||||
|
"default_named": "Default <2>({{name}})</2>",
|
||||||
"microphone": "Microphone",
|
"microphone": "Microphone",
|
||||||
"microphone_numbered": "Microphone {{n}}",
|
"microphone_numbered": "Microphone {{n}}",
|
||||||
"speaker": "Speaker",
|
"speaker": "Speaker",
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
export type DeviceLabel =
|
export type DeviceLabel =
|
||||||
| { type: "name"; name: string }
|
| { type: "name"; name: string }
|
||||||
| { type: "number"; number: number }
|
| { type: "number"; number: number }
|
||||||
| { type: "default" };
|
| { type: "default"; name: string | null };
|
||||||
|
|
||||||
export interface MediaDevice {
|
export interface MediaDevice {
|
||||||
/**
|
/**
|
||||||
@@ -104,7 +104,10 @@ function useMediaDevice(
|
|||||||
!available.has("") &&
|
!available.has("") &&
|
||||||
!available.has("default")
|
!available.has("default")
|
||||||
)
|
)
|
||||||
available = new Map([["", { type: "default" }], ...available]);
|
available = new Map([
|
||||||
|
["", { type: "default", name: availableRaw[0]?.label || null }],
|
||||||
|
...available,
|
||||||
|
]);
|
||||||
// Note: creating virtual default input devices would be another problem
|
// Note: creating virtual default input devices would be another problem
|
||||||
// entirely, because requesting a media stream from deviceId "" won't
|
// entirely, because requesting a media stream from deviceId "" won't
|
||||||
// automatically track the default device.
|
// automatically track the default device.
|
||||||
|
|||||||
@@ -16,3 +16,7 @@
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--cpd-space-4x);
|
gap: var(--cpd-space-4x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.secondary {
|
||||||
|
color: var(--cpd-color-text-secondary);
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,7 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
Please see LICENSE in the repository root for full details.
|
Please see LICENSE in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { type ChangeEvent, type FC, useCallback, useId } from "react";
|
import {
|
||||||
|
type ChangeEvent,
|
||||||
|
type FC,
|
||||||
|
type ReactElement,
|
||||||
|
type ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useId,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
Heading,
|
Heading,
|
||||||
InlineField,
|
InlineField,
|
||||||
@@ -13,7 +20,7 @@ import {
|
|||||||
RadioControl,
|
RadioControl,
|
||||||
Separator,
|
Separator,
|
||||||
} from "@vector-im/compound-web";
|
} from "@vector-im/compound-web";
|
||||||
import { useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { type MediaDevice } from "../livekit/MediaDevicesContext";
|
import { type MediaDevice } from "../livekit/MediaDevicesContext";
|
||||||
import styles from "./DeviceSelection.module.css";
|
import styles from "./DeviceSelection.module.css";
|
||||||
@@ -53,27 +60,49 @@ export const DeviceSelection: FC<Props> = ({
|
|||||||
</Heading>
|
</Heading>
|
||||||
<Separator className={styles.separator} />
|
<Separator className={styles.separator} />
|
||||||
<div className={styles.options}>
|
<div className={styles.options}>
|
||||||
{[...devices.available].map(([id, label]) => (
|
{[...devices.available].map(([id, label]) => {
|
||||||
<InlineField
|
let labelText: ReactNode;
|
||||||
key={id}
|
switch (label.type) {
|
||||||
name={groupId}
|
case "name":
|
||||||
control={
|
labelText = label.name;
|
||||||
<RadioControl
|
break;
|
||||||
checked={id === devices.selectedId}
|
case "number":
|
||||||
onChange={onChange}
|
labelText = numberedLabel(label.number);
|
||||||
value={id}
|
break;
|
||||||
/>
|
case "default":
|
||||||
}
|
labelText =
|
||||||
>
|
label.name === null ? (
|
||||||
<Label>
|
t("settings.devices.default")
|
||||||
{label.type === "name"
|
) : (
|
||||||
? label.name
|
<Trans
|
||||||
: label.type === "number"
|
i18nKey="settings.devices.default_named"
|
||||||
? numberedLabel(label.number)
|
name={label.name}
|
||||||
: t("settings.devices.default")}
|
>
|
||||||
</Label>
|
Default{" "}
|
||||||
</InlineField>
|
<span className={styles.secondary}>
|
||||||
))}
|
({{ name: label.name } as unknown as ReactElement})
|
||||||
|
</span>
|
||||||
|
</Trans>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<InlineField
|
||||||
|
key={id}
|
||||||
|
name={groupId}
|
||||||
|
control={
|
||||||
|
<RadioControl
|
||||||
|
checked={id === devices.selectedId}
|
||||||
|
onChange={onChange}
|
||||||
|
value={id}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Label>{labelText}</Label>
|
||||||
|
</InlineField>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user