Terminal UI V2, advanced binding
This commit is contained in:
@@ -1,32 +1,42 @@
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.ConsoleUI.App.KeyInputHandling;
|
||||
using TerminalUI;
|
||||
using TerminalUI.ConsoleDrivers;
|
||||
|
||||
namespace FileTime.ConsoleUI.App;
|
||||
|
||||
public class App : IApplication
|
||||
{
|
||||
private readonly ILifecycleService _lifecycleService;
|
||||
|
||||
private readonly IConsoleAppState _consoleAppState;
|
||||
//private readonly IAppKeyService<Key> _appKeyService;
|
||||
|
||||
private readonly IAppKeyService<ConsoleKey> _appKeyService;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly IApplicationContext _applicationContext;
|
||||
private readonly IConsoleDriver _consoleDriver;
|
||||
private readonly IKeyInputHandlerService _keyInputHandlerService;
|
||||
private readonly Thread _renderThread;
|
||||
|
||||
public App(
|
||||
ILifecycleService lifecycleService,
|
||||
IKeyInputHandlerService keyInputHandlerService,
|
||||
IConsoleAppState consoleAppState,
|
||||
//IAppKeyService<Key> appKeyService,
|
||||
IAppKeyService<ConsoleKey> appKeyService,
|
||||
MainWindow mainWindow,
|
||||
IApplicationContext applicationContext)
|
||||
IApplicationContext applicationContext,
|
||||
IConsoleDriver consoleDriver)
|
||||
{
|
||||
_lifecycleService = lifecycleService;
|
||||
_keyInputHandlerService = keyInputHandlerService;
|
||||
_consoleAppState = consoleAppState;
|
||||
//_appKeyService = appKeyService;
|
||||
_appKeyService = appKeyService;
|
||||
_mainWindow = mainWindow;
|
||||
_applicationContext = applicationContext;
|
||||
_consoleDriver = consoleDriver;
|
||||
|
||||
_renderThread = new Thread(Render);
|
||||
}
|
||||
|
||||
public void Run()
|
||||
@@ -34,7 +44,31 @@ public class App : IApplication
|
||||
Task.Run(async () => await _lifecycleService.InitStartupHandlersAsync()).Wait();
|
||||
|
||||
_mainWindow.Initialize();
|
||||
|
||||
_applicationContext.EventLoop.Run();
|
||||
foreach (var rootView in _mainWindow.RootViews())
|
||||
{
|
||||
_applicationContext.EventLoop.AddViewToRender(rootView);
|
||||
}
|
||||
|
||||
_applicationContext.IsRunning = true;
|
||||
_renderThread.Start();
|
||||
|
||||
while (_applicationContext.IsRunning)
|
||||
{
|
||||
if (_consoleDriver.CanRead())
|
||||
{
|
||||
var key = _consoleDriver.ReadKey();
|
||||
if (_appKeyService.MapKey(key.Key) is { } mappedKey)
|
||||
{
|
||||
var keyEventArgs = new GeneralKeyEventArgs
|
||||
{
|
||||
Key = mappedKey
|
||||
};
|
||||
_keyInputHandlerService.HandleKeyInput(keyEventArgs);
|
||||
}
|
||||
}
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
private void Render() => _applicationContext.EventLoop.Run();
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
|
||||
namespace FileTime.ConsoleUI.App.KeyInputHandling;
|
||||
|
||||
public class ConsoleAppKeyService : IAppKeyService<ConsoleKey>
|
||||
{
|
||||
private static readonly Dictionary<ConsoleKey, Keys> KeyMapping;
|
||||
|
||||
//TODO: write test for this. Test if every enum value is present in the dictionary.
|
||||
public static ReadOnlyDictionary<ConsoleKey, Keys> KeyMappingReadOnly { get; }
|
||||
|
||||
static ConsoleAppKeyService()
|
||||
{
|
||||
KeyMapping = new Dictionary<ConsoleKey, Keys>
|
||||
{
|
||||
{ConsoleKey.A, Keys.A},
|
||||
{ConsoleKey.B, Keys.B},
|
||||
{ConsoleKey.C, Keys.C},
|
||||
{ConsoleKey.D, Keys.D},
|
||||
{ConsoleKey.E, Keys.E},
|
||||
{ConsoleKey.F, Keys.F},
|
||||
{ConsoleKey.G, Keys.G},
|
||||
{ConsoleKey.H, Keys.H},
|
||||
{ConsoleKey.I, Keys.I},
|
||||
{ConsoleKey.J, Keys.J},
|
||||
{ConsoleKey.K, Keys.K},
|
||||
{ConsoleKey.L, Keys.L},
|
||||
{ConsoleKey.M, Keys.M},
|
||||
{ConsoleKey.N, Keys.N},
|
||||
{ConsoleKey.O, Keys.O},
|
||||
{ConsoleKey.P, Keys.P},
|
||||
{ConsoleKey.Q, Keys.Q},
|
||||
{ConsoleKey.R, Keys.R},
|
||||
{ConsoleKey.S, Keys.S},
|
||||
{ConsoleKey.T, Keys.T},
|
||||
{ConsoleKey.U, Keys.U},
|
||||
{ConsoleKey.V, Keys.V},
|
||||
{ConsoleKey.W, Keys.W},
|
||||
{ConsoleKey.X, Keys.X},
|
||||
{ConsoleKey.Y, Keys.Y},
|
||||
{ConsoleKey.Z, Keys.Z},
|
||||
{ConsoleKey.F1, Keys.F1},
|
||||
{ConsoleKey.F2, Keys.F2},
|
||||
{ConsoleKey.F3, Keys.F3},
|
||||
{ConsoleKey.F4, Keys.F4},
|
||||
{ConsoleKey.F5, Keys.F5},
|
||||
{ConsoleKey.F6, Keys.F6},
|
||||
{ConsoleKey.F7, Keys.F7},
|
||||
{ConsoleKey.F8, Keys.F8},
|
||||
{ConsoleKey.F9, Keys.F9},
|
||||
{ConsoleKey.F10, Keys.F10},
|
||||
{ConsoleKey.F11, Keys.F11},
|
||||
{ConsoleKey.F12, Keys.F12},
|
||||
{ConsoleKey.D0, Keys.Num0},
|
||||
{ConsoleKey.D1, Keys.Num1},
|
||||
{ConsoleKey.D2, Keys.Num2},
|
||||
{ConsoleKey.D3, Keys.Num3},
|
||||
{ConsoleKey.D4, Keys.Num4},
|
||||
{ConsoleKey.D5, Keys.Num5},
|
||||
{ConsoleKey.D6, Keys.Num6},
|
||||
{ConsoleKey.D7, Keys.Num7},
|
||||
{ConsoleKey.D8, Keys.Num8},
|
||||
{ConsoleKey.D9, Keys.Num9},
|
||||
{ConsoleKey.UpArrow, Keys.Up},
|
||||
{ConsoleKey.DownArrow, Keys.Down},
|
||||
{ConsoleKey.LeftArrow, Keys.Left},
|
||||
{ConsoleKey.RightArrow, Keys.Right},
|
||||
{ConsoleKey.Enter, Keys.Enter},
|
||||
{ConsoleKey.Escape, Keys.Escape},
|
||||
{ConsoleKey.Backspace, Keys.Backspace},
|
||||
{ConsoleKey.Spacebar, Keys.Space},
|
||||
{ConsoleKey.PageUp, Keys.PageUp},
|
||||
{ConsoleKey.PageDown, Keys.PageDown},
|
||||
{ConsoleKey.OemComma, Keys.Comma},
|
||||
{(ConsoleKey)0xA1, Keys.Question},
|
||||
{ConsoleKey.Tab, Keys.Tab},
|
||||
{ConsoleKey.LeftWindows, Keys.LWin},
|
||||
{ConsoleKey.RightWindows, Keys.RWin},
|
||||
};
|
||||
|
||||
KeyMappingReadOnly = new(KeyMapping);
|
||||
}
|
||||
|
||||
public Keys? MapKey(ConsoleKey key)
|
||||
{
|
||||
if (!KeyMapping.TryGetValue(key, out var mappedKey)) return null;
|
||||
return mappedKey;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq.Expressions;
|
||||
using DeclarativeProperty;
|
||||
using FileTime.App.Core.Models.Enums;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using TerminalUI;
|
||||
using TerminalUI.Controls;
|
||||
using TerminalUI.Extensions;
|
||||
using TerminalUI.Models;
|
||||
|
||||
namespace FileTime.ConsoleUI.App;
|
||||
|
||||
@@ -11,22 +14,28 @@ public class MainWindow
|
||||
{
|
||||
private readonly IConsoleAppState _consoleAppState;
|
||||
private readonly IApplicationContext _applicationContext;
|
||||
private const int ParentColumnWidth = 20;
|
||||
private readonly ITheme _theme;
|
||||
private ListView<IAppState, IItemViewModel> _selectedItemsView;
|
||||
|
||||
public MainWindow(IConsoleAppState consoleAppState, IApplicationContext applicationContext)
|
||||
public MainWindow(
|
||||
IConsoleAppState consoleAppState,
|
||||
IApplicationContext applicationContext,
|
||||
ITheme theme)
|
||||
{
|
||||
_consoleAppState = consoleAppState;
|
||||
_applicationContext = applicationContext;
|
||||
_theme = theme;
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
ListView<IAppState, IItemViewModel> selectedItemsView = new()
|
||||
_selectedItemsView = new()
|
||||
{
|
||||
DataContext = _consoleAppState,
|
||||
ApplicationContext = _applicationContext
|
||||
};
|
||||
selectedItemsView.DataContext = _consoleAppState;
|
||||
selectedItemsView.ItemTemplate = item =>
|
||||
|
||||
_selectedItemsView.ItemTemplate = item =>
|
||||
{
|
||||
var textBlock = item.CreateChild<TextBlock<IItemViewModel>>();
|
||||
textBlock.Bind(
|
||||
@@ -34,15 +43,44 @@ public class MainWindow
|
||||
dc => dc == null ? string.Empty : dc.DisplayNameText,
|
||||
tb => tb.Text
|
||||
);
|
||||
textBlock.Bind(
|
||||
textBlock,
|
||||
dc => dc == null ? _theme.DefaultForegroundColor : ToForegroundColor(dc.ViewMode.Value),
|
||||
tb => tb.Foreground
|
||||
);
|
||||
|
||||
return textBlock;
|
||||
};
|
||||
|
||||
selectedItemsView.Bind(
|
||||
selectedItemsView,
|
||||
appState => appState.SelectedTab.Map(t => t == null ? null : t.CurrentItems).Switch(),
|
||||
_selectedItemsView.Bind(
|
||||
_selectedItemsView,
|
||||
appState => appState == null ? null : appState.SelectedTab.Map(t => t == null ? null : t.CurrentItems).Switch(),
|
||||
v => v.ItemsSource);
|
||||
|
||||
selectedItemsView.RequestRerender();
|
||||
}
|
||||
|
||||
public IEnumerable<IView> RootViews() => new IView[] {_selectedItemsView};
|
||||
|
||||
private IColor? ToForegroundColor(ItemViewMode viewMode)
|
||||
=> viewMode switch
|
||||
{
|
||||
ItemViewMode.Default => _theme.DefaultForegroundColor,
|
||||
ItemViewMode.Alternative => _theme.AlternativeItemForegroundColor,
|
||||
ItemViewMode.Selected => _theme.SelectedItemForegroundColor,
|
||||
ItemViewMode.Marked => _theme.MarkedItemForegroundColor,
|
||||
ItemViewMode.MarkedSelected => _theme.MarkedSelectedItemForegroundColor,
|
||||
ItemViewMode.MarkedAlternative => _theme.MarkedAlternativeItemForegroundColor,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
|
||||
private IColor? ToBackgroundColor(ItemViewMode viewMode)
|
||||
=> viewMode switch
|
||||
{
|
||||
ItemViewMode.Default => _theme.DefaultBackgroundColor,
|
||||
ItemViewMode.Alternative => _theme.AlternativeItemBackgroundColor,
|
||||
ItemViewMode.Selected => _theme.SelectedItemBackgroundColor,
|
||||
ItemViewMode.Marked => _theme.MarkedItemBackgroundColor,
|
||||
ItemViewMode.MarkedSelected => _theme.MarkedSelectedItemBackgroundColor,
|
||||
ItemViewMode.MarkedAlternative => _theme.MarkedAlternativeItemBackgroundColor,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.ConsoleUI.App.Services;
|
||||
|
||||
public class ConsoleSystemClipboardService : ISystemClipboardService
|
||||
{
|
||||
public Task CopyToClipboardAsync(string text) => throw new NotImplementedException();
|
||||
|
||||
public Task<IEnumerable<FullName>> GetFilesAsync() => throw new NotImplementedException();
|
||||
|
||||
public Task SetFilesAsync(IEnumerable<FullName> files) => throw new NotImplementedException();
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using FileTime.Core.Interactions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using TerminalUI;
|
||||
using TerminalUI.ConsoleDrivers;
|
||||
|
||||
namespace FileTime.ConsoleUI.App;
|
||||
|
||||
@@ -19,9 +20,16 @@ public static class Startup
|
||||
services.TryAddSingleton<IAppState>(sp => sp.GetRequiredService<IConsoleAppState>());
|
||||
services.TryAddSingleton<IUserCommunicationService, ConsoleUserCommunicationService>();
|
||||
services.TryAddSingleton<IKeyInputHandlerService, KeyInputHandlerService>();
|
||||
services.TryAddSingleton<IAppKeyService<ConsoleKey>, ConsoleAppKeyService>();
|
||||
services.TryAddSingleton<ISystemClipboardService, ConsoleSystemClipboardService>();
|
||||
services.AddSingleton<CustomLoggerSink>();
|
||||
|
||||
services.TryAddSingleton<IApplicationContext, ApplicationContext>();
|
||||
services.TryAddSingleton<IApplicationContext>(sp
|
||||
=> new ApplicationContext
|
||||
{
|
||||
ConsoleDriver = sp.GetRequiredService<IConsoleDriver>()
|
||||
}
|
||||
);
|
||||
return services;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user