diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 74472b7d6..e5eac55ca 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -228,11 +228,15 @@ fn initialize_core_logic(app_handle: &AppHandle) { Err(e) => log::error!("Failed to unload model via tray: {}", e), } } + "transcribe" => { + utils::send_transcription_input(app, "transcribe", "tray"); + } + "stop" => { + utils::send_transcription_input(app, "transcribe", "tray"); + } "cancel" => { - use crate::utils::cancel_current_operation; - // Use centralized cancellation that handles all operations - cancel_current_operation(app); + utils::cancel_current_operation(app); } "quit" => { app.exit(0); @@ -481,9 +485,9 @@ pub fn run(cli_args: CliArgs) { builder .plugin(tauri_plugin_single_instance::init(|app, args, _cwd| { if args.iter().any(|a| a == "--toggle-transcription") { - signal_handle::send_transcription_input(app, "transcribe", "CLI"); + utils::send_transcription_input(app, "transcribe", "CLI"); } else if args.iter().any(|a| a == "--toggle-post-process") { - signal_handle::send_transcription_input(app, "transcribe_with_post_process", "CLI"); + utils::send_transcription_input(app, "transcribe_with_post_process", "CLI"); } else if args.iter().any(|a| a == "--cancel") { crate::utils::cancel_current_operation(app); } else { diff --git a/src-tauri/src/signal_handle.rs b/src-tauri/src/signal_handle.rs index 1f54c0d96..9bf6ae5ee 100644 --- a/src-tauri/src/signal_handle.rs +++ b/src-tauri/src/signal_handle.rs @@ -1,8 +1,7 @@ -use crate::TranscriptionCoordinator; +use crate::utils::send_transcription_input; #[cfg(unix)] use log::debug; -use log::warn; -use tauri::{AppHandle, Manager}; +use tauri::AppHandle; #[cfg(unix)] use signal_hook::consts::{SIGUSR1, SIGUSR2}; @@ -11,16 +10,6 @@ use signal_hook::iterator::Signals; #[cfg(unix)] use std::thread; -/// Send a transcription input to the coordinator. -/// Used by signal handlers, CLI flags, and any other external trigger. -pub fn send_transcription_input(app: &AppHandle, binding_id: &str, source: &str) { - if let Some(c) = app.try_state::() { - c.send_input(binding_id, source, true, false); - } else { - warn!("TranscriptionCoordinator not initialized"); - } -} - #[cfg(unix)] pub fn setup_signal_handler(app_handle: AppHandle, mut signals: Signals) { debug!("Signal handlers registered (SIGUSR1, SIGUSR2)"); diff --git a/src-tauri/src/tray.rs b/src-tauri/src/tray.rs index 39cfcb008..fcfc0fa7d 100644 --- a/src-tauri/src/tray.rs +++ b/src-tauri/src/tray.rs @@ -171,6 +171,8 @@ pub fn update_tray_menu(app: &AppHandle, state: &TrayIconState, locale: Option<& let menu = match state { TrayIconState::Recording | TrayIconState::Transcribing => { + let stop_i = MenuItem::with_id(app, "stop", &strings.stop, true, None::<&str>) + .expect("failed to create stop item"); let cancel_i = MenuItem::with_id(app, "cancel", &strings.cancel, true, None::<&str>) .expect("failed to create cancel item"); Menu::with_items( @@ -178,6 +180,7 @@ pub fn update_tray_menu(app: &AppHandle, state: &TrayIconState, locale: Option<& &[ &version_i, &separator(), + &stop_i, &cancel_i, &separator(), ©_last_transcript_i, @@ -190,23 +193,30 @@ pub fn update_tray_menu(app: &AppHandle, state: &TrayIconState, locale: Option<& ) .expect("failed to create menu") } - TrayIconState::Idle => Menu::with_items( - app, - &[ - &version_i, - &separator(), - ©_last_transcript_i, - &separator(), - &model_submenu, - &unload_model_i, - &separator(), - &settings_i, - &check_updates_i, - &separator(), - &quit_i, - ], - ) - .expect("failed to create menu"), + TrayIconState::Idle => { + let transcribe_i = + MenuItem::with_id(app, "transcribe", &strings.transcribe, true, None::<&str>) + .expect("failed to create transcribe item"); + Menu::with_items( + app, + &[ + &version_i, + &separator(), + &transcribe_i, + &separator(), + ©_last_transcript_i, + &separator(), + &model_submenu, + &unload_model_i, + &separator(), + &settings_i, + &check_updates_i, + &separator(), + &quit_i, + ], + ) + .expect("failed to create menu") + } }; let tray = app.state::(); diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 063e4b314..c2ccb03e3 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -2,7 +2,7 @@ use crate::managers::audio::AudioRecordingManager; use crate::managers::transcription::TranscriptionManager; use crate::shortcut; use crate::TranscriptionCoordinator; -use log::info; +use log::{info, warn}; use std::sync::Arc; use tauri::{AppHandle, Manager}; @@ -12,6 +12,16 @@ pub use crate::clipboard::*; pub use crate::overlay::*; pub use crate::tray::*; +/// Send a transcription input to the coordinator. +/// Used by signal handlers, CLI flags, tray menu, and any other external trigger. +pub fn send_transcription_input(app: &AppHandle, binding_id: &str, source: &str) { + if let Some(c) = app.try_state::() { + c.send_input(binding_id, source, true, false); + } else { + warn!("TranscriptionCoordinator not initialized"); + } +} + /// Centralized cancellation function that can be called from anywhere in the app. /// Handles cancelling both recording and transcription operations and updates UI state. pub fn cancel_current_operation(app: &AppHandle) { diff --git a/src/i18n/locales/ar/translation.json b/src/i18n/locales/ar/translation.json index feb641e57..b1ed4cc54 100644 --- a/src/i18n/locales/ar/translation.json +++ b/src/i18n/locales/ar/translation.json @@ -6,7 +6,9 @@ "unloadModel": "تفريغ النموذج", "model": "النموذج", "quit": "إنهاء", - "cancel": "إلغاء" + "cancel": "إلغاء", + "transcribe": "نسخ صوتي", + "stop": "إيقاف" }, "sidebar": { "general": "عام", diff --git a/src/i18n/locales/bg/translation.json b/src/i18n/locales/bg/translation.json index 10d638934..2b9f4b728 100644 --- a/src/i18n/locales/bg/translation.json +++ b/src/i18n/locales/bg/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Разтоварване на модела", "model": "Модел", "quit": "Изход", - "cancel": "Отказ" + "cancel": "Отказ", + "transcribe": "Транскрипция", + "stop": "Спри" }, "sidebar": { "general": "Общи", diff --git a/src/i18n/locales/cs/translation.json b/src/i18n/locales/cs/translation.json index d73a3c6ca..af367b54a 100644 --- a/src/i18n/locales/cs/translation.json +++ b/src/i18n/locales/cs/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Uvolnit model", "model": "Model", "quit": "Ukončit", - "cancel": "Zrušit" + "cancel": "Zrušit", + "transcribe": "Přepsat", + "stop": "Zastavit" }, "sidebar": { "general": "Obecné", diff --git a/src/i18n/locales/de/translation.json b/src/i18n/locales/de/translation.json index 1f5acddde..e518c4591 100644 --- a/src/i18n/locales/de/translation.json +++ b/src/i18n/locales/de/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Modell entladen", "model": "Modell", "quit": "Beenden", - "cancel": "Abbrechen" + "cancel": "Abbrechen", + "transcribe": "Transkribieren", + "stop": "Stopp" }, "sidebar": { "general": "Allgemein", diff --git a/src/i18n/locales/en/translation.json b/src/i18n/locales/en/translation.json index 775e33cd0..564485f12 100644 --- a/src/i18n/locales/en/translation.json +++ b/src/i18n/locales/en/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Unload Model", "model": "Model", "quit": "Quit", - "cancel": "Cancel" + "cancel": "Cancel", + "transcribe": "Transcribe", + "stop": "Stop" }, "sidebar": { "general": "General", diff --git a/src/i18n/locales/es/translation.json b/src/i18n/locales/es/translation.json index ac3c7dbf6..d7388bb60 100644 --- a/src/i18n/locales/es/translation.json +++ b/src/i18n/locales/es/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Descargar modelo", "model": "Modelo", "quit": "Salir", - "cancel": "Cancelar" + "cancel": "Cancelar", + "transcribe": "Transcribir", + "stop": "Detener" }, "sidebar": { "general": "General", diff --git a/src/i18n/locales/fr/translation.json b/src/i18n/locales/fr/translation.json index 58c13b4ef..d7f55423c 100644 --- a/src/i18n/locales/fr/translation.json +++ b/src/i18n/locales/fr/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Décharger le modèle", "model": "Modèle", "quit": "Quitter", - "cancel": "Annuler" + "cancel": "Annuler", + "transcribe": "Transcrire", + "stop": "Arrêter" }, "sidebar": { "general": "Général", diff --git a/src/i18n/locales/it/translation.json b/src/i18n/locales/it/translation.json index c1fb10ec5..7b2d3d168 100644 --- a/src/i18n/locales/it/translation.json +++ b/src/i18n/locales/it/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Rilascia modello", "model": "Modello", "quit": "Esci", - "cancel": "Annulla" + "cancel": "Annulla", + "transcribe": "Trascrivi", + "stop": "Ferma" }, "sidebar": { "general": "Generale", diff --git a/src/i18n/locales/ja/translation.json b/src/i18n/locales/ja/translation.json index 7aa003ad9..012a5e7d5 100644 --- a/src/i18n/locales/ja/translation.json +++ b/src/i18n/locales/ja/translation.json @@ -6,7 +6,9 @@ "unloadModel": "モデルをアンロード", "model": "モデル", "quit": "終了", - "cancel": "キャンセル" + "cancel": "キャンセル", + "transcribe": "文字起こし", + "stop": "停止" }, "sidebar": { "general": "一般", diff --git a/src/i18n/locales/ko/translation.json b/src/i18n/locales/ko/translation.json index b8b2bf227..8a3157dc8 100644 --- a/src/i18n/locales/ko/translation.json +++ b/src/i18n/locales/ko/translation.json @@ -6,7 +6,9 @@ "unloadModel": "모델 언로드", "model": "모델", "quit": "종료", - "cancel": "취소" + "cancel": "취소", + "transcribe": "받아쓰기", + "stop": "중지" }, "sidebar": { "general": "일반", diff --git a/src/i18n/locales/pl/translation.json b/src/i18n/locales/pl/translation.json index c90e0b7b9..f23b66cd6 100644 --- a/src/i18n/locales/pl/translation.json +++ b/src/i18n/locales/pl/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Zwolnij model", "model": "Model", "quit": "Zamknij", - "cancel": "Anuluj" + "cancel": "Anuluj", + "transcribe": "Transkrybuj", + "stop": "Zatrzymaj" }, "sidebar": { "general": "Ogólne", diff --git a/src/i18n/locales/pt/translation.json b/src/i18n/locales/pt/translation.json index 00c330828..e7c9b5f05 100644 --- a/src/i18n/locales/pt/translation.json +++ b/src/i18n/locales/pt/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Descarregar modelo", "model": "Modelo", "quit": "Sair", - "cancel": "Cancelar" + "cancel": "Cancelar", + "transcribe": "Transcrever", + "stop": "Parar" }, "sidebar": { "general": "Geral", diff --git a/src/i18n/locales/ru/translation.json b/src/i18n/locales/ru/translation.json index 359904bee..bdc846c93 100644 --- a/src/i18n/locales/ru/translation.json +++ b/src/i18n/locales/ru/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Выгрузить модель", "model": "Модель", "quit": "Выход", - "cancel": "Отмена" + "cancel": "Отмена", + "transcribe": "Транскрибировать", + "stop": "Остановить" }, "sidebar": { "general": "Общие", diff --git a/src/i18n/locales/sv/translation.json b/src/i18n/locales/sv/translation.json index 413143d35..f383cca00 100644 --- a/src/i18n/locales/sv/translation.json +++ b/src/i18n/locales/sv/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Avlasta modell", "model": "Modell", "quit": "Avsluta", - "cancel": "Avbryt" + "cancel": "Avbryt", + "transcribe": "Transkribera", + "stop": "Stoppa" }, "sidebar": { "general": "Allmänt", diff --git a/src/i18n/locales/tr/translation.json b/src/i18n/locales/tr/translation.json index 5973d230f..5445dc41a 100644 --- a/src/i18n/locales/tr/translation.json +++ b/src/i18n/locales/tr/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Modeli boşalt", "model": "Model", "quit": "Çıkış", - "cancel": "İptal" + "cancel": "İptal", + "transcribe": "Transkribe et", + "stop": "Durdur" }, "sidebar": { "general": "Genel", diff --git a/src/i18n/locales/uk/translation.json b/src/i18n/locales/uk/translation.json index 6c56dab21..badaf42f5 100644 --- a/src/i18n/locales/uk/translation.json +++ b/src/i18n/locales/uk/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Вивантажити модель", "model": "Модель", "quit": "Вийти", - "cancel": "Скасувати" + "cancel": "Скасувати", + "transcribe": "Транскрибувати", + "stop": "Зупинити" }, "sidebar": { "general": "Загальні", diff --git a/src/i18n/locales/vi/translation.json b/src/i18n/locales/vi/translation.json index 87c4d16d7..164b55536 100644 --- a/src/i18n/locales/vi/translation.json +++ b/src/i18n/locales/vi/translation.json @@ -6,7 +6,9 @@ "unloadModel": "Dỡ mô hình", "model": "Mô hình", "quit": "Thoát", - "cancel": "Hủy" + "cancel": "Hủy", + "transcribe": "Phiên âm", + "stop": "Dừng" }, "sidebar": { "general": "Chung", diff --git a/src/i18n/locales/zh-TW/translation.json b/src/i18n/locales/zh-TW/translation.json index bc95dfc44..a2bf8e4b3 100644 --- a/src/i18n/locales/zh-TW/translation.json +++ b/src/i18n/locales/zh-TW/translation.json @@ -6,7 +6,9 @@ "unloadModel": "卸載模型", "model": "模型", "quit": "結束", - "cancel": "取消" + "cancel": "取消", + "transcribe": "轉錄", + "stop": "停止" }, "sidebar": { "general": "一般", diff --git a/src/i18n/locales/zh/translation.json b/src/i18n/locales/zh/translation.json index 52305689f..bb03537cb 100644 --- a/src/i18n/locales/zh/translation.json +++ b/src/i18n/locales/zh/translation.json @@ -6,7 +6,9 @@ "unloadModel": "卸载模型", "model": "模型", "quit": "退出", - "cancel": "取消" + "cancel": "取消", + "transcribe": "转录", + "stop": "停止" }, "sidebar": { "general": "通用",