Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 10 additions & 130 deletions src-tauri/src/commands/native_voice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ use tokio::sync::mpsc as tokio_mpsc;

use super::mac_speech;
use super::{
native_input_mute, pocket_voice::parakeet_model_dir, voice_buddy,
voice_capture::VoiceCaptureState,
native_input_mute, pocket_voice::parakeet_model_dir, voice_capture::VoiceCaptureState,
};

pub(crate) const EVENT_NAME: &str = "voice-conversation:event";
Expand Down Expand Up @@ -1672,7 +1671,7 @@ pub async fn stop_native_voice_conversation_for_replacement(
Ok(status(&app, &state).await)
}

fn replacement_caller_matches_target(
fn caller_owns_target(
caller_window_label: &str,
target_owner: Option<&str>,
owns_foreground_session: bool,
Expand All @@ -1686,53 +1685,6 @@ fn replacement_caller_matches_target(
}
}

fn voice_target_window_focus_is_valid(
window_label: &str,
focused: bool,
app_is_active: bool,
main_surface_is_available: bool,
another_window_is_focused: bool,
) -> bool {
focused
|| (window_label == "main"
&& app_is_active
&& main_surface_is_available
&& !another_window_is_focused)
}

fn voice_main_surface_is_available(visible: bool, minimized: bool) -> bool {
visible && !minimized
}

#[cfg(target_os = "macos")]
fn app_is_active_for_main_window_focus_fallback() -> bool {
use objc2_app_kit::NSRunningApplication;

// The non-activating floating controls can leave Berd frontmost while
// AppKit reports that none of its ordinary windows are focused.
NSRunningApplication::currentApplication().isActive()
}

#[cfg(not(target_os = "macos"))]
fn app_is_active_for_main_window_focus_fallback() -> bool {
false
}

fn another_user_window_is_focused(webview_window: &WebviewWindow) -> Result<bool, String> {
for (label, window) in webview_window.app_handle().webview_windows() {
if label == webview_window.label() || label == voice_buddy::WINDOW_LABEL {
continue;
}
if window
.is_focused()
.map_err(|error| format!("Could not confirm Berd window focus: {error}"))?
{
return Ok(true);
}
}
Ok(false)
}

fn validate_voice_target_session(
capture: &VoiceCaptureState,
window_sessions: &super::window_session::WindowSessionRegistry,
Expand All @@ -1750,41 +1702,13 @@ fn validate_voice_target_session(
target_session_id,
foreground_generation,
)?;
if !replacement_caller_matches_target(
if !caller_owns_target(
webview_window.label(),
target_owner.as_deref(),
owns_foreground_session,
) {
return Err("The target session is no longer in the foreground.".to_string());
}
let focused = webview_window
.is_focused()
.map_err(|error| format!("Could not confirm the target session window focus: {error}"))?;
let app_is_active = !focused
&& webview_window.label() == "main"
&& app_is_active_for_main_window_focus_fallback();
let main_surface_is_available = if app_is_active {
let visible = webview_window
.is_visible()
.map_err(|error| format!("Could not confirm the main window visibility: {error}"))?;
let minimized = webview_window
.is_minimized()
.map_err(|error| format!("Could not confirm the main window state: {error}"))?;
voice_main_surface_is_available(visible, minimized)
} else {
false
};
let another_window_is_focused =
main_surface_is_available && another_user_window_is_focused(webview_window)?;
if !voice_target_window_focus_is_valid(
webview_window.label(),
focused,
app_is_active,
main_surface_is_available,
another_window_is_focused,
) {
return Err("The target session window is no longer focused.".to_string());
}
Ok(())
}

Expand Down Expand Up @@ -2965,65 +2889,21 @@ mod tests {
}

#[test]
fn replacement_stop_requires_the_target_session_window() {
assert!(replacement_caller_matches_target("main", None, true));
assert!(!replacement_caller_matches_target("main", None, false));
assert!(!replacement_caller_matches_target(
"main",
Some("session:target"),
true,
));
assert!(replacement_caller_matches_target(
fn call_target_ownership_survives_focus_changes_and_rejects_other_windows() {
assert!(caller_owns_target("main", None, true));
assert!(!caller_owns_target("main", None, false));
assert!(!caller_owns_target("main", Some("session:target"), true));
assert!(caller_owns_target(
"session:target",
Some("session:target"),
true,
));
assert!(!replacement_caller_matches_target(
assert!(!caller_owns_target(
"session:other",
Some("session:target"),
true,
));
assert!(!replacement_caller_matches_target(
"voice-buddy",
None,
true,
));
}

#[test]
fn replacement_focus_accepts_an_active_app_only_for_the_main_window() {
assert!(voice_main_surface_is_available(true, false));
assert!(!voice_main_surface_is_available(false, false));
assert!(!voice_main_surface_is_available(true, true));
assert!(voice_target_window_focus_is_valid(
"main", true, false, false, false,
));
assert!(voice_target_window_focus_is_valid(
"main", false, true, true, false,
));
assert!(!voice_target_window_focus_is_valid(
"main", false, true, true, true,
));
assert!(!voice_target_window_focus_is_valid(
"main", false, true, false, false,
));
assert!(!voice_target_window_focus_is_valid(
"main", false, false, true, false,
));
assert!(voice_target_window_focus_is_valid(
"session:target",
true,
false,
false,
false,
));
assert!(!voice_target_window_focus_is_valid(
"session:target",
false,
true,
true,
false,
));
assert!(!caller_owns_target("voice-buddy", None, true));
}

#[test]
Expand Down
Loading