Refactor command handlers and Startup

This commit is contained in:
2022-04-18 22:10:50 +02:00
parent 570f695e60
commit be6c3938ce
9 changed files with 207 additions and 127 deletions

View File

@@ -0,0 +1,10 @@
using FileTime.App.Core.Command;
namespace FileTime.App.Core.Services
{
public interface ICommandHandler
{
bool CanHandleCommand(Commands command);
Task HandleCommandAsync(Commands command);
}
}

View File

@@ -0,0 +1,23 @@
using FileTime.App.Core.Command;
namespace FileTime.App.Core.Services.CommandHandler
{
public abstract class CommandHanderBase : ICommandHandler
{
private readonly Dictionary<Commands, Func<Task>> _commandHandlers = new();
public bool CanHandleCommand(Commands command) => _commandHandlers.ContainsKey(command);
public async Task HandleCommandAsync(Commands command) => await _commandHandlers[command].Invoke();
protected void AddCommandHandler(Commands command, Func<Task> handler) => _commandHandlers.Add(command, handler);
protected void AddCommandHandlers(IEnumerable<(Commands command, Func<Task> handler)> commandHandlers)
{
foreach (var (command, handler) in commandHandlers)
{
AddCommandHandler(command, handler);
}
}
protected void RemoveCommandHandler(Commands command) => _commandHandlers.Remove(command);
}
}

View File

@@ -0,0 +1,71 @@
using System.Reactive.Linq;
using FileTime.App.Core.Command;
using FileTime.App.Core.Extensions;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
namespace FileTime.App.Core.Services.CommandHandler
{
public class NavigationCommandHandler : CommandHanderBase
{
private readonly IAppState _appState;
private ITabViewModel? _selectedTab;
private IContainer? _currentLocation;
private IItemViewModel? _currentSelectedItem;
private List<IItemViewModel> _currentItems = new();
public NavigationCommandHandler(IAppState appState)
{
_appState = appState;
_appState.SelectedTab.Subscribe(t => _selectedTab = t);
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation).Switch().Subscribe(l => _currentLocation = l);
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IItemViewModel?>(null) : t.CurrentSelectedItem).Switch().Subscribe(l => _currentSelectedItem = l);
_appState.SelectedTab.Select(t => t == null ? Observable.Return(Enumerable.Empty<IItemViewModel>()) : t.CurrentItems).Switch().Subscribe(i => _currentItems = i.ToList());
AddCommandHandlers(new (Commands, Func<Task>)[]
{
(Commands.GoUp, GoUp),
(Commands.MoveCursorDown, MoveCursorDown),
(Commands.MoveCursorUp, MoveCursorUp),
(Commands.Open, OpenContainer),
});
}
private Task OpenContainer()
{
if (_currentSelectedItem is not IContainerViewModel containerViewModel || containerViewModel.Container is null) return Task.CompletedTask;
_selectedTab?.Tab?.SetCurrentLocation(containerViewModel.Container);
return Task.CompletedTask;
}
private async Task GoUp()
{
if (_currentLocation?.Parent is not IAbsolutePath parentPath || await parentPath.ResolveAsyncSafe() is not IContainer newContainer) return;
_selectedTab?.Tab?.SetCurrentLocation(newContainer);
}
private Task MoveCursorDown()
{
SelectNewSelectedItem(i => i.SkipWhile(i => i != _currentSelectedItem).Skip(1).FirstOrDefault());
return Task.CompletedTask;
}
private Task MoveCursorUp()
{
SelectNewSelectedItem(i => i.TakeWhile(i => i != _currentSelectedItem).LastOrDefault());
return Task.CompletedTask;
}
private void SelectNewSelectedItem(Func<IEnumerable<IItemViewModel>, IItemViewModel?> getNewSelected)
{
if (_selectedTab is null || _currentLocation is null) return;
var newSelectedItem = getNewSelected(_currentItems);
if (newSelectedItem == null) return;
_selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath());
}
}
}

View File

