diff --git a/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/Handlers/Notifications/Notification.cs b/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/Handlers/Notifications/Notification.cs new file mode 100644 index 0000000..7fb09f3 --- /dev/null +++ b/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/Handlers/Notifications/Notification.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FRESHMusicPlayer.Handlers.Notifications +{ + public class Notification + { + /// + /// Whether the notification should appear on top of other notifications + /// + public bool IsImportant { get; set; } = false; + /// + /// Whether the notification should forcefully open the Notification pane + /// + public bool DisplayAsToast { get; set; } = false; + /// + /// Whether the user has seen the notification + /// + public bool Read { get; set; } = false; + /// + /// The actual content of the notification + /// + public string ContentText { get; set; } = string.Empty; + /// + /// The text to show in the button + /// + public string ButtonText { get; set; } = string.Empty; + /// + /// The type of notification + /// + public NotificationType Type { get; set; } = NotificationType.Generic; + /// + /// Invoked whenever the notification's button has been clicked. Return true to close the notification. + /// + public Func OnButtonClicked { get; set; } = null; + + public bool ShouldButtonBeVisible => !string.IsNullOrEmpty(ButtonText) && OnButtonClicked is not null; + } + public enum NotificationType + { + /// + /// The task the notification is associated with succeeded - green border + /// + Success, + /// + /// The notification displays information - no border + /// + Information, + /// + /// The task the notification is associated with failed - red border + /// + Failure, + /// + /// A generic notification + /// + Generic + } +} diff --git a/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/Handlers/Notifications/NotificationHandler.cs b/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/Handlers/Notifications/NotificationHandler.cs new file mode 100644 index 0000000..74c43a5 --- /dev/null +++ b/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/Handlers/Notifications/NotificationHandler.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FRESHMusicPlayer.Handlers.Notifications +{ + /// + /// Handles FMP's notifications + /// + public class NotificationHandler + { + /// + /// Gets the currently visible notifications for the window. + /// + public List Notifications { get; private set; } = new List(); + /// + /// Raised whenever a notification is added, removed, or updated. + /// + public event EventHandler NotificationInvalidate; + + public void Add(Notification box) + { + Notifications.Add(box); + NotificationInvalidate?.Invoke(null, EventArgs.Empty); + } + public void Update(Notification box) + { + int notificationindex = Notifications.IndexOf(box); + if (Notifications[notificationindex] != null) + { + Notifications[notificationindex] = box; + } + NotificationInvalidate?.Invoke(null, EventArgs.Empty); + } + public void Remove(Notification box) + { + Notifications.Remove(box); + NotificationInvalidate?.Invoke(null, EventArgs.Empty); + } + public void ClearAll() + { + Notifications.Clear(); + NotificationInvalidate?.Invoke(null, EventArgs.Empty); + } + + } +} diff --git a/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/ViewModels/MainWindowViewModel.cs b/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/ViewModels/MainWindowViewModel.cs index 6ffc0db..d07883c 100644 --- a/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/ViewModels/MainWindowViewModel.cs +++ b/FRESHMusicPlayer/FRESHMusicPlayer-Avalonia/ViewModels/MainWindowViewModel.cs @@ -3,6 +3,7 @@ using ATL.Playlist; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; +using AvaloniaPrimatives = Avalonia.Controls.Primitives; using Avalonia.Data.Converters; using Avalonia.Media; using Avalonia.Media.Imaging; @@ -10,6 +11,7 @@ using Avalonia.Threading; using FRESHMusicPlayer.Handlers; using FRESHMusicPlayer.Handlers.Configuration; using FRESHMusicPlayer.Handlers.Integrations; +using FRESHMusicPlayer.Handlers.Notifications; using FRESHMusicPlayer.Views; using LiteDB; using ReactiveUI; @@ -22,6 +24,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Timers; +using Avalonia.Markup.Xaml; namespace FRESHMusicPlayer.ViewModels { @@ -33,7 +36,7 @@ namespace FRESHMusicPlayer.ViewModels public ConfigurationFile Config { get; private set; } public Track CurrentTrack { get; private set; } public IntegrationHandler Integrations { get; private set; } = new(); - + public NotificationHandler Notifications { get; private set; } = new(); private Window Window { @@ -62,6 +65,11 @@ namespace FRESHMusicPlayer.ViewModels set => this.RaiseAndSetIfChanged(ref windowTitle, value); } + public ObservableCollection VisibleNotifications => new(Notifications.Notifications); + public bool AreThereAnyNotifications => Notifications.Notifications.Count > 0; + + public void ClearAllNotificationsCommand() => Notifications.ClearAll(); + #region Core private void Player_SongException(object sender, PlaybackExceptionEventArgs e) { @@ -342,6 +350,7 @@ namespace FRESHMusicPlayer.ViewModels Player.SongStopped += Player_SongStopped; Player.SongException += Player_SongException; ProgressTimer.Elapsed += ProgressTimer_Elapsed; // TODO: put this in a more logical place + Notifications.NotificationInvalidate += Notifications_NotificationInvalidate; LoggingHandler.Log("Handling config..."); Config = Program.Config; // HACK: this is a hack Volume = Config?.Volume ?? 1f; @@ -374,6 +383,20 @@ namespace FRESHMusicPlayer.ViewModels await PerformAutoImport(); } + private void Notifications_NotificationInvalidate(object sender, EventArgs e) + { + this.RaisePropertyChanged(nameof(VisibleNotifications)); + this.RaisePropertyChanged(nameof(AreThereAnyNotifications)); + foreach (Notification box in Notifications.Notifications) + { + if (box.DisplayAsToast && !box.Read) + { + var button = Window.FindControl - + + + + + + +