Commit Graph
3 Commits
Author SHA1 Message Date
KennethCheng a091e6839a fix(ui): Phase 7 C5 — 移除假按钮 + 真实托盘图标
用户报告设置页很多按钮无反应 + 关闭后托盘看不到图标。两处问题:\n\n1. ServerCard 占位按钮无回调:\n- server-card.slint:去掉了 toggled/edit-clicked/remove-clicked 三个回调以及 enabled 切换、Edit / Remove 按钮;变成纯展示卡(状态点 + name + url + 当前标记)\n- settings-page.slint:去掉硬编码的 Home / NAS 占位,改用 active-server-name / active-server-url / active-server-enabled 三个属性(MainWindow → AppConfig 实时填充);空时显示 '(未配置服务器)' 空态提示\n- app.slint:MainWindow 加三个属性 + 转发给 SettingsPage\n- lib.rs:startup 阶段把活跃服务器信息塞进 UI;测试连接成功/失败时更新 enabled 状态\n\n2. 托盘图标看不见:\n- tray.rs:原本 hIcon 写 null,Win10+ 上 Shell_NotifyIconW(NIM_ADD, NULL hIcon) 实际渲染为空白或很弱的小方块。改用 LoadIconW(NULL, IDI_APPLICATION) 加载 Windows 自带的应用程序图标(无需嵌入 .ico 资源,主题感知)。show_toast / Drop 的 hIcon 维持 null(让 NIM_MODIFY/NIM_DELETE 不动原有图标)。AGENTS.md §53 标记真 .ico 资源为 V2 项。
2026-09-19 20:40:33 +08:00
KennethCheng 680fbfa0ad feat(ui): Phase 2 C3 — Settings 页 + Dialogs + 窗口状态保存
- src/storage.rs: AppState (last_window_width/height) + load/save
  atomic write 到 %APPDATA%/WindowsGotify/state.json(§18)
- ui/settings-page.slint: 5 分组(Connection / Notifications / Startup
  / Appearance / Advanced),Appearance 实时切主题(System/Light/Dark
  radio);Advanced 折叠
- ui/dialogs.slint: AboutDialog + ConfirmDialog(§54)
- ui/server-card.slint: 单 server 行(name/url/enabled toggle/edit/remove)
- ui/app.slint: settings 页切换、About 导航、theme 联动
- src/lib.rs: load_state → 启动时应用窗口尺寸;ui.window()
  .on_close_requested 在 OS 关闭前 save_state;wire about/close
  callbacks
- src/error.rs: 加 AppError::Storage(String) 变体
- Cargo.toml: 加 serde + serde_json

避坑:
- Slint 1.x 同文件内 export component 必须在引用前定义(sub-components
  移到 SettingsPage 上面)
- Slint 不支持 padding 两值简写 (padding: 0 16px) → 用 padding-* 四属性
- Slint 不支持 Rectangle 内建 border-color 覆盖 → 命名 card-border
- Slint 不支持 alignment: right → 用 spacer + horizontal-stretch: 1
- 修了一处 .slint 文件被 PowerShell Set-Content GBK 损坏的问题(已
  通过 write 工具 + UTF-8 no BOM 重写并清理 ui/ 所有 .slint)

验证:cargo build / build --release 都 exit 0,0 warning
- debug   27.55 MB, subsystem = WINDOWS_CUI
- release  8.10 MB, subsystem = WINDOWS_GUI
2026-09-19 04:47:54 +08:00
KennethCheng 49cbd9e371 feat(ui): Phase 2 C1 — MainWindow + Sidebar + 颜色/主题系统
完成 AGENTS.md §57 Phase 2 的前 3 项:MainWindow 布局、Sidebar、Dark 主题
基础。剩余的 Message list / Empty state / Settings / Light-Switch /
Window state 留到 C2 / C3。

技术栈变化
----------

本次最大的工程变化是把 Slint UI 从 `slint!{}` macro 内嵌迁到独立
`.slint` 文件 + build.rs 编译:

  ui/app.slint           MainWindow + Sidebar 骨架(Phase 2 C1 完整实现)
  ui/theme.slint         export enum AppearanceMode { System, Light, Dark }
                         (不再有 export global Theme / Palette,见下文)
  ui/components.slint    NavItem / SectionLabel / Divider(Dark 默认颜色)
  ui/message-card.slint  占位 stub(C2 实现)
  ui/message-list.slint  占位 stub(C2 实现)
  ui/empty-state.slint   占位 stub(C2 实现)
  ui/settings-page.slint 占位 stub(C3 实现)
  ui/server-card.slint   占位 stub(C3 实现)
  ui/dialogs.slint       占位 stub(C3 实现)
  build.rs               slint_build::compile("ui/app.slint"),
                         把生成的 .rs 路径写入 SLINT_INCLUDE_GENERATED
  src/lib.rs             `slint::include_modules!()` 引入编译产物;
                         `MainWindow::new()` 拿 UI 实例;
                         `ui.set_theme(AppearanceMode::Dark)` 初始化
                         (C3 改成从 state.json 读 + 监听用户切换)

