// Main window + sidebar (AGENTS.md §6, §7). // // Phase 2 C3 wires the Settings page, About dialog, and window-state // persistence. The Appearance section in `settings-page.slint` is the only // settings UI that drives real state today — every other control is a // shell that Phase 5 hooks to `AppConfig`. import { AppearanceMode } from "./theme.slint"; import { NavItem, SectionLabel } from "./components.slint"; import { MessageItem } from "./message-card.slint"; import { MessageList } from "./message-list.slint"; import { EmptyState } from "./empty-state.slint"; import { SettingsPage } from "./settings-page.slint"; import { AboutDialog } from "./dialogs.slint"; export enum SidebarSelection { All, Settings, About, } export component MainWindow inherits Window { title: "Gotify"; preferred-width: 960px; preferred-height: 680px; min-width: 760px; min-height: 520px; // Theme switch — Rust-controllable via `ui.set_theme(...)`. in-out property theme: AppearanceMode.Dark; out property is-dark: theme != AppearanceMode.Light; // Palette — all derived from `is-dark` (AGENTS.md §52). out property bg: is-dark ? #1f2024 : #f5f6f8; out property surface: is-dark ? #28292d : #ffffff; out property surface-elev: is-dark ? #2f3035 : #fafbfc; out property border: is-dark ? #3a3b40 : #e4e6ea; out property text-primary: is-dark ? #e6e6e6 : #1a1a1a; out property text-second: is-dark ? #a0a0a0 : #5c5c5c; out property text-muted: is-dark ? #6a6a6a : #9a9a9a; out property accent: is-dark ? #4ea1ff : #0a66c2; out property success: #4caf50; out property warning: #ff9800; out property danger: #f44336; out property priority-low: #6a6a6a; out property priority-normal: is-dark ? #4ea1ff : #0a66c2; out property priority-high: #ff9800; out property priority-max: #f44336; background: bg; in-out property selection: SidebarSelection.All; // ── Phase 2 C2: mock messages + selection ──────────────────── in-out property <[MessageItem]> messages; in-out property selected-message-index: -1; callback test-notification-clicked(); callback message-card-clicked(int); // ── Phase 2 C3: Settings / About / window state ────────────── // Initial appearance radio (0=System/1=Light/2=Dark). Maps 1:1 to // AppearanceMode: System=0, Light=1, Dark=2. in-out property appearance-index: 2; // Show About dialog (one-shot — Rust closes it after handling). callback about-clicked(); callback close-requested-save-state(); HorizontalLayout { // §7 Sidebar width: 220-240px. Rectangle { width: 232px; background: surface; VerticalLayout { padding: 20px; spacing: 6px; Text { text: "Gotify"; color: text-primary; font-size: 18px; font-weight: 700; } Text { text: "Windows Client · Phase 2"; color: text-muted; font-size: 10px; } Rectangle { height: 16px; } SectionLabel { label: "MESSAGES"; text-color: text-muted; } NavItem { label: "All"; selected: root.selection == SidebarSelection.All; clicked => { root.selection = SidebarSelection.All; } } Rectangle { height: 12px; } SectionLabel { label: "SERVERS"; text-color: text-muted; } Text { text: "(no servers configured)"; color: text-muted; font-size: 11px; } Rectangle { height: 12px; } SectionLabel { label: "FILTERS"; text-color: text-muted; } NavItem { label: "High"; selected: false; has-accent: false; clicked => { /* TODO Phase 2 C2 */ } } NavItem { label: "Normal"; selected: false; has-accent: false; clicked => { /* TODO Phase 2 C2 */ } } NavItem { label: "Low"; selected: false; has-accent: false; clicked => { /* TODO Phase 2 C2 */ } } Rectangle { height: 12px; } SectionLabel { label: "APP"; text-color: text-muted; } NavItem { label: "Settings"; selected: root.selection == SidebarSelection.Settings; clicked => { root.selection = SidebarSelection.Settings; } } NavItem { label: "About"; selected: root.selection == SidebarSelection.About; clicked => { root.selection = SidebarSelection.About; root.about-clicked(); } } } } // Right pane — driven by `selection`. Rectangle { background: bg; if root.selection == SidebarSelection.All: VerticalLayout { padding: 24px; spacing: 12px; Text { text: messages.length == 0 ? "Messages" : "Messages · " + messages.length; color: text-primary; font-size: 18px; font-weight: 700; } if messages.length > 0: MessageList { messages: messages; selected-index: root.selected-message-index; height: parent.height - 48px; message-clicked(idx) => { root.selected-message-index = idx; root.message-card-clicked(idx); } } if messages.length == 0: EmptyState { test-notification => { root.test-notification-clicked(); } } } if root.selection == SidebarSelection.Settings: SettingsPage { appearance-index: root.appearance-index; appearance-changed(idx) => { root.appearance-index = idx; root.theme = idx == 0 ? AppearanceMode.System : idx == 1 ? AppearanceMode.Light : AppearanceMode.Dark; } } // About is rendered via a Dialog overlay — not in the right pane. // A separate About row keeps the layout stable; the dialog is // shown via `about-clicked` callback to Rust. if root.selection == SidebarSelection.About: Rectangle { background: bg; Text { x: 24px; y: 24px; text: "About — see the dialog."; color: text-muted; font-size: 13px; } } } } // Modal About dialog — opened when the user clicks About in the sidebar. AboutDialog { // visible-by-default is false. Toggled via Rust by listening to // `about-clicked`. C3 wires the bare open/close plumbing. } }