< Summary

Information
Class: MyNet.UI.ViewModels.Shell.Notifications.ShellNotificationsViewModel
Assembly: MyNet.UI
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/ViewModels/Shell/Notifications/ShellNotificationsViewModel.cs
Tag: 323_28699572109
Line coverage
87%
Covered lines: 43
Uncovered lines: 6
Coverable lines: 49
Total lines: 145
Line coverage: 87.7%
Branch coverage
28%
Covered branches: 4
Total branches: 14
Branch coverage: 28.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
set_HasNotifications(...)100%11100%
set_MaxSeverity(...)100%11100%
ApplyCollectionChange(...)20%231050%
RefreshNotificationState()50%4483.33%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/ViewModels/Shell/Notifications/ShellNotificationsViewModel.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="ShellNotificationsViewModel.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Specialized;
 9using System.Linq;
 10using System.Reactive.Disposables;
 11using System.Windows.Input;
 12using MyNet.Observable;
 13using MyNet.Observable.Collections;
 14using MyNet.UI.Commands;
 15using MyNet.UI.Notifications;
 16using MyNet.UI.Notifications.Models;
 17using MyNet.UI.Threading;
 18
 19namespace MyNet.UI.ViewModels.Shell.Notifications;
 20
 21/// <summary>
 22/// View model for the shell notifications panel (list, severity, close actions).
 23/// Drawer visibility is controlled by the shell host notifications drawer.
 24/// </summary>
 25public sealed class ShellNotificationsViewModel : ViewModelBase
 26{
 27    /// <summary>
 28    /// Initializes a new instance of the <see cref="ShellNotificationsViewModel"/> class.
 29    /// </summary>
 3030    public ShellNotificationsViewModel(
 3031        INotificationsManager notificationsManager,
 3032        ISchedulerProvider schedulerProvider,
 3033        ICommandFactory? commandFactory = null)
 34    {
 3035        ArgumentNullException.ThrowIfNull(notificationsManager);
 3036        ArgumentNullException.ThrowIfNull(schedulerProvider);
 37
 3038        var commands = commandFactory.GetOrDefault();
 39
 3040        Notifications = ExtendedCollection.Create<IClosableNotification>(schedulerProvider.Ui);
 41
 3042        Notifications.AddRange(notificationsManager.Notifications.OfType<IClosableNotification>());
 43
 3044        INotifyCollectionChanged collection = notificationsManager.Notifications;
 3045        collection.CollectionChanged += collectionChanged;
 3046        Disposables.Add(Disposable.Create(() => collection.CollectionChanged -= collectionChanged));
 47
 3048        ExecuteActionCommand = commands.CreateRequired<ActionNotification>(
 3049            static notification => notification.Action?.Invoke(notification),
 3050            static notification => notification.Action is not null);
 51
 3052        CloseCommand = commands.CreateRequired<IClosableNotification>(static n => n.RequestClose());
 53
 3054        ClearCommand = commands.Create(
 3055            () => Notifications.Where(static x => x.IsClosable).ToList().ForEach(static x => x.RequestClose()),
 3056            () => Notifications.Any(static x => x.IsClosable));
 57
 3058        Disposables.Add(
 3059            Notifications.ToObservableChangeSet().Subscribe(_ =>
 3060            {
 3061                MaxSeverity = Notifications.Count != 0
 3062                    ? Notifications.OfType<MessageNotification>().Max(static x => x.Severity)
 3063                    : null;
 3064
 3065                HasNotifications = Notifications.Count > 0;
 3066                NotificationsChanged?.Invoke(this, EventArgs.Empty);
 3067            }));
 68
 3069        RefreshNotificationState();
 3070        return;
 71        void collectionChanged(object? sender, NotifyCollectionChangedEventArgs e) => ApplyCollectionChange(e);
 72    }
 73
 74    /// <summary>
 75    /// Raised when the notification list or <see cref="HasNotifications"/> changes.
 76    /// </summary>
 77    public event EventHandler? NotificationsChanged;
 78
 79    /// <summary>
 80    /// Gets the notifications bound to the panel.
 81    /// </summary>
 82    public ExtendedCollection<IClosableNotification> Notifications { get; }
 83
 84    /// <summary>
 85    /// Gets a value indicating whether at least one notification is present.
 86    /// </summary>
 6387    public bool HasNotifications { get; private set => SetProperty(ref field, value); }
 88
 89    /// <summary>
 90    /// Gets the highest severity among <see cref="MessageNotification"/> items, if any.
 91    /// </summary>
 6392    public NotificationSeverity? MaxSeverity { get; private set => SetProperty(ref field, value); }
 93
 94    /// <summary>
 95    /// Gets the command that executes an actionable notification.
 96    /// </summary>
 97    public ICommand ExecuteActionCommand { get; }
 98
 99    /// <summary>
 100    /// Gets the command that closes a single notification.
 101    /// </summary>
 102    public ICommand CloseCommand { get; }
 103
 104    /// <summary>
 105    /// Gets the command that closes all closable notifications.
 106    /// </summary>
 107    public ICommand ClearCommand { get; }
 108
 109    private void ApplyCollectionChange(NotifyCollectionChangedEventArgs e)
 110    {
 3111        switch (e.Action)
 112        {
 113            case NotifyCollectionChangedAction.Add:
 3114                Notifications.AddRange(e.NewItems!.Cast<INotification>().OfType<IClosableNotification>());
 3115                break;
 116
 117            case NotifyCollectionChangedAction.Remove:
 0118                foreach (var removed in e.OldItems!.Cast<INotification>())
 119                {
 0120                    var match = Notifications.FirstOrDefault(x => x.Id == removed.Id);
 0121                    if (match is not null)
 0122                        Notifications.Remove(match);
 123                }
 124
 125                break;
 126
 127            case NotifyCollectionChangedAction.Reset:
 0128                Notifications.Clear();
 129                break;
 130        }
 131
 3132        RefreshNotificationState();
 3133    }
 134
 135    private void RefreshNotificationState()
 136    {
 33137        MaxSeverity = Notifications.Count != 0
 33138            ? Notifications.OfType<MessageNotification>().Max(static x => x.Severity)
 33139            : null;
 140
 33141        HasNotifications = Notifications.Count > 0;
 33142        NotificationsChanged?.Invoke(this, EventArgs.Empty);
 0143    }
 144}
 145