I don't know some changes....
This commit is contained in:
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class AboutPageAbstract : BasePage<AboutPageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class AccountDetailsPageAbstract : BasePage<AccountDetailsPageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class AccountManagementPageAbstract : BasePage<AccountManagementViewModel>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class AppShellAbstract : BasePage<AppShellViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class ComposePageAbstract : BasePage<ComposePageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class IdlePageAbstract : BasePage<IdlePageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class LanguageTimePageAbstract : BasePage<LanguageTimePageViewModel> { }
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public class MailListPageAbstract : BasePage<MailListPageViewModel>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class MailRenderingPageAbstract : BasePage<MailRenderingPageViewModel>
|
||||
{
|
||||
public bool IsDarkEditor
|
||||
{
|
||||
get { return (bool)GetValue(IsDarkEditorProperty); }
|
||||
set { SetValue(IsDarkEditorProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsDarkEditorProperty = DependencyProperty.Register(nameof(IsDarkEditor), typeof(bool), typeof(MailRenderingPageAbstract), new PropertyMetadata(false, OnIsComposerDarkModeChanged));
|
||||
|
||||
private static void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is MailRenderingPageAbstract page)
|
||||
{
|
||||
page.OnEditorThemeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnEditorThemeChanged() { }
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class MergedAccountDetailsPageAbstract : BasePage<MergedAccountDetailsPageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class MessageListPageAbstract : BasePage<MessageListPageViewModel> { }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class NewAccountManagementPageAbstract : BasePage<NewAccountManagementPageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class PersonalizationPageAbstract : SettingsPageBase<PersonalizationPageViewModel>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class ReadingPanePageAbstract : BasePage<ReadingPanePageViewModel> { }
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class SettingOptionsPageAbstract : SettingsPageBase<SettingOptionsPageViewModel>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class SettingsPageAbstract : BasePage<SettingsPageViewModel> { }
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public class SettingsPageBase<T> : BasePage<T> where T : BaseViewModel
|
||||
{
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(nameof(Title), typeof(string), typeof(SettingsPageBase<T>), new PropertyMetadata(string.Empty));
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class SignatureManagementPageAbstract : BasePage<SignatureManagementPageViewModel> { }
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using Wino.Mail.ViewModels;
|
||||
|
||||
namespace Wino.Views.Abstract
|
||||
{
|
||||
public abstract class WelcomePageAbstract : BasePage<WelcomePageViewModel>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,37 +0,0 @@
|
||||
using Wino.Core.Domain.Models.Folders;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml;
|
||||
#else
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class AccountDetailsPage : AccountDetailsPageAbstract
|
||||
{
|
||||
public AccountDetailsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void SyncFolderToggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is CheckBox checkBox && checkBox.Tag is IMailItemFolder folder)
|
||||
{
|
||||
await ViewModel.FolderSyncToggledAsync(folder, checkBox.IsChecked.GetValueOrDefault());
|
||||
}
|
||||
}
|
||||
|
||||
private async void UnreadBadgeCheckboxToggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is CheckBox checkBox && checkBox.Tag is IMailItemFolder folder)
|
||||
{
|
||||
await ViewModel.FolderShowUnreadToggled(folder, checkBox.IsChecked.GetValueOrDefault());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,20 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class AccountManagementPage : AccountManagementPageAbstract
|
||||
{
|
||||
public AccountManagementPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
NavigationCacheMode = NavigationCacheMode.Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Account
|
||||
{
|
||||
public sealed partial class MergedAccountDetailsPage : MergedAccountDetailsPageAbstract
|
||||
{
|
||||
public MergedAccountDetailsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,700 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using EmailValidation;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using MimeKit;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Foundation;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.UI.ViewManagement.Core;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.Reader;
|
||||
using Wino.Core.Messages.Mails;
|
||||
using Wino.Core.Messages.Shell;
|
||||
using Wino.Extensions;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Views.Abstract;
|
||||
using CommunityToolkit.WinUI.Controls;
|
||||
using Wino.Helpers;
|
||||
using System.Text.Json;
|
||||
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class ComposePage : ComposePageAbstract,
|
||||
IRecipient<NavigationPaneModeChanged>,
|
||||
IRecipient<CreateNewComposeMailRequested>,
|
||||
IRecipient<ApplicationThemeChanged>
|
||||
{
|
||||
public bool IsComposerDarkMode
|
||||
{
|
||||
get { return (bool)GetValue(IsComposerDarkModeProperty); }
|
||||
set { SetValue(IsComposerDarkModeProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsComposerDarkModeProperty = DependencyProperty.Register(nameof(IsComposerDarkMode), typeof(bool), typeof(ComposePage), new PropertyMetadata(false, OnIsComposerDarkModeChanged));
|
||||
public WebView2 GetWebView() => Chromium;
|
||||
|
||||
private TaskCompletionSource<bool> DOMLoadedTask = new TaskCompletionSource<bool>();
|
||||
|
||||
private List<IDisposable> Disposables = new List<IDisposable>();
|
||||
|
||||
public ComposePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation");
|
||||
}
|
||||
|
||||
private static async void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is ComposePage page)
|
||||
{
|
||||
await page.UpdateEditorThemeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private IDisposable GetSuggestionBoxDisposable(TokenizingTextBox box)
|
||||
{
|
||||
return Observable.FromEventPattern<TypedEventHandler<AutoSuggestBox, AutoSuggestBoxTextChangedEventArgs>, AutoSuggestBoxTextChangedEventArgs>(
|
||||
x => box.TextChanged += x,
|
||||
x => box.TextChanged -= x)
|
||||
.Throttle(TimeSpan.FromMilliseconds(120))
|
||||
.ObserveOn(SynchronizationContext.Current)
|
||||
.Subscribe(t =>
|
||||
{
|
||||
if (t.EventArgs.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||
{
|
||||
if (t.Sender is AutoSuggestBox senderBox && senderBox.Text.Length >= 3)
|
||||
{
|
||||
_ = ViewModel.ContactService.GetAddressInformationAsync(senderBox.Text).ContinueWith(x =>
|
||||
{
|
||||
_ = ViewModel.ExecuteUIThread(() =>
|
||||
{
|
||||
var addresses = x.Result;
|
||||
|
||||
senderBox.ItemsSource = addresses;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async void AddFilesClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// TODO: Pick files
|
||||
var picker = new FileOpenPicker()
|
||||
{
|
||||
SuggestedStartLocation = PickerLocationId.Desktop
|
||||
};
|
||||
|
||||
picker.FileTypeFilter.Add("*");
|
||||
var files = await picker.PickMultipleFilesAsync();
|
||||
|
||||
await AttachFiles(files);
|
||||
}
|
||||
|
||||
private void OnComposeGridDragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
ViewModel.IsDraggingOverComposerGrid = true;
|
||||
}
|
||||
|
||||
private void OnComposeGridDragLeave(object sender, DragEventArgs e)
|
||||
{
|
||||
ViewModel.IsDraggingOverComposerGrid = false;
|
||||
}
|
||||
|
||||
private void OnFileDropGridDragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
ViewModel.IsDraggingOverFilesDropZone = true;
|
||||
|
||||
e.AcceptedOperation = DataPackageOperation.Copy;
|
||||
e.DragUIOverride.Caption = Translator.ComposerAttachmentsDragDropAttach_Message;
|
||||
e.DragUIOverride.IsCaptionVisible = true;
|
||||
e.DragUIOverride.IsGlyphVisible = true;
|
||||
e.DragUIOverride.IsContentVisible = true;
|
||||
}
|
||||
|
||||
private void OnFileDropGridDragLeave(object sender, DragEventArgs e)
|
||||
{
|
||||
ViewModel.IsDraggingOverFilesDropZone = false;
|
||||
}
|
||||
|
||||
private async void OnFileDropGridFileDropped(object sender, DragEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.DataView.Contains(StandardDataFormats.StorageItems))
|
||||
{
|
||||
var storageItems = await e.DataView.GetStorageItemsAsync();
|
||||
var files = storageItems.OfType<StorageFile>();
|
||||
|
||||
await AttachFiles(files);
|
||||
}
|
||||
}
|
||||
// State should be reset even when an exception occurs, otherwise the UI will be stuck in a dragging state.
|
||||
finally
|
||||
{
|
||||
ViewModel.IsDraggingOverComposerGrid = false;
|
||||
ViewModel.IsDraggingOverFilesDropZone = false;
|
||||
}
|
||||
}
|
||||
private void OnImageDropGridDragEnter(object sender, DragEventArgs e)
|
||||
{
|
||||
bool isValid = false;
|
||||
if (e.DataView.Contains(StandardDataFormats.StorageItems))
|
||||
{
|
||||
// We can't use async/await here because DragUIOverride becomes inaccessible.
|
||||
// https://github.com/microsoft/microsoft-ui-xaml/issues/9296
|
||||
var files = e.DataView.GetStorageItemsAsync().GetAwaiter().GetResult().OfType<StorageFile>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (ValidateImageFile(file))
|
||||
{
|
||||
isValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e.AcceptedOperation = isValid ? DataPackageOperation.Copy : DataPackageOperation.None;
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
ViewModel.IsDraggingOverImagesDropZone = true;
|
||||
e.DragUIOverride.Caption = Translator.ComposerAttachmentsDragDropAttach_Message;
|
||||
e.DragUIOverride.IsCaptionVisible = true;
|
||||
e.DragUIOverride.IsGlyphVisible = true;
|
||||
e.DragUIOverride.IsContentVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnImageDropGridDragLeave(object sender, DragEventArgs e)
|
||||
{
|
||||
ViewModel.IsDraggingOverImagesDropZone = false;
|
||||
}
|
||||
|
||||
private async void OnImageDropGridImageDropped(object sender, DragEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (e.DataView.Contains(StandardDataFormats.StorageItems))
|
||||
{
|
||||
var storageItems = await e.DataView.GetStorageItemsAsync();
|
||||
var files = storageItems.OfType<StorageFile>();
|
||||
|
||||
var imageDataURLs = new List<string>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (ValidateImageFile(file))
|
||||
imageDataURLs.Add(await GetDataURL(file));
|
||||
}
|
||||
|
||||
await InvokeScriptSafeAsync($"insertImages({JsonSerializer.Serialize(imageDataURLs)});");
|
||||
}
|
||||
}
|
||||
// State should be reset even when an exception occurs, otherwise the UI will be stuck in a dragging state.
|
||||
finally
|
||||
{
|
||||
ViewModel.IsDraggingOverComposerGrid = false;
|
||||
ViewModel.IsDraggingOverImagesDropZone = false;
|
||||
}
|
||||
|
||||
static async Task<string> GetDataURL(StorageFile file)
|
||||
{
|
||||
return $"data:image/{file.FileType.Replace(".", "")};base64,{Convert.ToBase64String(await file.ReadBytesAsync())}";
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AttachFiles(IEnumerable<StorageFile> files)
|
||||
{
|
||||
if (files?.Any() != true) return;
|
||||
|
||||
// Convert files to MailAttachmentViewModel.
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (!ViewModel.IncludedAttachments.Any(a => a.FileName == file.Path))
|
||||
{
|
||||
var attachmentViewModel = await file.ToAttachmentViewModelAsync();
|
||||
|
||||
ViewModel.IncludedAttachments.Add(attachmentViewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateImageFile(StorageFile file)
|
||||
{
|
||||
string[] allowedTypes = new string[] { ".jpg", ".jpeg", ".png" };
|
||||
var fileType = file.FileType.ToLower();
|
||||
|
||||
return allowedTypes.Contains(fileType);
|
||||
}
|
||||
|
||||
private async void BoldButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('bold')");
|
||||
}
|
||||
|
||||
private async void ItalicButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('italic')");
|
||||
}
|
||||
|
||||
private async void UnderlineButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('underline')");
|
||||
}
|
||||
|
||||
private async void StrokeButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('strikethrough')");
|
||||
}
|
||||
|
||||
private async void BulletListButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('insertunorderedlist')");
|
||||
}
|
||||
|
||||
private async void OrderedListButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('insertorderedlist')");
|
||||
}
|
||||
|
||||
private async void IncreaseIndentClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('indent')");
|
||||
}
|
||||
|
||||
private async void DecreaseIndentClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.execCommand('outdent')");
|
||||
}
|
||||
|
||||
private async void AlignmentChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var selectedItem = AlignmentListView.SelectedItem as ComboBoxItem;
|
||||
var alignment = selectedItem.Tag.ToString();
|
||||
|
||||
switch (alignment)
|
||||
{
|
||||
case "left":
|
||||
await InvokeScriptSafeAsync("editor.execCommand('justifyleft')");
|
||||
break;
|
||||
case "center":
|
||||
await InvokeScriptSafeAsync("editor.execCommand('justifycenter')");
|
||||
break;
|
||||
case "right":
|
||||
await InvokeScriptSafeAsync("editor.execCommand('justifyright')");
|
||||
break;
|
||||
case "justify":
|
||||
await InvokeScriptSafeAsync("editor.execCommand('justifyfull')");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private async void WebViewToggleButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var enable = WebviewToolBarButton.IsChecked == true ? "true" : "false";
|
||||
await InvokeScriptSafeAsync($"toggleToolbar('{enable}');");
|
||||
}
|
||||
|
||||
public async Task<string> ExecuteScriptFunctionAsync(string functionName, params object[] parameters)
|
||||
{
|
||||
string script = functionName + "(";
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
script += JsonSerializer.Serialize(parameters[i]);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
script += ", ";
|
||||
}
|
||||
}
|
||||
script += ");";
|
||||
|
||||
return await Chromium.ExecuteScriptAsync(script);
|
||||
}
|
||||
|
||||
private async Task<string> InvokeScriptSafeAsync(string function)
|
||||
{
|
||||
if (Chromium == null) return string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
return await Chromium.ExecuteScriptAsync(function);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private async void AddImageClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await InvokeScriptSafeAsync("imageInput.click();");
|
||||
}
|
||||
|
||||
private async Task FocusEditorAsync()
|
||||
{
|
||||
await InvokeScriptSafeAsync("editor.selection.focus();");
|
||||
|
||||
Chromium.Focus(FocusState.Keyboard);
|
||||
Chromium.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
private async void EmojiButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CoreInputView.GetForCurrentView().TryShow(CoreInputViewKind.Emoji);
|
||||
|
||||
await FocusEditorAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateEditorThemeAsync()
|
||||
{
|
||||
await DOMLoadedTask.Task;
|
||||
|
||||
if (IsComposerDarkMode)
|
||||
{
|
||||
Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Dark;
|
||||
await InvokeScriptSafeAsync("SetDarkEditor();");
|
||||
}
|
||||
else
|
||||
{
|
||||
Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Light;
|
||||
await InvokeScriptSafeAsync("SetLightEditor();");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RenderInternalAsync(string htmlBody)
|
||||
{
|
||||
await DOMLoadedTask.Task;
|
||||
|
||||
await UpdateEditorThemeAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(htmlBody))
|
||||
{
|
||||
await ExecuteScriptFunctionAsync("RenderHTML", " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
await ExecuteScriptFunctionAsync("RenderHTML", htmlBody);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
base.OnNavigatingFrom(e);
|
||||
|
||||
DisposeDisposables();
|
||||
DisposeWebView2();
|
||||
}
|
||||
|
||||
private void DisposeWebView2()
|
||||
{
|
||||
if (Chromium == null) return;
|
||||
|
||||
Chromium.CoreWebView2Initialized -= ChromiumInitialized;
|
||||
|
||||
if (Chromium.CoreWebView2 != null)
|
||||
{
|
||||
Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded;
|
||||
Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived;
|
||||
}
|
||||
|
||||
Chromium.Close();
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private void DisposeDisposables()
|
||||
{
|
||||
if (Disposables.Any())
|
||||
Disposables.ForEach(a => a.Dispose());
|
||||
}
|
||||
|
||||
protected override async void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation("WebViewConnectedAnimation");
|
||||
anim?.TryStart(Chromium);
|
||||
|
||||
DisposeDisposables();
|
||||
|
||||
Disposables.Add(GetSuggestionBoxDisposable(ToBox));
|
||||
Disposables.Add(GetSuggestionBoxDisposable(CCBox));
|
||||
Disposables.Add(GetSuggestionBoxDisposable(BccBox));
|
||||
|
||||
Chromium.CoreWebView2Initialized -= ChromiumInitialized;
|
||||
Chromium.CoreWebView2Initialized += ChromiumInitialized;
|
||||
|
||||
await Chromium.EnsureCoreWebView2Async();
|
||||
|
||||
ViewModel.GetHTMLBodyFunction = new Func<Task<string>>(async () =>
|
||||
{
|
||||
var editorContent = await InvokeScriptSafeAsync("GetHTMLContent();");
|
||||
|
||||
return JsonSerializer.Deserialize<string>(editorContent);
|
||||
});
|
||||
|
||||
var underlyingThemeService = App.Current.Services.GetService<IUnderlyingThemeService>();
|
||||
|
||||
IsComposerDarkMode = underlyingThemeService.IsUnderlyingThemeDark();
|
||||
}
|
||||
|
||||
private async void ChromiumInitialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args)
|
||||
{
|
||||
var editorBundlePath = (await ViewModel.NativeAppService.GetEditorBundlePathAsync()).Replace("editor.html", string.Empty);
|
||||
|
||||
Chromium.CoreWebView2.SetVirtualHostNameToFolderMapping("app.editor", editorBundlePath, CoreWebView2HostResourceAccessKind.Allow);
|
||||
Chromium.Source = new Uri("https://app.editor/editor.html");
|
||||
|
||||
Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded;
|
||||
Chromium.CoreWebView2.DOMContentLoaded += DOMLoaded;
|
||||
|
||||
Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived;
|
||||
Chromium.CoreWebView2.WebMessageReceived += ScriptMessageReceived;
|
||||
}
|
||||
|
||||
private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
var change = JsonSerializer.Deserialize<WebViewMessage>(args.WebMessageAsJson);
|
||||
|
||||
if (change.Type == "bold")
|
||||
{
|
||||
BoldButton.IsChecked = change.Value == "true";
|
||||
}
|
||||
else if (change.Type == "italic")
|
||||
{
|
||||
ItalicButton.IsChecked = change.Value == "true";
|
||||
}
|
||||
else if (change.Type == "underline")
|
||||
{
|
||||
UnderlineButton.IsChecked = change.Value == "true";
|
||||
}
|
||||
else if (change.Type == "strikethrough")
|
||||
{
|
||||
StrokeButton.IsChecked = change.Value == "true";
|
||||
}
|
||||
else if (change.Type == "ol")
|
||||
{
|
||||
OrderedListButton.IsChecked = change.Value == "true";
|
||||
}
|
||||
else if (change.Type == "ul")
|
||||
{
|
||||
BulletListButton.IsChecked = change.Value == "true";
|
||||
}
|
||||
else if (change.Type == "indent")
|
||||
{
|
||||
IncreaseIndentButton.IsEnabled = change.Value == "disabled" ? false : true;
|
||||
}
|
||||
else if (change.Type == "outdent")
|
||||
{
|
||||
DecreaseIndentButton.IsEnabled = change.Value == "disabled" ? false : true;
|
||||
}
|
||||
else if (change.Type == "alignment")
|
||||
{
|
||||
var parsedValue = change.Value switch
|
||||
{
|
||||
"jodit-icon_left" => 0,
|
||||
"jodit-icon_center" => 1,
|
||||
"jodit-icon_right" => 2,
|
||||
"jodit-icon_justify" => 3,
|
||||
_ => 0
|
||||
};
|
||||
AlignmentListView.SelectionChanged -= AlignmentChanged;
|
||||
AlignmentListView.SelectedIndex = parsedValue;
|
||||
AlignmentListView.SelectionChanged += AlignmentChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void DOMLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args) => DOMLoadedTask.TrySetResult(true);
|
||||
|
||||
void IRecipient<NavigationPaneModeChanged>.Receive(NavigationPaneModeChanged message)
|
||||
{
|
||||
if (message.NewMode == MenuPaneMode.Hidden)
|
||||
TopPanelGrid.Padding = new Thickness(48, 6, 6, 6);
|
||||
else
|
||||
TopPanelGrid.Padding = new Thickness(16, 6, 6, 6);
|
||||
}
|
||||
|
||||
async void IRecipient<CreateNewComposeMailRequested>.Receive(CreateNewComposeMailRequested message)
|
||||
{
|
||||
await RenderInternalAsync(message.RenderModel.RenderHtml);
|
||||
}
|
||||
|
||||
private void BarDynamicOverflowChanging(CommandBar sender, DynamicOverflowItemsChangingEventArgs args)
|
||||
{
|
||||
if (args.Action == CommandBarDynamicOverflowAction.AddingToOverflow)
|
||||
sender.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible;
|
||||
else
|
||||
sender.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Collapsed;
|
||||
}
|
||||
|
||||
private void ShowCCBCCClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CCBCCShowButton.Visibility = Visibility.Collapsed;
|
||||
|
||||
CCTextBlock.Visibility = Visibility.Visible;
|
||||
CCBox.Visibility = Visibility.Visible;
|
||||
BccTextBlock.Visibility = Visibility.Visible;
|
||||
BccBox.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
|
||||
{
|
||||
// Check is valid email.
|
||||
|
||||
if (!EmailValidator.Validate(args.TokenText))
|
||||
{
|
||||
args.Cancel = true;
|
||||
ViewModel.NotifyInvalidEmail(args.TokenText);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var deferal = args.GetDeferral();
|
||||
|
||||
AddressInformation addedItem = null;
|
||||
|
||||
var boxTag = sender.Tag?.ToString();
|
||||
|
||||
if (boxTag == "ToBox")
|
||||
addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.ToItems);
|
||||
else if (boxTag == "CCBox")
|
||||
addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.CCItemsItems);
|
||||
else if (boxTag == "BCCBox")
|
||||
addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.BCCItems);
|
||||
|
||||
if (addedItem == null)
|
||||
{
|
||||
args.Cancel = true;
|
||||
ViewModel.NotifyAddressExists();
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Item = addedItem;
|
||||
}
|
||||
|
||||
deferal.Complete();
|
||||
}
|
||||
|
||||
void IRecipient<ApplicationThemeChanged>.Receive(ApplicationThemeChanged message)
|
||||
{
|
||||
IsComposerDarkMode = message.IsUnderlyingThemeDark;
|
||||
}
|
||||
|
||||
private void InvertComposerThemeClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
IsComposerDarkMode = !IsComposerDarkMode;
|
||||
}
|
||||
|
||||
private void ImportanceClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ImportanceFlyout.Hide();
|
||||
ImportanceSplitButton.IsChecked = true;
|
||||
|
||||
if (sender is Button senderButton)
|
||||
{
|
||||
var selectedImportance = (MessageImportance)senderButton.Tag;
|
||||
|
||||
ViewModel.SelectedMessageImportance = selectedImportance;
|
||||
(ImportanceSplitButton.Content as SymbolIcon).Symbol = (senderButton.Content as SymbolIcon).Symbol;
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachmentClicked(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
if (e.ClickedItem is MailAttachmentViewModel attachmentViewModel)
|
||||
{
|
||||
ViewModel.RemoveAttachmentCommand.Execute(attachmentViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddressBoxLostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Automatically add current text as item if it is valid mail address.
|
||||
|
||||
if (sender is TokenizingTextBox tokenizingTextBox)
|
||||
{
|
||||
if (!(tokenizingTextBox.Items.LastOrDefault() is ITokenStringContainer info)) return;
|
||||
|
||||
var currentText = info.Text;
|
||||
|
||||
if (!string.IsNullOrEmpty(currentText) && EmailValidator.Validate(currentText))
|
||||
{
|
||||
var boxTag = tokenizingTextBox.Tag?.ToString();
|
||||
|
||||
AddressInformation addedItem = null;
|
||||
ObservableCollection<AddressInformation> addressCollection = null;
|
||||
|
||||
if (boxTag == "ToBox")
|
||||
addressCollection = ViewModel.ToItems;
|
||||
else if (boxTag == "CCBox")
|
||||
addressCollection = ViewModel.CCItemsItems;
|
||||
else if (boxTag == "BCCBox")
|
||||
addressCollection = ViewModel.BCCItems;
|
||||
|
||||
if (addressCollection != null)
|
||||
addedItem = await ViewModel.GetAddressInformationAsync(currentText, addressCollection);
|
||||
|
||||
// Item has already been added.
|
||||
if (addedItem == null)
|
||||
{
|
||||
tokenizingTextBox.Text = string.Empty;
|
||||
}
|
||||
else if (addressCollection != null)
|
||||
{
|
||||
addressCollection.Add(addedItem);
|
||||
tokenizingTextBox.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hack: Tokenizing text box losing focus somehow on page Loaded and shifting focus to this element.
|
||||
// For once we'll switch back to it once CCBBCGotFocus element got focus.
|
||||
|
||||
private bool isInitialFocusHandled = false;
|
||||
|
||||
private void ComposerLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ToBox.Focus(FocusState.Programmatic);
|
||||
}
|
||||
|
||||
private void CCBBCGotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isInitialFocusHandled)
|
||||
{
|
||||
isInitialFocusHandled = true;
|
||||
ToBox.Focus(FocusState.Programmatic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<abstract:IdlePageAbstract
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
x:Class="Wino.Views.IdlePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<!-- Empty page for disposing composer or renderer page. -->
|
||||
<Grid />
|
||||
|
||||
</abstract:IdlePageAbstract>
|
||||
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class IdlePage : IdlePageAbstract
|
||||
{
|
||||
public IdlePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
<Page
|
||||
x:Class="Wino.Views.ImapSetup.AdvancedImapSetupPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:RequestedTheme="Dark"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
d:Background="Black"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid RowSpacing="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<ScrollViewer x:Name="MainScrollviewer" Padding="{StaticResource ImapSetupDialogSubPagePadding}">
|
||||
<StackPanel Spacing="12" Padding="0,0,16,0">
|
||||
<TextBlock
|
||||
d:Text="Advanced IMAP / SMTP Configuration"
|
||||
Text="{x:Bind domain:Translator.IMAPSetupDialog_Title}"
|
||||
Margin="1,0,0,0"
|
||||
Style="{StaticResource TitleTextBlockStyle}" />
|
||||
|
||||
<TextBox
|
||||
d:Header="Mail"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_MailAddress}"
|
||||
PlaceholderText="{x:Bind domain:Translator.IMAPSetupDialog_MailAddressPlaceholder}"
|
||||
x:Name="AddressBox" />
|
||||
|
||||
<TextBox
|
||||
d:Header="Display Name"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_DisplayName}"
|
||||
PlaceholderText="{x:Bind domain:Translator.IMAPSetupDialog_DisplayNamePlaceholder}"
|
||||
x:Name="DisplayNameBox" />
|
||||
|
||||
<CheckBox Content="{x:Bind domain:Translator.IMAPSetupDialog_UseSameConfig}" IsChecked="{x:Bind UseSameCredentialsForSending, Mode=TwoWay}" />
|
||||
|
||||
<muxc:TabView
|
||||
d:SelectedIndex="0"
|
||||
IsAddTabButtonVisible="False"
|
||||
CanReorderTabs="False"
|
||||
TabWidthMode="Equal">
|
||||
<muxc:TabViewItem Header="IMAP Settings" IsClosable="False">
|
||||
<!-- IMAP -->
|
||||
<StackPanel Padding="12" Spacing="10">
|
||||
<!-- Server + Port -->
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox
|
||||
d:Header="Incoming Server"
|
||||
TextChanged="IncomingServerChanged"
|
||||
PlaceholderText="eg. imap.gmail.com"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_IncomingMailServer}"
|
||||
x:Name="IncomingServerBox" />
|
||||
|
||||
<TextBox
|
||||
d:Header="Port"
|
||||
Text="993"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_IncomingMailServerPort}"
|
||||
x:Name="IncomingServerPortBox"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
|
||||
<!-- Username + Password -->
|
||||
<StackPanel Spacing="6">
|
||||
<TextBox
|
||||
d:Header="Username"
|
||||
TextChanged="IncomingUsernameChanged"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_Username}"
|
||||
PlaceholderText="{x:Bind domain:Translator.IMAPSetupDialog_UsernamePlaceholder}"
|
||||
x:Name="UsernameBox" />
|
||||
|
||||
<PasswordBox
|
||||
PasswordChanged="IncomingPasswordChanged"
|
||||
d:Header="Password"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_Password}"
|
||||
x:Name="PasswordBox" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Security and Authentication -->
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Security -->
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock
|
||||
d:Text="Connection security"
|
||||
Text="{x:Bind domain:Translator.ImapAdvancedSetupDialog_ConnectionSecurity}"
|
||||
HorizontalAlignment="Center" />
|
||||
<ComboBox
|
||||
x:Name="IncomingConnectionSecurity"
|
||||
SelectedIndex="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind AvailableConnectionSecurities}"
|
||||
DisplayMemberPath="DisplayName" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Authentication -->
|
||||
<StackPanel Grid.Column="1" Spacing="6">
|
||||
<TextBlock
|
||||
d:Text="Authentication method"
|
||||
Text="{x:Bind domain:Translator.ImapAdvancedSetupDialog_AuthenticationMethod}"
|
||||
HorizontalAlignment="Center" />
|
||||
<ComboBox
|
||||
x:Name="IncomingAuthenticationMethod"
|
||||
SelectedIndex="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind AvailableAuthenticationMethods}"
|
||||
DisplayMemberPath="DisplayName" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</muxc:TabViewItem>
|
||||
<muxc:TabViewItem IsClosable="False" Header="SMTP Settings">
|
||||
<!-- SMTP -->
|
||||
<StackPanel Padding="12" Spacing="10">
|
||||
<!-- Server + Port -->
|
||||
<Grid ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox
|
||||
d:Header="Outgoing Server"
|
||||
TextChanged="OutgoingServerChanged"
|
||||
PlaceholderText="eg. smtp.gmail.com"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_OutgoingMailServer}"
|
||||
x:Name="OutgoingServerBox" />
|
||||
|
||||
<TextBox
|
||||
d:Header="Port"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_OutgoingMailServerPort}"
|
||||
x:Name="OutgoingServerPort"
|
||||
Text="587"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
|
||||
<!-- Username + Password -->
|
||||
<StackPanel x:Name="OutgoingAuthenticationPanel" Spacing="6">
|
||||
<TextBox
|
||||
x:Name="OutgoingUsernameBox"
|
||||
d:Header="UserName"
|
||||
IsEnabled="{x:Bind helpers:XamlHelpers.ReverseBoolConverter(UseSameCredentialsForSending), Mode=OneWay}"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_OutgoingMailServerUsername}" />
|
||||
<PasswordBox
|
||||
x:Name="OutgoingPasswordBox"
|
||||
IsEnabled="{x:Bind helpers:XamlHelpers.ReverseBoolConverter(UseSameCredentialsForSending), Mode=OneWay}"
|
||||
d:Header="Password"
|
||||
Header="{x:Bind domain:Translator.IMAPSetupDialog_OutgoingMailServerPassword}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Security and Authentication -->
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- Security -->
|
||||
<StackPanel Spacing="6">
|
||||
<TextBlock Text="{x:Bind domain:Translator.ImapAdvancedSetupDialog_ConnectionSecurity}" HorizontalAlignment="Center" />
|
||||
<ComboBox
|
||||
x:Name="OutgoingConnectionSecurity"
|
||||
SelectedIndex="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind AvailableConnectionSecurities}"
|
||||
DisplayMemberPath="DisplayName" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Authentication -->
|
||||
<StackPanel Grid.Column="1" Spacing="6">
|
||||
<TextBlock Text="{x:Bind domain:Translator.ImapAdvancedSetupDialog_AuthenticationMethod}" HorizontalAlignment="Center" />
|
||||
<ComboBox
|
||||
x:Name="OutgoingAuthenticationMethod"
|
||||
SelectedIndex="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
ItemsSource="{x:Bind AvailableAuthenticationMethods}"
|
||||
DisplayMemberPath="DisplayName" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</muxc:TabViewItem>
|
||||
<muxc:TabViewItem IsClosable="False" Header="Proxy">
|
||||
<!-- Proxy -->
|
||||
<StackPanel Spacing="10" Padding="12">
|
||||
<TextBlock Text="Define your optional proxy server for the connection if your mail server requires it. This is optional." />
|
||||
<Grid ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBox Header="Proxy server" x:Name="ProxyServerBox" />
|
||||
<muxc:NumberBox
|
||||
Header="Port"
|
||||
Grid.Column="1"
|
||||
x:Name="ProxyServerPortBox" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</muxc:TabViewItem>
|
||||
</muxc:TabView>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Buttons -->
|
||||
<Grid
|
||||
Padding="{StaticResource ImapSetupDialogSubPagePadding}"
|
||||
Background="{ThemeResource ContentDialogBackground}"
|
||||
Grid.Row="1"
|
||||
VerticalAlignment="Bottom"
|
||||
ColumnSpacing="6">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button
|
||||
d:Content="Cancel"
|
||||
Content="{x:Bind domain:Translator.Buttons_Cancel}"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="CancelClicked" />
|
||||
|
||||
<Button
|
||||
d:Content="Sign In"
|
||||
Content="{x:Bind domain:Translator.Buttons_SignIn}"
|
||||
Click="SignInClicked"
|
||||
Style="{ThemeResource AccentButtonStyle}"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,219 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Models.Accounts;
|
||||
using Wino.Core.Domain.Models.AutoDiscovery;
|
||||
using Wino.Core.Messages.Mails;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views.ImapSetup
|
||||
{
|
||||
public sealed partial class AdvancedImapSetupPage : Page
|
||||
{
|
||||
public List<ImapAuthenticationMethodModel> AvailableAuthenticationMethods { get; } = new List<ImapAuthenticationMethodModel>()
|
||||
{
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.Auto, Translator.ImapAuthenticationMethod_Auto),
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.None, Translator.ImapAuthenticationMethod_None),
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.NormalPassword, Translator.ImapAuthenticationMethod_Plain),
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.EncryptedPassword, Translator.ImapAuthenticationMethod_EncryptedPassword),
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.Ntlm, Translator.ImapAuthenticationMethod_Ntlm),
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.CramMd5, Translator.ImapAuthenticationMethod_CramMD5),
|
||||
new ImapAuthenticationMethodModel(Core.Domain.Enums.ImapAuthenticationMethod.DigestMd5, Translator.ImapAuthenticationMethod_DigestMD5)
|
||||
};
|
||||
|
||||
public List<ImapConnectionSecurityModel> AvailableConnectionSecurities { get; set; } = new List<ImapConnectionSecurityModel>()
|
||||
{
|
||||
new ImapConnectionSecurityModel(Core.Domain.Enums.ImapConnectionSecurity.Auto, Translator.ImapConnectionSecurity_Auto),
|
||||
new ImapConnectionSecurityModel(Core.Domain.Enums.ImapConnectionSecurity.SslTls, Translator.ImapConnectionSecurity_SslTls),
|
||||
new ImapConnectionSecurityModel(Core.Domain.Enums.ImapConnectionSecurity.StartTls, Translator.ImapConnectionSecurity_StartTls),
|
||||
new ImapConnectionSecurityModel(Core.Domain.Enums.ImapConnectionSecurity.None, Translator.ImapConnectionSecurity_None)
|
||||
};
|
||||
|
||||
public bool UseSameCredentialsForSending
|
||||
{
|
||||
get { return (bool)GetValue(UseSameCredentialsForSendingProperty); }
|
||||
set { SetValue(UseSameCredentialsForSendingProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty UseSameCredentialsForSendingProperty = DependencyProperty.Register(nameof(UseSameCredentialsForSending), typeof(bool), typeof(AdvancedImapSetupPage), new PropertyMetadata(true, OnUseSameCredentialsForSendingChanged));
|
||||
|
||||
public AdvancedImapSetupPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
NavigationCacheMode = NavigationCacheMode.Enabled;
|
||||
}
|
||||
|
||||
private static void OnUseSameCredentialsForSendingChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (obj is AdvancedImapSetupPage page)
|
||||
{
|
||||
page.UpdateOutgoingAuthenticationPanel();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOutgoingAuthenticationPanel()
|
||||
{
|
||||
if (UseSameCredentialsForSending)
|
||||
{
|
||||
OutgoingUsernameBox.Text = UsernameBox.Text;
|
||||
OutgoingPasswordBox.Password = PasswordBox.Password;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutgoingUsernameBox.Text = string.Empty;
|
||||
OutgoingPasswordBox.Password = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
// ProtocolLogGrid.Visibility = Visibility.Collapsed;
|
||||
|
||||
// Connection is succesfull but error occurred.
|
||||
// Imap and Smptp settings exists here at this point.
|
||||
|
||||
if (e.Parameter is AutoDiscoverySettings preDefinedSettings && preDefinedSettings.UserMinimalSettings != null)
|
||||
{
|
||||
// TODO: Auto discovery settings adjustments.
|
||||
|
||||
UsernameBox.Text = preDefinedSettings.UserMinimalSettings.Email;
|
||||
AddressBox.Text = preDefinedSettings.UserMinimalSettings.Email;
|
||||
DisplayNameBox.Text = preDefinedSettings.UserMinimalSettings.DisplayName;
|
||||
PasswordBox.Password = preDefinedSettings.UserMinimalSettings.Password;
|
||||
|
||||
var serverInfo = preDefinedSettings.ToServerInformation();
|
||||
|
||||
IncomingServerBox.Text = serverInfo.IncomingServer;
|
||||
IncomingServerPortBox.Text = serverInfo.IncomingServerPort;
|
||||
|
||||
OutgoingPasswordBox.Password = serverInfo.OutgoingServerPassword;
|
||||
OutgoingServerPort.Text = serverInfo.OutgoingServerPort;
|
||||
OutgoingUsernameBox.Text = serverInfo.OutgoingServerUsername;
|
||||
|
||||
UseSameCredentialsForSending = OutgoingUsernameBox.Text == UsernameBox.Text;
|
||||
}
|
||||
else if (e.Parameter is AutoDiscoveryMinimalSettings autoDiscoveryMinimalSettings)
|
||||
{
|
||||
// Auto discovery failed. Only minimal settings are passed.
|
||||
|
||||
UsernameBox.Text = autoDiscoveryMinimalSettings.Email;
|
||||
AddressBox.Text = autoDiscoveryMinimalSettings.Email;
|
||||
DisplayNameBox.Text = autoDiscoveryMinimalSettings.DisplayName;
|
||||
PasswordBox.Password = autoDiscoveryMinimalSettings.Password;
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new ImapSetupDismissRequested(null));
|
||||
|
||||
private string GetServerWithoutPort(string server)
|
||||
{
|
||||
var splitted = server.Split(':');
|
||||
|
||||
if (splitted.Length > 1)
|
||||
{
|
||||
return splitted[0];
|
||||
}
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
private void SignInClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var info = new CustomServerInformation()
|
||||
{
|
||||
IncomingServer = GetServerWithoutPort(IncomingServerBox.Text),
|
||||
Id = Guid.NewGuid(),
|
||||
|
||||
IncomingServerPassword = PasswordBox.Password,
|
||||
IncomingServerType = Core.Domain.Enums.CustomIncomingServerType.IMAP4,
|
||||
IncomingServerUsername = UsernameBox.Text,
|
||||
IncomingAuthenticationMethod = (IncomingAuthenticationMethod.SelectedItem as ImapAuthenticationMethodModel).ImapAuthenticationMethod,
|
||||
IncomingServerSocketOption = (IncomingConnectionSecurity.SelectedItem as ImapConnectionSecurityModel).ImapConnectionSecurity,
|
||||
IncomingServerPort = IncomingServerPortBox.Text,
|
||||
|
||||
OutgoingServer = GetServerWithoutPort(OutgoingServerBox.Text),
|
||||
OutgoingServerPort = OutgoingServerPort.Text,
|
||||
OutgoingServerPassword = OutgoingPasswordBox.Password,
|
||||
OutgoingAuthenticationMethod = (OutgoingAuthenticationMethod.SelectedItem as ImapAuthenticationMethodModel).ImapAuthenticationMethod,
|
||||
OutgoingServerSocketOption = (OutgoingConnectionSecurity.SelectedItem as ImapConnectionSecurityModel).ImapConnectionSecurity,
|
||||
OutgoingServerUsername = OutgoingUsernameBox.Text,
|
||||
|
||||
ProxyServer = ProxyServerBox.Text,
|
||||
ProxyServerPort = ProxyServerPortBox.Text,
|
||||
Address = AddressBox.Text,
|
||||
DisplayName = DisplayNameBox.Text,
|
||||
MaxConcurrentClients = 5
|
||||
};
|
||||
|
||||
if (UseSameCredentialsForSending)
|
||||
{
|
||||
info.OutgoingServerUsername = info.IncomingServerUsername;
|
||||
info.OutgoingServerPassword = info.IncomingServerPassword;
|
||||
}
|
||||
else
|
||||
{
|
||||
info.OutgoingServerUsername = OutgoingUsernameBox.Text;
|
||||
info.OutgoingServerPassword = OutgoingPasswordBox.Password;
|
||||
}
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupNavigationRequested(typeof(TestingImapConnectionPage), info));
|
||||
}
|
||||
|
||||
private void IncomingServerChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (sender is TextBox senderTextBox)
|
||||
{
|
||||
var splitted = senderTextBox.Text.Split(':');
|
||||
|
||||
if (splitted.Length > 1)
|
||||
{
|
||||
IncomingServerPortBox.Text = splitted[splitted.Length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OutgoingServerChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (sender is TextBox senderTextBox)
|
||||
{
|
||||
var splitted = senderTextBox.Text.Split(':');
|
||||
|
||||
if (splitted.Length > 1)
|
||||
{
|
||||
OutgoingServerPort.Text = splitted[splitted.Length - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void IncomingUsernameChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (UseSameCredentialsForSending)
|
||||
{
|
||||
OutgoingUsernameBox.Text = UsernameBox.Text;
|
||||
}
|
||||
}
|
||||
|
||||
private void IncomingPasswordChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (UseSameCredentialsForSending)
|
||||
{
|
||||
OutgoingPasswordBox.Password = PasswordBox.Password;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
<Page
|
||||
x:Class="Wino.Views.ImapSetup.ImapConnectionFailedPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Wino.Views.ImapSetup"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Padding="24" RowSpacing="6">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Text="{x:Bind domain:Translator.IMAPSetupDialog_ConnectionFailedTitle}" Style="{StaticResource SubtitleTextBlockStyle}" />
|
||||
|
||||
<TextBlock
|
||||
x:Name="ConnectionFailedMessage"
|
||||
Grid.Row="1"
|
||||
Style="{StaticResource BodyTextBlockStyle}" />
|
||||
|
||||
<!-- Protocol Log Area -->
|
||||
<Grid
|
||||
x:Name="ProtocolLogGrid"
|
||||
Grid.Row="2"
|
||||
ColumnSpacing="12"
|
||||
Visibility="Collapsed">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
x:Name="ProtocolLogHeader"
|
||||
Foreground="{ThemeResource InfoBarWarningSeverityIconBackground}"
|
||||
VerticalAlignment="Center"
|
||||
Text="{x:Bind domain:Translator.ProtocolLogAvailable_Message}" />
|
||||
|
||||
<Button
|
||||
Content="{x:Bind domain:Translator.Buttons_Copy}"
|
||||
Click="CopyProtocolLogButtonClicked"
|
||||
Grid.Column="1" />
|
||||
</Grid>
|
||||
|
||||
<!-- Dismis / GoBack -->
|
||||
<Grid
|
||||
Grid.Row="3"
|
||||
VerticalAlignment="Bottom"
|
||||
ColumnSpacing="12">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button
|
||||
Content="{x:Bind domain:Translator.Buttons_Close}"
|
||||
Click="CloseClicked"
|
||||
HorizontalAlignment="Stretch" />
|
||||
|
||||
<Button
|
||||
Content="{x:Bind domain:Translator.Buttons_TryAgain}"
|
||||
Click="TryAgainClicked"
|
||||
Style="{ThemeResource AccentButtonStyle}"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Stretch" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,56 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Exceptions;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Messages.Mails;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views.ImapSetup
|
||||
{
|
||||
public sealed partial class ImapConnectionFailedPage : Page
|
||||
{
|
||||
private string _protocolLog;
|
||||
|
||||
private readonly IClipboardService _clipboardService = App.Current.Services.GetService<IClipboardService>();
|
||||
private readonly IDialogService _dialogService = App.Current.Services.GetService<IDialogService>();
|
||||
|
||||
public ImapConnectionFailedPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void CopyProtocolLogButtonClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await _clipboardService.CopyClipboardAsync(_protocolLog);
|
||||
|
||||
_dialogService.InfoBarMessage(Translator.ClipboardTextCopied_Title, string.Format(Translator.ClipboardTextCopied_Message, "Log"), Core.Domain.Enums.InfoBarMessageType.Information);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
if (e.Parameter is ImapConnectionFailedPackage failedPackage)
|
||||
{
|
||||
ConnectionFailedMessage.Text = failedPackage.GetErrorMessage();
|
||||
|
||||
ProtocolLogGrid.Visibility = !string.IsNullOrEmpty(failedPackage.ProtocolLog) ? Visibility.Visible : Visibility.Collapsed;
|
||||
_protocolLog = failedPackage.ProtocolLog;
|
||||
}
|
||||
}
|
||||
|
||||
private void TryAgainClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new ImapSetupBackNavigationRequested());
|
||||
|
||||
private void CloseClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new ImapSetupDismissRequested());
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
<Page
|
||||
x:Class="Wino.Views.ImapSetup.PreparingImapFoldersPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Wino.Views.ImapSetup"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<!-- Preparing Folders Panel -->
|
||||
<StackPanel
|
||||
x:Name="PreparingFoldersPanel"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
|
||||
<Viewbox
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Width="26"
|
||||
Height="26">
|
||||
<PathIcon Data="M1024,317.5L1024,507C1014.67,495.333 1004.67,484.167 994,473.5C983.333,462.833 972,453 960,444L960,320C960,311.333 958.333,303.083 955,295.25C951.667,287.417 947.083,280.583 941.25,274.75C935.417,268.917 928.583,264.333 920.75,261C912.917,257.667 904.667,256 896,256L522,256L458,298.5C436,312.833 412.333,320 387,320L64,320L64,832C64,841 65.6667,849.417 69,857.25C72.3333,865.083 76.8333,871.833 82.5,877.5C88.1667,883.167 94.9167,887.667 102.75,891C110.583,894.333 119,896 128,896L404.5,896C410.167,907.333 416.25,918.333 422.75,929C429.25,939.667 436.333,950 444,960L125.5,960C108.833,960 92.9167,956.583 77.75,949.75C62.5833,942.917 49.25,933.75 37.75,922.25C26.25,910.75 17.0833,897.417 10.25,882.25C3.41667,867.083 0,851.167 0,834.5L0,189.5C0,172.833 3.41667,156.917 10.25,141.75C17.0833,126.583 26.25,113.25 37.75,101.75C49.25,90.25 62.5833,81.0834 77.75,74.25C92.9167,67.4167 108.833,64.0001 125.5,64L368,64C388,64.0001 407.167,68.5001 425.5,77.5C443.833,86.5001 458.833,99.0001 470.5,115L528,192L898.5,192C915.167,192 931.083,195.417 946.25,202.25C961.417,209.083 974.75,218.25 986.25,229.75C997.75,241.25 1006.92,254.583 1013.75,269.75C1020.58,284.917 1024,300.833 1024,317.5ZM466,216L419,153.5C413,145.5 405.5,139.25 396.5,134.75C387.5,130.25 378,128 368,128L128,128C119,128 110.667,129.667 103,133C95.3333,136.333 88.5833,140.917 82.75,146.75C76.9167,152.583 72.3333,159.333 69,167C65.6667,174.667 64,183 64,192L64,256L387,256C394.333,256 401.5,254.667 408.5,252C415.5,249.333 422.25,246 428.75,242C435.25,238 441.583,233.667 447.75,229C453.917,224.333 460,220 466,216ZM1024,736C1024,775.667 1016.42,813 1001.25,848C986.083,883 965.5,913.5 939.5,939.5C913.5,965.5 883,986.083 848,1001.25C813,1016.42 775.667,1024 736,1024C696,1024 658.5,1016.5 623.5,1001.5C588.5,986.5 558,966 532,940C506,914 485.5,883.5 470.5,848.5C455.5,813.5 448,776 448,736C448,696.333 455.583,659 470.75,624C485.917,589 506.5,558.5 532.5,532.5C558.5,506.5 589,485.917 624,470.75C659,455.583 696.333,448 736,448C762.333,448 787.75,451.417 812.25,458.25C836.75,465.083 859.667,474.75 881,487.25C902.333,499.75 921.833,514.833 939.5,532.5C957.167,550.167 972.25,569.667 984.75,591C997.25,612.333 1006.92,635.25 1013.75,659.75C1020.58,684.25 1024,709.667 1024,736ZM896,576C896,567.333 892.833,559.833 886.5,553.5C880.167,547.167 872.667,544 864,544C857.667,544 852.5,545.167 848.5,547.5C844.5,549.833 841.25,552.917 838.75,556.75C836.25,560.583 834.5,565 833.5,570C832.5,575 832,580.167 832,585.5C816.333,577.167 800.917,570.833 785.75,566.5C770.583,562.167 754,560 736,560C724,560 711.75,561.25 699.25,563.75C686.75,566.25 674.5,569.917 662.5,574.75C650.5,579.583 639.083,585.417 628.25,592.25C617.417,599.083 608,607 600,616C597,619.333 594.667,622.75 593,626.25C591.333,629.75 590.5,633.833 590.5,638.5C590.5,647.5 593.667,655.167 600,661.5C606.333,667.833 614,671 623,671C628.667,671 634.75,668.583 641.25,663.75C647.75,658.917 655.333,653.5 664,647.5C672.667,641.5 682.75,636.083 694.25,631.25C705.75,626.417 719.333,624 735,624C746.667,624 757.5,625.25 767.5,627.75C777.5,630.25 787.667,634.333 798,640L785,640C779,640 773.083,640.25 767.25,640.75C761.417,641.25 756.167,642.583 751.5,644.75C746.833,646.917 743.083,650.167 740.25,654.5C737.417,658.833 736,664.667 736,672C736,680.667 739.167,688.167 745.5,694.5C751.833,700.833 759.333,704 768,704L864,704C872.667,704 880.167,700.833 886.5,694.5C892.833,688.167 896,680.667 896,672ZM881.5,833C881.5,824.333 878.333,816.833 872,810.5C865.667,804.167 858.167,801 849.5,801C842.833,801 836.333,803.417 830,808.25C823.667,813.083 816.333,818.5 808,824.5C799.667,830.5 789.833,835.917 778.5,840.75C767.167,845.583 753.333,848 737,848C725.333,848 714.5,846.75 704.5,844.25C694.5,841.75 684.333,837.667 674,832L687,832C692.667,832 698.417,831.75 704.25,831.25C710.083,830.75 715.333,829.417 720,827.25C724.667,825.083 728.5,821.833 731.5,817.5C734.5,813.167 736,807.333 736,800C736,791.333 732.833,783.833 726.5,777.5C720.167,771.167 712.667,768 704,768L608,768C599.333,768 591.833,771.167 585.5,777.5C579.167,783.833 576,791.333 576,800L576,896C576,904.667 579.167,912.167 585.5,918.5C591.833,924.833 599.333,928 608,928C614.333,928 619.5,926.833 623.5,924.5C627.5,922.167 630.75,919.083 633.25,915.25C635.75,911.417 637.5,907 638.5,902C639.5,897 640,891.833 640,886.5C655.667,894.833 671.083,901.167 686.25,905.5C701.417,909.833 718,912 736,912C748,912 760.333,910.75 773,908.25C785.667,905.75 797.917,902.083 809.75,897.25C821.583,892.417 832.833,886.583 843.5,879.75C854.167,872.917 863.667,865 872,856C878.333,849.333 881.5,841.667 881.5,833Z" />
|
||||
</Viewbox>
|
||||
|
||||
<TextBlock Text="{x:Bind domain:Translator.PreparingFoldersMessage}" />
|
||||
<muxc:ProgressBar IsIndeterminate="True" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,18 +0,0 @@
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
#else
|
||||
using Windows.UI.Xaml.Controls;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views.ImapSetup
|
||||
{
|
||||
|
||||
public sealed partial class PreparingImapFoldersPage : Page
|
||||
{
|
||||
public PreparingImapFoldersPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<Page
|
||||
x:Class="Wino.Views.ImapSetup.TestingImapConnectionPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Wino.Views.ImapSetup"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<!-- Testing Connection Panel -->
|
||||
<StackPanel
|
||||
x:Name="TestingConnectionPanel"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center">
|
||||
|
||||
<Viewbox
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Center"
|
||||
Width="26"
|
||||
Height="26">
|
||||
<PathIcon Data="F1 M 18.75 18.125 C 18.75 18.294271 18.68815 18.440756 18.564453 18.564453 C 18.440754 18.68815 18.29427 18.75 18.125 18.75 L 13.75 18.75 C 13.75 18.925781 13.717447 19.088541 13.652344 19.238281 C 13.587239 19.388021 13.497721 19.519857 13.383789 19.633789 C 13.269855 19.747721 13.13802 19.83724 12.988281 19.902344 C 12.838541 19.967447 12.675781 20 12.5 20 L 6.25 20 C 6.074219 20 5.909831 19.967447 5.756836 19.902344 C 5.603841 19.83724 5.472005 19.74935 5.361328 19.638672 C 5.250651 19.527994 5.16276 19.396158 5.097656 19.243164 C 5.032552 19.09017 5 18.925781 5 18.75 L 0.625 18.75 C 0.455729 18.75 0.309245 18.68815 0.185547 18.564453 C 0.061849 18.440756 0 18.294271 0 18.125 C 0 17.955729 0.061849 17.809244 0.185547 17.685547 C 0.309245 17.56185 0.455729 17.5 0.625 17.5 L 5 17.5 C 5 17.154949 5.120442 16.86198 5.361328 16.621094 C 5.608724 16.373699 5.904948 16.25 6.25 16.25 L 7.5 16.25 C 7.5 16.074219 7.532552 15.911459 7.597656 15.761719 C 7.66276 15.611979 7.752278 15.480144 7.866211 15.366211 C 7.980143 15.252279 8.111979 15.162761 8.261719 15.097656 C 8.411458 15.032553 8.574219 15 8.75 15 L 8.75 13.75 L 6.875 13.75 C 6.621094 13.75 6.380208 13.701172 6.152344 13.603516 C 5.924479 13.505859 5.724284 13.370769 5.551758 13.198242 C 5.379231 13.025717 5.244141 12.825521 5.146484 12.597656 C 5.048828 12.369792 5 12.128906 5 11.875 L 5 1.875 C 5 1.621094 5.048828 1.380209 5.146484 1.152344 C 5.244141 0.92448 5.379231 0.724285 5.551758 0.551758 C 5.724284 0.379232 5.924479 0.244141 6.152344 0.146484 C 6.380208 0.048828 6.621094 0 6.875 0 L 11.875 0 C 12.128906 0 12.369791 0.048828 12.597656 0.146484 C 12.825521 0.244141 13.025716 0.379232 13.198242 0.551758 C 13.370768 0.724285 13.505859 0.92448 13.603516 1.152344 C 13.701172 1.380209 13.75 1.621094 13.75 1.875 L 13.75 11.875 C 13.75 12.128906 13.701172 12.369792 13.603516 12.597656 C 13.505859 12.825521 13.370768 13.025717 13.198242 13.198242 C 13.025716 13.370769 12.825521 13.505859 12.597656 13.603516 C 12.369791 13.701172 12.128906 13.75 11.875 13.75 L 10 13.75 L 10 15 C 10.169271 15 10.330403 15.032553 10.483398 15.097656 C 10.636393 15.162761 10.769856 15.252279 10.883789 15.366211 C 10.997721 15.480144 11.087239 15.613607 11.152344 15.766602 C 11.217447 15.919597 11.25 16.080729 11.25 16.25 L 12.5 16.25 C 12.669271 16.25 12.828775 16.282553 12.978516 16.347656 C 13.128255 16.41276 13.261719 16.503906 13.378906 16.621094 C 13.626302 16.86849 13.75 17.161459 13.75 17.5 L 18.125 17.5 C 18.29427 17.5 18.440754 17.56185 18.564453 17.685547 C 18.68815 17.809244 18.75 17.955729 18.75 18.125 Z M 11.875 12.5 C 12.04427 12.5 12.190754 12.438151 12.314453 12.314453 C 12.43815 12.190756 12.5 12.044271 12.5 11.875 L 12.5 1.875 C 12.5 1.70573 12.43815 1.559246 12.314453 1.435547 C 12.190754 1.31185 12.04427 1.25 11.875 1.25 L 6.875 1.25 C 6.705729 1.25 6.559244 1.31185 6.435547 1.435547 C 6.311849 1.559246 6.25 1.70573 6.25 1.875 L 6.25 11.875 C 6.25 12.044271 6.311849 12.190756 6.435547 12.314453 C 6.559244 12.438151 6.705729 12.5 6.875 12.5 Z M 10.625 2.5 C 10.794271 2.5 10.940755 2.56185 11.064453 2.685547 C 11.18815 2.809246 11.25 2.95573 11.25 3.125 C 11.25 3.294271 11.18815 3.440756 11.064453 3.564453 C 10.940755 3.688152 10.794271 3.75 10.625 3.75 L 8.125 3.75 C 7.955729 3.75 7.809245 3.688152 7.685547 3.564453 C 7.561849 3.440756 7.5 3.294271 7.5 3.125 C 7.5 2.95573 7.561849 2.809246 7.685547 2.685547 C 7.809245 2.56185 7.955729 2.5 8.125 2.5 Z M 10.625 5 C 10.794271 5.000001 10.940755 5.06185 11.064453 5.185547 C 11.18815 5.309245 11.25 5.455729 11.25 5.625 C 11.25 5.794271 11.18815 5.940756 11.064453 6.064453 C 10.940755 6.188151 10.794271 6.25 10.625 6.25 L 8.125 6.25 C 7.955729 6.25 7.809245 6.188151 7.685547 6.064453 C 7.561849 5.940756 7.5 5.794271 7.5 5.625 C 7.5 5.455729 7.561849 5.309245 7.685547 5.185547 C 7.809245 5.06185 7.955729 5.000001 8.125 5 Z M 12.5 18.75 L 12.5 17.5 L 10.625 17.5 C 10.481771 17.5 10.367838 17.47233 10.283203 17.416992 C 10.198567 17.361654 10.135091 17.290039 10.092773 17.202148 C 10.050455 17.114258 10.022786 17.016602 10.009766 16.90918 C 9.996744 16.801758 9.990234 16.692709 9.990234 16.582031 C 9.990234 16.523438 9.991861 16.466471 9.995117 16.411133 C 9.998372 16.355795 10 16.302084 10 16.25 L 8.75 16.25 L 8.75 16.582031 C 8.75 16.692709 8.743489 16.801758 8.730469 16.90918 C 8.717447 17.016602 8.689778 17.114258 8.647461 17.202148 C 8.605143 17.290039 8.543294 17.361654 8.461914 17.416992 C 8.380533 17.47233 8.268229 17.5 8.125 17.5 L 6.25 17.5 L 6.25 18.75 Z " />
|
||||
</Viewbox>
|
||||
|
||||
<TextBlock Text="{x:Bind domain:Translator.TestingImapConnectionMessage}" />
|
||||
|
||||
<muxc:ProgressBar IsIndeterminate="True" Margin="0,4,0,0" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -1,85 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Exceptions;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.AutoDiscovery;
|
||||
using Wino.Core.Messages.Mails;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
namespace Wino.Views.ImapSetup
|
||||
{
|
||||
public sealed partial class TestingImapConnectionPage : Page
|
||||
{
|
||||
private IImapTestService _imapTestService = App.Current.Services.GetService<IImapTestService>();
|
||||
|
||||
public TestingImapConnectionPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async Task TryTestConnectionAsync(CustomServerInformation serverInformation)
|
||||
{
|
||||
await Task.Delay(1000);
|
||||
|
||||
await _imapTestService.TestImapConnectionAsync(serverInformation);
|
||||
|
||||
// All success. Finish setup with validated server information.
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupDismissRequested(serverInformation));
|
||||
}
|
||||
|
||||
protected override async void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
// We can only go back to this page from failed connection page.
|
||||
// We must go back once again in that case to actual setup dialog.
|
||||
if (e.NavigationMode == NavigationMode.Back)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupBackNavigationRequested());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Test connection
|
||||
|
||||
CustomServerInformation serverInformationToTest = null;
|
||||
AutoDiscoverySettings autoDiscoverySettings = null;
|
||||
|
||||
// Discovery settings are passed.
|
||||
// Create server information out of the discovery settings.
|
||||
if (e.Parameter is AutoDiscoverySettings parameterAutoDiscoverySettings)
|
||||
{
|
||||
autoDiscoverySettings = parameterAutoDiscoverySettings;
|
||||
serverInformationToTest = autoDiscoverySettings.ToServerInformation();
|
||||
}
|
||||
else if (e.Parameter is CustomServerInformation customServerInformation)
|
||||
{
|
||||
// Only server information is passed.
|
||||
serverInformationToTest = customServerInformation;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await TryTestConnectionAsync(serverInformationToTest);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string protocolLog = ex is ImapClientPoolException clientPoolException ? clientPoolException.ProtocolLog : string.Empty;
|
||||
|
||||
var failurePackage = new ImapConnectionFailedPackage(ex, protocolLog, autoDiscoverySettings);
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupBackNavigationRequested(typeof(ImapConnectionFailedPage), failurePackage));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,96 +0,0 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Entities;
|
||||
using Wino.Core.Domain.Exceptions;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Domain.Models.AutoDiscovery;
|
||||
using Wino.Core.Messages.Mails;
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views.ImapSetup
|
||||
{
|
||||
public sealed partial class WelcomeImapSetupPage : Page
|
||||
{
|
||||
private readonly IAutoDiscoveryService _autoDiscoveryService = App.Current.Services.GetService<IAutoDiscoveryService>();
|
||||
|
||||
public WelcomeImapSetupPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
AutoDiscoveryPanel.Visibility = Visibility.Collapsed;
|
||||
MainSetupPanel.Visibility = Visibility.Visible;
|
||||
|
||||
if (e.Parameter is MailAccount accountProperties)
|
||||
{
|
||||
DisplayNameBox.Text = accountProperties.Name;
|
||||
}
|
||||
}
|
||||
|
||||
private async void SignInClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MainSetupPanel.Visibility = Visibility.Collapsed;
|
||||
AutoDiscoveryPanel.Visibility = Visibility.Visible;
|
||||
|
||||
// Let users see the discovery message for a while...
|
||||
|
||||
await Task.Delay(1000);
|
||||
|
||||
var minimalSettings = new AutoDiscoveryMinimalSettings()
|
||||
{
|
||||
Password = PasswordBox.Password,
|
||||
DisplayName = DisplayNameBox.Text,
|
||||
Email = AddressBox.Text,
|
||||
};
|
||||
|
||||
var discoverySettings = await _autoDiscoveryService.GetAutoDiscoverySettings(minimalSettings);
|
||||
|
||||
if (discoverySettings == null)
|
||||
{
|
||||
// Couldn't find settings.
|
||||
|
||||
var failurePackage = new ImapConnectionFailedPackage(new Exception(Translator.Exception_ImapAutoDiscoveryFailed), string.Empty, discoverySettings);
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupBackNavigationRequested(typeof(ImapConnectionFailedPage), failurePackage));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Settings are found. Test the connection with the given password.
|
||||
|
||||
discoverySettings.UserMinimalSettings = minimalSettings;
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupNavigationRequested(typeof(TestingImapConnectionPage), discoverySettings));
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelClicked(object sender, RoutedEventArgs e) => WeakReferenceMessenger.Default.Send(new ImapSetupDismissRequested());
|
||||
|
||||
private void AdvancedConfigurationClicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var latestMinimalSettings = new AutoDiscoveryMinimalSettings()
|
||||
{
|
||||
DisplayName = DisplayNameBox.Text,
|
||||
Password = PasswordBox.Password,
|
||||
Email = AddressBox.Text
|
||||
};
|
||||
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new ImapSetupNavigationRequested(typeof(AdvancedImapSetupPage), latestMinimalSettings));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,881 +0,0 @@
|
||||
<abstract:MailListPageAbstract
|
||||
x:Class="Wino.Views.MailListPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:collections="using:CommunityToolkit.Mvvm.Collections"
|
||||
xmlns:controls="using:Wino.Controls"
|
||||
xmlns:controls1="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:domain="using:Wino.Core.Domain"
|
||||
xmlns:enums="using:Wino.Core.Domain.Enums"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:i="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:listview="using:Wino.Controls.Advanced"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:menuflyouts="using:Wino.MenuFlyouts"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
xmlns:selectors="using:Wino.Selectors"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:viewModelData="using:Wino.Mail.ViewModels.Data"
|
||||
xmlns:wino="using:Wino"
|
||||
xmlns:converters="using:Wino.Converters"
|
||||
x:Name="root"
|
||||
Loaded="MailListPageLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Page.Resources>
|
||||
<CollectionViewSource
|
||||
x:Name="MailCollectionViewSource"
|
||||
IsSourceGrouped="True"
|
||||
Source="{x:Bind ViewModel.MailCollection.MailItems, Mode=OneWay}" />
|
||||
|
||||
<Thickness x:Key="ExpanderHeaderPadding">0,0,0,0</Thickness>
|
||||
<Thickness x:Key="ExpanderChevronMargin">0,0,12,0</Thickness>
|
||||
<Thickness x:Key="ExpanderHeaderBorderThickness">0,0,0,0</Thickness>
|
||||
|
||||
<SolidColorBrush x:Key="CardBackgroundFillColorDefaultBrush">Transparent</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="CardBackgroundFillColorSecondaryBrush">Transparent</SolidColorBrush>
|
||||
<SolidColorBrush x:Key="ExpanderContentBorderBrush">Transparent</SolidColorBrush>
|
||||
|
||||
<StaticResource x:Key="ExpanderContentBackground" ResourceKey="CardBackgroundFillColorSecondaryBrush" />
|
||||
<StaticResource x:Key="ExpanderHeaderBackground" ResourceKey="CardBackgroundFillColorDefaultBrush" />
|
||||
|
||||
<SolidColorBrush x:Key="SystemControlRevealFocusVisualBrush" Color="#FF4C4A48" />
|
||||
<SolidColorBrush x:Key="SystemControlFocusVisualSecondaryBrush" Color="#FFFFFFFF" />
|
||||
|
||||
<DataTemplate x:Key="FolderPivotTemplate" x:DataType="viewModelData:FolderPivotViewModel">
|
||||
<StackPanel Orientation="Horizontal" Spacing="4">
|
||||
<TextBlock Text="{x:Bind FolderTitle}" />
|
||||
<TextBlock
|
||||
x:Name="CountTextBlock"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
Visibility="{x:Bind ShouldDisplaySelectedItemCount, Mode=OneWay}">
|
||||
<Run Text="(" /><Run Text="{x:Bind SelectedItemCount, Mode=OneWay}" /><Run Text=")" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Header Templates -->
|
||||
<DataTemplate x:Key="MailGroupHeaderDefaultTemplate" x:DataType="collections:IReadOnlyObservableGroup">
|
||||
<Grid
|
||||
Margin="6,2"
|
||||
AllowFocusOnInteraction="False"
|
||||
Background="{ThemeResource MailListHeaderBackgroundColor}"
|
||||
CornerRadius="6">
|
||||
<TextBlock
|
||||
Padding="12"
|
||||
VerticalAlignment="Center"
|
||||
AllowFocusOnInteraction="False"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Text="{x:Bind helpers:XamlHelpers.GetMailGroupDateString(Key)}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
<!--
|
||||
Thread items should not display multi select checkbox.
|
||||
We override one for thread view models, and default items should use
|
||||
what the system has by default. Overriding ListViewItem and ListViewItemPresenter styles
|
||||
are really dangerous since they are somehow messy at system level.
|
||||
-->
|
||||
|
||||
<!-- Thread Item Container Style -->
|
||||
<Style x:Key="ThreadItemContainerStyle" TargetType="ListViewItem">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
|
||||
<Setter Property="TabNavigation" Value="Local" />
|
||||
<Setter Property="IsHoldingEnabled" Value="True" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
|
||||
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
|
||||
<Setter Property="AllowDrop" Value="False" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
|
||||
<Setter Property="FocusVisualMargin" Value="0" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="ListViewItem">
|
||||
<ListViewItemPresenter
|
||||
x:Name="Root"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
CheckBoxBrush="Transparent"
|
||||
CheckBrush="Transparent"
|
||||
CheckMode="Overlay"
|
||||
ContentMargin="{TemplateBinding Padding}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||
Control.IsTemplateFocusTarget="True"
|
||||
CornerRadius="5"
|
||||
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
|
||||
DragBackground="{ThemeResource ListViewItemDragBackground}"
|
||||
DragForeground="{ThemeResource ListViewItemDragForeground}"
|
||||
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
|
||||
FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
|
||||
FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
|
||||
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
|
||||
PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
|
||||
PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
|
||||
PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
|
||||
PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
|
||||
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
|
||||
RevealBackground="{ThemeResource ListViewItemRevealBackground}"
|
||||
RevealBorderBrush="{ThemeResource ListViewItemRevealBorderBrush}"
|
||||
RevealBorderThickness="{ThemeResource ListViewItemRevealBorderThemeThickness}"
|
||||
SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
|
||||
SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
|
||||
SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
|
||||
SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
|
||||
SelectionCheckMarkVisualEnabled="False">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal" />
|
||||
<VisualState x:Name="Selected" />
|
||||
<VisualState x:Name="PointerOver">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOverSelected">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="PointerOver" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPointerOver}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOverPressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PressedSelected">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.(RevealBrush.State)" Value="Pressed" />
|
||||
<Setter Target="Root.RevealBorderBrush" Value="{ThemeResource ListViewItemRevealBorderBrushPressed}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="DisabledStates">
|
||||
<VisualState x:Name="Enabled" />
|
||||
<VisualState x:Name="Disabled">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Root.RevealBorderThickness" Value="0" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</ListViewItemPresenter>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Mail Item Container Style Selector -->
|
||||
<selectors:MailItemContainerStyleSelector x:Key="WinoContainerSelector" Thread="{StaticResource ThreadItemContainerStyle}" />
|
||||
|
||||
<!-- Swipe Items -->
|
||||
<!-- Left -->
|
||||
<muxc:SwipeItems x:Key="LeftSwipeItems" Mode="Execute">
|
||||
<muxc:SwipeItem
|
||||
BehaviorOnInvoked="Close"
|
||||
Invoked="LeftSwipeItemInvoked"
|
||||
Text="{x:Bind domain:Translator.MailOperation_Delete}">
|
||||
<muxc:SwipeItem.IconSource>
|
||||
<controls:WinoFontIconSource Icon="Delete" />
|
||||
</muxc:SwipeItem.IconSource>
|
||||
<muxc:SwipeItem.Background>
|
||||
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
|
||||
<GradientStop Offset="0.0" Color="#FFF5A6A6" />
|
||||
<GradientStop Offset="0.5" Color="#FFEF4444" />
|
||||
<GradientStop Offset="1.0" Color="#FFF32525" />
|
||||
</LinearGradientBrush>
|
||||
</muxc:SwipeItem.Background>
|
||||
</muxc:SwipeItem>
|
||||
</muxc:SwipeItems>
|
||||
|
||||
<!-- Right -->
|
||||
<muxc:SwipeItems x:Key="RightSwipeItems" Mode="Execute">
|
||||
<muxc:SwipeItem
|
||||
BehaviorOnInvoked="Close"
|
||||
Invoked="RightSwipeItemInvoked"
|
||||
Text="{x:Bind domain:Translator.MarkReadUnread}">
|
||||
<muxc:SwipeItem.IconSource>
|
||||
<controls:WinoFontIconSource Icon="MarkRead" />
|
||||
</muxc:SwipeItem.IconSource>
|
||||
</muxc:SwipeItem>
|
||||
</muxc:SwipeItems>
|
||||
|
||||
<!-- Single Mail Item Template -->
|
||||
<DataTemplate x:Key="SingleMailItemTemplate" x:DataType="viewModelData:MailItemViewModel">
|
||||
<muxc:SwipeControl
|
||||
LeftItems="{StaticResource LeftSwipeItems}"
|
||||
RightItems="{StaticResource RightSwipeItems}"
|
||||
Tag="{x:Bind}">
|
||||
<controls:MailItemDisplayInformationControl
|
||||
x:DefaultBindMode="OneWay"
|
||||
CenterHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.CenterHoverAction, Mode=OneWay}"
|
||||
ContextRequested="MailItemContextRequested"
|
||||
DisplayMode="{Binding ElementName=root, Path=ViewModel.PreferencesService.MailItemDisplayMode, Mode=OneWay}"
|
||||
FocusVisualMargin="8"
|
||||
FocusVisualPrimaryBrush="{StaticResource SystemControlRevealFocusVisualBrush}"
|
||||
FocusVisualPrimaryThickness="2"
|
||||
FocusVisualSecondaryBrush="{StaticResource SystemControlFocusVisualSecondaryBrush}"
|
||||
FocusVisualSecondaryThickness="1"
|
||||
FromAddress="{x:Bind FromAddress}"
|
||||
FromName="{x:Bind FromName}"
|
||||
HasAttachments="{x:Bind HasAttachments}"
|
||||
HoverActionExecutedCommand="{Binding ElementName=root, Path=ViewModel.ExecuteHoverActionCommand}"
|
||||
IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}"
|
||||
IsCustomFocused="{x:Bind IsCustomFocused, Mode=OneWay}"
|
||||
IsDraft="{x:Bind IsDraft, Mode=OneWay}"
|
||||
IsFlagged="{x:Bind IsFlagged, Mode=OneWay}"
|
||||
IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}"
|
||||
IsRead="{x:Bind IsRead, Mode=OneWay}"
|
||||
LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}"
|
||||
MailItem="{Binding}"
|
||||
Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}"
|
||||
ReceivedDate="{x:Bind CreationDate}"
|
||||
RightHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.RightHoverAction, Mode=OneWay}"
|
||||
ShowPreviewText="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowPreviewEnabled, Mode=OneWay}"
|
||||
Snippet="{x:Bind PreviewText}"
|
||||
Subject="{x:Bind Subject}" />
|
||||
</muxc:SwipeControl>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Single Mail Item Template for Threads -->
|
||||
<DataTemplate x:Key="ThreadSingleMailItemTemplate" x:DataType="viewModelData:MailItemViewModel">
|
||||
<muxc:SwipeControl
|
||||
LeftItems="{StaticResource LeftSwipeItems}"
|
||||
RightItems="{StaticResource RightSwipeItems}"
|
||||
Tag="{x:Bind}">
|
||||
<controls:MailItemDisplayInformationControl
|
||||
x:DefaultBindMode="OneWay"
|
||||
CenterHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.CenterHoverAction, Mode=OneWay}"
|
||||
ContextRequested="MailItemContextRequested"
|
||||
DisplayMode="{Binding ElementName=root, Path=ViewModel.PreferencesService.MailItemDisplayMode, Mode=OneWay}"
|
||||
FocusVisualMargin="8"
|
||||
FocusVisualPrimaryBrush="{StaticResource SystemControlRevealFocusVisualBrush}"
|
||||
FocusVisualPrimaryThickness="2"
|
||||
FocusVisualSecondaryBrush="{StaticResource SystemControlFocusVisualSecondaryBrush}"
|
||||
FocusVisualSecondaryThickness="1"
|
||||
FromAddress="{x:Bind FromAddress}"
|
||||
FromName="{x:Bind FromName}"
|
||||
HasAttachments="{x:Bind HasAttachments}"
|
||||
HoverActionExecutedCommand="{Binding ElementName=root, Path=ViewModel.ExecuteHoverActionCommand}"
|
||||
IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}"
|
||||
IsCustomFocused="{x:Bind IsCustomFocused, Mode=OneWay}"
|
||||
IsDraft="{x:Bind IsDraft, Mode=OneWay}"
|
||||
IsFlagged="{x:Bind IsFlagged, Mode=OneWay}"
|
||||
IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}"
|
||||
IsRead="{x:Bind IsRead, Mode=OneWay}"
|
||||
LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}"
|
||||
MailItem="{Binding}"
|
||||
Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}"
|
||||
ReceivedDate="{x:Bind CreationDate}"
|
||||
RightHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.RightHoverAction, Mode=OneWay}"
|
||||
ShowPreviewText="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowPreviewEnabled, Mode=OneWay}"
|
||||
Snippet="{x:Bind PreviewText}"
|
||||
Subject="{x:Bind Subject}" />
|
||||
</muxc:SwipeControl>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- Mail Item Content Selector -->
|
||||
<selectors:MailItemDisplaySelector x:Key="MailItemDisplaySelector" SingleMailItemTemplate="{StaticResource SingleMailItemTemplate}">
|
||||
<selectors:MailItemDisplaySelector.ThreadMailItemTemplate>
|
||||
<DataTemplate x:DataType="viewModelData:ThreadMailItemViewModel">
|
||||
<muxc:Expander
|
||||
x:Name="ThreadExpander"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
BackgroundSizing="InnerBorderEdge"
|
||||
BorderThickness="0"
|
||||
IsExpanded="{x:Bind IsThreadExpanded, Mode=TwoWay}">
|
||||
<muxc:Expander.Header>
|
||||
<controls:MailItemDisplayInformationControl
|
||||
x:DefaultBindMode="OneWay"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
CanDrag="True"
|
||||
CenterHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.CenterHoverAction, Mode=OneWay}"
|
||||
ConnectedExpander="{Binding ElementName=ThreadExpander}"
|
||||
ContextRequested="MailItemContextRequested"
|
||||
DisplayMode="{Binding ElementName=root, Path=ViewModel.PreferencesService.MailItemDisplayMode, Mode=OneWay}"
|
||||
DragStarting="ThreadHeaderDragStart"
|
||||
DropCompleted="ThreadHeaderDragFinished"
|
||||
FromAddress="{x:Bind FromAddress}"
|
||||
FromName="{x:Bind FromName}"
|
||||
HasAttachments="{x:Bind HasAttachments}"
|
||||
HoverActionExecutedCommand="{Binding ElementName=root, Path=ViewModel.ExecuteHoverActionCommand}"
|
||||
IsAvatarVisible="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowSenderPicturesEnabled, Mode=OneWay}"
|
||||
IsDraft="{x:Bind IsDraft}"
|
||||
IsFlagged="{x:Bind IsFlagged}"
|
||||
IsHitTestVisible="True"
|
||||
IsHoverActionsEnabled="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsHoverActionsEnabled, Mode=OneWay}"
|
||||
IsRead="{x:Bind IsRead}"
|
||||
LeftHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.LeftHoverAction, Mode=OneWay}"
|
||||
MailItem="{Binding}"
|
||||
Prefer24HourTimeFormat="{Binding ElementName=root, Path=ViewModel.PreferencesService.Prefer24HourTimeFormat, Mode=OneWay}"
|
||||
ReceivedDate="{x:Bind CreationDate}"
|
||||
RightHoverAction="{Binding ElementName=root, Path=ViewModel.PreferencesService.RightHoverAction, Mode=OneWay}"
|
||||
ShowPreviewText="{Binding ElementName=root, Path=ViewModel.PreferencesService.IsShowPreviewEnabled, Mode=OneWay}"
|
||||
Snippet="{x:Bind PreviewText}"
|
||||
Subject="{x:Bind Subject}" />
|
||||
</muxc:Expander.Header>
|
||||
<muxc:Expander.Content>
|
||||
<listview:WinoListView
|
||||
x:Name="ThreadItemsList"
|
||||
ui:ListViewExtensions.ItemContainerStretchDirection="Horizontal"
|
||||
IsThreadListView="True"
|
||||
ItemTemplate="{StaticResource ThreadSingleMailItemTemplate}"
|
||||
ItemsSource="{x:Bind ThreadItems}"
|
||||
ProcessKeyboardAccelerators="ProcessMailItemKeyboardAccelerator"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Hidden">
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection>
|
||||
<EdgeUIThemeTransition />
|
||||
</TransitionCollection>
|
||||
</ListView.ItemContainerTransitions>
|
||||
</listview:WinoListView>
|
||||
</muxc:Expander.Content>
|
||||
</muxc:Expander>
|
||||
</DataTemplate>
|
||||
</selectors:MailItemDisplaySelector.ThreadMailItemTemplate>
|
||||
</selectors:MailItemDisplaySelector>
|
||||
|
||||
<SolidColorBrush x:Key="ButtonBackgroundDisabled">Transparent</SolidColorBrush>
|
||||
|
||||
<Style
|
||||
x:Key="TopCommandBarButtonStyle"
|
||||
BasedOn="{StaticResource DefaultButtonStyle}"
|
||||
TargetType="Button">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="Padding" Value="12" />
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="TopCommandBarToggleButtonStyle"
|
||||
BasedOn="{StaticResource DefaultToggleButtonStyle}"
|
||||
TargetType="ToggleButton">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="Padding" Value="12" />
|
||||
</Style>
|
||||
</Page.Resources>
|
||||
|
||||
<wino:BasePage.ShellContent>
|
||||
<Grid>
|
||||
<!-- Hidden focus receiver... -->
|
||||
<TextBox
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Bottom"
|
||||
Opacity="0"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<AutoSuggestBox
|
||||
x:Name="SearchBar"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="Transparent"
|
||||
GotFocus="SearchBoxFocused"
|
||||
LostFocus="SearchBarUnfocused"
|
||||
PlaceholderText="{x:Bind domain:Translator.SearchBarPlaceholder}"
|
||||
QueryIcon="Find"
|
||||
Text="{x:Bind ViewModel.SearchQuery, Mode=TwoWay}"
|
||||
TextChanged="SearchBar_TextChanged">
|
||||
<i:Interaction.Behaviors>
|
||||
<ic:EventTriggerBehavior EventName="QuerySubmitted">
|
||||
<ic:InvokeCommandAction Command="{x:Bind ViewModel.PerformSearchCommand}" />
|
||||
</ic:EventTriggerBehavior>
|
||||
</i:Interaction.Behaviors>
|
||||
</AutoSuggestBox>
|
||||
</Grid>
|
||||
</wino:BasePage.ShellContent>
|
||||
|
||||
<Grid x:Name="RootGrid" Padding="0,0,0,7">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition
|
||||
x:Name="ReaderColumn"
|
||||
Width="*"
|
||||
MaxWidth="{x:Bind ViewModel.StatePersistanceService.MailListPaneLength, Mode=OneWay}" />
|
||||
<ColumnDefinition x:Name="RendererColumn" Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Mail Items -->
|
||||
<Border
|
||||
x:Name="ReaderGridContainer"
|
||||
Grid.Column="0"
|
||||
Padding="5,0,0,0"
|
||||
Background="{ThemeResource WinoContentZoneBackgroud}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="7">
|
||||
<Grid x:Name="ReaderGrid">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Top Area -->
|
||||
<Grid
|
||||
Padding="6"
|
||||
CornerRadius="8"
|
||||
RowSpacing="4">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Top Commands -->
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
Padding="2,0"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
|
||||
CornerRadius="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="48" />
|
||||
<RowDefinition Height="2" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Commands -->
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button
|
||||
Command="{x:Bind ViewModel.SyncFolderCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.CanSynchronize, Mode=OneWay}"
|
||||
Style="{StaticResource TopCommandBarButtonStyle}">
|
||||
<Button.Content>
|
||||
<controls:WinoFontIcon FontSize="16" Icon="Sync" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<ToggleButton
|
||||
x:Name="SelectionModeToggle"
|
||||
Grid.Column="1"
|
||||
Checked="SelectionModeToggleChecked"
|
||||
IsChecked="{x:Bind ViewModel.IsMultiSelectionModeEnabled, Mode=TwoWay}"
|
||||
Style="{StaticResource TopCommandBarToggleButtonStyle}"
|
||||
Unchecked="SelectionModeToggleUnchecked">
|
||||
<ToggleButton.Content>
|
||||
<controls:WinoFontIcon FontSize="18" Icon="MultiSelect" />
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
|
||||
<AppBarSeparator Grid.Column="2" Margin="2,0" />
|
||||
|
||||
<Button
|
||||
x:Name="ArchiveAppBarButton"
|
||||
Grid.Column="3"
|
||||
x:Load="{x:Bind helpers:XamlHelpers.ReverseBoolConverter(ViewModel.IsArchiveSpecialFolder), Mode=OneWay}"
|
||||
Command="{x:Bind ViewModel.MailOperationCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
|
||||
Style="{StaticResource TopCommandBarButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Archive}">
|
||||
<Button.Content>
|
||||
<controls:WinoFontIcon FontSize="18" Icon="Archive" />
|
||||
</Button.Content>
|
||||
<Button.CommandParameter>
|
||||
<enums:MailOperation>Archive</enums:MailOperation>
|
||||
</Button.CommandParameter>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="UnarchiveAppBarButton"
|
||||
Grid.Column="3"
|
||||
x:Load="{x:Bind ViewModel.IsArchiveSpecialFolder, Mode=OneWay}"
|
||||
Command="{x:Bind ViewModel.MailOperationCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
|
||||
Style="{StaticResource TopCommandBarButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Unarchive}">
|
||||
<Button.Content>
|
||||
<controls:WinoFontIcon FontSize="18" Icon="UnArchive" />
|
||||
</Button.Content>
|
||||
<Button.CommandParameter>
|
||||
<enums:MailOperation>UnArchive</enums:MailOperation>
|
||||
</Button.CommandParameter>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Grid.Column="4"
|
||||
Command="{x:Bind ViewModel.MailOperationCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
|
||||
Style="{StaticResource TopCommandBarButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Delete}">
|
||||
<Button.CommandParameter>
|
||||
<enums:MailOperation>SoftDelete</enums:MailOperation>
|
||||
</Button.CommandParameter>
|
||||
<Button.Content>
|
||||
<controls:WinoFontIcon FontSize="18" Icon="Delete" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
x:Name="MoveButtonAppBarButton"
|
||||
Grid.Column="5"
|
||||
Command="{x:Bind ViewModel.MailOperationCommand}"
|
||||
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
|
||||
Style="{StaticResource TopCommandBarButtonStyle}"
|
||||
ToolTipService.ToolTip="{x:Bind domain:Translator.MailOperation_Move}">
|
||||
<Button.CommandParameter>
|
||||
<enums:MailOperation>Move</enums:MailOperation>
|
||||
</Button.CommandParameter>
|
||||
<Button.Content>
|
||||
<controls:WinoFontIcon FontSize="18" Icon="Move" />
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
Grid.Column="6"
|
||||
IsEnabled="{x:Bind ViewModel.HasSelectedItems, Mode=OneWay}"
|
||||
Style="{StaticResource TopCommandBarButtonStyle}">
|
||||
<Button.Content>
|
||||
<controls:WinoFontIcon FontSize="20" Icon="More" />
|
||||
</Button.Content>
|
||||
<Button.Flyout>
|
||||
<MenuFlyout AreOpenCloseAnimationsEnabled="False" Placement="BottomEdgeAlignedLeft">
|
||||
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_SetFlag}">
|
||||
<MenuFlyoutItem.CommandParameter>
|
||||
<enums:MailOperation>SetFlag</enums:MailOperation>
|
||||
</MenuFlyoutItem.CommandParameter>
|
||||
<MenuFlyoutItem.Icon>
|
||||
<controls:WinoFontIcon Icon="Flag" />
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_ClearFlag}">
|
||||
<MenuFlyoutItem.CommandParameter>
|
||||
<enums:MailOperation>ClearFlag</enums:MailOperation>
|
||||
</MenuFlyoutItem.CommandParameter>
|
||||
<MenuFlyoutItem.Icon>
|
||||
<controls:WinoFontIcon Icon="ClearFlag" />
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_MarkAsRead}">
|
||||
<MenuFlyoutItem.CommandParameter>
|
||||
<enums:MailOperation>MarkAsRead</enums:MailOperation>
|
||||
</MenuFlyoutItem.CommandParameter>
|
||||
<MenuFlyoutItem.Icon>
|
||||
<controls:WinoFontIcon Icon="MarkRead" />
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
<MenuFlyoutItem Command="{x:Bind ViewModel.MailOperationCommand}" Text="{x:Bind domain:Translator.MailOperation_MarkAsUnread}">
|
||||
<MenuFlyoutItem.CommandParameter>
|
||||
<enums:MailOperation>MarkAsUnread</enums:MailOperation>
|
||||
</MenuFlyoutItem.CommandParameter>
|
||||
<MenuFlyoutItem.Icon>
|
||||
<controls:WinoFontIcon Icon="MarkUnread" />
|
||||
</MenuFlyoutItem.Icon>
|
||||
</MenuFlyoutItem>
|
||||
</MenuFlyout>
|
||||
</Button.Flyout>
|
||||
</Button>
|
||||
</Grid>
|
||||
|
||||
<muxc:ProgressBar
|
||||
x:Name="LoadingProgressBar"
|
||||
Grid.Row="1"
|
||||
x:Load="{x:Bind ViewModel.IsInitializingFolder, Mode=OneWay}"
|
||||
IsIndeterminate="True" />
|
||||
</Grid>
|
||||
|
||||
<!-- Pivot + Sync + Multi Select -->
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Margin="0,0,0,5"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.ReverseBoolToVisibilityConverter(ViewModel.IsInSearchMode), Mode=OneWay}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Select All Checkbox -->
|
||||
<CheckBox
|
||||
x:Name="SelectAllCheckbox"
|
||||
Grid.Row="1"
|
||||
MinWidth="0"
|
||||
Margin="8,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Canvas.ZIndex="100"
|
||||
Checked="SelectAllCheckboxChecked"
|
||||
Unchecked="SelectAllCheckboxUnchecked"
|
||||
Visibility="{x:Bind helpers:XamlHelpers.IsSelectionModeMultiple(MailListView.SelectionMode), Mode=OneWay}" />
|
||||
|
||||
<!-- Folders -->
|
||||
<controls:WinoPivotControl
|
||||
x:Name="WinoPivot"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
DataTemplate="{StaticResource FolderPivotTemplate}"
|
||||
ItemsSource="{x:Bind ViewModel.PivotFolders, Mode=OneWay}"
|
||||
SelectedItem="{x:Bind ViewModel.SelectedFolderPivot, Mode=TwoWay}"
|
||||
SelectionChanged="FolderPivotChanged"
|
||||
SelectorPipeColor="{ThemeResource NavigationViewSelectionIndicatorForeground}" />
|
||||
|
||||
<!-- Filtering -->
|
||||
<muxc:DropDownButton
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Content="{x:Bind ViewModel.SelectedFilterOption.Title, Mode=OneWay}"
|
||||
ToolTipService.ToolTip="Filter">
|
||||
<muxc:DropDownButton.Flyout>
|
||||
<menuflyouts:FilterMenuFlyout
|
||||
x:Name="FilterMenuFlyout"
|
||||
AreOpenCloseAnimationsEnabled="True"
|
||||
FilterOptions="{x:Bind ViewModel.FilterOptions, Mode=OneTime}"
|
||||
Placement="Bottom"
|
||||
SelectedFilterChangedCommand="{x:Bind ViewModel.SelectedFilterChangedCommand}"
|
||||
SelectedFilterOption="{x:Bind ViewModel.SelectedFilterOption, Mode=TwoWay}"
|
||||
SelectedSortingOption="{x:Bind ViewModel.SelectedSortingOption, Mode=TwoWay}"
|
||||
SelectedSortingOptionChangedCommand="{x:Bind ViewModel.SelectedSortingChangedCommand}"
|
||||
SortingOptions="{x:Bind ViewModel.SortingOptions, Mode=OneTime}" />
|
||||
</muxc:DropDownButton.Flyout>
|
||||
</muxc:DropDownButton>
|
||||
|
||||
<muxc:InfoBar
|
||||
Title="{x:Bind domain:Translator.InfoBarTitle_SynchronizationDisabledFolder}"
|
||||
Grid.Row="0"
|
||||
Grid.ColumnSpan="3"
|
||||
IsClosable="True"
|
||||
IsOpen="{x:Bind ViewModel.IsFolderSynchronizationEnabled, Converter={StaticResource ReverseBooleanConverter}, Mode=OneWay}"
|
||||
Message="{x:Bind domain:Translator.InfoBarMessage_SynchronizationDisabledFolder}"
|
||||
Severity="Informational">
|
||||
<muxc:InfoBar.ActionButton>
|
||||
<Button Command="{x:Bind ViewModel.EnableFolderSynchronizationCommand}" Content="Enable" />
|
||||
</muxc:InfoBar.ActionButton>
|
||||
</muxc:InfoBar>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<!-- No items createria -->
|
||||
<StackPanel
|
||||
x:Name="NoItemsPanel"
|
||||
Grid.Row="2"
|
||||
Grid.RowSpan="3"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Spacing="10">
|
||||
|
||||
<Viewbox
|
||||
Width="48"
|
||||
Opacity="0.4"
|
||||
Visibility="{x:Bind ViewModel.IsEmpty, Mode=OneWay}">
|
||||
<Path Data="M252,960C227,960 203.083,954.917 180.25,944.75C157.417,934.583 137.417,920.917 120.25,903.75C103.083,886.583 89.4167,866.583 79.25,843.75C69.0833,820.917 64,797 64,772L64,252C64,227 69.0833,203.083 79.25,180.25C89.4167,157.417 103.083,137.417 120.25,120.25C137.417,103.083 157.417,89.4167 180.25,79.25C203.083,69.0834 227,64.0001 252,64L772,64C797,64.0001 820.917,69.0834 843.75,79.25C866.583,89.4167 886.583,103.083 903.75,120.25C920.917,137.417 934.583,157.417 944.75,180.25C954.917,203.083 960,227 960,252L960,772C960,797 954.917,820.917 944.75,843.75C934.583,866.583 920.917,886.583 903.75,903.75C886.583,920.917 866.583,934.583 843.75,944.75C820.917,954.917 797,960 772,960ZM770.5,896C787.167,896 803.083,892.583 818.25,885.75C833.417,878.917 846.75,869.75 858.25,858.25C869.75,846.75 878.917,833.417 885.75,818.25C892.583,803.083 896,787.167 896,770.5L896,253.5C896,236.833 892.583,220.917 885.75,205.75C878.917,190.583 869.75,177.25 858.25,165.75C846.75,154.25 833.417,145.083 818.25,138.25C803.083,131.417 787.167,128 770.5,128L253.5,128C236.833,128 220.917,131.417 205.75,138.25C190.583,145.083 177.25,154.25 165.75,165.75C154.25,177.25 145.083,190.583 138.25,205.75C131.417,220.917 128,236.833 128,253.5L128,770.5C128,787.167 131.417,803.083 138.25,818.25C145.083,833.417 154.25,846.75 165.75,858.25C177.25,869.75 190.583,878.917 205.75,885.75C220.917,892.583 236.833,896 253.5,896ZM559,604.5C541.667,616.833 523.417,625.833 504.25,631.5C485.083,637.167 465,640 444,640C418,640 393.583,634.833 370.75,624.5C347.917,614.167 328,600.167 311,582.5C294,564.833 280.583,544.417 270.75,521.25C260.917,498.083 256,473.667 256,448C256,421.333 261,396.333 271,373C281,349.667 294.667,329.333 312,312C329.333,294.667 349.667,281 373,271C396.333,261 421.333,256 448,256C473.667,256 498.083,260.917 521.25,270.75C544.417,280.583 564.833,294 582.5,311C600.167,328 614.167,347.917 624.5,370.75C634.833,393.583 640,418 640,444C640,465 637.167,485.083 631.5,504.25C625.833,523.417 616.833,541.667 604.5,559L758.5,713.5C764.833,719.833 768,727.333 768,736C768,744.667 764.833,752.167 758.5,758.5C752.167,764.833 744.667,768 736,768C727.333,768 719.833,764.833 713.5,758.5ZM576,448L576,445.5C576,428.167 572.5,411.917 565.5,396.75C558.5,381.583 549.167,368.333 537.5,357C525.833,345.667 512.25,336.667 496.75,330C481.25,323.333 465,320 448,320C430.333,320 413.75,323.417 398.25,330.25C382.75,337.083 369.25,346.25 357.75,357.75C346.25,369.25 337.083,382.833 330.25,398.5C323.417,414.167 320,430.667 320,448C320,465.667 323.417,482.25 330.25,497.75C337.083,513.25 346.25,526.75 357.75,538.25C369.25,549.75 382.75,558.917 398.25,565.75C413.75,572.583 430.333,576 448,576C465.333,576 481.833,572.583 497.5,565.75C513.167,558.917 526.75,549.75 538.25,538.25C549.75,526.75 558.917,513.25 565.75,497.75C572.583,482.25 576,465.667 576,448Z" Fill="{ThemeResource InformationBrush}" />
|
||||
</Viewbox>
|
||||
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="20"
|
||||
FontWeight="ExtraLight"
|
||||
Foreground="{ThemeResource InformationBrush}"
|
||||
Opacity="0.4"
|
||||
Text="{x:Bind domain:Translator.NoMessageCrieteria}"
|
||||
Visibility="{x:Bind ViewModel.IsCriteriaFailed, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="20"
|
||||
FontWeight="ExtraLight"
|
||||
Foreground="{ThemeResource InformationBrush}"
|
||||
Opacity="0.4"
|
||||
Text="{x:Bind domain:Translator.NoMessageEmptyFolder}"
|
||||
Visibility="{x:Bind ViewModel.IsFolderEmpty, Mode=OneWay}" />
|
||||
|
||||
<muxc:ProgressRing
|
||||
x:Name="LoadingProgressIndicator"
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
x:Load="{x:Bind ViewModel.IsProgressRing, Mode=OneWay}"
|
||||
Canvas.ZIndex="999" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Mail Items -->
|
||||
<muxc:RefreshContainer
|
||||
Grid.Row="2"
|
||||
RefreshRequested="PullToRefreshRequested"
|
||||
Visibility="{x:Bind ViewModel.IsEmpty, Converter={StaticResource ReverseBooleanToVisibilityConverter}, Mode=OneWay}">
|
||||
<SemanticZoom x:Name="SemanticZoomContainer" CanChangeViews="{x:Bind ViewModel.PreferencesService.IsSemanticZoomEnabled, Mode=OneWay}">
|
||||
<SemanticZoom.ZoomedInView>
|
||||
<listview:WinoListView
|
||||
x:Name="MailListView"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ui:ListViewExtensions.ItemContainerStretchDirection="Horizontal"
|
||||
ItemContainerStyleSelector="{StaticResource WinoContainerSelector}"
|
||||
ItemDeletedCommand="{x:Bind ViewModel.MailOperationCommand}"
|
||||
ItemTemplateSelector="{StaticResource MailItemDisplaySelector}"
|
||||
ItemsSource="{x:Bind MailCollectionViewSource.View, Mode=OneWay}"
|
||||
LoadMoreCommand="{x:Bind ViewModel.LoadMoreItemsCommand}"
|
||||
ProcessKeyboardAccelerators="ProcessMailItemKeyboardAccelerator"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<ListView.ItemContainerTransitions>
|
||||
<TransitionCollection>
|
||||
<AddDeleteThemeTransition />
|
||||
</TransitionCollection>
|
||||
</ListView.ItemContainerTransitions>
|
||||
<ListView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsStackPanel AreStickyGroupHeadersEnabled="True" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListView.ItemsPanel>
|
||||
<ListView.Resources>
|
||||
<ResourceDictionary>
|
||||
<Style BasedOn="{StaticResource MailListHeaderStyle}" TargetType="ListViewHeaderItem" />
|
||||
</ResourceDictionary>
|
||||
</ListView.Resources>
|
||||
<ListView.GroupStyle>
|
||||
<GroupStyle HeaderTemplate="{StaticResource MailGroupHeaderDefaultTemplate}" HidesIfEmpty="True" />
|
||||
</ListView.GroupStyle>
|
||||
</listview:WinoListView>
|
||||
</SemanticZoom.ZoomedInView>
|
||||
<SemanticZoom.ZoomedOutView>
|
||||
<ListView
|
||||
x:Name="ZoomOutList"
|
||||
x:Load="{x:Bind helpers:XamlHelpers.ReverseBoolConverter(SemanticZoomContainer.IsZoomedInViewActive), Mode=OneWay}"
|
||||
ItemsSource="{x:Bind MailCollectionViewSource.View.CollectionGroups}">
|
||||
<ListView.Resources>
|
||||
<Style TargetType="ListViewItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="Margin" Value="0,12" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
</Style>
|
||||
</ListView.Resources>
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="ICollectionViewGroup">
|
||||
<Grid
|
||||
Margin="4,0"
|
||||
Background="{ThemeResource MailListHeaderBackgroundColor}"
|
||||
CornerRadius="4">
|
||||
<TextBlock
|
||||
Margin="12,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
Text="{x:Bind helpers:XamlHelpers.GetMailGroupDateString(Group)}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</SemanticZoom.ZoomedOutView>
|
||||
</SemanticZoom>
|
||||
</muxc:RefreshContainer>
|
||||
|
||||
|
||||
<!-- Update Info Bar -->
|
||||
<controls:WinoInfoBar
|
||||
Title="{x:Bind ViewModel.BarTitle, Mode=OneWay}"
|
||||
Grid.Row="2"
|
||||
Margin="6,0,6,6"
|
||||
VerticalAlignment="Bottom"
|
||||
AnimationType="SlideFromBottomToTop"
|
||||
DismissInterval="2"
|
||||
IsClosable="False"
|
||||
IsOpen="{x:Bind ViewModel.IsBarOpen, Mode=TwoWay}"
|
||||
Message="{x:Bind ViewModel.BarMessage, Mode=OneWay}"
|
||||
Severity="{x:Bind helpers:XamlHelpers.InfoBarSeverityConverter(ViewModel.BarSeverity), Mode=OneWay}" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Grid Grid.Column="1" x:Name="RenderingGrid">
|
||||
<!-- Mail Rendering Frame -->
|
||||
<Frame x:Name="RenderingFrame" IsNavigationStackEnabled="False" />
|
||||
|
||||
<!-- No Mail Selected Message -->
|
||||
<StackPanel
|
||||
x:Name="NoMailSelectedPanel"
|
||||
Opacity="0.5"
|
||||
Spacing="6"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
|
||||
<controls:WinoFontIcon Icon="Mail" FontSize="80" />
|
||||
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="31"
|
||||
Text="{x:Bind ViewModel.SelectedMessageText, Mode=OneWay}"
|
||||
Style="{StaticResource SubheaderTextBlockStyle}"
|
||||
x:Name="CountTextBlock" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="AdaptiveStates" CurrentStateChanged="AdaptivenessChanged">
|
||||
<VisualState x:Name="NormalState">
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="{x:Bind helpers:XamlHelpers.MailListAdaptivityConverter(ViewModel.StatePersistanceService.MailListPaneLength), Mode=OneWay}" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
|
||||
<VisualState x:Name="NarrowState">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ReaderGrid.MaxWidth" Value="10000" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
<AdaptiveTrigger MinWindowWidth="0" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
|
||||
<!-- Pane open adjustments -->
|
||||
<VisualStateGroup x:Name="PaneStates">
|
||||
<VisualState x:Name="PaneOpened">
|
||||
<VisualState.Setters>
|
||||
<!--<Setter Target="RootGrid.Margin" Value="-6,0,0,0" />-->
|
||||
<Setter Target="ReaderGrid.Margin" Value="-4,0,0,0" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
<StateTrigger IsActive="{x:Bind PreferencesService.IsNavigationPaneOpened, Mode=OneWay}" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PaneClosed" />
|
||||
</VisualStateGroup>
|
||||
|
||||
<!-- Mail reader states -->
|
||||
<VisualStateGroup x:Name="ReaderStates">
|
||||
<VisualState x:Name="ReaderActive">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="ReaderGrid.CornerRadius" Value="0" />
|
||||
</VisualState.Setters>
|
||||
<VisualState.StateTriggers>
|
||||
<StateTrigger IsActive="{x:Bind StatePersistanceService.IsReadingMail, Mode=OneWay}" />
|
||||
</VisualState.StateTriggers>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</abstract:MailListPageAbstract>
|
||||
@@ -1,582 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.AppCenter.Analytics;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using MoreLinq;
|
||||
using Windows.Foundation;
|
||||
|
||||
using Wino.Controls;
|
||||
using Wino.Controls.Advanced;
|
||||
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.Menus;
|
||||
using Wino.Core.Domain.Models.Navigation;
|
||||
using Wino.Core.Messages.Mails;
|
||||
using Wino.Core.Messages.Shell;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Mail.ViewModels.Messages;
|
||||
using Wino.MenuFlyouts.Context;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class MailListPage : MailListPageAbstract,
|
||||
IRecipient<ResetSingleMailItemSelectionEvent>,
|
||||
IRecipient<ClearMailSelectionsRequested>,
|
||||
IRecipient<ActiveMailItemChangedEvent>,
|
||||
IRecipient<ActiveMailFolderChangedEvent>,
|
||||
IRecipient<SelectMailItemContainerEvent>,
|
||||
IRecipient<ShellStateUpdated>,
|
||||
IRecipient<DisposeRenderingFrameRequested>
|
||||
{
|
||||
private const string NarrowVisualStateKey = "NarrowState";
|
||||
private const string AdaptivenessStatesKey = "AdaptiveStates";
|
||||
|
||||
private IStatePersistanceService StatePersistanceService { get; } = App.Current.Services.GetService<IStatePersistanceService>();
|
||||
private IPreferencesService PreferencesService { get; } = App.Current.Services.GetService<IPreferencesService>();
|
||||
private IKeyPressService KeyPressService { get; } = App.Current.Services.GetService<IKeyPressService>();
|
||||
|
||||
public MailListPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
// Bindings.Update();
|
||||
|
||||
// Delegate to ViewModel.
|
||||
if (e.Parameter is NavigateMailFolderEventArgs folderNavigationArgs)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new ActiveMailFolderChangedEvent(folderNavigationArgs.BaseFolderMenuItem, folderNavigationArgs.FolderInitLoadAwaitTask));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
|
||||
this.Bindings.StopTracking();
|
||||
|
||||
RenderingFrame.Navigate(typeof(IdlePage));
|
||||
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
private void UpdateSelectAllButtonStatus()
|
||||
{
|
||||
// Check all checkbox if all is selected.
|
||||
// Unhook events to prevent selection overriding.
|
||||
|
||||
SelectAllCheckbox.Checked -= SelectAllCheckboxChecked;
|
||||
SelectAllCheckbox.Unchecked -= SelectAllCheckboxUnchecked;
|
||||
|
||||
SelectAllCheckbox.IsChecked = MailListView.Items.Count > 0 && MailListView.SelectedItems.Count == MailListView.Items.Count;
|
||||
|
||||
SelectAllCheckbox.Checked += SelectAllCheckboxChecked;
|
||||
SelectAllCheckbox.Unchecked += SelectAllCheckboxUnchecked;
|
||||
}
|
||||
|
||||
private void SelectionModeToggleChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ChangeSelectionMode(ListViewSelectionMode.Multiple);
|
||||
}
|
||||
|
||||
private void FolderPivotChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
foreach (var addedItem in e.AddedItems)
|
||||
{
|
||||
if (addedItem is FolderPivotViewModel pivotItem)
|
||||
{
|
||||
pivotItem.IsSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var removedItem in e.RemovedItems)
|
||||
{
|
||||
if (removedItem is FolderPivotViewModel pivotItem)
|
||||
{
|
||||
pivotItem.IsSelected = false;
|
||||
}
|
||||
}
|
||||
|
||||
SelectAllCheckbox.IsChecked = false;
|
||||
SelectionModeToggle.IsChecked = false;
|
||||
|
||||
MailListView.ClearSelections();
|
||||
|
||||
UpdateSelectAllButtonStatus();
|
||||
ViewModel.SelectedPivotChangedCommand.Execute(null);
|
||||
}
|
||||
|
||||
private void ChangeSelectionMode(ListViewSelectionMode mode)
|
||||
{
|
||||
MailListView.ChangeSelectionMode(mode);
|
||||
|
||||
if (ViewModel?.PivotFolders != null)
|
||||
{
|
||||
ViewModel.PivotFolders.ForEach(a => a.IsExtendedMode = mode == ListViewSelectionMode.Extended);
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectionModeToggleUnchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ChangeSelectionMode(ListViewSelectionMode.Extended);
|
||||
}
|
||||
|
||||
private void SelectAllCheckboxChecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MailListView.SelectAllWino();
|
||||
}
|
||||
|
||||
private void SelectAllCheckboxUnchecked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MailListView.ClearSelections();
|
||||
}
|
||||
|
||||
#region Mostly UI
|
||||
|
||||
private void UpdateAdaptiveness()
|
||||
{
|
||||
|
||||
bool shouldDisplayNoMessagePanel, shouldDisplayMailingList, shouldDisplayRenderingFrame;
|
||||
|
||||
// This is the smallest state UI can get.
|
||||
// Either mailing list or rendering grid is visible.
|
||||
if (StatePersistanceService.IsReaderNarrowed)
|
||||
{
|
||||
// Start visibility checks by no message panel.
|
||||
|
||||
bool isMultiSelectionEnabled = ViewModel.IsMultiSelectionModeEnabled || KeyPressService.IsCtrlKeyPressed();
|
||||
|
||||
shouldDisplayMailingList = isMultiSelectionEnabled ? true : (!ViewModel.HasSelectedItems || ViewModel.HasMultipleItemSelections);
|
||||
shouldDisplayNoMessagePanel = shouldDisplayMailingList ? false : !ViewModel.HasSelectedItems || ViewModel.HasMultipleItemSelections;
|
||||
shouldDisplayRenderingFrame = shouldDisplayMailingList ? false : !shouldDisplayNoMessagePanel;
|
||||
}
|
||||
else
|
||||
{
|
||||
shouldDisplayMailingList = true;
|
||||
shouldDisplayNoMessagePanel = !ViewModel.HasSelectedItems || ViewModel.HasMultipleItemSelections;
|
||||
shouldDisplayRenderingFrame = !shouldDisplayNoMessagePanel;
|
||||
}
|
||||
|
||||
ReaderGridContainer.Visibility = shouldDisplayMailingList ? Visibility.Visible : Visibility.Collapsed;
|
||||
RenderingFrame.Visibility = shouldDisplayRenderingFrame ? Visibility.Visible : Visibility.Collapsed;
|
||||
NoMailSelectedPanel.Visibility = shouldDisplayNoMessagePanel ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
if (StatePersistanceService.IsReaderNarrowed)
|
||||
{
|
||||
if (RenderingFrame.Visibility == Visibility.Visible && ReaderGridContainer.Visibility == Visibility.Collapsed)
|
||||
{
|
||||
// Extend rendering frame to full width.
|
||||
Grid.SetColumn(RenderingGrid, 0);
|
||||
Grid.SetColumnSpan(RenderingGrid, 2);
|
||||
|
||||
Grid.SetColumn(ReaderGrid, 0);
|
||||
Grid.SetColumnSpan(ReaderGrid, 2);
|
||||
}
|
||||
else if (RenderingFrame.Visibility == Visibility.Collapsed && NoMailSelectedPanel.Visibility == Visibility.Collapsed)
|
||||
{
|
||||
// Only mail list is available.
|
||||
// Extend the mailing list.
|
||||
Grid.SetColumn(ReaderGridContainer, 0);
|
||||
Grid.SetColumnSpan(ReaderGridContainer, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mailing list is always visible on the first part.
|
||||
|
||||
Grid.SetColumn(ReaderGridContainer, 0);
|
||||
Grid.SetColumnSpan(ReaderGridContainer, 1);
|
||||
|
||||
// Rendering grid should take the rest of the space.
|
||||
Grid.SetColumn(RenderingGrid, 1);
|
||||
Grid.SetColumnSpan(RenderingGrid, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void AdaptivenessChanged(object sender, VisualStateChangedEventArgs e)
|
||||
{
|
||||
StatePersistanceService.IsReaderNarrowed = e.NewState.Name == "NarrowState";
|
||||
|
||||
UpdateAdaptiveness();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
void IRecipient<ResetSingleMailItemSelectionEvent>.Receive(ResetSingleMailItemSelectionEvent message)
|
||||
{
|
||||
// Single item in thread selected.
|
||||
// Force main list view to unselect all items, except for the one provided.
|
||||
|
||||
MailListView.ClearSelections(message.SelectedViewModel);
|
||||
}
|
||||
|
||||
private async void MailItemContextRequested(UIElement sender, ContextRequestedEventArgs args)
|
||||
{
|
||||
// Context is requested from a single mail point, but we might have multiple selected items.
|
||||
// This menu should be calculated based on all selected items by providers.
|
||||
|
||||
if (sender is MailItemDisplayInformationControl control && args.TryGetPosition(sender, out Point p))
|
||||
{
|
||||
await FocusManager.TryFocusAsync(control, FocusState.Keyboard);
|
||||
|
||||
if (control.DataContext is IMailItem clickedMailItemContext)
|
||||
{
|
||||
var targetItems = ViewModel.GetTargetMailItemViewModels(clickedMailItemContext);
|
||||
var availableActions = ViewModel.GetAvailableMailActions(targetItems);
|
||||
|
||||
if (!availableActions?.Any() ?? false) return;
|
||||
var t = targetItems.ElementAt(0);
|
||||
|
||||
ViewModel.ChangeCustomFocusedState(targetItems, true);
|
||||
|
||||
var clickedOperation = await GetMailOperationFromFlyoutAsync(availableActions, control, p.X, p.Y);
|
||||
|
||||
ViewModel.ChangeCustomFocusedState(targetItems, false);
|
||||
|
||||
if (clickedOperation == null) return;
|
||||
|
||||
var prepRequest = new MailOperationPreperationRequest(clickedOperation.Operation, targetItems.Select(a => a.MailCopy));
|
||||
|
||||
await ViewModel.ExecuteMailOperationAsync(prepRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<MailOperationMenuItem> GetMailOperationFromFlyoutAsync(IEnumerable<MailOperationMenuItem> availableActions,
|
||||
UIElement showAtElement,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
var source = new TaskCompletionSource<MailOperationMenuItem>();
|
||||
|
||||
var flyout = new MailOperationFlyout(availableActions, source);
|
||||
|
||||
flyout.ShowAt(showAtElement, new FlyoutShowOptions()
|
||||
{
|
||||
ShowMode = FlyoutShowMode.Standard,
|
||||
Position = new Point(x + 30, y - 20)
|
||||
});
|
||||
|
||||
return await source.Task;
|
||||
}
|
||||
|
||||
void IRecipient<ClearMailSelectionsRequested>.Receive(ClearMailSelectionsRequested message)
|
||||
{
|
||||
MailListView.ClearSelections(null, preserveThreadExpanding: true);
|
||||
}
|
||||
|
||||
void IRecipient<ActiveMailItemChangedEvent>.Receive(ActiveMailItemChangedEvent message)
|
||||
{
|
||||
// No active mail item. Go to empty page.
|
||||
if (message.SelectedMailItemViewModel == null)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Navigate to composing page.
|
||||
if (message.SelectedMailItemViewModel.IsDraft)
|
||||
{
|
||||
NavigationTransitionType composerPageTransition = NavigationTransitionType.None;
|
||||
|
||||
// Dispose active rendering if there is any and go to composer.
|
||||
if (IsRenderingPageActive())
|
||||
{
|
||||
// Prepare WebView2 animation from Rendering to Composing page.
|
||||
PrepareRenderingPageWebViewTransition();
|
||||
|
||||
// Dispose existing HTML content from rendering page webview.
|
||||
WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested());
|
||||
}
|
||||
else if (IsComposingPageActive())
|
||||
{
|
||||
// Composer is already active. Prepare composer WebView2 animation.
|
||||
PrepareComposePageWebViewTransition();
|
||||
}
|
||||
else
|
||||
composerPageTransition = NavigationTransitionType.DrillIn;
|
||||
|
||||
ViewModel.NavigationService.NavigateCompose(message.SelectedMailItemViewModel, composerPageTransition);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Find the MIME and go to rendering page.
|
||||
|
||||
if (message.SelectedMailItemViewModel == null) return;
|
||||
|
||||
if (IsComposingPageActive())
|
||||
{
|
||||
PrepareComposePageWebViewTransition();
|
||||
}
|
||||
|
||||
ViewModel.NavigationService.NavigateRendering(message.SelectedMailItemViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAdaptiveness();
|
||||
}
|
||||
|
||||
private bool IsRenderingPageActive() => RenderingFrame.Content is MailRenderingPage;
|
||||
private bool IsComposingPageActive() => RenderingFrame.Content is ComposePage;
|
||||
|
||||
private void PrepareComposePageWebViewTransition()
|
||||
{
|
||||
var webView = GetComposerPageWebView();
|
||||
|
||||
if (webView != null)
|
||||
{
|
||||
var animation = ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("WebViewConnectedAnimation", webView);
|
||||
animation.Configuration = new BasicConnectedAnimationConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareRenderingPageWebViewTransition()
|
||||
{
|
||||
var webView = GetRenderingPageWebView();
|
||||
|
||||
if (webView != null)
|
||||
{
|
||||
var animation = ConnectedAnimationService.GetForCurrentView().PrepareToAnimate("WebViewConnectedAnimation", webView);
|
||||
animation.Configuration = new BasicConnectedAnimationConfiguration();
|
||||
}
|
||||
}
|
||||
|
||||
#region Connected Animation Helpers
|
||||
|
||||
private WebView2 GetRenderingPageWebView()
|
||||
{
|
||||
if (RenderingFrame.Content is MailRenderingPage renderingPage)
|
||||
return renderingPage.GetWebView();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private WebView2 GetComposerPageWebView()
|
||||
{
|
||||
if (RenderingFrame.Content is ComposePage composePage)
|
||||
return composePage.GetWebView();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Receive(ActiveMailFolderChangedEvent message)
|
||||
{
|
||||
UpdateAdaptiveness();
|
||||
}
|
||||
|
||||
public async void Receive(SelectMailItemContainerEvent message)
|
||||
{
|
||||
if (message.SelectedMailViewModel == null) return;
|
||||
|
||||
await ViewModel.ExecuteUIThread(async () =>
|
||||
{
|
||||
MailListView.ClearSelections(message.SelectedMailViewModel, true);
|
||||
|
||||
int retriedSelectionCount = 0;
|
||||
trySelection:
|
||||
|
||||
bool isSelected = MailListView.SelectMailItemContainer(message.SelectedMailViewModel);
|
||||
|
||||
if (!isSelected)
|
||||
{
|
||||
for (int i = retriedSelectionCount; i < 5;)
|
||||
{
|
||||
// Retry with delay until the container is realized. Max 1 second.
|
||||
await Task.Delay(200);
|
||||
|
||||
retriedSelectionCount++;
|
||||
|
||||
goto trySelection;
|
||||
}
|
||||
}
|
||||
|
||||
// Automatically scroll to the selected item.
|
||||
// This is useful when creating draft.
|
||||
if (isSelected && message.ScrollToItem)
|
||||
{
|
||||
var collectionContainer = ViewModel.MailCollection.GetMailItemContainer(message.SelectedMailViewModel.UniqueId);
|
||||
|
||||
// Scroll to thread if available.
|
||||
if (collectionContainer.ThreadViewModel != null)
|
||||
{
|
||||
MailListView.ScrollIntoView(collectionContainer.ThreadViewModel, ScrollIntoViewAlignment.Default);
|
||||
}
|
||||
else if (collectionContainer.ItemViewModel != null)
|
||||
{
|
||||
MailListView.ScrollIntoView(collectionContainer.ItemViewModel, ScrollIntoViewAlignment.Default);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!isSelected)
|
||||
Analytics.TrackEvent("Mail Selection Failed");
|
||||
});
|
||||
}
|
||||
|
||||
public void Receive(ShellStateUpdated message)
|
||||
{
|
||||
UpdateAdaptiveness();
|
||||
}
|
||||
|
||||
private void SearchBoxFocused(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SearchBar.PlaceholderText = string.Empty;
|
||||
}
|
||||
|
||||
private void SearchBarUnfocused(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SearchBar.PlaceholderText = Translator.SearchBarPlaceholder;
|
||||
}
|
||||
|
||||
private void MailListPageLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// App might open with narrowed state.
|
||||
// VSM will not trigger in this case.
|
||||
// Set values to force updating adaptiveness.
|
||||
|
||||
var groups = VisualStateManager.GetVisualStateGroups(RootGrid);
|
||||
var adaptiveState = groups.FirstOrDefault(a => a.Name == AdaptivenessStatesKey);
|
||||
|
||||
if (adaptiveState == null) return;
|
||||
|
||||
// This should force UpdateAdaptiveness call.
|
||||
StatePersistanceService.IsReaderNarrowed = adaptiveState.CurrentState.Name == NarrowVisualStateKey;
|
||||
}
|
||||
|
||||
private void ProcessMailItemKeyboardAccelerator(UIElement sender, ProcessKeyboardAcceleratorEventArgs args)
|
||||
{
|
||||
if (args.Key == Windows.System.VirtualKey.Delete)
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
ViewModel?.MailOperationCommand?.Execute((int)MailOperation.SoftDelete);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thread header is mail info display control and it can be dragged spearately out of ListView.
|
||||
/// We need to prepare a drag package for it from the items inside.
|
||||
/// </summary>
|
||||
private void ThreadHeaderDragStart(UIElement sender, DragStartingEventArgs args)
|
||||
{
|
||||
if (sender is MailItemDisplayInformationControl control
|
||||
&& control.ConnectedExpander?.Content is WinoListView contentListView)
|
||||
{
|
||||
var allItems = contentListView.Items.Where(a => a is IMailItem);
|
||||
|
||||
// Highlight all items.
|
||||
allItems.Cast<MailItemViewModel>().ForEach(a => a.IsCustomFocused = true);
|
||||
|
||||
// Set native drag arg properties.
|
||||
args.AllowedOperations = Windows.ApplicationModel.DataTransfer.DataPackageOperation.Move;
|
||||
|
||||
var dragPackage = new MailDragPackage(allItems.Cast<IMailItem>());
|
||||
|
||||
args.Data.Properties.Add(nameof(MailDragPackage), dragPackage);
|
||||
args.DragUI.SetContentFromDataPackage();
|
||||
|
||||
control.ConnectedExpander.IsExpanded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void ThreadHeaderDragFinished(UIElement sender, DropCompletedEventArgs args)
|
||||
{
|
||||
if (sender is MailItemDisplayInformationControl control && control.ConnectedExpander != null && control.ConnectedExpander.Content is WinoListView contentListView)
|
||||
{
|
||||
contentListView.Items.Where(a => a is MailItemViewModel).Cast<MailItemViewModel>().ForEach(a => a.IsCustomFocused = false);
|
||||
}
|
||||
}
|
||||
|
||||
private async void LeftSwipeItemInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs args)
|
||||
{
|
||||
// Delete item for now.
|
||||
|
||||
var swipeControl = args.SwipeControl;
|
||||
|
||||
swipeControl.Close();
|
||||
|
||||
if (swipeControl.Tag is MailItemViewModel mailItemViewModel)
|
||||
{
|
||||
var package = new MailOperationPreperationRequest(MailOperation.SoftDelete, mailItemViewModel.MailCopy);
|
||||
await ViewModel.ExecuteMailOperationAsync(package);
|
||||
}
|
||||
else if (swipeControl.Tag is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
var package = new MailOperationPreperationRequest(MailOperation.SoftDelete, threadMailItemViewModel.GetMailCopies());
|
||||
await ViewModel.ExecuteMailOperationAsync(package);
|
||||
}
|
||||
}
|
||||
|
||||
private async void RightSwipeItemInvoked(Microsoft.UI.Xaml.Controls.SwipeItem sender, Microsoft.UI.Xaml.Controls.SwipeItemInvokedEventArgs args)
|
||||
{
|
||||
// Toggle status only for now.
|
||||
|
||||
var swipeControl = args.SwipeControl;
|
||||
|
||||
swipeControl.Close();
|
||||
|
||||
if (swipeControl.Tag is MailItemViewModel mailItemViewModel)
|
||||
{
|
||||
var operation = mailItemViewModel.IsRead ? MailOperation.MarkAsUnread : MailOperation.MarkAsRead;
|
||||
var package = new MailOperationPreperationRequest(operation, mailItemViewModel.MailCopy);
|
||||
|
||||
await ViewModel.ExecuteMailOperationAsync(package);
|
||||
}
|
||||
else if (swipeControl.Tag is ThreadMailItemViewModel threadMailItemViewModel)
|
||||
{
|
||||
bool isAllRead = threadMailItemViewModel.ThreadItems.All(a => a.IsRead);
|
||||
|
||||
var operation = isAllRead ? MailOperation.MarkAsUnread : MailOperation.MarkAsRead;
|
||||
var package = new MailOperationPreperationRequest(operation, threadMailItemViewModel.GetMailCopies());
|
||||
|
||||
await ViewModel.ExecuteMailOperationAsync(package);
|
||||
}
|
||||
}
|
||||
|
||||
private void PullToRefreshRequested(Microsoft.UI.Xaml.Controls.RefreshContainer sender, Microsoft.UI.Xaml.Controls.RefreshRequestedEventArgs args)
|
||||
{
|
||||
ViewModel.SyncFolderCommand?.Execute(null);
|
||||
}
|
||||
|
||||
private async void SearchBar_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
|
||||
{
|
||||
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput && string.IsNullOrWhiteSpace(sender.Text))
|
||||
{
|
||||
await ViewModel.PerformSearchAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(DisposeRenderingFrameRequested message)
|
||||
{
|
||||
ViewModel.NavigationService.Navigate(WinoPage.IdlePage, null, NavigationReferenceFrame.RenderingFrame, NavigationTransitionType.DrillIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,319 +0,0 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.AppCenter.Crashes;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Windows.System;
|
||||
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Messages.Mails;
|
||||
using Wino.Core.Messages.Shell;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class MailRenderingPage : MailRenderingPageAbstract,
|
||||
IRecipient<HtmlRenderingRequested>,
|
||||
IRecipient<CancelRenderingContentRequested>,
|
||||
IRecipient<NavigationPaneModeChanged>,
|
||||
IRecipient<ApplicationThemeChanged>,
|
||||
IRecipient<SaveAsPDFRequested>
|
||||
{
|
||||
private readonly IFontService _fontService = App.Current.Services.GetService<IFontService>();
|
||||
private readonly IDialogService _dialogService = App.Current.Services.GetService<IDialogService>();
|
||||
|
||||
private bool isRenderingInProgress = false;
|
||||
private TaskCompletionSource<bool> DOMLoadedTask = new TaskCompletionSource<bool>();
|
||||
|
||||
private bool isChromiumDisposed = false;
|
||||
|
||||
public WebView2 GetWebView() => Chromium;
|
||||
|
||||
public MailRenderingPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
|
||||
Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation,msWebView2CodeCache");
|
||||
}
|
||||
|
||||
public override async void OnEditorThemeChanged()
|
||||
{
|
||||
base.OnEditorThemeChanged();
|
||||
|
||||
await UpdateEditorThemeAsync();
|
||||
}
|
||||
|
||||
private async Task<string> InvokeScriptSafeAsync(string function)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await Chromium.ExecuteScriptAsync(function);
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public async Task<string> ExecuteScriptFunctionAsync(string functionName, params object[] parameters)
|
||||
{
|
||||
string script = functionName + "(";
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
script += JsonSerializer.Serialize(parameters[i]);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
script += ", ";
|
||||
}
|
||||
}
|
||||
script += ");";
|
||||
|
||||
return isChromiumDisposed ? string.Empty : await Chromium.ExecuteScriptAsync(script);
|
||||
}
|
||||
|
||||
private async Task RenderInternalAsync(string htmlBody)
|
||||
{
|
||||
isRenderingInProgress = true;
|
||||
|
||||
await DOMLoadedTask.Task;
|
||||
|
||||
await UpdateEditorThemeAsync();
|
||||
await UpdateReaderFontPropertiesAsync();
|
||||
|
||||
if (string.IsNullOrEmpty(htmlBody))
|
||||
{
|
||||
await ExecuteScriptFunctionAsync("RenderHTML", " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
await ExecuteScriptFunctionAsync("RenderHTML", htmlBody);
|
||||
}
|
||||
|
||||
isRenderingInProgress = false;
|
||||
}
|
||||
|
||||
private async void WindowRequested(CoreWebView2 sender, CoreWebView2NewWindowRequestedEventArgs args)
|
||||
{
|
||||
args.Handled = true;
|
||||
|
||||
try
|
||||
{
|
||||
await Launcher.LaunchUriAsync(new Uri(args.Uri));
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
private void DOMContentLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args) => DOMLoadedTask.TrySetResult(true);
|
||||
|
||||
async void IRecipient<HtmlRenderingRequested>.Receive(HtmlRenderingRequested message)
|
||||
{
|
||||
if (message == null || string.IsNullOrEmpty(message.HtmlBody))
|
||||
{
|
||||
await RenderInternalAsync(string.Empty);
|
||||
return;
|
||||
}
|
||||
|
||||
await Chromium.EnsureCoreWebView2Async();
|
||||
|
||||
await RenderInternalAsync(message.HtmlBody);
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedFrom(e);
|
||||
|
||||
WeakReferenceMessenger.Default.Send(new CancelRenderingContentRequested());
|
||||
|
||||
// Disposing the page.
|
||||
// Make sure the WebView2 is disposed properly.
|
||||
|
||||
DisposeWebView2();
|
||||
}
|
||||
|
||||
private void DisposeWebView2()
|
||||
{
|
||||
if (Chromium == null) return;
|
||||
|
||||
Chromium.CoreWebView2Initialized -= CoreWebViewInitialized;
|
||||
Chromium.NavigationStarting -= WebViewNavigationStarting;
|
||||
|
||||
if (Chromium.CoreWebView2 != null)
|
||||
{
|
||||
Chromium.CoreWebView2.DOMContentLoaded -= DOMContentLoaded;
|
||||
Chromium.CoreWebView2.NewWindowRequested -= WindowRequested;
|
||||
}
|
||||
|
||||
isChromiumDisposed = true;
|
||||
|
||||
Chromium.Close();
|
||||
GC.Collect();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation("WebViewConnectedAnimation");
|
||||
anim?.TryStart(Chromium);
|
||||
|
||||
Chromium.CoreWebView2Initialized -= CoreWebViewInitialized;
|
||||
Chromium.CoreWebView2Initialized += CoreWebViewInitialized;
|
||||
|
||||
_ = Chromium.EnsureCoreWebView2Async();
|
||||
|
||||
// We don't have shell initialized here. It's only standalone EML viewing.
|
||||
// Shift command bar from top to adjust the design.
|
||||
|
||||
if (ViewModel.StatePersistanceService.ShouldShiftMailRenderingDesign)
|
||||
RendererGridFrame.Margin = new Thickness(0, 24, 0, 0);
|
||||
else
|
||||
RendererGridFrame.Margin = new Thickness(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
private async void CoreWebViewInitialized(WebView2 sender, CoreWebView2InitializedEventArgs args)
|
||||
{
|
||||
if (Chromium.CoreWebView2 == null) return;
|
||||
|
||||
var editorBundlePath = (await ViewModel.NativeAppService.GetEditorBundlePathAsync()).Replace("editor.html", string.Empty);
|
||||
|
||||
Chromium.CoreWebView2.SetVirtualHostNameToFolderMapping("app.reader", editorBundlePath, CoreWebView2HostResourceAccessKind.Allow);
|
||||
|
||||
Chromium.CoreWebView2.DOMContentLoaded -= DOMContentLoaded;
|
||||
Chromium.CoreWebView2.DOMContentLoaded += DOMContentLoaded;
|
||||
|
||||
Chromium.CoreWebView2.NewWindowRequested -= WindowRequested;
|
||||
Chromium.CoreWebView2.NewWindowRequested += WindowRequested;
|
||||
|
||||
Chromium.Source = new Uri("https://app.reader/reader.html");
|
||||
}
|
||||
|
||||
|
||||
async void IRecipient<CancelRenderingContentRequested>.Receive(CancelRenderingContentRequested message)
|
||||
{
|
||||
await Chromium.EnsureCoreWebView2Async();
|
||||
|
||||
if (!isRenderingInProgress)
|
||||
{
|
||||
await RenderInternalAsync(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
void IRecipient<NavigationPaneModeChanged>.Receive(NavigationPaneModeChanged message)
|
||||
{
|
||||
if (message.NewMode == MenuPaneMode.Hidden)
|
||||
RendererBar.Margin = new Thickness(48, 6, 6, 6);
|
||||
else
|
||||
RendererBar.Margin = new Thickness(16, 6, 6, 6);
|
||||
}
|
||||
|
||||
private async void WebViewNavigationStarting(WebView2 sender, CoreWebView2NavigationStartingEventArgs args)
|
||||
{
|
||||
// This is our reader.
|
||||
if (args.Uri == "https://app.reader/reader.html")
|
||||
return;
|
||||
|
||||
// Cancel all external navigations since it's navigating to different address inside the WebView2.
|
||||
args.Cancel = !args.Uri.StartsWith("data:text/html");
|
||||
|
||||
// TODO: Check external link navigation setting is enabled.
|
||||
// Open all external urls in launcher.
|
||||
|
||||
if (args.Cancel && Uri.TryCreate(args.Uri, UriKind.Absolute, out Uri newUri))
|
||||
{
|
||||
await Launcher.LaunchUriAsync(newUri);
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachmentClicked(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
if (e.ClickedItem is MailAttachmentViewModel attachmentViewModel)
|
||||
{
|
||||
ViewModel.OpenAttachmentCommand.Execute(attachmentViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private void BarDynamicOverflowChanging(CommandBar sender, DynamicOverflowItemsChangingEventArgs args)
|
||||
{
|
||||
if (args.Action == CommandBarDynamicOverflowAction.AddingToOverflow || sender.SecondaryCommands.Any())
|
||||
sender.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Visible;
|
||||
else
|
||||
sender.OverflowButtonVisibility = CommandBarOverflowButtonVisibility.Collapsed;
|
||||
}
|
||||
|
||||
private async Task UpdateEditorThemeAsync()
|
||||
{
|
||||
await DOMLoadedTask.Task;
|
||||
|
||||
if (ViewModel.IsDarkWebviewRenderer)
|
||||
{
|
||||
Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Dark;
|
||||
|
||||
await InvokeScriptSafeAsync("SetDarkEditor();");
|
||||
}
|
||||
else
|
||||
{
|
||||
Chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Light;
|
||||
|
||||
await InvokeScriptSafeAsync("SetLightEditor();");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateReaderFontPropertiesAsync()
|
||||
{
|
||||
await ExecuteScriptFunctionAsync("ChangeFontSize", _fontService.GetCurrentReaderFontSize());
|
||||
|
||||
// Prepare font family name with fallback to sans-serif by default.
|
||||
var fontName = _fontService.GetCurrentReaderFont()?.FontFamilyName ?? "Arial";
|
||||
|
||||
// If font family name is not supported by the browser, fallback to sans-serif.
|
||||
fontName += ", sans-serif";
|
||||
|
||||
// var fontName = "Starborn";
|
||||
|
||||
await ExecuteScriptFunctionAsync("ChangeFontFamily", fontName);
|
||||
}
|
||||
|
||||
void IRecipient<ApplicationThemeChanged>.Receive(ApplicationThemeChanged message)
|
||||
{
|
||||
ViewModel.IsDarkWebviewRenderer = message.IsUnderlyingThemeDark;
|
||||
}
|
||||
|
||||
public async void Receive(SaveAsPDFRequested message)
|
||||
{
|
||||
try
|
||||
{
|
||||
bool isSaved = await Chromium.CoreWebView2.PrintToPdfAsync(message.FileSavePath, null);
|
||||
|
||||
if (isSaved)
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.Info_PDFSaveSuccessTitle,
|
||||
string.Format(Translator.Info_PDFSaveSuccessMessage, message.FileSavePath),
|
||||
InfoBarMessageType.Success);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dialogService.InfoBarMessage(Translator.Info_PDFSaveFailedTitle, ex.Message, InfoBarMessageType.Error);
|
||||
Crashes.TrackError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<abstract:NewAccountManagementPageAbstract
|
||||
x:Class="Wino.Views.NewAccountManagementPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModelData="using:Wino.Mail.ViewModels.Data"
|
||||
xmlns:winuiControls="using:Microsoft.UI.Xaml.Controls"
|
||||
Style="{StaticResource PageStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Border
|
||||
Style="{StaticResource PageRootBorderStyle}">
|
||||
<Grid
|
||||
MaxWidth="900"
|
||||
Padding="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
RowSpacing="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<winuiControls:BreadcrumbBar
|
||||
x:Name="Breadcrumb"
|
||||
ItemClicked="BreadItemClicked"
|
||||
ItemsSource="{x:Bind PageHistory, Mode=OneWay}">
|
||||
<winuiControls:BreadcrumbBar.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<winuiControls:BreadcrumbBarItem Margin="0,0,8,0">
|
||||
<winuiControls:BreadcrumbBarItem.ContentTemplate>
|
||||
<DataTemplate x:DataType="viewModelData:BreadcrumbNavigationItemViewModel">
|
||||
<TextBlock
|
||||
Margin="0,0,8,10"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsActive), Mode=OneWay}"
|
||||
Style="{StaticResource TitleTextBlockStyle}"
|
||||
Text="{Binding Title, Mode=OneWay}" />
|
||||
</DataTemplate>
|
||||
</winuiControls:BreadcrumbBarItem.ContentTemplate>
|
||||
</winuiControls:BreadcrumbBarItem>
|
||||
</DataTemplate>
|
||||
</winuiControls:BreadcrumbBar.ItemTemplate>
|
||||
</winuiControls:BreadcrumbBar>
|
||||
|
||||
<Frame x:Name="AccountPagesFrame" Grid.Row="1" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</abstract:NewAccountManagementPageAbstract>
|
||||
@@ -1,118 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using MoreLinq;
|
||||
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Messages.Navigation;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Messaging.Server;
|
||||
using Wino.Views.Abstract;
|
||||
using Wino.Views.Account;
|
||||
using Wino.Views.Settings;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class NewAccountManagementPage : NewAccountManagementPageAbstract,
|
||||
IRecipient<BackBreadcrumNavigationRequested>,
|
||||
IRecipient<BreadcrumbNavigationRequested>,
|
||||
IRecipient<MergedInboxRenamed>
|
||||
{
|
||||
public ObservableCollection<BreadcrumbNavigationItemViewModel> PageHistory { get; set; } = new ObservableCollection<BreadcrumbNavigationItemViewModel>();
|
||||
|
||||
public NewAccountManagementPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
var initialRequest = new BreadcrumbNavigationRequested("Manage Accounts", Core.Domain.Enums.WinoPage.AccountManagementPage);
|
||||
PageHistory.Add(new BreadcrumbNavigationItemViewModel(initialRequest, true));
|
||||
|
||||
AccountPagesFrame.Navigate(typeof(AccountManagementPage), null, new SuppressNavigationTransitionInfo());
|
||||
}
|
||||
|
||||
private Type GetPageNavigationType(WinoPage page)
|
||||
{
|
||||
return page switch
|
||||
{
|
||||
WinoPage.SignatureManagementPage => typeof(SignatureManagementPage),
|
||||
WinoPage.AccountDetailsPage => typeof(AccountDetailsPage),
|
||||
WinoPage.MergedAccountDetailsPage => typeof(MergedAccountDetailsPage),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message)
|
||||
{
|
||||
var pageType = GetPageNavigationType(message.PageType);
|
||||
|
||||
if (pageType == null) return;
|
||||
|
||||
AccountPagesFrame.Navigate(pageType, message.Parameter, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
|
||||
|
||||
PageHistory.ForEach(a => a.IsActive = false);
|
||||
|
||||
PageHistory.Add(new BreadcrumbNavigationItemViewModel(message, true));
|
||||
}
|
||||
|
||||
private void GoBackFrame()
|
||||
{
|
||||
if (AccountPagesFrame.CanGoBack)
|
||||
{
|
||||
PageHistory.RemoveAt(PageHistory.Count - 1);
|
||||
|
||||
AccountPagesFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
|
||||
}
|
||||
}
|
||||
|
||||
private void BreadItemClicked(Microsoft.UI.Xaml.Controls.BreadcrumbBar sender, Microsoft.UI.Xaml.Controls.BreadcrumbBarItemClickedEventArgs args)
|
||||
{
|
||||
var clickedPageHistory = PageHistory[args.Index];
|
||||
|
||||
while (PageHistory.FirstOrDefault(a => a.IsActive) != clickedPageHistory)
|
||||
{
|
||||
AccountPagesFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
|
||||
PageHistory.RemoveAt(PageHistory.Count - 1);
|
||||
PageHistory[PageHistory.Count - 1].IsActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Receive(BackBreadcrumNavigationRequested message)
|
||||
{
|
||||
GoBackFrame();
|
||||
}
|
||||
|
||||
public void Receive(AccountUpdatedMessage message)
|
||||
{
|
||||
// TODO: Find better way to retrieve page history from the stack for the account.
|
||||
var activePage = PageHistory.LastOrDefault();
|
||||
|
||||
if (activePage == null) return;
|
||||
|
||||
activePage.Title = message.Account.Name;
|
||||
}
|
||||
|
||||
public void Receive(MergedInboxRenamed message)
|
||||
{
|
||||
// TODO: Find better way to retrieve page history from the stack for the merged account.
|
||||
var activePage = PageHistory.LastOrDefault();
|
||||
|
||||
if (activePage == null) return;
|
||||
|
||||
activePage.Title = message.NewName;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class AboutPage : AboutPageAbstract
|
||||
{
|
||||
public AboutPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,19 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class LanguageTimePage : LanguageTimePageAbstract
|
||||
{
|
||||
public LanguageTimePage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public override void OnLanguageChanged()
|
||||
{
|
||||
base.OnLanguageChanged();
|
||||
|
||||
Bindings.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class MessageListPage : MessageListPageAbstract
|
||||
{
|
||||
public MessageListPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class PersonalizationPage : PersonalizationPageAbstract
|
||||
{
|
||||
public PersonalizationPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class ReadingPanePage : ReadingPanePageAbstract
|
||||
{
|
||||
public ReadingPanePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class SettingOptionsPage : SettingOptionsPageAbstract
|
||||
{
|
||||
public SettingOptionsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,12 +0,0 @@
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views.Settings
|
||||
{
|
||||
public sealed partial class SignatureManagementPage : SignatureManagementPageAbstract
|
||||
{
|
||||
public SignatureManagementPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
<abstract:SettingsPageAbstract
|
||||
x:Class="Wino.Views.SettingsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:helpers="using:Wino.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModelData="using:Wino.Mail.ViewModels.Data"
|
||||
xmlns:winuiControls="using:Microsoft.UI.Xaml.Controls"
|
||||
Style="{StaticResource PageStyle}"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Border Style="{StaticResource PageRootBorderStyle}">
|
||||
<Grid
|
||||
MaxWidth="900"
|
||||
Padding="20"
|
||||
HorizontalAlignment="Stretch"
|
||||
RowSpacing="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<winuiControls:BreadcrumbBar
|
||||
x:Name="Breadcrumb"
|
||||
ItemClicked="BreadItemClicked"
|
||||
ItemsSource="{x:Bind PageHistory, Mode=OneWay}">
|
||||
<winuiControls:BreadcrumbBar.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<winuiControls:BreadcrumbBarItem Margin="0,0,8,0">
|
||||
<winuiControls:BreadcrumbBarItem.ContentTemplate>
|
||||
<DataTemplate x:DataType="viewModelData:BreadcrumbNavigationItemViewModel">
|
||||
<TextBlock
|
||||
Margin="0,0,8,10"
|
||||
FontWeight="{x:Bind helpers:XamlHelpers.GetFontWeightBySyncState(IsActive), Mode=OneWay}"
|
||||
Style="{StaticResource TitleTextBlockStyle}"
|
||||
Text="{Binding Title}" />
|
||||
</DataTemplate>
|
||||
</winuiControls:BreadcrumbBarItem.ContentTemplate>
|
||||
</winuiControls:BreadcrumbBarItem>
|
||||
</DataTemplate>
|
||||
</winuiControls:BreadcrumbBar.ItemTemplate>
|
||||
</winuiControls:BreadcrumbBar>
|
||||
|
||||
<Frame x:Name="SettingsFrame" Grid.Row="1" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</abstract:SettingsPageAbstract>
|
||||
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using MoreLinq;
|
||||
|
||||
using Wino.Core.Domain;
|
||||
using Wino.Core.Domain.Enums;
|
||||
using Wino.Core.Messages.Navigation;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Views.Abstract;
|
||||
using Wino.Views.Settings;
|
||||
|
||||
#if NET8_0
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
#else
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
#endif
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class SettingsPage : SettingsPageAbstract, IRecipient<BreadcrumbNavigationRequested>
|
||||
{
|
||||
public ObservableCollection<BreadcrumbNavigationItemViewModel> PageHistory { get; set; } = new ObservableCollection<BreadcrumbNavigationItemViewModel>();
|
||||
|
||||
public SettingsPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
SettingsFrame.Navigate(typeof(SettingOptionsPage), null, new SuppressNavigationTransitionInfo());
|
||||
|
||||
var initialRequest = new BreadcrumbNavigationRequested(Translator.MenuSettings, WinoPage.SettingOptionsPage);
|
||||
PageHistory.Add(new BreadcrumbNavigationItemViewModel(initialRequest, true));
|
||||
}
|
||||
|
||||
public override void OnLanguageChanged()
|
||||
{
|
||||
base.OnLanguageChanged();
|
||||
|
||||
// Update Settings header in breadcrumb.
|
||||
|
||||
var settingsHeader = PageHistory.FirstOrDefault();
|
||||
|
||||
if (settingsHeader == null) return;
|
||||
|
||||
settingsHeader.Title = Translator.MenuSettings;
|
||||
}
|
||||
|
||||
private Type GetNavigationPageType(WinoPage page) => page switch
|
||||
{
|
||||
WinoPage.AboutPage => typeof(AboutPage),
|
||||
WinoPage.PersonalizationPage => typeof(PersonalizationPage),
|
||||
WinoPage.MessageListPage => typeof(MessageListPage),
|
||||
WinoPage.ReadingPanePage => typeof(ReadingPanePage),
|
||||
WinoPage.LanguageTimePage => typeof(LanguageTimePage),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
void IRecipient<BreadcrumbNavigationRequested>.Receive(BreadcrumbNavigationRequested message)
|
||||
{
|
||||
var pageType = GetNavigationPageType(message.PageType);
|
||||
|
||||
if (pageType == null) return;
|
||||
|
||||
SettingsFrame.Navigate(pageType, message.Parameter, new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
|
||||
|
||||
PageHistory.ForEach(a => a.IsActive = false);
|
||||
|
||||
PageHistory.Add(new BreadcrumbNavigationItemViewModel(message, true));
|
||||
}
|
||||
|
||||
private void BreadItemClicked(Microsoft.UI.Xaml.Controls.BreadcrumbBar sender, Microsoft.UI.Xaml.Controls.BreadcrumbBarItemClickedEventArgs args)
|
||||
{
|
||||
var clickedPageHistory = PageHistory[args.Index];
|
||||
var activeIndex = PageHistory.IndexOf(PageHistory.FirstOrDefault(a => a.IsActive));
|
||||
|
||||
while (PageHistory.FirstOrDefault(a => a.IsActive) != clickedPageHistory)
|
||||
{
|
||||
SettingsFrame.GoBack(new SlideNavigationTransitionInfo() { Effect = SlideNavigationTransitionEffect.FromRight });
|
||||
PageHistory.RemoveAt(PageHistory.Count - 1);
|
||||
PageHistory[PageHistory.Count - 1].IsActive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<abstract:WelcomePageAbstract
|
||||
x:Class="Wino.Views.WelcomePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:abstract="using:Wino.Views.Abstract"
|
||||
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Wino.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Border
|
||||
Margin="0,0,7,7"
|
||||
Background="{ThemeResource WinoContentZoneBackgroud}"
|
||||
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="7">
|
||||
<Grid Padding="24">
|
||||
<ScrollViewer>
|
||||
<controls:MarkdownTextBlock
|
||||
x:Name="MarkdownControl"
|
||||
Background="Transparent"
|
||||
CharacterSpacing="12"
|
||||
FontSize="16"
|
||||
Header1FontSize="30"
|
||||
Header2FontSize="22"
|
||||
ImageStretch="UniformToFill"
|
||||
LinkClicked="HyperlinkClicked"
|
||||
ListBulletSpacing="10"
|
||||
Text="{x:Bind ViewModel.CurrentVersionNotes, Mode=OneWay}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
</abstract:WelcomePageAbstract>
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using Windows.System;
|
||||
using Wino.Views.Abstract;
|
||||
|
||||
namespace Wino.Views
|
||||
{
|
||||
public sealed partial class WelcomePage : WelcomePageAbstract
|
||||
{
|
||||
public WelcomePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void HyperlinkClicked(object sender, Microsoft.Toolkit.Uwp.UI.Controls.LinkClickedEventArgs e)
|
||||
{
|
||||
await Launcher.LaunchUriAsync(new System.Uri(e.Link));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user