feat(ui): 主题切换 + 语言持久化 + About 对话框

- 新增 light/dark 主题调色板与 Windows 注册表系统主题探测
- 偏好设置对话框:主题三选一 + 语言下拉(en/zh-CN/de),即时生效
- 持久化 Language/Theme/AutoLockMinutes/MinimizeToTray 至 YAML 顶层
- 启动时按 config 中保存的语言初始化 i18n
- About 对话框展示 version/runtime/项目地址/许可证
- 全部硬编码颜色迁移到 themePalette,为深色模式做准备
This commit is contained in:
2026-06-12 03:38:13 +08:00
parent c671f2115e
commit b483360778
19 changed files with 687 additions and 48 deletions
+55
View File
@@ -0,0 +1,55 @@
package ui
import (
"runtime"
"gioui.org/layout"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"git.wxccs.org/iceking2nd/winauth-go/internal/i18n"
"git.wxccs.org/iceking2nd/winauth-go/internal/version"
)
// aboutDialog is a read-only popup describing the build, runtime and a
// short credits / project link blurb. Click "Close" to dismiss.
type aboutDialog struct {
closeBt widget.Clickable
}
func newAboutDialog() *aboutDialog { return &aboutDialog{} }
// Layout follows the simpler "single button" contract: onDone is called
// with no arguments when the user dismisses the dialog.
func (d *aboutDialog) Layout(
gtx layout.Context, th *material.Theme,
onDone func(),
) layout.Dimensions {
if d.closeBt.Clicked(gtx) {
onDone()
return layout.Dimensions{Size: gtx.Constraints.Max}
}
body := func(gtx layout.Context) layout.Dimensions {
line := func(text string) layout.FlexChild {
return layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return layout.Inset{Top: unit.Dp(2), Bottom: unit.Dp(2)}.Layout(gtx,
material.Body2(th, text).Layout)
})
}
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
line(i18n.T("about_app_name")),
line(i18n.T("about_version_label")+": "+version.String()),
line(i18n.T("about_runtime_label")+": "+runtime.Version()+" ("+runtime.GOOS+"/"+runtime.GOARCH+")"),
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
line(i18n.T("about_project_label")+": "+i18n.T("about_project_url")),
line(i18n.T("about_license_label")+": "+i18n.T("about_license_value")),
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
line(i18n.T("about_credits")),
)
}
return modalCardCancel(gtx, th, i18n.T("dialog_about_title"),
i18n.T("btn_close"), &d.closeBt, body)
}