using System; using System.Threading.Tasks; using System.Windows.Input; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Layout; using Avalonia.Threading; using FluentAvalonia.UI.Controls; using ReactiveUI; namespace Artemis.UI.Shared.Services.Builders; /// /// Represents a builder that can be used to create notifications. /// public class NotificationBuilder { private readonly InfoBar _infoBar; private readonly Window _parent; private TimeSpan _timeout = TimeSpan.FromSeconds(5); /// /// Creates a new instance of the class. /// /// The parent window that will host the notification. public NotificationBuilder(Window parent) { _parent = parent; _infoBar = new InfoBar(); _infoBar.Classes.Add("notification-info-bar"); } /// /// Changes the title of the notification. /// /// The new title. /// The notification builder that can be used to further build the notification. public NotificationBuilder WithTitle(string? title) { _infoBar.Title = title; return this; } /// /// Changes the message of the notification. /// /// The new message. /// The notification builder that can be used to further build the notification. public NotificationBuilder WithMessage(string? content) { _infoBar.Message = content; return this; } /// /// Changes the timeout of the notification after which it disappears automatically. /// /// The timeout of the notification after which it disappears automatically. /// The notification builder that can be used to further build the notification. public NotificationBuilder WithTimeout(TimeSpan timeout) { _timeout = timeout; return this; } /// /// Changes the vertical position of the notification inside the parent window. /// /// The vertical position of the notification inside the parent window. /// The notification builder that can be used to further build the notification. public NotificationBuilder WithVerticalPosition(VerticalAlignment position) { _infoBar.VerticalAlignment = position; return this; } /// /// Changes the horizontal position of the notification inside the parent window. /// /// The horizontal position of the notification inside the parent window. /// The notification builder that can be used to further build the notification. public NotificationBuilder WithHorizontalPosition(HorizontalAlignment position) { _infoBar.HorizontalAlignment = position; return this; } /// /// Changes the severity (color) of the notification. /// /// The severity (color) of the notification. /// The notification builder that can be used to further build the notification. public NotificationBuilder WithSeverity(NotificationSeverity severity) { _infoBar.Severity = (InfoBarSeverity) severity; return this; } /// /// Changes the action button of the notification. /// /// An action to configure the button. /// The notification builder that can be used to further build the notification. public NotificationBuilder HavingButton(Action configure) { NotificationButtonBuilder builder = new(); configure(builder); _infoBar.ActionButton = builder.Build(); return this; } /// /// Shows the notification. /// /// An action that can be called to hide the notification. /// public Action Show() { Dispatcher.UIThread.Post(() => { OverlayLayer? overlayLayer = OverlayLayer.GetOverlayLayer(_parent); if (overlayLayer == null) throw new ArtemisSharedUIException("Can't display a notification on a window an overlay layer."); NotificationHost container = new() {Content = _infoBar}; overlayLayer.Children.Add(container); _infoBar.Closed += InfoBarOnClosed; _infoBar.IsOpen = true; Dispatcher.UIThread.InvokeAsync(async () => { await Task.Delay(_timeout); _infoBar.IsOpen = false; }); return; void InfoBarOnClosed(InfoBar sender, InfoBarClosedEventArgs args) { overlayLayer.Children.Remove(container); _infoBar.Closed -= InfoBarOnClosed; } }); return () => Dispatcher.UIThread.Post(() => _infoBar.IsOpen = false); } } /// /// Represents a builder that can be used to create buttons inside notifications. /// public class NotificationButtonBuilder { private Action? _action; private Func? _asyncAction; private ICommand? _command; private object? _commandParameter; private string _text = "Text"; /// /// Changes text message of the button. /// /// The new text. /// The notification builder that can be used to further build the button. public NotificationButtonBuilder WithText(string text) { _text = text; return this; } /// /// Changes action that is called when the button is clicked. /// /// The action to call when the button is clicked. /// The builder that can be used to further build the button. public NotificationButtonBuilder WithAction(Action action) { _command = null; _action = action; return this; } /// /// Changes action that is called when the button is clicked. /// /// The action to call when the button is clicked. /// The builder that can be used to further build the button. public NotificationButtonBuilder WithAction(Func action) { _command = null; _asyncAction = action; return this; } /// /// Changes command that is called when the button is clicked. /// /// The command to call when the button is clicked. /// The builder that can be used to further build the button. public NotificationButtonBuilder WithCommand(ICommand command) { _action = null; _command = command; return this; } /// /// Changes parameter of the command that is called when the button is clicked. /// /// The parameter of the command to call when the button is clicked. /// The builder that can be used to further build the button. public NotificationButtonBuilder WithCommandParameter(object? commandParameter) { _commandParameter = commandParameter; return this; } internal Control Build() { Button button = new() {Content = _text}; button.Classes.Add("AppBarButton"); if (_action != null) { button.Command = ReactiveCommand.Create(() => _action()); } else if (_asyncAction != null) { button.Command = ReactiveCommand.CreateFromTask(() => _asyncAction()); } else if (_command != null) { button.Command = _command; button.CommandParameter = _commandParameter; } return button; } } /// /// Represents a severity of a notification. /// public enum NotificationSeverity { /// /// A severity for informational messages. /// Informational, /// /// A severity for success messages. /// Success, /// /// A severity for warning messages. /// Warning, /// /// A severity for error messages. /// Error }