From 63a1aa6cb756a623b21ff9fff69de8ea5be0bebc Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Sun, 17 Nov 2024 14:31:30 +0200 Subject: [PATCH] web/settings: add hacky preference editor --- web/src/ui/settings/SettingsView.css | 8 ++ web/src/ui/settings/SettingsView.tsx | 165 ++++++++++++++++++++++++++- web/src/ui/util/Toggle.css | 2 +- 3 files changed, 172 insertions(+), 3 deletions(-) diff --git a/web/src/ui/settings/SettingsView.css b/web/src/ui/settings/SettingsView.css index fad3c25..1ba2bd6 100644 --- a/web/src/ui/settings/SettingsView.css +++ b/web/src/ui/settings/SettingsView.css @@ -6,4 +6,12 @@ div.settings-view { > h2 { margin: 0; } + + table { + text-align: left; + + div.preference { + display: flex; + } + } } diff --git a/web/src/ui/settings/SettingsView.tsx b/web/src/ui/settings/SettingsView.tsx index 13e5a2d..11db4ab 100644 --- a/web/src/ui/settings/SettingsView.tsx +++ b/web/src/ui/settings/SettingsView.tsx @@ -13,18 +13,179 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { RoomStateStore } from "@/api/statestore" -import JSONView from "@/ui/util/JSONView.tsx" +import { use, useCallback } from "react" +import { RoomStateStore, usePreferences } from "@/api/statestore" +import { Preference, PreferenceContext, PreferenceValueType, Preferences, preferences } from "@/api/types/preferences" +import ClientContext from "../ClientContext.ts" +import JSONView from "../util/JSONView.tsx" +import Toggle from "../util/Toggle.tsx" +import CloseIcon from "@/icons/close.svg?react" import "./SettingsView.css" +interface PreferenceCellProps { + context: PreferenceContext + name: keyof Preferences + pref: Preference + setPref: SetPrefFunc + value: T | undefined + inheritedValue: T +} + +const useRemover = ( + context: PreferenceContext, setPref: SetPrefFunc, name: keyof Preferences, value: PreferenceValueType | undefined, +) => { + const onClear = useCallback(() => { + setPref(context, name, undefined) + }, [setPref, context, name]) + if (value === undefined) { + return null + } + return +} + +const BooleanPreferenceCell = ({ context, name, setPref, value, inheritedValue }: PreferenceCellProps) => { + const onChange = useCallback((evt: React.ChangeEvent) => { + setPref(context, name, evt.target.checked) + }, [setPref, context, name]) + return
+ + {useRemover(context, setPref, name, value)} +
+} + +const SelectPreferenceCell = ({ context, name, pref, setPref, value, inheritedValue }: PreferenceCellProps) => { + const onChange = useCallback((evt: React.ChangeEvent) => { + setPref(context, name, evt.target.value) + }, [setPref, context, name]) + const remover = useRemover(context, setPref, name, value) + if (!pref.allowedValues) { + return null + } + return
+ + {remover} +
+} + +type SetPrefFunc = (context: PreferenceContext, key: keyof Preferences, value: PreferenceValueType | undefined) => void + +interface PreferenceRowProps { + name: keyof Preferences + pref: Preference + setPref: SetPrefFunc + globalServer?: PreferenceValueType + globalLocal?: PreferenceValueType + roomServer?: PreferenceValueType + roomLocal?: PreferenceValueType +} + +const PreferenceRow = ({ + name, pref, setPref, globalServer, globalLocal, roomServer, roomLocal, +}: PreferenceRowProps) => { + const makeContentCell = ( + context: PreferenceContext, + val: PreferenceValueType | undefined, + inheritedVal: PreferenceValueType, + ) => { + const prefType = typeof pref.defaultValue + if (prefType === "boolean") { + return } + value={val as boolean | undefined} + inheritedValue={inheritedVal as boolean} + /> + } else if (typeof prefType === "string" && pref.allowedValues) { + return } + value={val as string | undefined} + inheritedValue={inheritedVal as string} + /> + } else { + return null + } + } + let inherit: PreferenceValueType + return + {pref.displayName} + {makeContentCell(PreferenceContext.Account, globalServer, inherit = pref.defaultValue)} + {makeContentCell(PreferenceContext.Device, globalLocal, inherit = globalServer ?? inherit)} + {makeContentCell(PreferenceContext.RoomAccount, roomServer, inherit = globalLocal ?? inherit)} + {makeContentCell(PreferenceContext.RoomDevice, roomLocal, inherit = roomServer ?? inherit)} + +} + interface SettingsViewProps { room: RoomStateStore } const SettingsView = ({ room }: SettingsViewProps) => { + const client = use(ClientContext)! + const setPref = useCallback((context: PreferenceContext, key: keyof Preferences, value: PreferenceValueType | undefined)=> { + if (context === PreferenceContext.Account) { + client.rpc.setAccountData("fi.mau.gomuks.preferences", { + ...client.store.serverPreferenceCache, + [key]: value, + }) + } else if (context === PreferenceContext.Device) { + if (value === undefined) { + delete client.store.localPreferenceCache[key] + } else { + (client.store.localPreferenceCache[key] as PreferenceValueType) = value + } + } else if (context === PreferenceContext.RoomAccount) { + client.rpc.setAccountData("fi.mau.gomuks.preferences", { + ...room.serverPreferenceCache, + [key]: value, + }, room.roomID) + } else if (context === PreferenceContext.RoomDevice) { + if (value === undefined) { + delete room.localPreferenceCache[key] + } else { + (room.localPreferenceCache[key] as PreferenceValueType) = value + } + } + }, [client, room]) + usePreferences(client.store, room) + const globalServer = client.store.serverPreferenceCache + const globalLocal = client.store.localPreferenceCache + const roomServer = room.serverPreferenceCache + const roomLocal = room.localPreferenceCache return <>

Settings

{room.roomID} + + + + + + + + + + + + {Object.entries(preferences).map(([key, pref]) => + )} + +
nameAccountDeviceRoom (account)Room (device)
} diff --git a/web/src/ui/util/Toggle.css b/web/src/ui/util/Toggle.css index abbb28b..d637bfc 100644 --- a/web/src/ui/util/Toggle.css +++ b/web/src/ui/util/Toggle.css @@ -10,7 +10,7 @@ input.toggle { border: 1px solid var(--disabled-color); border-radius: 1.5em; width: 3.5em; - height: 2em; + /*height: 2em;*/ padding: calc(.25em - 1px); transition: background-color var(--transition-duration), border-color var(--transition-duration);