Erste Version: Tauri-Grundgerüst, WinGet-Anbindung, Selbst-Updater und Release-Skript

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
DavitoandCopilot committed 2026-10-30 15:58:58 +01:00
commit e0773ba299
84 files changed
+12688

No files matched your search

+146
View File
@@ -0,0 +1,146 @@
//! 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);
}
}