From f61650c09c9668fac5dbc592cc685bd99dc3381d Mon Sep 17 00:00:00 2001 From: Thore Cimbal Date: Tue, 28 Jul 2026 22:46:19 +0200 Subject: [PATCH] feat: move camera/screen share quality settings to Video tab Previously these were only accessible under the "Developer" settings tab, gated behind an explicit "Developer mode" toggle in Preferences - functionally not developer-only at all (just resolution/framerate/ bitrate/codec pickers), just accidentally buried two clicks deep behind a checkbox most users would never find or think to enable. Extracted the MediaQualitySettings component out of DeveloperSettingsTab.tsx into its own file and moved both usages (camera + screen share) into the existing "Video" settings tab, visible to all users without any special mode. DeveloperSettingsTab keeps everything else (audio processing, connection stats, etc.) unchanged. Verified: full project typecheck clean, production embedded build succeeds. --- src/settings/DeveloperSettingsTab.tsx | 191 -------------------------- src/settings/MediaQualitySettings.tsx | 140 +++++++++++++++++++ src/settings/SettingsModal.tsx | 63 +++++++++ 3 files changed, 203 insertions(+), 191 deletions(-) create mode 100644 src/settings/MediaQualitySettings.tsx diff --git a/src/settings/DeveloperSettingsTab.tsx b/src/settings/DeveloperSettingsTab.tsx index 8ffcc347..dfef4ece 100644 --- a/src/settings/DeveloperSettingsTab.tsx +++ b/src/settings/DeveloperSettingsTab.tsx @@ -37,7 +37,6 @@ import { type Room as LivekitRoom } from "livekit-client"; import { FieldRow, InputField } from "../input/Input"; import { Config } from "../config/Config"; import { - type Setting, useSetting, duplicateTiles as duplicateTilesSetting, debugTileLayout as debugTileLayoutSetting, @@ -46,26 +45,13 @@ import { alwaysShowIphoneEarpiece as alwaysShowIphoneEarpieceSetting, matrixRTCMode as matrixRTCModeSetting, customLivekitUrl as customLivekitUrlSetting, - advancedScreenShare as advancedScreenShareSetting, - screenShareResolution as screenShareResolutionSetting, - screenShareFramerate as screenShareFramerateSetting, - screenShareBitrate as screenShareBitrateSetting, - screenShareCodec as screenShareCodecSetting, - advancedCamera as advancedCameraSetting, - cameraResolution as cameraResolutionSetting, - cameraFramerate as cameraFramerateSetting, - cameraBitrate as cameraBitrateSetting, - cameraCodec as cameraCodecSetting, echoCancellationSetting, noiseSuppressionSetting, autoGainControlSetting, - type VideoCodec, enableExtendedLivekitLogs as enableExtendedLivekitLogsSetting, } from "./settings"; import { MatrixRTCMode } from "../config/ConfigOptions"; import styles from "./DeveloperSettingsTab.module.css"; -import settingsStyles from "./SettingsModal.module.css"; -import { Slider } from "../Slider"; import { useUrlParams } from "../UrlParams"; import { getSFUConfigWithOpenID } from "../livekit/openIDSFU"; @@ -157,131 +143,6 @@ export const DeveloperSettingsTab: FC = ({ return null; }, [livekitRooms]); - const MediaQualitySettings: React.FC<{ - id: string; - header: string; - toggleLabel: string; - description: string; - toggleSetting: Setting; - resolutionSetting: Setting; - framerateSetting: Setting; - bitrateSetting: Setting; - codecSetting: Setting; - resolutionOptions: { value: string; label: string }[]; - bitrateRange: { min: number; max: number; step: number }; - }> = ({ - id, - header, - toggleLabel, - description, - toggleSetting, - resolutionSetting, - framerateSetting, - bitrateSetting, - codecSetting, - resolutionOptions, - bitrateRange, - }): ReactNode => { - const [advancedEnabled, setAdvancedEnabled] = useSetting(toggleSetting); - const [resolution, setResolution] = useSetting(resolutionSetting); - const [framerate, setFramerate] = useSetting(framerateSetting); - const [framerateRaw, setFramerateRaw] = useState(framerate); - const [bitrate, setBitrate] = useSetting(bitrateSetting); - const [bitrateRaw, setBitrateRaw] = useState(bitrate); - const [codec, setCodec] = useSetting(codecSetting); - - return ( - <> -

{header}

- - setAdvancedEnabled(e.target.checked)} - /> - - {advancedEnabled && ( - <> -
- - -
-
- - `${v} fps`} - /> -
-
- - - `${(v / 1_000_000).toFixed(1)} Mbps` - } - /> -
-
- - -
- - )} - - ); - }; - const AudioProcessingSettings: React.FC = (): ReactNode => { const [echoCancellation, setEchoCancellation] = useSetting( echoCancellationSetting, @@ -606,58 +467,6 @@ export const DeveloperSettingsTab: FC = ({

{t("developer_mode.url_params")}

{JSON.stringify(urlParams, null, 2)}
- - - - ); diff --git a/src/settings/MediaQualitySettings.tsx b/src/settings/MediaQualitySettings.tsx new file mode 100644 index 00000000..88936e96 --- /dev/null +++ b/src/settings/MediaQualitySettings.tsx @@ -0,0 +1,140 @@ +/* +Copyright 2022-2024 New Vector Ltd. + +SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE in the repository root for full details. +*/ + +import { type FC, type ReactNode, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import { FieldRow, InputField } from "../input/Input"; +import { type Setting, useSetting, type VideoCodec } from "./settings"; +import settingsStyles from "./SettingsModal.module.css"; +import { Slider } from "../Slider"; + +export const MediaQualitySettings: FC<{ + id: string; + header: string; + toggleLabel: string; + description: string; + toggleSetting: Setting; + resolutionSetting: Setting; + framerateSetting: Setting; + bitrateSetting: Setting; + codecSetting: Setting; + resolutionOptions: { value: string; label: string }[]; + bitrateRange: { min: number; max: number; step: number }; +}> = ({ + id, + header, + toggleLabel, + description, + toggleSetting, + resolutionSetting, + framerateSetting, + bitrateSetting, + codecSetting, + resolutionOptions, + bitrateRange, +}): ReactNode => { + const { t } = useTranslation(); + const [advancedEnabled, setAdvancedEnabled] = useSetting(toggleSetting); + const [resolution, setResolution] = useSetting(resolutionSetting); + const [framerate, setFramerate] = useSetting(framerateSetting); + const [framerateRaw, setFramerateRaw] = useState(framerate); + const [bitrate, setBitrate] = useSetting(bitrateSetting); + const [bitrateRaw, setBitrateRaw] = useState(bitrate); + const [codec, setCodec] = useSetting(codecSetting); + + return ( + <> +

{header}

+ + setAdvancedEnabled(e.target.checked)} + /> + + {advancedEnabled && ( + <> +
+ + +
+
+ + `${v} fps`} + /> +
+
+ + + `${(v / 1_000_000).toFixed(1)} Mbps` + } + /> +
+
+ + +
+ + )} + + ); +}; diff --git a/src/settings/SettingsModal.tsx b/src/settings/SettingsModal.tsx index 665eadf0..58efeb25 100644 --- a/src/settings/SettingsModal.tsx +++ b/src/settings/SettingsModal.tsx @@ -24,12 +24,23 @@ import { soundEffectVolume as soundEffectVolumeSetting, backgroundBlur as backgroundBlurSetting, developerMode, + advancedCamera as advancedCameraSetting, + cameraResolution as cameraResolutionSetting, + cameraFramerate as cameraFramerateSetting, + cameraBitrate as cameraBitrateSetting, + cameraCodec as cameraCodecSetting, + advancedScreenShare as advancedScreenShareSetting, + screenShareResolution as screenShareResolutionSetting, + screenShareFramerate as screenShareFramerateSetting, + screenShareBitrate as screenShareBitrateSetting, + screenShareCodec as screenShareCodecSetting, } from "./settings"; import { PreferencesSettingsTab } from "./PreferencesSettingsTab"; import { Slider } from "../Slider"; import { DeviceSelection } from "./DeviceSelection"; import { useTrackProcessor } from "../livekit/TrackProcessorContext"; import { DeveloperSettingsTab } from "./DeveloperSettingsTab"; +import { MediaQualitySettings } from "./MediaQualitySettings"; import { FieldRow, InputField } from "../input/Input"; import { useSubmitRageshake } from "./submit-rageshake"; import { useUrlParams } from "../UrlParams"; @@ -189,6 +200,58 @@ export const SettingsModal: FC = ({ + + + + ), };