Dispatch WebView2 runtime toast notification on UI thread (#811)

This commit is contained in:
Burak Kaan Köse
2026-02-16 16:32:47 +01:00
committed by GitHub
parent fec49ce6f8
commit 05112d6a35
7 changed files with 73 additions and 1 deletions
@@ -31,6 +31,11 @@ public interface INotificationBuilder
/// <param name="account">Account that needs attention.</param> /// <param name="account">Account that needs attention.</param>
void CreateAttentionRequiredNotification(MailAccount account); void CreateAttentionRequiredNotification(MailAccount account);
/// <summary>
/// Shows a notification when WebView2 runtime is unavailable.
/// </summary>
void CreateWebView2RuntimeMissingNotification();
/// <summary> /// <summary>
/// Creates a calendar reminder toast for the specified calendar item. /// Creates a calendar reminder toast for the specified calendar item.
/// </summary> /// </summary>
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace Wino.Core.Domain.Interfaces;
public interface IWebView2RuntimeValidatorService
{
/// <summary>
/// Validates whether WebView2 runtime is installed and available for use.
/// </summary>
Task<bool> IsRuntimeAvailableAsync();
}
@@ -238,6 +238,8 @@
"Error_FailedToSetupSystemFolders_Title": "Failed to setup system folders", "Error_FailedToSetupSystemFolders_Title": "Failed to setup system folders",
"Exception_AccountNeedsAttention_Title": "Account needs attention", "Exception_AccountNeedsAttention_Title": "Account needs attention",
"Exception_AccountNeedsAttention_Message": "'{0}' requires your attention to continue working.", "Exception_AccountNeedsAttention_Message": "'{0}' requires your attention to continue working.",
"Exception_WebView2RuntimeMissing_Message": "Wino Mail could not find Microsoft Edge WebView2 Runtime. Please install or repair the runtime to render message content correctly.",
"Exception_WebView2RuntimeMissing_Title": "WebView2 runtime is required",
"Exception_AuthenticationCanceled": "Authentication canceled", "Exception_AuthenticationCanceled": "Authentication canceled",
"Exception_CustomThemeExists": "This theme already exists.", "Exception_CustomThemeExists": "This theme already exists.",
"Exception_CustomThemeMissingName": "You must provide a name.", "Exception_CustomThemeMissingName": "You must provide a name.",
+15 -1
View File
@@ -77,6 +77,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
private readonly IWinoRequestDelegator _winoRequestDelegator; private readonly IWinoRequestDelegator _winoRequestDelegator;
private readonly IMailDialogService _dialogService; private readonly IMailDialogService _dialogService;
private readonly IMimeFileService _mimeFileService; private readonly IMimeFileService _mimeFileService;
private readonly IWebView2RuntimeValidatorService _webView2RuntimeValidatorService;
private readonly INativeAppService _nativeAppService; private readonly INativeAppService _nativeAppService;
private readonly IMailService _mailService; private readonly IMailService _mailService;
@@ -98,7 +99,8 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
IFolderService folderService, IFolderService folderService,
IStatePersistanceService statePersistanceService, IStatePersistanceService statePersistanceService,
IConfigurationService configurationService, IConfigurationService configurationService,
IStartupBehaviorService startupBehaviorService) IStartupBehaviorService startupBehaviorService,
IWebView2RuntimeValidatorService webView2RuntimeValidatorService)
{ {
StatePersistenceService = statePersistanceService; StatePersistenceService = statePersistanceService;
@@ -118,6 +120,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
_launchProtocolService = launchProtocolService; _launchProtocolService = launchProtocolService;
_notificationBuilder = notificationBuilder; _notificationBuilder = notificationBuilder;
_winoRequestDelegator = winoRequestDelegator; _winoRequestDelegator = winoRequestDelegator;
_webView2RuntimeValidatorService = webView2RuntimeValidatorService;
} }
protected override void OnDispatcherAssigned() protected override void OnDispatcherAssigned()
@@ -233,6 +236,7 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
await RecreateMenuItemsAsync(); await RecreateMenuItemsAsync();
await ProcessLaunchOptionsAsync(); await ProcessLaunchOptionsAsync();
await ValidateWebView2RuntimeAsync();
if (!Debugger.IsAttached) if (!Debugger.IsAttached)
{ {
@@ -242,6 +246,16 @@ public partial class MailAppShellViewModel : MailBaseViewModel,
await MakeSureEnableStartupLaunchAsync(); await MakeSureEnableStartupLaunchAsync();
} }
private async Task ValidateWebView2RuntimeAsync()
{
var isRuntimeAvailable = await _webView2RuntimeValidatorService.IsRuntimeAvailableAsync();
if (!isRuntimeAvailable)
{
await ExecuteUIThread(() => _notificationBuilder.CreateWebView2RuntimeMissingNotification());
}
}
private async Task MakeSureEnableStartupLaunchAsync() private async Task MakeSureEnableStartupLaunchAsync()
{ {
if (!_configurationService.Get<bool>(IsActivateStartupLaunchAskedKey, false)) if (!_configurationService.Get<bool>(IsActivateStartupLaunchAskedKey, false))
+1
View File
@@ -29,6 +29,7 @@ public static class CoreUWPContainerSetup
services.AddTransient<IFileService, FileService>(); services.AddTransient<IFileService, FileService>();
services.AddTransient<IStoreRatingService, StoreRatingService>(); services.AddTransient<IStoreRatingService, StoreRatingService>();
services.AddTransient<IKeyPressService, KeyPressService>(); services.AddTransient<IKeyPressService, KeyPressService>();
services.AddTransient<IWebView2RuntimeValidatorService, WebView2RuntimeValidatorService>();
services.AddTransient<INotificationBuilder, NotificationBuilder>(); services.AddTransient<INotificationBuilder, NotificationBuilder>();
services.AddSingleton<ICalendarReminderServer, CalendarReminderServer>(); services.AddSingleton<ICalendarReminderServer, CalendarReminderServer>();
services.AddTransient<IClipboardService, ClipboardService>(); services.AddTransient<IClipboardService, ClipboardService>();
@@ -252,6 +252,18 @@ public class NotificationBuilder : INotificationBuilder
builder.Show(); builder.Show();
} }
public void CreateWebView2RuntimeMissingNotification()
{
var builder = new ToastContentBuilder();
builder.SetToastScenario(ToastScenario.Default);
builder.AddText(Translator.Exception_WebView2RuntimeMissing_Title);
builder.AddText(Translator.Exception_WebView2RuntimeMissing_Message);
builder.AddButton(GetDismissButton());
builder.Show();
}
public Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds) public Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds)
{ {
if (calendarItem == null) if (calendarItem == null)
@@ -0,0 +1,26 @@
using System;
using System.Threading.Tasks;
using Microsoft.Web.WebView2.Core;
using Serilog;
using Wino.Core.Domain.Interfaces;
namespace Wino.Mail.WinUI.Services;
public class WebView2RuntimeValidatorService : IWebView2RuntimeValidatorService
{
public Task<bool> IsRuntimeAvailableAsync()
{
try
{
var version = CoreWebView2Environment.GetAvailableBrowserVersionString();
var hasRuntime = !string.IsNullOrWhiteSpace(version);
return Task.FromResult(hasRuntime);
}
catch (Exception ex)
{
Log.Error(ex, "WebView2 runtime validation failed.");
return Task.FromResult(false);
}
}
}