ContentAccess, CreateContainer

This commit is contained in:
2022-05-24 09:19:57 +02:00
parent 4ac99480fa
commit 60ab7f94ea
12 changed files with 209 additions and 62 deletions

View File

@@ -8,6 +8,7 @@ using FileTime.Core.Command.CreateContainer;
using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
using InitableService;
using Microsoft.Extensions.Logging;
using CopyCommand = FileTime.Core.Command.Copy.CopyCommand;
@@ -21,10 +22,9 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
private readonly IClipboardService _clipboardService;
private readonly IInputInterface _inputInterface;
private readonly ILogger<ItemManipulationUserCommandHandlerService> _logger;
private readonly ITimelessContentProvider _timelessContentProvider;
private readonly ICommandScheduler _commandScheduler;
private readonly IServiceProvider _serviceProvider;
private readonly BindedCollection<FullName>? _markedItems;
private PointInTime _currentPointInTime;
private IContainer? _currentLocation;
public ItemManipulationUserCommandHandlerService(
@@ -34,20 +34,19 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
IInputInterface inputInterface,
ILogger<ItemManipulationUserCommandHandlerService> logger,
ITimelessContentProvider timelessContentProvider,
ICommandScheduler commandScheduler) : base(appState, timelessContentProvider)
ICommandScheduler commandScheduler,
IServiceProvider serviceProvider) : base(appState, timelessContentProvider)
{
_userCommandHandlerService = userCommandHandlerService;
_clipboardService = clipboardService;
_inputInterface = inputInterface;
_logger = logger;
_timelessContentProvider = timelessContentProvider;
_commandScheduler = commandScheduler;
_currentPointInTime = null!;
_serviceProvider = serviceProvider;
SaveSelectedTab(t => _selectedTab = t);
SaveCurrentLocation(l => _currentLocation = l);
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
SaveCurrentPointInTime(t => _currentPointInTime = t);
_markedItems = new BindedCollection<FullName>(appState.SelectedTab.Select(t => t?.MarkedItems));
@@ -85,7 +84,9 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
else if (_currentSelectedItem?.BaseItem != null)
{
var item = _currentSelectedItem.BaseItem;
_clipboardService.AddContent(item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item)));
_clipboardService.AddContent(item.FullName ??
throw new ArgumentException($"{nameof(item.FullName)} can not be null.",
nameof(item)));
}
return Task.CompletedTask;
@@ -134,7 +135,9 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi
if (_currentLocation?.FullName is null || newContainerName is null) return;
var command = new CreateContainerCommand(_currentLocation.FullName, newContainerName, _timelessContentProvider);
var command = _serviceProvider
.GetInitableResolver<FullName, string>(_currentLocation.FullName, newContainerName)
.GetRequiredService<CreateContainerCommand>();
await _commandScheduler.AddCommand(command);
}
}

View File

@@ -4,6 +4,7 @@ using FileTime.App.Core.StartupServices;
using FileTime.App.Core.ViewModels;
using FileTime.App.Core.ViewModels.ItemPreview;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace FileTime.App.Core;
@@ -11,20 +12,19 @@ public static class Startup
{
public static IServiceCollection AddCoreAppServices(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddTransient<ITabViewModel, TabViewModel>()
.AddTransient<IContainerViewModel, ContainerViewModel>()
.AddTransient<IElementViewModel, ElementViewModel>()
.AddTransient<IFileViewModel, FileViewModel>()
.AddTransient<IContainerSizeContainerViewModel, ContainerSizeContainerViewModel>()
.AddTransient<IItemNameConverterService, ItemNameConverterService>()
.AddTransient<ElementPreviewViewModel>()
.AddSingleton<IUserCommandHandlerService, UserCommandHandlerService>()
.AddSingleton<IClipboardService, ClipboardService>()
.AddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>()
.AddSingleton<IStartupHandler, DefaultIdentifiableCommandHandlerRegister>()
.AddSingleton<IItemPreviewService, ItemPreviewService>()
.AddCommandHandlers();
serviceCollection.TryAddTransient<ITabViewModel, TabViewModel>();
serviceCollection.TryAddTransient<IContainerViewModel, ContainerViewModel>();
serviceCollection.TryAddTransient<IElementViewModel, ElementViewModel>();
serviceCollection.TryAddTransient<IFileViewModel, FileViewModel>();
serviceCollection.TryAddTransient<IContainerSizeContainerViewModel, ContainerSizeContainerViewModel>();
serviceCollection.TryAddTransient<IItemNameConverterService, ItemNameConverterService>();
serviceCollection.TryAddTransient<ElementPreviewViewModel>();
serviceCollection.TryAddSingleton<IUserCommandHandlerService, UserCommandHandlerService>();
serviceCollection.TryAddSingleton<IClipboardService, ClipboardService>();
serviceCollection.TryAddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>();
serviceCollection.TryAddSingleton<IStartupHandler, DefaultIdentifiableCommandHandlerRegister>();
serviceCollection.TryAddSingleton<IItemPreviewService, ItemPreviewService>();
return serviceCollection.AddCommandHandlers();
}
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)

