use crate::settings; use crate::settings::OverlayPosition; use log::debug; use tauri::{AppHandle, Emitter, Manager, WebviewWindowBuilder}; const OVERLAY_WIDTH: f64 = 172.0; const OVERLAY_HEIGHT: f64 = 36.0; const OVERLAY_TOP_OFFSET: f64 = 46.0; const OVERLAY_BOTTOM_OFFSET: f64 = 15.0; fn calculate_overlay_position(app_handle: &AppHandle) -> Option<(f64, f64)> { if let Ok(monitors) = app_handle.primary_monitor() { if let Some(monitor) = monitors { let work_area = monitor.work_area(); let scale = monitor.scale_factor(); let work_area_width = work_area.size.width as f64 / scale; let work_area_height = work_area.size.height as f64 / scale; let work_area_x = work_area.position.x as f64 / scale; let work_area_y = work_area.position.y as f64 / scale; let settings = settings::get_settings(app_handle); let x = work_area_x + (work_area_width - OVERLAY_WIDTH) / 2.0; let y = match settings.overlay_position { OverlayPosition::Top => work_area_y + OVERLAY_TOP_OFFSET, OverlayPosition::Bottom | OverlayPosition::None => { // don't subtract the overlay height it puts it too far up work_area_y + work_area_height - OVERLAY_BOTTOM_OFFSET } }; return Some((x, y)); } } None } /// Creates the recording overlay window and keeps it hidden by default pub fn create_recording_overlay(app_handle: &AppHandle) { if let Some((x, y)) = calculate_overlay_position(app_handle) { match WebviewWindowBuilder::new( app_handle, "recording_overlay", tauri::WebviewUrl::App("src/overlay/index.html".into()), ) .title("Recording") .position(x, y) .resizable(false) .inner_size(OVERLAY_WIDTH, OVERLAY_HEIGHT) .shadow(false) .maximizable(false) .minimizable(false) .closable(false) .accept_first_mouse(true) .decorations(false) .always_on_top(true) .skip_taskbar(true) .transparent(true) .focused(false) .visible(false) .build() { Ok(_window) => { debug!("Recording overlay window created successfully (hidden)"); } Err(e) => { debug!("Failed to create recording overlay window: {}", e); } } } } /// Shows the recording overlay window with fade-in animation pub fn show_recording_overlay(app_handle: &AppHandle) { // Check if overlay should be shown based on position setting let settings = settings::get_settings(app_handle); if settings.overlay_position == OverlayPosition::None { return; } if let Some(overlay_window) = app_handle.get_webview_window("recording_overlay") { let _ = overlay_window.show(); // Emit event to trigger fade-in animation with recording state let _ = overlay_window.emit("show-overlay", "recording"); } } /// Shows the transcribing overlay window pub fn show_transcribing_overlay(app_handle: &AppHandle) { // Check if overlay should be shown based on position setting let settings = settings::get_settings(app_handle); if settings.overlay_position == OverlayPosition::None { return; } if let Some(overlay_window) = app_handle.get_webview_window("recording_overlay") { let _ = overlay_window.show(); // Emit event to switch to transcribing state let _ = overlay_window.emit("show-overlay", "transcribing"); } } /// Updates the overlay window position based on current settings pub fn update_overlay_position(app_handle: &AppHandle) { if let Some(overlay_window) = app_handle.get_webview_window("recording_overlay") { if let Some((x, y)) = calculate_overlay_position(app_handle) { let _ = overlay_window .set_position(tauri::Position::Logical(tauri::LogicalPosition { x, y })); } } } /// Hides the recording overlay window with fade-out animation pub fn hide_recording_overlay(app_handle: &AppHandle) { // Always hide the overlay regardless of settings - if setting was changed while recording, // we still want to hide it properly if let Some(overlay_window) = app_handle.get_webview_window("recording_overlay") { // Emit event to trigger fade-out animation let _ = overlay_window.emit("hide-overlay", ()); // Hide the window after a short delay to allow animation to complete let window_clone = overlay_window.clone(); std::thread::spawn(move || { std::thread::sleep(std::time::Duration::from_millis(300)); let _ = window_clone.hide(); }); } } pub fn emit_levels(app_handle: &AppHandle, levels: &Vec) { // emit levels to main app let _ = app_handle.emit("mic-level", levels); // also emit to the recording overlay if it's open if let Some(overlay_window) = app_handle.get_webview_window("recording_overlay") { let _ = overlay_window.emit("mic-level", levels); } }