From bc0e2bd717893007b3aeebcadcd28dd186146c6e Mon Sep 17 00:00:00 2001 From: DismissedLight <1686188646@qq.com> Date: Sun, 15 Oct 2023 21:07:31 +0800 Subject: [PATCH] migrate to winappsdk notification --- src/Snap.Hutao/Snap.Hutao/App.xaml.cs | 2 +- .../Snap.Hutao/Core/LifeCycle/Activation.cs | 118 ++++++++---------- .../AppActivationArgumentsExtensions.cs | 13 ++ .../Snap.Hutao/Core/LifeCycle/IActivation.cs | 8 -- .../Snap.Hutao/Package.appxmanifest | 2 +- .../DailyNoteNotificationOperation.cs | 23 ++-- src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj | 1 - 7 files changed, 81 insertions(+), 86 deletions(-) diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs index bb79f0d1..1f23edb0 100644 --- a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs +++ b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs @@ -52,8 +52,8 @@ public sealed partial class App : Application if (firstInstance.IsCurrent) { // manually invoke - activation.NonRedirectToActivate(firstInstance, activatedEventArgs); activation.InitializeWith(firstInstance); + activation.NonRedirectToActivate(firstInstance, activatedEventArgs); LogDiagnosticInformation(); serviceProvider.GetRequiredService().ConfigureAsync().SafeForget(); diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs index d9884b1d..fa052efe 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/Activation.cs @@ -1,9 +1,9 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using CommunityToolkit.WinUI.Notifications; using Microsoft.Extensions.Caching.Memory; using Microsoft.Windows.AppLifecycle; +using Microsoft.Windows.AppNotifications; using Snap.Hutao.Core.Setting; using Snap.Hutao.Service.DailyNote; using Snap.Hutao.Service.Hutao; @@ -23,24 +23,9 @@ namespace Snap.Hutao.Core.LifeCycle; [SuppressMessage("", "CA1001")] internal sealed partial class Activation : IActivation { - /// - /// 操作 - /// public const string Action = nameof(Action); - - /// - /// Uid - /// public const string Uid = nameof(Uid); - - /// - /// 启动游戏启动参数 - /// public const string LaunchGame = nameof(LaunchGame); - - /// - /// 从剪贴板导入成就 - /// public const string ImportUIAFFromClipboard = nameof(ImportUIAFFromClipboard); private const string CategoryAchievement = "ACHIEVEMENT"; @@ -52,50 +37,50 @@ internal sealed partial class Activation : IActivation private readonly ICurrentWindowReference currentWindowReference; private readonly ITaskContext taskContext; private readonly SemaphoreSlim activateSemaphore = new(1); - - /// - public void Activate(object? sender, AppActivationArguments args) - { - _ = sender; - if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) - { - HandleActivationAsync(args, true).SafeForget(); - } - } + private readonly AppNotificationManager appNotificationManager = AppNotificationManager.Default; /// public void NonRedirectToActivate(object? sender, AppActivationArguments args) { - _ = sender; - if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) - { - HandleActivationAsync(args, false).SafeForget(); - } + HandleActivationAsync(args, false).SafeForget(); } /// public void InitializeWith(AppInstance appInstance) { - appInstance.Activated += Activate; - ToastNotificationManagerCompat.OnActivated += NotificationActivate; + appInstance.Activated += OnAppInstanceActivate; + appNotificationManager.NotificationInvoked += OnAppNotificationManagerNotificationInvoked; + appNotificationManager.Register(); } - private void NotificationActivate(ToastNotificationActivatedEventArgsCompat args) + private void OnAppInstanceActivate(object? sender, AppActivationArguments args) { - ToastArguments toastArgs = ToastArguments.Parse(args.Argument); + HandleActivationAsync(args, true).SafeForget(); + } - if (toastArgs.TryGetValue(Action, out string? action)) + private void OnAppNotificationManagerNotificationInvoked(AppNotificationManager manager, AppNotificationActivatedEventArgs args) + { + IDictionary arguments = args.Arguments; + HandleAppNotificationActivationAsync(arguments).SafeForget(); + } + + private async ValueTask HandleAppNotificationActivationAsync(IDictionary arguments) + { + if (arguments.TryGetValue(Action, out string? action)) { if (action == LaunchGame) { - _ = toastArgs.TryGetValue(Uid, out string? uid); - HandleLaunchGameActionAsync(uid).SafeForget(); + if (arguments.TryGetValue(Uid, out string? uid)) + { + await HandleLaunchGameActionAsync(uid).ConfigureAwait(false); + } } } } private async ValueTask HandleActivationAsync(AppActivationArguments args, bool isRedirected) { + // Refuse other activations if (activateSemaphore.CurrentCount > 0) { using (await activateSemaphore.EnterAsync().ConfigureAwait(false)) @@ -107,32 +92,42 @@ internal sealed partial class Activation : IActivation private async ValueTask HandleActivationCoreAsync(AppActivationArguments args, bool isRedirected) { - if (args.Kind == ExtendedActivationKind.Protocol) + switch (args.Kind) { - if (args.TryGetProtocolActivatedUri(out Uri? uri)) - { - await HandleUrlActivationAsync(uri, isRedirected).ConfigureAwait(false); - } - } - else if (args.Kind == ExtendedActivationKind.Launch) - { - if (args.TryGetLaunchActivatedArgument(out string? arguments)) - { - switch (arguments) + case ExtendedActivationKind.Launch: + if (args.TryGetLaunchActivatedArgument(out string? command)) { - case LaunchGame: - { - await HandleLaunchGameActionAsync().ConfigureAwait(false); - break; - } + switch (command) + { + case LaunchGame: + { + await HandleLaunchGameActionAsync().ConfigureAwait(false); + break; + } - default: - { - await HandleNormalLaunchActionAsync().ConfigureAwait(false); - break; - } + default: + { + await HandleNormalLaunchActionAsync().ConfigureAwait(false); + break; + } + } } - } + + break; + case ExtendedActivationKind.AppNotification: + if (args.TryGetAppNotificationActivatedArgument(out IDictionary? arguments)) + { + await HandleAppNotificationActivationAsync(arguments).ConfigureAwait(false); + } + + break; + case ExtendedActivationKind.Protocol: + if (args.TryGetProtocolActivatedUri(out Uri? uri)) + { + await HandleUrlActivationAsync(uri, isRedirected).ConfigureAwait(false); + } + + break; } } @@ -212,8 +207,6 @@ internal sealed partial class Activation : IActivation private async ValueTask HandleAchievementActionAsync(string action, string parameter, bool isRedirected) { - _ = parameter; - _ = isRedirected; switch (action) { case UrlActionImport: @@ -232,7 +225,6 @@ internal sealed partial class Activation : IActivation private async ValueTask HandleDailyNoteActionAsync(string action, string parameter, bool isRedirected) { - _ = parameter; switch (action) { case UrlActionRefresh: diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs index eb216a8e..b183de3f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. using Microsoft.Windows.AppLifecycle; +using Microsoft.Windows.AppNotifications; using Windows.ApplicationModel.Activation; namespace Snap.Hutao.Core.LifeCycle; @@ -47,4 +48,16 @@ internal static class AppActivationArgumentsExtensions arguments = launchArgs.Arguments.Trim(); return true; } + + public static bool TryGetAppNotificationActivatedArgument(this AppActivationArguments activatedEventArgs, [NotNullWhen(true)] out IDictionary? arguments) + { + arguments = null; + if (activatedEventArgs.Data is not AppNotificationActivatedEventArgs launchArgs) + { + return false; + } + + arguments = launchArgs.Arguments; + return true; + } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IActivation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IActivation.cs index 4859192d..6cef7dc4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IActivation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IActivation.cs @@ -10,14 +10,6 @@ namespace Snap.Hutao.Core.LifeCycle; /// internal interface IActivation { - /// - /// 响应激活事件 - /// 激活事件一般不会在UI线程上触发 - /// - /// 发送方 - /// 激活参数 - void Activate(object? sender, AppActivationArguments args); - /// /// 使用当前 App 实例初始化激活 /// diff --git a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest index 4910b0e9..e874296a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest +++ b/src/Snap.Hutao/Snap.Hutao/Package.appxmanifest @@ -48,7 +48,7 @@ - + diff --git a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs index 2286856b..2425b2f4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs +++ b/src/Snap.Hutao/Snap.Hutao/Service/DailyNote/DailyNoteNotificationOperation.cs @@ -1,7 +1,8 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. -using CommunityToolkit.WinUI.Notifications; +using Microsoft.Windows.AppNotifications; +using Microsoft.Windows.AppNotifications.Builder; using Snap.Hutao.Core; using Snap.Hutao.Core.LifeCycle; using Snap.Hutao.Model.Entity; @@ -63,18 +64,16 @@ internal sealed partial class DailyNoteNotificationOperation } } - ToastContentBuilder builder = new ToastContentBuilder() - .AddHeader(ToastHeaderIdArgument, SH.ServiceDailyNoteNotifierTitle, ToastHeaderIdArgument) - .AddAttributionText(attribution) - .AddButton(new ToastButton() - .SetContent(SH.ServiceDailyNoteNotifierActionLaunchGameButton) + AppNotificationBuilder builder = new AppNotificationBuilder() + .AddText(SH.ServiceDailyNoteNotifierTitle, new AppNotificationTextProperties().SetMaxLines(1)) + .SetAttributionText(attribution) + .AddButton(new AppNotificationButton(SH.ServiceDailyNoteNotifierActionLaunchGameButton) .AddArgument(Activation.Action, Activation.LaunchGame) - .AddArgument(Activation.Uid, entry.Uid)) - .AddButton(new ToastButtonDismiss(SH.ServiceDailyNoteNotifierActionLaunchGameDismiss)); + .AddArgument(Activation.Uid, entry.Uid)); if (options.IsReminderNotification) { - builder.SetToastScenario(ToastScenario.Reminder); + builder.SetScenario(AppNotificationScenario.Reminder); } if (notifyInfos.Count > 2) @@ -101,7 +100,7 @@ internal sealed partial class DailyNoteNotificationOperation group.Children.Add(subgroup); } - builder.AddVisualChild(group); + builder.SetGroup(group); } } else @@ -121,14 +120,14 @@ internal sealed partial class DailyNoteNotificationOperation // Image limitation. // https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/send-local-toast?tabs=uwp#adding-images // NotifySuppressed judge - ChcekResinNotifySuppressed(entry, notifyInfos); + CheckResinNotifySuppressed(entry, notifyInfos); CheckHomeCoinNotifySuppressed(entry, notifyInfos); CheckDailyTaskNotifySuppressed(entry, notifyInfos); CheckTransformerNotifySuppressed(entry, notifyInfos); CheckExpeditionNotifySuppressed(entry, notifyInfos); } - private static void ChcekResinNotifySuppressed(DailyNoteEntry entry, List notifyInfos) + private static void CheckResinNotifySuppressed(DailyNoteEntry entry, List notifyInfos) { ArgumentNullException.ThrowIfNull(entry.DailyNote); if (entry.DailyNote.CurrentResin >= entry.ResinNotifyThreshold) diff --git a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj index bdf870c4..6d12746a 100644 --- a/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj +++ b/src/Snap.Hutao/Snap.Hutao/Snap.Hutao.csproj @@ -261,7 +261,6 @@ - all