/* 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 { type MatrixClient } from "matrix-js-sdk"; import { Button, Root as Form, Separator } from "@vector-im/compound-web"; import { type Room as LivekitRoom } from "livekit-client"; import { useObservableEagerState } from "observable-hooks"; import { Modal } from "../Modal"; import styles from "./SettingsModal.module.css"; import { type Tab, TabContainer } from "../tabs/Tabs"; import { ProfileSettingsTab } from "./ProfileSettingsTab"; import { FeedbackSettingsTab } from "./FeedbackSettingsTab"; import { useMediaDevices, useMediaDeviceNames, iosDeviceMenu$, } from "../livekit/MediaDevicesContext"; import { widget } from "../widget"; import { useSetting, soundEffectVolume as soundEffectVolumeSetting, backgroundBlur as backgroundBlurSetting, developerMode, } from "./settings"; import { PreferencesSettingsTab } from "./PreferencesSettingsTab"; import { Slider } from "../Slider"; import { DeviceSelection } from "./DeviceSelection"; import { useTrackProcessor } from "../livekit/TrackProcessorContext"; import { DeveloperSettingsTab } from "./DeveloperSettingsTab"; import { FieldRow, InputField } from "../input/Input"; import { useSubmitRageshake } from "./submit-rageshake"; type SettingsTab = | "audio" | "video" | "profile" | "preferences" | "feedback" | "more" | "developer"; interface Props { open: boolean; onDismiss: () => void; tab: SettingsTab; onTabChange: (tab: SettingsTab) => void; client: MatrixClient; roomId?: string; livekitRoom?: LivekitRoom; } export const defaultSettingsTab: SettingsTab = "audio"; export const SettingsModal: FC = ({ open, onDismiss, tab, onTabChange, client, roomId, livekitRoom, }) => { const { t } = useTranslation(); // Generate a `Checkbox` input to turn blur on or off. const BlurCheckbox: React.FC = (): ReactNode => { const { supported } = useTrackProcessor(); const [blurActive, setBlurActive] = useSetting(backgroundBlurSetting); return ( <>

{t("settings.background_blur_header")}

setBlurActive(b.target.checked)} disabled={!supported} /> ); }; const devices = useMediaDevices(); useMediaDeviceNames(devices, open); const [soundVolume, setSoundVolume] = useSetting(soundEffectVolumeSetting); const [soundVolumeRaw, setSoundVolumeRaw] = useState(soundVolume); const [showDeveloperSettingsTab] = useSetting(developerMode); const { available: isRageshakeAvailable } = useSubmitRageshake(); const iosDeviceMenu = useObservableEagerState(iosDeviceMenu$); const audioTab: Tab = { key: "audio", name: t("common.audio"), content: ( <>
{!iosDeviceMenu && ( t("settings.devices.microphone_numbered", { n }) } /> )} {iosDeviceMenu && ( )} t("settings.devices.speaker_numbered", { n })} />

{t("settings.audio_tab.effect_volume_description")}

), }; const videoTab: Tab = { key: "video", name: t("common.video"), content: ( <>
t("settings.devices.camera_numbered", { n })} /> ), }; const preferencesTab: Tab = { key: "preferences", name: t("common.preferences"), content: , }; const profileTab: Tab = { key: "profile", name: t("common.profile"), content: , }; const feedbackTab: Tab = { key: "feedback", name: t("settings.feedback_tab_title"), content: , }; const developerTab: Tab = { key: "developer", name: t("settings.developer_tab_title"), content: , }; const tabs = [audioTab, videoTab]; if (widget === null) tabs.push(profileTab); tabs.push(preferencesTab); if (isRageshakeAvailable || import.meta.env.VITE_PACKAGE === "full") { // for full package we want to show the analytics consent checkbox // even if rageshake is not available tabs.push(feedbackTab); } if (showDeveloperSettingsTab) tabs.push(developerTab); return ( ); };