Timeless refactor

This commit is contained in:
2022-05-21 14:30:24 +02:00
parent ced0c88a10
commit 6ee5afa632
47 changed files with 571 additions and 181 deletions

View File

@@ -6,10 +6,10 @@ namespace FileTime.App.Core.Services;
public interface IClipboardService
{
Type? CommandType { get; }
IReadOnlyList<IAbsolutePath> Content { get; }
IReadOnlyList<FullName> Content { get; }
void AddContent(IAbsolutePath absolutePath);
void RemoveContent(IAbsolutePath absolutePath);
void AddContent(FullName absolutePath);
void RemoveContent(FullName absolutePath);
void Clear();
void SetCommand<T>() where T : ITransportationCommand;
}

View File

@@ -4,9 +4,9 @@ namespace FileTime.App.Core.UserCommand;
public class OpenContainerCommand : IUserCommand
{
public IAbsolutePath Path { get; }
public AbsolutePath Path { get; }
public OpenContainerCommand(IAbsolutePath path)
public OpenContainerCommand(AbsolutePath path)
{
Path = path;
}

View File

@@ -1,5 +1,7 @@
using System.Collections.ObjectModel;
using System.Reactive.Subjects;
using FileTime.App.Core.Models.Enums;
using FileTime.Core.Timeline;
namespace FileTime.App.Core.ViewModels;

View File

@@ -15,7 +15,7 @@ public interface ITabViewModel : IInitable<ITab, int>
IObservable<IContainer?> CurrentLocation { get; }
IObservable<IItemViewModel?> CurrentSelectedItem { get; }
IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; }
IObservable<IChangeSet<IAbsolutePath>> MarkedItems { get; }
IObservable<IChangeSet<FullName>> MarkedItems { get; }
IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; }
IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; }
BindedCollection<IItemViewModel>? CurrentItemsCollection { get; }
@@ -25,7 +25,7 @@ public interface ITabViewModel : IInitable<ITab, int>
IObservable<IReadOnlyCollection<IItemViewModel>?> ParentsChildrenCollectionObservable { get; }
IObservable<IReadOnlyCollection<IItemViewModel>?> SelectedsChildrenCollectionObservable { get; }
void ClearMarkedItems();
void RemoveMarkedItem(IAbsolutePath item);
void AddMarkedItem(IAbsolutePath item);
void ToggleMarkedItem(IAbsolutePath item);
void RemoveMarkedItem(FullName fullName);
void AddMarkedItem(FullName fullName);
void ToggleMarkedItem(FullName fullName);
}

View File

@@ -1,13 +1,14 @@
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
namespace FileTime.App.Core.Extensions;
public static class ViewModelExtensions
{
public static IAbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel)
public static AbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel, ITimelessContentProvider timelessContentProvider)
{
var item = itemViewModel.BaseItem ?? throw new ArgumentException($"{nameof(itemViewModel)} does not have {nameof(IItemViewModel.BaseItem)}");
return new AbsolutePath(item);
return new AbsolutePath(timelessContentProvider, item);
}
}

View File

