From 94b79ea981f5a4068cdcc4bfe03561b99b9454fb Mon Sep 17 00:00:00 2001 From: Luis von der Eltz Date: Sun, 7 Feb 2021 17:28:34 +0100 Subject: [PATCH] Rework launch action propagatioon on Windows --- .../AppleNotificationManager.cs | 6 +- .../AppBuilderExtensions.cs | 47 ++++++------ .../FreeDesktopNotificationManager.cs | 2 + .../WindowsApplicationContext.cs | 10 +-- .../WindowsNotificationManager.cs | 73 ++++++++----------- DesktopNotifications/ApplicationContext.cs | 11 +-- DesktopNotifications/INotificationManager.cs | 8 +- DesktopNotifications/NotificationEventArgs.cs | 1 - Example.Avalonia/MainWindow.axaml.cs | 5 ++ 9 files changed, 78 insertions(+), 85 deletions(-) diff --git a/DesktopNotifications.Apple/AppleNotificationManager.cs b/DesktopNotifications.Apple/AppleNotificationManager.cs index a65b15d..0476ce4 100644 --- a/DesktopNotifications.Apple/AppleNotificationManager.cs +++ b/DesktopNotifications.Apple/AppleNotificationManager.cs @@ -15,8 +15,10 @@ namespace DesktopNotifications.Apple { } - public event EventHandler NotificationActivated; - public event EventHandler NotificationDismissed; + public event EventHandler? NotificationActivated; + public event EventHandler? NotificationDismissed; + + public string? LaunchActionId { get; } public ValueTask Initialize() { diff --git a/DesktopNotifications.Avalonia/AppBuilderExtensions.cs b/DesktopNotifications.Avalonia/AppBuilderExtensions.cs index f5abe94..5280b63 100644 --- a/DesktopNotifications.Avalonia/AppBuilderExtensions.cs +++ b/DesktopNotifications.Avalonia/AppBuilderExtensions.cs @@ -21,35 +21,34 @@ namespace DesktopNotifications.Avalonia public static TAppBuilder SetupDesktopNotifications(this TAppBuilder builder) where TAppBuilder : AppBuilderBase, new() { - return builder.AfterSetup(async b => + INotificationManager manager; + var runtimeInfo = builder.RuntimePlatform.GetRuntimeInfo(); + + switch (runtimeInfo.OperatingSystem) { - var runtimeInfo = b.RuntimePlatform.GetRuntimeInfo(); - INotificationManager manager; - - switch (runtimeInfo.OperatingSystem) + case OperatingSystemType.WinNT: { - case OperatingSystemType.WinNT: - { - var context = WindowsApplicationContext.FromCurrentProcess(b.Instance.Name); - manager = new WindowsNotificationManager(context); - break; - } - - case OperatingSystemType.Linux: - { - var context = FreeDesktopApplicationContext.FromCurrentProcess(); - manager = new FreeDesktopNotificationManager(context); - break; - } - - //TODO: OSX once implemented/stable - default: return; + var context = WindowsApplicationContext.FromCurrentProcess(); + manager = new WindowsNotificationManager(context); + break; } - await manager.Initialize(); + case OperatingSystemType.Linux: + { + var context = FreeDesktopApplicationContext.FromCurrentProcess(); + manager = new FreeDesktopNotificationManager(context); + break; + } - AvaloniaLocator.CurrentMutable.Bind().ToConstant(manager); - }); + //TODO: OSX once implemented/stable + default: return builder; + } + + //manager.Initialize(); + + AvaloniaLocator.CurrentMutable.Bind().ToConstant(manager); + + return builder; } } } \ No newline at end of file diff --git a/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs b/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs index 6f1b860..f1600c8 100644 --- a/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs +++ b/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs @@ -39,6 +39,8 @@ namespace DesktopNotifications.FreeDesktop public event EventHandler? NotificationActivated; public event EventHandler? NotificationDismissed; + public string? LaunchActionId { get; } + public async ValueTask Initialize() { _connection = Connection.Session; diff --git a/DesktopNotifications.Windows/WindowsApplicationContext.cs b/DesktopNotifications.Windows/WindowsApplicationContext.cs index 01e37e6..537e7ef 100644 --- a/DesktopNotifications.Windows/WindowsApplicationContext.cs +++ b/DesktopNotifications.Windows/WindowsApplicationContext.cs @@ -18,15 +18,16 @@ namespace DesktopNotifications.Windows private static extern void SetCurrentProcessExplicitAppUserModelID( [MarshalAs(UnmanagedType.LPWStr)] string appId); - public static WindowsApplicationContext FromCurrentProcess(string? customName = null, + public static WindowsApplicationContext FromCurrentProcess( + string? customName = null, string? appUserModelId = null) { - var aumid = appUserModelId ?? Guid.NewGuid().ToString(); + var mainModule = Process.GetCurrentProcess().MainModule; + var appName = customName ?? Path.GetFileNameWithoutExtension(mainModule.FileName); + var aumid = appUserModelId ?? appName; //TODO: Add seeded bits to avoid collisions? SetCurrentProcessExplicitAppUserModelID(aumid); - var mainModule = Process.GetCurrentProcess().MainModule; - using var shortcut = new ShellLink { TargetPath = mainModule.FileName, @@ -36,7 +37,6 @@ namespace DesktopNotifications.Windows var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); var startMenuPath = Path.Combine(appData, @"Microsoft\Windows\Start Menu\Programs"); - var appName = customName ?? Path.GetFileNameWithoutExtension(mainModule.FileName); var shortcutFile = Path.Combine(startMenuPath, $"{appName}.lnk"); shortcut.Save(shortcutFile); diff --git a/DesktopNotifications.Windows/WindowsNotificationManager.cs b/DesktopNotifications.Windows/WindowsNotificationManager.cs index cec85df..cb51201 100644 --- a/DesktopNotifications.Windows/WindowsNotificationManager.cs +++ b/DesktopNotifications.Windows/WindowsNotificationManager.cs @@ -10,12 +10,11 @@ namespace DesktopNotifications.Windows { public class WindowsNotificationManager : INotificationManager { + private const int LaunchNotificationWaitMs = 5_000; private readonly WindowsApplicationContext _applicationContext; + private readonly TaskCompletionSource? _launchActionPromise; private readonly Dictionary _notifications; private readonly ToastNotifier _toastNotifier; - private string? _launchAction; - private TaskCompletionSource? _launchActionPromise; - private EventHandler? _notificationActivatedHandler; /// /// @@ -23,35 +22,31 @@ namespace DesktopNotifications.Windows public WindowsNotificationManager(WindowsApplicationContext? applicationContext = null) { _applicationContext = applicationContext ?? WindowsApplicationContext.FromCurrentProcess(); - _toastNotifier = ToastNotificationManager.CreateToastNotifier(_applicationContext.AppUserModelId); + _launchActionPromise = new TaskCompletionSource(); + + if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) + { + ToastNotificationManagerCompat.OnActivated += OnAppActivated; + + if (_launchActionPromise.Task.Wait(LaunchNotificationWaitMs)) + { + LaunchActionId = _launchActionPromise.Task.Result; + } + } + + _toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); _notifications = new Dictionary(); } - public event EventHandler? NotificationActivated - { - add - { - _notificationActivatedHandler += value; - ProcessLaunchAction(); - } - remove => _notificationActivatedHandler -= value; - } + public event EventHandler? NotificationActivated; public event EventHandler? NotificationDismissed; - public async ValueTask Initialize() + public string? LaunchActionId { get; } + + public ValueTask Initialize() { - if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) - { - _launchActionPromise = new TaskCompletionSource(); - ToastNotificationManagerCompat.OnActivated += OnAppActivated; - - _launchAction = await _launchActionPromise.Task; - - Debug.Assert(_launchAction != null); - - ProcessLaunchAction(); - } + return default; } public ValueTask ShowNotification(Notification notification, DateTimeOffset? expirationTime) @@ -79,20 +74,7 @@ namespace DesktopNotifications.Windows public void Dispose() { - } - - private void ProcessLaunchAction() - { - if (_launchAction == null || _notificationActivatedHandler == null) - { - return; - } - - //TODO: Lookup notification object from history? - _notificationActivatedHandler.Invoke(this, - new NotificationActivatedEventArgs(null!, _launchAction)); - - _launchAction = null; + ToastNotificationManagerCompat.Uninstall(); } private static XmlDocument GenerateXml(Notification notification) @@ -113,7 +95,9 @@ namespace DesktopNotifications.Windows private void OnAppActivated(ToastNotificationActivatedEventArgsCompat e) { Debug.Assert(_launchActionPromise != null); - _launchActionPromise.SetResult(e.Argument); + + var actionId = GetActionId(e.Argument); + _launchActionPromise.SetResult(actionId); } private static void ToastNotificationOnFailed(ToastNotification sender, ToastFailedEventArgs args) @@ -137,13 +121,18 @@ namespace DesktopNotifications.Windows _notifications.Remove(sender); } + private static string GetActionId(string argument) + { + return string.IsNullOrEmpty(argument) ? "default" : argument; + } + private void ToastNotificationOnActivated(ToastNotification sender, object args) { var activationArgs = (ToastActivatedEventArgs) args; var notification = _notifications[sender]; - var actionId = string.IsNullOrEmpty(activationArgs.Arguments) ? "default" : activationArgs.Arguments; + var actionId = GetActionId(activationArgs.Arguments); - _notificationActivatedHandler?.Invoke(this, new NotificationActivatedEventArgs(notification, actionId)); + NotificationActivated?.Invoke(this, new NotificationActivatedEventArgs(notification, actionId)); } } } \ No newline at end of file diff --git a/DesktopNotifications/ApplicationContext.cs b/DesktopNotifications/ApplicationContext.cs index 6afc75e..1a02081 100644 --- a/DesktopNotifications/ApplicationContext.cs +++ b/DesktopNotifications/ApplicationContext.cs @@ -1,11 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace DesktopNotifications +namespace DesktopNotifications { /// - /// /// public class ApplicationContext { @@ -15,9 +10,7 @@ namespace DesktopNotifications } /// - /// /// public string Name { get; } - } -} +} \ No newline at end of file diff --git a/DesktopNotifications/INotificationManager.cs b/DesktopNotifications/INotificationManager.cs index 40f7ae2..ab3ff42 100644 --- a/DesktopNotifications/INotificationManager.cs +++ b/DesktopNotifications/INotificationManager.cs @@ -8,18 +8,22 @@ namespace DesktopNotifications /// public interface INotificationManager : IDisposable { + /// + /// + string? LaunchActionId { get; } + /// /// Raised when a notification was activated. The notion of "activation" varies from platform to platform. /// event EventHandler NotificationActivated; /// - /// Raised when a notification was dismissed. The exact reason can be found in . + /// Raised when a notification was dismissed. The exact reason can be found in + /// . /// event EventHandler NotificationDismissed; /// - /// /// /// ValueTask Initialize(); diff --git a/DesktopNotifications/NotificationEventArgs.cs b/DesktopNotifications/NotificationEventArgs.cs index f037370..52adb6f 100644 --- a/DesktopNotifications/NotificationEventArgs.cs +++ b/DesktopNotifications/NotificationEventArgs.cs @@ -10,7 +10,6 @@ } /// - /// /// public Notification Notification { get; } } diff --git a/Example.Avalonia/MainWindow.axaml.cs b/Example.Avalonia/MainWindow.axaml.cs index 5355b0f..0b382b8 100644 --- a/Example.Avalonia/MainWindow.axaml.cs +++ b/Example.Avalonia/MainWindow.axaml.cs @@ -31,6 +31,11 @@ namespace Example.Avalonia _notificationManager = AvaloniaLocator.Current.GetService(); _notificationManager.NotificationActivated += OnNotificationActivated; _notificationManager.NotificationDismissed += OnNotificationDismissed; + + if (_notificationManager.LaunchActionId != null) + { + ((IList) _eventsListBox.Items).Add($"Launch action: {_notificationManager.LaunchActionId}"); + } } private void OnNotificationDismissed(object? sender, NotificationDismissedEventArgs e)