using System.ComponentModel; using DeclarativeProperty; using FileTime.App.Core.Models; using GeneralInputKey; using PropertyChanged.SourceGenerator; namespace FileTime.App.FuzzyPanel; public abstract partial class FuzzyPanelViewModel : IFuzzyPanelViewModel where TItem : class { private readonly Func _itemEquality; private string _searchText = String.Empty; [Notify(set: Setter.Protected)] private IDeclarativeProperty _showWindow; [Notify(set: Setter.Protected)] private List _filteredMatches; [Notify(set: Setter.Protected)] private TItem? _selectedItem; protected FuzzyPanelViewModel(Func? itemEquality = null) { _itemEquality = itemEquality ?? ((a, b) => a == b); } public string SearchText { get => _searchText; set { if (_searchText == value) return; _searchText = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(SearchText))); UpdateFilteredMatchesInternal(); } } private void UpdateFilteredMatchesInternal() { UpdateFilteredMatches(); if (SelectedItem != null && FilteredMatches.Contains(SelectedItem)) return; SelectedItem = FilteredMatches.Count > 0 ? FilteredMatches[0] : null; } public abstract void UpdateFilteredMatches(); public virtual Task HandleKeyDown(GeneralKeyEventArgs keyEventArgs) { if (keyEventArgs.Key == Keys.Down) { var nextItem = SelectedItem is null ? FilteredMatches.FirstOrDefault() : FilteredMatches.SkipWhile(i => !_itemEquality(i, SelectedItem)).Skip(1).FirstOrDefault(); if (nextItem is not null) { keyEventArgs.Handled = true; SelectedItem = nextItem; } return Task.FromResult(true); } else if (keyEventArgs.Key == Keys.Up) { var previousItem = SelectedItem is null ? FilteredMatches.LastOrDefault() : FilteredMatches.TakeWhile(i => !_itemEquality(i, SelectedItem)).LastOrDefault(); if (previousItem is not null) { keyEventArgs.Handled = true; SelectedItem = previousItem; } return Task.FromResult(true); } return Task.FromResult(false); } }