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:
commit
e0773ba299
84 files changed
+12688
No files matched your search
@@ -0,0 +1,73 @@
|
||||
//! Persistenter Zustand unter `%APPDATA%\VitosUpdater` (Phase 1: Fensterposition und -größe).
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Gespeicherte Fenstergeometrie in physischen Pixeln.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct WindowState {
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub maximized: bool,
|
||||
}
|
||||
|
||||
fn file(dir: &Path) -> PathBuf {
|
||||
dir.join("window.json")
|
||||
}
|
||||
|
||||
/// Lädt die gespeicherte Fenstergeometrie. Fehlt die Datei oder ist sie defekt, ist das Ergebnis `None`.
|
||||
pub fn load_window_state(dir: &Path) -> Option<WindowState> {
|
||||
let text = std::fs::read_to_string(file(dir)).ok()?;
|
||||
serde_json::from_str(&text).ok()
|
||||
}
|
||||
|
||||
/// Speichert die Fenstergeometrie atomar (Schreiben in temporäre Datei, dann Umbenennen).
|
||||
pub fn save_window_state(dir: &Path, state: &WindowState) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(dir)?;
|
||||
let tmp = dir.join("window.json.tmp");
|
||||
std::fs::write(&tmp, serde_json::to_string_pretty(state)?)?;
|
||||
std::fs::rename(tmp, file(dir))
|
||||
}
|
||||
|
||||
/// Prüft, ob ein Fensterrechteck ein Monitorrechteck `(x, y, breite, höhe)` ausreichend überlappt.
|
||||
pub fn is_visible_on(state: &WindowState, monitors: &[(i32, i32, u32, u32)]) -> bool {
|
||||
const MIN_VISIBLE: i64 = 120;
|
||||
monitors.iter().any(|&(mx, my, mw, mh)| {
|
||||
let left = i64::from(state.x.max(mx));
|
||||
let top = i64::from(state.y.max(my));
|
||||
let right = (i64::from(state.x) + i64::from(state.width)).min(i64::from(mx) + i64::from(mw));
|
||||
let bottom = (i64::from(state.y) + i64::from(state.height)).min(i64::from(my) + i64::from(mh));
|
||||
right - left >= MIN_VISIBLE && bottom - top >= MIN_VISIBLE
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn state(x: i32, y: i32) -> WindowState {
|
||||
WindowState { x, y, width: 1280, height: 800, maximized: false }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn visible_on_primary_monitor() {
|
||||
assert!(is_visible_on(&state(100, 100), &[(0, 0, 1920, 1080)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn offscreen_after_monitor_removed() {
|
||||
assert!(!is_visible_on(&state(2500, 100), &[(0, 0, 1920, 1080)]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip() {
|
||||
let dir = std::env::temp_dir().join("vitosupdater-test-window");
|
||||
let s = state(10, 20);
|
||||
save_window_state(&dir, &s).unwrap();
|
||||
assert_eq!(load_window_state(&dir), Some(s));
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user