diff --git a/src/Core/FileTime.Core.Abstraction/Command/CommandError.cs b/src/Core/FileTime.Core.Abstraction/Command/CommandError.cs new file mode 100644 index 0000000..689f7d8 --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/Command/CommandError.cs @@ -0,0 +1,3 @@ +namespace FileTime.Core.Command; + +public record CommandError(string Message, Exception? Exception); diff --git a/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs b/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs index 64b9a09..7045324 100644 --- a/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs +++ b/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using DeclarativeProperty; using FileTime.Core.Timeline; @@ -9,8 +10,9 @@ public interface ICommand IDeclarativeProperty DisplayDetailLabel { get; } IDeclarativeProperty TotalProgress { get; } IDeclarativeProperty CurrentProgress { get; } + IDeclarativeProperty> Errors { get; } Task CanRun(PointInTime currentTime); Task SimulateCommand(PointInTime currentTime); void Cancel(); -} \ No newline at end of file +} diff --git a/src/Core/FileTime.Core.Command/CommandBase.cs b/src/Core/FileTime.Core.Command/CommandBase.cs index 830860a..a736ab8 100644 --- a/src/Core/FileTime.Core.Command/CommandBase.cs +++ b/src/Core/FileTime.Core.Command/CommandBase.cs @@ -1,3 +1,4 @@ +using System.Collections.ObjectModel; using DeclarativeProperty; using FileTime.Core.Timeline; @@ -9,11 +10,14 @@ public abstract class CommandBase : ICommand private readonly DeclarativeProperty _displayDetailLabel; private readonly DeclarativeProperty _totalProgress; private readonly DeclarativeProperty _currentProgress; + private readonly DeclarativeProperty> _errorsProperty; + private readonly ObservableCollection _errors = []; public IDeclarativeProperty DisplayLabel { get; } public IDeclarativeProperty DisplayDetailLabel { get; } public IDeclarativeProperty TotalProgress { get; } public IDeclarativeProperty CurrentProgress { get; } + public IDeclarativeProperty> Errors { get; } protected CommandBase(string displayLabel = "", string displayDetailLabel = "", int totalProgress = 0, int currentProgress = 0) { @@ -21,11 +25,13 @@ public abstract class CommandBase : ICommand _displayDetailLabel = new(displayDetailLabel); _totalProgress = new(totalProgress); _currentProgress = new(currentProgress); + _errorsProperty = new(_errors); DisplayLabel = _displayLabel; DisplayDetailLabel = _displayDetailLabel; TotalProgress = _totalProgress; CurrentProgress = _currentProgress; + Errors = _errorsProperty; } public abstract Task CanRun(PointInTime currentTime); @@ -50,4 +56,6 @@ public abstract class CommandBase : ICommand return Task.FromResult((int)(dataList.Sum(d => d.Progress) * 100 / total)); }) .Subscribe(async (p, _) => await SetTotalProgress(p)); -} \ No newline at end of file + + protected void AddError(CommandError error) => _errors.Add(error); +} diff --git a/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs b/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs index 511f0c6..20763ab 100644 --- a/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs +++ b/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs @@ -30,7 +30,7 @@ public class CopyCommand : CommandBase, ITransportationCommand internal CopyCommand( ITimelessContentProvider timelessContentProvider, - ICommandSchedulerNotifier commandSchedulerNotifier, + ICommandSchedulerNotifier commandSchedulerNotifier, CopyStrategyFactory copyStrategyFactory, ILogger logger, IReadOnlyCollection sources, @@ -52,7 +52,7 @@ public class CopyCommand : CommandBase, ITransportationCommand return p?.Progress.Map(currentProgress => p.TotalCount == 0 ? 0 - : (int) (currentProgress * 100 / p.TotalCount) + : (int)(currentProgress * 100 / p.TotalCount) ); }) .Switch() @@ -156,7 +156,7 @@ public class CopyCommand : CommandBase, ITransportationCommand var statusList = statuses.ToList(); var done = statusList.Count(s => s) + 1; if (done > statusList.Count) done = statusList.Count; - + return Task.FromResult($"Copy - {done} / {statusList.Count}"); }) .Subscribe(async (v, _) => await SetDisplayLabelAsync(v)); @@ -174,7 +174,7 @@ public class CopyCommand : CommandBase, ITransportationCommand { if (_cancellationTokenSource.IsCancellationRequested) return; - var resolvedTarget = (IContainer) await target.ResolveAsync() ?? throw new Exception(); + var resolvedTarget = (IContainer)await target.ResolveAsync() ?? throw new Exception(); var item = await _timelessContentProvider.GetItemByFullNameAsync(source, currentTime); if (item is IContainer container) @@ -183,7 +183,7 @@ public class CopyCommand : CommandBase, ITransportationCommand { await container.WaitForLoaded(_cancellationTokenSource.Token); } - catch(OperationCanceledException) + catch (OperationCanceledException) { return; } @@ -208,7 +208,15 @@ public class CopyCommand : CommandBase, ITransportationCommand var currentProgress = _operationProgresses.Find(o => o.Key == element.FullName!.Path); await _currentOperationProgress.SetValue(currentProgress); - await copyOperation.CopyAsync(new AbsolutePath(_timelessContentProvider, element), newElementPath, new CopyCommandContext(UpdateProgress, currentProgress, _cancellationTokenSource.Token)); + try + { + await copyOperation.CopyAsync(new AbsolutePath(_timelessContentProvider, element), newElementPath, new CopyCommandContext(UpdateProgress, currentProgress, _cancellationTokenSource.Token)); + } + catch (Exception e) + { + _logger.LogError("Error while copying file: {Path}, {Message}", element.FullName!.Path, e.Message); + AddError(new CommandError("Error while copying file: " + element.FullName!.Path, e)); + } } } } @@ -235,4 +243,4 @@ public class CopyCommand : CommandBase, ITransportationCommand //Note: Maybe this should be removed altogether, and every command should use reactive progress return Task.CompletedTask; } -} \ No newline at end of file +}