From 60ab7f94ea5d554dce5e7693329a5d8d12931ca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81d=C3=A1m=20Kov=C3=A1cs?= Date: Tue, 24 May 2022 09:19:57 +0200 Subject: [PATCH] ContentAccess, CreateContainer --- ...emManipulationUserCommandHandlerService.cs | 19 +++--- src/AppCommon/FileTime.App.Core/Startup.cs | 28 ++++----- .../DependencyInjection.cs | 24 +++++--- .../ContentAccess/IContentAccessorFactory.cs | 7 +++ .../ContentAccess/IItemCreator.cs | 15 +++++ .../ContentAccess/ItemCreatorBase.cs | 17 ++++++ .../CreateContainer/CreateContainerCommand.cs | 61 +++++++++++++++---- .../ContentAccessorFactory.cs | 27 ++++++++ .../Avalonia/FileTime.GuiApp.App/Startup.cs | 38 ++++++------ .../FileTime.GuiApp/Views/MainWindow.axaml | 2 + .../LocalItemCreator.cs | 23 +++++++ .../FileTime.Providers.Local/Startup.cs | 10 +-- 12 files changed, 209 insertions(+), 62 deletions(-) create mode 100644 src/Core/FileTime.Core.Abstraction/ContentAccess/IContentAccessorFactory.cs create mode 100644 src/Core/FileTime.Core.Abstraction/ContentAccess/IItemCreator.cs create mode 100644 src/Core/FileTime.Core.Abstraction/ContentAccess/ItemCreatorBase.cs create mode 100644 src/Core/FileTime.Core.ContentAccess/ContentAccessorFactory.cs create mode 100644 src/Providers/FileTime.Providers.Local/LocalItemCreator.cs diff --git a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ItemManipulationUserCommandHandlerService.cs b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ItemManipulationUserCommandHandlerService.cs index 705f460..df19b87 100644 --- a/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ItemManipulationUserCommandHandlerService.cs +++ b/src/AppCommon/FileTime.App.Core/Services/UserCommandHandler/ItemManipulationUserCommandHandlerService.cs @@ -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 _logger; - private readonly ITimelessContentProvider _timelessContentProvider; private readonly ICommandScheduler _commandScheduler; + private readonly IServiceProvider _serviceProvider; private readonly BindedCollection? _markedItems; - private PointInTime _currentPointInTime; private IContainer? _currentLocation; public ItemManipulationUserCommandHandlerService( @@ -34,20 +34,19 @@ public class ItemManipulationUserCommandHandlerService : UserCommandHandlerServi IInputInterface inputInterface, ILogger 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(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(_currentLocation.FullName, newContainerName) + .GetRequiredService(); await _commandScheduler.AddCommand(command); } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/Startup.cs b/src/AppCommon/FileTime.App.Core/Startup.cs index c84f071..ae786b8 100644 --- a/src/AppCommon/FileTime.App.Core/Startup.cs +++ b/src/AppCommon/FileTime.App.Core/Startup.cs @@ -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() - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddCommandHandlers(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddTransient(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + return serviceCollection.AddCommandHandlers(); } private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection) diff --git a/src/AppCommon/FileTime.App.DependencyInjection/DependencyInjection.cs b/src/AppCommon/FileTime.App.DependencyInjection/DependencyInjection.cs index fa518ff..e8fa76b 100644 --- a/src/AppCommon/FileTime.App.DependencyInjection/DependencyInjection.cs +++ b/src/AppCommon/FileTime.App.DependencyInjection/DependencyInjection.cs @@ -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(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + return serviceCollection - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddTransient() - .AddTransient() .AddCoreAppServices() - .AddLocalServices(); + .AddLocalServices() + .RegisterCommands(); + } + + public static IServiceCollection RegisterCommands(this IServiceCollection serviceCollection) + { + return serviceCollection.AddTransient(); } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/ContentAccess/IContentAccessorFactory.cs b/src/Core/FileTime.Core.Abstraction/ContentAccess/IContentAccessorFactory.cs new file mode 100644 index 0000000..917c080 --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/ContentAccess/IContentAccessorFactory.cs @@ -0,0 +1,7 @@ +namespace FileTime.Core.ContentAccess; + +public interface IContentAccessorFactory +{ + IItemCreator GetItemCreator() where TContentProvider : IContentProvider; + IItemCreator GetItemCreator(IContentProvider provider); +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/ContentAccess/IItemCreator.cs b/src/Core/FileTime.Core.Abstraction/ContentAccess/IItemCreator.cs new file mode 100644 index 0000000..895227e --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/ContentAccess/IItemCreator.cs @@ -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 : IItemCreator where TContentProvider : IContentProvider +{ + Task CreateContainerAsync(TContentProvider contentProvider, FullName fullName); + Task CreateElementAsync(TContentProvider contentProvider, FullName fullName); +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Abstraction/ContentAccess/ItemCreatorBase.cs b/src/Core/FileTime.Core.Abstraction/ContentAccess/ItemCreatorBase.cs new file mode 100644 index 0000000..2916cb3 --- /dev/null +++ b/src/Core/FileTime.Core.Abstraction/ContentAccess/ItemCreatorBase.cs @@ -0,0 +1,17 @@ +using FileTime.Core.Models; + +namespace FileTime.Core.ContentAccess; + +public abstract class ItemCreatorBase : IItemCreator + 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); +} \ No newline at end of file diff --git a/src/Core/FileTime.Core.Command/CreateContainer/CreateContainerCommand.cs b/src/Core/FileTime.Core.Command/CreateContainer/CreateContainerCommand.cs index 13b2b9b..cb7e6e9 100644 --- a/src/Core/FileTime.Core.Command/CreateContainer/CreateContainerCommand.cs +++ b/src/Core/FileTime.Core.Command/CreateContainer/CreateContainerCommand.cs @@ -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 { 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 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 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() @@ -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 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; + } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.ContentAccess/ContentAccessorFactory.cs b/src/Core/FileTime.Core.ContentAccess/ContentAccessorFactory.cs new file mode 100644 index 0000000..6ae0fdd --- /dev/null +++ b/src/Core/FileTime.Core.ContentAccess/ContentAccessorFactory.cs @@ -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 GetItemCreator() where TContentProvider : IContentProvider + { + var genericType = typeof(IItemCreator<>).MakeGenericType(typeof(TContentProvider)); + + return (IItemCreator)_serviceProvider.GetRequiredService(genericType); + } + + public IItemCreator GetItemCreator(IContentProvider provider) + { + var genericType = typeof(IItemCreator<>).MakeGenericType(provider.GetType()); + + return (IItemCreator)_serviceProvider.GetRequiredService(genericType); + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs index f9908ae..485c213 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/Startup.cs @@ -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() - .AddSingleton() - .AddSingleton(s => s.GetRequiredService()) - .AddSingleton(s => s.GetRequiredService()); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(s => s.GetRequiredService()); + serviceCollection.TryAddSingleton(s => s.GetRequiredService()); + return serviceCollection; } + internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection) { - return serviceCollection - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton() - .AddSingleton(s => s.GetRequiredService()); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(s => s.GetRequiredService()); + 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) { diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml index 32873dd..b3f5d20 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml @@ -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" diff --git a/src/Providers/FileTime.Providers.Local/LocalItemCreator.cs b/src/Providers/FileTime.Providers.Local/LocalItemCreator.cs new file mode 100644 index 0000000..a9c3d3b --- /dev/null +++ b/src/Providers/FileTime.Providers.Local/LocalItemCreator.cs @@ -0,0 +1,23 @@ +using FileTime.Core.ContentAccess; +using FileTime.Core.Models; + +namespace FileTime.Providers.Local; + +public class LocalItemCreator : ItemCreatorBase +{ + 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)) + { + } + } +} \ No newline at end of file diff --git a/src/Providers/FileTime.Providers.Local/Startup.cs b/src/Providers/FileTime.Providers.Local/Startup.cs index 4f1bdf5..c804093 100644 --- a/src/Providers/FileTime.Providers.Local/Startup.cs +++ b/src/Providers/FileTime.Providers.Local/Startup.cs @@ -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() - .AddSingleton(sp => sp.GetRequiredService()); + serviceCollection.TryAddSingleton(); + serviceCollection.TryAddSingleton(sp => sp.GetRequiredService()); + serviceCollection.TryAddSingleton, LocalItemCreator>(); + serviceCollection.TryAddSingleton>(sp => sp.GetRequiredService>()); + return serviceCollection; } } \ No newline at end of file