为什么不用 `include_slint!` —— 那是 `slint_interpreter` crate 提供的
API,不在 `slint` 1.18 主 crate 里。官方推荐的"build-time precompile"
路线是 `slint_build::compile()` + `slint::include_modules!()`,文档明确
写了这一步。

为什么不用 export global Palette / Theme
---------------------------------------

最初一版我把 Theme + Palette 都做成 `export global`,期望从 Rust 端
用 `ui.global::<Theme>().set_appearance(...)` 切换 Light/Dark。失败
了:slint-build 1.18 在生成 Rust 代码时把这两个 global 都 dead-code
消除了,generated 的 pub use 列表里只剩 `MainWindow` 和
`SidebarSelection`。原因——global 的所有 binding 在编译期都被简化为
常量(Theme.appearance 默认 Dark,Palette.background 绑定直接 inline 成
`#1f2024`),没有任何 dynamic 引用保留 global 的符号表。

解决方案:把 Theme + Palette 全部搬到 MainWindow 上作为 out properties,
由 `MainWindow.theme` 触发 binding 重新计算。Rust 端用
`ui.set_theme(AppearanceMode::Light)` 切。代价是 sidebar 的 NavItem
暂时只有 Dark 默认色(fixed `#2f3035` 等),Light theme 在 C3 通过
property forwarding 扩展 NavItem 时补齐——这是 C1 阶段明确接受的折衷。

这一节值得写进 commit 而不是悄悄改掉——后面任何看到代码的人都会好奇
"为什么 palette 不直接 export global?",是这个原因。下次有 Phase 3+ 的人
碰这块也省得踩同样的坑。

Slint 版本对齐
--------------

之前 commit 时钉过 `slint = "1"`(让 cargo 选最新 1.x 稳定版),现在
slint-build 1.18.0 引入 build-deps:`slint-build`, `i-slint-compiler` 等。
两者锁到同一个 1.18.0 版本是 Slint 自身的 forward-compat 约束
(slint-build 的 `compat-1-18` feature 在 build.rs 启动时强校验)。

MainWindow / Sidebar 布局细节
-----------------------------

按 AGENTS.md §6 / §7:

- 960×680 preferred,760×520 min —— Slint 1.18 不允许同时设
  `width` + `min-width`,用 `preferred-width`/`preferred-height` 替代
  (之前第一次 build 报 `Cannot specify both 'width' and 'min-width'`,
  这里记录一下)。
- 232px sidebar 宽,含 AGENTS.md §7 列出的 6 个 section
  (logo + All + Servers 占位 + Filters 三个 + Settings + About)
- SidebarSelection enum 驱动右侧 view-switcher,三个 view 都有占位
  文字(Messages / Settings / About),C2 / C3 替换实际内容
- AGENTS.md §52 颜色 token 全部按 dark / light 两套列出,由
  `MainWindow.is-dark` 派生;优先级颜色(§7 message card)也按
  §7 Low/Normal/High/Max 映射

未做(按计划归到后续 commit)
------------------------------

C2:
  - src/models.rs(MessageItem + Priority enum,AGENTS.md §34)
  - src/mock.rs(生成 10 条 mock 消息)
  - ui/message-card.slint 真实内容
  - ui/message-list.slint 真实内容(ListView 接 Rust Model adapter)
  - ui/empty-state.slint 真实内容(§9 "You're all caught up" + ✦ + Test button)
  - main 区 if-switch 真正根据 list.is_empty 选 list / empty-state

C3:
  - src/storage/* —— 持久化 state.json
  - ui/settings-page.slint 真实内容(§10 五个分组 + Advanced 折叠)
  - ui/server-card.slint 真实内容
  - ui/dialogs.slint 真实内容(About + confirm)
  - sidebar NavItem 接 palette forwarding,Light theme 真的换 sidebar 颜色
  - 主题切到 Light/System 实时生效(System 跟随 Windows 主题)

验证
----

  cargo build              exit 0, 5.10s(增量)
  cargo build --release    exit 0(slint + skia + accesskit 全重编,约 8 分钟)
  warnings                 0
  debug   .exe             26.01 MB, subsystem = 3 (WINDOWS_CUI / console)
  release .exe              7.87 MB, subsystem = 2 (WINDOWS_GUI)

Phase 2 C1 验收:能在 Windows 上打开 MainWindow(960×680、Dark、含完整
Sidebar),通过 release profile 的 WINDOWS_GUI subsystem 验证无 console。
Sidebar 切换 Settings/About 时右侧文案占位更新——C2/C3 替换为实际 view。
2026-09-19 04:34:06 +08:00