@@ -1,129 +1,79 @@
using System.Reactive.Linq;
using FileTime.App.Core.Command; using FileTime.App.Core.Command;
using FileTime.App.Core.Extensions;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
namespace FileTime.App.Core.Services namespace FileTime.App.Core.Services
{ {
public class CommandHandlerService : ICommandHandlerService public class CommandHandlerService : ICommandHandlerService
{ {
private readonly Dictionary<Commands, Func<Task>> _commandHandlers; private readonly IEnumerable<ICommandHandler> _commandHandlers;
private readonly IAppState _appState;
private ITabViewModel? _selectedTab;
private IContainer? _currentLocation;
private IItemViewModel? _currentSelectedItem;
private List<IItemViewModel> _currentItems = new();
public CommandHandlerService(IAppState appState) public CommandHandlerService(IEnumerable<ICommandHandler> commandHandlers)
{ {
_appState = appState; _commandHandlers = commandHandlers;
_appState.SelectedTab.Subscribe(t => _selectedTab = t); //(Commands.AutoRefresh, ToggleAutoRefresh),
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation).Switch().Subscribe(l => _currentLocation = l); //(Commands.ChangeTimelineMode, ChangeTimelineMode),
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IItemViewModel?>(null) : t.CurrentSelectedItem).Switch().Subscribe(l => _currentSelectedItem = l); //(Commands.CloseTab, CloseTab),
_appState.SelectedTab.Select(t => t == null ? Observable.Return(Enumerable.Empty<IItemViewModel>()) : t.CurrentItems).Switch().Subscribe(i => _currentItems = i.ToList()); //(Commands.Compress, Compress),
//(Commands.Copy, Copy),
_commandHandlers = new Dictionary<Commands, Func<Task>> //(Commands.CopyHash, CopyHash),
{ //(Commands.CopyPath, CopyPath),
//{Commands.AutoRefresh, ToggleAutoRefresh}, //(Commands.CreateContainer, CreateContainer),
//{Commands.ChangeTimelineMode, ChangeTimelineMode}, //(Commands.CreateElement, CreateElement),
//{Commands.CloseTab, CloseTab}, //(Commands.Cut, Cut),
//{Commands.Compress, Compress}, //(Commands.Edit, Edit),
//{Commands.Copy, Copy}, //(Commands.EnterRapidTravel, EnterRapidTravelMode),
//{Commands.CopyHash, CopyHash}, //(Commands.FindByName, FindByName),
//{Commands.CopyPath, CopyPath}, //(Commands.FindByNameRegex, FindByNameRegex),
//{Commands.CreateContainer, CreateContainer}, //(Commands.GoToHome, GotToHome),
//{Commands.CreateElement, CreateElement}, //(Commands.GoToPath, GoToContainer),
//{Commands.Cut, Cut}, //(Commands.GoToProvider, GotToProvider),
//{Commands.Edit, Edit}, //(Commands.GoToRoot, GotToRoot),
//{Commands.EnterRapidTravel, EnterRapidTravelMode}, //(Commands.HardDelete, HardDelete),
//{Commands.FindByName, FindByName}, //(Commands.Mark, MarkCurrentItem),
//{Commands.FindByNameRegex, FindByNameRegex}, //(Commands.MoveCursorDownPage, MoveCursorDownPage),
//{Commands.GoToHome, GotToHome}, //(Commands.MoveCursorUpPage, MoveCursorUpPage),
//{Commands.GoToPath, GoToContainer}, //(Commands.MoveToFirst, MoveToFirst),
//{Commands.GoToProvider, GotToProvider}, //(Commands.MoveToLast, MoveToLast),
//{Commands.GoToRoot, GotToRoot}, //(Commands.NextTimelineBlock, SelectNextTimelineBlock),
{Commands.GoUp, GoUp}, //(Commands.NextTimelineCommand, SelectNextTimelineCommand),
//{Commands.HardDelete, HardDelete}, //(Commands.OpenInFileBrowser, OpenInDefaultFileExplorer),
//{Commands.Mark, MarkCurrentItem}, //(Commands.OpenOrRun, OpenOrRun),
{Commands.MoveCursorDown, MoveCursorDown}, //(Commands.PasteMerge, PasteMerge),
//{Commands.MoveCursorDownPage, MoveCursorDownPage}, //(Commands.PasteOverwrite, PasteOverwrite),
{Commands.MoveCursorUp, MoveCursorUp}, //(Commands.PasteSkip, PasteSkip),
//{Commands.MoveCursorUpPage, MoveCursorUpPage}, //(Commands.PinFavorite, PinFavorite),
//{Commands.MoveToFirst, MoveToFirst}, //(Commands.PreviousTimelineBlock, SelectPreviousTimelineBlock),
//{Commands.MoveToLast, MoveToLast}, //(Commands.PreviousTimelineCommand, SelectPreviousTimelineCommand),
//{Commands.NextTimelineBlock, SelectNextTimelineBlock}, //(Commands.Refresh, RefreshCurrentLocation),
//{Commands.NextTimelineCommand, SelectNextTimelineCommand}, //(Commands.Rename, Rename),
{Commands.Open, OpenContainer}, //(Commands.RunCommand, RunCommandInContainer),
//{Commands.OpenInFileBrowser, OpenInDefaultFileExplorer}, //(Commands.ScanContainerSize, ScanContainerSize),
//{Commands.OpenOrRun, OpenOrRun}, //(Commands.ShowAllShotcut, ShowAllShortcut),
//{Commands.PasteMerge, PasteMerge}, //(Commands.SoftDelete, SoftDelete),
//{Commands.PasteOverwrite, PasteOverwrite}, //(Commands.SwitchToLastTab, async() => await SwitchToTab(-1)),
//{Commands.PasteSkip, PasteSkip}, //(Commands.SwitchToTab1, async() => await SwitchToTab(1)),
//{Commands.PinFavorite, PinFavorite}, //(Commands.SwitchToTab2, async() => await SwitchToTab(2)),
//{Commands.PreviousTimelineBlock, SelectPreviousTimelineBlock}, //(Commands.SwitchToTab3, async() => await SwitchToTab(3)),
//{Commands.PreviousTimelineCommand, SelectPreviousTimelineCommand}, //(Commands.SwitchToTab4, async() => await SwitchToTab(4)),
//{Commands.Refresh, RefreshCurrentLocation}, //(Commands.SwitchToTab5, async() => await SwitchToTab(5)),
//{Commands.Rename, Rename}, //(Commands.SwitchToTab6, async() => await SwitchToTab(6)),
//{Commands.RunCommand, RunCommandInContainer}, //(Commands.SwitchToTab7, async() => await SwitchToTab(7)),
//{Commands.ScanContainerSize, ScanContainerSize}, //(Commands.SwitchToTab8, async() => await SwitchToTab(8)),
//{Commands.ShowAllShotcut, ShowAllShortcut}, //(Commands.TimelinePause, PauseTimeline),
//{Commands.SoftDelete, SoftDelete}, //(Commands.TimelineRefresh, RefreshTimeline),
//{Commands.SwitchToLastTab, async() => await SwitchToTab(-1)}, //(Commands.TimelineStart, ContinueTimeline),
//{Commands.SwitchToTab1, async() => await SwitchToTab(1)}, //(Commands.ToggleAdvancedIcons, ToggleAdvancedIcons),
//{Commands.SwitchToTab2, async() => await SwitchToTab(2)}, //(Commands.ToggleHidden, ToggleHidden),
//{Commands.SwitchToTab3, async() => await SwitchToTab(3)},
//{Commands.SwitchToTab4, async() => await SwitchToTab(4)},
//{Commands.SwitchToTab5, async() => await SwitchToTab(5)},
//{Commands.SwitchToTab6, async() => await SwitchToTab(6)},
//{Commands.SwitchToTab7, async() => await SwitchToTab(7)},
//{Commands.SwitchToTab8, async() => await SwitchToTab(8)},
//{Commands.TimelinePause, PauseTimeline},
//{Commands.TimelineRefresh, RefreshTimeline},
//{Commands.TimelineStart, ContinueTimeline},
//{Commands.ToggleAdvancedIcons, ToggleAdvancedIcons},
//{Commands.ToggleHidden, ToggleHidden},
};
} }
public async Task HandleCommandAsync(Commands command) => public async Task HandleCommandAsync(Commands command)
await _commandHandlers[command].Invoke();
private Task OpenContainer()
{ {
if (_currentSelectedItem is not IContainerViewModel containerViewModel || containerViewModel.Container is null) return Task.CompletedTask; var handler = _commandHandlers.FirstOrDefault(h => h.CanHandleCommand(command));
_selectedTab?.Tab?.SetCurrentLocation(containerViewModel.Container); if (handler != null)
return Task.CompletedTask; {
await handler.HandleCommandAsync(command);
} }
private async Task GoUp()
{
if (_currentLocation?.Parent is not IAbsolutePath parentPath || await parentPath.ResolveAsyncSafe() is not IContainer newContainer) return;
_selectedTab?.Tab?.SetCurrentLocation(newContainer);
}
private Task MoveCursorDown()
{
SelectNewSelectedItem(i => i.SkipWhile(i => i != _currentSelectedItem).Skip(1).FirstOrDefault());
return Task.CompletedTask;
}
private Task MoveCursorUp()
{
SelectNewSelectedItem(i => i.TakeWhile(i => i != _currentSelectedItem).LastOrDefault());
return Task.CompletedTask;
}
private void SelectNewSelectedItem(Func<IEnumerable<IItemViewModel>, IItemViewModel?> getNewSelected)
{
if (_selectedTab is null || _currentLocation is null) return;
var newSelectedItem = getNewSelected(_currentItems);
if (newSelectedItem == null) return;
_selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath());
} }
} }
} }