@@ -5,17 +5,17 @@ namespace FileTime.App.Core.Services;
public class ClipboardService : IClipboardService
{
private List<IAbsolutePath> _content;
public IReadOnlyList<IAbsolutePath> Content { get; private set; }
private List<FullName> _content;
public IReadOnlyList<FullName> Content { get; private set; }
public Type? CommandType { get; private set; }
public ClipboardService()
{
_content = new List<IAbsolutePath>();
_content = new List<FullName>();
Content = _content.AsReadOnly();
}
public void AddContent(IAbsolutePath absolutePath)
public void AddContent(FullName absolutePath)
{
foreach (var content in _content)
{
@@ -25,7 +25,7 @@ public class ClipboardService : IClipboardService
_content.Add(absolutePath);
}
public void RemoveContent(IAbsolutePath absolutePath)
public void RemoveContent(FullName absolutePath)
{
for (var i = 0; i < _content.Count; i++)
{
@@ -38,7 +38,7 @@ public class ClipboardService : IClipboardService
public void Clear()
{
_content = new List<IAbsolutePath>();
_content = new List<FullName>();
Content = _content.AsReadOnly();
CommandType = null;
}

View File

@@ -4,8 +4,10 @@ using FileTime.App.Core.Models.Enums;
using FileTime.App.Core.UserCommand;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Command;
using FileTime.Core.Command.CreateContainer;
using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
using Microsoft.Extensions.Logging;
using CopyCommand = FileTime.Core.Command.Copy.CopyCommand;
@@ -19,24 +21,30 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
private readonly IClipboardService _clipboardService;
private readonly IInputInterface _inputInterface;
private readonly ILogger<ItemManipulationUserCommandHandlerService> _logger;
private readonly BindedCollection<IAbsolutePath>? _markedItems;
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly BindedCollection<FullName>? _markedItems;
private PointInTime _currentPointInTime;
public ItemManipulationUserCommandHandlerService(
IAppState appState,
IUserCommandHandlerService userCommandHandlerService,
IClipboardService clipboardService,
IInputInterface inputInterface,
ILogger<ItemManipulationUserCommandHandlerService> logger) : base(appState)
ILogger<ItemManipulationUserCommandHandlerService> logger,
ITimelessContentProvider timelessContentProvider) : base(appState, timelessContentProvider)
{
_userCommandHandlerService = userCommandHandlerService;
_clipboardService = clipboardService;
_inputInterface = inputInterface;
_logger = logger;
_timelessContentProvider = timelessContentProvider;
_currentPointInTime = null!;
SaveSelectedTab(t => _selectedTab = t);
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
SaveCurrentPointInTime(t => _currentPointInTime = t);
_markedItems = new BindedCollection<IAbsolutePath>(appState.SelectedTab.Select(t => t?.MarkedItems));
_markedItems = new BindedCollection<FullName>(appState.SelectedTab.Select(t => t?.MarkedItems));
AddCommandHandlers(new IUserCommandHandler[]
{
@@ -51,7 +59,7 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
{
if (_selectedTab == null || _currentSelectedItem?.BaseItem?.FullName == null) return;
_selectedTab.ToggleMarkedItem(new AbsolutePath(_currentSelectedItem.BaseItem));
_selectedTab.ToggleMarkedItem(_currentSelectedItem.BaseItem.FullName);
await _userCommandHandlerService.HandleCommandAsync(MoveCursorDownCommand.Instance);
}
@@ -71,7 +79,8 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
}
else if (_currentSelectedItem?.BaseItem != null)
{
_clipboardService.AddContent(new AbsolutePath(_currentSelectedItem.BaseItem));
var item = _currentSelectedItem.BaseItem;
_clipboardService.AddContent(item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item)));
}
return Task.CompletedTask;
@@ -114,8 +123,10 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
var containerNameInput = new TextInputElement("Container name");
await _inputInterface.ReadInputs(new List<IInputElement>() { containerNameInput });
//TODO: message on empty result
var newContainerName = containerNameInput.Value;
var command = new CreateContainerCommand();
}
}

View File

@@ -4,6 +4,7 @@ using FileTime.App.Core.UserCommand;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
using FileTime.Core.Services;
using FileTime.Core.Timeline;
using FileTime.Providers.Local;
using Microsoft.Extensions.DependencyInjection;
@@ -15,6 +16,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
private readonly IServiceProvider _serviceProvider;
private readonly ILocalContentProvider _localContentProvider;
private readonly IUserCommandHandlerService _userCommandHandlerService;
private readonly ITimelessContentProvider _timelessContentProvider;
private ITabViewModel? _selectedTab;
private IContainer? _currentLocation;
private IItemViewModel? _currentSelectedItem;
@@ -25,12 +27,14 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
IAppState appState,
IServiceProvider serviceProvider,
ILocalContentProvider localContentProvider,
IUserCommandHandlerService userCommandHandlerService) : base(appState)
IUserCommandHandlerService userCommandHandlerService,
ITimelessContentProvider timelessContentProvider) : base(appState)
{
_appState = appState;
_serviceProvider = serviceProvider;
_localContentProvider = localContentProvider;
_userCommandHandlerService = userCommandHandlerService;
_timelessContentProvider = timelessContentProvider;
SaveSelectedTab(t => _selectedTab = t);
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
@@ -71,7 +75,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
private async Task GoUp()
{
if (_currentLocation?.Parent is not IAbsolutePath parentPath || await parentPath.ResolveAsyncSafe() is not IContainer newContainer) return;
if (_currentLocation?.Parent is not AbsolutePath parentPath || await parentPath.ResolveAsyncSafe() is not IContainer newContainer) return;
_selectedTab?.Tab?.SetCurrentLocation(newContainer);
}
@@ -94,7 +98,7 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
var newSelectedItem = getNewSelected(_currentItems);
if (newSelectedItem == null) return;
_selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath());
_selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath(_timelessContentProvider));
}
private Task EnterRapidTravel()

