CommandPalette use FuzzyPanel, Focus search textbox
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.FuzzyPanel.Abstraction\FileTime.App.FuzzyPanel.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -7,6 +7,7 @@ public interface ICommandPaletteService
|
||||
{
|
||||
IObservable<bool> ShowWindow { get; }
|
||||
void OpenCommandPalette();
|
||||
void CloseCommandPalette();
|
||||
IReadOnlyList<ICommandPaletteEntry> GetCommands();
|
||||
ICommandPaletteViewModel? CurrentModal { get; }
|
||||
}
|
||||
@@ -1,14 +1,10 @@
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.FuzzyPanel;
|
||||
|
||||
namespace FileTime.App.CommandPalette.ViewModels;
|
||||
|
||||
public interface ICommandPaletteViewModel : IModalViewModel
|
||||
public interface ICommandPaletteViewModel : IFuzzyPanelViewModel<ICommandPaletteEntryViewModel>, IModalViewModel
|
||||
{
|
||||
IObservable<bool> ShowWindow { get; }
|
||||
List<ICommandPaletteEntryViewModel> FilteredMatches { get; }
|
||||
string SearchText { get; set; }
|
||||
ICommandPaletteEntryViewModel SelectedItem { get; set; }
|
||||
void Close();
|
||||
void HandleKeyDown(KeyEventArgs keyEventArgs);
|
||||
}
|
||||
@@ -9,10 +9,12 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FileTime.App.CommandPalette.Abstractions\FileTime.App.CommandPalette.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.FuzzyPanel\FileTime.App.FuzzyPanel.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
|
||||
<PackageReference Include="PropertyChanged.SourceGenerator" Version="1.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -28,6 +28,16 @@ public partial class CommandPaletteService : ICommandPaletteService
|
||||
CurrentModal = _modalService.OpenModal<ICommandPaletteViewModel>();
|
||||
}
|
||||
|
||||
public void CloseCommandPalette()
|
||||
{
|
||||
_showWindow.OnNext(false);
|
||||
if (_currentModal is not null)
|
||||
{
|
||||
_modalService.CloseModal(_currentModal);
|
||||
CurrentModal = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<ICommandPaletteEntry> GetCommands() =>
|
||||
_identifiableUserCommandService
|
||||
.GetCommandIdentifiers()
|
||||
|
||||
@@ -1,59 +1,85 @@
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.CommandPalette.Services;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using MvvmGen;
|
||||
using FileTime.App.FuzzyPanel;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FileTime.App.CommandPalette.ViewModels;
|
||||
|
||||
[ViewModel]
|
||||
[Inject(typeof(ICommandPaletteService), "_commandPaletteService")]
|
||||
public partial class CommandPaletteViewModel : ICommandPaletteViewModel
|
||||
public class CommandPaletteViewModel : FuzzyPanelViewModel<ICommandPaletteEntryViewModel>, ICommandPaletteViewModel
|
||||
{
|
||||
private string _searchText;
|
||||
|
||||
[Property] private IObservable<bool> _showWindow;
|
||||
[Property] private List<ICommandPaletteEntryViewModel> _filteredMatches;
|
||||
[Property] private ICommandPaletteEntryViewModel? _selectedItem;
|
||||
private readonly ICommandPaletteService _commandPaletteService;
|
||||
private readonly IIdentifiableUserCommandService _identifiableUserCommandService;
|
||||
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
||||
private readonly ILogger<CommandPaletteViewModel> _logger;
|
||||
string IModalViewModel.Name => "CommandPalette";
|
||||
|
||||
public string SearchText
|
||||
{
|
||||
get => _searchText;
|
||||
set
|
||||
{
|
||||
if (_searchText == value) return;
|
||||
|
||||
_searchText = value;
|
||||
OnPropertyChanged();
|
||||
|
||||
UpdateFilteredMatches();
|
||||
}
|
||||
}
|
||||
|
||||
public void Close() => throw new NotImplementedException();
|
||||
|
||||
public void HandleKeyDown(KeyEventArgs keyEventArgs) => throw new NotImplementedException();
|
||||
|
||||
partial void OnInitialize()
|
||||
public CommandPaletteViewModel(
|
||||
ICommandPaletteService commandPaletteService,
|
||||
IIdentifiableUserCommandService identifiableUserCommandService,
|
||||
IUserCommandHandlerService userCommandHandlerService,
|
||||
ILogger<CommandPaletteViewModel> logger)
|
||||
{
|
||||
_commandPaletteService = commandPaletteService;
|
||||
_identifiableUserCommandService = identifiableUserCommandService;
|
||||
_userCommandHandlerService = userCommandHandlerService;
|
||||
_logger = logger;
|
||||
ShowWindow = _commandPaletteService.ShowWindow;
|
||||
UpdateFilteredMatches();
|
||||
UpdateFilteredMatchesInternal();
|
||||
}
|
||||
|
||||
private void UpdateFilteredMatches()
|
||||
{
|
||||
public void Close() => _commandPaletteService.CloseCommandPalette();
|
||||
|
||||
public override void UpdateFilteredMatches() => UpdateFilteredMatchesInternal();
|
||||
|
||||
private void UpdateFilteredMatchesInternal() =>
|
||||
FilteredMatches = _commandPaletteService
|
||||
.GetCommands()
|
||||
.Where(c =>
|
||||
c.Title.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|
||||
|| c.Identifier.Contains(SearchText, StringComparison.OrdinalIgnoreCase)
|
||||
)
|
||||
.Select(c =>
|
||||
(ICommandPaletteEntryViewModel) new CommandPaletteEntryViewModel(c.Identifier, c.Title))
|
||||
.Take(30) // TODO remove magic number
|
||||
.OrderBy(c => c.Title)
|
||||
.ToList();
|
||||
|
||||
if (SelectedItem != null && FilteredMatches.Contains(SelectedItem)) return;
|
||||
public override async Task<bool> HandleKeyDown(KeyEventArgs keyEventArgs)
|
||||
{
|
||||
var handled = await base.HandleKeyDown(keyEventArgs);
|
||||
if (handled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
SelectedItem = FilteredMatches.Count > 0
|
||||
? FilteredMatches[0]
|
||||
: null;
|
||||
if (keyEventArgs.Key == Key.Escape)
|
||||
{
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEventArgs.Key == Key.Enter)
|
||||
{
|
||||
if (SelectedItem is null) return false;
|
||||
|
||||
var command = _identifiableUserCommandService.GetCommand(SelectedItem.Identifier);
|
||||
if (command is null) return false;
|
||||
|
||||
try
|
||||
{
|
||||
await _userCommandHandlerService.HandleCommandAsync(command);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Unknown error while running command. {Command} {Error}", command.GetType().Name, e);
|
||||
}
|
||||
|
||||
Close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,6 @@ namespace FileTime.App.Core.Services;
|
||||
public interface IIdentifiableUserCommandService
|
||||
{
|
||||
void AddIdentifiableUserCommandFactory(string identifier, Func<IIdentifiableUserCommand> commandFactory);
|
||||
IIdentifiableUserCommand GetCommand(string identifier);
|
||||
IIdentifiableUserCommand? GetCommand(string identifier);
|
||||
IReadOnlyCollection<string> GetCommandIdentifiers();
|
||||
}
|
||||
@@ -9,8 +9,9 @@ public class IdentifiableUserCommandService : IIdentifiableUserCommandService
|
||||
public void AddIdentifiableUserCommandFactory(string identifier, Func<IIdentifiableUserCommand> commandFactory)
|
||||
=> _identifiableUserCommands.Add(identifier, commandFactory);
|
||||
|
||||
public IIdentifiableUserCommand GetCommand(string identifier)
|
||||
public IIdentifiableUserCommand? GetCommand(string identifier)
|
||||
{
|
||||
//TODO: refactor to not throw an exception
|
||||
if (!_identifiableUserCommands.ContainsKey(identifier))
|
||||
throw new IndexOutOfRangeException($"No command factory is registered for command {identifier}");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user