View File

@@ -0,0 +1,27 @@
using FileTime.App.Core.Services;
using FileTime.App.Core.Services.CommandHandler;
using FileTime.App.Core.ViewModels;
using Microsoft.Extensions.DependencyInjection;
namespace FileTime.App.Core
{
public static class Startup
{
public static IServiceCollection AddCoreAppServices(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddTransient<ITabViewModel, TabViewModel>()
.AddTransient<IContainerViewModel, ContainerViewModel>()
.AddTransient<IElementViewModel, ElementViewModel>()
.AddTransient<IItemNameConverterService, ItemNameConverterService>()
.AddSingleton<ICommandHandlerService, CommandHandlerService>()
.AddCommandHandlers();
}
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<ICommandHandler, NavigationCommandHandler>();
}
}
}

View File

@@ -1,3 +1,5 @@
using FileTime.App.Core;
using FileTime.Core.Services;
using FileTime.Providers.Local; using FileTime.Providers.Local;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@@ -10,6 +12,8 @@ namespace FileTime.App.DependencyInjection
serviceCollection ??= new ServiceCollection(); serviceCollection ??= new ServiceCollection();
return serviceCollection return serviceCollection
.AddTransient<ITab, Tab>()
.AddCoreAppServices()
.AddLocalServices(); .AddLocalServices();
} }
} }

