diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/Timeline/ICommandTimeStateViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/Timeline/ICommandTimeStateViewModel.cs index 59d12c3..700c12f 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/Timeline/ICommandTimeStateViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/Timeline/ICommandTimeStateViewModel.cs @@ -1,11 +1,13 @@ +using DeclarativeProperty; + namespace FileTime.App.Core.ViewModels.Timeline; public interface ICommandTimeStateViewModel { - IObservable TotalProgress { get; } - IObservable CurrentProgress { get; } - IObservable DisplayLabel { get; } - IObservable DisplayDetailLabel { get; } - IObservable IsSelected { get; } + IDeclarativeProperty TotalProgress { get; } + IDeclarativeProperty CurrentProgress { get; } + IDeclarativeProperty DisplayLabel { get; } + IDeclarativeProperty DisplayDetailLabel { get; } + IDeclarativeProperty IsSelected { get; } void Cancel(); } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/Timeline/CommandTimeStateViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/Timeline/CommandTimeStateViewModel.cs index f6765c4..6ca2c5e 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/Timeline/CommandTimeStateViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/Timeline/CommandTimeStateViewModel.cs @@ -1,4 +1,5 @@ using System.Reactive.Subjects; +using DeclarativeProperty; using FileTime.Core.Timeline; namespace FileTime.App.Core.ViewModels.Timeline; @@ -6,13 +7,13 @@ namespace FileTime.App.Core.ViewModels.Timeline; public class CommandTimeStateViewModel : ICommandTimeStateViewModel { private readonly CommandTimeState _commandTimeState; - public IObservable TotalProgress { get; } - public IObservable CurrentProgress { get; } + public IDeclarativeProperty TotalProgress { get; } + public IDeclarativeProperty CurrentProgress { get; } - public IObservable DisplayLabel { get; } - public IObservable DisplayDetailLabel { get; } + public IDeclarativeProperty DisplayLabel { get; } + public IDeclarativeProperty DisplayDetailLabel { get; } - public IObservable IsSelected { get; } + public IDeclarativeProperty IsSelected { get; } public CommandTimeStateViewModel(CommandTimeState commandTimeState) { @@ -22,7 +23,7 @@ public class CommandTimeStateViewModel : ICommandTimeStateViewModel TotalProgress = commandTimeState.Command.TotalProgress; CurrentProgress = commandTimeState.Command.CurrentProgress; //TODO - IsSelected = new BehaviorSubject(false); + IsSelected = new DeclarativeProperty(false); } public void Cancel() diff --git a/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs b/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs index 2fcde92..64b9a09 100644 --- a/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs +++ b/src/Core/FileTime.Core.Abstraction/Command/ICommand.cs @@ -1,13 +1,14 @@ +using DeclarativeProperty; using FileTime.Core.Timeline; namespace FileTime.Core.Command; public interface ICommand { - IObservable DisplayLabel { get; } - IObservable DisplayDetailLabel { get; } - IObservable TotalProgress { get; } - IObservable CurrentProgress { get; } + IDeclarativeProperty DisplayLabel { get; } + IDeclarativeProperty DisplayDetailLabel { get; } + IDeclarativeProperty TotalProgress { get; } + IDeclarativeProperty CurrentProgress { get; } Task CanRun(PointInTime currentTime); Task SimulateCommand(PointInTime currentTime); diff --git a/src/Core/FileTime.Core.Command/CommandBase.cs b/src/Core/FileTime.Core.Command/CommandBase.cs index dafab62..89fbe79 100644 --- a/src/Core/FileTime.Core.Command/CommandBase.cs +++ b/src/Core/FileTime.Core.Command/CommandBase.cs @@ -1,20 +1,21 @@ using System.Reactive.Linq; using System.Reactive.Subjects; +using DeclarativeProperty; using FileTime.Core.Timeline; namespace FileTime.Core.Command; public abstract class CommandBase : ICommand { - private readonly BehaviorSubject _displayLabel; - private readonly BehaviorSubject _displayDetailLabel; - private readonly BehaviorSubject _totalProgress; - private readonly BehaviorSubject _currentProgress; + private readonly DeclarativeProperty _displayLabel; + private readonly DeclarativeProperty _displayDetailLabel; + private readonly DeclarativeProperty _totalProgress; + private readonly DeclarativeProperty _currentProgress; - public IObservable DisplayLabel { get; } - public IObservable DisplayDetailLabel { get; } - public IObservable TotalProgress { get; } - public IObservable CurrentProgress { get; } + public IDeclarativeProperty DisplayLabel { get; } + public IDeclarativeProperty DisplayDetailLabel { get; } + public IDeclarativeProperty TotalProgress { get; } + public IDeclarativeProperty CurrentProgress { get; } protected CommandBase(string displayLabel = "", string displayDetailLabel = "", int totalProgress = 0, int currentProgress = 0) { @@ -23,32 +24,32 @@ public abstract class CommandBase : ICommand _totalProgress = new(totalProgress); _currentProgress = new(currentProgress); - DisplayLabel = _displayLabel.AsObservable(); - DisplayDetailLabel = _displayDetailLabel.AsObservable(); - TotalProgress = _totalProgress.AsObservable(); - CurrentProgress = _currentProgress.AsObservable(); + DisplayLabel = _displayLabel; + DisplayDetailLabel = _displayDetailLabel; + TotalProgress = _totalProgress; + CurrentProgress = _currentProgress; } public abstract Task CanRun(PointInTime currentTime); public abstract Task SimulateCommand(PointInTime currentTime); public abstract void Cancel(); - protected void SetDisplayLabel(string? displayLabel) => _displayLabel.OnNext(displayLabel ?? string.Empty); - protected void SetDisplayDetailLabel(string? displayLabel) => _displayDetailLabel.OnNext(displayLabel ?? string.Empty); + protected async Task SetDisplayLabelAsync(string? displayLabel) => await _displayLabel.SetValue(displayLabel ?? string.Empty); + protected async Task SetDisplayDetailLabel(string? displayLabel) => await _displayDetailLabel.SetValue(displayLabel ?? string.Empty); - protected void SetTotalProgress(int totalProgress) => _totalProgress.OnNext(totalProgress); + protected async Task SetTotalProgress(int totalProgress) => await _totalProgress.SetValue(totalProgress); - protected void SetCurrentProgress(int currentProgress) => _currentProgress.OnNext(currentProgress); + protected async Task SetCurrentProgress(int currentProgress) => await _currentProgress.SetValue(currentProgress); protected IDisposable TrackProgress(IEnumerable operationProgresses) => operationProgresses - .Select(op => op.Progress.Select(p => (Progress: p, TotalProgress: op.TotalCount))) - .CombineLatest() - .Select(data => + .Select(op => op.Progress.Map(p => (Progress: p, TotalProgress: op.TotalCount))) + .CombineAll(data => { - var total = data.Sum(d => d.TotalProgress); - if (total == 0) return 0; - return (int) (data.Sum(d => d.Progress) * 100 / total); + var dataList = data.ToList(); + var total = dataList.Sum(d => d.TotalProgress); + if (total == 0) return Task.FromResult(0); + return Task.FromResult((int)(dataList.Sum(d => d.Progress) * 100 / total)); }) - .Subscribe(SetTotalProgress); + .Subscribe(async (p, _) => await SetTotalProgress(p)); } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs b/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs index 13ee8d6..2498c12 100644 --- a/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs +++ b/src/Core/FileTime.Core.Command/Copy/CopyCommand.cs @@ -17,7 +17,7 @@ public class CopyCommand : CommandBase, ITransportationCommand private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly List _operationProgresses = new(); - private readonly BehaviorSubject _currentOperationProgress = new(null); + private readonly DeclarativeProperty _currentOperationProgress = new(); private long _recentTotalSum; private readonly DeclarativeProperty _recentTotalProcessed = new(); @@ -41,22 +41,21 @@ public class CopyCommand : CommandBase, ITransportationCommand ArgumentNullException.ThrowIfNull(sources); ArgumentNullException.ThrowIfNull(mode); ArgumentNullException.ThrowIfNull(targetFullName); - + _timelessContentProvider = timelessContentProvider; _commandSchedulerNotifier = commandSchedulerNotifier; _logger = logger; _currentOperationProgress - .Select(p => + .Map(p => { - if (p is null) return Observable.Never(); - return p.Progress.Select(currentProgress => + return p?.Progress.Map(currentProgress => p.TotalCount == 0 ? 0 : (int) (currentProgress * 100 / p.TotalCount) ); }) .Switch() - .Subscribe(SetCurrentProgress); + .Subscribe(async (p, _) => await SetCurrentProgress(p)); Sources = new List(sources).AsReadOnly(); TransportMode = mode; @@ -75,7 +74,7 @@ public class CopyCommand : CommandBase, ITransportationCommand recentSpeed .Debounce(TimeSpan.FromMilliseconds(500)) - .Subscribe(SetDisplayDetailLabel); + .Subscribe(async (l, _) => await SetDisplayDetailLabel(l)); } public override Task CanRun(PointInTime currentTime) @@ -145,20 +144,21 @@ public class CopyCommand : CommandBase, ITransportationCommand if (Sources.Count == 1) { - SetDisplayLabel($"Copy - {Sources[0].GetName()}"); + await SetDisplayLabelAsync($"Copy - {Sources[0].GetName()}"); } else { _operationProgresses .Select(o => o.IsDone) - .CombineLatest() - .Subscribe(statuses => + .CombineAll(statuses => { - var done = statuses.Count(s => s) + 1; - if (done > statuses.Count) done = statuses.Count; + var statusList = statuses.ToList(); + var done = statusList.Count(s => s) + 1; + if (done > statusList.Count) done = statusList.Count; - SetDisplayLabel($"Copy - {done} / {statuses.Count}"); - }); + return Task.FromResult($"Copy - {done} / {statusList.Count}"); + }) + .Subscribe(async (v, _) => await SetDisplayLabelAsync(v)); } } @@ -196,7 +196,7 @@ public class CopyCommand : CommandBase, ITransportationCommand var newElementPath = target.GetChild(newElementName, AbsolutePathType.Element); var currentProgress = _operationProgresses.Find(o => o.Key == element.FullName!.Path); - _currentOperationProgress.OnNext(currentProgress); + await _currentOperationProgress.SetValue(currentProgress); await copyOperation.CopyAsync(new AbsolutePath(_timelessContentProvider, element), newElementPath, new CopyCommandContext(UpdateProgress, currentProgress, _cancellationTokenSource.Token)); } diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/MainWindow.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/MainWindow.axaml index a2ecc99..92ea4bb 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/MainWindow.axaml +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Views/MainWindow.axaml @@ -21,7 +21,6 @@ x:DataType="vm:IMainWindowViewModelBase" xmlns="https://github.com/avaloniaui" xmlns:appCoreModels="using:FileTime.App.Core.Models" - xmlns:appInteractions="using:FileTime.App.Core.Interactions" xmlns:corevm="using:FileTime.App.Core.ViewModels" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity" @@ -346,7 +345,7 @@ VerticalAlignment="Top"> - +