diff --git a/src/frontend/src/features/home/routes/Home.tsx b/src/frontend/src/features/home/routes/Home.tsx index 5a50daf8..cc2f7f28 100644 --- a/src/frontend/src/features/home/routes/Home.tsx +++ b/src/frontend/src/features/home/routes/Home.tsx @@ -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() diff --git a/src/frontend/src/features/rooms/components/Join.tsx b/src/frontend/src/features/rooms/components/Join.tsx index 3d56f192..fd1a9964 100644 --- a/src/frontend/src/features/rooms/components/Join.tsx +++ b/src/frontend/src/features/rooms/components/Join.tsx @@ -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(null) diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx index 6132bbc0..b6b52815 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Device/AudioDevicesControl.tsx @@ -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, @@ -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({ diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx index bae6dcd7..62f2f294 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Device/VideoDeviceControl.tsx @@ -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 = ({ diff --git a/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx b/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx index 1a537c2f..52f55880 100644 --- a/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx +++ b/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx @@ -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() diff --git a/src/frontend/src/features/rooms/livekit/hooks/useNoiseReduction.ts b/src/frontend/src/features/rooms/livekit/hooks/useNoiseReduction.ts index 64388f67..5fb38521 100644 --- a/src/frontend/src/features/rooms/livekit/hooks/useNoiseReduction.ts +++ b/src/frontend/src/features/rooms/livekit/hooks/useNoiseReduction.ts @@ -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 diff --git a/src/frontend/src/features/rooms/livekit/hooks/usePersistentUserChoices.ts b/src/frontend/src/features/rooms/livekit/hooks/usePersistentUserChoices.ts deleted file mode 100644 index 8edc2b82..00000000 --- a/src/frontend/src/features/rooms/livekit/hooks/usePersistentUserChoices.ts +++ /dev/null @@ -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 - }, - } -} diff --git a/src/frontend/src/features/rooms/livekit/hooks/useVideoResolutionSubscription.ts b/src/frontend/src/features/rooms/livekit/hooks/useVideoResolutionSubscription.ts index 878d2430..0ca5abde 100644 --- a/src/frontend/src/features/rooms/livekit/hooks/useVideoResolutionSubscription.ts +++ b/src/frontend/src/features/rooms/livekit/hooks/useVideoResolutionSubscription.ts @@ -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() diff --git a/src/frontend/src/features/settings/components/tabs/AccountTab.tsx b/src/frontend/src/features/settings/components/tabs/AccountTab.tsx index 7376371d..1109c86d 100644 --- a/src/frontend/src/features/settings/components/tabs/AccountTab.tsx +++ b/src/frontend/src/features/settings/components/tabs/AccountTab.tsx @@ -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 & Pick export const AccountTab = ({ id, onOpenChange }: AccountTabProps) => { const { t } = useTranslation('settings') - const { saveUsername } = usePersistentUserChoices() const room = useRoomContext() const { user, isLoggedIn, logout } = useUser() diff --git a/src/frontend/src/features/settings/components/tabs/AudioTab.tsx b/src/frontend/src/features/settings/components/tabs/AudioTab.tsx index ab3a7ffd..19d7f36d 100644 --- a/src/frontend/src/features/settings/components/tabs/AudioTab.tsx +++ b/src/frontend/src/features/settings/components/tabs/AudioTab.tsx @@ -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 & Pick @@ -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) diff --git a/src/frontend/src/features/settings/components/tabs/VideoTab.tsx b/src/frontend/src/features/settings/components/tabs/VideoTab.tsx index ae9608e1..7a002333 100644 --- a/src/frontend/src/features/settings/components/tabs/VideoTab.tsx +++ b/src/frontend/src/features/settings/components/tabs/VideoTab.tsx @@ -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 & Pick @@ -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( null ) diff --git a/src/frontend/src/stores/userChoices.ts b/src/frontend/src/stores/userChoices.ts index 963dea5d..bf3c0c2b 100644 --- a/src/frontend/src/stores/userChoices.ts +++ b/src/frontend/src/stores/userChoices.ts @@ -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 +}