Console base WIP

This commit is contained in:
2023-08-07 14:55:18 +02:00
parent 2107d4f92a
commit b9adbc8272
18 changed files with 454 additions and 5 deletions

View File

@@ -0,0 +1,9 @@
namespace FileTime.ConsoleUI.App.Extensions;
public static class DeclarativePropertyExtensions
{
/*public static IDisposable Bind<T>(this IDeclarativeProperty<T> prop, Expression<Func<T>>)
{
}*/
}

View File

@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>FileTime.ConsoleUI.App</RootNamespace>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Terminal.Gui" Version="1.13.5" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,6 @@
namespace FileTime.ConsoleUI.App;
public interface IApplication
{
void Run();
}

View File

@@ -0,0 +1,8 @@
using FileTime.App.Core.ViewModels;
namespace FileTime.ConsoleUI.App;
public interface IConsoleAppState : IAppState
{
}

View File

@@ -0,0 +1,8 @@
using FileTime.App.Core.Models;
namespace FileTime.ConsoleUI.App.KeyInputHandling;
public interface IKeyInputHandlerService
{
void HandleKeyInput(GeneralKeyEventArgs keyEvent);
}

View File

@@ -0,0 +1,57 @@
using FileTime.App.Core.Services;
using FileTime.ConsoleUI.App.Extensions;
using FileTime.ConsoleUI.App.KeyInputHandling;
using FileTime.Core.Models;
using Terminal.Gui;
namespace FileTime.ConsoleUI.App;
public class App : IApplication
{
private readonly ILifecycleService _lifecycleService;
private readonly IConsoleAppState _consoleAppState;
private readonly IAppKeyService<Key> _appKeyService;
private readonly MainWindow _mainWindow;
private readonly IKeyInputHandlerService _keyInputHandlerService = null!;
public App(
ILifecycleService lifecycleService,
IConsoleAppState consoleAppState,
IAppKeyService<Key> appKeyService,
MainWindow mainWindow)
{
_lifecycleService = lifecycleService;
_consoleAppState = consoleAppState;
_appKeyService = appKeyService;
_mainWindow = mainWindow;
}
public void Run()
{
Task.Run(async () => await _lifecycleService.InitStartupHandlersAsync()).Wait();
_mainWindow.Initialize();
Application.Init();
foreach (var element in _mainWindow.GetElements())
{
Application.Top.Add(element);
}
Application.RootKeyEvent += e =>
{
if (e.ToGeneralKeyEventArgs(_appKeyService) is { } args)
{
_keyInputHandlerService.HandleKeyInput(args);
return args.Handled;
}
return false;
};
Application.Run();
Application.Shutdown();
}
}

View File

@@ -0,0 +1,8 @@
using FileTime.App.Core.ViewModels;
using FileTime.App.Core.ViewModels.Timeline;
namespace FileTime.ConsoleUI.App;
public class ConsoleAppState : AppStateBase, IConsoleAppState
{
}

View File

@@ -0,0 +1,16 @@
using FileTime.Core.Interactions;
namespace FileTime.ConsoleUI.App;
public class ConsoleUserCommunicationService : IUserCommunicationService
{
public Task<bool> ReadInputs(params IInputElement[] fields) => throw new NotImplementedException();
public Task<bool> ReadInputs(IInputElement field, IEnumerable<IPreviewElement>? previews = null) => throw new NotImplementedException();
public Task<bool> ReadInputs(IEnumerable<IInputElement> fields, IEnumerable<IPreviewElement>? previews = null) => throw new NotImplementedException();
public void ShowToastMessage(string text) => throw new NotImplementedException();
public Task<MessageBoxResult> ShowMessageBox(string text, bool showCancel = true, string? okText = null, string? cancelText = null) => throw new NotImplementedException();
}

View File

@@ -0,0 +1,43 @@
using System.Collections;
using System.Collections.ObjectModel;
using DeclarativeProperty;
using FileTime.App.Core.ViewModels;
using Terminal.Gui;
namespace FileTime.ConsoleUI.App.Controls;
public class ItemRenderer : IListDataSource
{
private readonly IDeclarativeProperty<ObservableCollection<IItemViewModel>?> _source;
public ItemRenderer(
IDeclarativeProperty<ObservableCollection<IItemViewModel>?> source,
ListView listView
)
{
_source = source;
source.Subscribe((_, _) =>
{
listView.EnsureSelectedItemVisible();
listView.SetNeedsDisplay();
});
}
public void Render(ListView container, ConsoleDriver driver, bool selected, int item, int col, int line, int width, int start = 0)
{
var itemViewModel = _source.Value?[item];
container.Move(col, line);
driver.AddStr(itemViewModel?.DisplayNameText ?? string.Empty);
}
public bool IsMarked(int item) => false;
public void SetMark(int item, bool value)
{
}
public IList ToList() => _source.Value!;
public int Count => _source.Value?.Count ?? 0;
public int Length => 20;
}

View File

