Rework launch action propagatioon on Windows

This commit is contained in:
Luis von der Eltz
2021-02-07 17:28:34 +01:00
parent 832837cee2
commit 94b79ea981
9 changed files with 78 additions and 85 deletions
@@ -15,8 +15,10 @@ namespace DesktopNotifications.Apple
{
}
public event EventHandler<NotificationActivatedEventArgs> NotificationActivated;
public event EventHandler<NotificationDismissedEventArgs> NotificationDismissed;
public event EventHandler<NotificationActivatedEventArgs>? NotificationActivated;
public event EventHandler<NotificationDismissedEventArgs>? NotificationDismissed;
public string? LaunchActionId { get; }
public ValueTask Initialize()
{
@@ -21,35 +21,34 @@ namespace DesktopNotifications.Avalonia
public static TAppBuilder SetupDesktopNotifications<TAppBuilder>(this TAppBuilder builder)
where TAppBuilder : AppBuilderBase<TAppBuilder>, 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<INotificationManager>().ToConstant(manager);
});
//TODO: OSX once implemented/stable
default: return builder;
}
//manager.Initialize();
AvaloniaLocator.CurrentMutable.Bind<INotificationManager>().ToConstant(manager);
return builder;
}
}
}
@@ -39,6 +39,8 @@ namespace DesktopNotifications.FreeDesktop
public event EventHandler<NotificationActivatedEventArgs>? NotificationActivated;
public event EventHandler<NotificationDismissedEventArgs>? NotificationDismissed;
public string? LaunchActionId { get; }
public async ValueTask Initialize()
{
_connection = Connection.Session;
@@ -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);
@@ -10,12 +10,11 @@ namespace DesktopNotifications.Windows
{
public class WindowsNotificationManager : INotificationManager
{
private const int LaunchNotificationWaitMs = 5_000;
private readonly WindowsApplicationContext _applicationContext;
private readonly TaskCompletionSource<string>? _launchActionPromise;
private readonly Dictionary<ToastNotification, Notification> _notifications;
private readonly ToastNotifier _toastNotifier;
private string? _launchAction;
private TaskCompletionSource<string?>? _launchActionPromise;
private EventHandler<NotificationActivatedEventArgs>? _notificationActivatedHandler;
/// <summary>
/// </summary>
@@ -23,35 +22,31 @@ namespace DesktopNotifications.Windows
public WindowsNotificationManager(WindowsApplicationContext? applicationContext = null)
{
_applicationContext = applicationContext ?? WindowsApplicationContext.FromCurrentProcess();
_toastNotifier = ToastNotificationManager.CreateToastNotifier(_applicationContext.AppUserModelId);
_launchActionPromise = new TaskCompletionSource<string>();
if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
{
ToastNotificationManagerCompat.OnActivated += OnAppActivated;
if (_launchActionPromise.Task.Wait(LaunchNotificationWaitMs))
{
LaunchActionId = _launchActionPromise.Task.Result;
}
}
_toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier();
_notifications = new Dictionary<ToastNotification, Notification>();
}
public event EventHandler<NotificationActivatedEventArgs>? NotificationActivated
{
add
{
_notificationActivatedHandler += value;
ProcessLaunchAction();
}
remove => _notificationActivatedHandler -= value;
}
public event EventHandler<NotificationActivatedEventArgs>? NotificationActivated;
public event EventHandler<NotificationDismissedEventArgs>? NotificationDismissed;
public async ValueTask Initialize()
public string? LaunchActionId { get; }
public ValueTask Initialize()
{
if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated())
{
_launchActionPromise = new TaskCompletionSource<string?>();
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));
}
}
}
+2 -9
View File
@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace DesktopNotifications
namespace DesktopNotifications
{
/// <summary>
///
/// </summary>
public class ApplicationContext
{
@@ -15,9 +10,7 @@ namespace DesktopNotifications
}
/// <summary>
///
/// </summary>
public string Name { get; }
}
}
}
+6 -2
View File
@@ -8,18 +8,22 @@ namespace DesktopNotifications
/// </summary>
public interface INotificationManager : IDisposable
{
/// <summary>
/// </summary>
string? LaunchActionId { get; }
/// <summary>
/// Raised when a notification was activated. The notion of "activation" varies from platform to platform.
/// </summary>
event EventHandler<NotificationActivatedEventArgs> NotificationActivated;
/// <summary>
/// Raised when a notification was dismissed. The exact reason can be found in <see cref="NotificationDismissedEventArgs"/>.
/// Raised when a notification was dismissed. The exact reason can be found in
/// <see cref="NotificationDismissedEventArgs" />.
/// </summary>
event EventHandler<NotificationDismissedEventArgs> NotificationDismissed;
/// <summary>
///
/// </summary>
/// <returns></returns>
ValueTask Initialize();
@@ -10,7 +10,6 @@
}
/// <summary>
///
/// </summary>
public Notification Notification { get; }
}
+5
View File
@@ -31,6 +31,11 @@ namespace Example.Avalonia
_notificationManager = AvaloniaLocator.Current.GetService<INotificationManager>();
_notificationManager.NotificationActivated += OnNotificationActivated;
_notificationManager.NotificationDismissed += OnNotificationDismissed;
if (_notificationManager.LaunchActionId != null)
{
((IList<string>) _eventsListBox.Items).Add($"Launch action: {_notificationManager.LaunchActionId}");
}
}
private void OnNotificationDismissed(object? sender, NotificationDismissedEventArgs e)