Custom TUI Library WIP
This commit is contained in:
@@ -11,8 +11,4 @@
|
||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Terminal.Gui" Version="1.13.5" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
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;
|
||||
|
||||
@@ -10,7 +7,7 @@ public class App : IApplication
|
||||
{
|
||||
private readonly ILifecycleService _lifecycleService;
|
||||
private readonly IConsoleAppState _consoleAppState;
|
||||
private readonly IAppKeyService<Key> _appKeyService;
|
||||
//private readonly IAppKeyService<Key> _appKeyService;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly IKeyInputHandlerService _keyInputHandlerService;
|
||||
|
||||
@@ -18,13 +15,13 @@ public class App : IApplication
|
||||
ILifecycleService lifecycleService,
|
||||
IKeyInputHandlerService keyInputHandlerService,
|
||||
IConsoleAppState consoleAppState,
|
||||
IAppKeyService<Key> appKeyService,
|
||||
//IAppKeyService<Key> appKeyService,
|
||||
MainWindow mainWindow)
|
||||
{
|
||||
_lifecycleService = lifecycleService;
|
||||
_keyInputHandlerService = keyInputHandlerService;
|
||||
_consoleAppState = consoleAppState;
|
||||
_appKeyService = appKeyService;
|
||||
//_appKeyService = appKeyService;
|
||||
_mainWindow = mainWindow;
|
||||
}
|
||||
|
||||
@@ -34,24 +31,5 @@ public class App : IApplication
|
||||
Task.Run(async () => await _lifecycleService.InitStartupHandlersAsync()).Wait();
|
||||
|
||||
_mainWindow.Initialize();
|
||||
|
||||
Application.Init();
|
||||
var asd = Application.Top.ColorScheme;
|
||||
|
||||
foreach (var element in _mainWindow.GetElements())
|
||||
{
|
||||
Application.Top.Add(element);
|
||||
}
|
||||
|
||||
Application.RootKeyEvent += e =>
|
||||
{
|
||||
if (e.ToGeneralKeyEventArgs(_appKeyService) is not { } args) return false;
|
||||
_keyInputHandlerService.HandleKeyInput(args);
|
||||
|
||||
return args.Handled;
|
||||
};
|
||||
|
||||
Application.Run();
|
||||
Application.Shutdown();
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
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,
|
||||
Action update
|
||||
)
|
||||
{
|
||||
_source = source;
|
||||
source.Subscribe((_, _) =>
|
||||
{
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace FileTime.ConsoleUI.App.Extensions;
|
||||
|
||||
public static class UiExtensions
|
||||
{
|
||||
public static void Update(this ListView listView)
|
||||
{
|
||||
listView.EnsureSelectedItemVisible();
|
||||
listView.SetNeedsDisplay();
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,16 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
||||
<PackageReference Include="Terminal.Gui" Version="1.13.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
||||
<ProjectReference Include="..\..\Library\TerminalUI\TerminalUI.csproj" />
|
||||
<ProjectReference Include="..\FileTime.ConsoleUI.App.Abstractions\FileTime.ConsoleUI.App.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controls\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
using DeclarativeProperty;
|
||||
using FileTime.ConsoleUI.App.Controls;
|
||||
using System.Collections.ObjectModel;
|
||||
using DeclarativeProperty;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.ConsoleUI.App.Extensions;
|
||||
using Terminal.Gui;
|
||||
using TerminalUI;
|
||||
using TerminalUI.Controls;
|
||||
using TerminalUI.Extensions;
|
||||
|
||||
namespace FileTime.ConsoleUI.App;
|
||||
|
||||
public class MainWindow
|
||||
{
|
||||
private readonly IConsoleAppState _consoleAppState;
|
||||
private View[] _views;
|
||||
private const int ParentColumnWidth = 20;
|
||||
|
||||
public MainWindow(IConsoleAppState consoleAppState)
|
||||
@@ -16,67 +18,16 @@ public class MainWindow
|
||||
_consoleAppState = consoleAppState;
|
||||
}
|
||||
|
||||
public void Initialize() =>
|
||||
_views = new View[]
|
||||
{
|
||||
GetSelectedItemsView(),
|
||||
GetParentsChildren(),
|
||||
GetSelectedsChildren()
|
||||
};
|
||||
|
||||
private ListView GetSelectedItemsView()
|
||||
public void Initialize()
|
||||
{
|
||||
ListView selectedItemsView = new() {X = ParentColumnWidth, Y = 1, Width = Dim.Percent(60) - 20, Height = Dim.Fill()};
|
||||
var selectedsItems = _consoleAppState
|
||||
.SelectedTab
|
||||
.Map(t => t.CurrentItems)
|
||||
.Switch();
|
||||
ListView<IAppState, IItemViewModel> selectedItemsView = new();
|
||||
selectedItemsView.DataContext = _consoleAppState;
|
||||
|
||||
var selectedItem = _consoleAppState.SelectedTab
|
||||
.Map(t => t.CurrentSelectedItem)
|
||||
.Switch();
|
||||
|
||||
DeclarativePropertyHelpers.CombineLatest(
|
||||
selectedItem,
|
||||
selectedsItems,
|
||||
(selected, items) => Task.FromResult(items.IndexOf(selected)))
|
||||
.Subscribe((index, _) =>
|
||||
{
|
||||
if (index == -1) return;
|
||||
selectedItemsView.SelectedItem = index;
|
||||
selectedItemsView.Update();
|
||||
});
|
||||
|
||||
var renderer = new ItemRenderer(selectedsItems, selectedItemsView.Update);
|
||||
selectedItemsView.Source = renderer;
|
||||
return selectedItemsView;
|
||||
selectedItemsView.Bind(
|
||||
selectedItemsView,
|
||||
appState => appState.SelectedTab.Map(t => t == null ? null : t.CurrentItems).Switch(),
|
||||
v => v.ItemsSource);
|
||||
|
||||
selectedItemsView.Render();
|
||||
}
|
||||
|
||||
private ListView GetParentsChildren()
|
||||
{
|
||||
ListView parentsChildrenView = new() {X = 0, Y = 1, Width = ParentColumnWidth, Height = Dim.Fill()};
|
||||
var parentsChildren = _consoleAppState
|
||||
.SelectedTab
|
||||
.Map(t => t.ParentsChildren)
|
||||
.Switch();
|
||||
|
||||
var renderer = new ItemRenderer(parentsChildren, parentsChildrenView.Update);
|
||||
parentsChildrenView.Source = renderer;
|
||||
return parentsChildrenView;
|
||||
}
|
||||
|
||||
private ListView GetSelectedsChildren()
|
||||
{
|
||||
ListView selectedsChildrenView = new() {X = Pos.Percent(60), Y = 1, Width = Dim.Percent(40), Height = Dim.Fill()};
|
||||
var selectedsChildren = _consoleAppState
|
||||
.SelectedTab
|
||||
.Map(t => t.SelectedsChildren)
|
||||
.Switch();
|
||||
|
||||
var renderer = new ItemRenderer(selectedsChildren, selectedsChildrenView.Update);
|
||||
selectedsChildrenView.Source = renderer;
|
||||
return selectedsChildrenView;
|
||||
}
|
||||
|
||||
public IEnumerable<View> GetElements() => _views;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.Models;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace FileTime.ConsoleUI.App.Services;
|
||||
|
||||
public class SystemClipboardService : ISystemClipboardService
|
||||
{
|
||||
public Task CopyToClipboardAsync(string text)
|
||||
{
|
||||
Clipboard.TrySetClipboardData(text);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task<IEnumerable<FullName>> GetFilesAsync() => throw new NotImplementedException();
|
||||
|
||||
public Task SetFilesAsync(IEnumerable<FullName> files) => throw new NotImplementedException();
|
||||
}
|
||||
@@ -5,7 +5,6 @@ using FileTime.ConsoleUI.App.Services;
|
||||
using FileTime.Core.Interactions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using Terminal.Gui;
|
||||
|
||||
namespace FileTime.ConsoleUI.App;
|
||||
|
||||
@@ -19,8 +18,6 @@ public static class Startup
|
||||
services.TryAddSingleton<IAppState>(sp => sp.GetRequiredService<IConsoleAppState>());
|
||||
services.TryAddSingleton<IUserCommunicationService, ConsoleUserCommunicationService>();
|
||||
services.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
|
||||
services.TryAddSingleton<IAppKeyService<Key>, ConsoleAppKeyService>();
|
||||
services.TryAddSingleton<ISystemClipboardService, SystemClipboardService>();
|
||||
services.AddSingleton<CustomLoggerSink>();
|
||||
|
||||
return services;
|
||||
|
||||
Reference in New Issue
Block a user