✨(frontend) add active speaker indicator to audio tab
Aligned layout and features with Gmeet. The layout is functional, though the code needs cleanup. Will open an issue for V3 enhancements.
This commit is contained in:
committed by
aleb_the_flash
parent
85aa7a7251
commit
82e994e5b1
@@ -27,12 +27,17 @@ export const SoundTester = () => {
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
invisible
|
||||
onPress={() => {
|
||||
audioRef?.current?.play()
|
||||
setIsPlaying(true)
|
||||
}}
|
||||
size="sm"
|
||||
isDisabled={isPlaying}
|
||||
fullWidth
|
||||
style={{
|
||||
color: isPlaying ? 'var(--colors-primary)' : undefined,
|
||||
}}
|
||||
>
|
||||
{isPlaying ? t('audio.speakers.ongoingTest') : t('audio.speakers.test')}
|
||||
</Button>
|
||||
|
||||
@@ -36,6 +36,7 @@ const tabPanelContainerStyle = css({
|
||||
display: 'flex',
|
||||
flexGrow: '1',
|
||||
marginTop: '3.5rem',
|
||||
minWidth: 0,
|
||||
})
|
||||
|
||||
export type SettingsDialogExtended = Pick<
|
||||
|
||||
@@ -1,10 +1,55 @@
|
||||
import { DialogProps, Field, H } from '@/primitives'
|
||||
|
||||
import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||
import { useMediaDeviceSelect } from '@livekit/components-react'
|
||||
import {
|
||||
useIsSpeaking,
|
||||
useMediaDeviceSelect,
|
||||
useRoomContext,
|
||||
} from '@livekit/components-react'
|
||||
import { isSafari } from '@/utils/livekit'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SoundTester } from '@/components/SoundTester.tsx'
|
||||
import { SoundTester } from '@/components/SoundTester'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
type RowWrapperProps = {
|
||||
heading: string
|
||||
children: ReactNode[]
|
||||
}
|
||||
|
||||
const RowWrapper = ({ heading, children }: RowWrapperProps) => {
|
||||
return (
|
||||
<>
|
||||
<H lvl={2}>{heading}</H>
|
||||
<HStack
|
||||
gap={0}
|
||||
style={{
|
||||
flexWrap: 'wrap',
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: '1 1 215px',
|
||||
minWidth: 0,
|
||||
}}
|
||||
>
|
||||
{children[0]}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
width: '10rem',
|
||||
justifyContent: 'center',
|
||||
display: 'flex',
|
||||
paddingLeft: '1.5rem',
|
||||
}}
|
||||
>
|
||||
{children[1]}
|
||||
</div>
|
||||
</HStack>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export type AudioTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
@@ -13,6 +58,9 @@ type DeviceItems = Array<{ value: string; label: string }>
|
||||
|
||||
export const AudioTab = ({ id }: AudioTabProps) => {
|
||||
const { t } = useTranslation('settings')
|
||||
const { localParticipant } = useRoomContext()
|
||||
|
||||
const isSpeaking = useIsSpeaking(localParticipant)
|
||||
|
||||
const {
|
||||
devices: devicesOut,
|
||||
@@ -60,20 +108,32 @@ export const AudioTab = ({ id }: AudioTabProps) => {
|
||||
|
||||
return (
|
||||
<TabPanel padding={'md'} flex id={id}>
|
||||
<H lvl={2}>{t('audio.microphone.heading')}</H>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('audio.microphone.label')}
|
||||
items={itemsIn}
|
||||
defaultSelectedKey={activeDeviceIdIn || getDefaultSelectedKey(itemsIn)}
|
||||
onSelectionChange={(key) => setActiveMediaDeviceIn(key as string)}
|
||||
{...disabledProps}
|
||||
/>
|
||||
<RowWrapper heading={t('audio.microphone.heading')}>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('audio.microphone.label')}
|
||||
items={itemsIn}
|
||||
defaultSelectedKey={
|
||||
activeDeviceIdIn || getDefaultSelectedKey(itemsIn)
|
||||
}
|
||||
onSelectionChange={(key) => setActiveMediaDeviceIn(key as string)}
|
||||
{...disabledProps}
|
||||
style={{
|
||||
width: '100%',
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
{localParticipant.isMicrophoneEnabled ? (
|
||||
<ActiveSpeaker isSpeaking={isSpeaking} />
|
||||
) : (
|
||||
<span>Micro désactivé</span>
|
||||
)}
|
||||
</>
|
||||
</RowWrapper>
|
||||
{/* Safari has a known limitation where its implementation of 'enumerateDevices' does not include audio output devices.
|
||||
To prevent errors or an empty selection list, we only render the speakers selection field on non-Safari browsers. */}
|
||||
{!isSafari() && (
|
||||
<>
|
||||
<H lvl={2}>{t('audio.speakers.heading')}</H>
|
||||
<RowWrapper heading={t('audio.speakers.heading')}>
|
||||
<Field
|
||||
type="select"
|
||||
label={t('audio.speakers.label')}
|
||||
@@ -85,9 +145,12 @@ export const AudioTab = ({ id }: AudioTabProps) => {
|
||||
setActiveMediaDeviceOut(key as string)
|
||||
}
|
||||
{...disabledProps}
|
||||
style={{
|
||||
minWidth: 0,
|
||||
}}
|
||||
/>
|
||||
<SoundTester />
|
||||
</>
|
||||
</RowWrapper>
|
||||
)}
|
||||
</TabPanel>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user