// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Controls.Primitives;
using Avalonia.VisualTree;
namespace Avalonia.Controls.Notifications
{
///
/// An that displays notifications in a .
///
public class WindowNotificationManager : TemplatedControl, IManagedNotificationManager
{
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);
});
}
}
static WindowNotificationManager()
{
PseudoClass(PositionProperty, x => x == NotificationPosition.TopLeft, ":topleft");
PseudoClass(PositionProperty, x => x == NotificationPosition.TopRight, ":topright");
PseudoClass(PositionProperty, x => x == NotificationPosition.BottomLeft, ":bottomleft");
PseudoClass(PositionProperty, x => x == NotificationPosition.BottomRight, ":bottomright");
HorizontalAlignmentProperty.OverrideDefaultValue(Layout.HorizontalAlignment.Stretch);
VerticalAlignmentProperty.OverrideDefaultValue(Layout.VerticalAlignment.Stretch);
}
///
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(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();
}
///
/// Installs the within the
/// of the host .
///
/// The that will be the host.
private void Install(Window host)
{
var adornerLayer = host.GetVisualDescendants()
.OfType()
.FirstOrDefault()
?.AdornerLayer;
if (adornerLayer != null)
{
adornerLayer.Children.Add(this);
}
}
}
}