diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/Extensions/DeclarativePropertyExtensions.cs b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/Extensions/DeclarativePropertyExtensions.cs new file mode 100644 index 0000000..57b124b --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/Extensions/DeclarativePropertyExtensions.cs @@ -0,0 +1,9 @@ +namespace FileTime.ConsoleUI.App.Extensions; + +public static class DeclarativePropertyExtensions +{ + /*public static IDisposable Bind(this IDeclarativeProperty prop, Expression>) + { + + }*/ +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/FileTime.ConsoleUI.App.Abstractions.csproj b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/FileTime.ConsoleUI.App.Abstractions.csproj new file mode 100644 index 0000000..316f89f --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/FileTime.ConsoleUI.App.Abstractions.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + FileTime.ConsoleUI.App + + + + + + + + + + + diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/IApplication.cs b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/IApplication.cs new file mode 100644 index 0000000..e5aafd3 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/IApplication.cs @@ -0,0 +1,6 @@ +namespace FileTime.ConsoleUI.App; + +public interface IApplication +{ + void Run(); +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/IConsoleAppState.cs b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/IConsoleAppState.cs new file mode 100644 index 0000000..00b6fa1 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/IConsoleAppState.cs @@ -0,0 +1,8 @@ +using FileTime.App.Core.ViewModels; + +namespace FileTime.ConsoleUI.App; + +public interface IConsoleAppState : IAppState +{ + +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/KeyInputHandling/IKeyInputHandlerService.cs b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/KeyInputHandling/IKeyInputHandlerService.cs new file mode 100644 index 0000000..2bb8d8a --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App.Abstractions/KeyInputHandling/IKeyInputHandlerService.cs @@ -0,0 +1,8 @@ +using FileTime.App.Core.Models; + +namespace FileTime.ConsoleUI.App.KeyInputHandling; + +public interface IKeyInputHandlerService +{ + void HandleKeyInput(GeneralKeyEventArgs keyEvent); +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/App.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/App.cs new file mode 100644 index 0000000..4287d59 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/App.cs @@ -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 _appKeyService; + private readonly MainWindow _mainWindow; + private readonly IKeyInputHandlerService _keyInputHandlerService = null!; + + public App( + ILifecycleService lifecycleService, + IConsoleAppState consoleAppState, + IAppKeyService 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(); + } +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/ConsoleAppState.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/ConsoleAppState.cs new file mode 100644 index 0000000..476e029 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/ConsoleAppState.cs @@ -0,0 +1,8 @@ +using FileTime.App.Core.ViewModels; +using FileTime.App.Core.ViewModels.Timeline; + +namespace FileTime.ConsoleUI.App; + +public class ConsoleAppState : AppStateBase, IConsoleAppState +{ +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/ConsoleUserCommunicationService.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/ConsoleUserCommunicationService.cs new file mode 100644 index 0000000..b738711 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/ConsoleUserCommunicationService.cs @@ -0,0 +1,16 @@ +using FileTime.Core.Interactions; + +namespace FileTime.ConsoleUI.App; + +public class ConsoleUserCommunicationService : IUserCommunicationService +{ + public Task ReadInputs(params IInputElement[] fields) => throw new NotImplementedException(); + + public Task ReadInputs(IInputElement field, IEnumerable? previews = null) => throw new NotImplementedException(); + + public Task ReadInputs(IEnumerable fields, IEnumerable? previews = null) => throw new NotImplementedException(); + + public void ShowToastMessage(string text) => throw new NotImplementedException(); + + public Task ShowMessageBox(string text, bool showCancel = true, string? okText = null, string? cancelText = null) => throw new NotImplementedException(); +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemRenderer.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemRenderer.cs new file mode 100644 index 0000000..5a7f4f7 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/Controls/ItemRenderer.cs @@ -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?> _source; + + public ItemRenderer( + IDeclarativeProperty?> 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; +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/Extensions/KeyEventArgsExtensions.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/Extensions/KeyEventArgsExtensions.cs new file mode 100644 index 0000000..ccdcdb3 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/Extensions/KeyEventArgsExtensions.cs @@ -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 appKeyService) + { + var maybeKey = appKeyService.MapKey(args.Key); + if (maybeKey is not { } key1) return null; + return new GeneralKeyEventArgs + { + Key = key1 + }; + } +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj b/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj index d5b8c5f..da8e67d 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/FileTime.ConsoleUI.App.csproj @@ -10,4 +10,14 @@ true + + + + + + + + + + diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/KeyInputHandling/ConsoleAppKeyService.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/KeyInputHandling/ConsoleAppKeyService.cs new file mode 100644 index 0000000..dc0294f --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/KeyInputHandling/ConsoleAppKeyService.cs @@ -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 +{ + private static readonly Dictionary KeyMapping; + + //TODO: write test for this. Test if every enum value is present in the dictionary. + public static ReadOnlyDictionary KeyMappingReadOnly { get; } + + static ConsoleAppKeyService() + { + KeyMapping = new Dictionary + { + {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; + } +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/KeyInputHandling/KeyInputHandlerService.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/KeyInputHandling/KeyInputHandlerService.cs new file mode 100644 index 0000000..1577b66 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/KeyInputHandling/KeyInputHandlerService.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs new file mode 100644 index 0000000..383e926 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/MainWindow.cs @@ -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 GetElements() + { + return new View[] {_selectedItemsView}; + } +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/Startup.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/Startup.cs new file mode 100644 index 0000000..bf1fc88 --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI.App/Startup.cs @@ -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(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(sp => sp.GetRequiredService()); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton, ConsoleAppKeyService>(); + + return services; + } +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI/DI.cs b/src/ConsoleApp/FileTime.ConsoleUI/DI.cs new file mode 100644 index 0000000..f5d41dc --- /dev/null +++ b/src/ConsoleApp/FileTime.ConsoleUI/DI.cs @@ -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(); +} \ No newline at end of file diff --git a/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj b/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj index 70517d1..82a9cbd 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj +++ b/src/ConsoleApp/FileTime.ConsoleUI/FileTime.ConsoleUI.csproj @@ -12,7 +12,17 @@ + + + + + + + + + + diff --git a/src/ConsoleApp/FileTime.ConsoleUI/Program.cs b/src/ConsoleApp/FileTime.ConsoleUI/Program.cs index 17b3ef8..a971185 100644 --- a/src/ConsoleApp/FileTime.ConsoleUI/Program.cs +++ b/src/ConsoleApp/FileTime.ConsoleUI/Program.cs @@ -1,7 +1,14 @@ -// See https://aka.ms/new-console-template for more information -Console.WriteLine("Hello, World!"); +using FileTime.ConsoleUI; +using FileTime.ConsoleUI.App; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; -var d1 = new DirectoryInfo("C:"); -var d2 = new DirectoryInfo("C:\\"); +var configuration = new ConfigurationBuilder() +#if DEBUG + .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) +#endif + .Build(); +DI.Initialize(configuration); -; \ No newline at end of file +var app = DI.ServiceProvider.GetRequiredService(); +app.Run(); \ No newline at end of file