Some more cleanup.

This commit is contained in:
Burak Kaan Köse
2026-04-05 13:18:50 +02:00
parent c1ab49fb1d
commit ca19297b92
22 changed files with 444 additions and 302 deletions
+1
View File
@@ -231,6 +231,7 @@ public partial class App : WinoApplication,
if (windowManager.GetWindow(WinoWindowKind.Welcome) is not WelcomeWindow welcomeWindow)
return;
welcomeWindow.PrepareForClose();
welcomeWindow.AllowClose();
welcomeWindow.Close();
}
@@ -1,35 +1,35 @@
{
"sections": [
{
"title": "# Wino Calendar is here!",
"title": "Wino Calendar is here!",
"description": "You can now create local or remote CalDAV-compatible calendars, manage recurring events, and respond to invitations — all from within Wino.",
"imageUrl": "ms-appx:///Assets/UpdateNotes/Images/Calendar.svg",
"imageWidth": 128,
"imageHeight": 128
},
{
"title": "# S/MIME Signing & Encryption",
"title": "S/MIME Signing & Encryption",
"description": "Wino now supports signing and encrypting your emails with personal certificates. Keep your communications secure and verifiable.",
"imageUrl": "ms-appx:///Assets/UpdateNotes/Images/Security.svg",
"imageWidth": 128,
"imageHeight": 128
},
{
"title": "# Threaded Mail View",
"title": "Threaded Mail View",
"description": "Emails are now grouped by conversation, making it easier to follow long discussions without losing context.",
"imageUrl": "ms-appx:///Assets/UpdateNotes/Images/Thread.svg",
"imageWidth": 128,
"imageHeight": 128
},
{
"title": "# Smarter Notifications",
"title": "Smarter Notifications",
"description": "Act on your emails directly from toast notifications — mark as read, delete, or archive without opening the app.",
"imageUrl": "ms-appx:///Assets/UpdateNotes/Images/Notification.svg",
"imageWidth": 128,
"imageHeight": 128
},
{
"title": "# And much more...",
"title": "And much more...",
"description": "Folder management, swipe actions, keyboard shortcuts, a custom print dialog, and significant performance improvements are all included in this release.\n\nThank you for using Wino Mail!",
"imageUrl": "ms-appx:///Assets/UpdateNotes/Images/More.svg",
"imageWidth": 128,
+36 -4
View File
@@ -13,6 +13,8 @@ namespace Wino.Mail.WinUI;
public partial class BasePage : Page, IRecipient<LanguageChanged>
{
private bool _isPreparedForClose;
public void Receive(LanguageChanged message)
{
OnLanguageChanged();
@@ -31,6 +33,24 @@ public partial class BasePage : Page, IRecipient<LanguageChanged>
protected virtual void UnregisterRecipients() { }
public virtual CoreBaseViewModel? AssociatedViewModel => null;
public virtual void PrepareForClose()
{
if (_isPreparedForClose)
return;
_isPreparedForClose = true;
WeakReferenceMessenger.Default.Unregister<LanguageChanged>(this);
UnregisterRecipients();
}
protected void ResetPreparedForCloseState()
{
_isPreparedForClose = false;
}
protected bool IsPreparedForClose => _isPreparedForClose;
}
public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
@@ -63,6 +83,7 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
var mode = GetNavigationMode(e.NavigationMode);
var parameter = e.Parameter;
ResetPreparedForCloseState();
WeakReferenceMessenger.Default.Register<LanguageChanged>(this);
RegisterRecipients();
@@ -76,14 +97,25 @@ public abstract class BasePage<T> : BasePage where T : CoreBaseViewModel
var mode = GetNavigationMode(e.NavigationMode);
var parameter = e.Parameter;
WeakReferenceMessenger.Default.Unregister<LanguageChanged>(this);
UnregisterRecipients();
ViewModel.OnNavigatedFrom(mode, parameter);
PrepareForClose(mode, parameter);
GC.Collect();
}
public override void PrepareForClose()
{
PrepareForClose(WinoNavigationMode.New, null);
}
private void PrepareForClose(WinoNavigationMode mode, object? parameter)
{
if (IsPreparedForClose)
return;
base.PrepareForClose();
ViewModel.OnNavigatedFrom(mode, parameter!);
}
private WinoNavigationMode GetNavigationMode(NavigationMode mode)
{
return (WinoNavigationMode)mode;
@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
namespace Wino.Mail.WinUI.Helpers;
internal static class WindowCleanupHelper
{
public static void CleanupFrame(Frame? frame)
{
if (frame == null)
return;
CleanupObject(frame.Content);
frame.BackStack.Clear();
frame.ForwardStack.Clear();
frame.Content = null;
}
public static void CleanupObject(object? instance)
{
if (instance == null)
return;
var visited = new HashSet<object>(ReferenceEqualityComparer.Instance);
CleanupObject(instance, visited);
}
private static void CleanupObject(object? instance, HashSet<object> visited)
{
if (instance == null || !visited.Add(instance))
return;
switch (instance)
{
case Views.WinoAppShell shell:
shell.PrepareForWindowClose();
break;
case Frame frame:
CleanupFrame(frame);
break;
case BasePage page:
page.PrepareForClose();
break;
}
if (instance is DependencyObject dependencyObject)
{
var childCount = VisualTreeHelper.GetChildrenCount(dependencyObject);
for (int i = 0; i < childCount; i++)
{
CleanupObject(VisualTreeHelper.GetChild(dependencyObject, i), visited);
}
}
if (instance is IDisposable disposable)
{
disposable.Dispose();
}
}
private sealed class ReferenceEqualityComparer : IEqualityComparer<object>
{
public static ReferenceEqualityComparer Instance { get; } = new();
public new bool Equals(object? x, object? y) => ReferenceEquals(x, y);
public int GetHashCode(object obj) => System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
}
}
@@ -221,12 +221,6 @@ public class PreferencesService(IConfigurationService configurationService) : Ob
set => SetPropertyAndSave(nameof(IsLoggingEnabled), value);
}
public bool IsMailkitProtocolLoggerEnabled
{
get => _configurationService.Get(nameof(IsMailkitProtocolLoggerEnabled), false);
set => SetPropertyAndSave(nameof(IsMailkitProtocolLoggerEnabled), value);
}
public bool IsGravatarEnabled
{
get => _configurationService.Get(nameof(IsGravatarEnabled), true);
+10
View File
@@ -16,6 +16,7 @@ using Wino.Core.Domain.Models.Synchronization;
using Wino.Extensions;
using Wino.Mail.WinUI.Activation;
using Wino.Mail.WinUI.Extensions;
using Wino.Mail.WinUI.Helpers;
using Wino.Mail.WinUI.Interfaces;
using Wino.Mail.WinUI.Models;
using Wino.Mail.WinUI.Views;
@@ -46,6 +47,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
private ITitleBarSearchHost? _activeTitleBarSearchHost;
private bool _isBackButtonVisibilityReady;
private bool _isSynchronizingTitleBarSearch;
private bool _isPreparedForClose;
public ShellWindow()
{
@@ -365,11 +367,18 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
public void PrepareForClose()
{
if (_isPreparedForClose)
return;
_isPreparedForClose = true;
if (MainShellFrame.Content is WinoAppShell shellPage)
{
shellPage.PrepareForWindowClose();
}
WindowCleanupHelper.CleanupFrame(MainShellFrame);
_allowClose = true;
}
@@ -384,6 +393,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
shellPage.PrepareForWindowClose();
}
WindowCleanupHelper.CleanupFrame(MainShellFrame);
UnregisterRecipients();
}
@@ -25,19 +25,21 @@ public sealed partial class WelcomeHostPage : WelcomeHostPageAbstract,
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
WeakReferenceMessenger.Default.Register<BackBreadcrumNavigationRequested>(this);
ResetWizard();
}
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
protected override void RegisterRecipients()
{
base.RegisterRecipients();
WeakReferenceMessenger.Default.Register<BreadcrumbNavigationRequested>(this);
WeakReferenceMessenger.Default.Register<BackBreadcrumNavigationRequested>(this);
}
protected override void UnregisterRecipients()
{
base.UnregisterRecipients();
WeakReferenceMessenger.Default.Unregister<BreadcrumbNavigationRequested>(this);
WeakReferenceMessenger.Default.Unregister<BackBreadcrumNavigationRequested>(this);
base.OnNavigatingFrom(e);
}
public void Receive(BreadcrumbNavigationRequested message)
@@ -28,6 +28,7 @@ using Wino.Mail.ViewModels;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.WinUI.ViewModels;
using Wino.Mail.WinUI.Controls;
using Wino.Mail.WinUI.Helpers;
using Wino.MenuFlyouts;
using Wino.MenuFlyouts.Context;
using Wino.Messaging.Client.Accounts;
@@ -127,6 +128,7 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
navigationView.MenuItemsSource = null;
CalendarHostListView.ItemsSource = null;
WindowCleanupHelper.CleanupFrame(InnerShellFrame);
}
private void OnLoaded(object sender, RoutedEventArgs e)
+19
View File
@@ -3,6 +3,7 @@ using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Interfaces;
using Wino.Mail.WinUI.Helpers;
using Wino.Mail.WinUI.Interfaces;
using WinUIEx;
@@ -11,6 +12,7 @@ namespace Wino.Mail.WinUI;
public sealed partial class WelcomeWindow : WindowEx
{
private bool _allowClose;
private bool _isPreparedForClose;
public Frame GetRootFrame() => RootFrame;
@@ -25,6 +27,7 @@ public sealed partial class WelcomeWindow : WindowEx
ConfigureWindowChrome();
AppWindow.Closing += OnAppWindowClosing;
Closed += OnWindowClosed;
}
private void ConfigureWindowChrome()
@@ -55,4 +58,20 @@ public sealed partial class WelcomeWindow : WindowEx
{
_allowClose = true;
}
public void PrepareForClose()
{
if (_isPreparedForClose)
return;
_isPreparedForClose = true;
WindowCleanupHelper.CleanupFrame(RootFrame);
}
private void OnWindowClosed(object sender, WindowEventArgs e)
{
Closed -= OnWindowClosed;
AppWindow.Closing -= OnAppWindowClosing;
PrepareForClose();
}
}