mirror of
https://github.com/Royce551/FRESHMusicPlayer.git
synced 2025-01-22 10:51:52 -05:00
Basic notification implementation
This commit is contained in:
parent
a2f589795b
commit
f9ba816e03
5 changed files with 189 additions and 2 deletions
|
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether the notification should appear on top of other notifications
|
||||
/// </summary>
|
||||
public bool IsImportant { get; set; } = false;
|
||||
/// <summary>
|
||||
/// Whether the notification should forcefully open the Notification pane
|
||||
/// </summary>
|
||||
public bool DisplayAsToast { get; set; } = false;
|
||||
/// <summary>
|
||||
/// Whether the user has seen the notification
|
||||
/// </summary>
|
||||
public bool Read { get; set; } = false;
|
||||
/// <summary>
|
||||
/// The actual content of the notification
|
||||
/// </summary>
|
||||
public string ContentText { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The text to show in the button
|
||||
/// </summary>
|
||||
public string ButtonText { get; set; } = string.Empty;
|
||||
/// <summary>
|
||||
/// The type of notification
|
||||
/// </summary>
|
||||
public NotificationType Type { get; set; } = NotificationType.Generic;
|
||||
/// <summary>
|
||||
/// Invoked whenever the notification's button has been clicked. Return true to close the notification.
|
||||
/// </summary>
|
||||
public Func<bool> OnButtonClicked { get; set; } = null;
|
||||
|
||||
public bool ShouldButtonBeVisible => !string.IsNullOrEmpty(ButtonText) && OnButtonClicked is not null;
|
||||
}
|
||||
public enum NotificationType
|
||||
{
|
||||
/// <summary>
|
||||
/// The task the notification is associated with succeeded - green border
|
||||
/// </summary>
|
||||
Success,
|
||||
/// <summary>
|
||||
/// The notification displays information - no border
|
||||
/// </summary>
|
||||
Information,
|
||||
/// <summary>
|
||||
/// The task the notification is associated with failed - red border
|
||||
/// </summary>
|
||||
Failure,
|
||||
/// <summary>
|
||||
/// A generic notification
|
||||
/// </summary>
|
||||
Generic
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FRESHMusicPlayer.Handlers.Notifications
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles FMP's notifications
|
||||
/// </summary>
|
||||
public class NotificationHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the currently visible notifications for the window.
|
||||
/// </summary>
|
||||
public List<Notification> Notifications { get; private set; } = new List<Notification>();
|
||||
/// <summary>
|
||||
/// Raised whenever a notification is added, removed, or updated.
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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<Notification> 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<Button>("NotificationButton");
|
||||
button.ContextFlyout.ShowAt(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void CloseThings()
|
||||
{
|
||||
LoggingHandler.Log("FMP is shutting down!");
|
||||
|
|
|
@ -92,7 +92,31 @@
|
|||
<Button Margin="0,5">
|
||||
<Image Source="{DynamicResource Search}"/>
|
||||
</Button>
|
||||
<Button Margin="0,5">
|
||||
<Button x:Name="NotificationButton" Click="OnShowNotificationButtonClick" Margin="0,5" IsVisible="{Binding AreThereAnyNotifications}">
|
||||
<Button.ContextFlyout>
|
||||
<Flyout ShowMode="Transient">
|
||||
<DockPanel>
|
||||
<DockPanel DockPanel.Dock="Top" LastChildFill="False" Margin="0,0,0,10">
|
||||
<TextBlock DockPanel.Dock="Left" Text="Notifications" FontSize="16" VerticalAlignment="Center" FontWeight="Bold"/>
|
||||
<Button DockPanel.Dock="Right" Content="Clear All" VerticalAlignment="Center" Command="{Binding ClearAllNotificationsCommand}"/>
|
||||
</DockPanel>
|
||||
<ListBox Items="{Binding VisibleNotifications}" MinWidth="300" MaxWidth="300">
|
||||
<ListBox.DataTemplates>
|
||||
<DataTemplate>
|
||||
<StackPanel Background="Transparent" Margin="-10">
|
||||
<TextBlock Text="{Binding ContentText}" TextWrapping="Wrap"/>
|
||||
<Button Click="OnNotificationButtonClick" HorizontalAlignment="Center" IsVisible="{Binding ShouldButtonBeVisible}">
|
||||
<Button.Content>
|
||||
<TextBlock Text="{Binding ButtonText}"/>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListBox.DataTemplates>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</Flyout>
|
||||
</Button.ContextFlyout>
|
||||
<Image Source="{DynamicResource Notification}"/>
|
||||
</Button>
|
||||
<Button Margin="0,5" Command="{Binding OpenQueueManagementCommand}" ToolTip.Tip="{x:Static resx:Resources.QueueManagement}">
|
||||
|
|
|
@ -13,6 +13,8 @@ using FRESHMusicPlayer.Utilities;
|
|||
using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
using FRESHMusicPlayer.Handlers.Notifications;
|
||||
using Avalonia.Controls.Primitives;
|
||||
|
||||
namespace FRESHMusicPlayer.Views
|
||||
{
|
||||
|
@ -87,6 +89,21 @@ namespace FRESHMusicPlayer.Views
|
|||
}
|
||||
}
|
||||
|
||||
private void OnShowNotificationButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var button = this.FindControl<Button>("NotificationButton");
|
||||
button.ContextFlyout.ShowAt(button);
|
||||
}
|
||||
|
||||
private void OnNotificationButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var cmd = (Button)sender;
|
||||
if (cmd.DataContext is Notification x)
|
||||
{
|
||||
if (x.OnButtonClicked?.Invoke() ?? true) ViewModel?.Notifications.Remove(x);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPointerWheelChanged(object sender, PointerWheelEventArgs e)
|
||||
{
|
||||
ViewModel.Volume += ((float)((e.Delta.Y) / 100) * 3);
|
||||
|
@ -141,6 +158,19 @@ namespace FRESHMusicPlayer.Views
|
|||
case Key.F4:
|
||||
Topmost = !Topmost;
|
||||
break;
|
||||
case Key.F6:
|
||||
ViewModel.Notifications.Add(new()
|
||||
{
|
||||
ContentText = "Catgirls are cute catgirls are cute catgirls are cute text wrap test text wrap test",
|
||||
ButtonText = "Testing 1 2 3!",
|
||||
DisplayAsToast = true,
|
||||
OnButtonClicked = () =>
|
||||
{
|
||||
new MessageBox().SetStuff("lols", "wtf, that actually worked?").ShowDialog(this);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue