Make app fully portable, remove installers
- Remove MSI and NSIS installer targets, only produce vesper.exe - Remove tauri-plugin-window-state, replace with manual window state save/restore to data/window-state.json next to the exe - Redirect WebView2 user data (including localStorage) to data/ folder next to the exe via WEBVIEW2_USER_DATA_DIR - Nothing written to AppData, registry, or any system location - Update README with portable usage info
This commit is contained in:
@@ -1,10 +1,94 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::Manager;
|
||||
|
||||
#[derive(Serialize, Deserialize, Default)]
|
||||
struct WindowState {
|
||||
x: Option<i32>,
|
||||
y: Option<i32>,
|
||||
width: Option<u32>,
|
||||
height: Option<u32>,
|
||||
maximized: Option<bool>,
|
||||
}
|
||||
|
||||
fn get_data_dir() -> PathBuf {
|
||||
env::current_exe()
|
||||
.ok()
|
||||
.and_then(|p| p.parent().map(|p| p.to_path_buf()))
|
||||
.unwrap_or_else(|| PathBuf::from("."))
|
||||
.join("data")
|
||||
}
|
||||
|
||||
fn load_window_state() -> WindowState {
|
||||
let path = get_data_dir().join("window-state.json");
|
||||
fs::read_to_string(&path)
|
||||
.ok()
|
||||
.and_then(|s| serde_json::from_str(&s).ok())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn save_window_state(state: &WindowState) {
|
||||
let dir = get_data_dir();
|
||||
let _ = fs::create_dir_all(&dir);
|
||||
let path = dir.join("window-state.json");
|
||||
if let Ok(json) = serde_json::to_string_pretty(state) {
|
||||
let _ = fs::write(path, json);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
let data_dir = get_data_dir();
|
||||
let _ = fs::create_dir_all(&data_dir);
|
||||
|
||||
// Redirect WebView2 user data to portable location next to the exe
|
||||
env::set_var(
|
||||
"WEBVIEW2_USER_DATA_DIR",
|
||||
data_dir.to_string_lossy().to_string(),
|
||||
);
|
||||
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_opener::init())
|
||||
.plugin(tauri_plugin_dialog::init())
|
||||
.plugin(tauri_plugin_fs::init())
|
||||
.plugin(tauri_plugin_window_state::Builder::new().build())
|
||||
.setup(|app| {
|
||||
let state = load_window_state();
|
||||
let window = app.get_webview_window("main").unwrap();
|
||||
|
||||
if let (Some(x), Some(y)) = (state.x, state.y) {
|
||||
let _ = window.set_position(tauri::Position::Physical(
|
||||
tauri::PhysicalPosition::new(x, y),
|
||||
));
|
||||
}
|
||||
if let (Some(w), Some(h)) = (state.width, state.height) {
|
||||
let _ = window.set_size(tauri::Size::Physical(
|
||||
tauri::PhysicalSize::new(w, h),
|
||||
));
|
||||
}
|
||||
if let Some(true) = state.maximized {
|
||||
let _ = window.maximize();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.on_window_event(|window, event| {
|
||||
if let tauri::WindowEvent::CloseRequested { .. } = event {
|
||||
let maximized = window.is_maximized().unwrap_or(false);
|
||||
if let (Ok(pos), Ok(size)) = (window.outer_position(), window.outer_size()) {
|
||||
let state = WindowState {
|
||||
x: Some(pos.x),
|
||||
y: Some(pos.y),
|
||||
width: Some(size.width),
|
||||
height: Some(size.height),
|
||||
maximized: Some(maximized),
|
||||
};
|
||||
save_window_state(&state);
|
||||
}
|
||||
}
|
||||
})
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user