Skip to content

feat(capsule): 录音胶囊样式可选(流光 Siri / Openless 默认)+ 修复 beta 构建破坏 - #887

Merged
appergb merged 4 commits into
betafrom
feat/capsule-style
Aug 3, 2026
Merged

feat(capsule): 录音胶囊样式可选(流光 Siri / Openless 默认)+ 修复 beta 构建破坏#887
appergb merged 4 commits into
betafrom
feat/capsule-style

Conversation

@appergb

@appergb appergb commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

User description

目标

设置 → 录音与输入在「录音胶囊」显示开关下新增「胶囊样式」下拉,用户可自行选择:

  • 流光 Siri 风格(默认,SiriGL 光效舞台,现状不变)
  • Openless 默认风格(恢复 1.3.14 经典毛玻璃药丸:音量条 + 取消/确认按钮 + thinking 扫光 + 翻译徽章)

兼容性

  • 新增偏好 capsuleStyle('siri' 默认 / 'classic'),旧配置缺失字段自动回落 'siri'(Rust/TS 双侧 serde default)
  • 胶囊样式随 capsule:state payload 下发(capsuleStyle 字段),设置里切换后下一次录音即生效,无新权限需求
  • 选区润色轻量提示不受样式影响

评审修复(commit 3)

  1. 经典药丸按钮可点:胶囊窗口自纯光效舞台时代起永久 set_ignore_cursor_events(true)(鼠标穿透),✕/✓ 按钮实际收不到点击。现在主线程闭包按「classic && visible && 非选区润色 && 录音/转写/润色中」关闭穿透(按钮可点;代价是窗口底部 460×180 区域在会话进行中拦截点击——与 1.3.x 经典胶囊同款取舍,终态 toast 立即恢复穿透),值不变时不重复调用系统 API。
  2. 音频线程零偏好锁:emit_capsule 在音频回调线程 ~30Hz 被调,原先直接 prefs.get()(整份克隆 + 偏好锁被 set() 跨磁盘 I/O 持有)。改为 Inner 上 AtomicU8 样式缓存,主线程闭包每帧从 prefs 同步(与 show_capsule 同源),音频线程只读原子。
  3. 恢复「录音胶囊」行 desc 文案(beta 原有)。
  4. Capsule.tsx 注释同步按样式区分的退出动画常量。

附加修复(独立 commit)

beta HEAD 存在构建破坏:SelectionPolishSection 仍传快捷键重构(e12c8dcc)已删除的 alignRecordButton / modifierPresets,tsc 必失败。本 PR 顺带适配新 API(value 可空 + onReset 恢复默认快捷键,等价旧「启用」按钮),恢复 beta 可构建状态。

测试

  • cargo test --manifest-path src-tauri/Cargo.toml:865 passed, 0 failed(注:overlay_elevenlabs_cancel_finishes_idle_without_error_capsule 为 beta 既有 flaky——macOS 非阻塞 socket WouldBlock 时序竞态,未改代码的 base 同样间歇失败,与本文无关)
  • npm run build(tsc + vite):通过
  • npm test:15 个前端契约测试全部通过
  • 手动预览:?style=classic(浏览器胶囊 dev 预览)

证据路径

  • 功能:设置页截图 / 两种胶囊形态录屏(手动 macOS 验证中)

PR Type

Enhancement, Bug fix


Description

  • Add selectable capsule style (Siri default / Classic pill)

  • Fix beta build break in SelectionPolishSection

  • Enable Classic pill Cancel/Confirm click handling

  • Cache capsule style atomically, no audio-thread lock


Diagram Walkthrough

flowchart LR
  Settings["Settings UI"] -- "capsuleStyle" --> Prefs["UserPreferences"]
  Prefs -- "capsule:state payload" --> Capsule["Capsule.tsx"]
  Capsule -- "siri" --> Siri["SiriGL stage"]
  Capsule -- "classic" --> Classic["Classic pill + buttons"]
  Classic -- "interactive" --> Click["Ignore cursor events off"]
Loading

File Walkthrough

Relevant files
Enhancement
6 files
coordinator.rs
Add atomic style and passthrough state fields                       
+16/-3   
capsule_focus.rs
Propagate capsule style and toggle cursor passthrough       
+40/-1   
types.rs
Add CapsuleStyle enum and payload fields                                 
+25/-0   
Capsule.tsx
Implement Classic pill and style-based rendering                 
+458/-13
types.ts
Add CapsuleStyle type and payload field                                   
+10/-0   
RecordingInputSection.tsx
Add capsule style dropdown to settings                                     
+15/-0   
I18n
5 files
en.ts
Add capsule style i18n strings                                                     
+3/-0     
ja.ts
Add capsule style i18n strings                                                     
+3/-0     
ko.ts
Add capsule style i18n strings                                                     
+3/-0     
zh-CN.ts
Add capsule style i18n strings                                                     
+3/-0     
zh-TW.ts
Add capsule style i18n strings                                                     
+3/-0     
Miscellaneous
1 files
mock-data.ts
Add capsuleStyle to mock preferences                                         
+1/-0     
Tests
1 files
stylePrefs.test.ts
Update test fixture with capsuleStyle                                       
+1/-0     
Bug fix
1 files
SelectionPolishSection.tsx
Fix ShortcutRecorder props for new API                                     
+18/-33 

