Files
Wino-Mail/Wino.Mail.WinUI/Services/WinoWindowManager.cs
T

236 lines
6.3 KiB
C#
Raw Normal View History

2026-03-05 10:12:03 +01:00
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using WinUIEx;
using Wino.Mail.WinUI.Interfaces;
using Wino.Mail.WinUI.Models;
namespace Wino.Mail.WinUI.Services;
public class WinoWindowManager : IWinoWindowManager
{
public event EventHandler<WindowEx?>? ActiveWindowChanged;
public event EventHandler<WindowEx>? WindowRemoved;
private readonly object _syncLock = new();
private readonly Dictionary<(WinoWindowKind Kind, string Name), WindowEx> _windows = [];
private readonly Dictionary<WindowEx, (WinoWindowKind Kind, string Name)> _windowKeys = [];
private readonly Dictionary<(WinoWindowKind Kind, string Name), Frame> _primaryNavigationFrames = [];
public WindowEx? ActiveWindow { get; private set; }
public WindowEx CreateWindow(WinoWindowKind kind, Func<WindowEx> factory, string? name = null)
{
var key = CreateKey(kind, name);
lock (_syncLock)
{
if (_windows.TryGetValue(key, out var existingWindow))
{
ActiveWindow = existingWindow;
ActiveWindowChanged?.Invoke(this, existingWindow);
return existingWindow;
}
}
var newWindow = factory();
lock (_syncLock)
{
if (_windows.TryGetValue(key, out var existingWindow))
{
ActiveWindow = existingWindow;
ActiveWindowChanged?.Invoke(this, existingWindow);
return existingWindow;
}
TrackWindow(key, newWindow);
ActiveWindow = newWindow;
ActiveWindowChanged?.Invoke(this, newWindow);
return newWindow;
}
}
public WindowEx? GetWindow(WinoWindowKind kind, string? name = null)
{
lock (_syncLock)
{
_windows.TryGetValue(CreateKey(kind, name), out var window);
return window;
}
}
public WindowEx? GetWindow(string name)
{
var normalizedName = NormalizeName(name);
lock (_syncLock)
{
return _windows
.Where(x => x.Key.Name.Equals(normalizedName, StringComparison.OrdinalIgnoreCase))
.Select(x => x.Value)
.FirstOrDefault();
}
}
public void ActivateWindow(WindowEx window)
{
window.Show();
window.BringToFront();
window.Activate();
lock (_syncLock)
{
ActiveWindow = window;
}
ActiveWindowChanged?.Invoke(this, window);
}
public bool ActivateWindow(WinoWindowKind kind, string? name = null)
{
var window = GetWindow(kind, name);
if (window == null)
return false;
ActivateWindow(window);
return true;
}
public void HideWindow(WindowEx window)
{
window.Hide();
lock (_syncLock)
{
if (ReferenceEquals(ActiveWindow, window))
{
ActiveWindow = null;
ActiveWindowChanged?.Invoke(this, null);
}
}
}
public bool HideWindow(WinoWindowKind kind, string? name = null)
{
var window = GetWindow(kind, name);
if (window == null)
return false;
HideWindow(window);
return true;
}
public void SetPrimaryNavigationFrame(WinoWindowKind kind, Frame frame, string? name = null)
{
lock (_syncLock)
{
_primaryNavigationFrames[CreateKey(kind, name)] = frame;
}
}
public Frame? GetPrimaryNavigationFrame(WinoWindowKind kind, string? name = null)
{
lock (_syncLock)
{
_primaryNavigationFrames.TryGetValue(CreateKey(kind, name), out var frame);
return frame;
}
}
private void TrackWindow((WinoWindowKind Kind, string Name) key, WindowEx window)
{
_windows[key] = window;
_windowKeys[window] = key;
window.Activated += WindowActivated;
window.Closed += WindowClosed;
}
private void WindowActivated(object sender, WindowActivatedEventArgs args)
{
if (sender is not WindowEx window)
return;
if (args.WindowActivationState == WindowActivationState.Deactivated)
return;
lock (_syncLock)
{
if (_windowKeys.ContainsKey(window))
{
ActiveWindow = window;
ActiveWindowChanged?.Invoke(this, window);
}
}
}
private void WindowClosed(object sender, WindowEventArgs args)
{
if (sender is not WindowEx window)
return;
lock (_syncLock)
{
if (!_windowKeys.TryGetValue(window, out var key))
return;
window.Activated -= WindowActivated;
window.Closed -= WindowClosed;
_windowKeys.Remove(window);
_windows.Remove(key);
_primaryNavigationFrames.Remove(key);
WindowRemoved?.Invoke(this, window);
if (ReferenceEquals(ActiveWindow, window))
{
ActiveWindow = null;
ActiveWindowChanged?.Invoke(this, null);
}
}
}
public void CloseAllWindows()
{
List<WindowEx> windows;
lock (_syncLock)
{
windows = _windows.Values.Distinct().ToList();
}
foreach (var window in windows)
{
try
{
window.Activated -= WindowActivated;
window.Closed -= WindowClosed;
window.Close();
}
catch
{
// Best effort shutdown for all tracked windows.
}
}
lock (_syncLock)
{
_windowKeys.Clear();
_windows.Clear();
_primaryNavigationFrames.Clear();
ActiveWindow = null;
}
ActiveWindowChanged?.Invoke(this, null);
}
private static (WinoWindowKind Kind, string Name) CreateKey(WinoWindowKind kind, string? name)
{
var resolvedName = NormalizeName(name ?? kind.ToString());
return (kind, string.IsNullOrWhiteSpace(resolvedName) ? kind.ToString() : resolvedName);
}
private static string NormalizeName(string name) => name.Trim();
}