Support search delay

This commit is contained in:
Jack251970 2025-03-15 21:58:55 +08:00
parent 4bb8bffb78
commit b1a46817f0
4 changed files with 130 additions and 51 deletions

View file

@ -275,6 +275,9 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public bool LeaveCmdOpen { get; set; } public bool LeaveCmdOpen { get; set; }
public bool HideWhenDeactivated { get; set; } = true; public bool HideWhenDeactivated { get; set; } = true;
public bool SearchQueryResultsWithDelay { get; set; } = false;
public int SearchInputDelay { get; set; } = 150;
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public SearchWindowScreens SearchWindowScreen { get; set; } = SearchWindowScreens.Cursor; public SearchWindowScreens SearchWindowScreen { get; set; } = SearchWindowScreens.Cursor;

View file

@ -104,6 +104,7 @@
<PackageReference Include="NHotkey.Wpf" Version="3.0.0" /> <PackageReference Include="NHotkey.Wpf" Version="3.0.0" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" /> <PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
<PackageReference Include="SemanticVersioning" Version="3.0.0" /> <PackageReference Include="SemanticVersioning" Version="3.0.0" />
<PackageReference Include="System.Reactive.Linq" Version="6.0.1" />
<PackageReference Include="TaskScheduler" Version="2.12.1" /> <PackageReference Include="TaskScheduler" Version="2.12.1" />
<PackageReference Include="VirtualizingWrapPanel" Version="2.1.1" /> <PackageReference Include="VirtualizingWrapPanel" Version="2.1.1" />
</ItemGroup> </ItemGroup>

View file