View File

@@ -2,6 +2,7 @@ using System.Reactive.Linq;
using DynamicData;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
namespace FileTime.App.Core.Services.UserCommandHandler;
@@ -9,10 +10,14 @@ public abstract class UserCommandHandlerServiceBase : IUserCommandHandler
{
private readonly List<IUserCommandHandler> _userCommandHandlers = new();
private readonly IAppState? _appState;
private readonly ITimelessContentProvider? _timelessContentProvider;
protected UserCommandHandlerServiceBase(IAppState? appState = null)
protected UserCommandHandlerServiceBase(
IAppState? appState = null,
ITimelessContentProvider? timelessContentProvider = null)
{
_appState = appState;
_timelessContentProvider = timelessContentProvider;
}
public bool CanHandleCommand(UserCommand.IUserCommand command) => _userCommandHandlers.Any(h => h.CanHandleCommand(command));
@@ -48,13 +53,23 @@ public abstract class UserCommandHandlerServiceBase : IUserCommandHandler
protected IDisposable SaveCurrentItems(Action<IEnumerable<IItemViewModel>> handler)
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t?.CurrentItemsCollectionObservable ?? Observable.Return((IEnumerable<IItemViewModel>?) Enumerable.Empty<IItemViewModel>())).Switch().Subscribe(i => handler(i ?? Enumerable.Empty<IItemViewModel>())));
protected IDisposable SaveMarkedItems(Action<IChangeSet<IAbsolutePath>> handler)
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t == null ? Observable.Empty<IChangeSet<IAbsolutePath>>() : t.MarkedItems).Switch().Subscribe(handler));
protected IDisposable SaveMarkedItems(Action<IChangeSet<FullName>> handler)
=> RunWithAppState(appState => appState.SelectedTab.Select(t => t == null ? Observable.Empty<IChangeSet<FullName>>() : t.MarkedItems).Switch().Subscribe(handler));
protected IDisposable SaveCurrentPointInTime(Action<PointInTime> handler)
=> RunWithTimelessContentProvider(timelessContentProvider => timelessContentProvider.CurrentPointInTime.Subscribe(handler));
private IDisposable RunWithAppState(Func<IAppState, IDisposable> act)
{
if (_appState == null) throw new NullReferenceException($"AppState is nit initialized in {nameof(UserCommandHandlerServiceBase)}.");
if (_appState == null) throw new NullReferenceException($"AppState is not initialized in {nameof(UserCommandHandlerServiceBase)}.");
return act(_appState);
}
private IDisposable RunWithTimelessContentProvider(Func<ITimelessContentProvider, IDisposable> act)
{
if (_timelessContentProvider == null) throw new NullReferenceException($"TimelessContainer is not initialized in {nameof(UserCommandHandlerServiceBase)}.");
return act(_timelessContentProvider);
}
}

View File

@@ -3,6 +3,7 @@ using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.App.Core.Models.Enums;
using FileTime.Core.Timeline;
using MvvmGen;
using MoreLinq;

