using System;
using System.Collections;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Controls.Primitives;
using Avalonia.Rendering;
using Avalonia.Data;
using Avalonia.VisualTree;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls.Notifications
{
///
/// An that displays notifications in a .
///
[PseudoClasses(":topleft", ":topright", ":bottomleft", ":bottomright")]
public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager, ICustomSimpleHitTest
{
private IList _items;
///
/// Defines the property.
///
public static readonly StyledProperty PositionProperty =
AvaloniaProperty.Register(nameof(Position), NotificationPosition.TopRight);
///
/// Defines which corner of the screen notifications can be displayed in.
///
///
public NotificationPosition Position
{
get { return GetValue(PositionProperty); }
set { SetValue(PositionProperty, value); }
}
///
/// Defines the property.
///
public static readonly StyledProperty MaxItemsProperty =
AvaloniaProperty.Register(nameof(MaxItems), 5);
///
/// Defines the maximum number of notifications visible at once.
///
public int MaxItems
{
get { return GetValue(MaxItemsProperty); }
set { SetValue(MaxItemsProperty, value); }
}
///
/// Initializes a new instance of the class.
///
/// The window that will host the control.
public WindowNotificationManager(Window host)
{
if (VisualChildren.Count != 0)
{
Install(host);
}
else
{
Observable.FromEventPattern(host, nameof(host.TemplateApplied)).Take(1)
.Subscribe(_ =>
{
Install(host);
});
}
UpdatePseudoClasses(Position);
}
static WindowNotificationManager()
{
HorizontalAlignmentProperty.OverrideDefaultValue(Layout.HorizontalAlignment.Stretch);
VerticalAlignmentProperty.OverrideDefaultValue(Layout.VerticalAlignment.Stretch);
}
///
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
var itemsControl = e.NameScope.Find("PART_Items");
_items = itemsControl?.Children;
}
///
public void Show(INotification content)
{
Show(content as object);
}
///
public async void Show(object content)
{
var notification = content as INotification;
var notificationControl = new NotificationCard
{
Content = content
};
if (notification != null)
{
notificationControl.NotificationClosed += (sender, args) =>
{
notification.OnClose?.Invoke();
_items.Remove(sender);
};
}
notificationControl.PointerPressed += (sender, args) =>
{
if (notification != null && notification.OnClick != null)
{
notification.OnClick.Invoke();
}
(sender as NotificationCard)?.Close();
};
_items.Add(notificationControl);
if (_items.OfType().Count(i => !i.IsClosing) > MaxItems)
{
_items.OfType().First(i => !i.IsClosing).Close();
}
if (notification != null && notification.Expiration == TimeSpan.Zero)
{
return;
}
await Task.Delay(notification?.Expiration ?? TimeSpan.FromSeconds(5));
notificationControl.Close();
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == PositionProperty)
{
UpdatePseudoClasses(change.NewValue.GetValueOrDefault());
}
}
///
/// Installs the within the
/// of the host .
///
/// The that will be the host.
private void Install(Window host)
{
var adornerLayer = host.FindDescendantOfType()?.AdornerLayer;
adornerLayer?.Children.Add(this);
}
private void UpdatePseudoClasses(NotificationPosition position)
{
PseudoClasses.Set(":topleft", position == NotificationPosition.TopLeft);
PseudoClasses.Set(":topright", position == NotificationPosition.TopRight);
PseudoClasses.Set(":bottomleft", position == NotificationPosition.BottomLeft);
PseudoClasses.Set(":bottomright", position == NotificationPosition.BottomRight);
}
public bool HitTest(Point point) => VisualChildren.HitTestCustom(point);
}
}