@ -5,7 +5,6 @@ using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Forms;
using Flow.Launcher.Core.Plugin; using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Core.Resource; using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper; using Flow.Launcher.Helper;
@ -27,6 +26,7 @@ using DataObject = System.Windows.DataObject;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Interop; using System.Windows.Interop;
using Windows.Win32; using Windows.Win32;
using System.Reactive.Linq;
namespace Flow.Launcher namespace Flow.Launcher
{ {
@ -68,6 +68,7 @@ namespace Flow.Launcher
var handle = new WindowInteropHelper(this).Handle; var handle = new WindowInteropHelper(this).Handle;
var win = HwndSource.FromHwnd(handle); var win = HwndSource.FromHwnd(handle);
win.AddHook(WndProc); win.AddHook(WndProc);
SetupSearchTextBoxReactiveness(_settings.SearchQueryResultsWithDelay);
}; };
} }
@ -204,63 +205,63 @@ namespace Flow.Launcher
switch (e.PropertyName) switch (e.PropertyName)
{ {
case nameof(MainViewModel.MainWindowVisibilityStatus): case nameof(MainViewModel.MainWindowVisibilityStatus):
{
Dispatcher.Invoke(() =>
{ {
if (_viewModel.MainWindowVisibilityStatus) Dispatcher.Invoke(() =>
{ {
if (_settings.UseSound) if (_viewModel.MainWindowVisibilityStatus)
{ {
SoundPlay(); if (_settings.UseSound)
} {
SoundPlay();
}
UpdatePosition(); UpdatePosition();
PreviewReset(); PreviewReset();
Activate(); Activate();
QueryTextBox.Focus(); QueryTextBox.Focus();
_settings.ActivateTimes++; _settings.ActivateTimes++;
if (!_viewModel.LastQuerySelected) if (!_viewModel.LastQuerySelected)
{
QueryTextBox.SelectAll();
_viewModel.LastQuerySelected = true;
}
if (_viewModel.ProgressBarVisibility == Visibility.Visible &&
isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false;
}
if (_settings.UseAnimation)
WindowAnimator();
}
else if (!isProgressBarStoryboardPaused)
{ {
QueryTextBox.SelectAll(); _progressBarStoryboard.Stop(ProgressBar);
_viewModel.LastQuerySelected = true; isProgressBarStoryboardPaused = true;
} }
});
if (_viewModel.ProgressBarVisibility == Visibility.Visible && break;
isProgressBarStoryboardPaused) }
case nameof(MainViewModel.ProgressBarVisibility):
{
Dispatcher.Invoke(() =>
{
if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
else if (_viewModel.MainWindowVisibilityStatus &&
isProgressBarStoryboardPaused)
{ {
_progressBarStoryboard.Begin(ProgressBar, true); _progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false; isProgressBarStoryboardPaused = false;
} }
});
if (_settings.UseAnimation) break;
WindowAnimator(); }
}
else if (!isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
});
break;
}
case nameof(MainViewModel.ProgressBarVisibility):
{
Dispatcher.Invoke(() =>
{
if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
else if (_viewModel.MainWindowVisibilityStatus &&
isProgressBarStoryboardPaused)
{
_progressBarStoryboard.Begin(ProgressBar, true);
isProgressBarStoryboardPaused = false;
}
});
break;
}
case nameof(MainViewModel.QueryTextCursorMovedToEnd): case nameof(MainViewModel.QueryTextCursorMovedToEnd):
if (_viewModel.QueryTextCursorMovedToEnd) if (_viewModel.QueryTextCursorMovedToEnd)
{ {
@ -415,10 +416,10 @@ namespace Flow.Launcher
{ {
switch (e.Button) switch (e.Button)
{ {
case MouseButtons.Left: case System.Windows.Forms.MouseButtons.Left:
_viewModel.ToggleFlowLauncher(); _viewModel.ToggleFlowLauncher();
break; break;
case MouseButtons.Right: case System.Windows.Forms.MouseButtons.Right:
contextMenu.IsOpen = true; contextMenu.IsOpen = true;
// Get context menu handle and bring it to the foreground // Get context menu handle and bring it to the foreground
@ -857,5 +858,78 @@ namespace Flow.Launcher
be.UpdateSource(); be.UpdateSource();
} }
} }
#region Search Delay
// Edited from: https://github.com/microsoft/PowerToys
private IDisposable _reactiveSubscription;
private void SetupSearchTextBoxReactiveness(bool showResultsWithDelay)
{
if (_reactiveSubscription != null)
{
_reactiveSubscription.Dispose();
_reactiveSubscription = null;
}
QueryTextBox.TextChanged -= QueryTextBox_TextChanged;
if (showResultsWithDelay)
{
_reactiveSubscription = Observable.FromEventPattern<TextChangedEventHandler, TextChangedEventArgs>(
conversion => (sender, eventArg) => conversion(sender, eventArg),
add => QueryTextBox.TextChanged += add,
remove => QueryTextBox.TextChanged -= remove)
.Do(@event => ClearAutoCompleteText((TextBox)@event.Sender))
.Throttle(TimeSpan.FromMilliseconds(_settings.SearchInputDelay))
.Do(@event => Dispatcher.Invoke(() => PerformSearchQuery((TextBox)@event.Sender)))
.Subscribe();
}
else
{
QueryTextBox.TextChanged += QueryTextBox_TextChanged;
}
}
private void QueryTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
var textBox = (TextBox)sender;
ClearAutoCompleteText(textBox);
PerformSearchQuery(textBox);
}
private void ClearAutoCompleteText(TextBox textBox)
{
var text = textBox.Text;
var autoCompleteText = QueryTextSuggestionBox.Text;
if (ShouldAutoCompleteTextBeEmpty(text, autoCompleteText))
{
QueryTextSuggestionBox.Text = string.Empty;
}
}
private static bool ShouldAutoCompleteTextBeEmpty(string queryText, string autoCompleteText)
{
if (string.IsNullOrEmpty(autoCompleteText))
{
return false;
}
else
{
// Using Ordinal this is internal
return string.IsNullOrEmpty(queryText) || !autoCompleteText.StartsWith(queryText, StringComparison.Ordinal);
}
}
private void PerformSearchQuery(TextBox textBox)
{
var text = textBox.Text;
_viewModel.QueryText = text;
_viewModel.Query();
}
#endregion
} }
} }

View file

@ -569,7 +569,6 @@ namespace Flow.Launcher.ViewModel
{ {
_queryText = value; _queryText = value;
OnPropertyChanged(); OnPropertyChanged();
Query();
} }
} }
@ -631,6 +630,7 @@ namespace Flow.Launcher.ViewModel
{ {
// re-query is done in QueryText's setter method // re-query is done in QueryText's setter method
QueryText = queryText; QueryText = queryText;
Query();
// set to false so the subsequent set true triggers // set to false so the subsequent set true triggers
// PropertyChanged and MoveQueryTextToEnd is called // PropertyChanged and MoveQueryTextToEnd is called
QueryTextCursorMovedToEnd = false; QueryTextCursorMovedToEnd = false;
@ -695,6 +695,7 @@ namespace Flow.Launcher.ViewModel
else else
{ {
QueryText = string.Empty; QueryText = string.Empty;
Query();
} }
} }