✨(frontend) add settings quick access from device controls
Enable opening settings dialog directly from device controls while inside a conference for quick access to device configuration. Improves UX by providing immediate settings access without enhancing convenience during meetings. Requested by users.
This commit is contained in:
committed by
aleb_the_flash
parent
a49893696b
commit
42107f4698
@@ -11,6 +11,8 @@ import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice'
|
||||
import Source = Track.Source
|
||||
import * as React from 'react'
|
||||
import { SelectDevice } from './SelectDevice'
|
||||
import { SettingsButton } from './SettingsButton'
|
||||
import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
|
||||
type AudioDevicesControlProps = Omit<
|
||||
UseTrackToggleProps<Source.Microphone>,
|
||||
@@ -114,6 +116,7 @@ export const AudioDevicesControl = ({
|
||||
onSubmit={saveAudioOutputDeviceId}
|
||||
/>
|
||||
</div>
|
||||
<SettingsButton settingTab={SettingsDialogExtendedKey.AUDIO} />
|
||||
</div>
|
||||
</Popover>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { useSettingsDialog } from '../SettingsDialogContext'
|
||||
import { Button } from '@/primitives'
|
||||
import { RiSettings3Line } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
|
||||
export const SettingsButton = ({
|
||||
settingTab,
|
||||
}: {
|
||||
settingTab: SettingsDialogExtendedKey
|
||||
}) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'selectDevice' })
|
||||
const { setDialogOpen, setDefaultSelectedKey } = useSettingsDialog()
|
||||
|
||||
return (
|
||||
<Button
|
||||
size="sm"
|
||||
square
|
||||
tooltip={t('settings')}
|
||||
aria-label={t('settings')}
|
||||
variant="primaryDark"
|
||||
onPress={() => {
|
||||
setDefaultSelectedKey(settingTab)
|
||||
setDialogOpen(true)
|
||||
}}
|
||||
>
|
||||
<RiSettings3Line size={24} />
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import { BackgroundProcessorFactory } from '../../blur'
|
||||
import Source = Track.Source
|
||||
import * as React from 'react'
|
||||
import { SelectDevice } from './SelectDevice'
|
||||
import { SettingsButton } from './SettingsButton'
|
||||
import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
|
||||
type VideoDeviceControlProps = Omit<
|
||||
UseTrackToggleProps<Source.Camera>,
|
||||
@@ -126,6 +128,7 @@ export const VideoDeviceControl = ({
|
||||
onSubmit={saveVideoInputDeviceId}
|
||||
/>
|
||||
</div>
|
||||
<SettingsButton settingTab={SettingsDialogExtendedKey.VIDEO} />
|
||||
</div>
|
||||
</Popover>
|
||||
)}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import {
|
||||
SettingsDialogExtended,
|
||||
SettingsDialogExtendedKeys,
|
||||
} from '@/features/settings/components/SettingsDialogExtended'
|
||||
import React, { createContext, useContext, useState } from 'react'
|
||||
import { SettingsDialogExtended } from '@/features/settings/components/SettingsDialogExtended'
|
||||
import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
|
||||
const SettingsDialogContext = createContext<
|
||||
| {
|
||||
dialogOpen: boolean
|
||||
defaultSelectedKey?: SettingsDialogExtendedKeys
|
||||
defaultSelectedKey?: SettingsDialogExtendedKey
|
||||
setDefaultSelectedKey: React.Dispatch<
|
||||
React.SetStateAction<SettingsDialogExtendedKeys | undefined>
|
||||
React.SetStateAction<SettingsDialogExtendedKey | undefined>
|
||||
>
|
||||
setDialogOpen: React.Dispatch<React.SetStateAction<boolean>>
|
||||
}
|
||||
@@ -20,7 +18,7 @@ export const SettingsDialogProvider: React.FC<{
|
||||
children: React.ReactNode
|
||||
}> = ({ children }) => {
|
||||
const [defaultSelectedKey, setDefaultSelectedKey] = useState<
|
||||
SettingsDialogExtendedKeys | undefined
|
||||
SettingsDialogExtendedKey | undefined
|
||||
>(undefined)
|
||||
const [dialogOpen, setDialogOpen] = useState(false)
|
||||
return (
|
||||
|
||||
@@ -18,6 +18,7 @@ import { AudioTab } from './tabs/AudioTab'
|
||||
import { VideoTab } from './tabs/VideoTab'
|
||||
import { useRef } from 'react'
|
||||
import { useMediaQuery } from '@/features/rooms/livekit/hooks/useMediaQuery'
|
||||
import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
|
||||
const tabsStyle = css({
|
||||
maxHeight: '40.625rem', // fixme size copied from meet settings modal
|
||||
@@ -43,18 +44,11 @@ const tabPanelContainerStyle = css({
|
||||
minWidth: 0,
|
||||
})
|
||||
|
||||
export type SettingsDialogExtendedKeys =
|
||||
| 'account'
|
||||
| 'audio'
|
||||
| 'video'
|
||||
| 'general'
|
||||
| 'notifications'
|
||||
|
||||
export type SettingsDialogExtended = Pick<
|
||||
DialogProps,
|
||||
'isOpen' | 'onOpenChange'
|
||||
> & {
|
||||
defaultSelectedKey?: SettingsDialogExtendedKeys
|
||||
defaultSelectedKey?: SettingsDialogExtendedKey
|
||||
}
|
||||
|
||||
export const SettingsDialogExtended = (props: SettingsDialogExtended) => {
|
||||
@@ -85,34 +79,38 @@ export const SettingsDialogExtended = (props: SettingsDialogExtended) => {
|
||||
</Heading>
|
||||
)}
|
||||
<TabList border={false}>
|
||||
<Tab icon highlight id="account">
|
||||
<Tab icon highlight id={SettingsDialogExtendedKey.ACCOUNT}>
|
||||
<RiAccountCircleLine />
|
||||
{isWideScreen && t('tabs.account')}
|
||||
{isWideScreen && t(`tabs.${SettingsDialogExtendedKey.ACCOUNT}`)}
|
||||
</Tab>
|
||||
<Tab icon highlight id="audio">
|
||||
<Tab icon highlight id={SettingsDialogExtendedKey.AUDIO}>
|
||||
<RiSpeakerLine />
|
||||
{isWideScreen && t('tabs.audio')}
|
||||
{isWideScreen && t(`tabs.${SettingsDialogExtendedKey.AUDIO}`)}
|
||||
</Tab>
|
||||
<Tab icon highlight id="video">
|
||||
<Tab icon highlight id={SettingsDialogExtendedKey.VIDEO}>
|
||||
<RiVideoOnLine />
|
||||
{isWideScreen && t('tabs.video')}
|
||||
{isWideScreen && t(`tabs.${SettingsDialogExtendedKey.VIDEO}`)}
|
||||
</Tab>
|
||||
<Tab icon highlight id="general">
|
||||
<Tab icon highlight id={SettingsDialogExtendedKey.GENERAL}>
|
||||
<RiSettings3Line />
|
||||
{isWideScreen && t('tabs.general')}
|
||||
{isWideScreen && t(`tabs.${SettingsDialogExtendedKey.GENERAL}`)}
|
||||
</Tab>
|
||||
<Tab icon highlight id="notifications">
|
||||
<Tab icon highlight id={SettingsDialogExtendedKey.NOTIFICATIONS}>
|
||||
<RiNotification3Line />
|
||||
{isWideScreen && t('tabs.notifications')}
|
||||
{isWideScreen &&
|
||||
t(`tabs.${SettingsDialogExtendedKey.NOTIFICATIONS}`)}
|
||||
</Tab>
|
||||
</TabList>
|
||||
</div>
|
||||
<div className={tabPanelContainerStyle}>
|
||||
<AccountTab id="account" onOpenChange={props.onOpenChange} />
|
||||
<AudioTab id="audio" />
|
||||
<VideoTab id="video" />
|
||||
<GeneralTab id="general" />
|
||||
<NotificationsTab id="notifications" />
|
||||
<AccountTab
|
||||
id={SettingsDialogExtendedKey.ACCOUNT}
|
||||
onOpenChange={props.onOpenChange}
|
||||
/>
|
||||
<AudioTab id={SettingsDialogExtendedKey.AUDIO} />
|
||||
<VideoTab id={SettingsDialogExtendedKey.VIDEO} />
|
||||
<GeneralTab id={SettingsDialogExtendedKey.GENERAL} />
|
||||
<NotificationsTab id={SettingsDialogExtendedKey.NOTIFICATIONS} />
|
||||
</div>
|
||||
</Tabs>
|
||||
</Dialog>
|
||||
|
||||
7
src/frontend/src/features/settings/type.ts
Normal file
7
src/frontend/src/features/settings/type.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export enum SettingsDialogExtendedKey {
|
||||
ACCOUNT = 'account',
|
||||
AUDIO = 'audio',
|
||||
VIDEO = 'video',
|
||||
GENERAL = 'general',
|
||||
NOTIFICATIONS = 'notifications',
|
||||
}
|
||||
@@ -11,6 +11,7 @@
|
||||
"loading": "Laden…",
|
||||
"select": "Wählen Sie einen Wert",
|
||||
"permissionsNeeded": "Genehmigung erforderlich",
|
||||
"settings": "Einstellungen",
|
||||
"videoinput": {
|
||||
"choose": "Kamera auswählen",
|
||||
"permissionsNeeded": "Kamera auswählen - genehmigung erforderlich",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"loading": "Loading…",
|
||||
"select": "Select a value",
|
||||
"permissionsNeeded": "Permission needed",
|
||||
"settings": "Settings",
|
||||
"videoinput": {
|
||||
"choose": "Select camera",
|
||||
"permissionsNeeded": "Select camera - permission needed",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"loading": "Chargement…",
|
||||
"select": "Sélectionnez une valeur",
|
||||
"permissionsNeeded": "Autorisations nécessaires",
|
||||
"settings": "Paramètres",
|
||||
"videoinput": {
|
||||
"choose": "Choisir la webcam",
|
||||
"permissionsNeeded": "Choisir la webcam - autorisations nécessaires",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"loading": "Bezig met laden…",
|
||||
"select": "Selecteer een waarde",
|
||||
"permissionsNeeded": "Toestemming vereist",
|
||||
"settings": "Instellingen",
|
||||
"videoinput": {
|
||||
"choose": "Selecteer camera",
|
||||
"permissionsNeeded": "Selecteer camera - Toestemming vereist",
|
||||
|
||||
Reference in New Issue
Block a user