Skip to content
Open
Show file tree
Hide file tree
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
23 changes: 22 additions & 1 deletion apps/desktop/src-tauri/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use sqlx::sqlite::SqlitePoolOptions;
use tauri::{Manager, WindowEvent};

const AUTOSTART_HIDDEN_ARG: &str = "--voquill-autostart-hidden";
pub(crate) const SURFACE_AFTER_UPDATE_FLAG: &str = "surface-after-update";

pub fn build() -> tauri::Builder<tauri::Wry> {
let updater_builder = tauri_plugin_updater::Builder::new();
Expand Down Expand Up @@ -47,6 +48,23 @@ pub fn build() -> tauri::Builder<tauri::Wry> {
// Write startup diagnostics for debugging
crate::system::diagnostics::write_startup_diagnostics(app.handle());

// Check if a previous update left the surface-after-update flag.
// On Windows, the NSIS installer relaunches the app with the original
// command-line args (including --voquill-autostart-hidden if the app
// was auto-started). The flag tells us to show the window anyway.
let should_surface_after_update = {
let mut result = false;
if let Ok(config_dir) = app.path().app_config_dir() {
let flag_file = config_dir.join(SURFACE_AFTER_UPDATE_FLAG);
if flag_file.exists() {
eprintln!("[app] Detected post-update launch, will surface window");
let _ = std::fs::remove_file(&flag_file);
result = true;
}
}
result
};

let db_url = {
let handle = app.handle();
crate::system::paths::database_url(&handle)
Expand All @@ -67,7 +85,9 @@ pub fn build() -> tauri::Builder<tauri::Wry> {

#[cfg(desktop)]
{
if std::env::args().any(|arg| arg == AUTOSTART_HIDDEN_ARG) {
if !should_surface_after_update
&& std::env::args().any(|arg| arg == AUTOSTART_HIDDEN_ARG)
{
if let Some(main_window) = app.get_webview_window("main") {
let _ = main_window.hide();
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -236,6 +256,7 @@ pub fn build() -> tauri::Builder<tauri::Wry> {
crate::commands::initialize_local_transcriber,
crate::commands::read_enterprise_target,
crate::commands::get_keyboard_language,
crate::commands::mark_surface_after_update,
])
}

Expand Down
11 changes: 11 additions & 0 deletions apps/desktop/src-tauri/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1347,3 +1347,14 @@ pub fn read_enterprise_target(app: AppHandle) -> Result<(String, Option<String>)
Ok((path_str, Some(content)))
}

#[tauri::command]
pub fn mark_surface_after_update(app: AppHandle) -> Result<(), String> {
let config_dir = app
.path()
.app_config_dir()
.map_err(|err| err.to_string())?;
let flag_file = config_dir.join(crate::app::SURFACE_AFTER_UPDATE_FLAG);
std::fs::write(&flag_file, "1").map_err(|err| err.to_string())?;
Ok(())
}

15 changes: 14 additions & 1 deletion apps/desktop/src/actions/updater.actions.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { invoke } from "@tauri-apps/api/core";
import { relaunch } from "@tauri-apps/plugin-process";
import {
check,
Expand Down Expand Up @@ -227,6 +228,19 @@ export const installAvailableUpdate = async (): Promise<void> => {
}
};

// Set surface flags before calling downloadAndInstall because on Windows,
// the process exits during this call (the Tauri updater spawns the NSIS
// installer then calls std::process::exit) and the .then() callback never
// runs. The file-based flag is checked by Rust on startup to skip the
// autostart-hidden logic; the localStorage flag is consumed by TypeScript
// to call surfaceMainWindow().
markSurfaceWindowForNextLaunch();
try {
await invoke("mark_surface_after_update");
} catch (error) {
console.error("Failed to mark surface after update", error);
}

try {
await update.downloadAndInstall(handleDownloadEvent);
succeeded = true;
Expand Down Expand Up @@ -258,7 +272,6 @@ export const installAvailableUpdate = async (): Promise<void> => {
if (!succeeded) {
return;
}
markSurfaceWindowForNextLaunch();
try {
await availableUpdate?.close();
await relaunch();
Expand Down