Initial v2 launch notification.

This commit is contained in:
Burak Kaan Köse
2026-04-25 16:12:49 +02:00
parent 3ea8b8ac46
commit 55ae6e1f3a
5 changed files with 58 additions and 10 deletions
@@ -51,6 +51,11 @@ public interface INotificationBuilder
/// </summary> /// </summary>
void CreateStoreUpdateNotification(); void CreateStoreUpdateNotification();
/// <summary>
/// Shows the one-time release migration notification.
/// </summary>
void CreateReleaseMigrationNotification();
/// <summary> /// <summary>
/// Creates a calendar reminder toast for the specified calendar item. /// Creates a calendar reminder toast for the specified calendar item.
/// </summary> /// </summary>
@@ -704,6 +704,8 @@
"Notifications_WinoUpdatedTitle": "Wino Mail has been updated.", "Notifications_WinoUpdatedTitle": "Wino Mail has been updated.",
"Notifications_StoreUpdateAvailableTitle": "Update available", "Notifications_StoreUpdateAvailableTitle": "Update available",
"Notifications_StoreUpdateAvailableMessage": "A newer version of Wino Mail is ready to install from Microsoft Store.", "Notifications_StoreUpdateAvailableMessage": "A newer version of Wino Mail is ready to install from Microsoft Store.",
"Notifications_ReleaseMigrationTitle": "New Wino Mail & Calendar",
"Notifications_ReleaseMigrationMessage": "Wino Mail got updated to the next version. Please re-create your accounts and start using the next version including calendar, mail templates, shortcuts, and a bunch of other improvements.",
"OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.", "OnlineSearchFailed_Message": "Failed to perform search\n{0}\n\nListing offline mails.",
"OnlineSearchTry_Line1": "Can't find what you are looking for?", "OnlineSearchTry_Line1": "Can't find what you are looking for?",
"OnlineSearchTry_Line2": "Try online search.", "OnlineSearchTry_Line2": "Try online search.",
+1 -1
View File
@@ -23,7 +23,7 @@
<Identity <Identity
Name="58272BurakKSE.WinoMailPreview" Name="58272BurakKSE.WinoMailPreview"
Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911" Publisher="CN=51FBDAF3-E212-4149-89A2-A2636B3BC911"
Version="2.0.6.0" /> Version="2.0.7.0" />
<mp:PhoneIdentity PhoneProductId="7b7e90e9-cc55-4409-9769-99b4b5ed6e9b" PhonePublisherId="00000000-0000-0000-0000-000000000000"/> <mp:PhoneIdentity PhoneProductId="7b7e90e9-cc55-4409-9769-99b4b5ed6e9b" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
@@ -233,6 +233,17 @@ public class NotificationBuilder : INotificationBuilder
ShowNotification(builder, "store-update-available"); ShowNotification(builder, "store-update-available");
} }
public void CreateReleaseMigrationNotification()
{
var builder = CreateBuilder();
builder.AddText(Translator.Notifications_ReleaseMigrationTitle);
builder.AddText(Translator.Notifications_ReleaseMigrationMessage);
builder.AddArgument(Constants.ToastModeKey, Constants.ToastModeMail);
builder.AddButton(CreateDismissButton());
ShowNotification(builder, "release-migration-v2");
}
public Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds) public Task CreateCalendarReminderNotificationAsync(CalendarItem calendarItem, long reminderDurationInSeconds)
{ {
if (calendarItem == null) if (calendarItem == null)
@@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Serilog; using Serilog;
using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Interfaces;
@@ -14,13 +15,16 @@ public sealed class ReleaseLocalAccountDataCleanupService
private readonly IConfigurationService _configurationService; private readonly IConfigurationService _configurationService;
private readonly IApplicationConfiguration _applicationConfiguration; private readonly IApplicationConfiguration _applicationConfiguration;
private readonly INotificationBuilder _notificationBuilder;
private readonly ILogger _logger = Log.ForContext<ReleaseLocalAccountDataCleanupService>(); private readonly ILogger _logger = Log.ForContext<ReleaseLocalAccountDataCleanupService>();
public ReleaseLocalAccountDataCleanupService(IConfigurationService configurationService, public ReleaseLocalAccountDataCleanupService(IConfigurationService configurationService,
IApplicationConfiguration applicationConfiguration) IApplicationConfiguration applicationConfiguration,
INotificationBuilder notificationBuilder)
{ {
_configurationService = configurationService; _configurationService = configurationService;
_applicationConfiguration = applicationConfiguration; _applicationConfiguration = applicationConfiguration;
_notificationBuilder = notificationBuilder;
} }
public async Task RunIfNeededAsync() public async Task RunIfNeededAsync()
@@ -45,44 +49,70 @@ public sealed class ReleaseLocalAccountDataCleanupService
Path.Combine(publisherPath, LegacyDatabaseFileName) Path.Combine(publisherPath, LegacyDatabaseFileName)
}; };
var hadLegacyData = false;
foreach (var targetPath in cleanupTargets) foreach (var targetPath in cleanupTargets)
{ {
await DeletePathIfExistsAsync(localFolderPath, targetPath).ConfigureAwait(false); hadLegacyData |= await DeletePathIfExistsAsync(targetPath, localFolderPath, publisherPath).ConfigureAwait(false);
} }
_configurationService.Set(CleanupCompletedSettingKey, true); _configurationService.Set(CleanupCompletedSettingKey, true);
if (hadLegacyData)
{
_notificationBuilder.CreateReleaseMigrationNotification();
}
_logger.Information("Completed one-time local account data cleanup for release migration."); _logger.Information("Completed one-time local account data cleanup for release migration.");
} }
private async Task DeletePathIfExistsAsync(string localFolderPath, string targetPath) private async Task<bool> DeletePathIfExistsAsync(string targetPath, params string[] allowedRootPaths)
{ {
try try
{ {
var fullTargetPath = Path.GetFullPath(targetPath); var fullTargetPath = Path.GetFullPath(targetPath);
var fullLocalFolderPath = Path.GetFullPath(localFolderPath); if (!allowedRootPaths.Any(rootPath => IsPathUnderAllowedRoot(fullTargetPath, rootPath)))
if (!fullTargetPath.StartsWith(fullLocalFolderPath, StringComparison.OrdinalIgnoreCase))
{ {
_logger.Warning("Skipped startup cleanup for path outside local folder: {TargetPath}", fullTargetPath); _logger.Warning("Skipped startup cleanup for path outside allowed roots: {TargetPath}", fullTargetPath);
return; return false;
} }
var targetExists = Directory.Exists(fullTargetPath) || File.Exists(fullTargetPath);
if (Directory.Exists(fullTargetPath)) if (Directory.Exists(fullTargetPath))
{ {
await Task.Run(() => Directory.Delete(fullTargetPath, recursive: true)).ConfigureAwait(false); await Task.Run(() => Directory.Delete(fullTargetPath, recursive: true)).ConfigureAwait(false);
_logger.Information("Deleted legacy startup cleanup directory {TargetPath}", fullTargetPath); _logger.Information("Deleted legacy startup cleanup directory {TargetPath}", fullTargetPath);
return; return true;
} }
if (File.Exists(fullTargetPath)) if (File.Exists(fullTargetPath))
{ {
File.Delete(fullTargetPath); File.Delete(fullTargetPath);
_logger.Information("Deleted legacy startup cleanup file {TargetPath}", fullTargetPath); _logger.Information("Deleted legacy startup cleanup file {TargetPath}", fullTargetPath);
return true;
} }
return targetExists;
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Warning(ex, "Failed to delete legacy startup cleanup path {TargetPath}", targetPath); _logger.Warning(ex, "Failed to delete legacy startup cleanup path {TargetPath}", targetPath);
} }
return false;
}
private static bool IsPathUnderAllowedRoot(string fullTargetPath, string rootPath)
{
if (string.IsNullOrWhiteSpace(rootPath))
return false;
var fullRootPath = Path.GetFullPath(rootPath);
var relativePath = Path.GetRelativePath(fullRootPath, fullTargetPath);
return relativePath != "." &&
!relativePath.StartsWith("..", StringComparison.Ordinal) &&
!Path.IsPathRooted(relativePath);
} }
} }