From efa1537049251ac3c2133a8d6872499dd0a463ba Mon Sep 17 00:00:00 2001 From: Cooper-X-Oak Date: Sat, 2 May 2026 01:32:34 +0800 Subject: [PATCH 1/2] =?UTF-8?q?docs(windows):=20=E5=8D=A0=E4=BD=8D?= =?UTF-8?q?=E6=89=BF=E6=8E=A5=20QA=20hotkey=20=E7=9B=91=E5=90=AC=E5=99=A8?= =?UTF-8?q?=E5=88=B7=E6=96=B0=E4=BF=AE=E5=A4=8D=20(#147)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From bcb00c60c18f80aede994df42e80470b9704c8c7 Mon Sep 17 00:00:00 2001 From: Cooper-X-Oak Date: Sat, 2 May 2026 06:01:56 +0800 Subject: [PATCH 2/2] fix(qa): refresh QA hotkey listener on settings writes --- openless-all/app/src-tauri/src/commands.rs | 106 ++++++++++++++++++++- 1 file changed, 102 insertions(+), 4 deletions(-) diff --git a/openless-all/app/src-tauri/src/commands.rs b/openless-all/app/src-tauri/src/commands.rs index d3497f30..f8ac06bc 100644 --- a/openless-all/app/src-tauri/src/commands.rs +++ b/openless-all/app/src-tauri/src/commands.rs @@ -24,11 +24,50 @@ pub fn get_settings(coord: CoordinatorState<'_>) -> UserPreferences { coord.prefs().get() } +trait SettingsWriter { + fn write_settings(&self, prefs: UserPreferences) -> Result<(), String>; + fn refresh_dictation_hotkey(&self); + fn refresh_qa_hotkey(&self); +} + +impl SettingsWriter for Coordinator { + fn write_settings(&self, prefs: UserPreferences) -> Result<(), String> { + self.prefs().set(prefs).map_err(|e| e.to_string()) + } + + fn refresh_dictation_hotkey(&self) { + self.update_hotkey_binding(); + } + + fn refresh_qa_hotkey(&self) { + self.update_qa_hotkey_binding(); + } +} + +impl SettingsWriter for Arc { + fn write_settings(&self, prefs: UserPreferences) -> Result<(), String> { + self.prefs().set(prefs).map_err(|e| e.to_string()) + } + + fn refresh_dictation_hotkey(&self) { + self.update_hotkey_binding(); + } + + fn refresh_qa_hotkey(&self) { + self.update_qa_hotkey_binding(); + } +} + +fn persist_settings(coord: &T, prefs: UserPreferences) -> Result<(), String> { + coord.write_settings(prefs)?; + coord.refresh_dictation_hotkey(); + coord.refresh_qa_hotkey(); + Ok(()) +} + #[tauri::command] pub fn set_settings(coord: CoordinatorState<'_>, prefs: UserPreferences) -> Result<(), String> { - coord.prefs().set(prefs).map_err(|e| e.to_string())?; - coord.update_hotkey_binding(); - Ok(()) + persist_settings(&*coord, prefs) } #[tauri::command] @@ -484,7 +523,33 @@ fn _ensure_snapshot_used(_: CredentialsSnapshot) {} #[cfg(test)] mod tests { - use super::{models_url, parse_model_ids}; + use super::{models_url, parse_model_ids, persist_settings, SettingsWriter}; + use crate::types::{ + HotkeyBinding, HotkeyMode, HotkeyTrigger, QaHotkeyBinding, UserPreferences, + }; + use std::sync::Mutex; + + #[derive(Default)] + struct FakeSettingsWriter { + saved: Mutex>, + dictation_refreshes: Mutex, + qa_refreshes: Mutex, + } + + impl SettingsWriter for FakeSettingsWriter { + fn write_settings(&self, prefs: UserPreferences) -> Result<(), String> { + *self.saved.lock().unwrap() = Some(prefs); + Ok(()) + } + + fn refresh_dictation_hotkey(&self) { + *self.dictation_refreshes.lock().unwrap() += 1; + } + + fn refresh_qa_hotkey(&self) { + *self.qa_refreshes.lock().unwrap() += 1; + } + } #[test] fn models_url_accepts_base_or_chat_endpoint() { @@ -505,4 +570,37 @@ mod tests { .unwrap(); assert_eq!(models, vec!["a".to_string(), "b".to_string()]); } + + #[test] + fn persist_settings_refreshes_both_hotkey_pipelines() { + let writer = FakeSettingsWriter::default(); + let prefs = UserPreferences { + hotkey: HotkeyBinding { + trigger: HotkeyTrigger::RightControl, + mode: HotkeyMode::Toggle, + }, + qa_hotkey: Some(QaHotkeyBinding { + primary: ";".to_string(), + modifiers: vec!["ctrl".to_string(), "shift".to_string()], + }), + ..Default::default() + }; + + persist_settings(&writer, prefs.clone()).unwrap(); + + let saved = writer + .saved + .lock() + .unwrap() + .clone() + .expect("settings saved"); + assert_eq!(saved.hotkey.trigger, prefs.hotkey.trigger); + assert_eq!(saved.hotkey.mode, prefs.hotkey.mode); + assert_eq!( + saved.qa_hotkey.unwrap().primary, + prefs.qa_hotkey.unwrap().primary + ); + assert_eq!(*writer.dictation_refreshes.lock().unwrap(), 1); + assert_eq!(*writer.qa_refreshes.lock().unwrap(), 1); + } }