feat(tray): add cancel recording/transcribing actions
This commit is contained in:
parent
e92f94573e
commit
6c26d6afb8
3 changed files with 108 additions and 0 deletions
|
|
@ -122,6 +122,25 @@ pub fn run() {
|
||||||
"check_updates" => {
|
"check_updates" => {
|
||||||
let _ = app.emit("check-for-updates", ());
|
let _ = app.emit("check-for-updates", ());
|
||||||
}
|
}
|
||||||
|
"cancel_listening" => {
|
||||||
|
use crate::utils::{change_tray_icon, TrayIconState};
|
||||||
|
use crate::managers::audio::AudioRecordingManager;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
// Cancel the recording without transcribing
|
||||||
|
let rm = app.state::<Arc<AudioRecordingManager>>();
|
||||||
|
rm.cancel_recording();
|
||||||
|
|
||||||
|
// Return to idle state
|
||||||
|
change_tray_icon(app, TrayIconState::Idle);
|
||||||
|
}
|
||||||
|
"cancel_transcribing" => {
|
||||||
|
use crate::utils::{change_tray_icon, TrayIconState};
|
||||||
|
|
||||||
|
// For now, just return to idle state
|
||||||
|
// TODO: In a future version, we could add actual request cancellation
|
||||||
|
change_tray_icon(app, TrayIconState::Idle);
|
||||||
|
}
|
||||||
"quit" => {
|
"quit" => {
|
||||||
app.exit(0);
|
app.exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -258,4 +258,25 @@ impl AudioRecordingManager {
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cancel any ongoing recording without returning audio samples
|
||||||
|
pub fn cancel_recording(&self) {
|
||||||
|
let mut state = self.state.lock().unwrap();
|
||||||
|
|
||||||
|
if let RecordingState::Recording { .. } = *state {
|
||||||
|
*state = RecordingState::Idle;
|
||||||
|
drop(state);
|
||||||
|
|
||||||
|
if let Some(rec) = self.recorder.lock().unwrap().as_ref() {
|
||||||
|
let _ = rec.stop(); // Discard the result
|
||||||
|
}
|
||||||
|
|
||||||
|
*self.is_recording.lock().unwrap() = false;
|
||||||
|
|
||||||
|
// In on-demand mode turn the mic off again
|
||||||
|
if matches!(*self.mode.lock().unwrap(), MicrophoneMode::OnDemand) {
|
||||||
|
self.stop_microphone_stream();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use tauri::image::Image;
|
||||||
use tauri::tray::TrayIcon;
|
use tauri::tray::TrayIcon;
|
||||||
use tauri::AppHandle;
|
use tauri::AppHandle;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
use tauri::menu::{Menu, MenuItem, PredefinedMenuItem};
|
||||||
use tauri_plugin_clipboard_manager::ClipboardExt;
|
use tauri_plugin_clipboard_manager::ClipboardExt;
|
||||||
|
|
||||||
fn send_paste() -> Result<(), String> {
|
fn send_paste() -> Result<(), String> {
|
||||||
|
|
@ -70,6 +71,7 @@ pub fn paste(text: String, app_handle: AppHandle) -> Result<(), String> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum TrayIconState {
|
pub enum TrayIconState {
|
||||||
Idle,
|
Idle,
|
||||||
Recording,
|
Recording,
|
||||||
|
|
@ -93,6 +95,72 @@ pub fn change_tray_icon(app: &AppHandle, icon: TrayIconState) {
|
||||||
)
|
)
|
||||||
.expect("failed to set icon"),
|
.expect("failed to set icon"),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Update menu based on state
|
||||||
|
update_tray_menu(app, &icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_tray_menu(app: &AppHandle, state: &TrayIconState) {
|
||||||
|
let version = env!("CARGO_PKG_VERSION");
|
||||||
|
let version_label = format!("Handy v{}", version);
|
||||||
|
|
||||||
|
// Platform-specific accelerators
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let settings_accelerator = Some("Cmd+,");
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let settings_accelerator = Some("Ctrl+,");
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
let quit_accelerator = Some("Cmd+Q");
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let quit_accelerator = Some("Ctrl+Q");
|
||||||
|
|
||||||
|
let version_i = MenuItem::with_id(app, "version", &version_label, false, None::<&str>).expect("failed to create version item");
|
||||||
|
let settings_i = MenuItem::with_id(app, "settings", "Settings...", true, settings_accelerator).expect("failed to create settings item");
|
||||||
|
let check_updates_i = MenuItem::with_id(app, "check_updates", "Check for Updates...", true, None::<&str>).expect("failed to create check updates item");
|
||||||
|
let quit_i = MenuItem::with_id(app, "quit", "Quit", true, quit_accelerator).expect("failed to create quit item");
|
||||||
|
|
||||||
|
let menu = match state {
|
||||||
|
TrayIconState::Recording => {
|
||||||
|
let cancel_i = MenuItem::with_id(app, "cancel_listening", "Cancel Listening", true, None::<&str>).expect("failed to create cancel listening item");
|
||||||
|
Menu::with_items(app, &[
|
||||||
|
&version_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&cancel_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&settings_i,
|
||||||
|
&check_updates_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&quit_i,
|
||||||
|
]).expect("failed to create menu")
|
||||||
|
}
|
||||||
|
TrayIconState::Transcribing => {
|
||||||
|
let cancel_i = MenuItem::with_id(app, "cancel_transcribing", "Cancel Transcribing", true, None::<&str>).expect("failed to create cancel transcribing item");
|
||||||
|
Menu::with_items(app, &[
|
||||||
|
&version_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&cancel_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&settings_i,
|
||||||
|
&check_updates_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&quit_i,
|
||||||
|
]).expect("failed to create menu")
|
||||||
|
}
|
||||||
|
TrayIconState::Idle => {
|
||||||
|
Menu::with_items(app, &[
|
||||||
|
&version_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&settings_i,
|
||||||
|
&check_updates_i,
|
||||||
|
&PredefinedMenuItem::separator(app).expect("failed to create separator"),
|
||||||
|
&quit_i,
|
||||||
|
]).expect("failed to create menu")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let tray = app.state::<TrayIcon>();
|
||||||
|
let _ = tray.set_menu(Some(menu));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Plays an audio resource from the resources directory.
|
/// Plays an audio resource from the resources directory.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue