migrate to winappsdk notification

This commit is contained in:
DismissedLight
2023-10-15 21:07:31 +08:00
parent 7b8ebd86b1
commit bc0e2bd717
7 changed files with 81 additions and 86 deletions

View File

@@ -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<IJumpListInterop>().ConfigureAsync().SafeForget();

View File

@@ -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
{
/// <summary>
/// 操作
/// </summary>
public const string Action = nameof(Action);
/// <summary>
/// Uid
/// </summary>
public const string Uid = nameof(Uid);
/// <summary>
/// 启动游戏启动参数
/// </summary>
public const string LaunchGame = nameof(LaunchGame);
/// <summary>
/// 从剪贴板导入成就
/// </summary>
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);
/// <inheritdoc/>
public void Activate(object? sender, AppActivationArguments args)
{
_ = sender;
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
{
HandleActivationAsync(args, true).SafeForget();
}
}
private readonly AppNotificationManager appNotificationManager = AppNotificationManager.Default;
/// <inheritdoc/>
public void NonRedirectToActivate(object? sender, AppActivationArguments args)
{
_ = sender;
if (!ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
{
HandleActivationAsync(args, false).SafeForget();
}
HandleActivationAsync(args, false).SafeForget();
}
/// <inheritdoc/>
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<string, string> arguments = args.Arguments;
HandleAppNotificationActivationAsync(arguments).SafeForget();
}
private async ValueTask HandleAppNotificationActivationAsync(IDictionary<string, string> 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<string, string>? 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:

View File

@@ -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<string, string>? arguments)
{
arguments = null;
if (activatedEventArgs.Data is not AppNotificationActivatedEventArgs launchArgs)
{
return false;
}
arguments = launchArgs.Arguments;
return true;
}
}

View File

@@ -10,14 +10,6 @@ namespace Snap.Hutao.Core.LifeCycle;
/// </summary>
internal interface IActivation
{
/// <summary>
/// 响应激活事件
/// 激活事件一般不会在UI线程上触发
/// </summary>
/// <param name="sender">发送方</param>
/// <param name="args">激活参数</param>
void Activate(object? sender, AppActivationArguments args);
/// <summary>
/// 使用当前 App 实例初始化激活
/// </summary>

View File

@@ -48,7 +48,7 @@
</desktop:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="Snap.Hutao.exe" Arguments="-ToastActivated" DisplayName="Snap Hutao Toast Activator">
<com:ExeServer Executable="Snap.Hutao.exe" Arguments="----AppNotificationActivated:" DisplayName="Snap Hutao Toast Activator">
<com:Class Id="5760ec4d-f7e8-4666-a965-9886d7dffe7d" DisplayName="Snap Hutao Toast Activator"/>
</com:ExeServer>
</com:ComServer>

View File

@@ -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<DailyNoteNotifyInfo> notifyInfos)
private static void CheckResinNotifySuppressed(DailyNoteEntry entry, List<DailyNoteNotifyInfo> notifyInfos)
{
ArgumentNullException.ThrowIfNull(entry.DailyNote);
if (entry.DailyNote.CurrentResin >= entry.ResinNotifyThreshold)

View File

@@ -261,7 +261,6 @@
<PackageReference Include="CommunityToolkit.WinUI.Controls.Segmented" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Controls.SettingsControls" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Media" Version="8.0.230907" />
<PackageReference Include="CommunityToolkit.WinUI.Notifications" Version="7.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.12" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.12">
<PrivateAssets>all</PrivateAssets>