@@ -0,0 +1,18 @@
using FileTime.App.Core.Models;
using FileTime.App.Core.Services;
using Terminal.Gui;
namespace FileTime.ConsoleUI.App.Extensions;
public static class KeyEventArgsExtensions
{
public static GeneralKeyEventArgs? ToGeneralKeyEventArgs(this KeyEvent args, IAppKeyService<Key> appKeyService)
{
var maybeKey = appKeyService.MapKey(args.Key);
if (maybeKey is not { } key1) return null;
return new GeneralKeyEventArgs
{
Key = key1
};
}
}

View File

@@ -10,4 +10,14 @@
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Terminal.Gui" Version="1.13.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
<ProjectReference Include="..\FileTime.ConsoleUI.App.Abstractions\FileTime.ConsoleUI.App.Abstractions.csproj" />
</ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,92 @@
using System.Collections.ObjectModel;
using FileTime.App.Core.Models;
using FileTime.App.Core.Services;
using Terminal.Gui;
namespace FileTime.ConsoleUI.App.KeyInputHandling;
public sealed class ConsoleAppKeyService : IAppKeyService<Key>
{
private static readonly Dictionary<Key, Keys> KeyMapping;
//TODO: write test for this. Test if every enum value is present in the dictionary.
public static ReadOnlyDictionary<Key, Keys> KeyMappingReadOnly { get; }
static ConsoleAppKeyService()
{
KeyMapping = new Dictionary<Key, Keys>
{
{Key.A, Keys.A},
{Key.B, Keys.B},
{Key.C, Keys.C},
{Key.D, Keys.D},
{Key.E, Keys.E},
{Key.F, Keys.F},
{Key.G, Keys.G},
{Key.H, Keys.H},
{Key.I, Keys.I},
{Key.J, Keys.J},
{Key.K, Keys.K},
{Key.L, Keys.L},
{Key.M, Keys.M},
{Key.N, Keys.N},
{Key.O, Keys.O},
{Key.P, Keys.P},
{Key.Q, Keys.Q},
{Key.R, Keys.R},
{Key.S, Keys.S},
{Key.T, Keys.T},
{Key.U, Keys.U},
{Key.V, Keys.V},
{Key.W, Keys.W},
{Key.X, Keys.X},
{Key.Y, Keys.Y},
{Key.Z, Keys.Z},
{Key.F1, Keys.F1},
{Key.F2, Keys.F2},
{Key.F3, Keys.F3},
{Key.F4, Keys.F4},
{Key.F5, Keys.F5},
{Key.F6, Keys.F6},
{Key.F7, Keys.F7},
{Key.F8, Keys.F8},
{Key.F9, Keys.F9},
{Key.F10, Keys.F10},
{Key.F11, Keys.F11},
{Key.F12, Keys.F12},
{Key.D0, Keys.Num0},
{Key.D1, Keys.Num1},
{Key.D2, Keys.Num2},
{Key.D3, Keys.Num3},
{Key.D4, Keys.Num4},
{Key.D5, Keys.Num5},
{Key.D6, Keys.Num6},
{Key.D7, Keys.Num7},
{Key.D8, Keys.Num8},
{Key.D9, Keys.Num9},
{Key.CursorUp, Keys.Up},
{Key.CursorDown, Keys.Down},
{Key.CursorLeft, Keys.Left},
{Key.CursorRight, Keys.Right},
{Key.Enter, Keys.Enter},
{Key.Esc, Keys.Escape},
{Key.Backspace, Keys.Backspace},
{Key.Space, Keys.Space},
{Key.PageUp, Keys.PageUp},
{Key.PageDown, Keys.PageDown},
{Key.Tab, Keys.Tab},
{(Key)44, Keys.Comma},
{(Key)63, Keys.Question},
{(Key)123456, Keys.LWin},
{(Key)123457, Keys.RWin},
};
KeyMappingReadOnly = new(KeyMapping);
}
public Keys? MapKey(Key key)
{
if (!KeyMapping.TryGetValue(key, out var mappedKey)) return null;
return mappedKey;
}
}

View File

@@ -0,0 +1,38 @@
using FileTime.App.Core.Models;
using FileTime.App.Core.Models.Enums;
using FileTime.App.Core.Services;
using FileTime.App.Core.ViewModels;
namespace FileTime.ConsoleUI.App.KeyInputHandling;
public class KeyInputHandlerService : IKeyInputHandlerService
{
private readonly IAppState _appState;
private readonly IDefaultModeKeyInputHandler _defaultModeKeyInputHandler;
private readonly IRapidTravelModeKeyInputHandler _rapidTravelModeKeyInputHandler;
bool _isCtrlPressed = false;
bool _isShiftPressed = false;
bool _isAltPressed = false;
public KeyInputHandlerService(
IAppState appState,
IDefaultModeKeyInputHandler defaultModeKeyInputHandler,
IRapidTravelModeKeyInputHandler rapidTravelModeKeyInputHandler)
{
_appState = appState;
_defaultModeKeyInputHandler = defaultModeKeyInputHandler;
_rapidTravelModeKeyInputHandler = rapidTravelModeKeyInputHandler;
}
public void HandleKeyInput(GeneralKeyEventArgs keyEvent)
{
var specialKeysStatus = new SpecialKeysStatus(_isAltPressed, _isShiftPressed, _isCtrlPressed);
if (_appState.ViewMode.Value == ViewMode.Default)
{
_defaultModeKeyInputHandler.HandleInputKey(keyEvent, specialKeysStatus);
}
else
{
_rapidTravelModeKeyInputHandler.HandleInputKey(keyEvent, specialKeysStatus);
}
}
}

