diff --git a/Directory.Packages.props b/Directory.Packages.props
index 15bf141d..7224d5b6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,64 +1,65 @@
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wino.Core.Domain/Models/DomainModelsJsonContext.cs b/Wino.Core.Domain/Models/DomainModelsJsonContext.cs
index 39ce4827..7e9c5fa8 100644
--- a/Wino.Core.Domain/Models/DomainModelsJsonContext.cs
+++ b/Wino.Core.Domain/Models/DomainModelsJsonContext.cs
@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
using Wino.Core.Domain.Models.AutoDiscovery;
using Wino.Core.Domain.Models.Personalization;
using Wino.Core.Domain.Models.Reader;
@@ -8,4 +9,5 @@ namespace Wino.Core.Domain.Models;
[JsonSerializable(typeof(AutoDiscoverySettings))]
[JsonSerializable(typeof(CustomThemeMetadata))]
[JsonSerializable(typeof(WebViewMessage))]
+[JsonSerializable(typeof(List))]
public partial class DomainModelsJsonContext: JsonSerializerContext;
diff --git a/Wino.Core.UWP/Extensions/WebViewExtensions.cs b/Wino.Core.UWP/Extensions/WebViewExtensions.cs
index c411351e..1edbe6fb 100644
--- a/Wino.Core.UWP/Extensions/WebViewExtensions.cs
+++ b/Wino.Core.UWP/Extensions/WebViewExtensions.cs
@@ -29,4 +29,17 @@ public static async Task ExecuteScriptFunctionSafeAsync(this Microsoft.U
return string.Empty;
}
+
+ public static async Task ExecuteScriptSafeAsync(this Microsoft.UI.Xaml.Controls.WebView2 Chromium, string script)
+ {
+ if (Chromium == null) return string.Empty;
+
+ try
+ {
+ return await Chromium.ExecuteScriptAsync(script);
+ }
+ catch { }
+
+ return string.Empty;
+ }
}
diff --git a/Wino.Mail/App.xaml b/Wino.Mail/App.xaml
index 965f4756..d044da41 100644
--- a/Wino.Mail/App.xaml
+++ b/Wino.Mail/App.xaml
@@ -15,6 +15,7 @@
+
diff --git a/Wino.Mail/Controls/WebViewEditorControl.cs b/Wino.Mail/Controls/WebViewEditorControl.cs
new file mode 100644
index 00000000..df12414f
--- /dev/null
+++ b/Wino.Mail/Controls/WebViewEditorControl.cs
@@ -0,0 +1,362 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Text.Json;
+using System.Threading.Tasks;
+using CommunityToolkit.WinUI;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.Web.WebView2.Core;
+using Windows.UI.ViewManagement.Core;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Markup;
+using Windows.UI.Xaml.Media;
+using Wino.Core.Domain;
+using Wino.Core.Domain.Interfaces;
+using Wino.Core.Domain.Models;
+using Wino.Core.Domain.Models.Reader;
+using Wino.Core.UWP.Extensions;
+
+namespace Wino.Mail.Controls;
+public sealed partial class WebViewEditorControl : Control, IDisposable
+{
+ private readonly INativeAppService _nativeAppService = App.Current.Services.GetService();
+ private readonly IFontService _fontService = App.Current.Services.GetService();
+ private readonly IPreferencesService _preferencesService = App.Current.Services.GetService();
+ private readonly IUnderlyingThemeService _underlyingThemeService = App.Current.Services.GetService();
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorDarkMode { get; set; }
+ async partial void OnIsEditorDarkModeChanged(bool newValue)
+ {
+ await UpdateEditorThemeAsync();
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorBold { get; set; }
+ private bool _isEditorBoldInternal;
+ async partial void OnIsEditorBoldChanged(bool newValue)
+ {
+ if (newValue != _isEditorBoldInternal)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("bold", BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorItalic { get; set; }
+ private bool _isEditorItalicInternal;
+ async partial void OnIsEditorItalicChanged(bool newValue)
+ {
+ if (newValue != _isEditorItalicInternal)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("italic", BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorUnderline { get; set; }
+ private bool _isEditorUnderlineInternal;
+ async partial void OnIsEditorUnderlineChanged(bool newValue)
+ {
+ if (newValue != _isEditorUnderlineInternal)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("underline", BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorStrikethrough { get; set; }
+ private bool _isEditorStrikethroughInternal;
+ async partial void OnIsEditorStrikethroughChanged(bool newValue)
+ {
+ if (newValue != _isEditorStrikethroughInternal)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("strikethrough", BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorOl { get; set; }
+ private bool _isEditorOlInternal;
+ async partial void OnIsEditorOlChanged(bool newValue)
+ {
+ if (newValue != _isEditorOlInternal)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("insertorderedlist", BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorUl { get; set; }
+ private bool _isEditorUlInternal;
+ async partial void OnIsEditorUlChanged(bool newValue)
+ {
+ if (newValue != _isEditorUlInternal)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("insertunorderedlist", BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorIndentEnabled { get; private set; }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorOutdentEnabled { get; private set; }
+
+ [GeneratedDependencyProperty]
+ public partial int EditorAlignmentSelectedIndex { get; set; }
+ private int _editorAlignmentSelectedIndexInternal;
+ async partial void OnEditorAlignmentSelectedIndexChanged(int newValue)
+ {
+ if (newValue != _editorAlignmentSelectedIndexInternal)
+ {
+ var alignmentAction = newValue switch
+ {
+ 0 => "justifyleft",
+ 1 => "justifycenter",
+ 2 => "justifyright",
+ 3 => "justifyfull",
+ _ => throw new ArgumentOutOfRangeException(nameof(newValue))
+ };
+
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize(alignmentAction, BasicTypesJsonContext.Default.String));
+ }
+ }
+
+ [GeneratedDependencyProperty]
+ public partial bool IsEditorWebViewEditor { get; set; }
+
+ async partial void OnIsEditorWebViewEditorChanged(bool newValue)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("toggleToolbar", JsonSerializer.Serialize(newValue, BasicTypesJsonContext.Default.Boolean));
+ }
+
+ private const string PART_WebView = "WebView";
+ private WebView2 _chromium;
+ private bool _disposedValue;
+ private readonly TaskCompletionSource _domLoadedTask = new();
+
+ public WebViewEditorControl()
+ {
+ this.DefaultStyleKey = typeof(WebViewEditorControl);
+
+ IsEditorIndentEnabled = true;
+
+ IsEditorDarkMode = _underlyingThemeService.IsUnderlyingThemeDark();
+ }
+
+ protected override async void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+
+ _chromium = GetTemplateChild(PART_WebView) as WebView2;
+
+ await InitializeComponent();
+ }
+
+ private async Task InitializeComponent()
+ {
+ Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
+ Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation");
+ _chromium.CoreWebView2Initialized += ChromiumInitialized;
+
+ await _chromium.EnsureCoreWebView2Async();
+ }
+
+ public async void EditorIndentAsync()
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("indent", BasicTypesJsonContext.Default.String));
+ }
+
+ public async void EditorOutdentAsync()
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("editor.execCommand", JsonSerializer.Serialize("outdent", BasicTypesJsonContext.Default.String));
+ }
+
+ public void ToggleEditorTheme()
+ {
+ IsEditorDarkMode = !IsEditorDarkMode;
+ }
+
+ public async Task GetHtmlBodyAsync()
+ {
+ var editorContent = await _chromium.ExecuteScriptFunctionSafeAsync("GetHTMLContent");
+
+ return JsonSerializer.Deserialize(editorContent, BasicTypesJsonContext.Default.String);
+ }
+
+ public async void ShowImagePicker()
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("imageInput.click");
+ }
+
+ public async Task InsertImagesAsync(List images)
+ {
+ await _chromium.ExecuteScriptFunctionSafeAsync("insertImages", JsonSerializer.Serialize(images, DomainModelsJsonContext.Default.ListImageInfo));
+ }
+
+ public async void ShowEmojiPicker()
+ {
+ CoreInputView.GetForCurrentView().TryShow(CoreInputViewKind.Emoji);
+
+ await FocusEditorAsync(focusControlAsWell: true);
+ }
+
+ public WebView2 GetUnderlyingWebView() => _chromium;
+
+ public async Task RenderHtmlAsync(string htmlBody)
+ {
+ await _domLoadedTask.Task;
+
+ await UpdateEditorThemeAsync();
+ await InitializeEditorAsync();
+
+ await _chromium.ExecuteScriptFunctionAsync("RenderHTML", parameters: JsonSerializer.Serialize(string.IsNullOrEmpty(htmlBody) ? " " : htmlBody, BasicTypesJsonContext.Default.String));
+ }
+
+ private async Task InitializeEditorAsync()
+ {
+ var fonts = _fontService.GetFonts();
+ var composerFont = _preferencesService.ComposerFont;
+ int composerFontSize = _preferencesService.ComposerFontSize;
+ var readerFont = _preferencesService.ReaderFont;
+ int readerFontSize = _preferencesService.ReaderFontSize;
+ return await _chromium.ExecuteScriptFunctionAsync("initializeJodit", false,
+ JsonSerializer.Serialize(fonts, BasicTypesJsonContext.Default.ListString),
+ JsonSerializer.Serialize(composerFont, BasicTypesJsonContext.Default.String),
+ JsonSerializer.Serialize(composerFontSize, BasicTypesJsonContext.Default.Int32),
+ JsonSerializer.Serialize(readerFont, BasicTypesJsonContext.Default.String),
+ JsonSerializer.Serialize(readerFontSize, BasicTypesJsonContext.Default.Int32));
+ }
+
+ private async void ChromiumInitialized(WebView2 sender, CoreWebView2InitializedEventArgs args)
+ {
+ var editorBundlePath = (await _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.WebMessageReceived += ScriptMessageReceived;
+ }
+
+ public async Task UpdateEditorThemeAsync()
+ {
+ await _domLoadedTask.Task;
+
+ if (IsEditorDarkMode)
+ {
+ _chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Dark;
+ await _chromium.ExecuteScriptFunctionSafeAsync("SetDarkEditor");
+ }
+ else
+ {
+ _chromium.CoreWebView2.Profile.PreferredColorScheme = CoreWebView2PreferredColorScheme.Light;
+ await _chromium.ExecuteScriptFunctionSafeAsync("SetLightEditor");
+ }
+ }
+
+ ///
+ /// Places the cursor in the composer.
+ ///
+ /// Whether control itself should be focused as well or not.
+ public async Task FocusEditorAsync(bool focusControlAsWell)
+ {
+ await _chromium.ExecuteScriptSafeAsync("editor.selection.setCursorIn(editor.editor.firstChild, true)");
+
+ if (focusControlAsWell)
+ {
+ _chromium.Focus(FocusState.Keyboard);
+ _chromium.Focus(FocusState.Programmatic);
+ }
+ }
+
+ private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
+ {
+ var change = JsonSerializer.Deserialize(args.WebMessageAsJson, DomainModelsJsonContext.Default.WebViewMessage);
+
+ if (change.Type == "bold")
+ {
+ _isEditorBoldInternal = change.Value == "true";
+ IsEditorBold = _isEditorBoldInternal;
+ }
+ else if (change.Type == "italic")
+ {
+ _isEditorItalicInternal = change.Value == "true";
+ IsEditorItalic = _isEditorItalicInternal;
+ }
+ else if (change.Type == "underline")
+ {
+ _isEditorUnderlineInternal = change.Value == "true";
+ IsEditorUnderline = _isEditorUnderlineInternal;
+ }
+ else if (change.Type == "strikethrough")
+ {
+ _isEditorStrikethroughInternal = change.Value == "true";
+ IsEditorStrikethrough = _isEditorStrikethroughInternal;
+ }
+ else if (change.Type == "ol")
+ {
+ _isEditorOlInternal = change.Value == "true";
+ IsEditorOl = _isEditorOlInternal;
+ }
+ else if (change.Type == "ul")
+ {
+ _isEditorUlInternal = change.Value == "true";
+ IsEditorUl = _isEditorUlInternal;
+ }
+ else if (change.Type == "indent")
+ {
+ IsEditorIndentEnabled = change.Value != "disabled";
+ }
+ else if (change.Type == "outdent")
+ {
+ IsEditorOutdentEnabled = change.Value != "disabled";
+ }
+ 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
+ };
+ _editorAlignmentSelectedIndexInternal = parsedValue;
+ EditorAlignmentSelectedIndex = _editorAlignmentSelectedIndexInternal;
+ }
+ }
+
+ private void DomLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args) => _domLoadedTask.TrySetResult(true);
+
+ private void Dispose(bool disposing)
+ {
+ if (!_disposedValue)
+ {
+ if (disposing && _chromium != null)
+ {
+ _chromium.CoreWebView2Initialized -= ChromiumInitialized;
+
+ if (_chromium.CoreWebView2 != null)
+ {
+ _chromium.CoreWebView2.DOMContentLoaded -= DomLoaded;
+ _chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived;
+ }
+
+ _chromium.Close();
+ }
+ _disposedValue = true;
+ }
+ }
+
+ public void Dispose()
+ {
+ // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
+ Dispose(disposing: true);
+ GC.SuppressFinalize(this);
+ }
+}
diff --git a/Wino.Mail/Dialogs/SignatureEditorDialog.xaml b/Wino.Mail/Dialogs/SignatureEditorDialog.xaml
index a10a2149..1e0893fa 100644
--- a/Wino.Mail/Dialogs/SignatureEditorDialog.xaml
+++ b/Wino.Mail/Dialogs/SignatureEditorDialog.xaml
@@ -5,6 +5,7 @@
xmlns:accounts="using:Wino.Core.Domain.Models.Accounts"
xmlns:controls="using:Wino.Controls"
xmlns:controls1="using:CommunityToolkit.WinUI.Controls"
+ xmlns:controls2="using:Wino.Mail.Controls"
xmlns:coreControls="using:Wino.Core.UWP.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:domain="using:Wino.Core.Domain"
@@ -55,10 +56,10 @@
IsOpen="False">
+ Visibility="{x:Bind WebViewEditor.IsEditorDarkMode, Mode=OneWay}">
@@ -66,10 +67,10 @@
+ Visibility="{x:Bind WebViewEditor.IsEditorDarkMode, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
@@ -78,9 +79,8 @@
@@ -88,9 +88,8 @@
@@ -98,9 +97,8 @@
@@ -108,9 +106,8 @@
@@ -119,9 +116,8 @@
@@ -129,9 +125,8 @@
@@ -142,9 +137,9 @@
@@ -152,9 +147,9 @@
@@ -164,10 +159,9 @@
+ SelectedIndex="{x:Bind WebViewEditor.EditorAlignmentSelectedIndex, Mode=TwoWay}">
@@ -207,9 +201,8 @@
@@ -225,9 +218,8 @@
@@ -236,9 +228,8 @@
@@ -252,11 +243,7 @@
BorderBrush="{StaticResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="3">
-
-
-
-
-
+
diff --git a/Wino.Mail/Dialogs/SignatureEditorDialog.xaml.cs b/Wino.Mail/Dialogs/SignatureEditorDialog.xaml.cs
index f4ae2ad9..29400f48 100644
--- a/Wino.Mail/Dialogs/SignatureEditorDialog.xaml.cs
+++ b/Wino.Mail/Dialogs/SignatureEditorDialog.xaml.cs
@@ -1,48 +1,20 @@
using System;
-using System.Text.Json;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Web.WebView2.Core;
-using Windows.UI.ViewManagement.Core;
-using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Wino.Core.Domain;
using Wino.Core.Domain.Entities.Mail;
-using Wino.Core.Domain.Interfaces;
-using Wino.Core.Domain.Models;
-using Wino.Core.Domain.Models.Reader;
-using Wino.Core.UWP.Extensions;
-using Wino.Views.Settings;
namespace Wino.Dialogs;
public sealed partial class SignatureEditorDialog : ContentDialog
{
- private Func> _getHTMLBodyFunction;
- private readonly TaskCompletionSource _domLoadedTask = new TaskCompletionSource();
-
- private readonly INativeAppService _nativeAppService = App.Current.Services.GetService();
- private readonly IFontService _fontService = App.Current.Services.GetService();
- private readonly IPreferencesService _preferencesService = App.Current.Services.GetService();
-
public AccountSignature Result;
- public bool IsComposerDarkMode
- {
- get { return (bool)GetValue(IsComposerDarkModeProperty); }
- set { SetValue(IsComposerDarkModeProperty, value); }
- }
-
- public static readonly DependencyProperty IsComposerDarkModeProperty = DependencyProperty.Register(nameof(IsComposerDarkMode), typeof(bool), typeof(SignatureManagementPage), new PropertyMetadata(false, OnIsComposerDarkModeChanged));
-
public SignatureEditorDialog()
{
InitializeComponent();
SignatureNameTextBox.Header = Translator.SignatureEditorDialog_SignatureName_TitleNew;
- Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
- Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation,FontAccess");
// TODO: Should be added additional logic to enable/disable primary button when webview content changed.
IsPrimaryButtonEnabled = true;
@@ -62,8 +34,6 @@ public SignatureEditorDialog(AccountSignature signatureModel)
MailAccountId = signatureModel.MailAccountId,
HtmlBody = signatureModel.HtmlBody
};
- Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
- Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation");
// TODO: Should be added additional logic to enable/disable primary button when webview content changed.
IsPrimaryButtonEnabled = true;
@@ -71,39 +41,17 @@ public SignatureEditorDialog(AccountSignature signatureModel)
private async void SignatureDialogOpened(ContentDialog sender, ContentDialogOpenedEventArgs args)
{
- Chromium.CoreWebView2Initialized -= ChromiumInitialized;
- Chromium.CoreWebView2Initialized += ChromiumInitialized;
-
- await Chromium.EnsureCoreWebView2Async();
-
- _getHTMLBodyFunction = new Func>(async () =>
- {
- var editorContent = await Chromium.ExecuteScriptFunctionSafeAsync("GetHTMLContent");
-
- return JsonSerializer.Deserialize(editorContent, BasicTypesJsonContext.Default.String);
- });
-
- var underlyingThemeService = App.Current.Services.GetService();
-
- IsComposerDarkMode = underlyingThemeService.IsUnderlyingThemeDark();
-
- await RenderInternalAsync(Result?.HtmlBody ?? string.Empty);
+ await WebViewEditor.RenderHtmlAsync(Result?.HtmlBody ?? string.Empty);
}
private void DialogClosed(ContentDialog sender, ContentDialogClosedEventArgs args)
{
- Chromium.CoreWebView2Initialized -= ChromiumInitialized;
-
- if (Chromium.CoreWebView2 != null)
- {
- Chromium.CoreWebView2.DOMContentLoaded -= DOMLoaded;
- Chromium.CoreWebView2.WebMessageReceived -= ScriptMessageReceived;
- }
+ WebViewEditor.Dispose();
}
private async void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
- var newSignature = Regex.Unescape(await _getHTMLBodyFunction());
+ var newSignature = Regex.Unescape(await WebViewEditor.GetHtmlBodyAsync());
if (Result == null)
{
@@ -128,249 +76,5 @@ private void CancelClicked(ContentDialog sender, ContentDialogButtonClickEventAr
Hide();
}
- 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 Task 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();
- }
-
- private async Task TryGetSelectedTextAsync()
- {
- try
- {
- return await Chromium.ExecuteScriptAsync("getSelectedText();");
- }
- catch { }
-
- return string.Empty;
- }
-
- private async void WebViewToggleButtonClicked(object sender, RoutedEventArgs e)
- {
- var enable = WebviewToolBarButton.IsChecked == true ? "true" : "false";
- await InvokeScriptSafeAsync($"toggleToolbar('{enable}');");
- }
-
- private 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();
- await InitializeEditorAsync();
-
- if (string.IsNullOrEmpty(htmlBody))
- {
- await Chromium.ExecuteScriptFunctionAsync("RenderHTML", parameters: JsonSerializer.Serialize(" ", BasicTypesJsonContext.Default.String));
- }
- else
- {
- await Chromium.ExecuteScriptFunctionAsync("RenderHTML", parameters: JsonSerializer.Serialize(htmlBody, BasicTypesJsonContext.Default.String));
-
- await FocusEditorAsync();
- }
- }
-
- private async Task InitializeEditorAsync()
- {
- var fonts = _fontService.GetFonts();
- var composerFont = _preferencesService.ComposerFont;
- int composerFontSize = _preferencesService.ComposerFontSize;
- var readerFont = _preferencesService.ReaderFont;
- int readerFontSize = _preferencesService.ReaderFontSize;
- return await Chromium.ExecuteScriptFunctionAsync("initializeJodit", false,
- JsonSerializer.Serialize(fonts, BasicTypesJsonContext.Default.ListString),
- JsonSerializer.Serialize(composerFont, BasicTypesJsonContext.Default.String),
- JsonSerializer.Serialize(composerFontSize, BasicTypesJsonContext.Default.Int32),
- JsonSerializer.Serialize(readerFont, BasicTypesJsonContext.Default.String),
- JsonSerializer.Serialize(readerFontSize, BasicTypesJsonContext.Default.Int32));
- }
-
- private async void ChromiumInitialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args)
- {
- var editorBundlePath = (await _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 static async void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
- {
- if (obj is SignatureEditorDialog dialog)
- {
- await dialog.UpdateEditorThemeAsync();
- }
- }
-
- private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
- {
- var change = JsonSerializer.Deserialize(args.WebMessageAsJson, DomainModelsJsonContext.Default.WebViewMessage);
-
- 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);
-
private void SignatureNameTextBoxTextChanged(object sender, TextChangedEventArgs e) => IsPrimaryButtonEnabled = !string.IsNullOrWhiteSpace(SignatureNameTextBox.Text);
-
- private void InvertComposerThemeClicked(object sender, RoutedEventArgs e) => IsComposerDarkMode = !IsComposerDarkMode;
}
diff --git a/Wino.Mail/JS/editor.js b/Wino.Mail/JS/editor.js
index a9fb22e0..f2e55a7a 100644
--- a/Wino.Mail/JS/editor.js
+++ b/Wino.Mail/JS/editor.js
@@ -115,7 +115,7 @@ function SetDarkEditor() {
function toggleToolbar(enable) {
const toolbar = document.querySelector('.jodit-toolbar__box');
- if (enable == 'true') {
+ if (enable) {
toolbar.style.display = 'flex';
}
else {
diff --git a/Wino.Mail/Styles/WebViewEditorControl.xaml b/Wino.Mail/Styles/WebViewEditorControl.xaml
new file mode 100644
index 00000000..f76cdc54
--- /dev/null
+++ b/Wino.Mail/Styles/WebViewEditorControl.xaml
@@ -0,0 +1,21 @@
+
+
+
+
diff --git a/Wino.Mail/Views/ComposePage.xaml b/Wino.Mail/Views/ComposePage.xaml
index 084f54ab..43a419e8 100644
--- a/Wino.Mail/Views/ComposePage.xaml
+++ b/Wino.Mail/Views/ComposePage.xaml
@@ -4,6 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:abstract="using:Wino.Views.Abstract"
xmlns:controls="using:Wino.Controls"
+ xmlns:controls1="using:Wino.Mail.Controls"
xmlns:coreControls="using:Wino.Core.UWP.Controls"
xmlns:customcontrols="using:Wino.Core.UWP.Controls.CustomControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -189,20 +190,20 @@
IsDynamicOverflowEnabled="True"
OverflowButtonAlignment="Left">
+ Visibility="{x:Bind WebViewEditor.IsEditorDarkMode, Mode=OneWay}">
+ Visibility="{x:Bind WebViewEditor.IsEditorDarkMode, Mode=OneWay, Converter={StaticResource ReverseBooleanToVisibilityConverter}}">
@@ -222,34 +223,22 @@
-
+
-
+
-
+
-
+
@@ -257,19 +246,13 @@
-
+
-
+
@@ -278,8 +261,8 @@
@@ -289,8 +272,8 @@
@@ -305,7 +288,7 @@
VerticalAlignment="Center"
Background="Transparent"
BorderBrush="Transparent"
- SelectionChanged="AlignmentChanged">
+ SelectedIndex="{x:Bind WebViewEditor.EditorAlignmentSelectedIndex, Mode=TwoWay}">
@@ -347,8 +330,7 @@
@@ -368,19 +350,13 @@
-
+
-
+
@@ -630,9 +606,7 @@
BorderThickness="1"
CornerRadius="7">
-
-
-
+
,
IRecipient
{
- 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;
+ public WebView2 GetWebView() => WebViewEditor.GetUnderlyingWebView();
- private readonly TaskCompletionSource _domLoadedTask = new TaskCompletionSource();
-
- private readonly List _disposables = new List();
+ private readonly List _disposables = [];
private readonly SystemNavigationManagerPreview _navManagerPreview = SystemNavigationManagerPreview.GetForCurrentView();
public ComposePage()
{
InitializeComponent();
_navManagerPreview.CloseRequested += OnClose;
-
- Environment.SetEnvironmentVariable("WEBVIEW2_DEFAULT_BACKGROUND_COLOR", "00FFFFFF");
- Environment.SetEnvironmentVariable("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "--enable-features=OverlayScrollbar,msOverlayScrollbarWinStyle,msOverlayScrollbarWinStyleAnimation");
}
private async void GlobalFocusManagerGotFocus(object sender, FocusManagerGotFocusEventArgs e)
@@ -71,17 +50,9 @@ private async void GlobalFocusManagerGotFocus(object sender, FocusManagerGotFocu
// This is not done on the WebView2 handlers, because somehow it is
// repeatedly focusing itself, even though when it has the focus already.
- if (e.NewFocusedElement == Chromium)
- {
- await FocusEditorAsync(false);
- }
- }
-
- private static async void OnIsComposerDarkModeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
- {
- if (obj is ComposePage page)
+ if (e.NewFocusedElement == WebViewEditor)
{
- await page.UpdateEditorThemeAsync();
+ await WebViewEditor.FocusEditorAsync(false);
}
}
@@ -216,7 +187,7 @@ private async void OnImageDropGridImageDropped(object sender, DragEventArgs e)
}
}
- await InvokeScriptSafeAsync($"insertImages({JsonSerializer.Serialize(imagesInformation, ComposerPageJsonContext.Default.ListImageInfo)});");
+ await WebViewEditor.InsertImagesAsync(imagesInformation);
}
}
// State should be reset even when an exception occurs, otherwise the UI will be stuck in a dragging state.
@@ -245,299 +216,41 @@ private async Task AttachFiles(IEnumerable files)
}
}
- private bool IsValidImageFile(StorageFile file)
+ private static bool IsValidImageFile(StorageFile file)
{
- string[] allowedTypes = new string[] { ".jpg", ".jpeg", ".png" };
+ string[] allowedTypes = [".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}');");
- }
-
- private async Task 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();");
- }
-
- ///
- /// Places the cursor in the composer.
- ///
- /// Whether control itself should be focused as well or not.
- private async Task FocusEditorAsync(bool focusControlAsWell)
- {
- await InvokeScriptSafeAsync("editor.selection.setCursorIn(editor.editor.firstChild, true)");
-
- if (focusControlAsWell)
- {
- Chromium.Focus(FocusState.Keyboard);
- Chromium.Focus(FocusState.Programmatic);
- }
- }
-
- private async void EmojiButtonClicked(object sender, RoutedEventArgs e)
- {
- CoreInputView.GetForCurrentView().TryShow(CoreInputViewKind.Emoji);
-
- await FocusEditorAsync(focusControlAsWell: true);
- }
-
- 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();
- await InitializeEditorAsync();
-
- if (string.IsNullOrEmpty(htmlBody))
- {
- await Chromium.ExecuteScriptFunctionAsync("RenderHTML", parameters: JsonSerializer.Serialize(" ", BasicTypesJsonContext.Default.String));
- }
- else
- {
- await Chromium.ExecuteScriptFunctionAsync("RenderHTML", parameters: JsonSerializer.Serialize(htmlBody, BasicTypesJsonContext.Default.String));
- }
- }
-
- private async Task InitializeEditorAsync()
- {
- var fonts = ViewModel.FontService.GetFonts();
- var composerFont = ViewModel.PreferencesService.ComposerFont;
- int composerFontSize = ViewModel.PreferencesService.ComposerFontSize;
- var readerFont = ViewModel.PreferencesService.ReaderFont;
- int readerFontSize = ViewModel.PreferencesService.ReaderFontSize;
- return await Chromium.ExecuteScriptFunctionAsync("initializeJodit",
- false,
- JsonSerializer.Serialize(fonts, BasicTypesJsonContext.Default.ListString),
- JsonSerializer.Serialize(composerFont, BasicTypesJsonContext.Default.String),
- JsonSerializer.Serialize(composerFontSize, BasicTypesJsonContext.Default.Int32),
- JsonSerializer.Serialize(readerFont, BasicTypesJsonContext.Default.String),
- JsonSerializer.Serialize(readerFontSize, BasicTypesJsonContext.Default.Int32));
- }
-
- 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())
+ if (_disposables.Count != 0)
_disposables.ForEach(a => a.Dispose());
}
- protected override async void OnNavigatedTo(NavigationEventArgs e)
+ protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
FocusManager.GotFocus += GlobalFocusManagerGotFocus;
- var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation("WebViewConnectedAnimation");
- anim?.TryStart(Chromium);
-
- DisposeDisposables();
+ // TODO: disabled animation for now, since it's still not working properly.
+ //var anim = ConnectedAnimationService.GetForCurrentView().GetAnimation("WebViewConnectedAnimation");
+ //anim?.TryStart(GetWebView());
_disposables.Add(GetSuggestionBoxDisposable(ToBox));
_disposables.Add(GetSuggestionBoxDisposable(CCBox));
_disposables.Add(GetSuggestionBoxDisposable(BccBox));
+ _disposables.Add(WebViewEditor);
- Chromium.CoreWebView2Initialized -= ChromiumInitialized;
- Chromium.CoreWebView2Initialized += ChromiumInitialized;
-
- await Chromium.EnsureCoreWebView2Async();
-
- ViewModel.GetHTMLBodyFunction = new Func>(async () =>
- {
- var editorContent = await InvokeScriptSafeAsync("GetHTMLContent();");
-
- return JsonSerializer.Deserialize(editorContent, BasicTypesJsonContext.Default.String);
- });
-
- var underlyingThemeService = App.Current.Services.GetService();
-
- 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(args.WebMessageAsJson, DomainModelsJsonContext.Default.WebViewMessage);
-
- 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;
- }
+ ViewModel.GetHTMLBodyFunction = WebViewEditor.GetHtmlBodyAsync;
}
- private void DOMLoaded(CoreWebView2 sender, CoreWebView2DOMContentLoadedEventArgs args) => _domLoadedTask.TrySetResult(true);
-
async void IRecipient.Receive(CreateNewComposeMailRequested message)
{
- await RenderInternalAsync(message.RenderModel.RenderHtml);
+ await WebViewEditor.RenderHtmlAsync(message.RenderModel.RenderHtml);
}
private void ShowCCBCCClicked(object sender, RoutedEventArgs e)
@@ -548,7 +261,6 @@ private void ShowCCBCCClicked(object sender, RoutedEventArgs e)
private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args)
{
// Check is valid email.
-
if (!EmailValidator.Validate(args.TokenText))
{
args.Cancel = true;
@@ -557,18 +269,15 @@ private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEven
return;
}
- var deferal = args.GetDeferral();
-
- AccountContact addedItem = null;
+ var deferral = args.GetDeferral();
- 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.CCItems);
- else if (boxTag == "BCCBox")
- addedItem = await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.BCCItems);
+ var addedItem = (sender.Tag?.ToString()) switch
+ {
+ "ToBox" => await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.ToItems),
+ "CCBox" => await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.CCItems),
+ "BCCBox" => await ViewModel.GetAddressInformationAsync(args.TokenText, ViewModel.BCCItems),
+ _ => null
+ };
if (addedItem == null)
{
@@ -580,17 +289,12 @@ private async void TokenItemAdding(TokenizingTextBox sender, TokenItemAddingEven
args.Item = addedItem;
}
- deferal.Complete();
+ deferral.Complete();
}
void IRecipient.Receive(ApplicationThemeChanged message)
{
- IsComposerDarkMode = message.IsUnderlyingThemeDark;
- }
-
- private void InvertComposerThemeClicked(object sender, RoutedEventArgs e)
- {
- IsComposerDarkMode = !IsComposerDarkMode;
+ WebViewEditor.IsEditorDarkMode = message.IsUnderlyingThemeDark;
}
private void ImportanceClicked(object sender, RoutedEventArgs e)
@@ -600,9 +304,7 @@ private void ImportanceClicked(object sender, RoutedEventArgs e)
if (sender is Button senderButton)
{
- var selectedImportance = (MessageImportance)senderButton.Tag;
-
- ViewModel.SelectedMessageImportance = selectedImportance;
+ ViewModel.SelectedMessageImportance = (MessageImportance)senderButton.Tag;
((ImportanceSplitButton.Content as Viewbox).Child as SymbolIcon).Symbol = (senderButton.Content as SymbolIcon).Symbol;
}
}
@@ -613,23 +315,21 @@ private async void AddressBoxLostFocus(object sender, RoutedEventArgs e)
if (sender is TokenizingTextBox tokenizingTextBox)
{
- if (!(tokenizingTextBox.Items.LastOrDefault() is ITokenStringContainer info)) return;
+ if (tokenizingTextBox.Items.LastOrDefault() is not ITokenStringContainer info) return;
var currentText = info.Text;
if (!string.IsNullOrEmpty(currentText) && EmailValidator.Validate(currentText))
{
- var boxTag = tokenizingTextBox.Tag?.ToString();
+ var addressCollection = tokenizingTextBox.Tag?.ToString() switch
+ {
+ "ToBox" => ViewModel.ToItems,
+ "CCBox" => ViewModel.CCItems,
+ "BCCBox" => ViewModel.BCCItems,
+ _ => null
+ };
AccountContact addedItem = null;
- ObservableCollection addressCollection = null;
-
- if (boxTag == "ToBox")
- addressCollection = ViewModel.ToItems;
- else if (boxTag == "CCBox")
- addressCollection = ViewModel.CCItems;
- else if (boxTag == "BCCBox")
- addressCollection = ViewModel.BCCItems;
if (addressCollection != null)
addedItem = await ViewModel.GetAddressInformationAsync(currentText, addressCollection);
@@ -676,7 +376,6 @@ protected override async void OnNavigatingFrom(NavigatingCancelEventArgs e)
await ViewModel.UpdateMimeChangesAsync();
DisposeDisposables();
- DisposeWebView2();
}
private async void OnClose(object sender, SystemNavigationCloseRequestedPreviewEventArgs e)
{
@@ -689,6 +388,3 @@ private async void OnClose(object sender, SystemNavigationCloseRequestedPreviewE
finally { deferral.Complete(); }
}
}
-
-[JsonSerializable(typeof(List))]
-public partial class ComposerPageJsonContext : JsonSerializerContext;
diff --git a/Wino.Mail/Wino.Mail.csproj b/Wino.Mail/Wino.Mail.csproj
index 957f80c8..0b963189 100644
--- a/Wino.Mail/Wino.Mail.csproj
+++ b/Wino.Mail/Wino.Mail.csproj
@@ -79,6 +79,7 @@
+