49cbd9e371ea9f12a35681cfd63a14c4d9010590
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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。
|
||
|
|
b30b2f0e28 |
feat: 实现 Phase 1 — Bootstrap(Slint hello window + 编译验证通过)
完成 AGENTS.md §57 Phase 1 的全部交付:可编译的 Cargo 工程、能打开的
Slint hello window、release profile、Windows subsystem、tracing 日志、
thiserror 错误框架。`cargo build` 与 `cargo build --release` 均通过,
0 warning。
实现概览
--------
新增 / 修改的文件:
src/lib.rs lib crate 入口;`slint!{}` 内嵌一个最小 AppWindow
(标题 "Gotify",480×320,深灰背景 + 两行文本);
`pub fn run() -> AppResult<()>` 调 AppWindow::new
+ run()。
src/main.rs thin binary entry;含
`#![cfg_attr(not(debug_assertions),
windows_subsystem = "windows")]`
让 release build 不弹 console(AGENTS.md §43);
debug build 保留 console 让 tracing 日志可见。
src/error.rs `AppError` + `AppResult`,thiserror 2.0.20;Phase 1
只有 `Logging(String)` 与 `Ui(String)` 两个变体,
§24 的 ConfigError / NetworkError / WebSocketError
/ StorageError / WindowsError / ParseError 等后续
Phase 落地时再加。
src/logging.rs `init_logging()`:tracing-subscriber 0.3.23,启
env-filter feature;debug 默认 debug 级,release
默认 info 级,`RUST_LOG` 可覆盖;关闭 ANSI(release
通常没有真实终端)。符合 §25 的"默认不记录消息正文"
基线——具体红线靠代码 review 强制。
Cargo.toml 实际可编译的 manifest:[[bin]] 指向 src/main.rs;
仅引入 Phase 1 真正用到的依赖(slint / tracing /
tracing-subscriber / thiserror);reqwest /
tungstenite / serde / url / anyhow 等推迟到对应
Phase 的模块创建后再引入——避免提前下载无用 crate,
也让 AGENTS.md §44 的 "Cargo 依赖最小化原则" 落到
每一阶段的 commit 上。
Cargo.lock 已生成(564 个 transitive deps,含 slint 1.18.0、
skia-bindings、accesskit、parley、fontique 等)。
二进制工程,lock 文件进 git——保证可重现构建。
技术选型说明
------------
- Slint 版本选择:AGENTS.md §1 写的是 "Slint 1.17.x 或当前稳定兼容版
本"。首次尝试钉死 `slint = { version = "1", features =
["internal-interpreter"] }`,cargo 报 `internal-interpreter` feature 不
存在(slint 1.18.0 已移除该 feature,slint!{} macro 走 default feature
set 即可)。改为 `slint = "1"`,cargo 自动选到 1.18.0,与 Rust 1.98.1 +
MSVC 工具链编译通过。AGENTS.md §1 的措辞明确允许"当前稳定兼容版本",
本次选 1.18.0 不偏离约束。
- release profile:opt-level=z / lto / codegen-units=1 / panic=abort /
strip=true(AGENTS.md §42 模板)。Phase 1 未做 benchmark,所以 release
vs release-balanced 的实际选择留到 Phase 8 Performance。
- 没引 slint-build / 没建 build.rs:Phase 1 hello window 内嵌在
`slint!{}` macro 里,足以通过验收。Phase 2 切到独立 .slint 文件 +
`include_slint!()` 时再决定是否需要 build.rs。
验证结果
--------
cargo build exit 0, 5.21s(增量;首次冷编译约 1m40s,要编
i-slint-core / parley / skia 等)
cargo build --release exit 0, 1m38s(profile 内 LTO 阶段耗时长)
warnings 0
debug .exe 25.58 MB, PE subsystem = 3 (WINDOWS_CUI / console)
release .exe 7.82 MB, PE subsystem = 2 (WINDOWS_GUI)
AGENTS.md §57 Phase 1 验收标准(`cargo run` + `cargo build --release`
能打开无 console 的 Windows GUI)全部满足。PE subsystem 通过直接读
Optional Header 的 Subsystem 字段验证——而不是盲目信任 cfg_attr。
下一步
------
进 Phase 2 — UI Shell(MainWindow / Sidebar / Message list / Empty
state / Settings / Dark-Light-System 主题)。本阶段仍然只用 mock 消息,
不接网络。
遗留
----
- commit message 之前那条 root commit (`a3a6a7c`) subject 前有个 UTF-8
BOM (`\ufeff`),是 PowerShell 5.1 `Set-Content -Encoding UTF8` 默认带
BOM 造成的。本 commit 用 `[System.IO.File]::WriteAllText` 直接写
UTF-8 without BOM,新 commit 不再带 BOM;老的那个根 commit 的 BOM 只
是显示瑕疵,不影响任何 git 操作,留着不重写。
- 首次 cargo build 拉了 564 个 crate、走代理拉取成功(crates.io 直连也
通,HTTPS_PROXY 走 127.0.0.1:7890 是兜底)。
- target/ 1.4 GB 在 .gitignore 内,不会进 git。
- 用户的 .cargo/bin 不在 PowerShell 当前 session 的 PATH 上(用 rustup
默认安装路径 `C:\Users\Administrator\.cargo\bin`),后续 cargo 命令
脚本里临时加 PATH 即可,未修改用户全局环境。
|
||
|
|
a3a6a7c91d |
chore: 初始化 Windows-Gotify-Client-Rust 项目骨架
使用 Rust + Slint 重建一个轻量、现代、Windows 原生体验良好的 Gotify
桌面客户端。本次只搭目录骨架与占位文件,未进入 Phase 1(Bootstrap)。
本次提交内容
------------
- 保留 AGENTS.md(1363 行定制 Agent 实施计划,含 8 阶段路线图)
- 新建 Cargo.toml([package] 元数据 + AGENTS.md §44 依赖模板 + §42
release profile;无 [[bin]],等 Phase 1 才加 src/main.rs)
- 新建 README.md(项目导览,引用 AGENTS.md)
- 新建 .gitignore(Rust / Slint / Windows / IDE / 密钥)
- 新建 LICENSE(MIT 占位)
- 按 AGENTS.md §4 建好全部 10 个目录,每个空目录放 .gitkeep:
assets/ assets/fonts/
ui/ scripts/
src/ src/gotify/
src/storage/ src/windows/
src/services/ tests/
未提交(Phase 1 起才落地)
------------------------
- src/main.rs 及所有 .rs 业务代码
- ui/*.slint 视图
- scripts/build-release.ps1 等构建脚本
- Cargo.lock(当前 Cargo.toml 是占位、无可编译代码)
技术栈约束(来自 AGENTS.md §1 / §2)
------------------------------------
- Rust stable + Slint 1.17.x + Windows 10/11
- 显式禁用:Tauri / Wails / Electron / WebView2 / WPF / WinUI 3 / Node 运行时
- 单一主程序,无浏览器运行时依赖;UI 由 Slint 原生渲染
仓库
----
远程:https://gitea.kennethcheng.cc/KennethCheng/Windows-Gotify-Client-Rust
|