Embedded images replaced with cid linked resources. (#313)
* Added logic to replace embedded images with linked resources * Added alt text for images and replaced NewtonSoft with Text.Json * Fix draft mime preparation * Fix crashes for signatures without images. --------- Co-authored-by: Burak Kaan Köse <bkaankose@outlook.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Toolkit.Uwp.Helpers;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Xaml;
|
||||
@@ -9,7 +10,6 @@ using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Animation;
|
||||
using Wino.Core.Domain.Interfaces;
|
||||
using Wino.Core.Services;
|
||||
using Wino.Helpers;
|
||||
using Wino.Views;
|
||||
|
||||
namespace Wino.Activation
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Newtonsoft.Json;
|
||||
using Windows.UI.ViewManagement.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
@@ -78,7 +78,7 @@ namespace Wino.Dialogs
|
||||
{
|
||||
var editorContent = await InvokeScriptSafeAsync("GetHTMLContent();");
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(editorContent);
|
||||
return JsonSerializer.Deserialize<string>(editorContent);
|
||||
});
|
||||
|
||||
var underlyingThemeService = App.Current.Services.GetService<IUnderlyingThemeService>();
|
||||
@@ -193,7 +193,7 @@ namespace Wino.Dialogs
|
||||
string script = functionName + "(";
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
script += JsonConvert.SerializeObject(parameters[i]);
|
||||
script += JsonSerializer.Serialize(parameters[i]);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
script += ", ";
|
||||
@@ -327,7 +327,7 @@ namespace Wino.Dialogs
|
||||
|
||||
private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
var change = JsonConvert.DeserializeObject<WebViewMessage>(args.WebMessageAsJson);
|
||||
var change = JsonSerializer.Deserialize<WebViewMessage>(args.WebMessageAsJson);
|
||||
|
||||
if (change.Type == "bold")
|
||||
{
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Wino.Helpers
|
||||
{
|
||||
public static class JsonHelpers
|
||||
{
|
||||
public static async Task<T> ToObjectAsync<T>(string value)
|
||||
{
|
||||
return await Task.Run<T>(() =>
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(value);
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task<string> StringifyAsync(object value)
|
||||
{
|
||||
return await Task.Run<string>(() =>
|
||||
{
|
||||
return JsonConvert.SerializeObject(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Streams;
|
||||
|
||||
namespace Wino.Helpers
|
||||
{
|
||||
// Use these extension methods to store and retrieve local and roaming app data
|
||||
// More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/uwp/app-settings/store-and-retrieve-app-data
|
||||
public static class SettingsStorageExtensions
|
||||
{
|
||||
private const string FileExtension = ".json";
|
||||
|
||||
public static bool IsRoamingStorageAvailable(this ApplicationData appData)
|
||||
{
|
||||
return appData.RoamingStorageQuota == 0;
|
||||
}
|
||||
|
||||
public static async Task SaveAsync<T>(this StorageFolder folder, string name, T content)
|
||||
{
|
||||
var file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting);
|
||||
var fileContent = await JsonHelpers.StringifyAsync(content);
|
||||
|
||||
await FileIO.WriteTextAsync(file, fileContent);
|
||||
}
|
||||
|
||||
public static async Task<T> ReadAsync<T>(this StorageFolder folder, string name)
|
||||
{
|
||||
if (!File.Exists(Path.Combine(folder.Path, GetFileName(name))))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var file = await folder.GetFileAsync($"{name}.json");
|
||||
var fileContent = await FileIO.ReadTextAsync(file);
|
||||
|
||||
return await JsonHelpers.ToObjectAsync<T>(fileContent);
|
||||
}
|
||||
|
||||
public static async Task SaveAsync<T>(this ApplicationDataContainer settings, string key, T value)
|
||||
{
|
||||
settings.SaveString(key, await JsonHelpers.StringifyAsync(value));
|
||||
}
|
||||
|
||||
public static void SaveString(this ApplicationDataContainer settings, string key, string value)
|
||||
{
|
||||
settings.Values[key] = value;
|
||||
}
|
||||
|
||||
public static async Task<T> ReadAsync<T>(this ApplicationDataContainer settings, string key)
|
||||
{
|
||||
object obj = null;
|
||||
|
||||
if (settings.Values.TryGetValue(key, out obj))
|
||||
{
|
||||
return await JsonHelpers.ToObjectAsync<T>((string)obj);
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
public static async Task<StorageFile> SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting)
|
||||
{
|
||||
if (content == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(content));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName));
|
||||
}
|
||||
|
||||
var storageFile = await folder.CreateFileAsync(fileName, options);
|
||||
await FileIO.WriteBytesAsync(storageFile, content);
|
||||
return storageFile;
|
||||
}
|
||||
|
||||
public static async Task<byte[]> ReadFileAsync(this StorageFolder folder, string fileName)
|
||||
{
|
||||
var item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false);
|
||||
|
||||
if ((item != null) && item.IsOfType(StorageItemTypes.File))
|
||||
{
|
||||
var storageFile = await folder.GetFileAsync(fileName);
|
||||
byte[] content = await storageFile.ReadBytesAsync();
|
||||
return content;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static async Task<byte[]> ReadBytesAsync(this StorageFile file)
|
||||
{
|
||||
if (file != null)
|
||||
{
|
||||
using (IRandomAccessStream stream = await file.OpenReadAsync())
|
||||
{
|
||||
using (var reader = new DataReader(stream.GetInputStreamAt(0)))
|
||||
{
|
||||
await reader.LoadAsync((uint)stream.Size);
|
||||
var bytes = new byte[stream.Size];
|
||||
reader.ReadBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string GetFileName(string name)
|
||||
{
|
||||
return string.Concat(name, FileExtension);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ function initializeJodit(fonts, defaultComposerFont, defaultComposerFontSize, de
|
||||
const reader = new FileReader();
|
||||
reader.onload = function (event) {
|
||||
const base64Image = event.target.result;
|
||||
insertImages([base64Image]);
|
||||
insertImages([{ data: base64Image, name: file.name }]);
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
@@ -121,8 +121,8 @@ function toggleToolbar(enable) {
|
||||
}
|
||||
}
|
||||
|
||||
function insertImages(images) {
|
||||
images.forEach(image => {
|
||||
editor.selection.insertHTML(`<img src="${image}" alt="Embedded Image">`);
|
||||
function insertImages(imagesInfo) {
|
||||
imagesInfo.forEach(imageInfo => {
|
||||
editor.selection.insertHTML(`<img src="${imageInfo.data}" alt="${imageInfo.name}">`);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
@@ -13,7 +14,6 @@ using Microsoft.Toolkit.Uwp.Helpers;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using MimeKit;
|
||||
using Newtonsoft.Json;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Foundation;
|
||||
using Windows.Storage;
|
||||
@@ -167,7 +167,7 @@ namespace Wino.Views
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (ValidateImageFile(file))
|
||||
if (IsValidImageFile(file))
|
||||
{
|
||||
isValid = true;
|
||||
}
|
||||
@@ -200,15 +200,21 @@ namespace Wino.Views
|
||||
var storageItems = await e.DataView.GetStorageItemsAsync();
|
||||
var files = storageItems.OfType<StorageFile>();
|
||||
|
||||
var imageDataURLs = new List<string>();
|
||||
var imagesInformation = new List<ImageInfo>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (ValidateImageFile(file))
|
||||
imageDataURLs.Add(await GetDataURL(file));
|
||||
if (IsValidImageFile(file))
|
||||
{
|
||||
imagesInformation.Add(new ImageInfo
|
||||
{
|
||||
Data = await GetDataURL(file),
|
||||
Name = file.Name
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await InvokeScriptSafeAsync($"insertImages({JsonConvert.SerializeObject(imageDataURLs)});");
|
||||
await InvokeScriptSafeAsync($"insertImages({JsonSerializer.Serialize(imagesInformation)});");
|
||||
}
|
||||
}
|
||||
// State should be reset even when an exception occurs, otherwise the UI will be stuck in a dragging state.
|
||||
@@ -240,7 +246,7 @@ namespace Wino.Views
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateImageFile(StorageFile file)
|
||||
private bool IsValidImageFile(StorageFile file)
|
||||
{
|
||||
string[] allowedTypes = new string[] { ".jpg", ".jpeg", ".png" };
|
||||
var fileType = file.FileType.ToLower();
|
||||
@@ -321,7 +327,7 @@ namespace Wino.Views
|
||||
string script = functionName + "(";
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
script += JsonConvert.SerializeObject(parameters[i]);
|
||||
script += JsonSerializer.Serialize(parameters[i]);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
script += ", ";
|
||||
@@ -463,7 +469,7 @@ namespace Wino.Views
|
||||
{
|
||||
var editorContent = await InvokeScriptSafeAsync("GetHTMLContent();");
|
||||
|
||||
return JsonConvert.DeserializeObject<string>(editorContent);
|
||||
return JsonSerializer.Deserialize<string>(editorContent);
|
||||
});
|
||||
|
||||
var underlyingThemeService = App.Current.Services.GetService<IUnderlyingThemeService>();
|
||||
@@ -487,7 +493,7 @@ namespace Wino.Views
|
||||
|
||||
private void ScriptMessageReceived(CoreWebView2 sender, CoreWebView2WebMessageReceivedEventArgs args)
|
||||
{
|
||||
var change = JsonConvert.DeserializeObject<WebViewMessage>(args.WebMessageAsJson);
|
||||
var change = JsonSerializer.Deserialize<WebViewMessage>(args.WebMessageAsJson);
|
||||
|
||||
if (change.Type == "bold")
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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 Newtonsoft.Json;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
@@ -70,7 +70,7 @@ namespace Wino.Views
|
||||
string script = functionName + "(";
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
script += JsonConvert.SerializeObject(parameters[i]);
|
||||
script += JsonSerializer.Serialize(parameters[i]);
|
||||
if (i < parameters.Length - 1)
|
||||
{
|
||||
script += ", ";
|
||||
|
||||
@@ -298,14 +298,12 @@
|
||||
<Compile Include="Dialogs\AccountCreationDialog.xaml.cs">
|
||||
<DependentUpon>AccountCreationDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Helpers\JsonHelpers.cs" />
|
||||
<Compile Include="Extensions\AnimationExtensions.cs" />
|
||||
<Compile Include="Extensions\CompositionExtensions.Implicit.cs" />
|
||||
<Compile Include="Extensions\CompositionExtensions.Size.cs" />
|
||||
<Compile Include="Extensions\CompositionEnums.cs" />
|
||||
<Compile Include="Extensions\EnumerableExtensions.cs" />
|
||||
<Compile Include="Extensions\UtilExtensions.cs" />
|
||||
<Compile Include="Helpers\SettingsStorageExtensions.cs" />
|
||||
<Compile Include="MenuFlyouts\FilterMenuFlyout.cs" />
|
||||
<Compile Include="Controls\ImagePreviewControl.cs" />
|
||||
<Compile Include="Controls\MailItemDisplayInformationControl.xaml.cs">
|
||||
|
||||
Reference in New Issue
Block a user