Main app aot compatibility.

This commit is contained in:
Burak Kaan Köse
2025-11-14 18:51:48 +01:00
parent ae64094feb
commit b356af8eb4
41 changed files with 220 additions and 327 deletions
+3
View File
@@ -8,6 +8,9 @@ dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4 tab_width = 4
indent_size = 4 indent_size = 4
end_of_line = crlf end_of_line = crlf
[XamlTypeInfo.g.cs]
dotnet_diagnostic.CS0612.severity = none
dotnet_diagnostic.CS0618.severity = none
dotnet_style_coalesce_expression = true:suggestion dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
@@ -1,22 +0,0 @@
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Animation;
using Wino.Views;
namespace Wino.Activation;
internal class DefaultActivationHandler : ActivationHandler<IActivatedEventArgs>
{
protected override Task HandleInternalAsync(IActivatedEventArgs args)
{
(Window.Current.Content as Frame).Navigate(typeof(AppShell), null, new DrillInNavigationTransitionInfo());
return Task.CompletedTask;
}
// Only navigate if Frame content doesn't exist.
protected override bool CanHandleInternal(IActivatedEventArgs args)
=> (Window.Current?.Content as Frame)?.Content == null;
}
@@ -1,67 +0,0 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Animation;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.WinUI.Extensions;
using Wino.Views;
namespace Wino.Activation;
internal class FileActivationHandler : ActivationHandler<FileActivatedEventArgs>
{
private readonly INativeAppService _nativeAppService;
private readonly IMimeFileService _mimeFileService;
private readonly IStatePersistanceService _statePersistanceService;
private readonly INavigationService _winoNavigationService;
public FileActivationHandler(INativeAppService nativeAppService,
IMimeFileService mimeFileService,
IStatePersistanceService statePersistanceService,
INavigationService winoNavigationService)
{
_nativeAppService = nativeAppService;
_mimeFileService = mimeFileService;
_statePersistanceService = statePersistanceService;
_winoNavigationService = winoNavigationService;
}
protected override async Task HandleInternalAsync(FileActivatedEventArgs args)
{
// Always handle the last item passed.
// Multiple files are not supported.
var file = args.Files.Last() as StorageFile;
// Only EML files are supported now.
var fileExtension = Path.GetExtension(file.Path);
if (string.Equals(fileExtension, ".eml", StringComparison.OrdinalIgnoreCase))
{
var fileBytes = await file.ToByteArrayAsync();
var directoryName = Path.GetDirectoryName(file.Path);
var messageInformation = await _mimeFileService.GetMimeMessageInformationAsync(fileBytes, directoryName).ConfigureAwait(false);
if (_nativeAppService.IsAppRunning())
{
// TODO: Activate another Window and go to mail rendering page.
_winoNavigationService.Navigate(WinoPage.MailRenderingPage, messageInformation, NavigationReferenceFrame.RenderingFrame);
}
else
{
_statePersistanceService.ShouldShiftMailRenderingDesign = true;
(Window.Current.Content as Frame).Navigate(typeof(MailRenderingPage), messageInformation, new DrillInNavigationTransitionInfo());
}
}
}
protected override bool CanHandleInternal(FileActivatedEventArgs args) => args.Files.Any();
}
@@ -1,76 +0,0 @@
using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Toolkit.Uwp.Notifications;
using Serilog;
using Windows.ApplicationModel.Activation;
using Wino.Core.Domain;
using Wino.Core.Domain.Interfaces;
using Wino.Mail.WinUI;
using Wino.Messaging.Client.Accounts;
namespace Wino.Activation;
/// <summary>
/// This handler will only handle the toasts that runs on foreground.
/// Background executions are not handled here like mark as read or delete.
/// </summary>
internal class ToastNotificationActivationHandler : ActivationHandler<ToastNotificationActivatedEventArgs>
{
private readonly IMailService _mailService;
private readonly IFolderService _folderService;
private ToastArguments _toastArguments;
public ToastNotificationActivationHandler(IMailService mailService,
IFolderService folderService)
{
_mailService = mailService;
_folderService = folderService;
}
protected override async Task HandleInternalAsync(ToastNotificationActivatedEventArgs args)
{
// Create the mail item navigation event.
// If the app is running, it'll be picked up by the Messenger.
// Otherwise we'll save it and handle it when the shell loads all accounts.
// Parse the mail unique id and perform above actions.
if (Guid.TryParse(_toastArguments[Constants.ToastMailUniqueIdKey], out Guid mailItemUniqueId))
{
var account = await _mailService.GetMailAccountByUniqueIdAsync(mailItemUniqueId).ConfigureAwait(false);
if (account == null) return;
var mailItem = await _mailService.GetSingleMailItemAsync(mailItemUniqueId).ConfigureAwait(false);
if (mailItem == null) return;
var message = new AccountMenuItemExtended(mailItem.AssignedFolder.Id, mailItem);
// Delegate this event to LaunchProtocolService so app shell can pick it up on launch if app doesn't work.
var launchProtocolService = App.Current.Services.GetRequiredService<ILaunchProtocolService>();
launchProtocolService.LaunchParameter = message;
// Send the messsage anyways. Launch protocol service will be ignored if the message is picked up by subscriber shell.
WeakReferenceMessenger.Default.Send(message);
}
}
protected override bool CanHandleInternal(ToastNotificationActivatedEventArgs args)
{
try
{
_toastArguments = ToastArguments.Parse(args.Argument);
return
_toastArguments.Contains(Constants.ToastMailUniqueIdKey) &&
_toastArguments.Contains(Constants.ToastActionKey);
}
catch (Exception ex)
{
Log.Error(ex, "Couldn't handle parsing toast notification arguments for foreground navigate.");
}
return false;
}
}
+7 -2
View File
@@ -75,6 +75,9 @@ public sealed partial class AppShell : AppShellAbstract,
var mailCopies = new List<MailCopy>(); var mailCopies = new List<MailCopy>();
var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
if (dragPackage == null) return;
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
// Extract mail copies from IMailItem. // Extract mail copies from IMailItem.
@@ -116,7 +119,7 @@ public sealed partial class AppShell : AppShellAbstract,
var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage; var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
// Invalid package. // Invalid package.
if (!dragPackage.DraggingMails.Any()) return false; if (dragPackage == null || !dragPackage.DraggingMails.Any()) return false;
// Check whether source and target folder are the same. // Check whether source and target folder are the same.
if (interactingContainer.IsSelected) return false; if (interactingContainer.IsSelected) return false;
@@ -144,6 +147,8 @@ public sealed partial class AppShell : AppShellAbstract,
var draggingFolder = droppedContainer.DataContext as IBaseFolderMenuItem; var draggingFolder = droppedContainer.DataContext as IBaseFolderMenuItem;
if (draggingFolder == null) return;
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move; e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName); e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName);
} }
@@ -235,7 +240,7 @@ public sealed partial class AppShell : AppShellAbstract,
private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) => TopShellContent = ((BasePage)e.Content).ShellContent; private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) => TopShellContent = ((BasePage)e.Content).ShellContent;
partial void OnTopShellContentChanged(UIElement newValue) => WeakReferenceMessenger.Default.Send(new TitleBarShellContentUpdated()); partial void OnTopShellContentChanged(UIElement? newValue) => WeakReferenceMessenger.Default.Send(new TitleBarShellContentUpdated());
private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args) private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args)
{ {
@@ -17,13 +17,13 @@ namespace Wino.Behaviors;
public partial class BindableCommandBarBehavior : Behavior<CommandBar> public partial class BindableCommandBarBehavior : Behavior<CommandBar>
{ {
private readonly IPreferencesService _preferencesService = App.Current.Services.GetService<IPreferencesService>(); private readonly IPreferencesService? _preferencesService = App.Current.Services.GetService<IPreferencesService>();
public static readonly DependencyProperty PrimaryCommandsProperty = DependencyProperty.Register( public static readonly DependencyProperty PrimaryCommandsProperty = DependencyProperty.Register(
"PrimaryCommands", typeof(object), typeof(BindableCommandBarBehavior), "PrimaryCommands", typeof(object), typeof(BindableCommandBarBehavior),
new PropertyMetadata(null, UpdateCommands)); new PropertyMetadata(null, UpdateCommands));
[GeneratedDependencyProperty] [GeneratedDependencyProperty]
public partial ICommand ItemClickedCommand { get; set; } public partial ICommand? ItemClickedCommand { get; set; }
public object PrimaryCommands public object PrimaryCommands
{ {
@@ -88,7 +88,7 @@ public partial class BindableCommandBarBehavior : Behavior<CommandBar>
{ {
if (command is MailOperationMenuItem mailOperationMenuItem) if (command is MailOperationMenuItem mailOperationMenuItem)
{ {
ICommandBarElement menuItem = null; ICommandBarElement? menuItem = null;
if (mailOperationMenuItem.Operation == Core.Domain.Enums.MailOperation.Seperator) if (mailOperationMenuItem.Operation == Core.Domain.Enums.MailOperation.Seperator)
{ {
@@ -97,13 +97,17 @@ public partial class BindableCommandBarBehavior : Behavior<CommandBar>
else else
{ {
var label = XamlHelpers.GetOperationString(mailOperationMenuItem.Operation); var label = XamlHelpers.GetOperationString(mailOperationMenuItem.Operation);
var labelPosition = string.IsNullOrWhiteSpace(label) || !_preferencesService.IsShowActionLabelsEnabled ? var labelPosition = string.IsNullOrWhiteSpace(label) || _preferencesService == null || !_preferencesService.IsShowActionLabelsEnabled ?
CommandBarLabelPosition.Collapsed : CommandBarLabelPosition.Default; CommandBarLabelPosition.Collapsed : CommandBarLabelPosition.Default;
var iconGlyph = XamlHelpers.GetWinoIconGlyph(mailOperationMenuItem.Operation);
var glyphValue = ControlConstants.WinoIconFontDictionary.TryGetValue(iconGlyph, out var glyph) ? glyph : string.Empty;
menuItem = new AppBarButton menuItem = new AppBarButton
{ {
Width = double.NaN, Width = double.NaN,
MinWidth = 40, MinWidth = 40,
Icon = new WinoFontIcon() { Glyph = ControlConstants.WinoIconFontDictionary[XamlHelpers.GetWinoIconGlyph(mailOperationMenuItem.Operation)] }, Icon = new WinoFontIcon() { Glyph = glyphValue },
Label = label, Label = label,
LabelPosition = labelPosition, LabelPosition = labelPosition,
DataContext = mailOperationMenuItem, DataContext = mailOperationMenuItem,
@@ -162,7 +166,7 @@ public partial class BindableCommandBarBehavior : Behavior<CommandBar>
UpdatePrimaryCommands(); UpdatePrimaryCommands();
} }
private void PrimaryCommandsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) private void PrimaryCommandsCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{ {
UpdatePrimaryCommands(); UpdatePrimaryCommands();
} }
@@ -58,7 +58,7 @@ public class CreateMailNavigationItemBehavior : Behavior<WinoNavigationViewItem>
} }
} }
private void MenuCollectionUpdated(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) private void MenuCollectionUpdated(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{ {
ManageAccounts(); ManageAccounts();
} }
@@ -28,8 +28,8 @@ public partial class AccountNavigationItem : WinoNavigationViewItem
private const string PART_NavigationViewItemMenuItemsHost = "NavigationViewItemMenuItemsHost"; private const string PART_NavigationViewItemMenuItemsHost = "NavigationViewItemMenuItemsHost";
private const string PART_SelectionIndicator = "CustomSelectionIndicator"; private const string PART_SelectionIndicator = "CustomSelectionIndicator";
private ItemsRepeater _itemsRepeater; private ItemsRepeater _itemsRepeater = null!;
private Microsoft.UI.Xaml.Shapes.Rectangle _selectionIndicator; private Microsoft.UI.Xaml.Shapes.Rectangle _selectionIndicator = null!;
public AccountNavigationItem() public AccountNavigationItem()
{ {
@@ -40,8 +40,8 @@ public partial class AccountNavigationItem : WinoNavigationViewItem
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
_itemsRepeater = GetTemplateChild(PART_NavigationViewItemMenuItemsHost) as ItemsRepeater; _itemsRepeater = (GetTemplateChild(PART_NavigationViewItemMenuItemsHost) as ItemsRepeater)!;
_selectionIndicator = GetTemplateChild(PART_SelectionIndicator) as Microsoft.UI.Xaml.Shapes.Rectangle; _selectionIndicator = (GetTemplateChild(PART_SelectionIndicator) as Microsoft.UI.Xaml.Shapes.Rectangle)!;
UpdateSelectionBorder(); UpdateSelectionBorder();
} }
@@ -15,7 +15,7 @@ public partial class WinoItemsView : ItemsView
private ScrollView? _internalScrollView; private ScrollView? _internalScrollView;
[GeneratedDependencyProperty] [GeneratedDependencyProperty]
public partial ICommand LoadMoreCommand { get; set; } public partial ICommand? LoadMoreCommand { get; set; }
public IEnumerable<object>? CastedItemsSource => ItemsSource as IEnumerable<object>; public IEnumerable<object>? CastedItemsSource => ItemsSource as IEnumerable<object>;
+28 -16
View File
@@ -60,13 +60,13 @@ public partial class ImagePreviewControl : Control
#endregion #endregion
private Ellipse Ellipse; private Ellipse Ellipse = null!;
private Grid InitialsGrid; private Grid InitialsGrid = null!;
private TextBlock InitialsTextblock; private TextBlock InitialsTextblock = null!;
private Image KnownHostImage; private Image KnownHostImage = null!;
private Border FaviconSquircle; private Border FaviconSquircle = null!;
private Image FaviconImage; private Image FaviconImage = null!;
private CancellationTokenSource contactPictureLoadingCancellationTokenSource; private CancellationTokenSource contactPictureLoadingCancellationTokenSource = null!;
public ImagePreviewControl() public ImagePreviewControl()
{ {
@@ -77,12 +77,12 @@ public partial class ImagePreviewControl : Control
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
InitialsGrid = GetTemplateChild(PART_EllipseInitialsGrid) as Grid; InitialsGrid = (GetTemplateChild(PART_EllipseInitialsGrid) as Grid)!;
InitialsTextblock = GetTemplateChild(PART_InitialsTextBlock) as TextBlock; InitialsTextblock = (GetTemplateChild(PART_InitialsTextBlock) as TextBlock)!;
KnownHostImage = GetTemplateChild(PART_KnownHostImage) as Image; KnownHostImage = (GetTemplateChild(PART_KnownHostImage) as Image)!;
Ellipse = GetTemplateChild(PART_Ellipse) as Ellipse; Ellipse = (GetTemplateChild(PART_Ellipse) as Ellipse)!;
FaviconSquircle = GetTemplateChild(PART_FaviconSquircle) as Border; FaviconSquircle = (GetTemplateChild(PART_FaviconSquircle) as Border)!;
FaviconImage = GetTemplateChild(PART_FaviconImage) as Image; FaviconImage = (GetTemplateChild(PART_FaviconImage) as Image)!;
UpdateInformation(); UpdateInformation();
} }
@@ -101,7 +101,7 @@ public partial class ImagePreviewControl : Control
// Cancel active image loading if exists. // Cancel active image loading if exists.
if (!contactPictureLoadingCancellationTokenSource?.IsCancellationRequested ?? false) if (!contactPictureLoadingCancellationTokenSource?.IsCancellationRequested ?? false)
{ {
contactPictureLoadingCancellationTokenSource.Cancel(); contactPictureLoadingCancellationTokenSource!.Cancel();
} }
string contactPicture = SenderContactPicture; string contactPicture = SenderContactPicture;
@@ -120,7 +120,9 @@ public partial class ImagePreviewControl : Control
{ {
// Show favicon in squircle // Show favicon in squircle
FaviconSquircle.Visibility = Visibility.Visible; FaviconSquircle.Visibility = Visibility.Visible;
if (InitialsGrid != null)
InitialsGrid.Visibility = Visibility.Collapsed; InitialsGrid.Visibility = Visibility.Collapsed;
if (KnownHostImage != null)
KnownHostImage.Visibility = Visibility.Collapsed; KnownHostImage.Visibility = Visibility.Collapsed;
var bitmapImage = await GetBitmapImageAsync(contactPicture); var bitmapImage = await GetBitmapImageAsync(contactPicture);
@@ -133,8 +135,11 @@ public partial class ImagePreviewControl : Control
else else
{ {
// Show normal avatar (tondo) // Show normal avatar (tondo)
if (FaviconSquircle != null)
FaviconSquircle.Visibility = Visibility.Collapsed; FaviconSquircle.Visibility = Visibility.Collapsed;
if (KnownHostImage != null)
KnownHostImage.Visibility = Visibility.Collapsed; KnownHostImage.Visibility = Visibility.Collapsed;
if (InitialsGrid != null)
InitialsGrid.Visibility = Visibility.Visible; InitialsGrid.Visibility = Visibility.Visible;
contactPictureLoadingCancellationTokenSource = new CancellationTokenSource(); contactPictureLoadingCancellationTokenSource = new CancellationTokenSource();
try try
@@ -145,7 +150,9 @@ public partial class ImagePreviewControl : Control
{ {
if (!contactPictureLoadingCancellationTokenSource?.Token.IsCancellationRequested ?? false) if (!contactPictureLoadingCancellationTokenSource?.Token.IsCancellationRequested ?? false)
{ {
if (Ellipse != null)
Ellipse.Fill = brush; Ellipse.Fill = brush;
if (InitialsTextblock != null)
InitialsTextblock.Text = string.Empty; InitialsTextblock.Text = string.Empty;
} }
} }
@@ -158,19 +165,24 @@ public partial class ImagePreviewControl : Control
} }
else else
{ {
if (FaviconSquircle != null)
FaviconSquircle.Visibility = Visibility.Collapsed; FaviconSquircle.Visibility = Visibility.Collapsed;
if (KnownHostImage != null)
KnownHostImage.Visibility = Visibility.Collapsed; KnownHostImage.Visibility = Visibility.Collapsed;
if (InitialsGrid != null)
InitialsGrid.Visibility = Visibility.Visible; InitialsGrid.Visibility = Visibility.Visible;
var colorHash = new ColorHash(); var colorHash = new ColorHash();
var rgb = colorHash.Rgb(FromAddress); var rgb = colorHash.Rgb(FromAddress);
if (Ellipse != null)
Ellipse.Fill = new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B)); Ellipse.Fill = new SolidColorBrush(Color.FromArgb(rgb.A, rgb.R, rgb.G, rgb.B));
if (InitialsTextblock != null)
InitialsTextblock.Text = ExtractInitialsFromName(FromName); InitialsTextblock.Text = ExtractInitialsFromName(FromName);
} }
} }
private static async Task<ImageBrush> GetContactImageBrushAsync(string base64) private static async Task<ImageBrush?> GetContactImageBrushAsync(string base64)
{ {
// Load the image from base64 string. // Load the image from base64 string.
@@ -181,7 +193,7 @@ public partial class ImagePreviewControl : Control
return new ImageBrush() { ImageSource = bitmapImage }; return new ImageBrush() { ImageSource = bitmapImage };
} }
private static async Task<BitmapImage> GetBitmapImageAsync(string base64) private static async Task<BitmapImage?> GetBitmapImageAsync(string base64)
{ {
try try
{ {
@@ -15,6 +15,6 @@ public partial class WinoMailItemContainerStyleSelector : StyleSelector
if (item is ThreadMailItemViewModel) if (item is ThreadMailItemViewModel)
return ThreadStyle ?? throw new Exception($"Missing style for {nameof(ThreadMailItemViewModel)}"); return ThreadStyle ?? throw new Exception($"Missing style for {nameof(ThreadMailItemViewModel)}");
return null; return base.SelectStyleCore(item, container);
} }
} }
@@ -19,9 +19,9 @@ namespace Wino.Mail.Controls;
public sealed partial class WebViewEditorControl : Control, IDisposable public sealed partial class WebViewEditorControl : Control, IDisposable
{ {
private readonly INativeAppService _nativeAppService = App.Current.Services.GetService<INativeAppService>(); private readonly INativeAppService _nativeAppService = App.Current.Services.GetService<INativeAppService>()!;
private readonly IFontService _fontService = App.Current.Services.GetService<IFontService>(); private readonly IFontService _fontService = App.Current.Services.GetService<IFontService>()!;
private readonly IPreferencesService _preferencesService = App.Current.Services.GetService<IPreferencesService>(); private readonly IPreferencesService _preferencesService = App.Current.Services.GetService<IPreferencesService>()!;
[GeneratedDependencyProperty] [GeneratedDependencyProperty]
public partial bool IsEditorDarkMode { get; set; } public partial bool IsEditorDarkMode { get; set; }
@@ -131,7 +131,7 @@ public sealed partial class WebViewEditorControl : Control, IDisposable
} }
private const string PART_WebView = "WebView"; private const string PART_WebView = "WebView";
private WebView2 _chromium; private WebView2 _chromium = null!;
private bool _disposedValue; private bool _disposedValue;
private readonly TaskCompletionSource<bool> _domLoadedTask = new(); private readonly TaskCompletionSource<bool> _domLoadedTask = new();
@@ -146,7 +146,7 @@ public sealed partial class WebViewEditorControl : Control, IDisposable
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
_chromium = GetTemplateChild(PART_WebView) as WebView2; _chromium = (GetTemplateChild(PART_WebView) as WebView2)!;
await InitializeComponent(); await InitializeComponent();
} }
@@ -175,7 +175,7 @@ public sealed partial class WebViewEditorControl : Control, IDisposable
IsEditorDarkMode = !IsEditorDarkMode; IsEditorDarkMode = !IsEditorDarkMode;
} }
public async Task<string> GetHtmlBodyAsync() public async Task<string?> GetHtmlBodyAsync()
{ {
var editorContent = await _chromium.ExecuteScriptFunctionSafeAsync("GetHTMLContent"); var editorContent = await _chromium.ExecuteScriptFunctionSafeAsync("GetHTMLContent");
@@ -273,6 +273,8 @@ public sealed partial class WebViewEditorControl : Control, IDisposable
{ {
var change = JsonSerializer.Deserialize(args.WebMessageAsJson, DomainModelsJsonContext.Default.WebViewMessage); var change = JsonSerializer.Deserialize(args.WebMessageAsJson, DomainModelsJsonContext.Default.WebViewMessage);
if (change == null) return;
if (change.Type == "bold") if (change.Type == "bold")
{ {
_isEditorBoldInternal = change.Value == "true"; _isEditorBoldInternal = change.Value == "true";
+6 -6
View File
@@ -13,9 +13,9 @@ public partial class WinoExpander : Control
private const string PART_ContentAreaWrapper = "ContentAreaWrapper"; private const string PART_ContentAreaWrapper = "ContentAreaWrapper";
private const string PART_ContentArea = "ContentArea"; private const string PART_ContentArea = "ContentArea";
private ContentControl HeaderGrid; private ContentControl HeaderGrid = null!;
private ContentControl ContentArea; private ContentControl ContentArea = null!;
private Grid ContentAreaWrapper; private Grid ContentAreaWrapper = null!;
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null)); public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(nameof(Header), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null));
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null)); public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(nameof(Content), typeof(UIElement), typeof(WinoExpander), new PropertyMetadata(null));
@@ -50,9 +50,9 @@ public partial class WinoExpander : Control
{ {
base.OnApplyTemplate(); base.OnApplyTemplate();
HeaderGrid = GetTemplateChild(PART_HeaderGrid) as ContentControl; HeaderGrid = (GetTemplateChild(PART_HeaderGrid) as ContentControl)!;
ContentAreaWrapper = GetTemplateChild(PART_ContentAreaWrapper) as Grid; ContentAreaWrapper = (GetTemplateChild(PART_ContentAreaWrapper) as Grid)!;
ContentArea = GetTemplateChild(PART_ContentArea) as ContentControl; ContentArea = (GetTemplateChild(PART_ContentArea) as ContentControl)!;
Guard.IsNotNull(HeaderGrid, nameof(HeaderGrid)); Guard.IsNotNull(HeaderGrid, nameof(HeaderGrid));
Guard.IsNotNull(ContentAreaWrapper, nameof(ContentAreaWrapper)); Guard.IsNotNull(ContentAreaWrapper, nameof(ContentAreaWrapper));
@@ -60,7 +60,7 @@ public partial class WinoSwipeControlItems : SwipeItems
this.Add(swipeItem); this.Add(swipeItem);
} }
private SwipeItem GetSwipeItem(MailOperation operation) private SwipeItem? GetSwipeItem(MailOperation operation)
{ {
if (MailItem == null) return null; if (MailItem == null) return null;
@@ -72,18 +72,18 @@ public partial class WinoSwipeControlItems : SwipeItems
{ {
var singleItem = MailItem as MailItemViewModel; var singleItem = MailItem as MailItemViewModel;
if (operation == MailOperation.MarkAsRead && singleItem.IsRead) if (singleItem != null && operation == MailOperation.MarkAsRead && singleItem.IsRead)
finalOperation = MailOperation.MarkAsUnread; finalOperation = MailOperation.MarkAsUnread;
else if (operation == MailOperation.MarkAsUnread && !singleItem.IsRead) else if (singleItem != null && operation == MailOperation.MarkAsUnread && !singleItem.IsRead)
finalOperation = MailOperation.MarkAsRead; finalOperation = MailOperation.MarkAsRead;
} }
else else
{ {
var threadItem = MailItem as ThreadMailItemViewModel; var threadItem = MailItem as ThreadMailItemViewModel;
if (operation == MailOperation.MarkAsRead && threadItem.ThreadEmails.All(a => a.IsRead)) if (threadItem != null && operation == MailOperation.MarkAsRead && threadItem.ThreadEmails.All(a => a.IsRead))
finalOperation = MailOperation.MarkAsUnread; finalOperation = MailOperation.MarkAsUnread;
else if (operation == MailOperation.MarkAsUnread && threadItem.ThreadEmails.All(a => !a.IsRead)) else if (threadItem != null && operation == MailOperation.MarkAsUnread && threadItem.ThreadEmails.All(a => !a.IsRead))
finalOperation = MailOperation.MarkAsRead; finalOperation = MailOperation.MarkAsRead;
} }
@@ -114,18 +114,21 @@ public partial class WinoSwipeControlItems : SwipeItems
{ {
var singleItem = MailItem as MailItemViewModel; var singleItem = MailItem as MailItemViewModel;
if (singleItem != null)
{
if (SwipeOperation == MailOperation.MarkAsRead && singleItem.IsRead) if (SwipeOperation == MailOperation.MarkAsRead && singleItem.IsRead)
finalOperation = MailOperation.MarkAsUnread; finalOperation = MailOperation.MarkAsUnread;
else if (SwipeOperation == MailOperation.MarkAsUnread && !singleItem.IsRead) else if (SwipeOperation == MailOperation.MarkAsUnread && !singleItem.IsRead)
finalOperation = MailOperation.MarkAsRead; finalOperation = MailOperation.MarkAsRead;
} }
}
else else
{ {
var threadItem = MailItem as ThreadMailItemViewModel; var threadItem = MailItem as ThreadMailItemViewModel;
if (SwipeOperation == MailOperation.MarkAsRead && threadItem.ThreadEmails.All(a => a.IsRead)) if (threadItem != null && SwipeOperation == MailOperation.MarkAsRead && threadItem.ThreadEmails.All(a => a.IsRead))
finalOperation = MailOperation.MarkAsUnread; finalOperation = MailOperation.MarkAsUnread;
else if (SwipeOperation == MailOperation.MarkAsUnread && threadItem.ThreadEmails.All(a => !a.IsRead)) else if (threadItem != null && SwipeOperation == MailOperation.MarkAsUnread && threadItem.ThreadEmails.All(a => !a.IsRead))
finalOperation = MailOperation.MarkAsRead; finalOperation = MailOperation.MarkAsRead;
} }
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel; using System;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
@@ -9,16 +10,16 @@ namespace Wino.Dialogs;
public sealed partial class AccountReorderDialog : ContentDialog public sealed partial class AccountReorderDialog : ContentDialog
{ {
public ObservableCollection<IAccountProviderDetailViewModel> Accounts { get; } public ObservableCollection<IAccountProviderDetailViewModel> Accounts { get; set; } = null!;
private int count; private int count;
private bool isOrdering = false; private bool isOrdering = false;
private readonly IAccountService _accountService = App.Current.Services.GetService<IAccountService>(); private readonly IAccountService? _accountService = App.Current.Services.GetService<IAccountService>();
public AccountReorderDialog(ObservableCollection<IAccountProviderDetailViewModel> accounts) public AccountReorderDialog(ObservableCollection<IAccountProviderDetailViewModel>? accounts)
{ {
Accounts = accounts; Accounts = accounts ?? throw new ArgumentNullException(nameof(accounts));
count = accounts.Count; count = accounts.Count;
@@ -33,7 +34,7 @@ public sealed partial class AccountReorderDialog : ContentDialog
private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => Accounts.CollectionChanged -= AccountsChanged; private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args) => Accounts.CollectionChanged -= AccountsChanged;
private async void AccountsChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) private async void AccountsChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{ {
if (count - 1 == Accounts.Count) if (count - 1 == Accounts.Count)
isOrdering = true; isOrdering = true;
@@ -44,6 +45,7 @@ public sealed partial class AccountReorderDialog : ContentDialog
var dict = Accounts.ToDictionary(a => a.StartupEntityId, a => Accounts.IndexOf(a)); var dict = Accounts.ToDictionary(a => a.StartupEntityId, a => Accounts.IndexOf(a));
if (_accountService != null)
await _accountService.UpdateAccountOrdersAsync(dict); await _accountService.UpdateAccountOrdersAsync(dict);
isOrdering = false; isOrdering = false;
@@ -7,7 +7,7 @@ namespace Wino.Dialogs;
public sealed partial class CreateAccountAliasDialog : ContentDialog, ICreateAccountAliasDialog public sealed partial class CreateAccountAliasDialog : ContentDialog, ICreateAccountAliasDialog
{ {
public MailAccountAlias CreatedAccountAlias { get; set; } public MailAccountAlias CreatedAccountAlias { get; set; } = null!;
public CreateAccountAliasDialog() public CreateAccountAliasDialog()
{ {
InitializeComponent(); InitializeComponent();
@@ -25,7 +25,7 @@ public sealed partial class KeyboardShortcutDialog : ContentDialog
{ {
InitializeComponent(); InitializeComponent();
AvailableMailOperations = GetAvailableMailOperations(); AvailableMailOperations = GetAvailableMailOperations();
SelectedMailOperation = AvailableMailOperations.FirstOrDefault(); SelectedMailOperation = AvailableMailOperations.FirstOrDefault()!;
} }
public KeyboardShortcutDialog(KeyboardShortcut existingShortcut) : this() public KeyboardShortcutDialog(KeyboardShortcut existingShortcut) : this()
@@ -33,7 +33,7 @@ public sealed partial class KeyboardShortcutDialog : ContentDialog
if (existingShortcut != null) if (existingShortcut != null)
{ {
KeyInputTextBox.Text = existingShortcut.Key; KeyInputTextBox.Text = existingShortcut.Key;
SelectedMailOperation = AvailableMailOperations.FirstOrDefault(x => x.Operation == existingShortcut.MailOperation); SelectedMailOperation = AvailableMailOperations.FirstOrDefault(x => x.Operation == existingShortcut.MailOperation)!;
var modifiers = existingShortcut.ModifierKeys; var modifiers = existingShortcut.ModifierKeys;
IsControlPressed = modifiers.HasFlag(ModifierKeys.Control); IsControlPressed = modifiers.HasFlag(ModifierKeys.Control);
@@ -8,8 +8,8 @@ namespace Wino.Mail.Dialogs;
public sealed partial class MessageSourceDialog : ContentDialog public sealed partial class MessageSourceDialog : ContentDialog
{ {
private readonly IClipboardService _clipboardService = App.Current.Services.GetService<IClipboardService>(); private readonly IClipboardService? _clipboardService = App.Current.Services.GetService<IClipboardService>();
public string MessageSource { get; set; } public string MessageSource { get; set; } = string.Empty;
public bool Copied { get; set; } public bool Copied { get; set; }
public MessageSourceDialog() public MessageSourceDialog()
{ {
@@ -18,7 +18,7 @@ public sealed partial class MessageSourceDialog : ContentDialog
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args) private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{ {
_clipboardService.CopyClipboardAsync(MessageSource); _clipboardService!.CopyClipboardAsync(MessageSource);
Copied = true; Copied = true;
} }
} }
@@ -17,7 +17,7 @@ public sealed partial class MoveMailDialog : ContentDialog
public static readonly DependencyProperty SelectedFolderProperty = DependencyProperty.Register(nameof(SelectedFolder), typeof(IMailItemFolder), typeof(MoveMailDialog), new PropertyMetadata(null, OnSelectedFolderChanged)); public static readonly DependencyProperty SelectedFolderProperty = DependencyProperty.Register(nameof(SelectedFolder), typeof(IMailItemFolder), typeof(MoveMailDialog), new PropertyMetadata(null, OnSelectedFolderChanged));
public List<IMailItemFolder> FolderList { get; set; } public List<IMailItemFolder> FolderList { get; set; } = [];
public MoveMailDialog(List<IMailItemFolder> allFolders) public MoveMailDialog(List<IMailItemFolder> allFolders)
{ {
@@ -58,7 +58,7 @@ public sealed partial class MoveMailDialog : ContentDialog
container.IsExpanded = !container.IsExpanded; container.IsExpanded = !container.IsExpanded;
} }
} }
SelectedFolder = null; SelectedFolder = null!;
} }
else else
{ {
@@ -43,7 +43,7 @@ public sealed partial class NewImapSetupDialog : ContentDialog,
public void Complete(bool cancel) public void Complete(bool cancel)
{ {
if (!_getServerInfoTaskCompletionSource.Task.IsCompleted) if (!_getServerInfoTaskCompletionSource.Task.IsCompleted)
_getServerInfoTaskCompletionSource.TrySetResult(null); _getServerInfoTaskCompletionSource.TrySetResult(null!);
isDismissRequested = true; isDismissRequested = true;
@@ -8,7 +8,7 @@ namespace Wino.Dialogs;
public sealed partial class SignatureEditorDialog : ContentDialog public sealed partial class SignatureEditorDialog : ContentDialog
{ {
public AccountSignature Result; public AccountSignature Result = null!;
public SignatureEditorDialog() public SignatureEditorDialog()
{ {
@@ -51,7 +51,7 @@ public sealed partial class SignatureEditorDialog : ContentDialog
private async void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) private async void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{ {
var newSignature = Regex.Unescape(await WebViewEditor.GetHtmlBodyAsync()); var newSignature = Regex.Unescape((await WebViewEditor.GetHtmlBodyAsync())!);
if (Result == null) if (Result == null)
{ {
@@ -5,7 +5,6 @@ using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain; using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Exceptions;
using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.Folders;
namespace Wino.Dialogs; namespace Wino.Dialogs;
@@ -14,14 +13,14 @@ public sealed partial class SystemFolderConfigurationDialog : ContentDialog
{ {
private bool canDismissDialog = false; private bool canDismissDialog = false;
public SystemFolderConfiguration Configuration { get; set; } public SystemFolderConfiguration? Configuration { get; set; }
public List<MailItemFolder> AvailableFolders { get; } public List<MailItemFolder> AvailableFolders { get; }
public MailItemFolder Sent { get; set; } public MailItemFolder? Sent { get; set; }
public MailItemFolder Draft { get; set; } public MailItemFolder? Draft { get; set; }
public MailItemFolder Archive { get; set; } public MailItemFolder? Archive { get; set; }
public MailItemFolder Junk { get; set; } public MailItemFolder? Junk { get; set; }
public MailItemFolder Trash { get; set; } public MailItemFolder? Trash { get; set; }
public SystemFolderConfigurationDialog(List<MailItemFolder> availableFolders) public SystemFolderConfigurationDialog(List<MailItemFolder> availableFolders)
{ {
@@ -29,11 +28,11 @@ public sealed partial class SystemFolderConfigurationDialog : ContentDialog
AvailableFolders = availableFolders; AvailableFolders = availableFolders;
Sent = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Sent); Sent = AvailableFolders.Find(a => a.SpecialFolderType == SpecialFolderType.Sent);
Draft = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Draft); Draft = AvailableFolders.Find(a => a.SpecialFolderType == SpecialFolderType.Draft);
Archive = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Archive); Archive = AvailableFolders.Find(a => a.SpecialFolderType == SpecialFolderType.Archive);
Junk = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Junk); Junk = AvailableFolders.Find(a => a.SpecialFolderType == SpecialFolderType.Junk);
Trash = AvailableFolders.Find(a => a.SpecialFolderType == Core.Domain.Enums.SpecialFolderType.Deleted); Trash = AvailableFolders.Find(a => a.SpecialFolderType == SpecialFolderType.Deleted);
} }
private void DialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args) private void DialogClosing(ContentDialog sender, ContentDialogClosingEventArgs args)
@@ -46,21 +45,21 @@ public sealed partial class SystemFolderConfigurationDialog : ContentDialog
private void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args) private void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{ {
ValidationErrorTextBlock.Text = string.Empty; ValidationErrorTextBlock!.Text = string.Empty;
var allSpecialFolders = new List<MailItemFolder>() var allSpecialFolders = new List<MailItemFolder?>()
{ {
Sent, Draft, Archive, Trash, Junk Sent, Draft, Archive, Trash, Junk
}; };
if (allSpecialFolders.Any(a => a != null && a.SpecialFolderType == SpecialFolderType.Inbox)) if (allSpecialFolders.Any(a => a != null && a.SpecialFolderType == SpecialFolderType.Inbox))
ValidationErrorTextBlock.Text = Translator.SystemFolderConfigDialogValidation_InboxSelected; ValidationErrorTextBlock!.Text = Translator.SystemFolderConfigDialogValidation_InboxSelected;
if (new HashSet<Guid>(allSpecialFolders.Where(a => a != null).Select(x => x.Id)).Count != allSpecialFolders.Where(a => a != null).Count()) if (new HashSet<Guid>(allSpecialFolders.Where(a => a != null).Select(x => x!.Id)).Count != allSpecialFolders.Where(a => a != null).Count())
ValidationErrorTextBlock.Text = Translator.SystemFolderConfigDialogValidation_DuplicateSystemFolders; ValidationErrorTextBlock!.Text = Translator.SystemFolderConfigDialogValidation_DuplicateSystemFolders;
// Check if we can save. // Check if we can save.
if (string.IsNullOrEmpty(ValidationErrorTextBlock.Text)) if (string.IsNullOrEmpty(ValidationErrorTextBlock!.Text))
{ {
var configuration = new SystemFolderConfiguration(Sent, Draft, Archive, Trash, Junk); var configuration = new SystemFolderConfiguration(Sent, Draft, Archive, Trash, Junk);
@@ -110,6 +110,7 @@ public partial class FilterMenuFlyout : MenuFlyout
var optionModel = button.Tag as SortingOption; var optionModel = button.Tag as SortingOption;
if (optionModel != null)
SelectSortingOption(optionModel); SelectSortingOption(optionModel);
} }
} }
@@ -124,6 +125,7 @@ public partial class FilterMenuFlyout : MenuFlyout
var optionModel = button.Tag as FilterOption; var optionModel = button.Tag as FilterOption;
if (optionModel != null)
SelectFilterOption(optionModel); SelectFilterOption(optionModel);
} }
} }
@@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Windows.Foundation;
using Microsoft.UI.Xaml; using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Windows.Foundation;
using Wino.Core.Domain.Entities.Mail; using Wino.Core.Domain.Entities.Mail;
namespace Wino.MenuFlyouts; namespace Wino.MenuFlyouts;
@@ -15,7 +15,7 @@ public class MoveButtonMenuItemClickedEventArgs
public partial class MoveButtonFlyout : MenuFlyout public partial class MoveButtonFlyout : MenuFlyout
{ {
public event TypedEventHandler<MoveButtonFlyout, MoveButtonMenuItemClickedEventArgs> MenuItemClick; public event TypedEventHandler<MoveButtonFlyout, MoveButtonMenuItemClickedEventArgs> MenuItemClick = delegate { };
public static readonly DependencyProperty FoldersProperty = DependencyProperty.Register(nameof(Folders), typeof(List<MailItemFolder>), typeof(MoveButtonFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnFoldersChanged))); public static readonly DependencyProperty FoldersProperty = DependencyProperty.Register(nameof(Folders), typeof(List<MailItemFolder>), typeof(MoveButtonFlyout), new PropertyMetadata(null, new PropertyChangedCallback(OnFoldersChanged)));
public List<MailItemFolder> Folders public List<MailItemFolder> Folders
@@ -66,7 +66,7 @@ public partial class MoveButtonFlyout : MenuFlyout
private void MenuItemClicked(object sender, RoutedEventArgs e) private void MenuItemClicked(object sender, RoutedEventArgs e)
{ {
var clickedFolder = (sender as MenuFlyoutItem).Tag as MailItemFolder; var clickedFolder = ((MenuFlyoutItem)sender).Tag as MailItemFolder ?? throw new InvalidOperationException("Clicked folder is null.");
MenuItemClick?.Invoke(this, new MoveButtonMenuItemClickedEventArgs() MenuItemClick?.Invoke(this, new MoveButtonMenuItemClickedEventArgs()
{ {
@@ -7,7 +7,7 @@ namespace Wino.MenuFlyouts;
public partial class WinoOperationFlyout<TActionType> : MenuFlyout, IDisposable where TActionType : class public partial class WinoOperationFlyout<TActionType> : MenuFlyout, IDisposable where TActionType : class
{ {
public TActionType ClickedOperation { get; set; } public TActionType ClickedOperation { get; set; } = null!;
protected readonly IEnumerable<TActionType> AvailableActions; protected readonly IEnumerable<TActionType> AvailableActions;
@@ -1,4 +1,5 @@
using Microsoft.UI.Xaml; using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Wino.Core.ViewModels.Data; using Wino.Core.ViewModels.Data;
@@ -6,14 +7,14 @@ namespace Wino.Selectors;
public partial class AccountProviderViewModelTemplateSelector : DataTemplateSelector public partial class AccountProviderViewModelTemplateSelector : DataTemplateSelector
{ {
public DataTemplate RootAccountTemplate { get; set; } public DataTemplate? RootAccountTemplate { get; set; }
public DataTemplate MergedAccountTemplate { get; set; } public DataTemplate? MergedAccountTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
if (item is MergedAccountProviderDetailViewModel) if (item is MergedAccountProviderDetailViewModel)
return MergedAccountTemplate; return MergedAccountTemplate ?? throw new ArgumentException(nameof(MergedAccountTemplate));
else else
return RootAccountTemplate; return RootAccountTemplate ?? throw new ArgumentException(nameof(RootAccountTemplate));
} }
} }
@@ -1,4 +1,5 @@
using Microsoft.UI.Xaml; using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Wino.Core.ViewModels.Data; using Wino.Core.ViewModels.Data;
@@ -6,16 +7,16 @@ namespace Wino.Selectors;
public partial class AccountReorderTemplateSelector : DataTemplateSelector public partial class AccountReorderTemplateSelector : DataTemplateSelector
{ {
public DataTemplate MergedAccountReorderTemplate { get; set; } public DataTemplate? MergedAccountReorderTemplate { get; set; }
public DataTemplate RootAccountReorderTemplate { get; set; } public DataTemplate? RootAccountReorderTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
if (item is MergedAccountProviderDetailViewModel) if (item is MergedAccountProviderDetailViewModel)
{ {
return MergedAccountReorderTemplate; return MergedAccountReorderTemplate ?? throw new ArgumentException(nameof(MergedAccountReorderTemplate));
} }
return RootAccountReorderTemplate; return RootAccountReorderTemplate ?? throw new ArgumentException(nameof(RootAccountReorderTemplate));
} }
} }
@@ -1,4 +1,5 @@
using Microsoft.UI.Xaml; using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Controls;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
@@ -9,9 +10,9 @@ namespace Wino.Selectors;
/// </summary> /// </summary>
public partial class MailItemDisplayModePreviewTemplateSelector : DataTemplateSelector public partial class MailItemDisplayModePreviewTemplateSelector : DataTemplateSelector
{ {
public DataTemplate CompactTemplate { get; set; } public DataTemplate? CompactTemplate { get; set; }
public DataTemplate MediumTemplate { get; set; } public DataTemplate? MediumTemplate { get; set; }
public DataTemplate SpaciousTemplate { get; set; } public DataTemplate? SpaciousTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{ {
@@ -20,11 +21,11 @@ public partial class MailItemDisplayModePreviewTemplateSelector : DataTemplateSe
switch (mode) switch (mode)
{ {
case MailListDisplayMode.Spacious: case MailListDisplayMode.Spacious:
return SpaciousTemplate; return SpaciousTemplate ?? throw new ArgumentException(nameof(SpaciousTemplate));
case MailListDisplayMode.Medium: case MailListDisplayMode.Medium:
return MediumTemplate; return MediumTemplate ?? throw new ArgumentException(nameof(MediumTemplate));
case MailListDisplayMode.Compact: case MailListDisplayMode.Compact:
return CompactTemplate; return CompactTemplate ?? throw new ArgumentException(nameof(CompactTemplate));
} }
} }
+2 -2
View File
@@ -149,7 +149,7 @@ public class DialogService : DialogServiceBase, IMailDialogService
return accountPicker.PickedAccount; return accountPicker.PickedAccount;
} }
public async Task<AccountSignature> ShowSignatureEditorDialog(AccountSignature signatureModel = null) public async Task<AccountSignature> ShowSignatureEditorDialog(AccountSignature? signatureModel = null)
{ {
SignatureEditorDialog signatureEditorDialog; SignatureEditorDialog signatureEditorDialog;
if (signatureModel != null) if (signatureModel != null)
@@ -169,7 +169,7 @@ public class DialogService : DialogServiceBase, IMailDialogService
var result = await HandleDialogPresentationAsync(signatureEditorDialog); var result = await HandleDialogPresentationAsync(signatureEditorDialog);
return result == ContentDialogResult.Primary ? signatureEditorDialog.Result : null; return result == ContentDialogResult.Primary ? signatureEditorDialog.Result : null!;
} }
public async Task ShowMessageSourceDialogAsync(string messageSource) public async Task ShowMessageSourceDialogAsync(string messageSource)
@@ -74,7 +74,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
} }
public bool Navigate(WinoPage page, public bool Navigate(WinoPage page,
object parameter = null, object? parameter = null,
NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame, NavigationReferenceFrame frame = NavigationReferenceFrame.ShellFrame,
NavigationTransitionType transition = NavigationTransitionType.None) NavigationTransitionType transition = NavigationTransitionType.None)
{ {
+3 -2
View File
@@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Wino.Core.Domain.Enums; using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
@@ -15,7 +16,7 @@ public class ProviderService : IProviderService
{ {
var details = GetAvailableProviders(); var details = GetAvailableProviders();
return details.FirstOrDefault(a => a.Type == type); return details.FirstOrDefault(a => a.Type == type) ?? throw new InvalidOperationException($"Provider detail not found for type: {type}");
} }
public List<IProviderDetail> GetAvailableProviders() public List<IProviderDetail> GetAvailableProviders()
+5 -1
View File
@@ -85,7 +85,11 @@ public sealed partial class ShellWindow : WindowEx, IWinoShellWindow, IRecipient
WeakReferenceMessenger.Default.Send(new DisposeRenderingFrameRequested()); WeakReferenceMessenger.Default.Send(new DisposeRenderingFrameRequested());
} }
private void MainFrameNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e) => ShellTitleBar.Content = (e.Content as BasePage).ShellContent; private void MainFrameNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e)
{
if (e.Content is BasePage basePage)
ShellTitleBar.Content = basePage.ShellContent;
}
private void PaneButtonClicked(Microsoft.UI.Xaml.Controls.TitleBar sender, object args) private void PaneButtonClicked(Microsoft.UI.Xaml.Controls.TitleBar sender, object args)
{ {
+11 -6
View File
@@ -41,7 +41,7 @@ public sealed partial class ComposePage : ComposePageAbstract,
InitializeComponent(); InitializeComponent();
} }
private async void GlobalFocusManagerGotFocus(object sender, FocusManagerGotFocusEventArgs e) private async void GlobalFocusManagerGotFocus(object? sender, FocusManagerGotFocusEventArgs e)
{ {
// In order to delegate cursor to the inner editor for WebView2. // In order to delegate cursor to the inner editor for WebView2.
// When the control got focus, we invoke script to focus the editor. // When the control got focus, we invoke script to focus the editor.
@@ -60,7 +60,7 @@ public sealed partial class ComposePage : ComposePageAbstract,
x => box.TextChanged += x, x => box.TextChanged += x,
x => box.TextChanged -= x) x => box.TextChanged -= x)
.Throttle(TimeSpan.FromMilliseconds(120)) .Throttle(TimeSpan.FromMilliseconds(120))
.ObserveOn(SynchronizationContext.Current) .ObserveOn(SynchronizationContext.Current!)
.Subscribe(t => .Subscribe(t =>
{ {
if (t.EventArgs.Reason == AutoSuggestionBoxTextChangeReason.UserInput) if (t.EventArgs.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
@@ -305,10 +305,15 @@ public sealed partial class ComposePage : ComposePageAbstract,
ImportanceFlyout.Hide(); ImportanceFlyout.Hide();
ImportanceSplitButton.IsChecked = true; ImportanceSplitButton.IsChecked = true;
if (sender is Button senderButton) if (sender is Button senderButton && senderButton.Tag is MessageImportance importance)
{ {
ViewModel.SelectedMessageImportance = (MessageImportance)senderButton.Tag; ViewModel.SelectedMessageImportance = importance;
((ImportanceSplitButton.Content as Viewbox).Child as SymbolIcon).Symbol = (senderButton.Content as SymbolIcon).Symbol; if (ImportanceSplitButton.Content is Viewbox viewbox &&
viewbox.Child is SymbolIcon symbolIcon &&
senderButton.Content is SymbolIcon contentIcon)
{
symbolIcon.Symbol = contentIcon.Symbol;
}
} }
} }
@@ -332,7 +337,7 @@ public sealed partial class ComposePage : ComposePageAbstract,
_ => null _ => null
}; };
AccountContact addedItem = null; AccountContact? addedItem = null;
if (addressCollection != null) if (addressCollection != null)
addedItem = await ViewModel.GetAddressInformationAsync(currentText, addressCollection); addedItem = await ViewModel.GetAddressInformationAsync(currentText, addressCollection);
@@ -200,15 +200,15 @@ public sealed partial class AdvancedImapSetupPage : Page
IncomingServerPassword = PasswordBox.Password, IncomingServerPassword = PasswordBox.Password,
IncomingServerType = Core.Domain.Enums.CustomIncomingServerType.IMAP4, IncomingServerType = Core.Domain.Enums.CustomIncomingServerType.IMAP4,
IncomingServerUsername = UsernameBox.Text, IncomingServerUsername = UsernameBox.Text,
IncomingAuthenticationMethod = (IncomingAuthenticationMethod.SelectedItem as ImapAuthenticationMethodModel).ImapAuthenticationMethod, IncomingAuthenticationMethod = (IncomingAuthenticationMethod.SelectedItem as ImapAuthenticationMethodModel)!.ImapAuthenticationMethod,
IncomingServerSocketOption = (IncomingConnectionSecurity.SelectedItem as ImapConnectionSecurityModel).ImapConnectionSecurity, IncomingServerSocketOption = (IncomingConnectionSecurity.SelectedItem as ImapConnectionSecurityModel)!.ImapConnectionSecurity,
IncomingServerPort = IncomingServerPortBox.Text, IncomingServerPort = IncomingServerPortBox.Text,
OutgoingServer = GetServerWithoutPort(OutgoingServerBox.Text), OutgoingServer = GetServerWithoutPort(OutgoingServerBox.Text),
OutgoingServerPort = OutgoingServerPort.Text, OutgoingServerPort = OutgoingServerPort.Text,
OutgoingServerPassword = OutgoingPasswordBox.Password, OutgoingServerPassword = OutgoingPasswordBox.Password,
OutgoingAuthenticationMethod = (OutgoingAuthenticationMethod.SelectedItem as ImapAuthenticationMethodModel).ImapAuthenticationMethod, OutgoingAuthenticationMethod = (OutgoingAuthenticationMethod.SelectedItem as ImapAuthenticationMethodModel)!.ImapAuthenticationMethod,
OutgoingServerSocketOption = (OutgoingConnectionSecurity.SelectedItem as ImapConnectionSecurityModel).ImapConnectionSecurity, OutgoingServerSocketOption = (OutgoingConnectionSecurity.SelectedItem as ImapConnectionSecurityModel)!.ImapConnectionSecurity,
OutgoingServerUsername = OutgoingUsernameBox.Text, OutgoingServerUsername = OutgoingUsernameBox.Text,
ProxyServer = ProxyServerBox.Text, ProxyServer = ProxyServerBox.Text,
@@ -13,10 +13,10 @@ namespace Wino.Views.ImapSetup;
public sealed partial class ImapConnectionFailedPage : Page public sealed partial class ImapConnectionFailedPage : Page
{ {
private string _protocolLog; private string? _protocolLog;
private readonly IClipboardService _clipboardService = App.Current.Services.GetService<IClipboardService>(); private readonly IClipboardService _clipboardService = App.Current.Services.GetService<IClipboardService>()!;
private readonly IMailDialogService _dialogService = App.Current.Services.GetService<IMailDialogService>(); private readonly IMailDialogService _dialogService = App.Current.Services.GetService<IMailDialogService>()!;
public ImapConnectionFailedPage() public ImapConnectionFailedPage()
{ {
@@ -15,8 +15,8 @@ namespace Wino.Views.ImapSetup;
public sealed partial class TestingImapConnectionPage : Page public sealed partial class TestingImapConnectionPage : Page
{ {
private AutoDiscoverySettings autoDiscoverySettings; private AutoDiscoverySettings autoDiscoverySettings = null!;
private CustomServerInformation serverInformationToTest; private CustomServerInformation serverInformationToTest = null!;
public TestingImapConnectionPage() public TestingImapConnectionPage()
{ {
@@ -19,7 +19,7 @@ namespace Wino.Views.ImapSetup;
public sealed partial class WelcomeImapSetupPage : Page public sealed partial class WelcomeImapSetupPage : Page
{ {
private readonly IAutoDiscoveryService _autoDiscoveryService = App.Current.Services.GetService<IAutoDiscoveryService>(); private readonly IAutoDiscoveryService _autoDiscoveryService = App.Current.Services.GetService<IAutoDiscoveryService>()!;
public WelcomeImapSetupPage() public WelcomeImapSetupPage()
{ {
+2 -7
View File
@@ -184,14 +184,9 @@
LostFocus="SearchBarUnfocused" LostFocus="SearchBarUnfocused"
PlaceholderText="{x:Bind domain:Translator.SearchBarPlaceholder}" PlaceholderText="{x:Bind domain:Translator.SearchBarPlaceholder}"
QueryIcon="Find" QueryIcon="Find"
QuerySubmitted="SearchbarQuerySubmitted"
Text="{x:Bind ViewModel.SearchQuery, Mode=TwoWay}" Text="{x:Bind ViewModel.SearchQuery, Mode=TwoWay}"
TextChanged="SearchBar_TextChanged"> TextChanged="SearchBar_TextChanged" />
<i:Interaction.Behaviors>
<i:EventTriggerBehavior EventName="QuerySubmitted">
<i:InvokeCommandAction Command="{x:Bind ViewModel.PerformSearchCommand}" />
</i:EventTriggerBehavior>
</i:Interaction.Behaviors>
</AutoSuggestBox>
</Grid> </Grid>
</wino:BasePage.ShellContent> </wino:BasePage.ShellContent>
+7 -1
View File
@@ -188,7 +188,7 @@ public sealed partial class MailListPage : MailListPageAbstract,
targetItems = ViewModel.MailCollection.SelectedItems; targetItems = ViewModel.MailCollection.SelectedItems;
var availableActions = ViewModel.GetAvailableMailActions(targetItems); var availableActions = ViewModel.GetAvailableMailActions(targetItems);
if (!availableActions?.Any() ?? false) return; if (availableActions == null || !availableActions.Any()) return;
var clickedOperation = await GetMailOperationFromFlyoutAsync(availableActions, control, p.X, p.Y); var clickedOperation = await GetMailOperationFromFlyoutAsync(availableActions, control, p.X, p.Y);
@@ -738,4 +738,10 @@ public sealed partial class MailListPage : MailListPageAbstract,
await WinoClickItemInternalAsync(e.ClickedItem); await WinoClickItemInternalAsync(e.ClickedItem);
} }
private void SearchbarQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
{
if (ViewModel.PerformSearchCommand.CanExecute(null))
ViewModel.PerformSearchCommand.Execute(null);
}
} }
@@ -28,8 +28,8 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
IRecipient<CancelRenderingContentRequested>, IRecipient<CancelRenderingContentRequested>,
IRecipient<ApplicationThemeChanged> IRecipient<ApplicationThemeChanged>
{ {
private readonly IPreferencesService _preferencesService = App.Current.Services.GetService<IPreferencesService>(); private readonly IPreferencesService _preferencesService = App.Current.Services.GetService<IPreferencesService>()!;
private readonly IMailDialogService _dialogService = App.Current.Services.GetService<IMailDialogService>(); private readonly IMailDialogService _dialogService = App.Current.Services.GetService<IMailDialogService>()!;
private bool isRenderingInProgress = false; private bool isRenderingInProgress = false;
private TaskCompletionSource<bool> DOMLoadedTask = new TaskCompletionSource<bool>(); private TaskCompletionSource<bool> DOMLoadedTask = new TaskCompletionSource<bool>();
@@ -232,7 +232,7 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
// TODO: Check external link navigation setting is enabled. // TODO: Check external link navigation setting is enabled.
// Open all external urls in launcher. // Open all external urls in launcher.
if (args.Cancel && Uri.TryCreate(args.Uri, UriKind.Absolute, out Uri newUri)) if (args.Cancel && Uri.TryCreate(args.Uri, UriKind.Absolute, out Uri? newUri) && newUri != null)
{ {
await Launcher.LaunchUriAsync(newUri); await Launcher.LaunchUriAsync(newUri);
} }
@@ -242,7 +242,7 @@ public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
{ {
if (e.ClickedItem is MailAttachmentViewModel attachmentViewModel) if (e.ClickedItem is MailAttachmentViewModel attachmentViewModel)
{ {
ViewModel.OpenAttachmentCommand.Execute(attachmentViewModel); ViewModel?.OpenAttachmentCommand.Execute(attachmentViewModel);
} }
} }
+12
View File
@@ -11,7 +11,16 @@
<UseWinUI>true</UseWinUI> <UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling> <EnableMsixTooling>true</EnableMsixTooling>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<!-- AOT / Trimming -->
<PublishAot Condition="'$(Configuration)' == 'Debug'">False</PublishAot>
<PublishAot Condition="'$(Configuration)' != 'Debug'">True</PublishAot>
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Single instancing -->
<DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants> <DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Remove="Assets\BadgeLogo.scale-100.png" /> <Content Remove="Assets\BadgeLogo.scale-100.png" />
@@ -262,8 +271,11 @@
<PropertyGroup> <PropertyGroup>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun> <PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun> <PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<!-- Trimming -->
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed> <PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed> <PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
<GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate> <GenerateTemporaryStoreCertificate>True</GenerateTemporaryStoreCertificate>
<GenerateAppInstallerFile>False</GenerateAppInstallerFile> <GenerateAppInstallerFile>False</GenerateAppInstallerFile>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled> <AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>