// 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); } } } }