Handy/src-tauri/src/utils.rs
johnpyp 7fdde63460
fix: transcription lock-up race condition & add small debounce (#824)
* fix: add TranscriptionState to prevent race conditions & add debounce

* refactor(transcription): replace state machine with actor coordinator

* some cleanup

* format

* minor cleanup

* format

---------

Co-authored-by: CJ Pais <cj@cjpais.com>
2026-02-16 22:18:50 +08:00

66 lines
2.2 KiB
Rust

use crate::managers::audio::AudioRecordingManager;
use crate::managers::transcription::TranscriptionManager;
use crate::shortcut;
use crate::TranscriptionCoordinator;
use log::info;
use std::sync::Arc;
use tauri::{AppHandle, Manager};
// Re-export all utility modules for easy access
// pub use crate::audio_feedback::*;
pub use crate::clipboard::*;
pub use crate::overlay::*;
pub use crate::tray::*;
/// 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) {
info!("Initiating operation cancellation...");
// Unregister the cancel shortcut asynchronously
shortcut::unregister_cancel_shortcut(app);
// Cancel any ongoing recording
let audio_manager = app.state::<Arc<AudioRecordingManager>>();
let recording_was_active = audio_manager.is_recording();
audio_manager.cancel_recording();
// Update tray icon and hide overlay
change_tray_icon(app, crate::tray::TrayIconState::Idle);
hide_recording_overlay(app);
// Unload model if immediate unload is enabled
let tm = app.state::<Arc<TranscriptionManager>>();
tm.maybe_unload_immediately("cancellation");
// Notify coordinator so it can keep lifecycle state coherent.
if let Some(coordinator) = app.try_state::<TranscriptionCoordinator>() {
coordinator.notify_cancel(recording_was_active);
}
info!("Operation cancellation completed - returned to idle state");
}
/// Check if using the Wayland display server protocol
#[cfg(target_os = "linux")]
pub fn is_wayland() -> bool {
std::env::var("WAYLAND_DISPLAY").is_ok()
|| std::env::var("XDG_SESSION_TYPE")
.map(|v| v.to_lowercase() == "wayland")
.unwrap_or(false)
}
/// Check if running on KDE Plasma desktop environment
#[cfg(target_os = "linux")]
pub fn is_kde_plasma() -> bool {
std::env::var("XDG_CURRENT_DESKTOP")
.map(|v| v.to_uppercase().contains("KDE"))
.unwrap_or(false)
|| std::env::var("KDE_SESSION_VERSION").is_ok()
}
/// Check if running on KDE Plasma with Wayland
#[cfg(target_os = "linux")]
pub fn is_kde_wayland() -> bool {
is_wayland() && is_kde_plasma()
}