View File

@@ -0,0 +1,43 @@
using DeclarativeProperty;
using FileTime.App.Core.ViewModels;
using FileTime.ConsoleUI.App.Controls;
using FileTime.Core.Models;
using Terminal.Gui;
namespace FileTime.ConsoleUI.App;
public class MainWindow
{
private readonly IConsoleAppState _consoleAppState;
private readonly ListView _selectedItemsView;
public MainWindow(IConsoleAppState consoleAppState)
{
_consoleAppState = consoleAppState;
_selectedItemsView = new() {X = 1, Y = 0, Width = Dim.Fill(), Height = Dim.Fill()};
_selectedItemsView.AddKeyBinding(Key.Space, Command.ToggleChecked);
_selectedItemsView.OpenSelectedItem += (e) =>
{
if (e.Value is IItemViewModel {BaseItem: IContainer container}
&& consoleAppState.SelectedTab.Value?.Tab is { } tab)
tab.SetCurrentLocation(container);
};
}
public void Initialize()
{
var selectedsItems = _consoleAppState
.SelectedTab
.Map(t => t.CurrentItems)
.Switch();
var renderer = new ItemRenderer(selectedsItems, _selectedItemsView);
_selectedItemsView.Source = renderer;
}
public IEnumerable<View> GetElements()
{
return new View[] {_selectedItemsView};
}
}

View File

@@ -0,0 +1,25 @@
using FileTime.App.Core.Services;
using FileTime.App.Core.ViewModels;
using FileTime.ConsoleUI.App.KeyInputHandling;
using FileTime.Core.Interactions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Terminal.Gui;
namespace FileTime.ConsoleUI.App;
public static class Startup
{
public static IServiceCollection AddConsoleServices(this IServiceCollection services)
{
services.TryAddSingleton<IApplication, App>();
services.TryAddSingleton<MainWindow>();
services.TryAddSingleton<IConsoleAppState, ConsoleAppState>();
services.TryAddSingleton<IAppState>(sp => sp.GetRequiredService<IConsoleAppState>());
services.TryAddSingleton<IUserCommunicationService, ConsoleUserCommunicationService>();
services.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
services.TryAddSingleton<IAppKeyService<Key>, ConsoleAppKeyService>();
return services;
}
}

View File

@@ -0,0 +1,33 @@
using FileTime.App.CommandPalette;
using FileTime.App.ContainerSizeScanner;
using FileTime.App.DependencyInjection;
using FileTime.App.FrequencyNavigation;
using FileTime.App.Search;
using FileTime.ConsoleUI.App;
using FileTime.Providers.Local;
using FileTime.Server.Common;
using FileTime.Tools.Compression;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
namespace FileTime.ConsoleUI;
public class DI
{
public static IServiceProvider ServiceProvider { get; set; } = null!;
public static void Initialize(IConfigurationRoot configuration)
=> ServiceProvider = DependencyInjection
.RegisterDefaultServices(configuration: configuration)
.AddConsoleServices()
.AddLocalProviderServices()
.AddServerCoreServices()
.AddFrequencyNavigation()
.AddCommandPalette()
.AddContainerSizeScanner()
.AddSearch()
.AddCompression()
.AddLogging(loggingBuilder => loggingBuilder.AddSerilog())
.BuildServiceProvider();
}

View File

@@ -12,7 +12,17 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\AppCommon\FileTime.App.ContainerSizeScanner\FileTime.App.ContainerSizeScanner.csproj" />
<ProjectReference Include="..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
<ProjectReference Include="..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
<ProjectReference Include="..\..\Tools\FileTime.Tools.Compression\FileTime.Tools.Compression.csproj" />
<ProjectReference Include="..\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj" /> <ProjectReference Include="..\FileTime.ConsoleUI.App\FileTime.ConsoleUI.App.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,7 +1,14 @@
// See https://aka.ms/new-console-template for more information using FileTime.ConsoleUI;
Console.WriteLine("Hello, World!"); using FileTime.ConsoleUI.App;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
var d1 = new DirectoryInfo("C:"); var configuration = new ConfigurationBuilder()
var d2 = new DirectoryInfo("C:\\"); #if DEBUG
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
#endif
.Build();
DI.Initialize(configuration);
; var app = DI.ServiceProvider.GetRequiredService<IApplication>();
app.Run();