using System.Windows; using System.Windows.Threading; using Notification.Core; using Notification.Wpf; using Notification.Wpf.Constants; using ytLive.Helpers; namespace ytLive.Services; /// /// Toast notifications rendered inside the main window's ToastArea, whose /// position is configurable in App Settings (bottom-right by default). Info/success auto-dismiss after ~4s, /// warnings ~8s, errors stay until dismissed. App Settings can make all alerts sticky and /// dismissible by clicking the card. Calls from any thread are /// marshalled to the captured dispatcher. /// public sealed class NotificationService : INotificationService { public const string AreaName = "ToastArea"; internal static readonly IReadOnlyDictionary Cards = new Dictionary { [AppNotificationSeverity.Info] = (ThemeBrush.Hex("Brush.InfoContainer"), 4), [AppNotificationSeverity.Success] = (ThemeBrush.Hex("Brush.SuccessContainer"), 4), [AppNotificationSeverity.Warning] = (ThemeBrush.Hex("Brush.WarningContainer"), 8), [AppNotificationSeverity.Error] = (ThemeBrush.Hex("Brush.ErrorContainer"), 0), }; private readonly NotificationManager _manager = new(); private readonly Dispatcher _dispatcher; private readonly Func _stickyAlertsUntilDismissed; public NotificationService() : this(Application.Current?.Dispatcher, static () => false) { } internal NotificationService(Dispatcher? dispatcher) : this(dispatcher, static () => false) { } internal NotificationService(Dispatcher? dispatcher, Func stickyAlertsUntilDismissed) { _dispatcher = dispatcher ?? Dispatcher.CurrentDispatcher; _stickyAlertsUntilDismissed = stickyAlertsUntilDismissed; NotificationConstants.NotificationCornerRadius = new CornerRadius(8); NotificationConstants.KeepNotificationVisibleOnMouseOver = true; } public void Show(string title, string message, AppNotificationSeverity severity) { _dispatcher.Invoke(() => _manager.Show(BuildRequestForCurrentSettings(title, message, severity))); } internal NotificationRequest BuildRequestForCurrentSettings(string title, string message, AppNotificationSeverity severity) => BuildRequest(title, message, severity, _stickyAlertsUntilDismissed()); internal static NotificationRequest BuildRequest(string title, string message, AppNotificationSeverity severity, bool stickyUntilDismissed = false) { var (backgroundHex, expirationSeconds) = Cards[severity]; var builder = NotificationBuilder .Create(title, message) .InArea(AreaName) .WithBackground(NotificationColor.FromHex(backgroundHex)) .WithForeground(NotificationColor.FromHex(ThemeBrush.Hex("Brush.OnSurface"))) .CloseOnClick(stickyUntilDismissed); if (stickyUntilDismissed) builder.NeverExpires(); else if (severity == AppNotificationSeverity.Error) builder.NeverExpires(); else builder.ExpiresInSeconds(expirationSeconds); return builder.Build(); } }