using System.IO;
using System.Text.Json;
using System.Windows;
namespace TeamsISO.App.Services;
///
/// Saves / restores the main window's size, position, and state across launches.
/// Stored as JSON at %LOCALAPPDATA%\TeamsISO\window.json. Multi-monitor
/// friendly: a saved position that no longer falls inside any working area is
/// rejected on restore so the window doesn't disappear off-screen when a monitor
/// has been disconnected.
///
public static class WindowStateStore
{
private static readonly string Path =
System.IO.Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"TeamsISO",
"window.json");
public sealed record Snapshot(
double Left,
double Top,
double Width,
double Height,
WindowState State);
/// Save the current window placement.
public static void Save(Window window)
{
try
{
var snap = new Snapshot(
Left: window.Left,
Top: window.Top,
Width: window.ActualWidth,
Height: window.ActualHeight,
State: window.WindowState == WindowState.Minimized ? WindowState.Normal : window.WindowState);
var dir = System.IO.Path.GetDirectoryName(Path);
if (!string.IsNullOrEmpty(dir)) Directory.CreateDirectory(dir);
File.WriteAllText(Path, JsonSerializer.Serialize(snap, new JsonSerializerOptions { WriteIndented = true }));
}
catch
{
// Best-effort persistence; never crash on shutdown for a UI nicety.
}
}
///
/// Apply a previously-saved placement. Clamps onto a visible work area so a
/// monitor change doesn't strand the window off-screen. Returns true if a
/// valid snapshot was applied; false if no file existed or the snapshot was
/// rejected for being entirely outside any visible work area.
///
public static bool TryApply(Window window)
{
try
{
if (!File.Exists(Path)) return false;
var json = File.ReadAllText(Path);
var snap = JsonSerializer.Deserialize(json);
if (snap is null) return false;
// Sanity-check sizes (don't restore a 0×0 or absurdly large window).
if (snap.Width < 320 || snap.Height < 240) return false;
if (snap.Width > 16000 || snap.Height > 12000) return false;
// Reject if entirely off-screen (any working area on any screen contains
// a corner). System.Windows.Forms gives us per-monitor work areas here;
// we deliberately stick with WPF's SystemParameters which only reports the
// primary, so we use a generous on-screen check rather than refusing
// multi-monitor positions.
if (!IsAnyCornerOnScreen(snap)) return false;
window.WindowStartupLocation = WindowStartupLocation.Manual;
window.Left = snap.Left;
window.Top = snap.Top;
window.Width = snap.Width;
window.Height = snap.Height;
window.WindowState = snap.State;
return true;
}
catch
{
return false;
}
}
///
/// Approximate "is at least one corner of the saved rect within the virtual
/// screen?" check. Uses SystemParameters.VirtualScreen* which spans every
/// monitor.
///
private static bool IsAnyCornerOnScreen(Snapshot snap)
{
var minX = SystemParameters.VirtualScreenLeft;
var minY = SystemParameters.VirtualScreenTop;
var maxX = minX + SystemParameters.VirtualScreenWidth;
var maxY = minY + SystemParameters.VirtualScreenHeight;
var corners = new[]
{
(snap.Left, snap.Top),
(snap.Left + snap.Width, snap.Top),
(snap.Left, snap.Top + snap.Height),
(snap.Left + snap.Width, snap.Top + snap.Height),
};
foreach (var (x, y) in corners)
{
if (x >= minX && x <= maxX && y >= minY && y <= maxY)
return true;
}
return false;
}
}