mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-07 09:23:38 +00:00
⚡️(frontend) handle actions on userChoices store directly in the module
The Valtio actions on the store were initially defined inside a hook, which was a bad idea: it does not follow Valtio's recommendation of defining actions at the module level, and the function definitions were re-created every time the hook re-rendered, which happened on every state update. These action has nothing related to React. Additionally, the snapshot should be used more directly so Valtio can understand and optimize which parts of the proxy are of interest to the snapshot being made.
This commit is contained in:
committed by
aleb_the_flash
parent
7390673bfc
commit
04ec967a99
@@ -16,11 +16,12 @@ import { ReactNode, useEffect, useState } from 'react'
|
||||
|
||||
import { css } from '@/styled-system/css'
|
||||
import { menuRecipe } from '@/primitives/menuRecipe.ts'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { useConfig } from '@/api/useConfig'
|
||||
import { LoginButton } from '@/components/LoginButton'
|
||||
import { ApiRoom } from '@/features/rooms/api/ApiRoom'
|
||||
import { LoadingScreen } from '@/components/LoadingScreen'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { userChoicesStore } from '@/stores/userChoices'
|
||||
|
||||
const Columns = ({ children }: { children?: ReactNode }) => {
|
||||
return (
|
||||
@@ -148,9 +149,7 @@ const IntroText = styled('div', {
|
||||
})
|
||||
|
||||
const CreateMeetingMenu = () => {
|
||||
const {
|
||||
userChoices: { username },
|
||||
} = usePersistentUserChoices()
|
||||
const { username } = useSnapshot(userChoicesStore)
|
||||
|
||||
const { t } = useTranslation('home')
|
||||
const { mutateAsync: createRoom } = useCreateRoom()
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
} from '../livekit/components/effects/EffectsConfiguration'
|
||||
import { SelectDevice } from '../livekit/components/controls/Device/SelectDevice'
|
||||
import { ToggleDevice } from '../livekit/components/controls/Device/ToggleDevice'
|
||||
import { usePersistentUserChoices } from '../livekit/hooks/usePersistentUserChoices'
|
||||
import { BackgroundProcessorFactory } from '../livekit/components/blur'
|
||||
import { isMobileBrowser } from '@livekit/components-core'
|
||||
import { fetchRoom } from '@/features/rooms/api/fetchRoom'
|
||||
@@ -37,8 +36,20 @@ import { useLoginHint } from '@/hooks/useLoginHint'
|
||||
import { openPermissionsDialog } from '@/stores/permissions'
|
||||
import { useResolveInitiallyDefaultDeviceId } from '../livekit/hooks/useResolveInitiallyDefaultDeviceId'
|
||||
import { isSafari } from '@/utils/livekit'
|
||||
import type { LocalUserChoices } from '@/stores/userChoices'
|
||||
|
||||
import {
|
||||
type LocalUserChoices,
|
||||
saveAudioInputDeviceId,
|
||||
saveAudioInputEnabled,
|
||||
saveAudioOutputDeviceId,
|
||||
saveUsername,
|
||||
saveVideoInputDeviceId,
|
||||
saveVideoInputEnabled,
|
||||
userChoicesStore,
|
||||
} from '@/stores/userChoices'
|
||||
|
||||
import { useCannotUseDevice } from '../livekit/hooks/useCannotUseDevice'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
const onError = (e: Error) => console.error('ERROR', e)
|
||||
|
||||
@@ -104,22 +115,14 @@ export const Join = ({
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'join' })
|
||||
|
||||
const {
|
||||
userChoices: {
|
||||
audioEnabled,
|
||||
videoEnabled,
|
||||
audioDeviceId,
|
||||
audioOutputDeviceId,
|
||||
videoDeviceId,
|
||||
processorConfig,
|
||||
username,
|
||||
},
|
||||
saveAudioInputEnabled,
|
||||
saveAudioOutputDeviceId,
|
||||
saveVideoInputEnabled,
|
||||
saveAudioInputDeviceId,
|
||||
saveVideoInputDeviceId,
|
||||
saveUsername,
|
||||
} = usePersistentUserChoices()
|
||||
audioEnabled,
|
||||
videoEnabled,
|
||||
audioDeviceId,
|
||||
audioOutputDeviceId,
|
||||
videoDeviceId,
|
||||
processorConfig,
|
||||
username,
|
||||
} = useSnapshot(userChoicesStore)
|
||||
|
||||
const initialUserChoices = useRef<LocalUserChoices | null>(null)
|
||||
|
||||
|
||||
+10
-8
@@ -6,7 +6,6 @@ import { Track } from 'livekit-client'
|
||||
|
||||
import { ToggleDevice } from './ToggleDevice'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { usePersistentUserChoices } from '../../../hooks/usePersistentUserChoices'
|
||||
import { useCanPublishTrack } from '../../../hooks/useCanPublishTrack'
|
||||
import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice'
|
||||
import * as React from 'react'
|
||||
@@ -16,6 +15,14 @@ import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
import { TrackSource } from '@livekit/protocol'
|
||||
import Source = Track.Source
|
||||
import { isSafari } from '@/utils/livekit'
|
||||
import {
|
||||
saveAudioInputDeviceId,
|
||||
saveAudioInputEnabled,
|
||||
saveAudioOutputDeviceId,
|
||||
userChoicesStore,
|
||||
} from '@/stores/userChoices'
|
||||
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
type AudioDevicesControlProps = Omit<
|
||||
UseTrackToggleProps<Source.Microphone>,
|
||||
@@ -30,17 +37,12 @@ export const AudioDevicesControl = ({
|
||||
}: AudioDevicesControlProps) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'selectDevice' })
|
||||
|
||||
const {
|
||||
userChoices: { audioDeviceId, audioOutputDeviceId },
|
||||
saveAudioInputDeviceId,
|
||||
saveAudioInputEnabled,
|
||||
saveAudioOutputDeviceId,
|
||||
} = usePersistentUserChoices()
|
||||
const { audioDeviceId, audioOutputDeviceId } = useSnapshot(userChoicesStore)
|
||||
|
||||
const onChange = React.useCallback(
|
||||
(enabled: boolean, isUserInitiated: boolean) =>
|
||||
isUserInitiated ? saveAudioInputEnabled(enabled) : null,
|
||||
[saveAudioInputEnabled]
|
||||
[]
|
||||
)
|
||||
|
||||
const trackProps = useTrackToggle({
|
||||
|
||||
+12
-8
@@ -6,7 +6,6 @@ import { Track, type VideoCaptureOptions } from 'livekit-client'
|
||||
|
||||
import { ToggleDevice } from './ToggleDevice'
|
||||
import { css } from '@/styled-system/css'
|
||||
import { usePersistentUserChoices } from '../../../hooks/usePersistentUserChoices'
|
||||
import { useCanPublishTrack } from '../../../hooks/useCanPublishTrack'
|
||||
import { useCannotUseDevice } from '../../../hooks/useCannotUseDevice'
|
||||
import { useSidePanel } from '../../../hooks/useSidePanel'
|
||||
@@ -17,6 +16,13 @@ import { SelectDevice } from './SelectDevice'
|
||||
import { SettingsButton } from './SettingsButton'
|
||||
import { SettingsDialogExtendedKey } from '@/features/settings/type'
|
||||
import { TrackSource } from '@livekit/protocol'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
import {
|
||||
saveVideoInputDeviceId,
|
||||
saveVideoInputEnabled,
|
||||
userChoicesStore,
|
||||
} from '@/stores/userChoices'
|
||||
|
||||
const EffectsButton = ({ onPress }: { onPress: () => void }) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'selectDevice' })
|
||||
@@ -51,13 +57,12 @@ export const VideoDeviceControl = ({
|
||||
}: VideoDeviceControlProps) => {
|
||||
const { t } = useTranslation('rooms', { keyPrefix: 'selectDevice' })
|
||||
|
||||
const { userChoices, saveVideoInputDeviceId, saveVideoInputEnabled } =
|
||||
usePersistentUserChoices()
|
||||
const { videoDeviceId, processorConfig } = useSnapshot(userChoicesStore)
|
||||
|
||||
const onChange = React.useCallback(
|
||||
(enabled: boolean, isUserInitiated: boolean) =>
|
||||
isUserInitiated ? saveVideoInputEnabled(enabled) : null,
|
||||
[saveVideoInputEnabled]
|
||||
[]
|
||||
)
|
||||
|
||||
const trackProps = useTrackToggle({
|
||||
@@ -82,9 +87,8 @@ export const VideoDeviceControl = ({
|
||||
*
|
||||
* See https://github.com/numerique-gouv/meet/pull/309#issuecomment-2622404121
|
||||
*/
|
||||
const processor = BackgroundProcessorFactory.fromProcessorConfig(
|
||||
userChoices.processorConfig
|
||||
)
|
||||
const processor =
|
||||
BackgroundProcessorFactory.fromProcessorConfig(processorConfig)
|
||||
|
||||
const toggle = trackProps.toggle as (
|
||||
forceState: boolean,
|
||||
@@ -152,7 +156,7 @@ export const VideoDeviceControl = ({
|
||||
<SelectDevice
|
||||
context="room"
|
||||
kind={kind}
|
||||
id={userChoices.videoDeviceId}
|
||||
id={videoDeviceId}
|
||||
onSubmit={saveVideoInputDeviceId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
+3
-13
@@ -30,9 +30,9 @@ import { useDeleteFile } from '@/features/files/api/deleteFile.ts'
|
||||
import { useUser } from '@/features/auth/api/useUser'
|
||||
import { ApiFileItem } from '@/features/files/api/types.ts'
|
||||
import { useConfig } from '@/api/useConfig.ts'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices.ts'
|
||||
import { proxy, useSnapshot } from 'valtio'
|
||||
import { Spinner } from '@/primitives/Spinner.tsx'
|
||||
import { userChoicesStore, saveProcessorConfig } from '@/stores/userChoices'
|
||||
|
||||
enum BlurRadius {
|
||||
NONE = 0,
|
||||
@@ -114,10 +114,7 @@ export const EffectsConfiguration = ({
|
||||
> | null>(null)
|
||||
const effectAnnouncementId = useRef(0)
|
||||
|
||||
const {
|
||||
saveProcessorConfig,
|
||||
userChoices: { processorConfig },
|
||||
} = usePersistentUserChoices()
|
||||
const { processorConfig } = useSnapshot(userChoicesStore)
|
||||
|
||||
const selectedId = useMemo(
|
||||
() =>
|
||||
@@ -247,14 +244,7 @@ export const EffectsConfiguration = ({
|
||||
setTimeout(() => setProcessorPending(false))
|
||||
}
|
||||
},
|
||||
[
|
||||
enabled,
|
||||
saveProcessorConfig,
|
||||
selectedId,
|
||||
toggle,
|
||||
updateEffectStatusMessage,
|
||||
videoTrack,
|
||||
]
|
||||
[enabled, selectedId, toggle, updateEffectStatusMessage, videoTrack]
|
||||
)
|
||||
|
||||
const { data: appConfig } = useConfig()
|
||||
|
||||
@@ -2,16 +2,15 @@ import { useEffect } from 'react'
|
||||
import { Track } from 'livekit-client'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
import { RnnNoiseProcessor } from '../processors/RnnNoiseProcessor'
|
||||
import { usePersistentUserChoices } from './usePersistentUserChoices'
|
||||
import { useNoiseReductionAvailable } from '@/features/rooms/livekit/hooks/useNoiseReductionAvailable'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { userChoicesStore } from '@/stores/userChoices'
|
||||
|
||||
export const useNoiseReduction = () => {
|
||||
const room = useRoomContext()
|
||||
const noiseReductionAvailable = useNoiseReductionAvailable()
|
||||
|
||||
const {
|
||||
userChoices: { noiseReductionEnabled },
|
||||
} = usePersistentUserChoices()
|
||||
const { noiseReductionEnabled } = useSnapshot(userChoicesStore)
|
||||
|
||||
const audioTrack = room.localParticipant.getTrackPublication(
|
||||
Track.Source.Microphone
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { userChoicesStore } from '@/stores/userChoices'
|
||||
import type { VideoResolution } from '@/stores/userChoices'
|
||||
import { ProcessorConfig } from '@/features/rooms/livekit/components/blur'
|
||||
import type { VideoQuality } from 'livekit-client'
|
||||
|
||||
export function usePersistentUserChoices() {
|
||||
const userChoicesSnap = useSnapshot(userChoicesStore)
|
||||
|
||||
return {
|
||||
userChoices: userChoicesSnap,
|
||||
saveAudioInputEnabled: (isEnabled: boolean) => {
|
||||
userChoicesStore.audioEnabled = isEnabled
|
||||
},
|
||||
saveVideoInputEnabled: (isEnabled: boolean) => {
|
||||
userChoicesStore.videoEnabled = isEnabled
|
||||
},
|
||||
saveAudioInputDeviceId: (deviceId: string) => {
|
||||
userChoicesStore.audioDeviceId = deviceId
|
||||
},
|
||||
saveAudioOutputDeviceId: (deviceId: string) => {
|
||||
userChoicesStore.audioOutputDeviceId = deviceId
|
||||
},
|
||||
saveVideoInputDeviceId: (deviceId: string) => {
|
||||
userChoicesStore.videoDeviceId = deviceId
|
||||
},
|
||||
saveVideoPublishResolution: (resolution: VideoResolution) => {
|
||||
userChoicesStore.videoPublishResolution = resolution
|
||||
},
|
||||
saveVideoSubscribeQuality: (quality: VideoQuality) => {
|
||||
userChoicesStore.videoSubscribeQuality = quality
|
||||
},
|
||||
saveUsername: (username: string) => {
|
||||
userChoicesStore.username = username
|
||||
},
|
||||
saveNoiseReductionEnabled: (enabled: boolean) => {
|
||||
userChoicesStore.noiseReductionEnabled = enabled
|
||||
},
|
||||
saveProcessorConfig: (processorConfig: ProcessorConfig | undefined) => {
|
||||
userChoicesStore.processorConfig = processorConfig
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useEffect } from 'react'
|
||||
import { usePersistentUserChoices } from './usePersistentUserChoices'
|
||||
import { useRoomContext } from '@livekit/components-react'
|
||||
import {
|
||||
type RemoteParticipant,
|
||||
@@ -8,15 +7,15 @@ import {
|
||||
Track,
|
||||
VideoQuality,
|
||||
} from 'livekit-client'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { userChoicesStore } from '@/stores/userChoices'
|
||||
|
||||
/**
|
||||
* This hook sets initial video quality for new participants as they join.
|
||||
* LiveKit doesn't allow handling video quality preferences at the room level.
|
||||
*/
|
||||
export const useVideoResolutionSubscription = () => {
|
||||
const {
|
||||
userChoices: { videoSubscribeQuality },
|
||||
} = usePersistentUserChoices()
|
||||
const { videoSubscribeQuality } = useSnapshot(userChoicesStore)
|
||||
|
||||
const room = useRoomContext()
|
||||
|
||||
|
||||
@@ -7,15 +7,14 @@ import { TabPanel, TabPanelProps } from '@/primitives/Tabs'
|
||||
import { HStack } from '@/styled-system/jsx'
|
||||
import { useState } from 'react'
|
||||
import { LoginButton } from '@/components/LoginButton'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { useRenameParticipant } from '@/features/rooms/api/renameParticipant'
|
||||
import { saveUsername } from '@/stores/userChoices'
|
||||
|
||||
export type AccountTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
|
||||
export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => {
|
||||
const { t } = useTranslation('settings')
|
||||
const { saveUsername } = usePersistentUserChoices()
|
||||
const room = useRoomContext()
|
||||
const { user, isLoggedIn, logout } = useUser()
|
||||
|
||||
|
||||
@@ -10,10 +10,16 @@ import { isSafari } from '@/utils/livekit'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SoundTester } from '@/components/SoundTester'
|
||||
import { ActiveSpeaker } from '@/features/rooms/components/ActiveSpeaker'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { useNoiseReductionAvailable } from '@/features/rooms/livekit/hooks/useNoiseReductionAvailable'
|
||||
import posthog from 'posthog-js'
|
||||
import { RowWrapper } from './layout/RowWrapper'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import {
|
||||
saveAudioInputDeviceId,
|
||||
saveAudioOutputDeviceId,
|
||||
saveNoiseReductionEnabled,
|
||||
userChoicesStore,
|
||||
} from '@/stores/userChoices'
|
||||
|
||||
export type AudioTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
@@ -24,12 +30,8 @@ export const AudioTab = ({ id }: AudioTabProps) => {
|
||||
const { t } = useTranslation('settings')
|
||||
const { localParticipant } = useRoomContext()
|
||||
|
||||
const {
|
||||
userChoices: { noiseReductionEnabled, audioDeviceId, audioOutputDeviceId },
|
||||
saveAudioInputDeviceId,
|
||||
saveNoiseReductionEnabled,
|
||||
saveAudioOutputDeviceId,
|
||||
} = usePersistentUserChoices()
|
||||
const { noiseReductionEnabled, audioDeviceId, audioOutputDeviceId } =
|
||||
useSnapshot(userChoicesStore)
|
||||
|
||||
const isSpeaking = useIsSpeaking(localParticipant)
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ import { DialogProps, Field } from '@/primitives'
|
||||
import { TabPanel, type TabPanelProps } from '@/primitives/Tabs'
|
||||
import { useMediaDeviceSelect, useRoomContext } from '@livekit/components-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { usePersistentUserChoices } from '@/features/rooms/livekit/hooks/usePersistentUserChoices'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { css } from '@/styled-system/css'
|
||||
import {
|
||||
@@ -14,8 +13,15 @@ import {
|
||||
VideoQuality,
|
||||
} from 'livekit-client'
|
||||
import { BackgroundProcessorFactory } from '@/features/rooms/livekit/components/blur'
|
||||
import { VideoResolution } from '@/stores/userChoices'
|
||||
import {
|
||||
saveVideoInputDeviceId,
|
||||
saveVideoPublishResolution,
|
||||
saveVideoSubscribeQuality,
|
||||
userChoicesStore,
|
||||
VideoResolution,
|
||||
} from '@/stores/userChoices'
|
||||
import { RowWrapper } from './layout/RowWrapper'
|
||||
import { useSnapshot } from 'valtio'
|
||||
|
||||
export type VideoTabProps = Pick<DialogProps, 'onOpenChange'> &
|
||||
Pick<TabPanelProps, 'id'>
|
||||
@@ -29,16 +35,12 @@ export const VideoTab = ({ id }: VideoTabProps) => {
|
||||
const { localParticipant, remoteParticipants } = useRoomContext()
|
||||
|
||||
const {
|
||||
userChoices: {
|
||||
videoDeviceId,
|
||||
processorConfig,
|
||||
videoPublishResolution,
|
||||
videoSubscribeQuality,
|
||||
},
|
||||
saveVideoInputDeviceId,
|
||||
saveVideoPublishResolution,
|
||||
saveVideoSubscribeQuality,
|
||||
} = usePersistentUserChoices()
|
||||
videoDeviceId,
|
||||
processorConfig,
|
||||
videoPublishResolution,
|
||||
videoSubscribeQuality,
|
||||
} = useSnapshot(userChoicesStore)
|
||||
|
||||
const [videoElement, setVideoElement] = useState<HTMLVideoElement | null>(
|
||||
null
|
||||
)
|
||||
|
||||
@@ -61,3 +61,45 @@ if (userChoicesStore.processorConfig?.type === ProcessorType.VIRTUAL) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const saveAudioInputEnabled = (isEnabled: boolean) => {
|
||||
userChoicesStore.audioEnabled = isEnabled
|
||||
}
|
||||
|
||||
export const saveVideoInputEnabled = (isEnabled: boolean) => {
|
||||
userChoicesStore.videoEnabled = isEnabled
|
||||
}
|
||||
|
||||
export const saveAudioInputDeviceId = (deviceId: string) => {
|
||||
userChoicesStore.audioDeviceId = deviceId
|
||||
}
|
||||
|
||||
export const saveAudioOutputDeviceId = (deviceId: string) => {
|
||||
userChoicesStore.audioOutputDeviceId = deviceId
|
||||
}
|
||||
|
||||
export const saveVideoInputDeviceId = (deviceId: string) => {
|
||||
userChoicesStore.videoDeviceId = deviceId
|
||||
}
|
||||
|
||||
export const saveVideoPublishResolution = (resolution: VideoResolution) => {
|
||||
userChoicesStore.videoPublishResolution = resolution
|
||||
}
|
||||
|
||||
export const saveVideoSubscribeQuality = (quality: VideoQuality) => {
|
||||
userChoicesStore.videoSubscribeQuality = quality
|
||||
}
|
||||
|
||||
export const saveUsername = (username: string) => {
|
||||
userChoicesStore.username = username
|
||||
}
|
||||
|
||||
export const saveNoiseReductionEnabled = (enabled: boolean) => {
|
||||
userChoicesStore.noiseReductionEnabled = enabled
|
||||
}
|
||||
|
||||
export const saveProcessorConfig = (
|
||||
processorConfig: ProcessorConfig | undefined
|
||||
) => {
|
||||
userChoicesStore.processorConfig = processorConfig
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user