// Stream settings — resolution / refresh / bitrate / gamepad / compositor / mic, written to // the flatpak client's JSON (main.py set_settings), which the client reads on launch. The // accepted gamepad/compositor names mirror punktfunk-core's `*Pref::from_name`. import { Dropdown, Field, SliderField, Spinner, ToggleField } from "@decky/ui"; import { FC, useEffect, useState } from "react"; import { getSettings, setSettings, StreamSettings } from "./backend"; const RESOLUTIONS: [number, number, string][] = [ [0, 0, "Native display"], [1280, 720, "1280 × 720"], [1280, 800, "1280 × 800 (Deck)"], [1920, 1080, "1920 × 1080"], [2560, 1440, "2560 × 1440"], ]; const REFRESH = [0, 30, 60, 90, 120]; const GAMEPADS = ["auto", "xbox360", "xboxone", "dualsense", "dualshock4", "steamdeck"]; const GAMEPAD_LABELS: Record = { auto: "Automatic", xbox360: "Xbox 360", xboxone: "Xbox One", dualsense: "DualSense", dualshock4: "DualShock 4", steamdeck: "Steam Deck", }; const COMPOSITORS = ["auto", "kwin", "wlroots", "mutter", "gamescope"]; const COMPOSITOR_LABELS: Record = { auto: "Automatic", kwin: "KDE Plasma (KWin)", wlroots: "Sway (wlroots)", mutter: "GNOME (Mutter)", gamescope: "gamescope", }; export const SettingsSection: FC = () => { const [s, setS] = useState(null); useEffect(() => { void getSettings().then(setS); }, []); const patch = (p: Partial) => { setS((cur) => { if (!cur) return cur; const next = { ...cur, ...p }; void setSettings(next); return next; }); }; if (!s) return ; const resIdx = Math.max( 0, RESOLUTIONS.findIndex(([w, h]) => w === s.width && h === s.height), ); return ( <> ({ data: i, label }))} selectedOption={resIdx} onChange={(o) => { const [w, h] = RESOLUTIONS[o.data as number]; patch({ width: w, height: h }); }} /> ({ data: r, label: r === 0 ? "Native" : `${r} Hz` }))} selectedOption={s.refresh_hz} onChange={(o) => patch({ refresh_hz: o.data as number })} /> patch({ bitrate_kbps: v * 1000 })} /> ({ data: g, label: GAMEPAD_LABELS[g] ?? g }))} selectedOption={s.gamepad} onChange={(o) => patch({ gamepad: o.data as string })} /> {(s.gamepad === "steamdeck" || s.gamepad === "auto") && ( )} ({ data: c, label: COMPOSITOR_LABELS[c] ?? c }))} selectedOption={s.compositor} onChange={(o) => patch({ compositor: o.data as string })} /> patch({ mic_enabled: v })} /> ); };