View File

@@ -1,10 +1,12 @@
using FileTime.App.Core;
using FileTime.Core.Command;
using FileTime.Core.Command.CreateContainer;
using FileTime.Core.ContentAccess;
using FileTime.Core.Services;
using FileTime.Core.Timeline;
using FileTime.Providers.Local;
using Microsoft.Extensions.DependencyInjection;
using ICommandExecutor = FileTime.Core.Timeline.ICommandExecutor;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace FileTime.App.DependencyInjection;
@@ -14,13 +16,21 @@ public static class DependencyInjection
{
serviceCollection ??= new ServiceCollection();
serviceCollection.TryAddSingleton<ICommandScheduler, CommandScheduler>();
serviceCollection.TryAddSingleton<ITimelessContentProvider, TimelessContentProvider>();
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
serviceCollection.TryAddSingleton<ITab, Tab>();
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
return serviceCollection
.AddSingleton<ICommandScheduler, CommandScheduler>()
.AddSingleton<ITimelessContentProvider, TimelessContentProvider>()
.AddSingleton<ICommandRunner, CommandRunner>()
.AddTransient<ITab, Tab>()
.AddTransient<ILocalCommandExecutor, LocalCommandExecutor>()
.AddCoreAppServices()
.AddLocalServices();
.AddLocalServices()
.RegisterCommands();
}
public static IServiceCollection RegisterCommands(this IServiceCollection serviceCollection)
{
return serviceCollection.AddTransient<CreateContainerCommand>();
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.Core.ContentAccess;
public interface IContentAccessorFactory
{
IItemCreator<TContentProvider> GetItemCreator<TContentProvider>() where TContentProvider : IContentProvider;
IItemCreator GetItemCreator(IContentProvider provider);
}

View File

@@ -0,0 +1,15 @@
using FileTime.Core.Models;
namespace FileTime.Core.ContentAccess;
public interface IItemCreator
{
Task CreateContainerAsync(IContentProvider contentProvider, FullName fullName);
Task CreateElementAsync(IContentProvider contentProvider, FullName fullName);
}
public interface IItemCreator<in TContentProvider> : IItemCreator where TContentProvider : IContentProvider
{
Task CreateContainerAsync(TContentProvider contentProvider, FullName fullName);
Task CreateElementAsync(TContentProvider contentProvider, FullName fullName);
}

View File

@@ -0,0 +1,17 @@
using FileTime.Core.Models;
namespace FileTime.Core.ContentAccess;
public abstract class ItemCreatorBase<TContentProvider> : IItemCreator<TContentProvider>
where TContentProvider : IContentProvider
{
public async Task CreateContainerAsync(IContentProvider contentProvider, FullName fullName)
=> await CreateContainerAsync((TContentProvider)contentProvider, fullName);
public async Task CreateElementAsync(IContentProvider contentProvider, FullName fullName)
=> await CreateElementAsync((TContentProvider)contentProvider, fullName);
public abstract Task CreateContainerAsync(TContentProvider contentProvider, FullName fullName);
public abstract Task CreateElementAsync(TContentProvider contentProvider, FullName fullName);
}

View File

@@ -1,28 +1,36 @@
using FileTime.Core.ContentAccess;
using FileTime.Core.Enums;
using FileTime.Core.Extensions;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
using InitableService;
namespace FileTime.Core.Command.CreateContainer;
public class CreateContainerCommand : IExecutableCommand
public class CreateContainerCommand : IExecutableCommand, IInitable<FullName, string>
{
private readonly ITimelessContentProvider _timelessContentProvider;
public FullName Parent { get; }
public string NewContainerName { get; }
private readonly IContentAccessorFactory _contentAccessorFactory;
public FullName? Parent { get; private set; }
public string? NewContainerName { get; private set; }
public CreateContainerCommand(
FullName parent,
string newContainerName,
ITimelessContentProvider timelessContentProvider)
ITimelessContentProvider timelessContentProvider,
IContentAccessorFactory contentAccessorFactory)
{
_timelessContentProvider = timelessContentProvider;
Parent = parent;
NewContainerName = newContainerName;
_contentAccessorFactory = contentAccessorFactory;
}
public async Task<CanCommandRun> CanRun(PointInTime currentTime)
{
if (Parent is null)
throw new ArgumentNullException(nameof(Parent),
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
if (NewContainerName is null)
throw new ArgumentNullException(nameof(NewContainerName),
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
try
{
var parent = await ResolveParentAsync();
@@ -49,6 +57,13 @@ public class CreateContainerCommand : IExecutableCommand
public Task<PointInTime> SimulateCommand(PointInTime currentTime)
{
if (Parent is null)
throw new ArgumentNullException(nameof(Parent),
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
if (NewContainerName is null)
throw new ArgumentNullException(nameof(NewContainerName),
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
return Task.FromResult(
currentTime.WithDifferences(newPointInTime =>
new List<Difference>()
@@ -66,11 +81,35 @@ public class CreateContainerCommand : IExecutableCommand
);
}
public Task Execute()
public async Task Execute()
{
return Task.CompletedTask;
if (Parent is null)
throw new ArgumentNullException(nameof(Parent),
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
if (NewContainerName is null)
throw new ArgumentNullException(nameof(NewContainerName),
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
var resolvedParent = await _timelessContentProvider.GetItemByFullNameAsync(Parent, PointInTime.Present);
var itemCreator = _contentAccessorFactory.GetItemCreator(resolvedParent.Provider);
await itemCreator.CreateContainerAsync(resolvedParent.Provider, Parent.GetChild(NewContainerName));
}
private async Task<IItem> ResolveParentAsync()
=> await _timelessContentProvider.GetItemByFullNameAsync(Parent, PointInTime.Present);
{
if (Parent is null)
throw new ArgumentNullException(nameof(Parent),
$"Property {nameof(Parent)} is not initialized. Call the {nameof(Init)} method before using the command.");
if (NewContainerName is null)
throw new ArgumentNullException(nameof(NewContainerName),
$"Property {nameof(NewContainerName)} is not initialized. Call the {nameof(Init)} method before using the command.");
return await _timelessContentProvider.GetItemByFullNameAsync(Parent, PointInTime.Present);
}
public void Init(FullName parent, string newContainerName)
{
Parent = parent;
NewContainerName = newContainerName;
}
}

View File

@@ -0,0 +1,27 @@
using Microsoft.Extensions.DependencyInjection;
namespace FileTime.Core.ContentAccess;
public class ContentAccessorFactory : IContentAccessorFactory
{
private readonly IServiceProvider _serviceProvider;
public ContentAccessorFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IItemCreator<TContentProvider> GetItemCreator<TContentProvider>() where TContentProvider : IContentProvider
{
var genericType = typeof(IItemCreator<>).MakeGenericType(typeof(TContentProvider));
return (IItemCreator<TContentProvider>)_serviceProvider.GetRequiredService(genericType);
}
public IItemCreator GetItemCreator(IContentProvider provider)
{
var genericType = typeof(IItemCreator<>).MakeGenericType(provider.GetType());
return (IItemCreator)_serviceProvider.GetRequiredService(genericType);
}
}

View File

@@ -11,6 +11,7 @@ using FileTime.GuiApp.Services;
using FileTime.GuiApp.ViewModels;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Serilog;
using Serilog.Configuration;
@@ -20,26 +21,27 @@ public static class Startup
{
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<MainWindowViewModel>()
.AddSingleton<GuiAppState>()
.AddSingleton<IAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>());
serviceCollection.TryAddSingleton<MainWindowViewModel>();
serviceCollection.TryAddSingleton<GuiAppState>();
serviceCollection.TryAddSingleton<IAppState>(s => s.GetRequiredService<GuiAppState>());
serviceCollection.TryAddSingleton<IGuiAppState>(s => s.GetRequiredService<GuiAppState>());
return serviceCollection;
}
internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>()
.AddSingleton<IKeyInputHandlerService, KeyInputHandlerService>()
.AddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>()
.AddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>()
.AddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>()
.AddSingleton<IStartupHandler, RootDriveInfoService>()
.AddSingleton<LifecycleService>()
.AddSingleton<IIconProvider, MaterialIconProvider>()
.AddSingleton<IModalService, ModalService>()
.AddSingleton<IDialogService, DialogService>()
.AddSingleton<IInputInterface>(s => s.GetRequiredService<IDialogService>());
serviceCollection.TryAddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>();
serviceCollection.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
serviceCollection.TryAddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>();
serviceCollection.TryAddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>();
serviceCollection.TryAddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>();
serviceCollection.TryAddSingleton<IStartupHandler, RootDriveInfoService>();
serviceCollection.TryAddSingleton<LifecycleService>();
serviceCollection.TryAddSingleton<IIconProvider, MaterialIconProvider>();
serviceCollection.TryAddSingleton<IModalService, ModalService>();
serviceCollection.TryAddSingleton<IDialogService, DialogService>();
serviceCollection.TryAddSingleton<IInputInterface>(s => s.GetRequiredService<IDialogService>());
return serviceCollection;
}
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
@@ -79,7 +81,7 @@ public static class Startup
return serviceProvider;
}
internal static LoggerConfiguration MessageBoxSink(
private static LoggerConfiguration MessageBoxSink(
this LoggerSinkConfiguration loggerConfiguration,
IServiceProvider serviceProvider)
{

View File

@@ -10,6 +10,8 @@
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"
d:DesignHeight="450"
d:DesignWidth="800"

View File

@@ -0,0 +1,23 @@
using FileTime.Core.ContentAccess;
using FileTime.Core.Models;
namespace FileTime.Providers.Local;
public class LocalItemCreator : ItemCreatorBase<ILocalContentProvider>
{
public override Task CreateContainerAsync(ILocalContentProvider contentProvider, FullName fullName)
{
var path = contentProvider.GetNativePath(fullName).Path;
if (!Directory.Exists(path)) Directory.CreateDirectory(path);
return Task.CompletedTask;
}
public override async Task CreateElementAsync(ILocalContentProvider contentProvider, FullName fullName)
{
var path = contentProvider.GetNativePath(fullName).Path;
await using (File.Create(path))
{
}
}
}

View File

@@ -1,6 +1,6 @@
using FileTime.Core.ContentAccess;
using FileTime.Core.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace FileTime.Providers.Local;
@@ -8,8 +8,10 @@ public static class Startup
{
public static IServiceCollection AddLocalServices(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<ILocalContentProvider, LocalContentProvider>()
.AddSingleton<IContentProvider, ILocalContentProvider>(sp => sp.GetRequiredService<ILocalContentProvider>());
serviceCollection.TryAddSingleton<ILocalContentProvider, LocalContentProvider>();
serviceCollection.TryAddSingleton<IContentProvider>(sp => sp.GetRequiredService<ILocalContentProvider>());
serviceCollection.TryAddSingleton<IItemCreator<ILocalContentProvider>, LocalItemCreator>();
serviceCollection.TryAddSingleton<IItemCreator<LocalContentProvider>>(sp => sp.GetRequiredService<IItemCreator<ILocalContentProvider>>());
return serviceCollection;
}
}