View File

@@ -10,6 +10,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" /> <ProjectReference Include="..\..\Providers\FileTime.Providers.Local\FileTime.Providers.Local.csproj" />
<ProjectReference Include="..\FileTime.App.Core\FileTime.App.Core.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -17,6 +17,7 @@ namespace FileTime.GuiApp
.RegisterDefaultServices() .RegisterDefaultServices()
.AddConfiguration() .AddConfiguration()
.RegisterLogging() .RegisterLogging()
.RegisterServices()
.AddViewModels() .AddViewModels()
.BuildServiceProvider() .BuildServiceProvider()
.InitSerilog(); .InitSerilog();

View File

@@ -1,9 +1,7 @@
using System; using System;
using System.IO; using System.IO;
using FileTime.App.Core;
using FileTime.App.Core.Services; using FileTime.App.Core.Services;
using FileTime.App.Core.ViewModels; using FileTime.App.Core.ViewModels;
using FileTime.Core.Services;
using FileTime.GuiApp.Configuration; using FileTime.GuiApp.Configuration;
using FileTime.GuiApp.Logging; using FileTime.GuiApp.Logging;
using FileTime.GuiApp.Services; using FileTime.GuiApp.Services;
@@ -23,17 +21,12 @@ namespace FileTime.GuiApp
.AddSingleton<MainWindowViewModel>() .AddSingleton<MainWindowViewModel>()
.AddSingleton<GuiAppState>() .AddSingleton<GuiAppState>()
.AddSingleton<IAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>()) .AddSingleton<IAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>())
.AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>()) .AddSingleton<IGuiAppState, GuiAppState>(s => s.GetRequiredService<GuiAppState>());
.AddSingleton<DefaultModeKeyInputHandler>() }
.AddSingleton<RapidTravelModeKeyInputHandler>() internal static IServiceCollection RegisterServices(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>() .AddSingleton<IRxSchedulerService, AvaloniaRxSchedulerService>()
//TODO: move??
.AddTransient<ITab, Tab>()
.AddTransient<ITabViewModel, TabViewModel>()
.AddTransient<IContainerViewModel, ContainerViewModel>()
.AddTransient<IElementViewModel, ElementViewModel>()
.AddTransient<IItemNameConverterService, ItemNameConverterService>()
.AddSingleton<ICommandHandlerService, CommandHandlerService>()
.AddSingleton<IKeyInputHandlerService, KeyInputHandlerService>() .AddSingleton<IKeyInputHandlerService, KeyInputHandlerService>()
.AddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>() .AddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>()
.AddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>() .AddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>()