// AGENTS.md §10 / §11 settings page. // // C3 lays out the five sections (Connection / Notifications / Startup / // Appearance / Advanced) with controls. The Appearance section is the only // one wired back to the model: the radio selection drives // `MainWindow.theme` via the `appearance-changed` callback. Everything else // is a UI shell — Phase 5 wires it to `AppConfig` + Settings → state.json. // // Sub-components MUST be defined before the components that reference them // in Slint 1.x, so `SettingsToggleRow` / `AppearanceRadio` come first. import { SectionLabel } from "./components.slint"; import { ServerCard } from "./server-card.slint"; // ─── Sub-components ──────────────────────────────────────────────── export component SettingsToggleRow inherits Rectangle { in property label; in property value: false; in property enabled: true; callback toggled(bool); in property row-bg: #28292d; in property row-border: #3a3b40; in property label-color: #e6e6e6; in property toggle-on: #4ea1ff; in property toggle-off: #6a6a6a; width: 100%; height: 44px; border-radius: 8px; background: row-bg; border-color: row-border; border-width: 1px; opacity: enabled ? 1.0 : 0.5; HorizontalLayout { padding-top: 0; padding-bottom: 0; padding-left: 16px; padding-right: 16px; alignment: center; Text { text: label; color: label-color; font-size: 13px; horizontal-stretch: 1; } Rectangle { width: 36px; height: 20px; border-radius: 10px; background: value ? toggle-on : toggle-off; y: parent.height / 2 - self.height / 2; Rectangle { width: 16px; height: 16px; border-radius: 8px; background: #ffffff; x: value ? parent.width - self.width - 2px : 2px; y: (parent.height - self.height) / 2; } TouchArea { enabled: root.enabled; clicked => { root.toggled(!root.value); } } } } } export component AppearanceRadio inherits Rectangle { in property label; in property description; in property selected: false; callback chosen(); in property row-bg: #28292d; in property row-border: #3a3b40; in property row-border-selected: #4ea1ff; in property label-color: #e6e6e6; in property hint-color: #6a6a6a; width: 160px; height: 64px; border-radius: 8px; background: row-bg; border-color: selected ? row-border-selected : row-border; border-width: selected ? 2px : 1px; VerticalLayout { padding: 12px; spacing: 2px; Text { text: label; color: label-color; font-size: 13px; font-weight: 600; } Text { text: description; color: hint-color; font-size: 11px; } } TouchArea { clicked => { root.chosen(); } } } // ─── Main page ───────────────────────────────────────────────────── export component SettingsPage inherits Rectangle { // Appearance (live wired) in-out property appearance-index: 2; callback appearance-changed(int); // Notifications (UI shell) in-out property desktop-notify: true; in-out property sound: true; in-out property notify-high: true; in-out property notify-max: true; // Startup (UI shell) in-out property start-with-windows: false; in-out property start-minimized: false; in-out property close-to-tray: true; // Advanced (collapsed by default per §10) in-out property advanced-expanded: false; // Connection (Phase 3 C2) in-out property test-in-progress: false; callback test-connection-requested(); // Tokens in property divider-color: #3a3b40; in property hint-color: #6a6a6a; background: transparent; VerticalLayout { padding: 24px; spacing: 24px; // CONNECTION VerticalLayout { spacing: 8px; SectionLabel { label: "CONNECTION"; text-color: hint-color; } // "Test Connection" button — Phase 3 C2 wires this to the // real `GotifyApi::health` round-trip. Rectangle { width: 160px; height: 32px; background: #2f3035; border-radius: 6px; Text { x: (parent.width - self.width) / 2; y: (parent.height - self.height) / 2; text: root.test-in-progress ? "Testing..." : "Test Connection"; color: #e6e6e6; font-size: 12px; } TouchArea { enabled: !root.test-in-progress; clicked => { root.test-connection-requested(); } } } ServerCard { server-name: "Home"; server-url: "https://gotify.example.com"; enabled: true; is-current: true; } ServerCard { server-name: "NAS"; server-url: "http://192.168.50.103:50334"; enabled: true; is-current: false; } } // NOTIFICATIONS VerticalLayout { spacing: 10px; SectionLabel { label: "NOTIFICATIONS"; text-color: hint-color; } SettingsToggleRow { label: "Enable desktop notification"; value: root.desktop-notify; } SettingsToggleRow { label: "Play sound"; value: root.sound; enabled: root.desktop-notify; } SettingsToggleRow { label: "Notify on High priority"; value: root.notify-high; enabled: root.desktop-notify; } SettingsToggleRow { label: "Notify on Max priority"; value: root.notify-max; enabled: root.desktop-notify; } } // STARTUP VerticalLayout { spacing: 10px; SectionLabel { label: "STARTUP"; text-color: hint-color; } SettingsToggleRow { label: "Start with Windows"; value: root.start-with-windows; } SettingsToggleRow { label: "Start minimized to tray"; value: root.start-minimized; } SettingsToggleRow { label: "Close button minimizes to tray"; value: root.close-to-tray; } } // APPEARANCE (live wired) VerticalLayout { spacing: 10px; SectionLabel { label: "APPEARANCE"; text-color: hint-color; } HorizontalLayout { spacing: 12px; AppearanceRadio { label: "System"; description: "Follow Windows theme"; selected: root.appearance-index == 0; chosen => { root.appearance-index = 0; root.appearance-changed(0); } } AppearanceRadio { label: "Light"; description: "Bright neutrals"; selected: root.appearance-index == 1; chosen => { root.appearance-index = 1; root.appearance-changed(1); } } AppearanceRadio { label: "Dark"; description: "Graphite"; selected: root.appearance-index == 2; chosen => { root.appearance-index = 2; root.appearance-changed(2); } } } SettingsToggleRow { label: "Compact message density"; value: false; enabled: false; } } // ADVANCED (collapsed by default per §10) VerticalLayout { spacing: 10px; HorizontalLayout { spacing: 8px; alignment: center; Text { text: advanced-expanded ? "v" : ">"; color: hint-color; font-size: 11px; } Text { text: "ADVANCED"; color: hint-color; font-size: 11px; font-weight: 700; } TouchArea { clicked => { root.advanced-expanded = !root.advanced-expanded; } } } if advanced-expanded: VerticalLayout { spacing: 10px; SettingsToggleRow { label: "Log level: Info (release default)"; value: false; enabled: false; } SettingsToggleRow { label: "Clear local state (messages + window size)"; value: false; enabled: false; } SettingsToggleRow { label: "Reset settings to defaults"; value: false; enabled: false; } } } } }