Conversation
…包 postinst 改 D-Bus 重载 - 胶囊:录音/思考不再画红/黑外圈(用户报「语音输入弹窗有一个红边」), 改成 Tauri 的「1px 中性描边 + 随音量放大 1.8%」;中心声波/流体圆点保留。 两条新测试锁死:录音相位不得出现偏红涂色、GPU 回调数固定 1/1/0。 - 风格直达快捷键:草稿行选择器曾把 draft_pack 当行号下发 StyleHotkeyRepack, 会把已有行的包改掉,且 StyleHotkeyDraftPack 从未构造(编译告警)。 新增 style_pack_pick_action(row: Option<usize>, next) + 测试。 - popup_layer:去掉不必要的 unsafe 与未被使用的 FrameCallback 别名。 - 打包脚本:postinst/postrm 不再 `fcitx5 -r`(会替换 daemon 并前台常驻、装包卡 5s), 改用 D-Bus controller Restart(实测 0.002s 返回)。
…ze 语义只比 ctrl/alt/shift/super;近失日志降到 Info 并加可开关逐键 trace;宿主逐项记录注册的 (sym,states)
…oard settings theme + UX polish - Add OpenLessBuildInfo.VERSION (manually bumped per debug build) and use it to reset all restart-cause counters on a fresh build, and to show the running build on the keyboard settings screen. - OpenLessProcessRestartStats now tracks today's count only (no more 3-day retention), with a resetToday() used on version bump. - OpenLessKeyboardSettingsActivity: follows the app's own light/dark theme instead of being hardcoded dark, live Max/Set labels on the vibration sliders, halved the duration range for finer control, and reorganized the restart-cause rows with short Chinese glosses. - OpenLessImeService: hide the stroke-encode clear button when there's nothing to clear, add a divider to the two-line "History/Correct" key, and trigger haptic feedback at the recording/transcribing/done points of the dictation lifecycle. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
…e settings-open request OpenLessBackendWarmupActivity auto-backgrounds itself 180ms after every launch unless a settings-open request is in flight. That flag was only ever set from Intent extras/action read in onCreate()/onNewIntent(), which depends on whose Intent gets delivered first. On-device logs showed ensureBackendReady()'s silent warmup and a genuine open request (launcher icon or Logo tap) landing within ~10ms of each other right after the OS killed the process in the background — under the losing ordering, the auto-hide timer fired before the real request could cancel it, and the settings window flashed and vanished. Add a settingsOpenPending flag set synchronously by openSettings()/ openSettingsIfRunning() before startActivity() is ever called (and applied directly to an already-live instance, bypassing Intent-delivery timing entirely for the common reuse case). Also re-check isRunning() right before launchWarmup()'s own delayed startActivity(), since something else can have already started the host in the 120ms window since the caller's own check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
…backspace, tune edit panel Settings black screen (two independent causes, both fixed): - OpenLessBackendWarmupActivity's settingsRequested race: silent ensureBackendReady() warmup and a genuine settings-open request could land on the same singleTask Activity within milliseconds after an OS background kill, and depending on ordering the 180ms auto-hide timer could fire before the real request cancelled it. Fixed with a settingsOpenPending flag set synchronously before startActivity(), plus an isRunning() recheck before launchWarmup()'s delayed launch. - WebView renderer left blank after the OS freezes it in the background (this Activity spends almost all its life backgrounded) and doesn't always resume compositing when brought back to the foreground. Fixed by capturing the WebView via WryActivity's onWebViewCreate() hook and forcing a reload() whenever a genuine (non-warmup) settings-open is detected. Dictation result controls: - Deleting via the IME's own backspace key (plain or select-all-then- backspace, both go through deleteBackward()) no longer clears lastDictationText, so the undo/redo/edit row stays up and usable — only a change from outside the IME (e.g. the host app clearing the field after send) still invalidates it. Starting a new, non-correction recording now proactively hides the row instead of leaving it pointing at a soon-to-be-stale result. - Edit panel's "add correction rule" checkbox: enlarged 1.5x and moved lower in the panel; defaults unchecked when the whole dictated span is selected (or nothing is selected, falling back to the whole result), checked only for a genuine partial selection. Also: build version line now shows an install/reset timestamp (build_first_seen_wall_time, written whenever the version bump resets the restart-cause counters), and the Android README documents the full black-screen investigation plus a restart-cause recordStart() code map for cross-checking. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
…istener 变 Option)
Linux egui 的发布此前是一条从没被调用、也从没跑成功过的独立工作流: fork 里 dispatch 时它带了一个不以 v 开头的 release_tag,在第 8 步 (依赖安装 + fcitx5 插件构建 + 全量测试之后)报 "release_tag must name an existing v* release",白烧 4.5 分钟 runner。 - release-tauri.yml 变成唯一一条发版流水线,按 tag 后缀决定构建哪些平台: v*-tauri → macOS/Windows 的 Tauri 包;v*-egui → Linux deb/rpm(egui 原生宿主, 通过 workflow_call 复用 release-linux-egui.yml);手动 dispatch → 两侧都构建。 - 新增 bundle-all-artifacts:把本次 run 的全部 artifact 收成一个 OpenLess-<tag>-all-artifacts.zip(zip 名自带 -tauri/-egui 后缀), 根目录附覆盖全部文件的 SHA256SUMS,tag 推送时挂到同一个 release。 与 build job 同一套渠道判定,beta release 不会被这个只挂 zip 的 job 升格。 - release-linux-egui.yml:tag 校验提到编译之前(几秒出结论);release target 从「release 必须先存在」改为「tag 必须存在」,让 -egui 这个新命名空间 首次推送时能自己建 release;版本推导先剥 -egui(-tauri 仅作历史兼容, 保持 release 契约测试要求的写法);首次为 -egui tag 建 release 时正确标 prerelease。
…引擎占用时释放(pinyin QuickPhraseKey,带备份)
实测 run 35120587777:22.04 上冷缓存重编 libspa 0.10.1 直接编译失败 (spa_video_info_raw has no field named flags / missing spa_meta_first), 整条发布流程卡在第 8 步。ci.yml 的 linux-core-contract 早就因为同一个原因 换到 ubuntu-24.04 并留了注释,这条工作流从没跑过所以一直没跟上。 注意:deb/rpm 的 glibc 基线随之抬高到 24.04(glibc 2.39);若需要覆盖 22.04 用户,得在依赖层解决 libspa/PipeWire 版本,而不是换 runner。
… Linux egui)
按用户拍板的方案 B 收口 tag 约定:v<version>-egui(例 v2.0.0-Beta.1-egui)
一次推送 → 同一个 run 里四平台并发构建 → 所有产物挂同一个 Release
→ 末尾 bundle-all-artifacts 打成 OpenLess-<tag>-all-artifacts.zip。
- 后缀不再是平台分发开关:-egui tag 下 build(Tauri 三腿)与
release-linux-egui(workflow_call,tag 由编排层传入)都跑,zip job needs 全四者。
- build 里所有 release 相关步骤(签名可用性检查、release body prelude、
Create/update release)从「仅 -tauri」放宽到任何 v* tag,否则 -egui 发布时
dmg/msi/exe 只进 artifacts、不会挂到 Release。
- 历史 v*-tauri tag 兼容保留:仍只跑 Tauri 三平台(旧行为),文件头注释写清
两者关系与迁移注意(Cask URL/README/bump-version.sh/android-apk.yml)。
- Linux 产物命名统一带 egui 标识:deb/rpm 已是
OpenLess-Linux-egui-<ver>-<arch>(脚本原有),校验和文件改名 SHA256SUMS-egui,
避免与其它平台/聚合层那份混淆;版本串仍由传入 tag 推导(剥 -egui)。
- update-homebrew-cask 保持仅 -tauri:cask 下载 URL 写死 v#{version}-tauri,
迁移到 -egui 前不能动,已作为待办写进文件头注释。
…rl+Shift+; 匹配「Shift 折进符号」
三个实测问题(-40 真机反馈):
1. 点关闭键没反应:winit 在原生 Wayland 上 `set_visible` 是空实现
(winit-0.30 wayland/window/mod.rs「Not possible on Wayland」),
所以 -40 的 `Visible(false)` 等于什么都没做。最小化虽受支持,但最小化的
surface 拿不到 frame callback → eframe 的 update() 停摆 → 热键、托盘、
单实例唤起全部失效(实测心跳停、按热键无反应、重启也拉不回来)。
改为 Wayland 上隐藏 = 临时放开最小内尺寸 + 塌缩到 1x1 并保持映射:
窗口看不见了,事件循环照常跑(实测隐藏后 recording=true,热键仍生效;
再次启动能把窗口按原尺寸恢复)。X11 仍走真 unmap。
2. 事件泵保活必须用真线程:tokio 运行时是 current-thread,spawn 的任务只在
别处 block_on 时才推进,当后台泵用等于没保活。
3. Ctrl+Shift+; 到达插件时是 sym=0x3a(':') 且 states 里【没有 Shift 位】
(trace 实测;字母如 Ctrl+Shift+S 则是 sym=0x53 states=0x05)。注册值
0x3b/0x05 因此永远匹配不上。匹配规则改为:符号相同则严格比修饰位;符号
成 base/shifted 对时,只有注册值本身带 Shift 才接受、并忽略事件里的
Shift 位(Ctrl+; 与 Ctrl+Shift+; 双向仍可区分)。近失日志同步放宽到
「除 Shift 外的修饰位一致」,否则这类失败永远没有日志。
…聚合 job needs: build 会让 Linux 腿等 macOS/Windows 编完才启动,那不是四平台并发。 去掉它之后两个 job 可能同时建同一个 release,所以: - release-linux-egui.yml 新增 attach_release 输入(默认 true 保持单独 dispatch 行为) - 编排层传 attach_release: false,Linux 资产改由 bundle-all-artifacts(needs 四者、 最后一个 job)统一挂到 release,顺带和 zip 一起写,写入点唯一。 bundle job 里 Linux 资产那步用 hashFiles 守卫:egui 腿失败时不会让整步失败、 也不会把 zip 一起拖下水(zip 自己有 test -s 硬门禁)。
…ader-anchored panel transitions - New always-on status dot next to the Logo (voice panel only, 12dp, breathing pulse): light green when ready, red while recording, blue while processing, amber when a new periodic heartbeat check (runBackendHeartbeatCheck(), every 6s) finds isBackendReady() false — surfaces the "mic tap does nothing, no waveform, recovers on its own a moment later" symptom before the user even taps, instead of only reacting after a failed attempt. A bad heartbeat reading also proactively calls ensureBackendReady() and records a new "heartbeat" restart-cause counter (added to the keyboard settings screen and the version-bump reset list). - refreshInputView(slideDirection) now only animates each panel's content (childAt(1..)), leaving the header row (Logo/mode toggle/link indicator, always childAt(0) — every panel builder addView()'s it first) anchored in place across the transition instead of sliding with the rest. The four-segment mode toggle now drives the same slide animation on tap (direction from InputMode.entries order), not just swipe gestures. - SwipeModeContainer's swipe-to-switch commit threshold changed from a fixed 100dp to 70% of the panel's own width, scaling with screen size instead of a constant figure. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
…d candidates
New three-layer English keyboard (buildKeyboardView() rewrite):
- EnglishLayer{LETTERS,NUMBERS,SYMBOLS} replaces the old two-state
symbolMode boolean, matching iOS 17's own ABC/123/#+= key relationships,
row counts, relative widths, and switching logic (row-3 toggle only
moves between Numbers/Symbols; the bottom-row toggle always jumps
straight to/from Letters). Colors/key surface stay OpenLess's own
(roundedButton()/tone()), matching the stroke panel.
- Key-press preview bubble (KeyPreviewBubbleView, plain Canvas drawing)
shown via PopupWindow.showAsDropDown() anchored to the pressed key —
showAtLocation() with manual absolute coordinates turned out not to
render reliably from an IME's own window. Supports dragging onto an
adjacent key in the same row to retarget the eventual commit.
- Candidate bar: same HorizontalScrollView/candidateItemView()/overflow
"▼" button/showCandidateOverlay() the stroke panel already uses, so
layout, colors, and the first-candidate highlight are identical by
construction. Framed with the same divider lines used elsewhere in the
panel, hidden together when suggestions are toggled off.
- EnglishCandidateProvider/EnglishUserFrequency: prefix trie + background
executor + LRU cache + log-scaled-count/recency-decay user frequency,
directly mirroring StrokePhraseRepository/StrokeUserFrequency's
existing architecture rather than a new indexing scheme. Base
dictionary: hermitdave/FrequencyWords (MIT License, OpenSubtitles-2018
English), filtered to 20,000 words (~250KB) by
scripts/generate-english-dictionary.mjs — see
android/assets/english-frequency.LICENSE.txt for full attribution.
Candidate selection verifies actual field content against the tracked
prefix (progressively shorter suffixes, same technique as
invalidateDictationResultIfTextChanged()) before deleting, so any
drift can't leave old letters sitting in front of the inserted word.
- New "English word suggestions" toggle in keyboard settings
(english_suggestions_enabled).
No other input mode's key components, InputConnection protocol, or
Service lifecycle were touched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
Editing a dictation result or swiping a clipboard entry to "correct" it used to auto-write a CorrectionRule (pattern -> replacement). Switch both entry points to add_vocabulary_if_absent() on the same global Dictionary the desktop UI's add_vocab command uses, so corrections improve ASR/LLM accuracy directly instead of piling up hand-written substitution rules; CorrectionRule is now hand-maintained only. - native_bridge.rs: spawn_add_vocabulary_word/vocabulary_phrases_json/ spawn_remove_vocabulary_word + matching JNI exports - OpenLessNative.kt: nativeAddVocabularyWord/nativeVocabularyPhrases/ nativeRemoveVocabularyWord externs - OpenLessImeService.kt: addCorrectionRuleForEdit -> addToDictionaryForEdit, edit-panel checkbox and clipboard swipe labels/callbacks updated - bump OpenLessBuildInfo.VERSION to 1.28 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
…oard UI Clipboard swipe-left "add" no longer opens the voice-correction panel (that flow only made sense when it produced a pattern->replacement CorrectionRule); it now calls nativeAddVocabularyWord() directly and refreshes the panel, matching the already-direct "remove" side. Removed the now-dead openCorrectionRuleViaVoice()/ editingForClipboardCorrection plumbing this obsoletes. Also relabels remaining "Correct"/"纠正" keyboard UI to "Dict"/"字典" to match the underlying Dictionary-backed behavior, and changes the edit panel's dictionary checkbox to default unchecked (opt-in) with updated wording. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HNM6vtTz2hgN2ppqCoJ9k4
- bundle-all-artifacts 只下载 openless-linux-egui-x86_64 这一个 artifact, zip 根部就是打包脚本的原始文件名(.deb/.rpm/SHA256SUMS),不再塞 dmg/msi/exe, 也不再另造一层汇总校验和——打包脚本自带的 SHA256SUMS 就是权威。 - Linux 校验和文件命名改回 SHA256SUMS(撤销上一轮的 SHA256SUMS-egui)。 - needs 仍为 [build, release-linux-egui]:它仍是 Linux 资产的唯一 release 写入点 (egui job 保持 attach_release: false)。 - ubuntu-24.04 的分发基线写进注释:glibc ≥ 2.39,支持范围 Ubuntu 24.04+, 22.04 / Debian 12 不在支持范围内(用户已确认,防止被改回去)。 - Homebrew、Cask、README、bump-version.sh、android-apk.yml、macOS/Windows 构建步骤均未动。
…键消费与弹窗拉起一起失效) - 有托盘:最小化 → 与关闭键同一条 hide 路径(Wayland 塌缩隐藏,事件循环继续跑) - 无托盘:保持真正的窗口管理器最小化,否则窗口找不回来 - 新增 minimize_action() 决策函数 + 测试锁死该语义
a_per_user_copy_only_shadows_when_the_package_has_the_addon 之前直接断言 /usr/lib/x86_64-linux-gnu/fcitx5/libopenless.so 存在:装了 deb 的开发机绿, 干净的 CI runner 上 is_file()=false → 该断言必挂,于是 Linux 发布腿在第 8 步 「Verify framework-independent Linux contract」失败,后续 upload/checksums 与聚合 zip job 级联失败。 改为 tempfile 自建 per-user 文件,覆盖「无文件」与「有文件 + 包内有 addon」两个 分支,并保留「无包内 addon 时不 shadow」的反例断言。用 unshare + tmpfs 隐藏系统 插件目录后该测试仍通过,证明不再依赖宿主文件系统。
已实测证伪「拼音的 QuickPhraseKey=semicolon 会吃掉 Ctrl+Shift+;」:
fcitx 的 Key::check 要求修饰位精确相等(semicolon 是 states=0,而
Ctrl+Shift+; 到达时是 states=Ctrl),两者本就能共存。用户真机验证:
保持 QuickPhraseKey=semicolon 时按 Ctrl+Shift+; 面板照常弹出。
- settings.rs: 去掉 apply_hotkeys 里对 release_engine_key_conflict 的调用
- fcitx5.rs: 删除 release_engine_key_conflict{,_in}、release_engine_reserved_key、
engine_reserved_keys、fcitx_key_aliases、fcitx_punctuation_name、
reload_addon_config 及 4 个相关单元测试(-259 行)
- tests/fcitx5_config_contract.rs: 新增不变量契约,断言宿主源码里不出现
输入法配置目录与引擎保留键;已用注入违规验证它非空转
- 真机 A/B:旧二进制会把临时 HOME 的 QuickPhraseKey 清空并留日志,
新二进制字节不变、0 条日志,且启动路径确实跑过(有热键注册日志)
冲突只出现在 openless-all/app/linux-egui/src/main.rs(4 处),且都是官方对这版 monolith 的 provider 编辑器 / remote_ui 做增量改动、而本分支 91 个提交已把这两个 子系统搬进 ui/frontend/*(改由 tr_l10n + FrontendViewModel 渲染)造成的结构性冲突。 解决方式(未使用整文件 --ours/--theirs,逐块判定): - 4 处冲突保留本分支结构,丢弃 752 行已被替换的 monolith 实现(provider 渠道列表、 provider_fields_ui/save_provider_editor/clear_provider_secrets/_ui、remote_ui、secret_edit) - 官方 auto-merge 进来的语义改动全部保留:core 的 provider_rules(+194)、 provider_service、credentials、api/llm_protocol/polish/prompts、docs 基线、 linux-egui/credentials.rs 的 volcengine_service,以及 ProviderEditor.volcengine_service 字段与其读取路径 - 官方新增的两个 remote UI 测试依赖本分支已删除的 remote_ui() 与 rendered_text()/disconnected_app() 助手,在本结构下无法编译(orphan auto-merge): 删除其中被 auto-merge 进来的一个,其覆盖改由前端测试 remote_certificate_details_hide_when_stopped_or_stale_and_warn_without_a_full_fingerprint 承担 - 同时把官方该测试覆盖的行为移植进我们的前端 settings.rs:地址过期(urls_stale)时 不再展示旧网址/配对码;服务在监听但拿不到 64 位十六进制完整指纹时,显式显示 「完整指纹不可用」告警(theme::WARN),而不是静默省略 验证:cargo test --locked 全绿(linux-egui 809 + 其余各 target 0 failed)、 41 个 scripts/*.test.mjs 全 pass、sync-egui-i18n --check 干净(881 keys / 0 added)、 cargo check 无 error。
`1157fe51` 的界面重写把旧 monolith 的 provider 编辑器一起删了,新设置页只留住 「渠道列表 + 新建 + 启停 + 校验 + 删除」,于是 Linux 版既不能录入/修改/删除云服务 凭据,也不能改名、换 provider 类型、重排渠道、选当前渠道 —— 发布流水线第 8 步的 `check-linux-public-surface.ps1` 正是在拦这个(它的注释写明:只有状态、或只有本地 模型捷径的界面不算可用安装路径)。 - 宿主重新接上 Core 的 provider/凭据 API:rename_channel、set_channel_provider_type、 reorder_channels、set_active_provider、set_credential、remove_credential,以及 provider.validate / provider.list_models(模型目录属于 Core)。 - 编辑器草稿放在宿主侧(ProviderEditorForm)并每帧镜像给 view model:重新拉取渠道 列表不会冲掉正在输入的内容;密钥字段只写,打开编辑器不会把已存密钥读进 egui。 - 界面补回:渠道行的编辑/上移下移/换类型/设为当前,以及按 AuthRequirement 渲染的 编辑器(Endpoint/Model/Resource ID/密钥/鉴权模式 + 读取模型 + 保存 + 清空密钥)。 - 顺手修掉「新建渠道」名称框推的是编辑前的值:宿主会把旧值写回,每敲一个字被回灌。 - 新增本地契约测试 provider_surface_contract.rs,把这组 Core 调用钉住,避免下次合并 或清理再把实现删掉(历史上正是这样丢的)。
用户澄清了这个 zip 的用途:不是把安装包再打一层,而是给装不了 deb/rpm 的发行版 手动安装用。所以: - payload 用 `dpkg-deb -x` 解开 deb 得到精确安装树(usr/bin/openless、 usr/lib/*/fcitx5/libopenless.so、addon conf、desktop、metainfo、icon), 并新增硬门禁:散装清单必须与 `dpkg-deb -c` 的文件清单逐项一致(漏文件最难发现)。 - 新增 `openless-all/app/scripts/linux-egui-manual-install.sh`,随包发布为 install.sh:检查 root、先验 SHA256SUMS、按用途给权限铺到 /、用 D-Bus controller Restart 重载 fcitx5(与 deb postinst 一致,不用会卡住的 `fcitx5 -r`),最后打印 重启与卸载提示。 - SHA256SUMS 改为对散装文件 + install.sh 重算;zip 内硬门禁断言不得出现 deb/rpm。 - zip 名自解释:OpenLess-Linux-egui-<tag 或 run>-x86_64-manual.zip;job 名/artifact 名与注释一并从 all-artifacts 改为 manual install,避免语义继续误导。 - deb/rpm 与它们自己的 SHA256SUMS 仍作为独立 release 资产保留(那条 attach 步骤没动)。 - bundle job 补 checkout(脚本随仓库版本走,不内联进 workflow)。
… 升 action 到 node24 版本消掉 node 警告 - 去掉 workflow_call 调用:release-linux-egui.yml 的步骤内联为 release-tauri.yml 里与 build 平级的 linux-egui job,Actions 页面上不再被渲染成嵌套折叠条目 - 同一个 job 内完成 deb/rpm 打包与手动安装 zip 组装(删掉单独的 bundle job) - release 竞态:内联后与 Tauri 三层并发写同一 release,先用 gh release view||create 幂等地建出来(吞掉并发 422),softprops 只做 attach/update - manual zip 语义:散装 usr/ 树 + install.sh + 重算 SHA256SUMS,不含 deb/rpm; deb/rpm 仍作为独立 release 资产 - action 升版(仅这两个发布工作流):checkout v4→v6、setup-node v4→v7、 upload-artifact v4→v7,消除 GitHub action 自身 node20 运行时带来的 DEP0040 punycode / DEP0169 url.parse 弃用警告(用户点名的 node 警告) - 契约测试加锁:断言 Linux 腿必须是内联普通 job、manual zip 必须在同一 job 产出、 两份副本的关键门禁不能漂移
- release-tauri.yml: push.tags 收敛为 'v*';build 与 linux-egui 的 if 不再按 -tauri/-egui 后缀分流(后缀降级为命名约定);Homebrew cask 仍只跟稳定的 -tauri 正式版 (注释写明该边界与影响,避免被顺手放开) - android-apk.yml: 触发从 'v*-tauri' 扩展为 'v*';is_tag_release 判定不再要求 -tauri; OPENLESS_RELEASE_CHANNEL 判定与桌面统一(含 -beta-egui);未签名 debug fallback 语义不变; 注释说明为何 Android 是独立 workflow(另一套 JDK/SDK/Gradle 工具链,塞进 matrix 会让 每步都长满 if)以及它的资产如何落到同一个 release - 顺带把这几个 action 升到 node24 版本(checkout v6 / setup-node v7 / upload-artifact v7), 与发布工作流一致,消掉 action 自身运行时带出的弃用警告 - 契约测试新增:两份工作流都必须对 'v*' 触发、安卓必须挂到同一个 release、 build/linux 两个 job 必须无条件运行、Homebrew 仍锁 -tauri
- 抽出与渲染无关的 tick():原生事件、托盘命令、自动更新检查、心跳日志; eframe 的 update() 与无窗口宿主的 run_headless() 循环共用它,热键消费与 弹窗拉起不再依赖「窗口是否在绘制」(最小化/隐藏/无窗口都照常工作)。 - 关闭键/最小化键:有托盘且没有进行中的会话时切到无窗口宿主。Wayland 下 winit 无法隐藏窗口(set_visible 是空实现),只有窗口进程真的退出,任务栏 与窗口列表里的条目才会消失;会话进行中退回托盘,避免新进程重开后端丢会话。 - 进程形态切换用同可执行文件的新进程 + --takeover:新进程等旧进程释放单实例 锁后接管(不在交接期被转发后直接退出),托盘在接管后重试一次;接管超时降级 为无锁启动,保证托盘/窗口仍可用。 - Core 的 ShowMain/FocusMain 提示在无窗口宿主里不拉起窗口进程(那只是「把已有 窗口推前面」),只有托盘「显示主窗口」才是明确的用户动作。
… fix, mode toggle redesign - Fix black settings screen on cold start: sendToBackground() now polls WebView.progress instead of trusting a fixed 180ms delay before backgrounding the warmup Activity, so a slow first WebView init isn't interrupted mid-load (the earlier version's null-check had this backwards, treating "not created yet" as "nothing to wait for"). - Mic button gestures: swipe down while recording cancels outright (with a warning haptic + intercept-guard against the panel's own dismiss-swipe); swipe up arms "skip LLM polish" for this utterance (orange link-indicator, double haptic) — from idle, swipe up starts recording with it pre-armed. Backend: DictationContext::with_raw_requested() + DictationStopOptions.raw_requested, threaded through a new nativeStopDictationForImeWithRaw() JNI export, genuinely skips the LLM step via the existing uses_llm_polisher() built-in-Raw-style check. - Ready-state link indicator pulses slower (1800ms vs 900ms) to read as an actual breathing animation. - Top mode-toggle (voice/stroke/edit/EN) selected segment is now a floating rounded pill (KeyPreviewBubbleView-style, keyboard-key gray) instead of a sharp panel-colored rectangle, animated between segments with a 180ms ValueAnimator instead of snapping. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Pressing the title bar hands the pointer to the compositor on the press frame (Wayland's xdg_toplevel.move only accepts that serial). The price is that the release of that gesture belongs to the compositor too, so egui keeps believing the button is still down and keeps the drag attached to the title-bar drag zone. ScrollArea refuses the wheel while dragged_id is set, so after moving a window the whole page stopped scrolling until the user clicked something; the window also moved under the pointer without any motion event, leaving egui with the press-time coordinates (usually on the title bar), which drops the wheel as well. raw_input_hook now repairs both before each pass: it releases a press the window manager kept for longer than a normal click, and, when a wheel arrives while the known pointer position is not inside the body, points the pointer at the body centre - the wheel proves it is over the window, and a real pointer event overrides the guess immediately. Also match macOS on the settings sheet: the mask is the blurred page plus the same --ol-overlay-bg tint, and the card uses the --ol-shadow-xl sized shadow.
…ing the wheel Three reports from the same build: * The blurred settings mask was painted as a square image over the rounded bottom corners, so it stuck out past the window shape. It is now a textured rounded rect using the content corners (and no rounding when the window fills the screen), and the tint above it shares the same shape. * A maximized or tiled window kept the 6px transparent margin and the 14px corner radius that exist to make the floating window look like one, leaving a blank frame around the screen. Both are now dropped when the window fills the screen (maximized, fullscreen, or surface size matching the monitor). * Resizing from a corner still killed page scrolling: the corner grips are the app's own BeginResize zones, so the press is handed to the compositor exactly like a title-bar drag, and the release never comes back. The grips now record the handoff too, so the orphaned press is released and the wheel works again. A regression test reproduces the reported flow (Overview, drag the corner to the minimum size, then scroll); without the fix it reports offset=0.
Adds "导出 / 导入配置" (Export/Import settings) to the native keyboard settings page, covering seven categories the user can select independently for each direction: - Cloud notes webhook URL/token, haptic settings, stroke ranking (StrokeUserFrequency), and pinyin combo learning (LitePinyinLearnedPhrases) — all already local to this Android process, exported/imported directly. - ASR/LLM/style-pack provider selection and the actual ASR/LLM API key credentials — both live in the Rust-managed preferences/ credential vault, not previously reachable from Android Kotlin at all. Two new synchronous JNI bridges (nativeExportPreferencesSubset/nativeImportPreferencesSubset, nativeExportCredentialsSnapshot/nativeImportCredentialsSnapshot) read/write these through the same PreferencesStore/CredentialsVault the running backend itself uses, rather than hand-parsing preferences.json from Kotlin. Export produces plain (unencrypted) JSON — an explicit product decision, since the whole point is painless device-to-device migration; the settings page's own export button carries a one-line warning that a Cloud notes token or (if selected) a raw API key ends up in the file in plaintext. Import shows a checkbox dialog scoped to whichever categories are actually present in the chosen file, and tells the user to fully restart OpenLess afterward if anything credential/provider-selection-related was restored (that data only takes effect once the backend next reads it from disk). New file: OpenLessSettingsExport.kt (collect-for-export / apply-for-import, no View dependencies, kept out of the already-large settings Activity). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
toggleDictation() no longer routes cloudNoteArmed to the Raw stop call
— only rawModeArmed still does. Cloud notes now goes through the same
plain (LLM-polished) stop as a normal commit; handleImeTextReady()
already just forwards whatever text arrives to submitCloudNoteText()
regardless of which pipeline produced it, so no change was needed
there. Updated the settings page's own description text to match
("原始转写"/"raw transcript" -> "整理后的文字"/"polished transcript").
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bring release/2.0.0-beta.3-20260925 onto the integration branch, including the macOS CI packaging work from #1107. Co-authored-by: TRIP <1933142963@qq.com>
…r cancel (#1110) The production change was already present in Beta 3. Keep the formatted test harness already on this branch. Co-authored-by: TRIP <1933142963@qq.com>
…eback (#1106) Keep Beta 3's ZIP integrity checks and research notes. Take the Linux egui CA fingerprint test helpers that Beta 3 left out. Co-authored-by: TRIP <1933142963@qq.com>
Co-authored-by: TRIP <1933142963@qq.com>
Keep both physical sides of a modifier chord. Beta 3 already records side-specific modifiers; modifier-only chords use chordModifiersFromPressedCodes so Ctrl+Ctrl is not collapsed to one side. Co-authored-by: TRIP <1933142963@qq.com>
…on (#1094) Co-authored-by: TRIP <1933142963@qq.com>
…on (#1066) Co-authored-by: TRIP <1933142963@qq.com>
…1067) Keep the iOS source note and link the Android IME architecture doc. Co-authored-by: TRIP <1933142963@qq.com>
Bring in the Linux egui host, packaging, and contract checks. Keep the current Beta desktop paths for hotkeys, streaming insertion, QA, and the selection polish preview. Refresh the workspace lockfile for the new Linux UI dependencies. Co-authored-by: TRIP <1933142963@qq.com>
Keep the lazy remote-metadata refresh already on Beta, and drop the duplicated mirror helpers introduced while combining the download source. Co-authored-by: TRIP <1933142963@qq.com>
Keep exact MiniMax host matching so unrelated custom endpoints stay on the transcriptions path, and retain the Requesty descriptor beside MiniMax. Co-authored-by: TRIP <1933142963@qq.com>
The Quick Note path, history retention, and hotkey supervisor were already present on this Beta. Keep those newer implementations, including encrypted-sync history writes and QA output targeting. Co-authored-by: TRIP <1933142963@qq.com>
… timing (#1074) Recording cues and the processing animation were already on this Beta. Keep Beta 3's macOS streaming insertion, which confirms delivery at the session barrier instead of waiting on AX after every chunk. Co-authored-by: TRIP <1933142963@qq.com>
…ed (#1073) The preview now fills the tool window through shared overlay styles. Keep the nonactivating panel mask and the session-scoped cancel path already on this Beta. Co-authored-by: TRIP <1933142963@qq.com>
…1064) Add the bundled PI computer backend, its protocol crate, and release checks. Linux packages include that backend when it has been prepared, and keep the current deb/rpm layout. Co-authored-by: TRIP <1933142963@qq.com>
…rent plugin The extra snapshot assertions need ContextSnapshot, which belongs to the older plugin rewrite and is not part of the parity host. Separate the Linux core and egui CI jobs. Co-authored-by: TRIP <1933142963@qq.com>
…ngs dialog (#1055) The parity host already carries the current Linux 2.0 interface, so the earlier token and settings-dialog slice is not mixed back into it. Co-authored-by: TRIP <1933142963@qq.com>
Document which open beta PRs landed and which older Linux UI slices stayed out. Refresh the workspace lockfile so openless-computer resolves with --locked, and write the Linux package script comments in English. Co-authored-by: TRIP <1933142963@qq.com>
Remove the duplicate HistorySource variant so openless-core compiles, route the selection polish preview window, and point Linux PI packaging at a shared resource path. Pin Cargo to stable and keep a single Linux CI job. Co-authored-by: TRIP <1933142963@qq.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
摘要
在新分支
cursor/beta-integrate-cleanup-77db上,从最新beta汇入 2.0 Beta 3,以及当时仍开放、且以beta为基线的用户 PR。没有改写beta或这些 PR 的原分支。随后跑了 Core、Linux 库、远程 TLS 和前端测试,并修掉会让这些测试无法开始的问题。修复 / 新增 / 改进
pi-backend、openless-computer)已进入工作区。Cargo.lock,使openless-computer可被--locked解析。HistorySource只保留一个QuickNote,否则openless-core无法编译。?window=selection-polish-preview渲染该页,能力表同时授权这个窗口和语音意图窗。resources/pi-backend。准备脚本仍写入 Tauri 资源目录,再链接到该路径。CI 只保留linux-egui-package。rust-toolchain.toml(stable)。去掉指向不存在的vendor/wayland-scanner的补丁,保留wry本地补丁。LC_ALL、LC_MESSAGES和LANG,避免宿主已有的LC_ALL盖过被测变量。兼容
src/i18n/。Tauri 宿主里的 Linuxcfg仍保留;支持的 Linux 产品是 egui,React 侧不再长出第二套 Linux 界面。stable。测试计划
cargo test --locked -p openless-core(Rust 1.98.1):17 个测试二进制,1211 通过,0 失败,1 忽略shared_hotkey_edges_own_hold_auto_and_combo_abort_semantics通过cargo test --locked -p openless-computer:11 通过cargo test --locked -p openless-linux-egui --lib:186 通过,1 忽略(需要真实 Wayland/X11 会话)cargo test --locked --manifest-path src-tauri/backend-tests/Cargo.toml --test remote_tls:10 通过npm run build后 107 个前端/合同测试通过,热键门禁单独通过