diff --git a/DesktopNotifications.Apple/AppleNotificationManager.cs b/DesktopNotifications.Apple/AppleNotificationManager.cs index 2513b8b..c3d657d 100644 --- a/DesktopNotifications.Apple/AppleNotificationManager.cs +++ b/DesktopNotifications.Apple/AppleNotificationManager.cs @@ -20,22 +20,22 @@ namespace DesktopNotifications.Apple public string? LaunchActionId { get; } - public ValueTask Initialize() + public Task Initialize() { - return default; + return Task.CompletedTask; } - public ValueTask ShowNotification(Notification notification, DateTimeOffset? expirationTime = null) + public Task ShowNotification(Notification notification, DateTimeOffset? expirationTime = null) { ShowNotification(); - return default; + return Task.CompletedTask; } - public ValueTask ScheduleNotification(Notification notification, DateTimeOffset deliveryTime, + public Task ScheduleNotification(Notification notification, DateTimeOffset deliveryTime, DateTimeOffset? expirationTime = null) { - return default; + return Task.CompletedTask; } } } diff --git a/DesktopNotifications.Apple/DesktopNotifications.Apple.csproj b/DesktopNotifications.Apple/DesktopNotifications.Apple.csproj index 26c116d..cb7e3ab 100644 --- a/DesktopNotifications.Apple/DesktopNotifications.Apple.csproj +++ b/DesktopNotifications.Apple/DesktopNotifications.Apple.csproj @@ -1,19 +1,27 @@  - - netcoreapp3.1;net5.0-windows10.0.17763.0 - enable - true - A cross-platform C# library for native desktop "toast" notifications. - MIT - https://github.com/pr8x/DesktopNotifications - DesktopNotifications.Apple - DesktopNotifications.Apple - DesktopNotifications.Apple - + + + netstandard2.0;net5.0 + + + netstandard2.0;net5.0-windows10.0.17763.0 + - - - + + enable + 8.0 + true + A cross-platform C# library for native desktop "toast" notifications. + MIT + https://github.com/pr8x/DesktopNotifications + DesktopNotifications.Apple + DesktopNotifications.Apple + DesktopNotifications.Apple + - + + + + + \ No newline at end of file diff --git a/DesktopNotifications.Avalonia/DesktopNotifications.Avalonia.csproj b/DesktopNotifications.Avalonia/DesktopNotifications.Avalonia.csproj index c6e5cfa..284bf15 100644 --- a/DesktopNotifications.Avalonia/DesktopNotifications.Avalonia.csproj +++ b/DesktopNotifications.Avalonia/DesktopNotifications.Avalonia.csproj @@ -1,21 +1,30 @@  - - netcoreapp3.1;net5.0-windows10.0.17763.0 - A cross-platform C# library for native desktop "toast" notifications. - true - MIT - https://github.com/pr8x/DesktopNotifications - + + + netstandard2.0;net5.0 + + + netstandard2.0;net5.0-windows10.0.17763.0 + - - - + + enable + 8.0 + A cross-platform C# library for native desktop "toast" notifications. + true + MIT + https://github.com/pr8x/DesktopNotifications + - - - - - + + + - + + + + + + + \ No newline at end of file diff --git a/DesktopNotifications.FreeDesktop/DesktopNotifications.FreeDesktop.csproj b/DesktopNotifications.FreeDesktop/DesktopNotifications.FreeDesktop.csproj index 4aff672..7030e70 100644 --- a/DesktopNotifications.FreeDesktop/DesktopNotifications.FreeDesktop.csproj +++ b/DesktopNotifications.FreeDesktop/DesktopNotifications.FreeDesktop.csproj @@ -1,20 +1,28 @@  - - netcoreapp3.1;net5.0-windows10.0.17763.0 - enable - A cross-platform C# library for native desktop "toast" notifications. - true - MIT - https://github.com/pr8x/DesktopNotifications - + + + netstandard2.0;net5.0 + + + netstandard2.0;net5.0-windows10.0.17763.0 + - - - + + enable + 8.0 + A cross-platform C# library for native desktop "toast" notifications. + true + MIT + https://github.com/pr8x/DesktopNotifications + - - - + + + - + + + + + \ No newline at end of file diff --git a/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs b/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs index ea76449..74268b2 100644 --- a/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs +++ b/DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using Tmds.DBus; @@ -41,7 +40,7 @@ namespace DesktopNotifications.FreeDesktop public string? LaunchActionId { get; } - public async ValueTask Initialize() + public async Task Initialize() { _connection = Connection.Session; @@ -62,7 +61,7 @@ namespace DesktopNotifications.FreeDesktop ); } - public async ValueTask ShowNotification(Notification notification, DateTimeOffset? expirationTime = null) + public async Task ShowNotification(Notification notification, DateTimeOffset? expirationTime = null) { if (_connection == null || _proxy == null) { @@ -91,7 +90,7 @@ namespace DesktopNotifications.FreeDesktop _activeNotifications[id] = notification; } - public async ValueTask ScheduleNotification( + public async Task ScheduleNotification( Notification notification, DateTimeOffset deliveryTime, DateTimeOffset? expirationTime = null) @@ -135,7 +134,9 @@ namespace DesktopNotifications.FreeDesktop private void OnNotificationClosed((uint id, uint reason) @event) { - _activeNotifications.Remove(@event.id, out var notification); + var notification = _activeNotifications[@event.id]; + + _activeNotifications.Remove(@event.id); //TODO: Not sure why but it calls this event twice sometimes //In this case the notification has already been removed from the dict. diff --git a/DesktopNotifications.Windows/DesktopNotifications.Windows.csproj b/DesktopNotifications.Windows/DesktopNotifications.Windows.csproj index e7a8bf4..f992d06 100644 --- a/DesktopNotifications.Windows/DesktopNotifications.Windows.csproj +++ b/DesktopNotifications.Windows/DesktopNotifications.Windows.csproj @@ -1,17 +1,36 @@  - - netcoreapp3.1;net5.0-windows10.0.17763.0 - enable - true - A cross-platform C# library for native desktop "toast" notifications. - MIT - https://github.com/pr8x/DesktopNotifications - + + + netstandard2.0;net5.0 + + + netstandard2.0;net5.0-windows10.0.17763.0 + - - - - + + 8.0 + enable + true + A cross-platform C# library for native desktop "toast" notifications. + MIT + https://github.com/pr8x/DesktopNotifications + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DesktopNotifications.Windows/NullImpl_WindowsNotificationManager.cs b/DesktopNotifications.Windows/NullImpl_WindowsNotificationManager.cs new file mode 100644 index 0000000..6f7f4d1 --- /dev/null +++ b/DesktopNotifications.Windows/NullImpl_WindowsNotificationManager.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading.Tasks; + +#pragma warning disable CS0067 + +namespace DesktopNotifications.Windows +{ + public class WindowsApplicationContext : ApplicationContext + { + public static WindowsApplicationContext FromCurrentProcess( + string? customName = null, + string? appUserModelId = null) + { + throw new PlatformNotSupportedException(); + } + + public WindowsApplicationContext(string name) : base(name) + { + throw new PlatformNotSupportedException(); + } + } + + public class WindowsNotificationManager : INotificationManager + { + public WindowsNotificationManager(WindowsApplicationContext? context = null) + { + throw new PlatformNotSupportedException(); + } + + public void Dispose() + { + throw new PlatformNotSupportedException(); + } + + public string? LaunchActionId { get; } + + public event EventHandler? NotificationActivated; + + public event EventHandler? NotificationDismissed; + + public Task Initialize() + { + throw new PlatformNotSupportedException(); + } + + public Task ShowNotification(Notification notification, DateTimeOffset? expirationTime = null) + { + throw new PlatformNotSupportedException(); + } + + public Task ScheduleNotification(Notification notification, DateTimeOffset deliveryTime, + DateTimeOffset? expirationTime = null) + { + throw new PlatformNotSupportedException(); + } + } +} \ No newline at end of file diff --git a/DesktopNotifications.Windows/WindowsNotificationManager.cs b/DesktopNotifications.Windows/WindowsNotificationManager.cs index 32ca9a2..2905330 100644 --- a/DesktopNotifications.Windows/WindowsNotificationManager.cs +++ b/DesktopNotifications.Windows/WindowsNotificationManager.cs @@ -1,10 +1,16 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Threading.Tasks; -using Windows.Data.Xml.Dom; using Windows.UI.Notifications; +using XmlDocument = Windows.Data.Xml.Dom.XmlDocument; + +#if NETSTANDARD +using System.IO; +using System.Xml; +#else +using System.Diagnostics; using Microsoft.Toolkit.Uwp.Notifications; +#endif namespace DesktopNotifications.Windows { @@ -14,7 +20,12 @@ namespace DesktopNotifications.Windows private readonly WindowsApplicationContext _applicationContext; private readonly TaskCompletionSource? _launchActionPromise; private readonly Dictionary _notifications; + +#if NETSTANDARD + private readonly ToastNotifier _toastNotifier; +#else private readonly ToastNotifierCompat _toastNotifier; +#endif /// /// @@ -24,6 +35,7 @@ namespace DesktopNotifications.Windows _applicationContext = applicationContext ?? WindowsApplicationContext.FromCurrentProcess(); _launchActionPromise = new TaskCompletionSource(); +#if !NETSTANDARD if (ToastNotificationManagerCompat.WasCurrentProcessToastActivated()) { ToastNotificationManagerCompat.OnActivated += OnAppActivated; @@ -33,8 +45,14 @@ namespace DesktopNotifications.Windows LaunchActionId = _launchActionPromise.Task.Result; } } +#endif +#if NETSTANDARD + _toastNotifier = ToastNotificationManager.CreateToastNotifier(_applicationContext.AppUserModelId); +#else _toastNotifier = ToastNotificationManagerCompat.CreateToastNotifier(); +#endif + _notifications = new Dictionary(); } @@ -44,12 +62,12 @@ namespace DesktopNotifications.Windows public string? LaunchActionId { get; } - public ValueTask Initialize() + public Task Initialize() { - return default; + return Task.CompletedTask; } - public ValueTask ShowNotification(Notification notification, DateTimeOffset? expirationTime) + public Task ShowNotification(Notification notification, DateTimeOffset? expirationTime) { if (expirationTime < DateTimeOffset.Now) { @@ -69,10 +87,10 @@ namespace DesktopNotifications.Windows _toastNotifier.Show(toastNotification); _notifications[toastNotification] = notification; - return default; + return Task.CompletedTask; } - public ValueTask ScheduleNotification( + public Task ScheduleNotification( Notification notification, DateTimeOffset deliveryTime, DateTimeOffset? expirationTime = null) @@ -90,7 +108,7 @@ namespace DesktopNotifications.Windows _toastNotifier.AddToSchedule(toastNotification); - return default; + return Task.CompletedTask; } public void Dispose() @@ -99,6 +117,57 @@ namespace DesktopNotifications.Windows private static XmlDocument GenerateXml(Notification notification) { +#if NETSTANDARD + var sw = new StringWriter(); + var xw = XmlWriter.Create(sw, new XmlWriterSettings + { + OmitXmlDeclaration = true, + Indent = true + }); + + xw.WriteStartElement("toast"); + + xw.WriteStartElement("visual"); + + xw.WriteStartElement("binding"); + + xw.WriteAttributeString("template", "ToastGeneric"); + + xw.WriteStartElement("text"); + xw.WriteString(notification.Title ?? string.Empty); + xw.WriteEndElement(); + + xw.WriteStartElement("text"); + xw.WriteString(notification.Body ?? string.Empty); + xw.WriteEndElement(); + + xw.WriteEndElement(); + + xw.WriteEndElement(); + + xw.WriteStartElement("actions"); + + foreach (var (title, actionId) in notification.Buttons) + { + xw.WriteStartElement("action"); + xw.WriteAttributeString("content", title); + xw.WriteAttributeString("activationType", "foreground"); + xw.WriteAttributeString("arguments", actionId); + xw.WriteEndElement(); + } + + xw.WriteEndElement(); + + xw.WriteEndElement(); + xw.Flush(); + + var xmlStr = sw.ToString(); + var xmlDoc = new XmlDocument(); + xmlDoc.LoadXml(xmlStr); + + return xmlDoc; + +#else var builder = new ToastContentBuilder(); builder.AddText(notification.Title); @@ -110,8 +179,11 @@ namespace DesktopNotifications.Windows } return builder.GetXml(); + +#endif } +#if !NETSTANDARD private void OnAppActivated(ToastNotificationActivatedEventArgsCompat e) { Debug.Assert(_launchActionPromise != null); @@ -119,6 +191,7 @@ namespace DesktopNotifications.Windows var actionId = GetActionId(e.Argument); _launchActionPromise.SetResult(actionId); } +#endif private static void ToastNotificationOnFailed(ToastNotification sender, ToastFailedEventArgs args) { @@ -127,11 +200,13 @@ namespace DesktopNotifications.Windows private void ToastNotificationOnDismissed(ToastNotification sender, ToastDismissedEventArgs args) { - if (!_notifications.Remove(sender, out var notification)) + if (!_notifications.TryGetValue(sender, out var notification)) { return; } + _notifications.Remove(sender); + var reason = args.Reason switch { ToastDismissalReason.UserCanceled => NotificationDismissReason.User, @@ -150,7 +225,7 @@ namespace DesktopNotifications.Windows private void ToastNotificationOnActivated(ToastNotification sender, object args) { - var activationArgs = (ToastActivatedEventArgs) args; + var activationArgs = (ToastActivatedEventArgs)args; var notification = _notifications[sender]; var actionId = GetActionId(activationArgs.Arguments); diff --git a/DesktopNotifications/DesktopNotifications.csproj b/DesktopNotifications/DesktopNotifications.csproj index 8b09245..4182b51 100644 --- a/DesktopNotifications/DesktopNotifications.csproj +++ b/DesktopNotifications/DesktopNotifications.csproj @@ -1,12 +1,20 @@  - - netcoreapp3.1;net5.0-windows10.0.17763.0 - enable - true - A cross-platform C# library for native desktop "toast" notifications. - MIT - https://github.com/pr8x/DesktopNotifications - + + + netstandard2.0;net5.0 + + + netstandard2.0;net5.0-windows10.0.17763.0 + + + + enable + 8.0 + true + A cross-platform C# library for native desktop "toast" notifications. + MIT + https://github.com/pr8x/DesktopNotifications + - + \ No newline at end of file diff --git a/DesktopNotifications/INotificationManager.cs b/DesktopNotifications/INotificationManager.cs index c25eb91..b541e58 100644 --- a/DesktopNotifications/INotificationManager.cs +++ b/DesktopNotifications/INotificationManager.cs @@ -32,14 +32,14 @@ namespace DesktopNotifications /// Initialized the notification manager. /// /// - ValueTask Initialize(); + Task Initialize(); /// /// Schedules a notification for presentation. /// /// The notification to present. /// The expiration time marking the point when the notification gets removed. - ValueTask ShowNotification(Notification notification, DateTimeOffset? expirationTime = null); + Task ShowNotification(Notification notification, DateTimeOffset? expirationTime = null); /// /// @@ -47,7 +47,7 @@ namespace DesktopNotifications /// /// /// - ValueTask ScheduleNotification( + Task ScheduleNotification( Notification notification, DateTimeOffset deliveryTime, DateTimeOffset? expirationTime = null); diff --git a/Example.Avalonia/Example.Avalonia.csproj b/Example.Avalonia/Example.Avalonia.csproj index fef03d2..cedb29f 100644 --- a/Example.Avalonia/Example.Avalonia.csproj +++ b/Example.Avalonia/Example.Avalonia.csproj @@ -1,15 +1,24 @@  - - WinExe - netcoreapp3.1;net5.0-windows10.0.17763.0 - enable - - - - - - - - - - + + + + netcoreapp3.1;net5.0 + + + netcoreapp3.1;net5.0-windows10.0.17763.0 + + + + 8.0 + WinExe + enable + + + + + + + + + + \ No newline at end of file diff --git a/Example.Avalonia/MainWindow.axaml.cs b/Example.Avalonia/MainWindow.axaml.cs index 81ddc78..faa128e 100644 --- a/Example.Avalonia/MainWindow.axaml.cs +++ b/Example.Avalonia/MainWindow.axaml.cs @@ -29,7 +29,8 @@ namespace Example.Avalonia _eventsListBox = this.FindControl("EventsListBox"); _eventsListBox.Items = new ObservableCollection(); - _notificationManager = AvaloniaLocator.Current.GetService(); + _notificationManager = AvaloniaLocator.Current.GetService() ?? + throw new InvalidOperationException("Missing notification manager"); _notificationManager.NotificationActivated += OnNotificationActivated; _notificationManager.NotificationDismissed += OnNotificationDismissed; @@ -61,7 +62,11 @@ namespace Example.Avalonia _notificationManager.ShowNotification(new Notification { Title = _titleTextBox.Text ?? _titleTextBox.Watermark, - Body = _bodyTextBox.Text ?? _bodyTextBox.Watermark + Body = _bodyTextBox.Text ?? _bodyTextBox.Watermark, + Buttons = + { + ("This is awesome!", "awesome") + } }); } diff --git a/Example/Example.csproj b/Example/Example.csproj index 6aab8ac..7ddff54 100644 --- a/Example/Example.csproj +++ b/Example/Example.csproj @@ -1,16 +1,24 @@  - - Exe - netcoreapp3.1;net5.0-windows10.0.17763.0 - enable - + + + netstandard2.0;net5.0 + + + netstandard2.0;net5.0-windows10.0.17763.0 + - - - - - - + + Exe + enable + 8.0 + - + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 4d24038..c4938b7 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,14 @@ A cross-platform C# library for native desktop "toast" notifications. |--------------------------|---------|---------------------|-----| | Show notifications | ✓ | ✓ | ✕ | | Schedule notifications | ✓ | ✓* | ✕ | -| Launch actions** | ✓ | ✕ | ✕ | +| Launch actions** | ✓*** | ✕ | ✕ | | Replacing notifications | ✕ | ✕ | ✕ | | Buttons | ✓ | ✓ | ✕ | | Advanced content (Audio, Images, etc) | ✕ | ✕ | ✕ | * Scheduled notifications will only be delivered while the application is running. - ** Some platforms support launching your application when the user clicked a notification. The associated action identifier is passed as a command-line argument. + ** Some platforms support launching your application when the user clicked a notification. The associated action identifier is passed as a command-line argument. + *** This is currently not supported when targeting .netstandard # Application Context