Add versioned DB migrations, startup error dialog and native basics
rusqlite_migration with a VACUUM INTO backup before upgrading; M2 adds GST registration, snapshot, cancellation and draft columns and backfills snapshots for existing invoices. Startup failures now show a native dialog instead of exiting silently. Adds single-instance and window-state plugins, minimum window 960x600, embedBootstrapper, DMABUF workaround on Linux and xbps dependency updates.
This commit is contained in:
+71
-15
@@ -3,32 +3,84 @@ mod db;
|
||||
mod models;
|
||||
|
||||
use rusqlite::Connection;
|
||||
use std::path::PathBuf;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Mutex;
|
||||
use tauri::Manager;
|
||||
use tauri_plugin_dialog::{DialogExt, MessageDialogKind};
|
||||
|
||||
pub struct AppState {
|
||||
pub db: Mutex<Connection>,
|
||||
pub data_dir: PathBuf,
|
||||
}
|
||||
|
||||
/// Show a native error dialog. Release builds have no console on Windows, so
|
||||
/// without this a startup failure would look like the app silently not opening.
|
||||
fn show_startup_error(app: &tauri::App, error: &dyn std::fmt::Display, data_dir: Option<&Path>) {
|
||||
let location = data_dir
|
||||
.map(|d| format!("\n\nData directory:\n{}", d.display()))
|
||||
.unwrap_or_default();
|
||||
eprintln!("Voiced could not start: {error}");
|
||||
app.dialog()
|
||||
.message(format!("{error}{location}"))
|
||||
.title("Voiced could not start")
|
||||
.kind(MessageDialogKind::Error)
|
||||
.blocking_show();
|
||||
}
|
||||
|
||||
fn init_state(app: &tauri::App) -> Result<AppState, Box<dyn std::error::Error>> {
|
||||
let data_dir = match app.path().app_data_dir() {
|
||||
Ok(dir) => dir,
|
||||
Err(e) => {
|
||||
show_startup_error(app, &format!("Could not resolve the application data directory: {e}"), None);
|
||||
return Err(e.into());
|
||||
}
|
||||
};
|
||||
if let Err(e) = std::fs::create_dir_all(&data_dir) {
|
||||
show_startup_error(app, &format!("Could not create the application data directory: {e}"), Some(&data_dir));
|
||||
return Err(e.into());
|
||||
}
|
||||
let conn = match db::open(&data_dir.join("voiced.db"), &data_dir.join("backups")) {
|
||||
Ok(conn) => conn,
|
||||
Err(e) => {
|
||||
show_startup_error(app, &format!("Could not open the database: {e}"), Some(&data_dir));
|
||||
return Err(e.into());
|
||||
}
|
||||
};
|
||||
Ok(AppState {
|
||||
db: Mutex::new(conn),
|
||||
data_dir,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
tauri::Builder::default()
|
||||
// WebKitGTK's DMABUF renderer shows a blank window on several Linux GPU/driver
|
||||
// combinations. Respect an explicit user setting, otherwise turn it off.
|
||||
#[cfg(target_os = "linux")]
|
||||
if std::env::var_os("WEBKIT_DISABLE_DMABUF_RENDERER").is_none() {
|
||||
std::env::set_var("WEBKIT_DISABLE_DMABUF_RENDERER", "1");
|
||||
}
|
||||
|
||||
let builder = tauri::Builder::default();
|
||||
|
||||
// The single-instance plugin must be registered before every other plugin.
|
||||
#[cfg(desktop)]
|
||||
let builder = builder
|
||||
.plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| {
|
||||
if let Some(window) = app.get_webview_window("main") {
|
||||
let _ = window.unminimize();
|
||||
let _ = window.show();
|
||||
let _ = window.set_focus();
|
||||
}
|
||||
}))
|
||||
.plugin(tauri_plugin_window_state::Builder::default().build());
|
||||
|
||||
let result = builder
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.setup(|app| {
|
||||
let data_dir = app
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.expect("could not resolve the application data directory");
|
||||
std::fs::create_dir_all(&data_dir).expect("could not create the application data directory");
|
||||
|
||||
let conn = db::open(&data_dir.join("voiced.db")).expect("could not open the database");
|
||||
app.manage(AppState {
|
||||
db: Mutex::new(conn),
|
||||
data_dir,
|
||||
});
|
||||
let state = init_state(app)?;
|
||||
app.manage(state);
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
@@ -54,6 +106,10 @@ pub fn run() {
|
||||
commands::assets::remove_asset,
|
||||
commands::assets::save_binary_file,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running the Voiced application");
|
||||
.run(tauri::generate_context!());
|
||||
|
||||
if let Err(e) = result {
|
||||
eprintln!("error while running the Voiced application: {e}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user