From 502fb6dbed3c0b26608b49a15e02f9f8e82c4fb2 Mon Sep 17 00:00:00 2001
From: DismissedLight <1686188646@qq.com>
Date: Sun, 16 Jun 2024 17:27:20 +0800
Subject: [PATCH] fix notification activation
---
src/Snap.Hutao/Snap.Hutao/App.xaml.cs | 11 +-
.../Core/LifeCycle/AppActivation.cs | 237 ++++++++----------
.../AppActivationArgumentsExtensions.cs | 25 +-
.../LifeCycle/HutaoActivationArguments.cs | 24 +-
.../Core/LifeCycle/HutaoActivationKind.cs | 2 +-
.../Core/LifeCycle/IAppActivation.cs | 2 +-
.../Job/DailyNoteRefreshJobScheduler.cs | 2 +-
7 files changed, 137 insertions(+), 166 deletions(-)
diff --git a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs
index d084385a..4e950dc9 100644
--- a/src/Snap.Hutao/Snap.Hutao/App.xaml.cs
+++ b/src/Snap.Hutao/Snap.Hutao/App.xaml.cs
@@ -71,7 +71,7 @@ public sealed partial class App : Application
{
// Important: You must call AppNotificationManager::Default().Register
// before calling AppInstance.GetCurrent.GetActivatedEventArgs.
- AppNotificationManager.Default.NotificationInvoked += activation.NotificationActivate;
+ AppNotificationManager.Default.NotificationInvoked += activation.NotificationInvoked;
AppNotificationManager.Default.Register();
AppActivationArguments activatedEventArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
@@ -85,15 +85,8 @@ public sealed partial class App : Application
logger.LogColorizedInformation((ConsoleBanner, ConsoleColor.DarkYellow));
LogDiagnosticInformation();
- HutaoActivationArguments hutaoArgs = HutaoActivationArguments.FromAppActivationArguments(activatedEventArgs);
- if (hutaoArgs.Kind is HutaoActivationKind.Toast)
- {
- Exit();
- return;
- }
-
// Manually invoke
- activation.Activate(hutaoArgs);
+ activation.Activate(HutaoActivationArguments.FromAppActivationArguments(activatedEventArgs));
activation.PostInitialization();
}
catch (Exception ex)
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivation.cs
index 4fef7e60..9eb7cf3a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivation.cs
@@ -11,7 +11,6 @@ using Snap.Hutao.Core.Windowing;
using Snap.Hutao.Core.Windowing.HotKey;
using Snap.Hutao.Core.Windowing.NotifyIcon;
using Snap.Hutao.Service;
-using Snap.Hutao.Service.DailyNote;
using Snap.Hutao.Service.Discord;
using Snap.Hutao.Service.Hutao;
using Snap.Hutao.Service.Job;
@@ -37,9 +36,7 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
public const string ImportUIAFFromClipboard = nameof(ImportUIAFFromClipboard);
private const string CategoryAchievement = "ACHIEVEMENT";
- private const string CategoryDailyNote = "DAILYNOTE";
private const string UrlActionImport = "/IMPORT";
- private const string UrlActionRefresh = "/REFRESH";
private readonly ICurrentXamlWindowReference currentWindowReference;
private readonly IServiceProvider serviceProvider;
@@ -50,21 +47,49 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
///
public void Activate(HutaoActivationArguments args)
{
- HandleActivationAsync(args).SafeForget();
- }
+ HandleActivationExclusiveAsync(args).SafeForget();
- public void NotificationActivate(AppNotificationManager manager, AppNotificationActivatedEventArgs args)
- {
- if (args.Arguments.TryGetValue(Action, out string? action))
+ async ValueTask HandleActivationExclusiveAsync(HutaoActivationArguments args)
{
- if (action == LaunchGame)
+ await taskContext.SwitchToBackgroundAsync();
+
+ if (activateSemaphore.CurrentCount > 0)
{
- _ = args.Arguments.TryGetValue(Uid, out string? uid);
- HandleLaunchGameActionAsync(uid).SafeForget();
+ using (await activateSemaphore.EnterAsync().ConfigureAwait(false))
+ {
+ switch (args.Kind)
+ {
+ case HutaoActivationKind.Protocol:
+ {
+ ArgumentNullException.ThrowIfNull(args.ProtocolActivatedUri);
+ await HandleProtocolActivationAsync(args.ProtocolActivatedUri, args.IsRedirectTo).ConfigureAwait(false);
+ break;
+ }
+
+ case HutaoActivationKind.Launch:
+ {
+ ArgumentNullException.ThrowIfNull(args.LaunchActivatedArguments);
+ await HandleLaunchActivationAsync(args.IsRedirectTo).ConfigureAwait(false);
+ break;
+ }
+
+ case HutaoActivationKind.AppNotification:
+ {
+ ArgumentNullException.ThrowIfNull(args.AppNotificationActivatedArguments);
+ await HandleAppNotificationActivationAsync(args.AppNotificationActivatedArguments, args.IsRedirectTo).ConfigureAwait(false);
+ break;
+ }
+ }
+ }
}
}
}
+ public void NotificationInvoked(AppNotificationManager manager, AppNotificationActivatedEventArgs args)
+ {
+ HandleAppNotificationActivationAsync(args.Arguments, false).SafeForget();
+ }
+
///
public void PostInitialization()
{
@@ -74,19 +99,22 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
{
await taskContext.SwitchToBackgroundAsync();
- serviceProvider.GetRequiredService().RunAsync().SafeForget();
-
using (await activateSemaphore.EnterAsync().ConfigureAwait(false))
{
// TODO: Introduced in 1.10.2, remove in later version
- serviceProvider.GetRequiredService().ClearAsync().SafeForget();
- serviceProvider.GetRequiredService().UnregisterAllTasks();
+ {
+ serviceProvider.GetRequiredService().ClearAsync().SafeForget();
+ serviceProvider.GetRequiredService().UnregisterAllTasks();
+ }
if (UnsafeLocalSetting.Get(SettingKeys.Major1Minor10Revision0GuideState, GuideState.Language) < GuideState.Completed)
{
return;
}
+ serviceProvider.GetRequiredService().RunAsync().SafeForget();
+
+ // RegisterHotKey should be called from main thread
await taskContext.SwitchToMainThreadAsync();
serviceProvider.GetRequiredService().RegisterAll();
@@ -99,7 +127,18 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
_ = serviceProvider.GetRequiredService();
}
- serviceProvider.GetRequiredService().StartAsync(default).SafeForget();
+ serviceProvider.GetRequiredService().SetNormalActivityAsync().SafeForget();
+ serviceProvider.GetRequiredService().StartAsync().SafeForget();
+
+ if (serviceProvider.GetRequiredService() is IMetadataServiceInitialization metadataServiceInitialization)
+ {
+ metadataServiceInitialization.InitializeInternalAsync().SafeForget();
+ }
+
+ if (serviceProvider.GetRequiredService() is IHutaoUserServiceInitialization hutaoUserServiceInitialization)
+ {
+ hutaoUserServiceInitialization.InitializeInternalAsync().SafeForget();
+ }
}
}
}
@@ -145,38 +184,36 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
}
}
- private async ValueTask HandleActivationAsync(HutaoActivationArguments args)
+ private async ValueTask HandleProtocolActivationAsync(Uri uri, bool isRedirectTo)
{
- await taskContext.SwitchToBackgroundAsync();
+ UriBuilder builder = new(uri);
- if (activateSemaphore.CurrentCount > 0)
+ string category = builder.Host.ToUpperInvariant();
+ string action = builder.Path.ToUpperInvariant();
+
+ // string parameter = builder.Query.ToUpperInvariant();
+ switch (category)
{
- using (await activateSemaphore.EnterAsync().ConfigureAwait(false))
- {
- await HandleActivationCoreAsync(args).ConfigureAwait(false);
- }
- }
- }
-
- private async ValueTask HandleActivationCoreAsync(HutaoActivationArguments args)
- {
- switch (args.Kind)
- {
- case HutaoActivationKind.Protocol:
+ case CategoryAchievement:
{
- ArgumentNullException.ThrowIfNull(args.ProtocolActivatedUri);
- await HandleUrlActivationAsync(args.ProtocolActivatedUri, args.IsRedirectTo).ConfigureAwait(false);
- break;
- }
-
- case HutaoActivationKind.Launch:
- {
- ArgumentNullException.ThrowIfNull(args.LaunchActivatedArguments);
- switch (args.LaunchActivatedArguments)
+ await WaitMainWindowOrCurrentAsync().ConfigureAwait(false);
+ if (currentWindowReference.Window is not MainWindow)
{
- default:
+ // TODO: Send notification to hint?
+ return;
+ }
+
+ switch (action)
+ {
+ case UrlActionImport:
{
- await HandleNormalLaunchActionAsync(args.IsRedirectTo).ConfigureAwait(false);
+ await taskContext.SwitchToMainThreadAsync();
+
+ INavigationAwaiter navigationAwaiter = new NavigationExtra(ImportUIAFFromClipboard);
+ await serviceProvider
+ .GetRequiredService()
+ .NavigateAsync(navigationAwaiter, true)
+ .ConfigureAwait(false);
break;
}
}
@@ -184,14 +221,15 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
break;
}
- case HutaoActivationKind.Toast:
+ default:
{
+ await HandleLaunchActivationAsync(isRedirectTo).ConfigureAwait(false);
break;
}
}
}
- private async ValueTask HandleNormalLaunchActionAsync(bool isRedirectTo)
+ private async ValueTask HandleLaunchActivationAsync(bool isRedirectTo)
{
if (!isRedirectTo)
{
@@ -223,6 +261,22 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
await WaitMainWindowOrCurrentAsync().ConfigureAwait(false);
}
+ private async ValueTask HandleAppNotificationActivationAsync(IDictionary arguments, bool isRedirectTo)
+ {
+ if (arguments.TryGetValue(Action, out string? action))
+ {
+ if (action == LaunchGame)
+ {
+ _ = arguments.TryGetValue(Uid, out string? uid);
+ await HandleLaunchGameActionAsync(uid).ConfigureAwait(false);
+ }
+ }
+ else
+ {
+ await HandleLaunchActivationAsync(isRedirectTo).ConfigureAwait(false);
+ }
+ }
+
private async ValueTask WaitMainWindowOrCurrentAsync()
{
if (currentWindowReference.Window is { } window)
@@ -239,100 +293,5 @@ internal sealed partial class AppActivation : IAppActivation, IAppActivationActi
mainWindow.SwitchTo();
mainWindow.BringToForeground();
-
- await taskContext.SwitchToBackgroundAsync();
-
- if (serviceProvider.GetRequiredService() is IMetadataServiceInitialization metadataServiceInitialization)
- {
- metadataServiceInitialization.InitializeInternalAsync().SafeForget();
- }
-
- if (serviceProvider.GetRequiredService() is IHutaoUserServiceInitialization hutaoUserServiceInitialization)
- {
- hutaoUserServiceInitialization.InitializeInternalAsync().SafeForget();
- }
-
- serviceProvider.GetRequiredService().SetNormalActivityAsync().SafeForget();
- }
-
- private async ValueTask HandleUrlActivationAsync(Uri uri, bool isRedirectTo)
- {
- UriBuilder builder = new(uri);
-
- string category = builder.Host.ToUpperInvariant();
- string action = builder.Path.ToUpperInvariant();
- string parameter = builder.Query.ToUpperInvariant();
-
- switch (category)
- {
- case CategoryAchievement:
- {
- await WaitMainWindowOrCurrentAsync().ConfigureAwait(false);
- await HandleAchievementActionAsync(action, parameter, isRedirectTo).ConfigureAwait(false);
- break;
- }
-
- case CategoryDailyNote:
- {
- await HandleDailyNoteActionAsync(action, parameter, isRedirectTo).ConfigureAwait(false);
- break;
- }
-
- default:
- {
- await HandleNormalLaunchActionAsync(isRedirectTo).ConfigureAwait(false);
- break;
- }
- }
- }
-
- private async ValueTask HandleAchievementActionAsync(string action, string parameter, bool isRedirectTo)
- {
- _ = parameter;
- _ = isRedirectTo;
- switch (action)
- {
- case UrlActionImport:
- {
- await taskContext.SwitchToMainThreadAsync();
-
- INavigationAwaiter navigationAwaiter = new NavigationExtra(ImportUIAFFromClipboard);
- await serviceProvider
- .GetRequiredService()
- .NavigateAsync(navigationAwaiter, true)
- .ConfigureAwait(false);
- break;
- }
- }
- }
-
- private async ValueTask HandleDailyNoteActionAsync(string action, string parameter, bool isRedirectTo)
- {
- _ = parameter;
- switch (action)
- {
- case UrlActionRefresh:
- {
- try
- {
- await serviceProvider
- .GetRequiredService()
- .RefreshDailyNotesAsync()
- .ConfigureAwait(false);
- }
- catch
- {
- }
-
- // Check if it's redirected.
- if (!isRedirectTo)
- {
- // It's a direct open process, should exit immediately.
- Process.GetCurrentProcess().Kill();
- }
-
- break;
- }
- }
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs
index 2fc31d32..fc69033f 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/AppActivationArgumentsExtensions.cs
@@ -1,8 +1,8 @@
// Copyright (c) DGP Studio. All rights reserved.
// Licensed under the MIT license.
-using Microsoft.Extensions.Primitives;
using Microsoft.Windows.AppLifecycle;
+using Microsoft.Windows.AppNotifications;
using Windows.ApplicationModel.Activation;
namespace Snap.Hutao.Core.LifeCycle;
@@ -25,10 +25,9 @@ internal static class AppActivationArgumentsExtensions
return true;
}
- public static bool TryGetLaunchActivatedArguments(this AppActivationArguments activatedEventArgs, [NotNullWhen(true)] out string? arguments, out bool isToastActivated)
+ public static bool TryGetLaunchActivatedArguments(this AppActivationArguments activatedEventArgs, [NotNullWhen(true)] out string? arguments)
{
arguments = null;
- isToastActivated = false;
if (activatedEventArgs.Data is not ILaunchActivatedEventArgs launchArgs)
{
@@ -36,15 +35,23 @@ internal static class AppActivationArgumentsExtensions
}
arguments = launchArgs.Arguments.Trim();
- foreach (StringSegment segment in new StringTokenizer(arguments, [' ']))
+ return true;
+ }
+
+ public static bool TryGetAppNotificationActivatedArguments(this AppActivationArguments activatedEventArgs, out string? argument, [NotNullWhen(true)] out IDictionary? arguments, [NotNullWhen(true)] out IDictionary? userInput)
+ {
+ argument = null;
+ arguments = null;
+ userInput = null;
+
+ if (activatedEventArgs.Data is not AppNotificationActivatedEventArgs appNotificationArgs)
{
- if (segment.AsSpan().SequenceEqual("----AppNotificationActivated:"))
- {
- isToastActivated = true;
- break;
- }
+ return false;
}
+ argument = appNotificationArgs.Argument;
+ arguments = appNotificationArgs.Arguments;
+ userInput = appNotificationArgs.UserInput;
return true;
}
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationArguments.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationArguments.cs
index 3fa39818..7b71f052 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationArguments.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationArguments.cs
@@ -15,6 +15,10 @@ internal sealed class HutaoActivationArguments
public string? LaunchActivatedArguments { get; set; }
+ public IDictionary? AppNotificationActivatedArguments { get; set; }
+
+ public IDictionary? AppNotificationActivatedUserInput { get; set; }
+
public static HutaoActivationArguments FromAppActivationArguments(AppActivationArguments args, bool isRedirected = false)
{
HutaoActivationArguments result = new()
@@ -27,14 +31,9 @@ internal sealed class HutaoActivationArguments
case ExtendedActivationKind.Launch:
{
result.Kind = HutaoActivationKind.Launch;
-
- if (args.TryGetLaunchActivatedArguments(out string? arguments, out bool isToastActivated))
+ if (args.TryGetLaunchActivatedArguments(out string? arguments))
{
result.LaunchActivatedArguments = arguments;
- if (isToastActivated)
- {
- result.Kind = HutaoActivationKind.Toast;
- }
}
break;
@@ -48,6 +47,19 @@ internal sealed class HutaoActivationArguments
result.ProtocolActivatedUri = uri;
}
+ break;
+ }
+
+ case ExtendedActivationKind.AppNotification:
+ {
+ result.Kind = HutaoActivationKind.AppNotification;
+ if (args.TryGetAppNotificationActivatedArguments(out string? argument, out IDictionary? arguments, out IDictionary? userInput))
+ {
+ result.LaunchActivatedArguments = argument;
+ result.AppNotificationActivatedArguments = arguments;
+ result.AppNotificationActivatedUserInput = userInput;
+ }
+
break;
}
}
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationKind.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationKind.cs
index 66211290..8bce6505 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationKind.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/HutaoActivationKind.cs
@@ -7,6 +7,6 @@ internal enum HutaoActivationKind
{
None,
Launch,
- Toast,
+ AppNotification,
Protocol,
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IAppActivation.cs b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IAppActivation.cs
index 075894fa..c14d95e3 100644
--- a/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IAppActivation.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Core/LifeCycle/IAppActivation.cs
@@ -9,7 +9,7 @@ internal interface IAppActivation
{
void Activate(HutaoActivationArguments args);
- void NotificationActivate(AppNotificationManager manager, AppNotificationActivatedEventArgs args);
+ void NotificationInvoked(AppNotificationManager manager, AppNotificationActivatedEventArgs args);
void PostInitialization();
}
\ No newline at end of file
diff --git a/src/Snap.Hutao/Snap.Hutao/Service/Job/DailyNoteRefreshJobScheduler.cs b/src/Snap.Hutao/Snap.Hutao/Service/Job/DailyNoteRefreshJobScheduler.cs
index 9635e576..14837f3a 100644
--- a/src/Snap.Hutao/Snap.Hutao/Service/Job/DailyNoteRefreshJobScheduler.cs
+++ b/src/Snap.Hutao/Snap.Hutao/Service/Job/DailyNoteRefreshJobScheduler.cs
@@ -25,8 +25,8 @@ internal sealed partial class DailyNoteRefreshJobScheduler : IJobScheduler
ITrigger dailyNoteTrigger = TriggerBuilder.Create()
.WithIdentity(JobIdentity.DailyNoteRefreshTriggerName, JobIdentity.DailyNoteGroupName)
- .StartNow()
.WithSimpleSchedule(builder => builder.WithIntervalInSeconds(interval).RepeatForever())
+ .StartAt(DateTimeOffset.Now.AddSeconds(interval))
.Build();
await scheduler.ScheduleJob(dailyNoteJob, dailyNoteTrigger).ConfigureAwait(false);