Handling some warnings and proper disposals of shells etc.

This commit is contained in:
Burak Kaan Köse
2026-03-27 14:45:36 +01:00
parent 3712041689
commit fb8a3d8f90
21 changed files with 470 additions and 298 deletions
+16 -4
View File
@@ -10,6 +10,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Toolkit.Uwp.Notifications;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.Windows.AppLifecycle;
using Microsoft.Windows.AppNotifications;
using MimeKit.Cryptography;
@@ -192,7 +193,7 @@ public partial class App : WinoApplication,
if (welcomeWindow == null)
return;
windowManager.HideWindow(WinoWindowKind.Shell);
CloseShellWindowIfPresent();
await ActivateWindowAsync(welcomeWindow);
}
@@ -232,6 +233,16 @@ public partial class App : WinoApplication,
welcomeWindow.Close();
}
private void CloseShellWindowIfPresent()
{
var windowManager = Services.GetRequiredService<IWinoWindowManager>();
if (windowManager.GetWindow(WinoWindowKind.Shell) is not ShellWindow shellWindow)
return;
shellWindow.PrepareForClose();
shellWindow.Close();
}
private async Task ActivateWindowAsync(WindowEx window)
{
var windowManager = Services.GetRequiredService<IWinoWindowManager>();
@@ -792,8 +803,9 @@ public partial class App : WinoApplication,
}
else
{
Services.GetRequiredService<INavigationService>()
.Navigate(WinoPage.WelcomeHostPage, null, NavigationReferenceFrame.ShellFrame, NavigationTransitionType.None);
rootFrame.BackStack.Clear();
rootFrame.ForwardStack.Clear();
rootFrame.Navigate(typeof(WelcomeHostPage), null, new SuppressNavigationTransitionInfo());
}
}
@@ -926,8 +938,8 @@ public partial class App : WinoApplication,
// All accounts removed — go back to welcome wizard from step 1
Services.GetRequiredService<WelcomeWizardContext>().Reset();
StopAutoSynchronizationLoop();
CloseShellWindowIfPresent();
CreateWelcomeWindow();
windowManager.HideWindow(WinoWindowKind.Shell);
if (MainWindow != null)
await ActivateWindowAsync(MainWindow);
});
@@ -9,22 +9,22 @@
Loaded="ControlLoaded"
SelectionChanged="ModeSegmentedControlSelectionChanged"
Unloaded="ControlUnloaded">
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.KeyboardShortcuts_ModeMail, Mode=OneWay}">
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.KeyboardShortcuts_ModeMail}">
<controls:SegmentedItem.Icon>
<SymbolIcon Symbol="Mail" />
</controls:SegmentedItem.Icon>
</controls:SegmentedItem>
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.KeyboardShortcuts_ModeCalendar, Mode=OneWay}">
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.KeyboardShortcuts_ModeCalendar}">
<controls:SegmentedItem.Icon>
<SymbolIcon Symbol="Calendar" />
</controls:SegmentedItem.Icon>
</controls:SegmentedItem>
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.ContactsPage_Title, Mode=OneWay}">
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.ContactsPage_Title}">
<controls:SegmentedItem.Icon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE716;" />
</controls:SegmentedItem.Icon>
</controls:SegmentedItem>
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.MenuSettings, Mode=OneWay}">
<controls:SegmentedItem Padding="0" ToolTipService.ToolTip="{x:Bind domain:Translator.MenuSettings}">
<controls:SegmentedItem.Icon>
<SymbolIcon Symbol="Setting" />
</controls:SegmentedItem.Icon>
@@ -52,6 +52,10 @@
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ParagraphStyleOptionTemplate" x:DataType="mail:EditorParagraphStyleOption">
<TextBlock Text="{x:Bind Name}" />
</DataTemplate>
</UserControl.Resources>
<toolkit:TabbedCommandBar>
@@ -231,7 +235,7 @@
x:Name="ParagraphStyleComboBox"
Grid.Column="1"
MinWidth="104"
DisplayMemberPath="Name"
ItemTemplate="{StaticResource ParagraphStyleOptionTemplate}"
PlaceholderText="Paragraph"
SelectionChanged="ParagraphStyleComboBox_SelectionChanged"
Style="{StaticResource CompactComboBoxStyle}" />
@@ -30,7 +30,7 @@
FontFamily="Consolas"
FontSize="12"
IsTextSelectionEnabled="True"
Text="{x:Bind MessageSource, Mode=OneWay}"
Text="{x:Bind MessageSource}"
TextWrapping="Wrap" />
</Border>
</ScrollViewer>
+1 -1
View File
@@ -61,7 +61,7 @@
CanDragItems="False"
CanReorderItems="False"
ItemTemplate="{StaticResource FolderStructureMenuFlyoutItemTemplate}"
ItemsSource="{x:Bind FolderList, Mode=OneWay}"
ItemsSource="{x:Bind FolderList}"
SelectedItem="{x:Bind SelectedFolder, Mode=TwoWay}"
SelectionMode="Single" />
</Grid>
@@ -163,7 +163,7 @@
<ComboBox
Grid.Row="4"
Header="{x:Bind domain:Translator.ImapCalDavSettingsPage_CalendarModeHeader, Mode=OneWay}"
Header="{x:Bind domain:Translator.ImapCalDavSettingsPage_CalendarModeHeader}"
ItemsSource="{x:Bind CalendarModeOptions, Mode=OneWay}"
SelectedIndex="{x:Bind SelectedCalendarModeIndex, Mode=TwoWay}" />
@@ -28,13 +28,13 @@
<StackPanel Margin="0,8,0,0" Spacing="12">
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind domain:Translator.CalendarEventCompose_DefaultCalendarHint, Mode=OneWay}"
Text="{x:Bind domain:Translator.CalendarEventCompose_DefaultCalendarHint}"
TextWrapping="WrapWholeWords" />
<HyperlinkButton
HorizontalAlignment="Left"
Click="OpenCalendarSettingsClicked"
Content="{x:Bind domain:Translator.CalendarEventCompose_DefaultCalendarSettingsLink, Mode=OneWay}"
Content="{x:Bind domain:Translator.CalendarEventCompose_DefaultCalendarSettingsLink}"
Padding="0" />
<ScrollViewer MaxHeight="400">
@@ -67,7 +67,7 @@
Width="14"
Height="14"
VerticalAlignment="Center"
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex), Mode=OneWay}" />
Fill="{x:Bind helpers:XamlHelpers.GetSolidColorBrushFromHex(BackgroundColorHex)}" />
<TextBlock
Grid.Column="1"
@@ -3,7 +3,7 @@
"Wino.Mail.WinUI (Package)": {
"commandName": "MsixPackage",
"doNotLaunchApp": false,
"nativeDebugging": true
"nativeDebugging": false
},
"Wino.Mail.WinUI (Unpackaged)": {
"commandName": "Project"
-11
View File
@@ -143,17 +143,6 @@
</LinearGradientBrush>
</Border.Background>
<StackPanel Spacing="4">
<Border
Width="40"
Height="40"
HorizontalAlignment="Left"
Background="{ThemeResource AccentFillColorDefaultBrush}"
CornerRadius="20">
<FontIcon
FontSize="18"
Foreground="White"
Glyph="&#xE77B;" />
</Border>
<TextBlock
Margin="0,8,0,0"
Style="{StaticResource SubtitleTextBlockStyle}"
+19 -1
View File
@@ -34,6 +34,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
IRecipient<WinoAccountProfileUpdatedMessage>,
IRecipient<WinoAccountProfileDeletedMessage>
{
private bool _allowClose;
public IStatePersistanceService StatePersistanceService { get; } = WinoApplication.Current.Services.GetService<IStatePersistanceService>() ?? throw new Exception("StatePersistanceService not registered in DI container.");
public IPreferencesService PreferencesService { get; } = WinoApplication.Current.Services.GetService<IPreferencesService>() ?? throw new Exception("PreferencesService not registered in DI container.");
public INavigationService NavigationService { get; } = WinoApplication.Current.Services.GetService<INavigationService>() ?? throw new Exception("NavigationService not registered in DI container.");
@@ -354,7 +355,7 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
private void OnAppWindowClosing(object sender, Microsoft.UI.Windowing.AppWindowClosingEventArgs e)
{
if ((Application.Current as App)?.IsExiting == true)
if (_allowClose || (Application.Current as App)?.IsExiting == true)
return;
e.Cancel = true;
@@ -362,10 +363,27 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow,
windowManager?.HideWindow(this);
}
public void PrepareForClose()
{
if (MainShellFrame.Content is WinoAppShell shellPage)
{
shellPage.PrepareForWindowClose();
}
_allowClose = true;
}
private void OnWindowClosed(object sender, WindowEventArgs e)
{
Closed -= OnWindowClosed;
AppWindow.Closing -= OnAppWindowClosing;
StatePersistanceService.StatePropertyChanged -= StatePersistenceServiceChanged;
if (MainShellFrame.Content is WinoAppShell shellPage)
{
shellPage.PrepareForWindowClose();
}
UnregisterRecipients();
}
@@ -34,6 +34,12 @@ public sealed class ContactsShellClient(INavigationService navigationService) :
public void Activate(ShellModeActivationContext activationContext)
{
OnNavigatedTo(NavigationMode.New, activationContext);
if (MenuItems?.Count == 0)
{
MenuItems.Add(_newContactMenuItem);
}
navigationService.Navigate(WinoPage.ContactsPage, null, NavigationReferenceFrame.InnerShellFrame);
}
@@ -42,6 +48,16 @@ public sealed class ContactsShellClient(INavigationService navigationService) :
OnNavigatedFrom(NavigationMode.New, null!);
}
public void PrepareForShellShutdown()
{
SelectedMenuItem = null;
if (MenuItems != null)
{
MenuItems.Clear();
MenuItems.Add(_newContactMenuItem);
}
}
public Task HandleNavigationItemInvokedAsync(IMenuItem? menuItem)
{
if (menuItem is NewContactMenuItem)
@@ -57,6 +57,18 @@ public partial class SettingsShellClient(INavigationService navigationService) :
{
}
public void PrepareForShellShutdown()
{
if (_hasRegisteredPersistentRecipients)
{
UnregisterRecipients();
_hasRegisteredPersistentRecipients = false;
}
SelectedMenuItem = null;
MenuItems?.Clear();
}
public Task HandleNavigationItemInvokedAsync(IMenuItem? menuItem)
{
if (menuItem is not SettingsShellPageMenuItem settingsMenuItem)
File diff suppressed because one or more lines are too long
@@ -447,7 +447,7 @@
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind Email}"
TextTrimming="CharacterEllipsis"
Visibility="{x:Bind HasDistinctDisplayName, Mode=OneWay}" />
Visibility="{x:Bind HasDistinctDisplayName}" />
</StackPanel>
<Button
@@ -14,6 +14,7 @@
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:reader="using:Wino.Core.Domain.Models.Reader"
xmlns:toolkitExt="using:CommunityToolkit.WinUI"
xmlns:x509="using:System.Security.Cryptography.X509Certificates"
x:Name="root"
mc:Ignorable="d">
@@ -65,18 +66,23 @@
Grid.Column="2"
Click="SetAliasPrimary_Click"
CommandParameter="{x:Bind}"
IsChecked="{x:Bind IsPrimary, Mode=OneWay}" />
IsChecked="{x:Bind IsPrimary}" />
<ComboBox
Grid.Column="3"
HorizontalAlignment="Center"
DisplayMemberPath="Subject"
DropDownClosed="SigningCertificateDropDownClosed"
IsEnabled="{x:Bind IsSmimeEncryptionEnabled}"
ItemsSource="{x:Bind Certificates, Mode=OneWay}"
ItemsSource="{x:Bind Certificates}"
PlaceholderText="{x:Bind domain:Translator.SettingsSignatureAndEncryption_SigningCertificatePlaceholder}"
SelectedItem="{Binding SelectedSigningCertificate, Mode=TwoWay}" />
SelectedItem="{x:Bind SelectedSigningCertificate, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate x:DataType="x509:X509Certificate2">
<TextBlock Text="{x:Bind Subject}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<CheckBox
Grid.Column="4"
@@ -65,17 +65,17 @@
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Text="{x:Bind Subject, Mode=OneWay}" />
<TextBlock Grid.Column="1" Text="{x:Bind Subject}" />
<TextBlock
Grid.Column="2"
FontSize="10"
Foreground="Gray"
Text="{x:Bind NotAfter, Mode=OneWay}" />
Text="{x:Bind NotAfter}" />
<TextBlock
Grid.Column="3"
FontSize="10"
Foreground="Gray"
Text="{x:Bind Thumbprint, Mode=OneWay}" />
Text="{x:Bind Thumbprint}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
@@ -146,17 +146,17 @@
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Text="{x:Bind Subject, Mode=OneWay}" />
<TextBlock Grid.Column="1" Text="{x:Bind Subject}" />
<TextBlock
Grid.Column="2"
FontSize="10"
Foreground="Gray"
Text="{x:Bind NotAfter, Mode=OneWay}" />
Text="{x:Bind NotAfter}" />
<TextBlock
Grid.Column="3"
FontSize="10"
Foreground="Gray"
Text="{x:Bind Thumbprint, Mode=OneWay}" />
Text="{x:Bind Thumbprint}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
@@ -21,23 +21,23 @@
</controls:SettingsCard.HeaderIcon>
<controls:SettingsCard.Header>
<StackPanel Spacing="8">
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.GetTranslatedString(NameKey), Mode=OneWay}" />
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.GetTranslatedString(NameKey)}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind domain:Translator.GetTranslatedString(DescriptionKey), Mode=OneWay}"
Text="{x:Bind domain:Translator.GetTranslatedString(DescriptionKey)}"
TextWrapping="WrapWholeWords" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.GetTranslatedString(KeywordsKey), Mode=OneWay}"
Text="{x:Bind domain:Translator.GetTranslatedString(KeywordsKey)}"
TextWrapping="WrapWholeWords" />
<StackPanel
Margin="0,4,0,0"
Orientation="Horizontal"
Spacing="12">
<Button
Command="{x:Bind PurchaseCommand, Mode=OneWay}"
Command="{x:Bind PurchaseCommand}"
CommandParameter="{x:Bind}"
Content="{x:Bind domain:Translator.Buttons_Purchase}"
Style="{StaticResource AccentButtonStyle}" />
@@ -59,7 +59,7 @@
</controls:SettingsExpander.HeaderIcon>
<controls:SettingsExpander.Header>
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.GetTranslatedString(NameKey), Mode=OneWay}" />
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.GetTranslatedString(NameKey)}" />
<Border
Padding="8,2"
Background="{ThemeResource SystemAccentColor}"
@@ -88,7 +88,7 @@
Text="{x:Bind RenewalText, Mode=OneWay}" />
</StackPanel>
</controls:SettingsExpander.Description>
<HyperlinkButton Command="{x:Bind ManageCommand, Mode=OneWay}" Content="{x:Bind domain:Translator.Buttons_Manage}" />
<HyperlinkButton Command="{x:Bind ManageCommand}" Content="{x:Bind domain:Translator.Buttons_Manage}" />
<controls:SettingsExpander.Items>
<controls:SettingsCard HorizontalContentAlignment="Stretch">
<controls:SettingsCard.Header>
@@ -137,16 +137,16 @@
</controls:SettingsCard.HeaderIcon>
<controls:SettingsCard.Header>
<StackPanel Spacing="8">
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.GetTranslatedString(NameKey), Mode=OneWay}" />
<TextBlock FontWeight="SemiBold" Text="{x:Bind domain:Translator.GetTranslatedString(NameKey)}" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource BodyTextBlockStyle}"
Text="{x:Bind domain:Translator.GetTranslatedString(DescriptionKey), Mode=OneWay}"
Text="{x:Bind domain:Translator.GetTranslatedString(DescriptionKey)}"
TextWrapping="WrapWholeWords" />
<TextBlock
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind domain:Translator.GetTranslatedString(KeywordsKey), Mode=OneWay}"
Text="{x:Bind domain:Translator.GetTranslatedString(KeywordsKey)}"
TextWrapping="WrapWholeWords" />
<Border
Padding="12,4"
+66 -1
View File
@@ -23,7 +23,10 @@ using Wino.Core.Domain.Models.Calendar;
using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.MailItem;
using Wino.Core.Domain.Models.Navigation;
using Wino.Calendar.ViewModels;
using Wino.Mail.ViewModels;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.WinUI.ViewModels;
using Wino.Mail.WinUI.Controls;
using Wino.MenuFlyouts;
using Wino.MenuFlyouts.Context;
@@ -49,6 +52,7 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
private WinoApplicationMode? _activeMode;
private bool _isSyncingNavigationViewSelection;
private bool _isSynchronizingVisibleDateRangeCalendar;
private bool _isPreparedForWindowClose;
public WinoAppShell()
{
@@ -98,10 +102,33 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
DeactivateCurrentMode();
if (!_isPreparedForWindowClose)
{
DeactivateCurrentMode();
DetachLifetimeSubscriptions();
}
Bindings.StopTracking();
}
public void PrepareForWindowClose()
{
if (_isPreparedForWindowClose)
return;
_isPreparedForWindowClose = true;
DeactivateAllShellClients();
WeakReferenceMessenger.Default.Unregister<LanguageChanged>(this);
UnregisterRecipients();
DetachLifetimeSubscriptions();
Bindings.StopTracking();
navigationView.MenuItemsSource = null;
CalendarHostListView.ItemsSource = null;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
UpdateNavigationPaneLayout(navigationView.DisplayMode);
@@ -155,6 +182,44 @@ public sealed partial class WinoAppShell : Views.Abstract.WinoAppShellAbstract,
}
}
private void DeactivateAllShellClients()
{
ViewModel.StatePersistenceService.IsReadingMail = false;
ViewModel.StatePersistenceService.IsEventDetailsVisible = false;
ViewModel.MailClient.Deactivate();
ViewModel.CalendarClient.Deactivate();
if (ViewModel.GetClient(WinoApplicationMode.Contacts) is ContactsShellClient contactsClient)
{
contactsClient.PrepareForShellShutdown();
}
if (ViewModel.GetClient(WinoApplicationMode.Settings) is SettingsShellClient settingsClient)
{
settingsClient.PrepareForShellShutdown();
}
if (ViewModel.MailClient is MailAppShellViewModel mailClient)
{
mailClient.PrepareForShellShutdown();
}
if (ViewModel.CalendarClient is CalendarAppShellViewModel calendarClient)
{
calendarClient.PrepareForShellShutdown();
}
}
private void DetachLifetimeSubscriptions()
{
ViewModel.MailClient.PropertyChanged -= MailClientPropertyChanged;
ViewModel.CalendarClient.PropertyChanged -= CalendarClientPropertyChanged;
ViewModel.PropertyChanged -= ViewModelPropertyChanged;
ViewModel.PreferencesService.PreferenceChanged -= PreferencesServiceChanged;
ViewModel.StatePersistenceService.StatePropertyChanged -= StatePersistenceServiceChanged;
}
private void ResetShellModeNavigationState()
{
InnerShellFrame.BackStack.Clear();