Removing UWP project.
@@ -1,8 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Wino.BackgroundTasks.NET8</RootNamespace>
|
||||
|
||||
<RuntimeIdentifiers Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) >= 8">win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) < 8">win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
|
||||
@@ -56,7 +56,6 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MimeKit" Version="4.7.1" />
|
||||
<PackageReference Include="sqlite-net-pcl" Version="1.9.172" />
|
||||
<PackageReference Include="MimeKit" Version="4.7.1" />
|
||||
<PackageReference Include="MailKit" Version="4.7.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
20
Wino.Core.UWP/WinAppDispatcher.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
|
||||
namespace Wino.Core.WinUI
|
||||
{
|
||||
public class WinAppDispatcher : IDispatcher
|
||||
{
|
||||
private readonly DispatcherQueue _dispatcherQueue;
|
||||
|
||||
public WinAppDispatcher(DispatcherQueue dispatcherQueue)
|
||||
{
|
||||
_dispatcherQueue = dispatcherQueue;
|
||||
}
|
||||
|
||||
public Task ExecuteOnUIThread(Action action) => _dispatcherQueue.EnqueueAsync(() => { action(); });
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Wino.Core.WinUI</RootNamespace>
|
||||
<RuntimeIdentifiers Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) >= 8">win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers Condition="$([MSBuild]::GetTargetFrameworkVersion('$(TargetFramework)')) < 8">win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Properties\**" />
|
||||
<Content Remove="Properties\**" />
|
||||
|
||||
39
Wino.Mail.WinUI/Activation/ActivationHandler.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wino.Activation
|
||||
{
|
||||
// For more information on understanding and extending activation flow see
|
||||
// https://github.com/microsoft/TemplateStudio/blob/main/docs/UWP/activation.md
|
||||
internal abstract class ActivationHandler
|
||||
{
|
||||
public abstract bool CanHandle(object args);
|
||||
|
||||
public abstract Task HandleAsync(object args);
|
||||
}
|
||||
|
||||
// Extend this class to implement new ActivationHandlers
|
||||
internal abstract class ActivationHandler<T> : ActivationHandler
|
||||
where T : class
|
||||
{
|
||||
// Override this method to add the activation logic in your activation handler
|
||||
protected abstract Task HandleInternalAsync(T args);
|
||||
|
||||
public override async Task HandleAsync(object args)
|
||||
{
|
||||
await HandleInternalAsync(args as T);
|
||||
}
|
||||
|
||||
public override bool CanHandle(object args)
|
||||
{
|
||||
// CanHandle checks the args is of type you have configured
|
||||
return args is T && CanHandleInternal(args as T);
|
||||
}
|
||||
|
||||
// You can override this method to add extra validation on activation args
|
||||
// to determine if your ActivationHandler should handle this activation args
|
||||
protected virtual bool CanHandleInternal(T args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
Wino.Mail.WinUI/Activation/BackgroundActivationHandler.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Serilog;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Background;
|
||||
using Windows.UI.Notifications;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.UWP.Services;
|
||||
|
||||
#if NET8_0
|
||||
using CommunityToolkit.WinUI.Notifications;
|
||||
#else
|
||||
using Microsoft.Toolkit.Uwp.Notifications;
|
||||
#endif
|
||||
|
||||
namespace Wino.Activation
|
||||
{
|
||||
internal class BackgroundActivationHandler : ActivationHandler<BackgroundActivatedEventArgs>
|
||||
{
|
||||
private const string BackgroundExecutionLogTag = "[BackgroundExecution] ";
|
||||
|
||||
private readonly IWinoRequestDelegator _winoRequestDelegator;
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IWinoRequestProcessor _winoRequestProcessor;
|
||||
private readonly IWinoServerConnectionManager _winoServerConnectionManager;
|
||||
private readonly IMailService _mailService;
|
||||
private ToastArguments _toastArguments;
|
||||
|
||||
BackgroundTaskDeferral _deferral;
|
||||
public BackgroundActivationHandler(IWinoRequestDelegator winoRequestDelegator,
|
||||
INativeAppService nativeAppService,
|
||||
IWinoRequestProcessor winoRequestProcessor,
|
||||
IWinoServerConnectionManager winoServerConnectionManager,
|
||||
IMailService mailService)
|
||||
{
|
||||
_winoRequestDelegator = winoRequestDelegator;
|
||||
_nativeAppService = nativeAppService;
|
||||
_winoRequestProcessor = winoRequestProcessor;
|
||||
_winoServerConnectionManager = winoServerConnectionManager;
|
||||
_mailService = mailService;
|
||||
}
|
||||
|
||||
protected override async Task HandleInternalAsync(BackgroundActivatedEventArgs args)
|
||||
{
|
||||
var instance = args.TaskInstance;
|
||||
var taskName = instance.Task.Name;
|
||||
|
||||
instance.Canceled -= OnBackgroundExecutionCanceled;
|
||||
instance.Canceled += OnBackgroundExecutionCanceled;
|
||||
|
||||
_deferral = instance.GetDeferral();
|
||||
|
||||
if (taskName == BackgroundTaskService.ToastActivationTaskEx)
|
||||
{
|
||||
if (instance.TriggerDetails is ToastNotificationActionTriggerDetail toastNotificationActionTriggerDetail)
|
||||
_toastArguments = ToastArguments.Parse(toastNotificationActionTriggerDetail.Argument);
|
||||
|
||||
// All toast activation mail actions are handled here like mark as read or delete.
|
||||
// This should not launch the application on the foreground.
|
||||
|
||||
// Get the action and mail item id.
|
||||
// Prepare package and send to delegator.
|
||||
|
||||
if (_toastArguments.TryGetValue(Constants.ToastMailItemIdKey, out string mailItemId) &&
|
||||
_toastArguments.TryGetValue(Constants.ToastActionKey, out MailOperation action) &&
|
||||
_toastArguments.TryGetValue(Constants.ToastMailItemRemoteFolderIdKey, out string remoteFolderId))
|
||||
{
|
||||
var mailItem = await _mailService.GetSingleMailItemAsync(mailItemId, remoteFolderId);
|
||||
|
||||
if (mailItem == null) return;
|
||||
|
||||
if (_nativeAppService.IsAppRunning())
|
||||
{
|
||||
// Just send the package. We should reflect the UI changes as well.
|
||||
var package = new MailOperationPreperationRequest(action, mailItem);
|
||||
|
||||
await _winoRequestDelegator.ExecuteAsync(package);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need to synchronize changes without reflection the UI changes.
|
||||
|
||||
// var synchronizer = _winoSynchronizerFactory.GetAccountSynchronizer(mailItem.AssignedAccount.Id);
|
||||
var prepRequest = new MailOperationPreperationRequest(action, mailItem);
|
||||
|
||||
var requests = await _winoRequestProcessor.PrepareRequestsAsync(prepRequest);
|
||||
|
||||
foreach (var request in requests)
|
||||
{
|
||||
_winoServerConnectionManager.QueueRequest(request, mailItem.AssignedAccount.Id);
|
||||
|
||||
// synchronizer.QueueRequest(request);
|
||||
}
|
||||
|
||||
//var options = new SynchronizationOptions()
|
||||
//{
|
||||
// Type = SynchronizationType.ExecuteRequests,
|
||||
// AccountId = mailItem.AssignedAccount.Id
|
||||
//};
|
||||
|
||||
//await synchronizer.SynchronizeAsync(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
instance.Canceled -= OnBackgroundExecutionCanceled;
|
||||
|
||||
_deferral.Complete();
|
||||
}
|
||||
|
||||
private void OnBackgroundExecutionCanceled(Windows.ApplicationModel.Background.IBackgroundTaskInstance sender, Windows.ApplicationModel.Background.BackgroundTaskCancellationReason reason)
|
||||
{
|
||||
Log.Error($"{BackgroundExecutionLogTag} ({sender.Task.Name}) Background task is canceled. Reason -> {reason}");
|
||||
|
||||
_deferral?.Complete();
|
||||
}
|
||||
|
||||
protected override bool CanHandleInternal(BackgroundActivatedEventArgs args)
|
||||
{
|
||||
var instance = args.TaskInstance;
|
||||
var taskName = instance.Task.Name;
|
||||
|
||||
if (taskName == BackgroundTaskService.ToastActivationTaskEx)
|
||||
{
|
||||
// User clicked Mark as Read or Delete in toast notification.
|
||||
// MailId and Action must present in the arguments.
|
||||
|
||||
return true;
|
||||
|
||||
//if (instance.TriggerDetails is ToastNotificationActionTriggerDetail toastNotificationActionTriggerDetail)
|
||||
//{
|
||||
// _toastArguments = ToastArguments.Parse(toastNotificationActionTriggerDetail.Argument);
|
||||
|
||||
// return
|
||||
// _toastArguments.Contains(Constants.ToastMailItemIdKey) &&
|
||||
// _toastArguments.Contains(Constants.ToastActionKey);
|
||||
//}
|
||||
|
||||
}
|
||||
else if (taskName == BackgroundTaskService.BackgroundSynchronizationTimerTaskNameEx)
|
||||
{
|
||||
// This is timer based background synchronization.
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Wino.Mail.WinUI/Activation/DefaultActivationHandler.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Wino.Views;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
76
Wino.Mail.WinUI/Activation/FileActivationHandler.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Storage;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Services;
|
||||
using Wino.Helpers;
|
||||
using Wino.Views;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Activation
|
||||
{
|
||||
internal class FileActivationHandler : ActivationHandler<FileActivatedEventArgs>
|
||||
{
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IMimeFileService _mimeFileService;
|
||||
private readonly IStatePersistanceService _statePersistanceService;
|
||||
private readonly IWinoNavigationService _winoNavigationService;
|
||||
|
||||
public FileActivationHandler(INativeAppService nativeAppService,
|
||||
IMimeFileService mimeFileService,
|
||||
IStatePersistanceService statePersistanceService,
|
||||
IWinoNavigationService 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.ReadBytesAsync();
|
||||
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.NavigateRendering(messageInformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
_statePersistanceService.ShouldShiftMailRenderingDesign = true;
|
||||
|
||||
(Window.Current.Content as Frame).Navigate(typeof(MailRenderingPage), messageInformation, new DrillInNavigationTransitionInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool CanHandleInternal(FileActivatedEventArgs args) => args.Files.Any();
|
||||
|
||||
}
|
||||
}
|
||||
56
Wino.Mail.WinUI/Activation/ProtocolActivationHandler.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Messages.Authorization;
|
||||
using Wino.Core.Messages.Shell;
|
||||
|
||||
namespace Wino.Activation
|
||||
{
|
||||
internal class ProtocolActivationHandler : ActivationHandler<ProtocolActivatedEventArgs>
|
||||
{
|
||||
private const string GoogleAuthorizationProtocolTag = "google.pw.oauth2";
|
||||
private const string MailtoProtocolTag = "mailto:";
|
||||
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly ILaunchProtocolService _launchProtocolService;
|
||||
|
||||
public ProtocolActivationHandler(INativeAppService nativeAppService, ILaunchProtocolService launchProtocolService)
|
||||
{
|
||||
_nativeAppService = nativeAppService;
|
||||
_launchProtocolService = launchProtocolService;
|
||||
}
|
||||
|
||||
protected override Task HandleInternalAsync(ProtocolActivatedEventArgs args)
|
||||
{
|
||||
// Check URI prefix.
|
||||
|
||||
var protocolString = args.Uri.AbsoluteUri;
|
||||
|
||||
// Google OAuth Response
|
||||
if (protocolString.StartsWith(GoogleAuthorizationProtocolTag))
|
||||
{
|
||||
// App must be working already. No need to check for running state.
|
||||
WeakReferenceMessenger.Default.Send(new ProtocolAuthorizationCallbackReceived(args.Uri));
|
||||
}
|
||||
else if (protocolString.StartsWith(MailtoProtocolTag))
|
||||
{
|
||||
// mailto activation. Try to parse params.
|
||||
|
||||
var replaced = protocolString.Replace(MailtoProtocolTag, "mailto=");
|
||||
replaced = Wino.Core.Extensions.StringExtensions.ReplaceFirst(replaced, "?", "&");
|
||||
|
||||
_launchProtocolService.MailtoParameters = HttpUtility.ParseQueryString(replaced);
|
||||
|
||||
if (_nativeAppService.IsAppRunning())
|
||||
{
|
||||
// Just send publish a message. Shell will continue.
|
||||
WeakReferenceMessenger.Default.Send(new MailtoProtocolMessageRequested());
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Messages.Accounts;
|
||||
using Wino.Mail.WinUI;
|
||||
|
||||
|
||||
#if NET8_0
|
||||
using CommunityToolkit.WinUI.Notifications;
|
||||
#else
|
||||
using Microsoft.Toolkit.Uwp.Notifications;
|
||||
#endif
|
||||
|
||||
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 INativeAppService _nativeAppService;
|
||||
private readonly IMailService _mailService;
|
||||
private readonly IFolderService _folderService;
|
||||
|
||||
private ToastArguments _toastArguments;
|
||||
|
||||
public ToastNotificationActivationHandler(INativeAppService nativeAppService,
|
||||
IMailService mailService,
|
||||
IFolderService folderService)
|
||||
{
|
||||
_nativeAppService = nativeAppService;
|
||||
_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.ToastMailItemIdKey], 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.GetService<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.ToastMailItemIdKey) &&
|
||||
_toastArguments.Contains(Constants.ToastActionKey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, "Couldn't handle parsing toast notification arguments for foreground navigate.");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Application
|
||||
x:Class="Wino.Mail.WinUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
@@ -8,9 +8,9 @@
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
<!-- Other app resources here -->
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
||||
@@ -1,50 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.UI.Xaml.Shapes;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
using Windows.Storage;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Services;
|
||||
using Wino.Core.WinUI.Services;
|
||||
using Wino.Views;
|
||||
using WinUIEx;
|
||||
|
||||
namespace Wino.Mail.WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
private WindowEx m_Window;
|
||||
private Frame m_ShellFrame;
|
||||
|
||||
private readonly IApplicationConfiguration _applicationFolderConfiguration;
|
||||
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
if (WebAuthenticator.CheckOAuthRedirectionActivation()) return;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Services = ConfigureServices();
|
||||
|
||||
_applicationFolderConfiguration = Services.GetService<IApplicationConfiguration>();
|
||||
_logInitializer = Services.GetService<ILogInitializer>();
|
||||
|
||||
ConfigureLogger();
|
||||
ConfigureAppCenter();
|
||||
ConfigurePrelaunch();
|
||||
ConfigureXbox();
|
||||
|
||||
// Make sure the paths are setup on app start.
|
||||
_applicationFolderConfiguration.ApplicationDataFolderPath = ApplicationData.Current.LocalFolder.Path;
|
||||
_applicationFolderConfiguration.PublisherSharedFolderPath = ApplicationData.Current.GetPublisherCacheFolder(ApplicationConfiguration.SharedFolderName).Path;
|
||||
|
||||
_themeService = Services.GetService<IThemeService>();
|
||||
_databaseService = Services.GetService<IDatabaseService>();
|
||||
_translationService = Services.GetService<ITranslationService>();
|
||||
_appShellService = Services.GetService<IAppShellService>();
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
m_window = new MainWindow();
|
||||
m_window.Activate();
|
||||
ConfigureWindow();
|
||||
|
||||
_appShellService.AppWindow = m_Window;
|
||||
|
||||
foreach (var service in initializeServices)
|
||||
{
|
||||
await service.InitializeAsync();
|
||||
}
|
||||
|
||||
m_ShellFrame.Navigate(typeof(AppShell));
|
||||
m_Window.Activate();
|
||||
}
|
||||
|
||||
private Window m_window;
|
||||
private void ConfigureWindow()
|
||||
{
|
||||
m_Window = new WindowEx
|
||||
{
|
||||
SystemBackdrop = new MicaBackdrop(),
|
||||
ExtendsContentIntoTitleBar = true,
|
||||
MinWidth = 420
|
||||
};
|
||||
|
||||
m_ShellFrame = new Frame();
|
||||
|
||||
m_Window.Content = m_ShellFrame;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
534
Wino.Mail.WinUI/AppShell.xaml
Normal file
302
Wino.Mail.WinUI/AppShell.xaml.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.Foundation;
|
||||
using Wino.Controls;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.Messages.Accounts;
|
||||
using Wino.Core.Messages.Mails;
|
||||
using Wino.Core.Messages.Shell;
|
||||
using Wino.Extensions;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.MenuFlyouts;
|
||||
using Wino.MenuFlyouts.Context;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class AppShell : AppShellAbstract,
|
||||
IRecipient<AccountMenuItemExtended>,
|
||||
IRecipient<NavigateMailFolderEvent>,
|
||||
IRecipient<CreateNewMailWithMultipleAccountsRequested>,
|
||||
IRecipient<InfoBarMessageRequested>
|
||||
{
|
||||
public AppShell() : base()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
|
||||
coreTitleBar.LayoutMetricsChanged += TitleBarLayoutUpdated;
|
||||
}
|
||||
|
||||
private void TitleBarLayoutUpdated(CoreApplicationViewTitleBar sender, object args) => UpdateTitleBarLayout(sender);
|
||||
|
||||
private void UpdateTitleBarLayout(CoreApplicationViewTitleBar coreTitleBar) => RealAppBar.SystemReserved = coreTitleBar.SystemOverlayRightInset;
|
||||
|
||||
private async void ItemDroppedOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
// Validate package content.
|
||||
if (sender is WinoNavigationViewItem droppedContainer)
|
||||
{
|
||||
droppedContainer.IsDraggingItemOver = false;
|
||||
|
||||
if (CanContinueDragDrop(droppedContainer, e))
|
||||
{
|
||||
if (droppedContainer.DataContext is IBaseFolderMenuItem draggingFolder)
|
||||
{
|
||||
var mailCopies = new List<MailCopy>();
|
||||
|
||||
var dragPackage = e.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
|
||||
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
|
||||
// Extract mail copies from IMailItem.
|
||||
// ThreadViewModels will be divided into pieces.
|
||||
|
||||
foreach (var item in dragPackage.DraggingMails)
|
||||
{
|
||||
if (item is MailItemViewModel singleMailItemViewModel)
|
||||
{
|
||||
mailCopies.Add(singleMailItemViewModel.MailCopy);
|
||||
}
|
||||
else if (item is ThreadMailItemViewModel threadViewModel)
|
||||
{
|
||||
mailCopies.AddRange(threadViewModel.GetMailCopies());
|
||||
}
|
||||
}
|
||||
|
||||
await ViewModel.PerformMoveOperationAsync(mailCopies, draggingFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ItemDragLeaveFromFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
if (sender is WinoNavigationViewItem leavingContainer)
|
||||
{
|
||||
leavingContainer.IsDraggingItemOver = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanContinueDragDrop(WinoNavigationViewItem interactingContainer, DragEventArgs args)
|
||||
{
|
||||
// TODO: Maybe override caption with some information why the validation failed?
|
||||
// Note: Caption has a max length. It may be trimmed in some languages.
|
||||
|
||||
if (interactingContainer == null || !args.DataView.Properties.ContainsKey(nameof(MailDragPackage))) return false;
|
||||
|
||||
var dragPackage = args.DataView.Properties[nameof(MailDragPackage)] as MailDragPackage;
|
||||
|
||||
// Invalid package.
|
||||
if (!dragPackage.DraggingMails.Any()) return false;
|
||||
|
||||
// Check whether source and target folder are the same.
|
||||
if (interactingContainer.IsSelected) return false;
|
||||
|
||||
// Check if the interacting container is a folder.
|
||||
if (!(interactingContainer.DataContext is IBaseFolderMenuItem folderMenuItem)) return false;
|
||||
|
||||
// Check if the folder is a move target.
|
||||
if (!folderMenuItem.IsMoveTarget) return false;
|
||||
|
||||
// Check whether the moving item's account has at least one same as the target folder's account.
|
||||
var draggedAccountIds = folderMenuItem.HandlingFolders.Select(a => a.MailAccountId);
|
||||
|
||||
if (!dragPackage.DraggingMails.Any(a => draggedAccountIds.Contains(a.AssignedAccount.Id))) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ItemDragEnterOnFolder(object sender, DragEventArgs e)
|
||||
{
|
||||
// Validate package content.
|
||||
if (sender is WinoNavigationViewItem droppedContainer && CanContinueDragDrop(droppedContainer, e))
|
||||
{
|
||||
droppedContainer.IsDraggingItemOver = true;
|
||||
|
||||
var draggingFolder = droppedContainer.DataContext as IBaseFolderMenuItem;
|
||||
|
||||
e.AcceptedOperation = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
e.DragUIOverride.Caption = string.Format(Translator.DragMoveToFolderCaption, draggingFolder.FolderName);
|
||||
}
|
||||
}
|
||||
|
||||
public async void Receive(AccountMenuItemExtended message)
|
||||
{
|
||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, async () =>
|
||||
{
|
||||
if (message.FolderId == default) return;
|
||||
|
||||
if (ViewModel.MenuItems.TryGetFolderMenuItem(message.FolderId, out IBaseFolderMenuItem foundMenuItem))
|
||||
{
|
||||
if (foundMenuItem == null) return;
|
||||
|
||||
foundMenuItem.Expand();
|
||||
|
||||
await ViewModel.NavigateFolderAsync(foundMenuItem);
|
||||
|
||||
navigationView.SelectedItem = foundMenuItem;
|
||||
|
||||
if (message.NavigateMailItem == null) return;
|
||||
|
||||
// At this point folder is navigated and items are loaded.
|
||||
WeakReferenceMessenger.Default.Send(new MailItemNavigationRequested(message.NavigateMailItem.UniqueId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async void MenuSelectionChanged(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewSelectionChangedEventArgs args)
|
||||
{
|
||||
if (args.SelectedItem is IMenuItem invokedMenuItem)
|
||||
{
|
||||
await ViewModel.MenuItemInvokedOrSelectedAsync(invokedMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
private async void NavigationViewItemInvoked(Microsoft.UI.Xaml.Controls.NavigationView sender, Microsoft.UI.Xaml.Controls.NavigationViewItemInvokedEventArgs args)
|
||||
{
|
||||
// SelectsOnInvoked is handled in MenuSelectionChanged.
|
||||
// This part is only for the items that are not selectable.
|
||||
if (args.InvokedItemContainer is WinoNavigationViewItem winoNavigationViewItem)
|
||||
{
|
||||
if (winoNavigationViewItem.SelectsOnInvoked) return;
|
||||
|
||||
await ViewModel.MenuItemInvokedOrSelectedAsync(winoNavigationViewItem.DataContext as IMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(NavigateMailFolderEvent message)
|
||||
{
|
||||
if (message.BaseFolderMenuItem == null) return;
|
||||
|
||||
if (navigationView.SelectedItem != message.BaseFolderMenuItem)
|
||||
{
|
||||
var navigateFolderArgs = new NavigateMailFolderEventArgs(message.BaseFolderMenuItem, message.FolderInitLoadAwaitTask);
|
||||
|
||||
ViewModel.NavigationService.NavigateFolder(navigateFolderArgs);
|
||||
|
||||
// Prevent double navigation.
|
||||
navigationView.SelectionChanged -= MenuSelectionChanged;
|
||||
navigationView.SelectedItem = message.BaseFolderMenuItem;
|
||||
navigationView.SelectionChanged += MenuSelectionChanged;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Complete the init task since we are already on the right page.
|
||||
message.FolderInitLoadAwaitTask?.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShellFrameContentNavigated(object sender, Microsoft.UI.Xaml.Navigation.NavigationEventArgs e)
|
||||
=> RealAppBar.ShellFrameContent = (e.Content as BasePage).ShellContent;
|
||||
|
||||
private void BackButtonClicked(Controls.Advanced.WinoAppTitleBar sender, RoutedEventArgs args)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new ClearMailSelectionsRequested());
|
||||
WeakReferenceMessenger.Default.Send(new DisposeRenderingFrameRequested());
|
||||
WeakReferenceMessenger.Default.Send(new ShellStateUpdated());
|
||||
|
||||
}
|
||||
|
||||
private async void MenuItemContextRequested(UIElement sender, ContextRequestedEventArgs args)
|
||||
{
|
||||
// Delegate this request to ViewModel.
|
||||
// VM will prepare available actions for this folder and show Menu Flyout.
|
||||
|
||||
if (sender is WinoNavigationViewItem menuItem &&
|
||||
menuItem.DataContext is IBaseFolderMenuItem baseFolderMenuItem &&
|
||||
baseFolderMenuItem.IsMoveTarget &&
|
||||
args.TryGetPosition(sender, out Point p))
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
var source = new TaskCompletionSource<FolderOperationMenuItem>();
|
||||
|
||||
var actions = ViewModel.GetFolderContextMenuActions(baseFolderMenuItem);
|
||||
var flyout = new FolderOperationFlyout(actions, source);
|
||||
|
||||
flyout.ShowAt(menuItem, new FlyoutShowOptions()
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Standard,
|
||||
Position = new Point(p.X + 30, p.Y - 20)
|
||||
});
|
||||
|
||||
var operation = await source.Task;
|
||||
|
||||
flyout.Dispose();
|
||||
|
||||
// No action selected.
|
||||
if (operation == null) return;
|
||||
|
||||
await ViewModel.PerformFolderOperationAsync(operation.Operation, baseFolderMenuItem);
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(CreateNewMailWithMultipleAccountsRequested message)
|
||||
{
|
||||
// Find the NewMail menu item container.
|
||||
|
||||
var container = navigationView.ContainerFromMenuItem(ViewModel.CreateMailMenuItem);
|
||||
|
||||
var flyout = new AccountSelectorFlyout(message.AllAccounts, ViewModel.CreateNewMailForAsync);
|
||||
|
||||
flyout.ShowAt(container, new FlyoutShowOptions()
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Auto,
|
||||
Placement = FlyoutPlacementMode.Right
|
||||
});
|
||||
}
|
||||
|
||||
private void NavigationPaneOpening(Microsoft.UI.Xaml.Controls.NavigationView sender, object args)
|
||||
{
|
||||
// It's annoying that NavigationView doesn't respect expansion state of the items in Minimal display mode.
|
||||
// Expanded items are collaped, and users need to expand them again.
|
||||
// Regardless of the reason, we will expand the selected item if it's a folder with parent account for visibility.
|
||||
|
||||
if (sender.DisplayMode == Microsoft.UI.Xaml.Controls.NavigationViewDisplayMode.Minimal && sender.SelectedItem is IFolderMenuItem selectedFolderMenuItem)
|
||||
{
|
||||
selectedFolderMenuItem.Expand();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// InfoBar message is requested.
|
||||
/// </summary>
|
||||
public async void Receive(InfoBarMessageRequested message)
|
||||
{
|
||||
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(message.ActionButtonTitle) || message.Action == null)
|
||||
{
|
||||
ShellInfoBar.ActionButton = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ShellInfoBar.ActionButton = new Button()
|
||||
{
|
||||
Content = message.ActionButtonTitle,
|
||||
Command = new RelayCommand(message.Action)
|
||||
};
|
||||
}
|
||||
|
||||
ShellInfoBar.Message = message.Message;
|
||||
ShellInfoBar.Title = message.Title;
|
||||
ShellInfoBar.Severity = message.Severity.AsMUXCInfoBarSeverity();
|
||||
ShellInfoBar.IsOpen = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
25
Wino.Mail.WinUI/AppThemes/Acrylic.xaml
Normal file
@@ -0,0 +1,25 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.UI.Xaml.Media"
|
||||
xmlns:xaml="using:Microsoft.UI.Xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Acrylic</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<!-- Acrylic Template -->
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Reading Page Date/Name Group Header Background -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#ecf0f1</SolidColorBrush>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#2C2C2C</SolidColorBrush>
|
||||
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
18
Wino.Mail.WinUI/AppThemes/Clouds.xaml
Normal file
@@ -0,0 +1,18 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Clouds</x:String>
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/Clouds.jpg</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<ImageBrush x:Key="WinoApplicationBackgroundColor" ImageSource="{StaticResource ThemeBackgroundImage}" />
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#b2dffc</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#b2dffc</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
47
Wino.Mail.WinUI/AppThemes/Custom.xaml
Normal file
@@ -0,0 +1,47 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:xaml="using:Microsoft.UI.Xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Custom</x:String>
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appdata:///local/CustomWallpaper.jpg</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<ImageBrush
|
||||
x:Key="WinoApplicationBackgroundColor"
|
||||
ImageSource="{StaticResource ThemeBackgroundImage}"
|
||||
Stretch="UniformToFill" />
|
||||
|
||||
<!-- Navigation View Settings -->
|
||||
<xaml:CornerRadius x:Key="NavigationViewContentGridCornerRadius">0,0,0,0</xaml:CornerRadius>
|
||||
<xaml:CornerRadius x:Key="OverlayCornerRadius">0,1,0,0</xaml:CornerRadius>
|
||||
<Thickness x:Key="NavigationViewContentMargin">0,0,0,0</Thickness>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Reading Page Date/Name Group Header Background -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#ecf0f1</SolidColorBrush>
|
||||
|
||||
<Color x:Key="MainCustomThemeColor">#D9FFFFFF</Color>
|
||||
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor" Color="{StaticResource MainCustomThemeColor}" />
|
||||
<SolidColorBrush x:Key="NavigationViewContentBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="{StaticResource MainCustomThemeColor}" />
|
||||
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground" Color="{StaticResource MainCustomThemeColor}" />
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Reading Page Date/Name Group Header Background -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#1f1f1f</SolidColorBrush>
|
||||
|
||||
<Color x:Key="MainCustomThemeColor">#E61F1F1F</Color>
|
||||
|
||||
<!-- Reading Pane Background -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush" Color="{StaticResource MainCustomThemeColor}" />
|
||||
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor" Color="{StaticResource MainCustomThemeColor}" />
|
||||
<SolidColorBrush x:Key="NavigationViewContentBackground" Color="Transparent" />
|
||||
<SolidColorBrush x:Key="NavigationViewExpandedPaneBackground" Color="{StaticResource MainCustomThemeColor}" />
|
||||
<SolidColorBrush x:Key="NavigationViewDefaultPaneBackground" Color="{StaticResource MainCustomThemeColor}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
21
Wino.Mail.WinUI/AppThemes/Forest.xaml
Normal file
@@ -0,0 +1,21 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:xaml="using:Windows.UI.Xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Forest</x:String>
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/Forest.jpg</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<ImageBrush x:Key="WinoApplicationBackgroundColor" ImageSource="{StaticResource ThemeBackgroundImage}" />
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#A800D608</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#59001C01</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
18
Wino.Mail.WinUI/AppThemes/Garden.xaml
Normal file
@@ -0,0 +1,18 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Garden</x:String>
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/Garden.jpg</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<ImageBrush x:Key="WinoApplicationBackgroundColor" ImageSource="{StaticResource ThemeBackgroundImage}" />
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#dcfad8</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#dcfad8</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
19
Wino.Mail.WinUI/AppThemes/Mica.xaml
Normal file
@@ -0,0 +1,19 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Mica</x:String>
|
||||
<x:Boolean x:Key="UseMica">True</x:Boolean>
|
||||
|
||||
<SolidColorBrush x:Key="WinoApplicationBackgroundColor">Transparent</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<!-- Mica Template -->
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Reading Page Date/Name Group Header Background -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#ecf0f1</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#1f1f1f</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
20
Wino.Mail.WinUI/AppThemes/Nighty.xaml
Normal file
@@ -0,0 +1,20 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Nighty</x:String>
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/Nighty.jpg</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<ImageBrush x:Key="WinoApplicationBackgroundColor" ImageSource="{StaticResource ThemeBackgroundImage}" />
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#fdcb6e</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#5413191F</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
20
Wino.Mail.WinUI/AppThemes/Snowflake.xaml
Normal file
@@ -0,0 +1,20 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Snowflake</x:String>
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/Snowflake.jpg</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<ImageBrush x:Key="WinoApplicationBackgroundColor" ImageSource="{StaticResource ThemeBackgroundImage}" />
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#b0c6dd</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#b0c6dd</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
22
Wino.Mail.WinUI/AppThemes/TestTheme.xaml
Normal file
@@ -0,0 +1,22 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">TestTheme.xaml</x:String>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Background Image -->
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/bg6.jpg</x:String>
|
||||
<SolidColorBrush x:Key="ShellTitleBarBackgroundColorBrush">#A3FFFFFF</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ShellNavigationViewBackgroundColorBrush">#A3FFFFFF</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#fdcb6e</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Background Image -->
|
||||
<x:String x:Key="ThemeBackgroundImage">ms-appx:///BackgroundImages/bg6.jpg</x:String>
|
||||
|
||||
<SolidColorBrush x:Key="ShellTitleBarBackgroundColorBrush">#A3000000</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ShellNavigationViewBackgroundColorBrush">#A3000000</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3262626</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
BIN
Wino.Mail.WinUI/Assets/BadgeLogo.scale-100.png
Normal file
|
After Width: | Height: | Size: 209 B |
BIN
Wino.Mail.WinUI/Assets/BadgeLogo.scale-125.png
Normal file
|
After Width: | Height: | Size: 238 B |
BIN
Wino.Mail.WinUI/Assets/BadgeLogo.scale-150.png
Normal file
|
After Width: | Height: | Size: 286 B |
BIN
Wino.Mail.WinUI/Assets/BadgeLogo.scale-200.png
Normal file
|
After Width: | Height: | Size: 360 B |
BIN
Wino.Mail.WinUI/Assets/BadgeLogo.scale-400.png
Normal file
|
After Width: | Height: | Size: 673 B |
BIN
Wino.Mail.WinUI/Assets/EML/eml.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_archive.png
Normal file
|
After Width: | Height: | Size: 348 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_audio.png
Normal file
|
After Width: | Height: | Size: 504 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_executable.png
Normal file
|
After Width: | Height: | Size: 678 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_html.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_image.png
Normal file
|
After Width: | Height: | Size: 599 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_none.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_other.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_pdf.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_rar.png
Normal file
|
After Width: | Height: | Size: 621 B |
BIN
Wino.Mail.WinUI/Assets/FileTypes/type_video.png
Normal file
|
After Width: | Height: | Size: 413 B |
BIN
Wino.Mail.WinUI/Assets/LargeTile.scale-100.png
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
Wino.Mail.WinUI/Assets/LargeTile.scale-125.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
Wino.Mail.WinUI/Assets/LargeTile.scale-150.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
Wino.Mail.WinUI/Assets/LargeTile.scale-200.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Wino.Mail.WinUI/Assets/LargeTile.scale-400.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
Wino.Mail.WinUI/Assets/NotificationIcons/delete.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Wino.Mail.WinUI/Assets/NotificationIcons/dismiss.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Wino.Mail.WinUI/Assets/NotificationIcons/markread.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
Wino.Mail.WinUI/Assets/NotificationIcons/profile-dark.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Wino.Mail.WinUI/Assets/NotificationIcons/profile-light.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Wino.Mail.WinUI/Assets/Providers/Gmail.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Wino.Mail.WinUI/Assets/Providers/IMAP4.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Wino.Mail.WinUI/Assets/Providers/Office 365.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
Wino.Mail.WinUI/Assets/Providers/Outlook.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Wino.Mail.WinUI/Assets/Providers/Yahoo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
33
Wino.Mail.WinUI/Assets/ReleaseNotes/176.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# 🚀 Welcome to Wino Mail 1.7.6
|
||||
|
||||
This version brings bunch of UI improvements and bugfixes on top of the added features thanks to our community members.
|
||||
|
||||
## Separated UI Zones
|
||||
|
||||
Community liked the proposed designs for separated UI parts and it's implemented now thanks to [Tiktack](https://github.com/Tiktack)
|
||||
|
||||

|
||||
|
||||
## Including Conversation History for Replies and Forwards
|
||||
|
||||
Previously when you replied to an e-mail conversation history was not included into new draft. This was a limitation due to Quill editor we use as a composer editor but now thanks to [Tiktack](https://github.com/Tiktack) Wino now uses Jodit editor as a composer. It's able to render HTML as it is better.
|
||||
|
||||
## HTML Signatures
|
||||
|
||||
You can now copy your signature as HTML and paste directly into signature editor. This was asked by community and now is possible with the new Jodit composer.
|
||||
|
||||
## Reworked Menu System
|
||||
|
||||
Merged accounts will not list individual accounts below instead of inside the More folder menu item.
|
||||
|
||||
## New IMAP and Gmail Folder Synchronization
|
||||
|
||||
IMAP and Gmail folder synchronization mechanism is reworked. New code works faster and fixed couple parent-child relation issues with the folder. I hope this will also resolve a lot of people complaining some Gmail folders are not visible for them after the initial sync.
|
||||
|
||||
## New Languages
|
||||
|
||||
Thanks to our amazing community members Wino has more languages supported in this version with the help of Crowdin contributors.
|
||||
|
||||

|
||||
|
||||
Some of the translations are not completed yet, and Wino will fallback to English strings in case of the translation has not been translated yet.
|
||||
BIN
Wino.Mail.WinUI/Assets/SmallTile.scale-100.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Wino.Mail.WinUI/Assets/SmallTile.scale-125.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Wino.Mail.WinUI/Assets/SmallTile.scale-150.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
Wino.Mail.WinUI/Assets/SmallTile.scale-200.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
Wino.Mail.WinUI/Assets/SmallTile.scale-400.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Wino.Mail.WinUI/Assets/SplashScreen.scale-100.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
Wino.Mail.WinUI/Assets/SplashScreen.scale-125.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
Wino.Mail.WinUI/Assets/SplashScreen.scale-150.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 28 KiB |
BIN
Wino.Mail.WinUI/Assets/SplashScreen.scale-400.png
Normal file
|
After Width: | Height: | Size: 102 KiB |
BIN
Wino.Mail.WinUI/Assets/Square150x150Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
Wino.Mail.WinUI/Assets/Square150x150Logo.scale-125.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
Wino.Mail.WinUI/Assets/Square150x150Logo.scale-150.png
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 8.5 KiB |
BIN
Wino.Mail.WinUI/Assets/Square150x150Logo.scale-400.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 755 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 755 B |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.scale-125.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.scale-150.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 4.2 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.scale-400.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-16.png
Normal file
|
After Width: | Height: | Size: 592 B |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-24.png
Normal file
|
After Width: | Height: | Size: 962 B |
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 1.2 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-256.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-32.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Wino.Mail.WinUI/Assets/Square44x44Logo.targetsize-48.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Wino.Mail.WinUI/Assets/StoreLogo.backup.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Wino.Mail.WinUI/Assets/StoreLogo.scale-100.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Wino.Mail.WinUI/Assets/StoreLogo.scale-125.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Wino.Mail.WinUI/Assets/StoreLogo.scale-150.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
Wino.Mail.WinUI/Assets/StoreLogo.scale-200.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
Wino.Mail.WinUI/Assets/StoreLogo.scale-400.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
Wino.Mail.WinUI/Assets/Thumbnails/airbnb.com.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Wino.Mail.WinUI/Assets/Thumbnails/apple.com.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Wino.Mail.WinUI/Assets/Thumbnails/google.com.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |