WIP CommandScheduler UI
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
namespace FileTime.App.Core.UserCommand;
|
||||
|
||||
public class PauseCommandSchedulerCommand : IIdentifiableUserCommand
|
||||
{
|
||||
public const string CommandName = "pause_command_scheduler";
|
||||
public static PauseCommandSchedulerCommand Instance { get; } = new();
|
||||
|
||||
private PauseCommandSchedulerCommand()
|
||||
{
|
||||
}
|
||||
|
||||
public string UserCommandID => CommandName;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace FileTime.App.Core.UserCommand;
|
||||
|
||||
public sealed class StartCommandSchedulerCommand : IIdentifiableUserCommand
|
||||
{
|
||||
public const string CommandName = "start_command_scheduler";
|
||||
public static StartCommandSchedulerCommand Instance { get; } = new();
|
||||
|
||||
private StartCommandSchedulerCommand()
|
||||
{
|
||||
}
|
||||
|
||||
public string UserCommandID => CommandName;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Subjects;
|
||||
using FileTime.App.Core.Models.Enums;
|
||||
using FileTime.Core.Timeline;
|
||||
using FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels;
|
||||
|
||||
@@ -13,6 +12,7 @@ public interface IAppState
|
||||
IObservable<ViewMode> ViewMode { get; }
|
||||
string RapidTravelText { get; set; }
|
||||
ITabViewModel? CurrentSelectedTab { get; }
|
||||
ITimelineViewModel TimelineViewModel { get; }
|
||||
|
||||
void AddTab(ITabViewModel tabViewModel);
|
||||
void RemoveTab(ITabViewModel tabViewModel);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
public interface ICommandTimeStateViewModel
|
||||
{
|
||||
IObservable<int> TotalProgress { get; }
|
||||
IObservable<string> DisplayLabel { get; }
|
||||
IObservable<bool> IsSelected { get; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
public interface IParallelCommandsViewModel
|
||||
{
|
||||
BindedCollection<ICommandTimeStateViewModel> Commands { get; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
public interface ITimelineViewModel
|
||||
{
|
||||
BindedCollection<IParallelCommandsViewModel> ParallelCommandsGroups { get; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.Services.UserCommandHandler;
|
||||
|
||||
public class CommandSchedulerUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
{
|
||||
private readonly ICommandScheduler _commandScheduler;
|
||||
|
||||
public CommandSchedulerUserCommandHandlerService(ICommandScheduler commandScheduler)
|
||||
{
|
||||
_commandScheduler = commandScheduler;
|
||||
AddCommandHandlers(new IUserCommandHandler[]
|
||||
{
|
||||
new TypeUserCommandHandler<PauseCommandSchedulerCommand>(PauseCommandScheduler),
|
||||
new TypeUserCommandHandler<StartCommandSchedulerCommand>(StartCommandScheduler),
|
||||
});
|
||||
}
|
||||
|
||||
private async Task PauseCommandScheduler()
|
||||
=> await _commandScheduler.SetRunningEnabledAsync(false);
|
||||
|
||||
private async Task StartCommandScheduler()
|
||||
=> await _commandScheduler.SetRunningEnabledAsync(true);
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
|
||||
SaveCurrentLocation(l => _currentLocation = l);
|
||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||
|
||||
_markedItems = new BindedCollection<FullName>(appState.SelectedTab.Select(t => t?.MarkedItems));
|
||||
_markedItems = appState.SelectedTab.Select(t => t?.MarkedItems).ToBindedCollection();
|
||||
|
||||
AddCommandHandlers(new IUserCommandHandler[]
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using FileTime.App.Core.Services.UserCommandHandler;
|
||||
using FileTime.App.Core.StartupServices;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
using FileTime.App.Core.ViewModels.Timeline;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
@@ -23,6 +24,7 @@ public static class Startup
|
||||
serviceCollection.TryAddSingleton<IClipboardService, ClipboardService>();
|
||||
serviceCollection.TryAddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>();
|
||||
serviceCollection.TryAddSingleton<IItemPreviewService, ItemPreviewService>();
|
||||
serviceCollection.TryAddSingleton<ITimelineViewModel, TimelineViewModel>();
|
||||
|
||||
return serviceCollection
|
||||
.AddCommandHandlers()
|
||||
@@ -35,6 +37,7 @@ public static class Startup
|
||||
return serviceCollection
|
||||
.AddSingleton<IUserCommandHandler, NavigationUserCommandHandlerService>()
|
||||
.AddSingleton<IUserCommandHandler, ItemManipulationUserCommandHandlerService>()
|
||||
.AddSingleton<IUserCommandHandler, ToolUserCommandHandlerService>();
|
||||
.AddSingleton<IUserCommandHandler, ToolUserCommandHandlerService>()
|
||||
.AddSingleton<IUserCommandHandler, CommandSchedulerUserCommandHandlerService>();
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,9 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
||||
AddUserCommand(PasteCommand.Merge);
|
||||
AddUserCommand(PasteCommand.Overwrite);
|
||||
AddUserCommand(PasteCommand.Skip);
|
||||
AddUserCommand(PauseCommandSchedulerCommand.Instance);
|
||||
AddUserCommand(RefreshCommand.Instance);
|
||||
AddUserCommand(StartCommandSchedulerCommand.Instance);
|
||||
AddUserCommand(SwitchToTabCommand.SwitchToLastTab);
|
||||
AddUserCommand(SwitchToTabCommand.SwitchToTab1);
|
||||
AddUserCommand(SwitchToTabCommand.SwitchToTab2);
|
||||
|
||||
@@ -3,12 +3,14 @@ using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using DynamicData;
|
||||
using FileTime.App.Core.Models.Enums;
|
||||
using FileTime.App.Core.ViewModels.Timeline;
|
||||
using MvvmGen;
|
||||
using MoreLinq;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels;
|
||||
|
||||
[ViewModel]
|
||||
[Inject(typeof(ITimelineViewModel), "TimelineViewModel", PropertyAccessModifier = AccessModifier.Public)]
|
||||
public abstract partial class AppStateBase : IAppState
|
||||
{
|
||||
private readonly BehaviorSubject<string?> _searchText = new(null);
|
||||
@@ -76,7 +78,10 @@ public abstract partial class AppStateBase : IAppState
|
||||
|
||||
private ITabViewModel? GetSelectedTab(IEnumerable<ITabViewModel> tabs, ITabViewModel? expectedSelectedTab)
|
||||
{
|
||||
var (preferred, others) = tabs.OrderBy(t => t.TabNumber).Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0));
|
||||
var (preferred, others) =
|
||||
tabs
|
||||
.OrderBy(t => t.TabNumber)
|
||||
.Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0));
|
||||
return preferred.Concat(others.Reverse()).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Reactive.Subjects;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
public class CommandTimeStateViewModel : ICommandTimeStateViewModel
|
||||
{
|
||||
public IObservable<int> TotalProgress { get; }
|
||||
|
||||
public IObservable<string> DisplayLabel { get; }
|
||||
|
||||
public IObservable<bool> IsSelected { get; }
|
||||
|
||||
public CommandTimeStateViewModel(CommandTimeState commandTimeState)
|
||||
{
|
||||
DisplayLabel = commandTimeState.Command.DisplayLabel;
|
||||
TotalProgress = commandTimeState.Command.TotalProgress;
|
||||
//TODO
|
||||
IsSelected = new BehaviorSubject<bool>(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using DynamicData.Alias;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
public class ParallelCommandsViewModel : IParallelCommandsViewModel
|
||||
{
|
||||
public BindedCollection<ICommandTimeStateViewModel> Commands { get; }
|
||||
|
||||
public ParallelCommandsViewModel(ParallelCommands parallelCommands)
|
||||
{
|
||||
Commands = parallelCommands
|
||||
.Commands
|
||||
.Select(c => new CommandTimeStateViewModel(c) as ICommandTimeStateViewModel)
|
||||
.ToBindedCollection();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using DynamicData.Alias;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.Timeline;
|
||||
|
||||
public class TimelineViewModel : ITimelineViewModel
|
||||
{
|
||||
public BindedCollection<IParallelCommandsViewModel> ParallelCommandsGroups { get; }
|
||||
|
||||
public TimelineViewModel(ICommandScheduler commandScheduler)
|
||||
{
|
||||
ParallelCommandsGroups =
|
||||
commandScheduler
|
||||
.CommandsToRun
|
||||
.Select(p => new ParallelCommandsViewModel(p) as IParallelCommandsViewModel)
|
||||
.ToBindedCollection();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ namespace FileTime.Core.Command;
|
||||
|
||||
public enum ExecutionState
|
||||
{
|
||||
Initializing,
|
||||
Waiting,
|
||||
Running,
|
||||
Finished
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace FileTime.Core.Command;
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
IObservable<string> DisplayLabel { get; }
|
||||
IObservable<int> TotalProgress { get; }
|
||||
IObservable<int> CurrentProgress { get; }
|
||||
|
||||
Task<CanCommandRun> CanRun(PointInTime currentTime);
|
||||
Task<PointInTime> SimulateCommand(PointInTime currentTime);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Extensions;
|
||||
|
||||
public static class BindedCollectionExtensions
|
||||
{
|
||||
public static BindedCollection<T> ToBindedCollection<T>(this IObservable<IChangeSet<T>> source)
|
||||
{
|
||||
return new BindedCollection<T>(source);
|
||||
}
|
||||
|
||||
public static BindedCollection<T> ToBindedCollection<T>(this IObservable<IObservable<IChangeSet<T>>?> source)
|
||||
{
|
||||
return new BindedCollection<T>(source);
|
||||
}
|
||||
|
||||
public static BindedCollection<T, TKey> ToBindedCollection<T, TKey>(this IObservable<IChangeSet<T, TKey>> source) where TKey : notnull
|
||||
{
|
||||
return new BindedCollection<T, TKey>(source);
|
||||
}
|
||||
|
||||
public static BindedCollection<T, TKey> ToBindedCollection<T, TKey>(this IObservable<IObservable<IChangeSet<T, TKey>>?> source) where TKey : notnull
|
||||
{
|
||||
return new BindedCollection<T, TKey>(source);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public static class DynamicDataExtensions
|
||||
this IObservable<IChangeSet<AbsolutePath, string>> stream)
|
||||
=> await GetItemsAsync(stream.ToCollection());
|
||||
|
||||
private static Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
public static Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
this IObservable<IReadOnlyCollection<AbsolutePath>> stream)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<IEnumerable<AbsolutePath>?>();
|
||||
|
||||
@@ -3,7 +3,7 @@ using System.ComponentModel;
|
||||
using DynamicData;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
|
||||
namespace FileTime.App.Core.Models;
|
||||
namespace FileTime.Core.Models;
|
||||
|
||||
public partial class BindedCollection<T> : IDisposable, INotifyPropertyChanged
|
||||
{
|
||||
@@ -4,18 +4,50 @@ namespace FileTime.Core.Timeline;
|
||||
|
||||
public class CommandTimeState
|
||||
{
|
||||
private object _executionStateLock = new object();
|
||||
private ExecutionState _executionState;
|
||||
public ICommand Command { get; }
|
||||
public CanCommandRun CanRun { get; private set; } = CanCommandRun.False;
|
||||
public bool ForceRun { get; set; }
|
||||
public ExecutionState ExecutionState { get; set; }
|
||||
|
||||
public ExecutionState ExecutionState
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_executionStateLock)
|
||||
{
|
||||
return _executionState;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_executionStateLock)
|
||||
{
|
||||
_executionState = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CommandTimeState(ICommand command)
|
||||
{
|
||||
Command = command;
|
||||
SetToWait();
|
||||
}
|
||||
|
||||
public async Task UpdateStateAsync(PointInTime? startPoint)
|
||||
{
|
||||
CanRun = startPoint == null ? CanCommandRun.False : await Command.CanRun(startPoint);
|
||||
}
|
||||
|
||||
private async void SetToWait()
|
||||
{
|
||||
// This command won't be shown in the scheduler until this timeout is over
|
||||
// Short living commands while not "blink on" the list
|
||||
await Task.Delay(100);
|
||||
lock (_executionStateLock)
|
||||
{
|
||||
if (_executionState == ExecutionState.Initializing)
|
||||
_executionState = ExecutionState.Waiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
@@ -7,5 +8,8 @@ public interface ICommandScheduler
|
||||
{
|
||||
Task AddCommand(ICommand command, int? batchId = null, bool toNewBatch = false);
|
||||
IObservable<FullName> ContainerToRefresh { get; }
|
||||
IObservable<IChangeSet<ParallelCommands>> CommandsToRun { get; }
|
||||
bool IsRunningEnabled { get; }
|
||||
void RefreshContainer(FullName container);
|
||||
Task SetRunningEnabledAsync(bool value);
|
||||
}
|
||||
@@ -1,15 +1,32 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Timeline;
|
||||
|
||||
public class ParallelCommands
|
||||
public class ParallelCommands : IDisposable
|
||||
{
|
||||
private static ushort _idCounter;
|
||||
private List<CommandTimeState> _commands;
|
||||
private readonly SourceList<CommandTimeState> _commands;
|
||||
private PointInTime? _startTime;
|
||||
|
||||
public ushort Id { get; }
|
||||
public IReadOnlyList<CommandTimeState> Commands { get; }
|
||||
|
||||
public IObservable<IChangeSet<CommandTimeState>> Commands { get; }
|
||||
|
||||
public BindedCollection<CommandTimeState> CommandsCollection { get; }
|
||||
|
||||
public PointInTime? Result { get; private set; }
|
||||
|
||||
public PointInTime? StartTime => _startTime;
|
||||
|
||||
public async Task<PointInTime?> SetStartTimeAsync(PointInTime? startTime)
|
||||
{
|
||||
_startTime = startTime;
|
||||
return await RefreshResult();
|
||||
}
|
||||
|
||||
public ParallelCommands(PointInTime? result)
|
||||
: this(new List<CommandTimeState>(), result)
|
||||
{
|
||||
@@ -19,8 +36,10 @@ public class ParallelCommands
|
||||
{
|
||||
Id = _idCounter++;
|
||||
|
||||
_commands = commands;
|
||||
Commands = _commands.AsReadOnly();
|
||||
_commands = new SourceList<CommandTimeState>();
|
||||
_commands.Edit((innerList) => innerList.AddRange(commands));
|
||||
Commands = _commands.Connect();
|
||||
CommandsCollection = Commands.ToBindedCollection();
|
||||
|
||||
Result = result;
|
||||
}
|
||||
@@ -63,10 +82,17 @@ public class ParallelCommands
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PointInTime?> RefreshResult(PointInTime? startPoint)
|
||||
public async Task RemoveCommand(ICommand command)
|
||||
{
|
||||
var result = startPoint;
|
||||
foreach (var commandTimeState in _commands)
|
||||
var commandTimeState = _commands.Items.First(c => c.Command == command);
|
||||
_commands.Remove(commandTimeState);
|
||||
await RefreshResult();
|
||||
}
|
||||
|
||||
public async Task<PointInTime?> RefreshResult()
|
||||
{
|
||||
var result = StartTime;
|
||||
foreach (var commandTimeState in _commands.Items)
|
||||
{
|
||||
await commandTimeState.UpdateStateAsync(result);
|
||||
if (result != null)
|
||||
@@ -87,7 +113,8 @@ public class ParallelCommands
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void RemoveAt(int number) => _commands.RemoveAt(number);
|
||||
|
||||
internal void Remove(CommandTimeState command) => _commands.Remove(command);
|
||||
public void Dispose()
|
||||
{
|
||||
CommandsCollection.Dispose();
|
||||
}
|
||||
}
|
||||
36
src/Core/FileTime.Core.Command/CommandBase.cs
Normal file
36
src/Core/FileTime.Core.Command/CommandBase.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command;
|
||||
|
||||
public abstract class CommandBase : ICommand
|
||||
{
|
||||
private readonly BehaviorSubject<string> _displayLabel;
|
||||
private readonly BehaviorSubject<int> _totalProgress;
|
||||
private readonly BehaviorSubject<int> _currentProgress;
|
||||
|
||||
public IObservable<string> DisplayLabel { get; }
|
||||
public IObservable<int> TotalProgress { get; }
|
||||
public IObservable<int> CurrentProgress { get; }
|
||||
|
||||
protected CommandBase(string displayLabel = "", int totalProgress = 0, int currentProgress = 0)
|
||||
{
|
||||
_displayLabel = new(displayLabel);
|
||||
_totalProgress = new(totalProgress);
|
||||
_currentProgress = new(currentProgress);
|
||||
|
||||
DisplayLabel = _displayLabel.AsObservable();
|
||||
TotalProgress = _totalProgress.AsObservable();
|
||||
CurrentProgress = _currentProgress.AsObservable();
|
||||
}
|
||||
|
||||
public abstract Task<CanCommandRun> CanRun(PointInTime currentTime);
|
||||
public abstract Task<PointInTime> SimulateCommand(PointInTime currentTime);
|
||||
|
||||
protected void SetDisplayLabel(string displayLabel) => _displayLabel.OnNext(displayLabel);
|
||||
|
||||
protected void SetTotalProgress(int totalProgress) => _totalProgress.OnNext(totalProgress);
|
||||
|
||||
protected void SetCurrentProgress(int currentProgress) => _currentProgress.OnNext(currentProgress);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command.Copy;
|
||||
|
||||
public class CopyCommand : ITransportationCommand
|
||||
public class CopyCommand : CommandBase, ITransportationCommand
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
|
||||
@@ -22,18 +22,19 @@ public class CopyCommand : ITransportationCommand
|
||||
public CopyCommand(
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
ICommandSchedulerNotifier commandSchedulerNotifier)
|
||||
: base("Copy")
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_commandSchedulerNotifier = commandSchedulerNotifier;
|
||||
}
|
||||
|
||||
public Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
//TODO:
|
||||
return Task.FromResult(CanCommandRun.True);
|
||||
}
|
||||
|
||||
public async Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
public override async Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
|
||||
@@ -7,7 +7,7 @@ using InitableService;
|
||||
|
||||
namespace FileTime.Core.Command.Create;
|
||||
|
||||
public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, string>
|
||||
public abstract class CreateItemBase : CommandBase, IExecutableCommand, IInitable<FullName, string>
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
@@ -17,12 +17,13 @@ public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, s
|
||||
protected CreateItemBase(
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
: base("Create")
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public async Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
public override async Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
if (Parent is null)
|
||||
{
|
||||
@@ -60,7 +61,7 @@ public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, s
|
||||
return CanCommandRun.False;
|
||||
}
|
||||
|
||||
public Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
public override Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
if (Parent is null)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command.Delete;
|
||||
|
||||
public class DeleteCommand : IExecutableCommand
|
||||
public class DeleteCommand : CommandBase, IExecutableCommand
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
@@ -15,18 +15,19 @@ public class DeleteCommand : IExecutableCommand
|
||||
public DeleteCommand(
|
||||
IContentAccessorFactory contentAccessorFactory,
|
||||
ITimelessContentProvider timelessContentProvider)
|
||||
: base("Delete")
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
}
|
||||
|
||||
public Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
//TODO
|
||||
return Task.FromResult(CanCommandRun.True);
|
||||
}
|
||||
|
||||
public Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
public override Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
//TODO
|
||||
return Task.FromResult(currentTime);
|
||||
|
||||
@@ -13,28 +13,31 @@ public class CommandScheduler : ICommandScheduler
|
||||
private readonly Subject<FullName> _containerToRefresh = new();
|
||||
|
||||
private readonly object _guard = new();
|
||||
private bool _enableRunning = true;
|
||||
private bool _isRunningEnabled = true;
|
||||
private bool _resourceIsInUse;
|
||||
|
||||
public IObservable<FullName> ContainerToRefresh { get; }
|
||||
|
||||
public bool EnableRunning
|
||||
public bool IsRunningEnabled => _isRunningEnabled;
|
||||
|
||||
public async Task SetRunningEnabledAsync(bool value)
|
||||
{
|
||||
get
|
||||
_isRunningEnabled = value;
|
||||
if (value)
|
||||
{
|
||||
var result = true;
|
||||
RunWithLock(() => result = _enableRunning);
|
||||
return result;
|
||||
await RunWithLockAsync(ExecuteCommands);
|
||||
}
|
||||
}
|
||||
|
||||
set { RunWithLock(() => _enableRunning = value); }
|
||||
}
|
||||
public IObservable<IChangeSet<ParallelCommands>> CommandsToRun { get; }
|
||||
|
||||
public CommandScheduler(ILocalCommandExecutor localExecutor)
|
||||
{
|
||||
CommandsToRun = _commandsToRun.Connect();
|
||||
|
||||
ContainerToRefresh = _containerToRefresh.AsObservable();
|
||||
|
||||
localExecutor.CommandFinished += LocalExecutorOnCommandFinished;
|
||||
localExecutor.CommandFinished += ExecutorOnCommandFinished;
|
||||
_commandExecutors.Add(localExecutor);
|
||||
}
|
||||
|
||||
@@ -46,6 +49,7 @@ public class CommandScheduler : ICommandScheduler
|
||||
|
||||
if (_commandsToRun.Count == 0)
|
||||
{
|
||||
//TODO: Add event handler to update
|
||||
batchToAdd = new ParallelCommands(PointInTime.CreateEmpty());
|
||||
_commandsToRun.Add(batchToAdd);
|
||||
}
|
||||
@@ -82,13 +86,11 @@ public class CommandScheduler : ICommandScheduler
|
||||
|
||||
private void ExecuteCommands()
|
||||
{
|
||||
if (!_enableRunning) return;
|
||||
if (!_isRunningEnabled) return;
|
||||
|
||||
var parallelCommandsToExecute = _commandsToRun.Items.FirstOrDefault();
|
||||
if (parallelCommandsToExecute is null ||
|
||||
parallelCommandsToExecute.Commands.All(c => c.ExecutionState != ExecutionState.Waiting)) return;
|
||||
var commandsToExecute = _commandsToRun.Items.FirstOrDefault()?.CommandsCollection.Collection;
|
||||
if (commandsToExecute is null || commandsToExecute.All(c => c.ExecutionState != ExecutionState.Initializing && c.ExecutionState != ExecutionState.Waiting)) return;
|
||||
|
||||
var commandsToExecute = parallelCommandsToExecute.Commands;
|
||||
|
||||
foreach (var commandToExecute in commandsToExecute)
|
||||
{
|
||||
@@ -108,15 +110,20 @@ public class CommandScheduler : ICommandScheduler
|
||||
return _commandExecutors[0];
|
||||
}
|
||||
|
||||
private void LocalExecutorOnCommandFinished(object? sender, ICommand command)
|
||||
private async void ExecutorOnCommandFinished(object? sender, ICommand command)
|
||||
{
|
||||
var parallelCommandsToExecute = _commandsToRun.Items.FirstOrDefault();
|
||||
if (parallelCommandsToExecute is null) return;
|
||||
var firstCommandBlock = _commandsToRun
|
||||
.Items
|
||||
.FirstOrDefault();
|
||||
var state = firstCommandBlock
|
||||
?.CommandsCollection
|
||||
.Collection
|
||||
?.FirstOrDefault(c => c.Command == command);
|
||||
|
||||
var state = parallelCommandsToExecute.Commands.FirstOrDefault(c => c.Command == command);
|
||||
if (state is null) return;
|
||||
|
||||
state.ExecutionState = ExecutionState.Finished;
|
||||
if (firstCommandBlock is not null) await firstCommandBlock.RemoveCommand(command);
|
||||
}
|
||||
|
||||
private async Task RefreshCommands()
|
||||
@@ -125,7 +132,7 @@ public class CommandScheduler : ICommandScheduler
|
||||
|
||||
foreach (var batch in _commandsToRun.Items)
|
||||
{
|
||||
currentTime = await batch.RefreshResult(currentTime);
|
||||
currentTime = await batch.SetStartTimeAsync(currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace FileTime.Core.Timeline;
|
||||
public class LocalCommandExecutor : ILocalCommandExecutor
|
||||
{
|
||||
private readonly ICommandRunner _commandRunner;
|
||||
public event EventHandler<ICommand> CommandFinished;
|
||||
public event EventHandler<ICommand>? CommandFinished;
|
||||
|
||||
public LocalCommandExecutor(ICommandRunner commandRunner)
|
||||
{
|
||||
@@ -15,7 +15,7 @@ public class LocalCommandExecutor : ILocalCommandExecutor
|
||||
public void ExecuteCommand(ICommand command)
|
||||
{
|
||||
var context = new CommandRunnerContext(command);
|
||||
var thread = new Thread(new ParameterizedThreadStart(RunCommand));
|
||||
var thread = new Thread(RunCommand);
|
||||
thread.Start(context);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ public class LocalCommandExecutor : ILocalCommandExecutor
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
|
||||
CommandFinished.Invoke(this, context.Command);
|
||||
CommandFinished?.Invoke(this, context.Command);
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,7 @@ public static class MainConfiguration
|
||||
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Key.D, Key.D }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.Edit, new KeyConfig(Key.F4)),
|
||||
new(EnterRapidTravelCommand.CommandName,new KeyConfig(Key.OemComma, shift: true)),
|
||||
new(EnterRapidTravelCommand.CommandName,new KeyConfig(Key.OemQuestion, shift: true)),
|
||||
//new CommandBindingConfiguration(ConfigCommand.FindByName, new[] { Key.F, Key.N }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.FindByNameRegex, new[] { Key.F, Key.R }),
|
||||
new(GoToHomeCommand.CommandName, new[] { Key.G, Key.H }),
|
||||
@@ -92,9 +93,9 @@ public static class MainConfiguration
|
||||
new(SwitchToTabCommand.SwitchToTab6CommandName, Key.D6),
|
||||
new(SwitchToTabCommand.SwitchToTab7CommandName, Key.D7),
|
||||
new(SwitchToTabCommand.SwitchToTab8CommandName, Key.D8),
|
||||
//new CommandBindingConfiguration(ConfigCommand.TimelinePause, new[] { Key.T, Key.P }),
|
||||
new (PauseCommandSchedulerCommand.CommandName, new[] { Key.T, Key.P }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.TimelineRefresh, new[] { Key.T, Key.R }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.TimelineStart, new[] { Key.T, Key.S }),
|
||||
new (StartCommandSchedulerCommand.CommandName, new[] { Key.T, Key.S }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ToggleAdvancedIcons, new[] { Key.Z, Key.I }),
|
||||
new(GoUpCommand.CommandName, Key.Left),
|
||||
new(OpenSelectedCommand.CommandName, Key.Right),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.Configuration;
|
||||
|
||||
namespace FileTime.GuiApp.ViewModels;
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.Core.ViewModels.Timeline;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.Configuration;
|
||||
using FileTime.GuiApp.ViewModels;
|
||||
using MvvmGen;
|
||||
|
||||
namespace FileTime.GuiApp.CustomImpl.ViewModels;
|
||||
|
||||
[ViewModel]
|
||||
[ViewModel(GenerateConstructor = false)]
|
||||
public partial class GuiAppState : AppStateBase, IGuiAppState
|
||||
{
|
||||
public GuiAppState(ITimelineViewModel timelineViewModel) : base(timelineViewModel)
|
||||
{
|
||||
}
|
||||
|
||||
[Property] private bool _isAllShortcutVisible;
|
||||
|
||||
[Property] private bool _noCommandFound;
|
||||
@@ -18,7 +23,7 @@ public partial class GuiAppState : AppStateBase, IGuiAppState
|
||||
|
||||
[Property] private BindedCollection<RootDriveInfo, string> _rootDriveInfos = new();
|
||||
|
||||
[Property] private IReadOnlyList<PlaceInfo> _places;
|
||||
[Property] private IReadOnlyList<PlaceInfo> _places = new List<PlaceInfo>();
|
||||
|
||||
public List<KeyConfig> PreviousKeys { get; } = new();
|
||||
public ObservableCollection<string> PopupTexts { get; } = new();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
<Styles
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Styles.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Converters.axaml"></ResourceInclude>
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Converters.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Styles.Resources>
|
||||
@@ -28,7 +29,7 @@
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
<Style Selector="ListBox.ContentListView > ListBoxItem">
|
||||
<Style Selector="ListBox.ContentListView > ListBoxItem">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
@@ -61,10 +62,10 @@
|
||||
<ControlTemplate>
|
||||
<Border>
|
||||
<RadioButton
|
||||
VerticalAlignment="Center"
|
||||
Content="{TemplateBinding ContentPresenter.Content}"
|
||||
Foreground="{DynamicResource ForegroundBrush}"
|
||||
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
|
||||
VerticalAlignment="Center" />
|
||||
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
@@ -74,9 +75,9 @@
|
||||
<Style Selector="Image.LoadingAnimation">
|
||||
<Style.Animations>
|
||||
<Animation
|
||||
Duration="0:0:2"
|
||||
Easing="QuadraticEaseInOut"
|
||||
IterationCount="INFINITE">
|
||||
IterationCount="INFINITE"
|
||||
Duration="0:0:2">
|
||||
<KeyFrame Cue="0%">
|
||||
<Setter Property="RotateTransform.Angle" Value="45" />
|
||||
</KeyFrame>
|
||||
@@ -86,4 +87,8 @@
|
||||
</Animation>
|
||||
</Style.Animations>
|
||||
</Style>
|
||||
|
||||
<Style Selector="Border.SelectedTimelineCommand">
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource ForegroundBrush}" />
|
||||
</Style>
|
||||
</Styles>
|
||||
@@ -4,6 +4,7 @@ using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.Configuration;
|
||||
using FileTime.GuiApp.Extensions;
|
||||
@@ -44,7 +45,7 @@ public class DefaultModeKeyInputHandler : IDefaultModeKeyInputHandler
|
||||
_appState.SelectedTab.Subscribe(t => _selectedTab = t);
|
||||
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation!).Switch().Subscribe(l => _currentLocation = l);
|
||||
|
||||
_openModals = new BindedCollection<IModalViewModel>(modalService.OpenModals);
|
||||
_openModals = modalService.OpenModals.ToBindedCollection();
|
||||
|
||||
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Up) });
|
||||
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Down) });
|
||||
|
||||
@@ -3,6 +3,7 @@ using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Services;
|
||||
using FileTime.GuiApp.Configuration;
|
||||
@@ -42,7 +43,7 @@ public class RapidTravelModeKeyInputHandler : IRapidTravelModeKeyInputHandler
|
||||
|
||||
_appState.SelectedTab.Subscribe(t => _selectedTab = t);
|
||||
|
||||
_openModals = new BindedCollection<IModalViewModel>(modalService.OpenModals);
|
||||
_openModals = modalService.OpenModals.ToBindedCollection();
|
||||
}
|
||||
|
||||
public async Task HandleInputKey(Key key, SpecialKeysStatus specialKeysStatus, Action<bool> setHandled)
|
||||
|
||||
@@ -4,6 +4,7 @@ using DynamicData;
|
||||
using DynamicData.Binding;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
using FileTime.GuiApp.ViewModels;
|
||||
@@ -53,7 +54,7 @@ public class RootDriveInfoService : IStartupHandler
|
||||
.Transform(t => new RootDriveInfo(t.Drive, t.Container))
|
||||
.Sort(SortExpressionComparer<RootDriveInfo>.Ascending(d => d.Name));
|
||||
|
||||
guiAppState.RootDriveInfos = new BindedCollection<RootDriveInfo, string>(rootDriveInfos);
|
||||
guiAppState.RootDriveInfos = rootDriveInfos.ToBindedCollection();
|
||||
|
||||
void InitRootDrives()
|
||||
{
|
||||
|
||||
@@ -2,35 +2,35 @@
|
||||
x:Class="FileTime.GuiApp.Views.MainWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:appCoreModels="using:FileTime.App.Core.Models"
|
||||
xmlns:config="using:FileTime.GuiApp.Configuration"
|
||||
xmlns:corevm="using:FileTime.App.Core.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:interactions="using:FileTime.Core.Interactions"
|
||||
xmlns:local="using:FileTime.GuiApp.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:vm="using:FileTime.GuiApp.ViewModels"
|
||||
xmlns:config="using:FileTime.GuiApp.Configuration"
|
||||
xmlns:appCoreModels="using:FileTime.App.Core.Models"
|
||||
xmlns:interactions="using:FileTime.Core.Interactions"
|
||||
MinHeight="600"
|
||||
MinWidth="800"
|
||||
Title="FileTime"
|
||||
MinWidth="800"
|
||||
MinHeight="600"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
x:CompileBindings="True"
|
||||
x:DataType="vm:IMainWindowViewModelBase"
|
||||
Background="Transparent"
|
||||
Closed="OnWindowClosed"
|
||||
ExtendClientAreaToDecorationsHint="True"
|
||||
Icon="/Assets/filetime.ico"
|
||||
InputElement.KeyDown="OnKeyDown"
|
||||
Opened="OnWindowOpened"
|
||||
Closed="OnWindowClosed"
|
||||
TransparencyLevelHint="Blur"
|
||||
mc:Ignorable="d">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/SolarizedDarkTheme.axaml"></ResourceInclude>
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Brushes.axaml"></ResourceInclude>
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Converters.axaml"></ResourceInclude>
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/SolarizedDarkTheme.axaml" />
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Brushes.axaml" />
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Converters.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
@@ -62,18 +62,22 @@
|
||||
<StackPanel
|
||||
Margin="20,10"
|
||||
Orientation="Horizontal">
|
||||
<local:PathPresenter
|
||||
DataContext="{Binding AppState.SelectedTab^.CurrentLocation^.FullName.Path,Converter={StaticResource PathPreformatter}}" />
|
||||
<local:PathPresenter DataContext="{Binding AppState.SelectedTab^.CurrentLocation^.FullName.Path, Converter={StaticResource PathPreformatter}}" />
|
||||
<TextBlock
|
||||
Foreground="{StaticResource AccentBrush}"
|
||||
Text="{Binding AppState.SelectedTab^.CurrentSelectedItem^.DisplayNameText}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<Border CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="10"
|
||||
Margin="10">
|
||||
<Border
|
||||
Margin="10"
|
||||
Padding="10"
|
||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||
CornerRadius="10">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
@@ -85,9 +89,13 @@
|
||||
Items="{Binding AppState.RootDriveInfos.Collection}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:RootDriveInfo">
|
||||
<Grid Classes="SidebarContainerPresenter"
|
||||
PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
|
||||
<Grid Margin="0,5" ColumnDefinitions="Auto,*,Auto"
|
||||
<Grid
|
||||
Classes="SidebarContainerPresenter"
|
||||
Cursor="Hand"
|
||||
PointerPressed="OnHasContainerPointerPressed">
|
||||
<Grid
|
||||
Margin="0,5"
|
||||
ColumnDefinitions="Auto,*,Auto"
|
||||
RowDefinitions="Auto,Auto">
|
||||
<Image
|
||||
Grid.RowSpan="2"
|
||||
@@ -99,8 +107,8 @@
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
@@ -112,35 +120,38 @@
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="ExtraSmallText"
|
||||
Text="{Binding Label}"
|
||||
IsVisible="{Binding Label,Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
||||
IsVisible="{Binding Label, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"
|
||||
Text="{Binding Label}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Grid.Column="2"
|
||||
Orientation="Horizontal"
|
||||
VerticalAlignment="Center">
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock Classes="SmallText" VerticalAlignment="Center"
|
||||
Text="{Binding Free, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="SmallText"
|
||||
Text="{Binding Free, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}" />
|
||||
|
||||
<TextBlock Classes="SmallText" VerticalAlignment="Center"
|
||||
Text=" / ">
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="SmallText"
|
||||
Text=" / " />
|
||||
|
||||
<TextBlock Classes="SmallText" VerticalAlignment="Center"
|
||||
Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
Classes="SmallText"
|
||||
Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}" />
|
||||
</StackPanel>
|
||||
|
||||
<ProgressBar
|
||||
Margin="5,0,0,0"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="1"
|
||||
MinWidth="100"
|
||||
Margin="5,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Maximum="100"
|
||||
Value="{Binding UsedPercentage}" />
|
||||
@@ -152,8 +163,12 @@
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="1" CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}"
|
||||
Padding="0,10" Margin="10">
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
Margin="10"
|
||||
Padding="0,10"
|
||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||
CornerRadius="10">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
@@ -165,10 +180,14 @@
|
||||
Items="{Binding AppState.Places}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:PlaceInfo">
|
||||
<Grid Classes="SidebarContainerPresenter"
|
||||
PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
|
||||
<StackPanel Orientation="Horizontal" Margin="10,5"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Grid
|
||||
Classes="SidebarContainerPresenter"
|
||||
Cursor="Hand"
|
||||
PointerPressed="OnHasContainerPointerPressed">
|
||||
<StackPanel
|
||||
Margin="10,5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Horizontal">
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
@@ -258,6 +277,46 @@
|
||||
Grid.Column="1"
|
||||
RowDefinitions="Auto,40,*,Auto">
|
||||
|
||||
<Grid>
|
||||
<ItemsControl Items="{Binding AppState.TimelineViewModel.ParallelCommandsGroups.Collection}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
MaxHeight="200"
|
||||
Margin="0,0,10,0"
|
||||
Padding="5"
|
||||
Background="{DynamicResource ContainerBackgroundColor}"
|
||||
CornerRadius="10">
|
||||
<ScrollViewer>
|
||||
<ItemsControl Items="{Binding Commands.Collection}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border
|
||||
BorderThickness="1"
|
||||
Classes.SelectedTimelineCommand="{Binding IsSelected}">
|
||||
<StackPanel>
|
||||
<TextBlock Text="{Binding DisplayLabel^}" />
|
||||
<ProgressBar
|
||||
Margin="0,5,0,0"
|
||||
Maximum="100"
|
||||
Value="{Binding TotalProgress^}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
|
||||
<ItemsControl
|
||||
Grid.Row="1"
|
||||
Items="{Binding AppState.Tabs}">
|
||||
@@ -308,9 +367,9 @@
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="corevm:IItemViewModel">
|
||||
<local:ItemView
|
||||
ShowAttributes="False"
|
||||
HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch" />
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ShowAttributes="False" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
@@ -326,8 +385,7 @@
|
||||
<Grid
|
||||
Grid.Column="2"
|
||||
RowDefinitions="Auto,*">
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.SelectedTab^.CurrentLocation^.IsLoading^, FallbackValue=False}">
|
||||
<Grid IsVisible="{Binding AppState.SelectedTab^.CurrentLocation^.IsLoading^, FallbackValue=False}">
|
||||
<Image
|
||||
Width="40"
|
||||
Height="40"
|
||||
@@ -341,9 +399,9 @@
|
||||
Classes="ContentListView"
|
||||
IsTabStop="True"
|
||||
Items="{Binding AppState.SelectedTab^.CurrentItemsCollection.Collection}"
|
||||
SelectedItem="{Binding AppState.SelectedTab^.CurrentSelectedItem^}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Visible">
|
||||
ScrollViewer.VerticalScrollBarVisibility="Visible"
|
||||
SelectedItem="{Binding AppState.SelectedTab^.CurrentSelectedItem^}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="corevm:IItemViewModel">
|
||||
<local:ItemView
|
||||
@@ -375,10 +433,8 @@
|
||||
Fill="{DynamicResource ContentSeparatorBrush}" />
|
||||
|
||||
<Grid Grid.Column="4">
|
||||
<Grid
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^,Converter={x:Static ObjectConverters.IsNull}}">
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildrenCollection.Collection, Converter={x:Static ObjectConverters.IsNotNull}, FallbackValue=False}">
|
||||
<Grid IsVisible="{Binding ItemPreviewService.ItemPreview^, Converter={x:Static ObjectConverters.IsNull}}">
|
||||
<Grid IsVisible="{Binding AppState.SelectedTab^.SelectedsChildrenCollection.Collection, Converter={x:Static ObjectConverters.IsNotNull}, FallbackValue=False}">
|
||||
<ListBox
|
||||
x:Name="ChildItems"
|
||||
x:CompileBindings="False"
|
||||
@@ -428,26 +484,31 @@
|
||||
</ItemsRepeater>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^,Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<TextBlock HorizontalAlignment="Center" Text="Don't know how to preview this item."
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Unknown},FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}" />
|
||||
<TextBlock HorizontalAlignment="Center" Text="Empty"
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Empty},FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}" />
|
||||
<ScrollViewer
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Text},FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}">
|
||||
<Grid IsVisible="{Binding ItemPreviewService.ItemPreview^, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Unknown}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
Text="Don't know how to preview this item." />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Empty}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
Text="Empty" />
|
||||
<ScrollViewer IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Text}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}">
|
||||
<TextBox
|
||||
IsReadOnly="True"
|
||||
x:CompileBindings="False"
|
||||
IsReadOnly="True"
|
||||
Text="{Binding ItemPreviewService.ItemPreview^.TextContent}" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<ItemsRepeater Items="{Binding AppState.PopupTexts}" Margin="0,0,0,20"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Top"
|
||||
IsVisible="{Binding AppState.PopupTexts.Count,Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||
<ItemsRepeater
|
||||
Margin="0,0,0,20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="{Binding AppState.PopupTexts.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}"
|
||||
Items="{Binding AppState.PopupTexts}">
|
||||
<ItemsRepeater.Styles>
|
||||
<Style Selector="TextBlock">
|
||||
<Style.Animations>
|
||||
@@ -464,11 +525,14 @@
|
||||
</ItemsRepeater.Styles>
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate x:DataType="x:String">
|
||||
<Border Background="{DynamicResource ContainerGradientBackgroundBrush}" Margin="5"
|
||||
Padding="5">
|
||||
<TextBlock Text="{Binding}"
|
||||
<Border
|
||||
Margin="5"
|
||||
Padding="5"
|
||||
Background="{DynamicResource ContainerGradientBackgroundBrush}">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
Foreground="{DynamicResource AccentComplementBrush}"
|
||||
HorizontalAlignment="Center" />
|
||||
Text="{Binding}" />
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
@@ -502,8 +566,7 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.PossibleCommands.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||
<Grid IsVisible="{Binding AppState.PossibleCommands.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1" />
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -528,7 +591,8 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding KeysDisplayText}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Text="{Binding Command, Converter={StaticResource CommandToCommandNameConverter}}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
@@ -540,15 +604,15 @@
|
||||
</Grid>
|
||||
|
||||
<Border
|
||||
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
||||
IsVisible="{Binding DialogService.ReadInput^, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<Border
|
||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||
Padding="20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center">
|
||||
VerticalAlignment="Center"
|
||||
Background="{DynamicResource ContainerBackgroundBrush}">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<ItemsControl
|
||||
@@ -556,22 +620,26 @@
|
||||
Items="{Binding DialogService.ReadInput^.Inputs}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid MinWidth="500" ColumnDefinitions="250,*" Margin="10,5" x:Name="ItemRoot">
|
||||
<Grid
|
||||
x:Name="ItemRoot"
|
||||
MinWidth="500"
|
||||
Margin="10,5"
|
||||
ColumnDefinitions="250,*">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding Label}" />
|
||||
<Grid Grid.Column="1">
|
||||
<TextBox
|
||||
VerticalAlignment="Top"
|
||||
x:DataType="interactions:TextInputElement"
|
||||
IsVisible="{Binding Type, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static interactions:InputType.Text}}"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding Value, Mode=TwoWay}" />
|
||||
<TextBox
|
||||
VerticalAlignment="Top"
|
||||
x:DataType="interactions:PasswordInputElement"
|
||||
IsVisible="{Binding Type, Converter={StaticResource EqualityConverter}, ConverterParameter={x:Static interactions:InputType.Password}}"
|
||||
PasswordChar="{Binding PasswordChar}"
|
||||
VerticalAlignment="Top"
|
||||
Text="{Binding Value, Mode=TwoWay}" />
|
||||
<ListBox
|
||||
x:DataType="interactions:IOptionsInputElement"
|
||||
@@ -587,17 +655,17 @@
|
||||
<StackPanel
|
||||
DataContext="{Binding DialogService.ReadInput^}"
|
||||
Grid.Row="1"
|
||||
Orientation="Horizontal"
|
||||
Margin="0,10,0,0">
|
||||
Margin="0,10,0,0"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
HorizontalContentAlignment="Center"
|
||||
Width="80"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding ProcessCommand}"
|
||||
Content="Ok" />
|
||||
<Button
|
||||
HorizontalContentAlignment="Center"
|
||||
Width="80"
|
||||
Margin="10,0,0,0"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding CancelCommand}"
|
||||
Content="Cancel" />
|
||||
</StackPanel>
|
||||
@@ -606,32 +674,32 @@
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
||||
DataContext="{Binding DialogService.LastMessageBox^}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
DataContext="{Binding DialogService.LastMessageBox^}"
|
||||
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
||||
IsVisible="{Binding Converter={x:Static ObjectConverters.IsNotNull}, FallbackValue=False}">
|
||||
<Border
|
||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||
Padding="20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Padding="20">
|
||||
Background="{DynamicResource ContainerBackgroundBrush}">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock Text="{Binding Text}" />
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Orientation="Horizontal"
|
||||
Margin="0,10,0,0">
|
||||
Margin="0,10,0,0"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
HorizontalContentAlignment="Center"
|
||||
Width="80"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding OkCommand}"
|
||||
Content="Yes" />
|
||||
<Button
|
||||
HorizontalContentAlignment="Center"
|
||||
Width="80"
|
||||
Margin="10,0,0,0"
|
||||
HorizontalContentAlignment="Center"
|
||||
Command="{Binding CancelCommand}"
|
||||
Content="No" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -232,30 +232,32 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
||||
pointInTime,
|
||||
exceptions,
|
||||
new ExtensionCollection().AsReadOnly(),
|
||||
Observable.FromAsync(async () => await Task.Run(InitChildren))
|
||||
//Observable.FromAsync(async () => await Task.Run(InitChildrenHelper)
|
||||
Observable.Return(InitChildren())
|
||||
);
|
||||
|
||||
Task<IObservable<IChangeSet<AbsolutePath, string>>?> InitChildren()
|
||||
Task<IObservable<IChangeSet<AbsolutePath, string>>?> InitChildrenHelper() => Task.FromResult(InitChildren());
|
||||
|
||||
IObservable<IChangeSet<AbsolutePath, string>>? InitChildren()
|
||||
{
|
||||
if (!initializeChildren) return null;
|
||||
|
||||
try
|
||||
{
|
||||
var items = initializeChildren ? (List<AbsolutePath>?) GetItemsByContainer(directoryInfo, pointInTime) : null;
|
||||
if (items != null)
|
||||
{
|
||||
var items = GetItemsByContainer(directoryInfo, pointInTime);
|
||||
var result = new SourceCache<AbsolutePath, string>(i => i.Path.Path);
|
||||
|
||||
if (items.Count == 0) return Task.FromResult((IObservable<IChangeSet<AbsolutePath, string>>?) result.Connect().StartWithEmpty());
|
||||
if (items.Count == 0) return (IObservable<IChangeSet<AbsolutePath, string>>?) result.Connect().StartWithEmpty();
|
||||
|
||||
result.AddOrUpdate(items);
|
||||
return Task.FromResult((IObservable<IChangeSet<AbsolutePath, string>>?) result.Connect());
|
||||
}
|
||||
return (IObservable<IChangeSet<AbsolutePath, string>>?) result.Connect();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
exceptions.OnNext(new List<Exception>() {e});
|
||||
exceptions.OnNext(new List<Exception> {e});
|
||||
}
|
||||
|
||||
return Task.FromResult((IObservable<IChangeSet<AbsolutePath, string>>?) null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user