using System;
using System.Diagnostics.CodeAnalysis;
using CommunityToolkit.Mvvm.Input;
using NLog;
using StabilityMatrix.Avalonia.Services;
using StabilityMatrix.Core.Extensions;
namespace StabilityMatrix.Avalonia.Extensions;
[SuppressMessage("ReSharper", "MemberCanBePrivate.Global")]
public static class RelayCommandExtensions
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
///
/// Attach an error handler to the command that will invoke the given action when an exception occurs.
///
/// The command to attach the error handler to.
/// The action to invoke when an exception occurs.
/// Thrown if the command was not created with the FlowExceptionsToTaskScheduler option enabled.
public static T WithErrorHandler(this T command, Action onError) where T : IAsyncRelayCommand
{
if (command is AsyncRelayCommand relayCommand)
{
// Check that the FlowExceptionsToTaskScheduler flag is set
var options = relayCommand.GetPrivateField("options");
if (!options.HasFlag(AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler))
{
throw new ArgumentException(
"The command must be created with the FlowExceptionsToTaskScheduler option enabled"
);
}
}
command.PropertyChanged += (sender, e) =>
{
if (sender is not IAsyncRelayCommand senderCommand)
{
return;
}
// On ExecutionTask updates, check if there is an exception
if (
e.PropertyName == nameof(AsyncRelayCommand.ExecutionTask)
&& senderCommand.ExecutionTask is { Exception: { } exception }
)
{
onError(exception);
}
};
return command;
}
///
/// Attach an error handler to the command that will log the error and show a notification.
///
/// The command to attach the error handler to.
/// The notification service to use to show the notification.
/// The log level to use when logging the error. Defaults to LogLevel.Error
/// Thrown if the command was not created with the FlowExceptionsToTaskScheduler option enabled.
public static T WithNotificationErrorHandler(
this T command,
INotificationService notificationService,
LogLevel? logLevel = default
) where T : IAsyncRelayCommand
{
logLevel ??= LogLevel.Error;
return command.WithErrorHandler(e =>
{
Logger.Log(logLevel, e, "Error executing command");
notificationService.ShowPersistent("Error", $"[{e.GetType().Name}] {e.Message}");
});
}
}