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
}