feat(ui): 首次启动加密引导 + 真窗口图标 (.syso)
首次启动: - 配置文件不存在时弹欢迎对话框:选「启用密码保护」或「稍后再说」 - 选启用直接进 setPasswordDialog,OK 时 store.SetPassword 触发首次保存 - io/fs.ErrNotExist 检测新分支 - modalCard 抽出 modalShell 内核以便 welcomeDialog 自定义 footer 真窗口图标: - tools/gen_ico 从 PNG 生成多分辨率 .ico(7 尺寸:16~256) - 提交 rsrc_windows.syso(rsrc 通过 goproxy.cn 生成),go build 自动链入 - tray_windows.go 改用嵌入资源 ID=1,失败 fallback IDI_APPLICATION - README 更新完整的图标生成流程
This commit is contained in:
+26
-2
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io/fs"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -97,6 +98,7 @@ type appState struct {
|
||||
pwDialog *passwordDialog
|
||||
setPwDialog *setPasswordDialog
|
||||
changePwDlg *changePasswordDialog
|
||||
welcomeDlg *welcomeDialog
|
||||
importDialog *importLegacyDialog
|
||||
hotkeyDialog *hotkeyDialog
|
||||
hotkeyTarget *entry
|
||||
@@ -169,10 +171,15 @@ func loop(w *app.Window, configPath string) error {
|
||||
w.Invalidate()
|
||||
})
|
||||
|
||||
// First-load attempt: empty passphrase. If the file is encrypted we'll
|
||||
// surface a password dialog on the first frame.
|
||||
// First-load attempt: empty passphrase. The branches are:
|
||||
// - file missing → first-run welcome dialog (encrypt / skip)
|
||||
// - file encrypted → password dialog
|
||||
// - other load error → log + show error banner
|
||||
if cfg, err := state.store.Load(nil); err != nil {
|
||||
switch {
|
||||
case errors.Is(err, fs.ErrNotExist):
|
||||
global.Log.WithField("func", fn).Info("no config file; showing first-run welcome")
|
||||
state.welcomeDlg = newWelcomeDialog()
|
||||
case errors.Is(err, ErrPasswordRequired):
|
||||
state.pwDialog = newPasswordDialog(i18n.T("msg_password_required"))
|
||||
default:
|
||||
@@ -474,6 +481,23 @@ func drawFrame(gtx layout.Context, th *material.Theme, st *appState, w *app.Wind
|
||||
st.rowMenu = newRowActionMenu(moreTargetIdx, total)
|
||||
}
|
||||
|
||||
// First-run welcome dialog. Routed before all other dialogs so the
|
||||
// encryption choice appears immediately on a fresh install.
|
||||
if st.welcomeDlg != nil {
|
||||
return st.welcomeDlg.Layout(gtx, th, func(r welcomeResult) {
|
||||
st.welcomeDlg = nil
|
||||
if r.encrypt {
|
||||
// Hand off to the existing setPasswordDialog. OK on
|
||||
// that dialog will call store.SetPassword, which
|
||||
// creates the config file.
|
||||
st.setPwDialog = newSetPasswordDialog()
|
||||
}
|
||||
// skip: leave entries empty and unencrypted; the user
|
||||
// can encrypt later via Settings → Set password.
|
||||
w.Invalidate()
|
||||
})
|
||||
}
|
||||
|
||||
// Password retry / first-decrypt loop.
|
||||
if st.pwDialog != nil {
|
||||
return st.pwDialog.Layout(gtx, th, func(pw []byte, ok bool) {
|
||||
|
||||
Reference in New Issue
Block a user