mirror of
https://github.com/4sval/FModel.git
synced 2026-08-06 03:03:04 -05:00
Add debounced package search
This commit is contained in:
parent
07ede1555e
commit
990c38bbcb
|
|
@ -68,6 +68,10 @@ public class SearchViewModel : ViewModel
|
|||
private set => SetProperty(ref _searchResults, value);
|
||||
}
|
||||
private ListCollectionView _searchResultsView;
|
||||
private string[] _filters = [];
|
||||
private Regex _filterRegex;
|
||||
private bool _isRegexValid = true;
|
||||
|
||||
public ListCollectionView SearchResultsView
|
||||
{
|
||||
get
|
||||
|
|
@ -75,9 +79,10 @@ public class SearchViewModel : ViewModel
|
|||
if (_searchResultsView != null)
|
||||
return _searchResultsView;
|
||||
|
||||
PrepareFilter();
|
||||
_searchResultsView = new ListCollectionView(SearchResults)
|
||||
{
|
||||
Filter = e => ItemFilter(e, FilterText.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries)),
|
||||
Filter = ItemFilter,
|
||||
};
|
||||
ResultsCount = _searchResultsView.Count;
|
||||
return _searchResultsView;
|
||||
|
|
@ -91,6 +96,7 @@ public class SearchViewModel : ViewModel
|
|||
|
||||
public void RefreshFilter()
|
||||
{
|
||||
PrepareFilter();
|
||||
SearchResultsView.Refresh();
|
||||
ResultsCount = SearchResultsView.Count;
|
||||
}
|
||||
|
|
@ -148,16 +154,38 @@ public class SearchViewModel : ViewModel
|
|||
ChangeCollection(sorted, RefFile);
|
||||
}
|
||||
|
||||
private bool ItemFilter(object item, IEnumerable<string> filters)
|
||||
private void PrepareFilter()
|
||||
{
|
||||
_filters = FilterText.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
_filterRegex = null;
|
||||
_isRegexValid = true;
|
||||
|
||||
if (!HasRegexEnabled)
|
||||
return;
|
||||
|
||||
var options = RegexOptions.Compiled;
|
||||
if (!HasMatchCaseEnabled)
|
||||
options |= RegexOptions.IgnoreCase;
|
||||
|
||||
try
|
||||
{
|
||||
_filterRegex = new Regex(FilterText, options);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
_isRegexValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ItemFilter(object item)
|
||||
{
|
||||
if (item is not GameFile entry)
|
||||
return true;
|
||||
|
||||
if (!HasRegexEnabled)
|
||||
return filters.All(x => entry.Path.Contains(x, HasMatchCaseEnabled ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase));
|
||||
return _filters.All(x => entry.Path.Contains(x,
|
||||
HasMatchCaseEnabled ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
var o = RegexOptions.None;
|
||||
if (!HasMatchCaseEnabled) o |= RegexOptions.IgnoreCase;
|
||||
return new Regex(FilterText, o).Match(entry.Path).Success;
|
||||
return _isRegexValid && _filterRegex.IsMatch(entry.Path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
xmlns:adonisExtensions="clr-namespace:AdonisUI.Extensions;assembly=AdonisUI"
|
||||
WindowStartupLocation="CenterScreen" ResizeMode="CanResize" ShowInTaskbar="True"
|
||||
IconVisibility="Collapsed" KeyDown="OnWindowKeyDown" StateChanged="OnStateChanged"
|
||||
Closed="OnWindowClosed"
|
||||
Height="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenHeight}, Converter={converters:RatioConverter}, ConverterParameter='0.75'}"
|
||||
Width="{Binding Source={x:Static SystemParameters.MaximizedPrimaryScreenWidth}, Converter={converters:RatioConverter}, ConverterParameter='0.65'}">
|
||||
<adonisControls:AdonisWindow.Style>
|
||||
|
|
@ -38,14 +39,15 @@
|
|||
</Canvas>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
<TextBox x:Name="SearchTextBox" Grid.Column="0" Grid.ColumnSpan="2" Padding="25 0 0 0" AcceptsTab="False" AcceptsReturn="False">
|
||||
<TextBox x:Name="SearchTextBox" Grid.Column="0" Grid.ColumnSpan="2" Padding="25 0 0 0" AcceptsTab="False" AcceptsReturn="False"
|
||||
TextChanged="OnSearchTextChanged">
|
||||
<TextBox.Style>
|
||||
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
|
||||
<Setter Property="Text" Value="{Binding SearchTab.FilterText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Write your pattern and press enter..." />
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Search package paths..." />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding SearchTab.HasRegexEnabled}" Value="True">
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Write your regex pattern and press enter..." />
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Search package paths with a regex..." />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
|
@ -402,14 +404,15 @@
|
|||
</Canvas>
|
||||
</Viewbox>
|
||||
</Grid>
|
||||
<TextBox x:Name="RefSearchTextBox" Grid.Column="0" Grid.ColumnSpan="2" Padding="25 0 0 0" AcceptsTab="False" AcceptsReturn="False">
|
||||
<TextBox x:Name="RefSearchTextBox" Grid.Column="0" Grid.ColumnSpan="2" Padding="25 0 0 0" AcceptsTab="False" AcceptsReturn="False"
|
||||
TextChanged="OnSearchTextChanged">
|
||||
<TextBox.Style>
|
||||
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
|
||||
<Setter Property="Text" Value="{Binding RefTab.FilterText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Write your pattern and press enter..." />
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Search package paths..." />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding RefTab.HasRegexEnabled}" Value="True">
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Write your regex pattern and press enter..." />
|
||||
<Setter Property="adonisExtensions:WatermarkExtension.Watermark" Value="Search package paths with a regex..." />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System.Threading.Tasks;
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using CUE4Parse.FileProvider.Objects;
|
||||
using FModel.Services;
|
||||
using FModel.ViewModels;
|
||||
|
|
@ -19,15 +20,22 @@ public enum ESearchViewTab
|
|||
|
||||
public partial class SearchView
|
||||
{
|
||||
private static readonly TimeSpan AutoSearchDelay = TimeSpan.FromMilliseconds(500);
|
||||
|
||||
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
|
||||
private ApplicationViewModel _applicationView => ApplicationService.ApplicationView;
|
||||
private SearchViewModel _searchViewModel => _applicationView.CUE4Parse.SearchVm;
|
||||
private SearchViewModel _refViewModel => _applicationView.CUE4Parse.RefVm;
|
||||
|
||||
private ESearchViewTab _currentTab = ESearchViewTab.SearchView;
|
||||
private readonly DispatcherTimer _autoSearchTimer;
|
||||
private SearchViewModel _pendingAutoSearch;
|
||||
|
||||
public SearchView()
|
||||
{
|
||||
_autoSearchTimer = new DispatcherTimer { Interval = AutoSearchDelay };
|
||||
_autoSearchTimer.Tick += OnAutoSearchTimerTick;
|
||||
|
||||
DataContext = new
|
||||
{
|
||||
mainApplication = _applicationView,
|
||||
|
|
@ -95,9 +103,30 @@ public partial class SearchView
|
|||
if (viewModel == null)
|
||||
return;
|
||||
viewModel.FilterText = string.Empty;
|
||||
CancelAutoSearch();
|
||||
viewModel.RefreshFilter();
|
||||
}
|
||||
|
||||
private void OnSearchTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
_pendingAutoSearch = ReferenceEquals(sender, RefSearchTextBox) ? _refViewModel : _searchViewModel;
|
||||
_autoSearchTimer.Stop();
|
||||
_autoSearchTimer.Start();
|
||||
}
|
||||
|
||||
private void OnAutoSearchTimerTick(object sender, EventArgs e)
|
||||
{
|
||||
var viewModel = _pendingAutoSearch;
|
||||
CancelAutoSearch();
|
||||
viewModel?.RefreshFilter();
|
||||
}
|
||||
|
||||
private void CancelAutoSearch()
|
||||
{
|
||||
_autoSearchTimer.Stop();
|
||||
_pendingAutoSearch = null;
|
||||
}
|
||||
|
||||
private SearchViewModel CurrentViewModel => _currentTab switch
|
||||
{
|
||||
ESearchViewTab.SearchView => _applicationView.CUE4Parse.SearchVm,
|
||||
|
|
@ -187,9 +216,17 @@ public partial class SearchView
|
|||
{
|
||||
if (e.Key != Key.Enter)
|
||||
return;
|
||||
|
||||
CancelAutoSearch();
|
||||
CurrentViewModel?.RefreshFilter();
|
||||
}
|
||||
|
||||
private void OnWindowClosed(object sender, EventArgs e)
|
||||
{
|
||||
CancelAutoSearch();
|
||||
_autoSearchTimer.Tick -= OnAutoSearchTimerTick;
|
||||
}
|
||||
|
||||
private void OnStateChanged(object sender, EventArgs e)
|
||||
{
|
||||
switch (WindowState)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user