fix(windows): 静默启动 #468 最后一公里 - 前端兜底#474
Conversation
release-sync: beta → main (no tag, internal merge)
…诊断 (#471) 集中修复 4 个 Windows-only bug: - #469 IME 切不回 — restore_profile 对称补 legacy TSF ChangeCurrentLanguage + ActivateLanguageProfile,回归点是 c3b5932 升级激活路径时漏改恢复路径。现代 ActivateProfile 失败降为 warn(legacy 已完成视觉切回)。 - #468 Win11 静默启动失效 — single-instance 回调读 start_minimized,true 时跳过 show_main_window;托盘 / CLI intent 路径不受影响。 - #466 QA 弹窗 X/ESC 关不掉 — Win 上从 SW_SHOWNOACTIVATE 切到 Tauri window.show + set_focus,让 webview 拿键盘焦点。配套 focus-dance:begin_qa_session 抓选区前临时把焦点还给用户原 app,抓完再 refocus QA;多轮场景下用 GetWindowThreadProcessId 区分本进程窗口,刷新 qa_focus_target,避免 stale HWND。 - #470 录音胶囊不显示 — 加 per-process 一次性诊断 log(CapsuleState 用 capsule_state_log_name 显式短名,不走 Debug 防字段扩展时泄露),下次能直接定位 prefs / state / Win32 哪一环失败。 pr_agent 五轮迭代到 No major issues + No security concerns;Cloud 评审建议的 begin_qa_session 双锁 TOCTOU 已合并为单 scope。三平台 build + pr_agent CI 全绿。 #470 没标 closes,是 refs—需要真机日志才能定位真因,先 ship 诊断手段。
权限页 (Settings → 快捷键 → 权限): - Pill 组件加 whiteSpace:nowrap + flexShrink:0 → "已安装"徽章在 Win 窄宽下不再被挤成 3 行(每个汉字一行)。 - 行内 message span 加 whiteSpace:nowrap + overflow:hidden + textOverflow:ellipsis + minWidth:0 → 长文本("Windows 低层键盘 hook 已安装")超宽时省略号收尾,徽章保持完整。 - zh-CN 描述大段精简:descAcc / descNoAcc / micDesc / accDesc / hotkeyDesc / networkDesc / windowsImeDesc / windowsIme.* 都改短, 减少 Win 上拥挤感(用户反馈 zh 文案过长)。 高级页 (Settings → 高级 → 本地 ASR): - Windows 上把"本地 ASR 模型(实验性)"标题区 + 警告小字 + Qwen3 行 整组 opacity:0.45 灰显 —— Qwen3 在 Win 是 stub 不支持,那条"实验性" 主线在 Win 没意义;用户视觉关注点应落到下方独立的 Foundry 行(Foundry 保持正常颜色)。Toggle 的 disabled 行为已经在原 onToggle 条件里,本次 纯加视觉灰显。
#471 在 Rust 端 setup() / single-instance callback 都加了 start_minimized suppression,本机日志确认 Rust 路径完全正确("[main] start_minimized=true → 跳过初始 show")。但用户在 Win11 1.3.4-3 上仍然「重启进桌面那一刻主 窗口就出来了」。 定位到最后一条遗漏路径在前端:App.tsx 里 mount 时一条 useEffect 无条件 通过 IPC 调 `getCurrentWindow().show()`,把 Rust 端已经 suppress 的窗口 又拉出来 —— 这条路径 Rust log 完全看不见(走的是 plugin-window 的 showWindow IPC,不经过我们的 show_main_window helper)。 那条 useEffect 当初是给 issue #163 引入的:Windows 权限探测可能死锁让 首屏卡灰,所以前端兜底 force show 一次。 修法:show 前先读 prefs.startMinimized,true 就 return。读 prefs 失败 (极少数情况)保持原 show 行为,不让 #163 的兜底语义丢失。 closes #468 (the actual one this time, Rust + JS 双端都收敛了)
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
|
@claude 请审查这个 PR。 简短说明:
主要关注点:
辛苦。 |
|
Claude finished @appergb's task in 2m 48s —— View job PR #474 代码审查
总体结论修复思路正确,针对 issue #468 的最后一公里路径(前端 IPC show 绕过 Rust 抑制)定位准确。三个关注点的详细分析如下。 关注点 1:cancelled 标志处理结论:基本正确,有一个无害的检测空隙。 当前检测点: 问题所在:在 为什么不是真正的 Bug:
如果追求最严格的写法,可在 const prefs = await getSettings();
if (cancelled) return; // ← 可加
if (prefs.startMinimized) return;不加也不影响正确性,看项目风格偏好。 关注点 2:getSettings 失败时走原 show 路径结论:合理,保留了 #163 的兜底语义。 } catch (err) {
console.warn('[startup] read startMinimized failed, falling back to show', err);
}
// 继续走 show 路径失败时默认行为是"展示窗口"而非"静默",这是正确的 fail-safe 方向:
唯一值得商量的地方:失败时也许应读取 关注点 3:跨平台 —— macOS 副作用结论:存在一个轻微的设计风险,实际影响极低,但建议后续修复。 当前问题:Settings UI 中 macOS 的 Rust 端
建议的改法:将 if (os === 'win') {
try {
const prefs = await getSettings();
if (prefs.startMinimized) return;
} catch (err) {
console.warn('[startup] read startMinimized failed, falling back to show', err);
}
}这消除了对 macOS 的任何影响,且逻辑更清晰:静默启动是 Windows autostart 特性,不适用于 macOS 的 其他小观察
是否可以合并Windows macOS 的 |
* fix(startup): autostart catch 块缺 return 导致复活主窗口 (#468) PR #474 引入的"前端兜底"useEffect 在 webview ready 后读 prefs.startMinimized,true 则跳过 currentWindow.show()。但 catch 块只 console.warn 没有 return,控制流继续走到 show()——等于"prefs 读失败 = 强 show"。 autostart 早期 IPC 抖动时 getSettings() 偶发失败,旧逻辑让用户明明开了 静默启动仍把主窗口弹出来。 修复: catch 块加 return,安全侧默认 = 当作 startMinimized=true 保持隐藏。 宁可让用户从 tray 手动唤起,也不要在 autostart 抖动时强 show 一个白色 / 透明主窗口。 LSUIElement 不在本 PR 范围: 那是全局 macOS UX 决策,会影响 Finder 双击 / Spotlight / Launchpad 启动场景,应单独 PR + 单独评审。 正确做法是 Rust 端动态切 activationPolicy 而非 plist 静态写死。 Refs #468 * docs(startup): clarify catch rationale + improve warn diagnostics Both local review and PR-Agent bot flagged the "fallback when settings read fails" semantic reversal. Re-analysis confirms the change is correct, but the rationale needs to be explicit in the code: - Rust `get_settings` signature is `pub fn -> UserPreferences` (not Result), so this catch is unreachable from a normal first-launch scenario (returns defaults). Only Tauri IPC infrastructure failures (e.g. __TAURI_INTERNALS__ not ready during autostart early-mount) reach this branch. - Tray is registered by Rust setup() before webview ready, so it remains the universal fallback entry point — no "user locked out" risk. - Improved console.warn to include err.message for diagnostics, since raw err objects serialize as [object Object] in Tauri devtools. No behavior change; comment + log improvement only. Refs review of #488 --------- Co-authored-by: baiqing <lbx12309@icloud.com>
User description
closes #468 — 详见 PR description (Rust 端 #471 修了 setup + single-instance 后,前端 App.tsx 仍无条件 IPC show 把窗口拉出来;现在 show 前读 startMinimized 兜底)
PR Type
Bug fix
Description
Respect
startMinimizedbefore showingPreserve fallback when settings read fails
Stop frontend relaunch from reopening
Diagram Walkthrough
File Walkthrough
App.tsx
Guard startup show by settingsopenless-all/app/src/App.tsx
getSettingsfor startup prefsstartMinimizedbefore window show