sim added 2 commits August 3, 2026 13:53
设置 → 录音与输入新增「胶囊样式」下拉(保留显示开关):
- UserPreferences.capsule_style('siri' 默认 / 'classic')随 capsule:state
  payload 下发,切换后下一次录音即生效
- Capsule.tsx 双样式分支:siri 保留 SiriGL 光效舞台;classic 恢复 1.3.14
  经典毛玻璃药丸(音量条 + 取消/确认按钮 + thinking 扫光 + 翻译徽章),
  取消/确认改走 lib/ipc/dictation.ts,退出动画时长按样式区分
- 预览支持 ?style=classic;i18n 五语言新增胶囊样式文案
beta HEAD 在快捷键录入交互重构(e12c8dcc)合并后遗留的构建破坏:
SelectionPolishSection 仍传已删除的 alignRecordButton / modifierPresets,
tsc 直接报错。改为新 API(value 可空 + onReset 恢复默认快捷键,
等价于旧「启用」按钮),恢复 beta 可构建状态。
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit 215eef3)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Possible Issue

The set_ignore_cursor_events(true) restore logic only runs inside the deferred (entry-frame) main-thread closure, next to the window.show handling. Mid-session state transitions (Recording → Transcribing → Polishing → Done/Cancelled/Error) go through the non-deferred immediate emit path, so the capsule window keeps ignore_cursor_events=false during the whole ~1.5s terminal toast, swallowing clicks aimed at the app below in the 460×180 area — contrary to the PR description's stated intent that the terminal toast immediately restores mouse passthrough. Passthrough is only restored on the next session's entry frame. This assumes defer_capsule_emit is only set when the window is shown from hidden, as the surrounding comments indicate; if the terminal-state emit is also deferred, this issue would not trigger.

let interactive = classic_style
    && visible
    && !selection_polish
    && matches!(
        state,
        CapsuleState::Recording | CapsuleState::Transcribing | CapsuleState::Polishing
    );
let want_passthrough = !interactive;
if inner_for_main
    .capsule_cursor_passthrough
    .swap(want_passthrough, Ordering::SeqCst)
    != want_passthrough
{
    if let Err(e) = window.set_ignore_cursor_events(want_passthrough) {
        log::warn!("[capsule] set_ignore_cursor_events failed: {e}");
    }
}

- 经典样式(Openless 默认)下胶囊窗口长期 set_ignore_cursor_events(true)
  (纯光效舞台时代遗留),✕/✓ 按钮实际不可点。现在主线程闭包按
  「classic && visible && 非选区润色 && 录音/转写/润色中」关闭鼠标穿透,
  终态 toast / 隐藏 / Siri / 选区润色保持穿透;值不变时不重复调用
  set_ignore_cursor_events
- emit_capsule 在音频回调线程 ~30Hz 被调,原先直接读 prefs(整份克隆 +
  偏好锁被 set() 跨磁盘 I/O 持有)。改为 Inner 上 AtomicU8 样式缓存,
  主线程闭包每帧从 prefs 同步(与 show_capsule 同源读取),音频线程零开销
- 恢复「录音胶囊」行的 desc 文案(beta 原有,重构时被误删)
- Capsule.tsx 退出动画注释同步为按样式区分的常量名
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 1231453

@appergb
appergb merged commit 006cb78 into beta Aug 3, 2026
4 of 5 checks passed
@appergb
appergb deleted the feat/capsule-style branch August 3, 2026 06:17
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 215eef3

H-Chris233 added a commit that referenced this pull request Aug 3, 2026
Follow latest beta (capsule style #887, fcitx5 crash fix #883); take beta's
SelectionPolishSection rewrite which supersedes the earlier prop cleanup.
H-Chris233 added a commit that referenced this pull request Aug 3, 2026
#887 introduced desktop-only capsule cursor-passthrough logic into the
unconditionally-compiled capsule_focus module, breaking Android cargo check
(E0599: no method set_ignore_cursor_events on tauri::WebviewWindow). Gate the
block to desktop; variables it consumes (classic_style, selection_polish,
visible) are still used on mobile outside the block.
H-Chris233 added a commit that referenced this pull request Aug 3, 2026
)

* fix(less-computer): restore OpenCode model execution

* fix(capsule): gate set_ignore_cursor_events behind #[cfg(not(mobile))]

#887 introduced desktop-only capsule cursor-passthrough logic into the
unconditionally-compiled capsule_focus module, breaking Android cargo check
(E0599: no method set_ignore_cursor_events on tauri::WebviewWindow). Gate the
block to desktop; variables it consumes (classic_style, selection_polish,
visible) are still used on mobile outside the block.

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Chris233 <h-chris233@outlook.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant