From 4d5d6c26b038be4b2919dcb678b581fd9ebf3dfd Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sat, 10 May 2025 21:47:14 +1000 Subject: [PATCH 1/2] fix clearing of results logic & minor adjustment to results update --- Flow.Launcher/ViewModel/MainViewModel.cs | 64 ++++++++++++--------- Flow.Launcher/ViewModel/ResultsForUpdate.cs | 3 +- Flow.Launcher/ViewModel/ResultsViewModel.cs | 11 +++- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c0b74dc6870..d2aa5c932b4 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -33,7 +33,7 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private bool _isQueryRunning; private Query _lastQuery; - private bool _lastIsHomeQuery; + private bool _previousIsHomeQuery; private string _queryTextBeforeLeaveResults; private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results @@ -1264,7 +1264,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and RawQuery <{query.RawQuery}>"); - var isHomeQuery = query.RawQuery == string.Empty; + var currentIsHomeQuery = query.RawQuery == string.Empty; _updateSource?.Dispose(); @@ -1284,14 +1284,10 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b // Update the query's IsReQuery property to true if this is a re-query query.IsReQuery = isReQuery; - // handle the exclusiveness of plugin using action keyword - RemoveOldQueryResults(query, isHomeQuery); - - _lastQuery = query; - _lastIsHomeQuery = isHomeQuery; + ICollection plugins = Array.Empty(); - if (isHomeQuery) + if (currentIsHomeQuery) { if (Settings.ShowHomePage) { @@ -1347,7 +1343,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b // plugins are ICollection, meaning LINQ will get the Count and preallocate Array Task[] tasks; - if (isHomeQuery) + if (currentIsHomeQuery) { tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch { @@ -1397,7 +1393,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) { App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>"); - if (searchDelay && !isHomeQuery) // Do not delay for home query + if (searchDelay && !currentIsHomeQuery) // Do not delay for home query { var searchDelayTime = plugin.Metadata.SearchDelayTime ?? Settings.SearchDelayTime; @@ -1410,7 +1406,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) // Task.Yield will force it to run in ThreadPool await Task.Yield(); - var results = isHomeQuery ? + var results = currentIsHomeQuery ? await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : await PluginManager.QueryForPluginAsync(plugin, query, token); @@ -1439,8 +1435,13 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : 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 + var clearExistingResultsRequired = RequireClearExistingResults(query, currentIsHomeQuery); + _lastQuery = query; + _previousIsHomeQuery = currentIsHomeQuery; + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, - token, reSelect))) + token, reSelect, clearExistingResultsRequired))) { App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } @@ -1542,25 +1543,36 @@ private async Task BuildQueryAsync(IEnumerable builtIn } } - private void RemoveOldQueryResults(Query query, bool isHomeQuery) + /// + /// 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 + /// 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, + /// and vice versa. The same applies to home page query results. + /// + /// There is no need to clear results from global action keyword if a new set of results comes along that is also from global action keywords. + /// This is because the removal of obsolete results is handled in ResultsViewModel.NewResults(ICollection). + /// + /// The current query. + /// A flag indicating if the current query is a home query. + /// True if the existing results should be cleared, false otherwise. + private bool RequireClearExistingResults(Query query, bool currentIsHomeQuery) { - // If last and current query are home query, we don't need to clear the results - if (_lastIsHomeQuery && isHomeQuery) + // If previous or current results are from home query, we need to clear them + if (_previousIsHomeQuery || currentIsHomeQuery) { - return; + App.API.LogDebug(ClassName, $"Cleared old results"); + return true; } - // If last or current query is home query, we need to clear the results - else if (_lastIsHomeQuery || isHomeQuery) - { - App.API.LogDebug(ClassName, $"Remove old results"); - Results.Clear(); - } - // If last and current query are not home query, we need to check action keyword - else if (_lastQuery?.ActionKeyword != query?.ActionKeyword) + + // If the last and current query are not home query type, we need to check the action keyword + if (_lastQuery?.ActionKeyword != query?.ActionKeyword) { - App.API.LogDebug(ClassName, $"Remove old results"); - Results.Clear(); + App.API.LogDebug(ClassName, $"Cleared old results"); + return true; } + + return false; } private Result ContextMenuTopMost(Result result) diff --git a/Flow.Launcher/ViewModel/ResultsForUpdate.cs b/Flow.Launcher/ViewModel/ResultsForUpdate.cs index bc0be0de81e..8c5db57f5fc 100644 --- a/Flow.Launcher/ViewModel/ResultsForUpdate.cs +++ b/Flow.Launcher/ViewModel/ResultsForUpdate.cs @@ -9,7 +9,8 @@ public record struct ResultsForUpdate( PluginMetadata Metadata, Query Query, CancellationToken Token, - bool ReSelectFirstResult = true) + bool ReSelectFirstResult = true, + bool requireClearExistingResults = false) { public string ID { get; } = Metadata.ID; } diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 02fb379fa07..770bda9c18d 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -232,10 +232,15 @@ private List NewResults(ICollection resultsFo if (!resultsForUpdates.Any()) return Results; + var newResults = resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings)); + + if (resultsForUpdates.Any(x => x.requireClearExistingResults)) + return newResults.OrderByDescending(rv => rv.Result.Score).ToList(); + return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID)) - .Concat(resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) - .OrderByDescending(rv => rv.Result.Score) - .ToList(); + .Concat(newResults) + .OrderByDescending(rv => rv.Result.Score) + .ToList(); } #endregion From 8bc497aee2a497964b3df71a4779f4b8024b0d71 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sat, 10 May 2025 22:26:12 +1000 Subject: [PATCH 2/2] fix naming --- Flow.Launcher/ViewModel/MainViewModel.cs | 6 +++--- Flow.Launcher/ViewModel/ResultsForUpdate.cs | 2 +- Flow.Launcher/ViewModel/ResultsViewModel.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d2aa5c932b4..0c299875fdf 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1436,12 +1436,12 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : 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 - var clearExistingResultsRequired = RequireClearExistingResults(query, currentIsHomeQuery); + var shouldClearExistingResults = ShouldClearExistingResults(query, currentIsHomeQuery); _lastQuery = query; _previousIsHomeQuery = currentIsHomeQuery; if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, - token, reSelect, clearExistingResultsRequired))) + token, reSelect, shouldClearExistingResults))) { App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } @@ -1556,7 +1556,7 @@ private async Task BuildQueryAsync(IEnumerable builtIn /// The current query. /// A flag indicating if the current query is a home query. /// True if the existing results should be cleared, false otherwise. - private bool RequireClearExistingResults(Query query, bool currentIsHomeQuery) + private bool ShouldClearExistingResults(Query query, bool currentIsHomeQuery) { // If previous or current results are from home query, we need to clear them if (_previousIsHomeQuery || currentIsHomeQuery) diff --git a/Flow.Launcher/ViewModel/ResultsForUpdate.cs b/Flow.Launcher/ViewModel/ResultsForUpdate.cs index 8c5db57f5fc..1563f85bae2 100644 --- a/Flow.Launcher/ViewModel/ResultsForUpdate.cs +++ b/Flow.Launcher/ViewModel/ResultsForUpdate.cs @@ -10,7 +10,7 @@ public record struct ResultsForUpdate( Query Query, CancellationToken Token, bool ReSelectFirstResult = true, - bool requireClearExistingResults = false) + bool shouldClearExistingResults = false) { public string ID { get; } = Metadata.ID; } diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 770bda9c18d..cd2736afa37 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -234,7 +234,7 @@ private List NewResults(ICollection resultsFo var newResults = resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings)); - if (resultsForUpdates.Any(x => x.requireClearExistingResults)) + if (resultsForUpdates.Any(x => x.shouldClearExistingResults)) return newResults.OrderByDescending(rv => rv.Result.Score).ToList(); return Results.Where(r => r?.Result != null && resultsForUpdates.All(u => u.ID != r.Result.PluginID))