Initial commit.
39
Wino.Mail/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
174
Wino.Mail/Activation/BackgroundActivationHandler.cs
Normal file
@@ -0,0 +1,174 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Toolkit.Uwp.Notifications;
|
||||
using Serilog;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Background;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Notifications;
|
||||
using Wino.Core;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.MailItem;
|
||||
using Wino.Core.Domain.Models.Synchronization;
|
||||
using Wino.Core.UWP.Services;
|
||||
using Wino.Services;
|
||||
|
||||
namespace Wino.Activation
|
||||
{
|
||||
internal class BackgroundActivationHandler : ActivationHandler<BackgroundActivatedEventArgs>
|
||||
{
|
||||
private const string BackgroundExecutionLogTag = "[BackgroundExecution] ";
|
||||
|
||||
private readonly IWinoRequestDelegator _winoRequestDelegator;
|
||||
private readonly IBackgroundSynchronizer _backgroundSynchronizer;
|
||||
private readonly INativeAppService _nativeAppService;
|
||||
private readonly IWinoRequestProcessor _winoRequestProcessor;
|
||||
private readonly IWinoSynchronizerFactory _winoSynchronizerFactory;
|
||||
private readonly IMailService _mailService;
|
||||
private ToastArguments _toastArguments;
|
||||
|
||||
BackgroundTaskDeferral _deferral;
|
||||
public BackgroundActivationHandler(IWinoRequestDelegator winoRequestDelegator,
|
||||
IBackgroundSynchronizer backgroundSynchronizer,
|
||||
INativeAppService nativeAppService,
|
||||
IWinoRequestProcessor winoRequestProcessor,
|
||||
IWinoSynchronizerFactory winoSynchronizerFactory,
|
||||
IMailService mailService)
|
||||
{
|
||||
_winoRequestDelegator = winoRequestDelegator;
|
||||
_backgroundSynchronizer = backgroundSynchronizer;
|
||||
_nativeAppService = nativeAppService;
|
||||
_winoRequestProcessor = winoRequestProcessor;
|
||||
_winoSynchronizerFactory = winoSynchronizerFactory;
|
||||
_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)
|
||||
{
|
||||
// ToastNotificationActionTriggerDetail somehow use UI thread.
|
||||
// Calling this without a dispatcher will result in error.
|
||||
|
||||
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
|
||||
{
|
||||
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))
|
||||
{
|
||||
// TODO: Remote folder id.
|
||||
var mailItem = await _mailService.GetSingleMailItemAsync(mailItemId, string.Empty);
|
||||
|
||||
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)
|
||||
{
|
||||
synchronizer.QueueRequest(request);
|
||||
}
|
||||
|
||||
var options = new SynchronizationOptions()
|
||||
{
|
||||
Type = SynchronizationType.ExecuteRequests,
|
||||
AccountId = mailItem.AssignedAccount.Id
|
||||
};
|
||||
|
||||
await synchronizer.SynchronizeAsync(options);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (taskName == BackgroundTaskService.BackgroundSynchronizationTimerTaskNameEx)
|
||||
{
|
||||
var watch = new Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
// Run timer based background synchronization.
|
||||
|
||||
await _backgroundSynchronizer.RunBackgroundSynchronizationAsync(BackgroundSynchronizationReason.Timer);
|
||||
|
||||
watch.Stop();
|
||||
Log.Information($"{BackgroundExecutionLogTag}Background synchronization is completed in {watch.Elapsed.TotalSeconds} seconds.");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Wino.Mail/Activation/DefaultActivationHandler.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.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;
|
||||
}
|
||||
}
|
||||
68
Wino.Mail/Activation/FileActivationHandler.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Services;
|
||||
using Wino.Helpers;
|
||||
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 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/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Wino.Mail/Activation/ToastNotificationActivationHandler.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
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.Core.Messages.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 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
212
Wino.Mail/App.xaml
Normal file
@@ -0,0 +1,212 @@
|
||||
<Application
|
||||
x:Class="Wino.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:selectors="using:Wino.Selectors"
|
||||
xmlns:wino="using:Wino">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<ResourceDictionary Source="/Styles/Converters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/FontIcons.xaml" />
|
||||
<ResourceDictionary Source="/Styles/Colors.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ContentPresenters.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ImagePreviewControl.xaml" />
|
||||
<ResourceDictionary Source="/Styles/CommandBarItems.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ItemContainerStyles.xaml" />
|
||||
<ResourceDictionary Source="/Styles/WinoInfoBar.xaml" />
|
||||
|
||||
<ResourceDictionary>
|
||||
|
||||
<x:Double x:Key="AppBarButtonContentHeight">19</x:Double>
|
||||
<x:Double x:Key="NavigationViewItemOnLeftIconBoxHeight">19</x:Double>
|
||||
<Thickness x:Key="ImapSetupDialogSubPagePadding">24,24,24,24</Thickness>
|
||||
|
||||
<Style x:Key="PageStyle" TargetType="Page">
|
||||
<Setter Property="Margin" Value="-1,0,0,0" />
|
||||
<Setter Property="Padding" Value="12" />
|
||||
<Setter Property="Background" Value="{ThemeResource AppBarBackgroundColor}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid Padding="12">
|
||||
<ContentPresenter />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Default StackPanel animation. -->
|
||||
<Style TargetType="StackPanel">
|
||||
<Setter Property="ChildrenTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection>
|
||||
<EntranceThemeTransition IsStaggeringEnabled="True" />
|
||||
</TransitionCollection>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Default Style for ContentDialog -->
|
||||
<Style
|
||||
x:Key="WinoDialogStyle"
|
||||
BasedOn="{StaticResource DefaultContentDialogStyle}"
|
||||
TargetType="ContentDialog" />
|
||||
|
||||
<!-- Settings Menu Item Template -->
|
||||
<Style TargetType="controls:SettingsMenuItemControl">
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalAlignment" Value="Stretch" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="IsClickable" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:SettingsMenuItemControl">
|
||||
<Grid>
|
||||
<Button
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Command="{TemplateBinding Command}"
|
||||
CommandParameter="{TemplateBinding CommandParameter}"
|
||||
IsEnabled="{TemplateBinding IsEnabled}"
|
||||
IsHitTestVisible="{TemplateBinding IsClickable}">
|
||||
<Grid
|
||||
Height="70"
|
||||
Padding="0,6,12,6"
|
||||
CornerRadius="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="50" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ContentControl
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding Icon}" />
|
||||
|
||||
<Grid
|
||||
Grid.Column="1"
|
||||
Margin="4,0"
|
||||
VerticalAlignment="Center"
|
||||
RowSpacing="3">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
Style="{StaticResource BodyTextBlockStyle}"
|
||||
Text="{TemplateBinding Title}" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{TemplateBinding Description}" />
|
||||
</Grid>
|
||||
|
||||
<Viewbox
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Width="16"
|
||||
Height="16"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=IsNavigateIconVisible}">
|
||||
<PathIcon Data="F1 M 5.029297 19.091797 L 14.111328 10 L 5.029297 0.908203 L 5.908203 0.029297 L 15.888672 10 L 5.908203 19.970703 Z " />
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
</Button>
|
||||
|
||||
<ContentControl
|
||||
Grid.RowSpan="2"
|
||||
Margin="0,0,16,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding SideContent}"
|
||||
IsHitTestVisible="True"
|
||||
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=IsNavigateIconVisible, Converter={StaticResource ReverseBooleanToVisibilityConverter}}" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Wino Navigation View Item -->
|
||||
<Style TargetType="controls:WinoNavigationViewItem">
|
||||
<Setter Property="ContentTransitions">
|
||||
<Setter.Value>
|
||||
<TransitionCollection>
|
||||
<PopupThemeTransition />
|
||||
</TransitionCollection>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<DataTemplate x:Key="NoneTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_none.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ExecutableTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_executable.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ImageTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_image.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="VideoTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_video.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="AudioTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_audio.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="PDFTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_pdf.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="HTMLTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_html.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="RarTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_rar.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="ArchiveTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_archive.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate x:Key="OtherTemplate">
|
||||
<Image Source="/Assets/FileTypes/type_other.png" />
|
||||
</DataTemplate>
|
||||
|
||||
<selectors:FileAttachmentTypeSelector
|
||||
x:Key="FileTypeIconSelector"
|
||||
Archive="{StaticResource ArchiveTemplate}"
|
||||
Executable="{StaticResource ExecutableTemplate}"
|
||||
HTML="{StaticResource HTMLTemplate}"
|
||||
Image="{StaticResource ImageTemplate}"
|
||||
None="{StaticResource NoneTemplate}"
|
||||
Other="{StaticResource OtherTemplate}"
|
||||
PDF="{StaticResource PDFTemplate}"
|
||||
RarArchive="{StaticResource RarTemplate}"
|
||||
Video="{StaticResource VideoTemplate}" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
|
||||
<!-- Last item must always be the default theme. -->
|
||||
<ResourceDictionary Source="/AppThemes/Mica.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
334
Wino.Mail/App.xaml.cs
Normal file
@@ -0,0 +1,334 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AppCenter;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using Microsoft.AppCenter.Crashes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Serilog;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.ApplicationModel.Resources;
|
||||
using Windows.Foundation.Metadata;
|
||||
using Windows.Globalization;
|
||||
using Windows.Storage;
|
||||
using Windows.System.Profile;
|
||||
using Windows.UI;
|
||||
using Windows.UI.ViewManagement;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Wino.Activation;
|
||||
using Wino.Core;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Services;
|
||||
using Wino.Core.UWP;
|
||||
using Wino.Core.UWP.Services;
|
||||
using Wino.Mail.ViewModels;
|
||||
using Wino.Services;
|
||||
|
||||
namespace Wino
|
||||
{
|
||||
public sealed partial class App : Application
|
||||
{
|
||||
private const string WinoLaunchLogPrefix = "[Wino Launch] ";
|
||||
private const string AppCenterKey = "90deb1d0-a77f-47d0-8a6b-7eaf111c6b72";
|
||||
|
||||
public new static App Current => (App)Application.Current;
|
||||
public IServiceProvider Services { get; }
|
||||
|
||||
private readonly ILogInitializer _logInitializer;
|
||||
private readonly IThemeService _themeService;
|
||||
private readonly IDatabaseService _databaseService;
|
||||
private readonly IAppInitializerService _appInitializerService;
|
||||
private readonly IWinoSynchronizerFactory _synchronizerFactory;
|
||||
private readonly ITranslationService _translationService;
|
||||
|
||||
// Order matters.
|
||||
private List<IInitializeAsync> initializeServices => new List<IInitializeAsync>()
|
||||
{
|
||||
_translationService,
|
||||
_databaseService,
|
||||
_themeService,
|
||||
_synchronizerFactory
|
||||
};
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
UnhandledException += OnAppUnhandledException;
|
||||
EnteredBackground += OnEnteredBackground;
|
||||
LeavingBackground += OnLeavingBackground;
|
||||
|
||||
Services = ConfigureServices();
|
||||
|
||||
_logInitializer = Services.GetService<ILogInitializer>();
|
||||
|
||||
ConfigureLogger();
|
||||
ConfigureAppCenter();
|
||||
ConfigurePrelaunch();
|
||||
ConfigureXbox();
|
||||
|
||||
_themeService = Services.GetService<IThemeService>();
|
||||
_databaseService = Services.GetService<IDatabaseService>();
|
||||
_appInitializerService = Services.GetService<IAppInitializerService>();
|
||||
_synchronizerFactory = Services.GetService<IWinoSynchronizerFactory>();
|
||||
_translationService = Services.GetService<ITranslationService>();
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
}
|
||||
|
||||
private void LogActivation(string log) => Log.Information($"{WinoLaunchLogPrefix}{log}");
|
||||
private void OnLeavingBackground(object sender, LeavingBackgroundEventArgs e) => LogActivation($"Wino went foreground.");
|
||||
private void OnEnteredBackground(object sender, EnteredBackgroundEventArgs e) => LogActivation($"Wino went background.");
|
||||
private IServiceProvider ConfigureServices()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.RegisterCoreServices();
|
||||
services.RegisterCoreUWPServices();
|
||||
|
||||
RegisterUWPServices(services);
|
||||
RegisterViewModels(services);
|
||||
RegisterActivationHandlers(services);
|
||||
|
||||
return services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
#region Dependency Injection
|
||||
|
||||
private void RegisterActivationHandlers(IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<ProtocolActivationHandler>();
|
||||
services.AddTransient<BackgroundActivationHandler>();
|
||||
services.AddTransient<ToastNotificationActivationHandler>();
|
||||
services.AddTransient<FileActivationHandler>();
|
||||
}
|
||||
|
||||
private void RegisterUWPServices(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IApplicationResourceManager<ResourceDictionary>, ApplicationResourceManager>();
|
||||
services.AddSingleton<IThemeService, ThemeService>();
|
||||
services.AddSingleton<IThemeService, ThemeService>();
|
||||
services.AddSingleton<IPreferencesService, PreferencesService>();
|
||||
services.AddSingleton<IStatePersistanceService, StatePersistenceService>();
|
||||
services.AddSingleton<ILaunchProtocolService, LaunchProtocolService>();
|
||||
services.AddSingleton<IWinoNavigationService, WinoNavigationService>();
|
||||
services.AddSingleton<IDialogService, DialogService>();
|
||||
}
|
||||
|
||||
private void RegisterViewModels(IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton(typeof(AppShellViewModel));
|
||||
services.AddTransient(typeof(SettingsDialogViewModel));
|
||||
services.AddTransient(typeof(PersonalizationPageViewModel));
|
||||
services.AddTransient(typeof(SettingOptionsPageViewModel));
|
||||
services.AddTransient(typeof(MailListPageViewModel));
|
||||
services.AddTransient(typeof(MailRenderingPageViewModel));
|
||||
services.AddTransient(typeof(AccountManagementViewModel));
|
||||
services.AddTransient(typeof(WelcomePageViewModel));
|
||||
services.AddTransient(typeof(AboutPageViewModel));
|
||||
services.AddTransient(typeof(ComposePageViewModel));
|
||||
services.AddTransient(typeof(IdlePageViewModel));
|
||||
services.AddTransient(typeof(SettingsPageViewModel));
|
||||
services.AddTransient(typeof(NewAccountManagementPageViewModel));
|
||||
services.AddTransient(typeof(AccountDetailsPageViewModel));
|
||||
services.AddTransient(typeof(SignatureManagementPageViewModel));
|
||||
services.AddTransient(typeof(MessageListPageViewModel));
|
||||
services.AddTransient(typeof(ReadingPanePageViewModel));
|
||||
services.AddTransient(typeof(MergedAccountDetailsPageViewModel));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Misc Configuration
|
||||
|
||||
private void ConfigureLogger() => _logInitializer.SetupLogger(ApplicationData.Current.LocalFolder.Path);
|
||||
|
||||
private void ConfigureAppCenter() => AppCenter.Start(AppCenterKey, typeof(Analytics), typeof(Crashes));
|
||||
|
||||
private void ConfigurePrelaunch()
|
||||
{
|
||||
if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch"))
|
||||
CoreApplication.EnablePrelaunch(true);
|
||||
}
|
||||
|
||||
private void ConfigureXbox()
|
||||
{
|
||||
// Xbox users should use Reveal focus.
|
||||
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 6))
|
||||
{
|
||||
FocusVisualKind = AnalyticsInfo.VersionInfo.DeviceFamily == "Xbox" ? FocusVisualKind.Reveal : FocusVisualKind.HighVisibility;
|
||||
}
|
||||
}
|
||||
|
||||
private void ConfigureTitleBar()
|
||||
{
|
||||
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
|
||||
var applicationViewTitleBar = ApplicationView.GetForCurrentView().TitleBar;
|
||||
|
||||
// Extend shell content into core window to meet design requirements.
|
||||
coreTitleBar.ExtendViewIntoTitleBar = true;
|
||||
|
||||
// Change system buttons and background colors to meet design requirements.
|
||||
applicationViewTitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.BackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
|
||||
applicationViewTitleBar.ButtonForegroundColor = Colors.White;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnWindowCreated(WindowCreatedEventArgs args)
|
||||
{
|
||||
base.OnWindowCreated(args);
|
||||
|
||||
LogActivation("Window is created.");
|
||||
|
||||
ConfigureTitleBar();
|
||||
}
|
||||
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
LogActivation($"OnLaunched -> {args.GetType().Name}, Kind -> {args.Kind}, PreviousExecutionState -> {args.PreviousExecutionState}, IsPrelaunch -> {args.PrelaunchActivated}");
|
||||
|
||||
if (!args.PrelaunchActivated)
|
||||
{
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async void OnFileActivated(FileActivatedEventArgs args)
|
||||
{
|
||||
base.OnFileActivated(args);
|
||||
|
||||
Log.Information($"File activation for {args.Files.Count} item(s).");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
protected override async void OnActivated(IActivatedEventArgs args)
|
||||
{
|
||||
base.OnActivated(args);
|
||||
|
||||
Log.Information($"OnActivated -> {args.GetType().Name}, Kind -> {args.Kind}, Prev Execution State -> {args.PreviousExecutionState}");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
|
||||
{
|
||||
base.OnBackgroundActivated(args);
|
||||
|
||||
LogActivation($"OnBackgroundActivated -> {args.GetType().Name}, TaskInstanceIdName -> {args.TaskInstance?.Task?.Name ?? "NA"}");
|
||||
|
||||
await ActivateWinoAsync(args);
|
||||
}
|
||||
|
||||
private void OnAppUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
|
||||
{
|
||||
var parameters = new Dictionary<string, string>()
|
||||
{
|
||||
{ "BaseMessage", e.Exception.GetBaseException().Message },
|
||||
{ "BaseStackTrace", e.Exception.GetBaseException().StackTrace },
|
||||
{ "StackTrace", e.Exception.StackTrace },
|
||||
{ "Message", e.Exception.Message },
|
||||
};
|
||||
|
||||
Log.Error(e.Exception, "[Wino Crash]");
|
||||
|
||||
Crashes.TrackError(e.Exception, parameters);
|
||||
Analytics.TrackEvent("Wino Crashed", parameters);
|
||||
}
|
||||
|
||||
private bool IsInteractiveLaunchArgs(object args) => args is IActivatedEventArgs;
|
||||
|
||||
private async Task ActivateWinoAsync(object args)
|
||||
{
|
||||
await PreInitializationAsync();
|
||||
|
||||
if (IsInteractiveLaunchArgs(args))
|
||||
{
|
||||
if (Window.Current.Content == null)
|
||||
{
|
||||
var mainFrame = new Frame();
|
||||
|
||||
Window.Current.Content = mainFrame;
|
||||
|
||||
await _themeService.InitializeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
await HandleActivationAsync(args);
|
||||
|
||||
if (IsInteractiveLaunchArgs(args))
|
||||
{
|
||||
Window.Current.Activate();
|
||||
|
||||
LogActivation("Window activated");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tasks that must run before the activation and launch.
|
||||
/// Regardless of whether it's an interactive launch or not.
|
||||
/// </summary>
|
||||
private async Task PreInitializationAsync()
|
||||
{
|
||||
// Handle migrations.
|
||||
// TODO: Automate migration process with more proper way.
|
||||
|
||||
if (!ApplicationData.Current.LocalSettings.Values.ContainsKey("Migration_169"))
|
||||
{
|
||||
try
|
||||
{
|
||||
await _appInitializerService.MigrateAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error(ex, $"{WinoLaunchLogPrefix}Migration_169 failed.");
|
||||
}
|
||||
finally
|
||||
{
|
||||
ApplicationData.Current.LocalSettings.Values["Migration_169"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var service in initializeServices)
|
||||
{
|
||||
await service.InitializeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleActivationAsync(object activationArgs)
|
||||
{
|
||||
var activationHandler = GetActivationHandlers().FirstOrDefault(h => h.CanHandle(activationArgs));
|
||||
|
||||
if (activationHandler != null)
|
||||
{
|
||||
await activationHandler.HandleAsync(activationArgs);
|
||||
}
|
||||
|
||||
if (IsInteractiveLaunchArgs(activationArgs))
|
||||
{
|
||||
var defaultHandler = new DefaultActivationHandler();
|
||||
if (defaultHandler.CanHandle(activationArgs))
|
||||
{
|
||||
await defaultHandler.HandleAsync(activationArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<ActivationHandler> GetActivationHandlers()
|
||||
{
|
||||
yield return Services.GetService<ProtocolActivationHandler>();
|
||||
yield return Services.GetService<BackgroundActivationHandler>();
|
||||
yield return Services.GetService<ToastNotificationActivationHandler>();
|
||||
yield return Services.GetService<FileActivationHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
613
Wino.Mail/AppShell.xaml
Normal file
303
Wino.Mail/AppShell.xaml.cs
Normal file
@@ -0,0 +1,303 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Input;
|
||||
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;
|
||||
|
||||
var menuItem = ViewModel.MenuItems.GetFolderItem(message.FolderId);
|
||||
|
||||
if (menuItem == null) return;
|
||||
|
||||
menuItem.Expand();
|
||||
|
||||
await ViewModel.NavigateFolderAsync(menuItem);
|
||||
|
||||
navigationView.SelectedItem = menuItem;
|
||||
|
||||
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, Windows.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());
|
||||
}
|
||||
|
||||
private void OnShellLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Wino.Mail/AppThemes/Acrylic.xaml
Normal file
@@ -0,0 +1,43 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:local="using:Microsoft.UI.Xaml.Media"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
|
||||
<x:String x:Key="ThemeName">Acrylic</x:String>
|
||||
<x:Boolean x:Key="UseMica">False</x:Boolean>
|
||||
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
<Thickness x:Key="RendererGridMargin">0,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<!-- Acrylic Template -->
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Reading Pane Background -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">white</SolidColorBrush>
|
||||
|
||||
<!-- Reading Page Date/Name Group Header Background -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#ecf0f1</SolidColorBrush>
|
||||
|
||||
<local:AcrylicBrush
|
||||
x:Key="WinoApplicationBackgroundColor"
|
||||
TintColor="#FCFCFC"
|
||||
TintOpacity="0.75"
|
||||
FallbackColor="#F9F9F9"
|
||||
BackgroundSource="HostBackdrop" />
|
||||
</ResourceDictionary>
|
||||
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">Transparent</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#2C2C2C</SolidColorBrush>
|
||||
|
||||
<local:AcrylicBrush
|
||||
x:Key="WinoApplicationBackgroundColor"
|
||||
TintColor="#2C2C2C"
|
||||
TintOpacity="0.30"
|
||||
FallbackColor="#2C2C2C"
|
||||
BackgroundSource="HostBackdrop" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
27
Wino.Mail/AppThemes/Clouds.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
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>
|
||||
<Thickness x:Key="RendererGridMargin">4,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3FFFFFF</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#FFFFFF</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3262626</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#5413191F</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
53
Wino.Mail/AppThemes/Custom.xaml
Normal file
@@ -0,0 +1,53 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/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"
|
||||
Stretch="UniformToFill"
|
||||
ImageSource="{StaticResource ThemeBackgroundImage}" />
|
||||
|
||||
<Thickness x:Key="RendererGridMargin">0,0,0,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">0,6,6,0</xaml:CornerRadius>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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 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>
|
||||
27
Wino.Mail/AppThemes/Forest.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/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>
|
||||
<Thickness x:Key="RendererGridMargin">4,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#2900F00A</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#A800D608</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3262626</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#59001C01</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
27
Wino.Mail/AppThemes/Garden.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
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>
|
||||
<Thickness x:Key="RendererGridMargin">4,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3FFFFFF</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#FFFFFF</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3262626</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#5413191F</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
28
Wino.Mail/AppThemes/Mica.xaml
Normal file
@@ -0,0 +1,28 @@
|
||||
<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">Mica</x:String>
|
||||
<x:Boolean x:Key="UseMica">True</x:Boolean>
|
||||
|
||||
<SolidColorBrush x:Key="WinoApplicationBackgroundColor">Transparent</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="AppBarBackgroundColor">Transparent</SolidColorBrush>
|
||||
<Thickness x:Key="RendererGridMargin">0,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<!-- Mica Template -->
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Reading Pane Background -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">white</SolidColorBrush>
|
||||
|
||||
<!-- Reading Page Date/Name Group Header Background -->
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#ecf0f1</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">Transparent</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#1f1f1f</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
27
Wino.Mail/AppThemes/Nighty.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
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>
|
||||
<Thickness x:Key="RendererGridMargin">4,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3FFFFFF</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#fdcb6e</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3262626</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#5413191F</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
27
Wino.Mail/AppThemes/Snowflake.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:xaml="using:Windows.UI.Xaml"
|
||||
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>
|
||||
<Thickness x:Key="RendererGridMargin">4,0,4,0</Thickness>
|
||||
<xaml:CornerRadius x:Key="MailListGridCornerRadius">6,6,6,6</xaml:CornerRadius>
|
||||
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Name="Light">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3FFFFFF</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#FFFFFF</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
<ResourceDictionary x:Name="Dark">
|
||||
<!-- Brushes -->
|
||||
<SolidColorBrush x:Key="ReadingPaneBackgroundColorBrush">#A3262626</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="MailListHeaderBackgroundColor">#5413191F</SolidColorBrush>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.ThemeDictionaries>
|
||||
</ResourceDictionary>
|
||||
22
Wino.Mail/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/Assets/BadgeLogo.scale-100.png
Normal file
|
After Width: | Height: | Size: 228 B |
BIN
Wino.Mail/Assets/BadgeLogo.scale-125.png
Normal file
|
After Width: | Height: | Size: 265 B |
BIN
Wino.Mail/Assets/BadgeLogo.scale-150.png
Normal file
|
After Width: | Height: | Size: 338 B |
BIN
Wino.Mail/Assets/BadgeLogo.scale-200.png
Normal file
|
After Width: | Height: | Size: 437 B |
BIN
Wino.Mail/Assets/BadgeLogo.scale-400.png
Normal file
|
After Width: | Height: | Size: 903 B |
BIN
Wino.Mail/Assets/EML/eml.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
Wino.Mail/Assets/FileTypes/type_archive.png
Normal file
|
After Width: | Height: | Size: 348 B |
BIN
Wino.Mail/Assets/FileTypes/type_audio.png
Normal file
|
After Width: | Height: | Size: 504 B |
BIN
Wino.Mail/Assets/FileTypes/type_executable.png
Normal file
|
After Width: | Height: | Size: 678 B |
BIN
Wino.Mail/Assets/FileTypes/type_html.png
Normal file
|
After Width: | Height: | Size: 591 B |
BIN
Wino.Mail/Assets/FileTypes/type_image.png
Normal file
|
After Width: | Height: | Size: 599 B |
BIN
Wino.Mail/Assets/FileTypes/type_none.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Wino.Mail/Assets/FileTypes/type_other.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
Wino.Mail/Assets/FileTypes/type_pdf.png
Normal file
|
After Width: | Height: | Size: 712 B |
BIN
Wino.Mail/Assets/FileTypes/type_rar.png
Normal file
|
After Width: | Height: | Size: 621 B |
BIN
Wino.Mail/Assets/FileTypes/type_video.png
Normal file
|
After Width: | Height: | Size: 413 B |
BIN
Wino.Mail/Assets/LargeTile.scale-100.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Wino.Mail/Assets/LargeTile.scale-125.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
Wino.Mail/Assets/LargeTile.scale-150.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
Wino.Mail/Assets/LargeTile.scale-200.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
Wino.Mail/Assets/LargeTile.scale-400.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
Wino.Mail/Assets/NotificationIcons/delete.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Wino.Mail/Assets/NotificationIcons/dismiss.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Wino.Mail/Assets/NotificationIcons/markread.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
Wino.Mail/Assets/NotificationIcons/profile-dark.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
Wino.Mail/Assets/NotificationIcons/profile-light.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Wino.Mail/Assets/Providers/Gmail.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Wino.Mail/Assets/Providers/IMAP4.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
Wino.Mail/Assets/Providers/Office 365.png
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
Wino.Mail/Assets/Providers/Outlook.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
Wino.Mail/Assets/Providers/Yahoo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
11
Wino.Mail/Assets/ReleaseNotes/170.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# 🚀 Good job on building Wino Mail from the source 🙂
|
||||
|
||||
## Once we finish pre-release testing, I will add the 1.7.0 patch notes here.
|
||||
|
||||
### Right now, it's pretty lonely here. 🤷♂️
|
||||
|
||||
- Make sure you read the contributuion guidelines before you start diving into the code. ⚠️
|
||||
- You may find some redundant methods, interfaces, classes, etc. that are not used in the project. Please ignore them for now 🥺. I will clean them up in the future.
|
||||
- If you want to disable the unlimited account check, go to AccountManagementViewModel.cs and update the Free Account Count property at the top 😁
|
||||
- If you have any questions, feel free to ask me on [Twitter 🐦](https://twitter.com/TrayhopeR) or project's Discord channels.
|
||||
- Good luck! 🍀
|
||||
BIN
Wino.Mail/Assets/SmallTile.scale-100.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Wino.Mail/Assets/SmallTile.scale-125.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
Wino.Mail/Assets/SmallTile.scale-150.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Wino.Mail/Assets/SmallTile.scale-200.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
Wino.Mail/Assets/SmallTile.scale-400.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
Wino.Mail/Assets/SplashScreen.scale-100.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
Wino.Mail/Assets/SplashScreen.scale-125.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
Wino.Mail/Assets/SplashScreen.scale-150.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
Wino.Mail/Assets/SplashScreen.scale-200.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
Wino.Mail/Assets/SplashScreen.scale-400.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
Wino.Mail/Assets/Square150x150Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Wino.Mail/Assets/Square150x150Logo.scale-125.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
Wino.Mail/Assets/Square150x150Logo.scale-150.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
Wino.Mail/Assets/Square150x150Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
Wino.Mail/Assets/Square150x150Logo.scale-400.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 764 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 764 B |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.scale-125.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.scale-150.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.scale-400.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.targetsize-16.png
Normal file
|
After Width: | Height: | Size: 568 B |
BIN
Wino.Mail/Assets/Square44x44Logo.targetsize-24.png
Normal file
|
After Width: | Height: | Size: 956 B |
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.targetsize-256.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.targetsize-32.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Wino.Mail/Assets/Square44x44Logo.targetsize-48.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Wino.Mail/Assets/StoreLogo.backup.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Wino.Mail/Assets/StoreLogo.scale-100.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
Wino.Mail/Assets/StoreLogo.scale-125.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
Wino.Mail/Assets/StoreLogo.scale-150.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
Wino.Mail/Assets/StoreLogo.scale-200.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
Wino.Mail/Assets/StoreLogo.scale-400.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
Wino.Mail/Assets/Thumbnails/airbnb.com.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
Wino.Mail/Assets/Thumbnails/apple.com.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
Wino.Mail/Assets/Thumbnails/google.com.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
Wino.Mail/Assets/Thumbnails/microsoft.com.png
Normal file
|
After Width: | Height: | Size: 574 B |
BIN
Wino.Mail/Assets/Thumbnails/steampowered.com.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
Wino.Mail/Assets/Thumbnails/uber.com.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
Wino.Mail/Assets/Thumbnails/youtube.com.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Wino.Mail/Assets/Wide310x150Logo.scale-100.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |