Merge pull request #3553 from Flow-Launcher/fix_result_clearing_nonquery

Fix result clearing for non-query calls and home page + history results page toggling
This commit is contained in:
Jeremy Wu 2025-05-19 18:35:53 +10:00 committed by GitHub
commit 3abb2f0f52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 74 additions and 27 deletions

View file

@ -173,7 +173,20 @@ namespace Flow.Launcher.Infrastructure.UserSettings
} }
} }
public bool ShowHistoryResultsForHomePage { get; set; } = false; private bool _showHistoryResultsForHomePage = false;
public bool ShowHistoryResultsForHomePage
{
get => _showHistoryResultsForHomePage;
set
{
if (_showHistoryResultsForHomePage != value)
{
_showHistoryResultsForHomePage = value;
OnPropertyChanged();
}
}
}
public int MaxHistoryResultsToShowForHomePage { get; set; } = 5; public int MaxHistoryResultsToShowForHomePage { get; set; } = 5;
public int CustomExplorerIndex { get; set; } = 0; public int CustomExplorerIndex { get; set; } = 0;
@ -395,29 +408,29 @@ namespace Flow.Launcher.Infrastructure.UserSettings
var list = FixedHotkeys(); var list = FixedHotkeys();
// Customizeable hotkeys // Customizeable hotkeys
if(!string.IsNullOrEmpty(Hotkey)) if (!string.IsNullOrEmpty(Hotkey))
list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = "")); list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = ""));
if(!string.IsNullOrEmpty(PreviewHotkey)) if (!string.IsNullOrEmpty(PreviewHotkey))
list.Add(new(PreviewHotkey, "previewHotkey", () => PreviewHotkey = "")); list.Add(new(PreviewHotkey, "previewHotkey", () => PreviewHotkey = ""));
if(!string.IsNullOrEmpty(AutoCompleteHotkey)) if (!string.IsNullOrEmpty(AutoCompleteHotkey))
list.Add(new(AutoCompleteHotkey, "autoCompleteHotkey", () => AutoCompleteHotkey = "")); list.Add(new(AutoCompleteHotkey, "autoCompleteHotkey", () => AutoCompleteHotkey = ""));
if(!string.IsNullOrEmpty(AutoCompleteHotkey2)) if (!string.IsNullOrEmpty(AutoCompleteHotkey2))
list.Add(new(AutoCompleteHotkey2, "autoCompleteHotkey", () => AutoCompleteHotkey2 = "")); list.Add(new(AutoCompleteHotkey2, "autoCompleteHotkey", () => AutoCompleteHotkey2 = ""));
if(!string.IsNullOrEmpty(SelectNextItemHotkey)) if (!string.IsNullOrEmpty(SelectNextItemHotkey))
list.Add(new(SelectNextItemHotkey, "SelectNextItemHotkey", () => SelectNextItemHotkey = "")); list.Add(new(SelectNextItemHotkey, "SelectNextItemHotkey", () => SelectNextItemHotkey = ""));
if(!string.IsNullOrEmpty(SelectNextItemHotkey2)) if (!string.IsNullOrEmpty(SelectNextItemHotkey2))
list.Add(new(SelectNextItemHotkey2, "SelectNextItemHotkey", () => SelectNextItemHotkey2 = "")); list.Add(new(SelectNextItemHotkey2, "SelectNextItemHotkey", () => SelectNextItemHotkey2 = ""));
if(!string.IsNullOrEmpty(SelectPrevItemHotkey)) if (!string.IsNullOrEmpty(SelectPrevItemHotkey))
list.Add(new(SelectPrevItemHotkey, "SelectPrevItemHotkey", () => SelectPrevItemHotkey = "")); list.Add(new(SelectPrevItemHotkey, "SelectPrevItemHotkey", () => SelectPrevItemHotkey = ""));
if(!string.IsNullOrEmpty(SelectPrevItemHotkey2)) if (!string.IsNullOrEmpty(SelectPrevItemHotkey2))
list.Add(new(SelectPrevItemHotkey2, "SelectPrevItemHotkey", () => SelectPrevItemHotkey2 = "")); list.Add(new(SelectPrevItemHotkey2, "SelectPrevItemHotkey", () => SelectPrevItemHotkey2 = ""));
if(!string.IsNullOrEmpty(SettingWindowHotkey)) if (!string.IsNullOrEmpty(SettingWindowHotkey))
list.Add(new(SettingWindowHotkey, "SettingWindowHotkey", () => SettingWindowHotkey = "")); list.Add(new(SettingWindowHotkey, "SettingWindowHotkey", () => SettingWindowHotkey = ""));
if(!string.IsNullOrEmpty(OpenContextMenuHotkey)) if (!string.IsNullOrEmpty(OpenContextMenuHotkey))
list.Add(new(OpenContextMenuHotkey, "OpenContextMenuHotkey", () => OpenContextMenuHotkey = "")); list.Add(new(OpenContextMenuHotkey, "OpenContextMenuHotkey", () => OpenContextMenuHotkey = ""));
if(!string.IsNullOrEmpty(SelectNextPageHotkey)) if (!string.IsNullOrEmpty(SelectNextPageHotkey))
list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = "")); list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = ""));
if(!string.IsNullOrEmpty(SelectPrevPageHotkey)) if (!string.IsNullOrEmpty(SelectPrevPageHotkey))
list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = "")); list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = ""));
if (!string.IsNullOrEmpty(CycleHistoryUpHotkey)) if (!string.IsNullOrEmpty(CycleHistoryUpHotkey))
list.Add(new(CycleHistoryUpHotkey, "CycleHistoryUpHotkey", () => CycleHistoryUpHotkey = "")); list.Add(new(CycleHistoryUpHotkey, "CycleHistoryUpHotkey", () => CycleHistoryUpHotkey = ""));

View file

@ -113,7 +113,7 @@ namespace Flow.Launcher
Win32Helper.DisableControlBox(this); Win32Helper.DisableControlBox(this);
} }
private async void OnLoaded(object sender, RoutedEventArgs _) private void OnLoaded(object sender, RoutedEventArgs _)
{ {
// Check first launch // Check first launch
if (_settings.FirstLaunch) if (_settings.FirstLaunch)
@ -283,6 +283,7 @@ namespace Flow.Launcher
InitializeContextMenu(); InitializeContextMenu();
break; break;
case nameof(Settings.ShowHomePage): case nameof(Settings.ShowHomePage):
case nameof(Settings.ShowHistoryResultsForHomePage):
if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText)) if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText))
{ {
_viewModel.QueryResults(); _viewModel.QueryResults();

View file

@ -265,7 +265,7 @@ namespace Flow.Launcher.ViewModel
if (token.IsCancellationRequested) return; if (token.IsCancellationRequested) return;
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query,
token))) token)))
{ {
App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); App.API.LogError(ClassName, "Unable to add item to Result Update Queue");
@ -791,7 +791,7 @@ namespace Flow.Launcher.ViewModel
public Visibility ProgressBarVisibility { get; set; } public Visibility ProgressBarVisibility { get; set; }
public Visibility MainWindowVisibility { get; set; } public Visibility MainWindowVisibility { get; set; }
// This is to be used for determining the visibility status of the main window instead of MainWindowVisibility // This is to be used for determining the visibility status of the main window instead of MainWindowVisibility
// because it is more accurate and reliable representation than using Visibility as a condition check // because it is more accurate and reliable representation than using Visibility as a condition check
public bool MainWindowVisibilityStatus { get; set; } = true; public bool MainWindowVisibilityStatus { get; set; } = true;
@ -1068,7 +1068,7 @@ namespace Flow.Launcher.ViewModel
path = QueryResultsPreviewed() ? Results.SelectedItem?.Result?.Preview.FilePath : string.Empty; path = QueryResultsPreviewed() ? Results.SelectedItem?.Result?.Preview.FilePath : string.Empty;
return !string.IsNullOrEmpty(path); return !string.IsNullOrEmpty(path);
} }
private bool QueryResultsPreviewed() private bool QueryResultsPreviewed()
{ {
var previewed = PreviewSelectedItem == Results.SelectedItem; var previewed = PreviewSelectedItem == Results.SelectedItem;
@ -1278,8 +1278,6 @@ namespace Flow.Launcher.ViewModel
// Update the query's IsReQuery property to true if this is a re-query // Update the query's IsReQuery property to true if this is a re-query
query.IsReQuery = isReQuery; query.IsReQuery = isReQuery;
ICollection<PluginPair> plugins = Array.Empty<PluginPair>(); ICollection<PluginPair> plugins = Array.Empty<PluginPair>();
if (currentIsHomeQuery) if (currentIsHomeQuery)
{ {
@ -1310,8 +1308,7 @@ namespace Flow.Launcher.ViewModel
} }
} }
var validPluginNames = plugins.Select(x => $"<{x.Metadata.Name}>"); App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}");
App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", validPluginNames)}");
// Do not wait for performance improvement // Do not wait for performance improvement
/*if (string.IsNullOrEmpty(query.ActionKeyword)) /*if (string.IsNullOrEmpty(query.ActionKeyword))
@ -1339,6 +1336,12 @@ namespace Flow.Launcher.ViewModel
Task[] tasks; Task[] tasks;
if (currentIsHomeQuery) if (currentIsHomeQuery)
{ {
if (ShouldClearExistingResultsForNonQuery(plugins))
{
Results.Clear();
App.API.LogDebug(ClassName, $"Existing results are cleared for non-query");
}
tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch
{ {
false => QueryTaskAsync(plugin, currentCancellationToken), false => QueryTaskAsync(plugin, currentCancellationToken),
@ -1430,7 +1433,7 @@ namespace Flow.Launcher.ViewModel
App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>"); App.API.LogDebug(ClassName, $"Update results for plugin <{plugin.Metadata.Name}>");
// Indicate if to clear existing results so to show only ones from plugins with action keywords // Indicate if to clear existing results so to show only ones from plugins with action keywords
var shouldClearExistingResults = ShouldClearExistingResults(query, currentIsHomeQuery); var shouldClearExistingResults = ShouldClearExistingResultsForQuery(query, currentIsHomeQuery);
_lastQuery = query; _lastQuery = query;
_previousIsHomeQuery = currentIsHomeQuery; _previousIsHomeQuery = currentIsHomeQuery;
@ -1452,8 +1455,13 @@ namespace Flow.Launcher.ViewModel
App.API.LogDebug(ClassName, $"Update results for history"); App.API.LogDebug(ClassName, $"Update results for history");
// Indicate if to clear existing results so to show only ones from plugins with action keywords
var shouldClearExistingResults = ShouldClearExistingResultsForQuery(query, currentIsHomeQuery);
_lastQuery = query;
_previousIsHomeQuery = currentIsHomeQuery;
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, _historyMetadata, query, if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, _historyMetadata, query,
token))) token, reSelect, shouldClearExistingResults)))
{ {
App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); App.API.LogError(ClassName, "Unable to add item to Result Update Queue");
} }
@ -1539,7 +1547,9 @@ namespace Flow.Launcher.ViewModel
/// <summary> /// <summary>
/// Determines whether the existing search results should be cleared based on the current query and the previous query type. /// Determines whether the existing search results should be cleared based on the current query and the previous query type.
/// This is needed because of the design that treats plugins with action keywords and global action keywords separately. Results are gathered /// This is used to indicate to QueryTaskAsync or QueryHistoryTask whether to clear results. If both QueryTaskAsync and QueryHistoryTask
/// are not called then use ShouldClearExistingResultsForNonQuery instead.
/// This method needed because of the design that treats plugins with action keywords and global action keywords separately. Results are gathered
/// either from plugins with matching action keywords or global action keyword, but not both. So when the current results are from plugins /// either from plugins with matching action keywords or global action keyword, but not both. So when the current results are from plugins
/// with a matching action keyword and a new result set comes from a new query with the global action keyword, the existing results need to be cleared, /// with a matching action keyword and a new result set comes from a new query with the global action keyword, the existing results need to be cleared,
/// and vice versa. The same applies to home page query results. /// and vice versa. The same applies to home page query results.
@ -1550,19 +1560,39 @@ namespace Flow.Launcher.ViewModel
/// <param name="query">The current query.</param> /// <param name="query">The current query.</param>
/// <param name="currentIsHomeQuery">A flag indicating if the current query is a home query.</param> /// <param name="currentIsHomeQuery">A flag indicating if the current query is a home query.</param>
/// <returns>True if the existing results should be cleared, false otherwise.</returns> /// <returns>True if the existing results should be cleared, false otherwise.</returns>
private bool ShouldClearExistingResults(Query query, bool currentIsHomeQuery) private bool ShouldClearExistingResultsForQuery(Query query, bool currentIsHomeQuery)
{ {
// If previous or current results are from home query, we need to clear them // If previous or current results are from home query, we need to clear them
if (_previousIsHomeQuery || currentIsHomeQuery) if (_previousIsHomeQuery || currentIsHomeQuery)
{ {
App.API.LogDebug(ClassName, $"Cleared old results"); App.API.LogDebug(ClassName, $"Existing results should be cleared for query");
return true; return true;
} }
// If the last and current query are not home query type, we need to check the action keyword // If the last and current query are not home query type, we need to check the action keyword
if (_lastQuery?.ActionKeyword != query?.ActionKeyword) if (_lastQuery?.ActionKeyword != query?.ActionKeyword)
{ {
App.API.LogDebug(ClassName, $"Cleared old results"); App.API.LogDebug(ClassName, $"Existing results should be cleared for query");
return true;
}
return false;
}
/// <summary>
/// Determines whether existing results should be cleared for non-query calls.
/// A non-query call is where QueryTaskAsync and QueryHistoryTask methods are both not called.
/// QueryTaskAsync and QueryHistoryTask both handle result updating (clearing if required) so directly calling
/// Results.Clear() is not required. However when both are not called, we need to directly clear results and this
/// method determines on the condition when clear results should happen.
/// </summary>
/// <param name="plugins">The collection of plugins to check.</param>
/// <returns>True if existing results should be cleared, false otherwise.</returns>
private bool ShouldClearExistingResultsForNonQuery(ICollection<PluginPair> plugins)
{
if (!Settings.ShowHistoryResultsForHomePage && (plugins.Count == 0 || plugins.All(x => x.Metadata.HomeDisabled == true)))
{
App.API.LogDebug(ClassName, $"Existing results should be cleared for non-query");
return true; return true;
} }

View file

@ -245,7 +245,10 @@ namespace Flow.Launcher.ViewModel
var newResults = resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings)); var newResults = resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings));
if (resultsForUpdates.Any(x => x.shouldClearExistingResults)) if (resultsForUpdates.Any(x => x.shouldClearExistingResults))
{
App.API.LogDebug("NewResults", $"Existing results are cleared for query");
return newResults.OrderByDescending(rv => rv.Result.Score).ToList(); return newResults.OrderByDescending(rv => rv.Result.Score).ToList();
}
return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID))
.Concat(newResults) .Concat(newResults)