Skip to content

Commit

Permalink
HideNotification (#18)
Browse files Browse the repository at this point in the history
* HideNotification support

* Fix warning
  • Loading branch information
pr8x committed Jun 22, 2023
1 parent 76e84b0 commit c9440df
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 31 deletions.
5 changes: 5 additions & 0 deletions DesktopNotifications.Apple/AppleNotificationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,10 @@ public Task ScheduleNotification(Notification notification, DateTimeOffset deliv
{
return Task.CompletedTask;
}

public Task HideNotification(Notification notification)
{
return Task.CompletedTask;
}
}
}
34 changes: 26 additions & 8 deletions DesktopNotifications.FreeDesktop/FreeDesktopNotificationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Threading.Tasks;
using Tmds.DBus;
using static DesktopNotifications.Extensions;

namespace DesktopNotifications.FreeDesktop
{
Expand Down Expand Up @@ -63,10 +64,7 @@ public async Task Initialize()

public async Task ShowNotification(Notification notification, DateTimeOffset? expirationTime = null)
{
if (_connection == null || _proxy == null)
{
throw new InvalidOperationException("Not connected. Call Initialize() first.");
}
CheckConnection();

if (expirationTime < DateTimeOffset.Now)
{
Expand All @@ -76,25 +74,45 @@ public async Task ShowNotification(Notification notification, DateTimeOffset? ex
var duration = expirationTime - DateTimeOffset.Now;
var actions = GenerateActions(notification);

var id = await _proxy.NotifyAsync(
var id = await _proxy!.NotifyAsync(
_appContext.Name,
0,
_appContext.AppIcon ?? string.Empty,
notification.Title ?? throw new ArgumentException(),
notification.Body ?? throw new ArgumentException(),
actions.ToArray(),
new Dictionary<string, object> {{"urgency", 1}},
new Dictionary<string, object> { { "urgency", 1 } },
duration?.Milliseconds ?? 0
).ConfigureAwait(false);

_activeNotifications[id] = notification;
}

private void CheckConnection()
{
if (_connection == null || _proxy == null)
{
throw new InvalidOperationException("Not connected. Call Initialize() first.");
}
}

public async Task HideNotification(Notification notification)
{
CheckConnection();

if (_activeNotifications.TryGetKey(notification, out var id))
{
await _proxy!.CloseNotificationAsync(id);
}
}

public async Task ScheduleNotification(
Notification notification,
DateTimeOffset deliveryTime,
DateTimeOffset? expirationTime = null)
{
CheckConnection();

if (deliveryTime < DateTimeOffset.Now || deliveryTime > expirationTime)
{
throw new ArgumentException(nameof(deliveryTime));
Expand Down Expand Up @@ -135,7 +153,7 @@ private static NotificationDismissReason GetReason(uint reason)
private void OnNotificationClosed((uint id, uint reason) @event)
{
if (!_activeNotifications.TryGetValue(@event.id, out var notification)) return;

_activeNotifications.Remove(@event.id);

//TODO: Not sure why but it calls this event twice sometimes
Expand All @@ -144,7 +162,7 @@ private void OnNotificationClosed((uint id, uint reason) @event)
{
return;
}

var dismissReason = GetReason(@event.reason);

NotificationDismissed?.Invoke(this,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ public Task ShowNotification(Notification notification, DateTimeOffset? expirati
throw new PlatformNotSupportedException();
}

public Task HideNotification(Notification notification)
{
throw new PlatformNotSupportedException();
}

public Task ScheduleNotification(Notification notification, DateTimeOffset deliveryTime,
DateTimeOffset? expirationTime = null)
{
Expand Down
31 changes: 29 additions & 2 deletions DesktopNotifications.Windows/WindowsNotificationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Windows.UI.Notifications;
using XmlDocument = Windows.Data.Xml.Dom.XmlDocument;
using System.Linq;

#if NETSTANDARD
using System.IO;
Expand All @@ -20,6 +21,7 @@ public class WindowsNotificationManager : INotificationManager
private readonly WindowsApplicationContext _applicationContext;
private readonly TaskCompletionSource<string>? _launchActionPromise;
private readonly Dictionary<ToastNotification, Notification> _notifications;
private readonly Dictionary<ScheduledToastNotification, Notification> _scheduledNotification;

#if NETSTANDARD
private readonly ToastNotifier _toastNotifier;
Expand Down Expand Up @@ -54,6 +56,7 @@ public WindowsNotificationManager(WindowsApplicationContext? applicationContext
#endif

_notifications = new Dictionary<ToastNotification, Notification>();
_scheduledNotification = new Dictionary<ScheduledToastNotification, Notification>();
}

public event EventHandler<NotificationActivatedEventArgs>? NotificationActivated;
Expand Down Expand Up @@ -90,6 +93,21 @@ public Task ShowNotification(Notification notification, DateTimeOffset? expirati
return Task.CompletedTask;
}

public Task HideNotification(Notification notification)
{
if (_notifications.TryGetKey(notification, out var toastNotification))
{
_toastNotifier.Hide(toastNotification);
}

if (_scheduledNotification.TryGetKey(notification, out var scheduledToastNotification))
{
_toastNotifier.RemoveFromSchedule(scheduledToastNotification);
}

return Task.CompletedTask;
}

public Task ScheduleNotification(
Notification notification,
DateTimeOffset deliveryTime,
Expand All @@ -107,12 +125,15 @@ public Task ScheduleNotification(
};

_toastNotifier.AddToSchedule(toastNotification);
_scheduledNotification[toastNotification] = notification;

return Task.CompletedTask;
}

public void Dispose()
{
_notifications.Clear();
_scheduledNotification.Clear();
}

private static XmlDocument GenerateXml(Notification notification)
Expand Down Expand Up @@ -225,11 +246,17 @@ private static string GetActionId(string argument)

private void ToastNotificationOnActivated(ToastNotification sender, object args)
{
if (!_notifications.TryGetValue(sender, out var notification))
{
return;
}

var activationArgs = (ToastActivatedEventArgs)args;
var notification = _notifications[sender];
var actionId = GetActionId(activationArgs.Arguments);

NotificationActivated?.Invoke(this, new NotificationActivatedEventArgs(notification, actionId));
NotificationActivated?.Invoke(
this,
new NotificationActivatedEventArgs(notification, actionId));
}
}
}
23 changes: 23 additions & 0 deletions DesktopNotifications/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;

namespace DesktopNotifications
{
public static class Extensions
{
public static bool TryGetKey<K, V>(this IDictionary<K, V> dict, V value, out K key)
{
foreach (var entry in dict)
{
if (entry.Value?.Equals(value) == true)
{
key = entry.Key;
return true;
}
}

key = default!;

return false;
}
}
}
9 changes: 8 additions & 1 deletion DesktopNotifications/INotificationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,19 @@ public interface INotificationManager : IDisposable
Task Initialize();

/// <summary>
/// Schedules a notification for presentation.
/// Schedules a notification for delivery.
/// </summary>
/// <param name="notification">The notification to present.</param>
/// <param name="expirationTime">The expiration time marking the point when the notification gets removed.</param>
Task ShowNotification(Notification notification, DateTimeOffset? expirationTime = null);

/// <summary>
/// Hides an already delivered notification (if possible).
/// If the notification is scheduled for delivery the schedule will be cancelled.
/// </summary>
/// <param name="notification">The notification to hide</param>
Task HideNotification(Notification notification);

/// <summary>
/// </summary>
/// <param name="notification"></param>
Expand Down
1 change: 1 addition & 0 deletions Example.Avalonia/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

<Button Click="Show_OnClick" Content="Show Notification" />
<Button Click="Schedule_OnClick" Content="Schedule notification (in 5 Seconds)" />
<Button Click="HideLast_OnClick" Content="Hide last notification" />

<TextBlock Foreground="Gray">Events:</TextBlock>
<ListBox Name="EventsListBox" Height="200" />
Expand Down
88 changes: 68 additions & 20 deletions Example.Avalonia/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using DesktopNotifications;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;

namespace Example.Avalonia
{
Expand All @@ -17,6 +17,8 @@ public class MainWindow : Window
private readonly TextBox _titleTextBox;
private readonly INotificationManager _notificationManager;

private Notification? _lastNotification;

public MainWindow()
{
InitializeComponent();
Expand All @@ -36,47 +38,93 @@ public MainWindow()

if (_notificationManager.LaunchActionId != null)
{
((IList<string>) _eventsListBox.Items).Add($"Launch action: {_notificationManager.LaunchActionId}");
RegisterEvent($"Launch action: {_notificationManager.LaunchActionId}");
}
}

private void RegisterEvent(string @event)
{
((IList<string>)_eventsListBox.Items).Add(@event);
}

private void OnNotificationDismissed(object? sender, NotificationDismissedEventArgs e)
{
((IList<string>) _eventsListBox.Items).Add($"Notification dismissed: {e.Reason}");
RegisterEvent($"Notification dismissed: {e.Reason}");
}

private void OnNotificationActivated(object? sender, NotificationActivatedEventArgs e)
{
((IList<string>) _eventsListBox.Items).Add($"Notification activated: {e.ActionId}");
RegisterEvent($"Notification activated: {e.ActionId}");
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}

public void Show_OnClick(object? sender, RoutedEventArgs e)
public async void Show_OnClick(object? sender, RoutedEventArgs e)
{
Debug.Assert(_notificationManager != null);

_notificationManager.ShowNotification(new Notification
try
{
Title = _titleTextBox.Text ?? _titleTextBox.Watermark,
Body = _bodyTextBox.Text ?? _bodyTextBox.Watermark,
Buttons =
Debug.Assert(_notificationManager != null);

var nf = new Notification
{
Title = _titleTextBox.Text ?? _titleTextBox.Watermark,
Body = _bodyTextBox.Text ?? _bodyTextBox.Watermark,
Buttons =
{
("This is awesome!", "awesome")
}
});
};

await _notificationManager.ShowNotification(nf);

_lastNotification = nf;
}
catch (Exception ex)
{
RegisterEvent(ex.Message);
}
}

private async void Schedule_OnClick(object? sender, RoutedEventArgs e)
{
try
{
var nf = new Notification
{
Title = _titleTextBox.Text ?? _titleTextBox.Watermark,
Body = _bodyTextBox.Text ?? _bodyTextBox.Watermark

};

await _notificationManager.ScheduleNotification(
nf,
DateTimeOffset.Now + TimeSpan.FromSeconds(5));

_lastNotification = nf;
}
catch (Exception ex)
{
RegisterEvent(ex.Message);
}
}

private void Schedule_OnClick(object? sender, RoutedEventArgs e)
private async void HideLast_OnClick(object? sender, RoutedEventArgs e)
{
_notificationManager.ScheduleNotification(new Notification
try
{
Title = _titleTextBox.Text ?? _titleTextBox.Watermark,
Body = _bodyTextBox.Text ?? _bodyTextBox.Watermark
}, DateTimeOffset.Now + TimeSpan.FromSeconds(5));
if (_lastNotification != null)
{
await _notificationManager.HideNotification(_lastNotification);
}

}
catch (Exception ex)
{
RegisterEvent(ex.Message);
}
}
}
}

0 comments on commit c9440df

Please sign in to comment.