147 lines
5.1 KiB
Rust
147 lines
5.1 KiB
Rust
//! VitosUpdater – einheitliche Paketverwaltung für Windows.
|
||
|
||
pub mod commands;
|
||
pub mod error;
|
||
pub mod logging;
|
||
pub mod managers;
|
||
pub mod models;
|
||
pub mod process;
|
||
pub mod settings;
|
||
pub mod updater;
|
||
|
||
use std::path::PathBuf;
|
||
use std::sync::atomic::{AtomicU64, Ordering};
|
||
use std::sync::{Arc, Mutex};
|
||
use std::time::Duration;
|
||
|
||
use tauri::{Manager, PhysicalPosition, PhysicalSize, WebviewWindow, WindowEvent};
|
||
|
||
use settings::WindowState;
|
||
|
||
/// Letzte normale (nicht maximierte) Geometrie und Zähler für das Entprellen des Speicherns.
|
||
struct WindowTracker {
|
||
dir: PathBuf,
|
||
normal: Mutex<Option<WindowState>>,
|
||
generation: AtomicU64,
|
||
}
|
||
|
||
fn restore_window(window: &WebviewWindow, saved: Option<WindowState>) {
|
||
if let Some(state) = saved {
|
||
let monitors: Vec<(i32, i32, u32, u32)> = window
|
||
.available_monitors()
|
||
.unwrap_or_default()
|
||
.iter()
|
||
.map(|m| (m.position().x, m.position().y, m.size().width, m.size().height))
|
||
.collect();
|
||
if settings::is_visible_on(&state, &monitors) {
|
||
let _ = window.set_size(PhysicalSize::new(state.width, state.height));
|
||
let _ = window.set_position(PhysicalPosition::new(state.x, state.y));
|
||
}
|
||
if state.maximized {
|
||
let _ = window.maximize();
|
||
}
|
||
}
|
||
let _ = window.show();
|
||
}
|
||
|
||
fn track_window(window: &WebviewWindow, tracker: &Arc<WindowTracker>) {
|
||
let maximized = window.is_maximized().unwrap_or(false);
|
||
let minimized = window.is_minimized().unwrap_or(false);
|
||
if minimized {
|
||
return;
|
||
}
|
||
{
|
||
let mut normal = tracker.normal.lock().unwrap_or_else(|e| e.into_inner());
|
||
if !maximized {
|
||
if let (Ok(pos), Ok(size)) = (window.outer_position(), window.inner_size()) {
|
||
*normal = Some(WindowState { x: pos.x, y: pos.y, width: size.width, height: size.height, maximized: false });
|
||
}
|
||
} else if let Some(state) = normal.as_mut() {
|
||
state.maximized = true;
|
||
}
|
||
}
|
||
let generation = tracker.generation.fetch_add(1, Ordering::SeqCst) + 1;
|
||
let tracker = Arc::clone(tracker);
|
||
tauri::async_runtime::spawn(async move {
|
||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||
if tracker.generation.load(Ordering::SeqCst) != generation {
|
||
return;
|
||
}
|
||
let snapshot = *tracker.normal.lock().unwrap_or_else(|e| e.into_inner());
|
||
if let Some(mut state) = snapshot {
|
||
state.maximized = maximized;
|
||
if let Err(err) = settings::save_window_state(&tracker.dir, &state) {
|
||
tracing::warn!(%err, "Fensterzustand konnte nicht gespeichert werden");
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/// Startet die Anwendung.
|
||
pub fn run() {
|
||
let dir = logging::data_dir();
|
||
let _guard = logging::init(&dir);
|
||
tracing::info!(version = env!("CARGO_PKG_VERSION"), "VitosUpdater startet");
|
||
|
||
let tracker = Arc::new(WindowTracker {
|
||
dir: dir.clone(),
|
||
normal: Mutex::new(settings::load_window_state(&dir)),
|
||
generation: AtomicU64::new(0),
|
||
});
|
||
let saved = settings::load_window_state(&dir);
|
||
let event_tracker = Arc::clone(&tracker);
|
||
|
||
let result = tauri::Builder::default()
|
||
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
|
||
if let Some(window) = app.get_webview_window("main") {
|
||
let _ = window.unminimize();
|
||
let _ = window.show();
|
||
let _ = window.set_focus();
|
||
}
|
||
}))
|
||
.plugin(tauri_plugin_opener::init())
|
||
.plugin(tauri_plugin_notification::init())
|
||
.plugin(tauri_plugin_updater::Builder::new().build())
|
||
.manage(commands::Registry::new())
|
||
.manage(updater::UpdaterState::new(dir.clone()))
|
||
.invoke_handler(tauri::generate_handler![
|
||
commands::detect_managers,
|
||
commands::search_packages,
|
||
commands::list_installed,
|
||
commands::list_updates,
|
||
commands::get_package_details,
|
||
commands::list_sources,
|
||
commands::install_winget_module,
|
||
commands::install_app_installer,
|
||
updater::updater_ready,
|
||
updater::get_updater_status,
|
||
updater::get_update_offer,
|
||
updater::check_for_update,
|
||
updater::snooze_update,
|
||
updater::skip_update,
|
||
updater::clear_skipped_version,
|
||
updater::set_update_interval,
|
||
updater::install_update,
|
||
updater::take_update_notice,
|
||
])
|
||
.setup(move |app| {
|
||
if let Some(window) = app.get_webview_window("main") {
|
||
restore_window(&window, saved);
|
||
}
|
||
Ok(())
|
||
})
|
||
.on_window_event(move |window, event| {
|
||
if matches!(event, WindowEvent::Moved(_) | WindowEvent::Resized(_)) {
|
||
if let Some(webview) = window.app_handle().get_webview_window(window.label()) {
|
||
track_window(&webview, &event_tracker);
|
||
}
|
||
}
|
||
})
|
||
.run(tauri::generate_context!());
|
||
|
||
if let Err(err) = result {
|
||
tracing::error!(%err, "Anwendung wurde mit einem Fehler beendet");
|
||
std::process::exit(1);
|
||
}
|
||
}
|