View File

@@ -57,7 +57,7 @@ public abstract partial class ItemViewModel : IItemViewModel
DisplayNameText = item.DisplayName;
IsMarked = itemViewModelType is ItemViewModelType.Main
? parentTab.MarkedItems.ToCollection().Select(m => m.Any(i => i.Path.Path == item.FullName?.Path))
? parentTab.MarkedItems.ToCollection().Select(m => m.Any(i => i.Path == item.FullName?.Path))
: Observable.Return(false);
IsSelected = itemViewModelType is ItemViewModelType.Main

View File

@@ -19,7 +19,7 @@ public partial class TabViewModel : ITabViewModel, IDisposable
private readonly IItemNameConverterService _itemNameConverterService;
private readonly IAppState _appState;
private readonly IRxSchedulerService _rxSchedulerService;
private readonly SourceList<IAbsolutePath> _markedItems = new();
private readonly SourceList<FullName> _markedItems = new();
private readonly List<IDisposable> _disposables = new();
private bool _disposed;
@@ -31,7 +31,7 @@ public partial class TabViewModel : ITabViewModel, IDisposable
public IObservable<IContainer?> CurrentLocation { get; private set; } = null!;
public IObservable<IItemViewModel?> CurrentSelectedItem { get; private set; } = null!;
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; private set; } = null!;
public IObservable<IChangeSet<IAbsolutePath>> MarkedItems { get; }
public IObservable<IChangeSet<FullName>> MarkedItems { get; }
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; private set; } = null!;
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; private set; } = null!;
@@ -171,7 +171,7 @@ public partial class TabViewModel : ITabViewModel, IDisposable
}
}
private static async Task<IItem> MapItem(IAbsolutePath item)
private static async Task<IItem> MapItem(AbsolutePath item)
=> await item.ResolveAsync(forceResolve: true,
itemInitializationSettings: new ItemInitializationSettings(true));
@@ -211,24 +211,24 @@ public partial class TabViewModel : ITabViewModel, IDisposable
throw new ArgumentException($"{nameof(item)} is not {nameof(IContainer)} neither {nameof(IElement)}");
}
public void AddMarkedItem(IAbsolutePath item) => _markedItems.Add(item);
public void AddMarkedItem(FullName fullName) => _markedItems.Add(fullName);
public void RemoveMarkedItem(IAbsolutePath item)
public void RemoveMarkedItem(FullName fullName)
{
var itemsToRemove = _markedItems.Items.Where(i => i.Path.Path == item.Path.Path).ToList();
var itemsToRemove = _markedItems.Items.Where(i => i.Path == fullName.Path).ToList();
_markedItems.RemoveMany(itemsToRemove);
}
public void ToggleMarkedItem(IAbsolutePath item)
public void ToggleMarkedItem(FullName fullName)
{
if (_markedItems.Items.Any(i => i.Path.Path == item.Path.Path))
if (_markedItems.Items.Any(i => i.Path == fullName.Path))
{
RemoveMarkedItem(item);
RemoveMarkedItem(fullName);
}
else
{
AddMarkedItem(item);
AddMarkedItem(fullName);
}
}

View File

@@ -1,5 +1,6 @@
using FileTime.App.Core;
using FileTime.Core.Services;
using FileTime.Core.Timeline;
using FileTime.Providers.Local;
using Microsoft.Extensions.DependencyInjection;
@@ -13,6 +14,8 @@ public static class DependencyInjection
return serviceCollection
.AddTransient<ITab, Tab>()
.AddSingleton<ICommandScheduler, CommandScheduler>()
.AddSingleton<ITimelessContentProvider, TimelessContentProvider>()
.AddCoreAppServices()
.AddLocalServices();
}

View File

@@ -14,6 +14,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Core\FileTime.Core.Timeline\FileTime.Core.Timeline.csproj" />
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" />
<ProjectReference Include="..\FileTime.App.Core\FileTime.App.Core.csproj" />
</ItemGroup>