236 lines
6.3 KiB
C#
236 lines
6.3 KiB
C#
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();
|
|
}
|