From e0721aae1464ba54a2c8fb2591cb7fd15660bc61 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 29 Mar 2025 22:03:30 +0800 Subject: [PATCH 01/31] Add new interfaces --- .../Interfaces/IAsyncEmptyQuery.cs | 23 +++++++++++++++ .../Interfaces/IEmptyQuery.cs | 28 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs create mode 100644 Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs diff --git a/Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs b/Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs new file mode 100644 index 00000000000..a18f0848d8d --- /dev/null +++ b/Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Flow.Launcher.Plugin +{ + /// + /// Asynchronous Query Model for Flow Launcher When Query Text is Empty + /// + public interface IAsyncEmptyQuery + { + /// + /// Asynchronous Querying When Query Text is Empty + /// + /// + /// If the Querying method requires high IO transmission + /// or performing CPU intense jobs (performing better with cancellation), please use this IAsyncEmptyQuery interface + /// + /// Cancel when querying job is obsolete + /// + Task> EmptyQueryAsync(CancellationToken token); + } +} diff --git a/Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs b/Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs new file mode 100644 index 00000000000..4ebdcf1fdcb --- /dev/null +++ b/Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Flow.Launcher.Plugin +{ + /// + /// Synchronous Query Model for Flow Launcher When Query Text is Empty + /// + /// If the Querying method requires high IO transmission + /// or performaing CPU intense jobs (performing better with cancellation), please try the IAsyncEmptyQuery interface + /// + /// + public interface IEmptyQuery : IAsyncEmptyQuery + { + /// + /// Querying When Query Text is Empty + /// + /// This method will be called within a Task.Run, + /// so please avoid synchrously wait for long. + /// + /// + /// + List EmptyQuery(); + + Task> IAsyncEmptyQuery.EmptyQueryAsync(CancellationToken token) => Task.Run(EmptyQuery); + } +} From aa0f9b2e73c550964475f4b0e2454c3c5728ecb7 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 08:58:40 +0800 Subject: [PATCH 02/31] Update name --- .../{IAsyncEmptyQuery.cs => IAsyncHomeQuery.cs} | 6 +++--- .../Interfaces/{IEmptyQuery.cs => IHomeQuery.cs} | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) rename Flow.Launcher.Plugin/Interfaces/{IAsyncEmptyQuery.cs => IAsyncHomeQuery.cs} (79%) rename Flow.Launcher.Plugin/Interfaces/{IEmptyQuery.cs => IHomeQuery.cs} (72%) diff --git a/Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs b/Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs similarity index 79% rename from Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs rename to Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs index a18f0848d8d..f7a820f18c6 100644 --- a/Flow.Launcher.Plugin/Interfaces/IAsyncEmptyQuery.cs +++ b/Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs @@ -7,17 +7,17 @@ namespace Flow.Launcher.Plugin /// /// Asynchronous Query Model for Flow Launcher When Query Text is Empty /// - public interface IAsyncEmptyQuery + public interface IAsyncHomeQuery { /// /// Asynchronous Querying When Query Text is Empty /// /// /// If the Querying method requires high IO transmission - /// or performing CPU intense jobs (performing better with cancellation), please use this IAsyncEmptyQuery interface + /// or performing CPU intense jobs (performing better with cancellation), please use this IAsyncHomeQuery interface /// /// Cancel when querying job is obsolete /// - Task> EmptyQueryAsync(CancellationToken token); + Task> HomeQueryAsync(CancellationToken token); } } diff --git a/Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs b/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs similarity index 72% rename from Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs rename to Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs index 4ebdcf1fdcb..f3c9cfcad97 100644 --- a/Flow.Launcher.Plugin/Interfaces/IEmptyQuery.cs +++ b/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs @@ -8,10 +8,10 @@ namespace Flow.Launcher.Plugin /// Synchronous Query Model for Flow Launcher When Query Text is Empty /// /// If the Querying method requires high IO transmission - /// or performaing CPU intense jobs (performing better with cancellation), please try the IAsyncEmptyQuery interface + /// or performaing CPU intense jobs (performing better with cancellation), please try the IAsyncHomeQuery interface /// /// - public interface IEmptyQuery : IAsyncEmptyQuery + public interface IHomeQuery : IAsyncHomeQuery { /// /// Querying When Query Text is Empty @@ -21,8 +21,8 @@ public interface IEmptyQuery : IAsyncEmptyQuery /// /// /// - List EmptyQuery(); + List HomeQuery(); - Task> IAsyncEmptyQuery.EmptyQueryAsync(CancellationToken token) => Task.Run(EmptyQuery); + Task> IAsyncHomeQuery.HomeQueryAsync(CancellationToken token) => Task.Run(HomeQuery); } } From 3089928599fca94487b21dbeff5fa35609e43463 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 16:31:49 +0800 Subject: [PATCH 03/31] Support home query interface --- .../Main.cs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Main.cs index 05e8d960fb0..48717816b0d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Main.cs @@ -3,21 +3,33 @@ namespace Flow.Launcher.Plugin.PluginIndicator { - public class Main : IPlugin, IPluginI18n + public class Main : IPlugin, IPluginI18n, IHomeQuery { internal PluginInitContext Context { get; private set; } public List Query(Query query) + { + return QueryResults(query); + } + + public List HomeQuery() + { + return QueryResults(); + } + + private List QueryResults(Query query = null) { var nonGlobalPlugins = GetNonGlobalPlugins(); + var querySearch = query?.Search ?? string.Empty; + var results = from keyword in nonGlobalPlugins.Keys let plugin = nonGlobalPlugins[keyword].Metadata - let keywordSearchResult = Context.API.FuzzySearch(query.Search, keyword) - let searchResult = keywordSearchResult.IsSearchPrecisionScoreMet() ? keywordSearchResult : Context.API.FuzzySearch(query.Search, plugin.Name) + let keywordSearchResult = Context.API.FuzzySearch(querySearch, keyword) + let searchResult = keywordSearchResult.IsSearchPrecisionScoreMet() ? keywordSearchResult : Context.API.FuzzySearch(querySearch, plugin.Name) let score = searchResult.Score where (searchResult.IsSearchPrecisionScoreMet() - || string.IsNullOrEmpty(query.Search)) // To list all available action keywords + || string.IsNullOrEmpty(querySearch)) // To list all available action keywords && !plugin.Disabled select new Result { From 0f09fea30b28526d72088e9c6603dfacf614e725 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 16:32:07 +0800 Subject: [PATCH 04/31] Make async home query to be feature interface --- Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs b/Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs index f7a820f18c6..78d6454ae5f 100644 --- a/Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs +++ b/Flow.Launcher.Plugin/Interfaces/IAsyncHomeQuery.cs @@ -7,7 +7,7 @@ namespace Flow.Launcher.Plugin /// /// Asynchronous Query Model for Flow Launcher When Query Text is Empty /// - public interface IAsyncHomeQuery + public interface IAsyncHomeQuery : IFeatures { /// /// Asynchronous Querying When Query Text is Empty From 17a0834bcda4ba856179543f152a04c987ff9c1c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 16:50:50 +0800 Subject: [PATCH 05/31] Support query for plugins with home query interface --- Flow.Launcher.Core/Plugin/PluginManager.cs | 51 ++++++++++++++ .../UserSettings/Settings.cs | 5 ++ Flow.Launcher.Plugin/Result.cs | 3 + Flow.Launcher/ViewModel/MainViewModel.cs | 68 ++++++++++++------- 4 files changed, 104 insertions(+), 23 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 72303c8b754..b0f8962145f 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -25,6 +25,7 @@ public static class PluginManager private static readonly string ClassName = nameof(PluginManager); private static IEnumerable _contextMenuPlugins; + private static IEnumerable _homePlugins; public static List AllPlugins { get; private set; } public static readonly HashSet GlobalPlugins = new(); @@ -227,6 +228,8 @@ public static async Task InitializePluginsAsync() await Task.WhenAll(InitTasks); _contextMenuPlugins = GetPluginsForInterface(); + _homePlugins = GetPluginsForInterface(); + foreach (var plugin in AllPlugins) { // set distinct on each plugin's action keywords helps only firing global(*) and action keywords once where a plugin @@ -274,6 +277,14 @@ public static ICollection ValidPluginsForQuery(Query query) }; } + public static ICollection ValidPluginsForHomeQuery(Query query) + { + if (query is not null) + return Array.Empty(); + + return _homePlugins.ToList(); + } + public static async Task> QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token) { var results = new List(); @@ -318,6 +329,36 @@ public static async Task> QueryForPluginAsync(PluginPair pair, Quer return results; } + public static async Task> QueryHomeForPluginAsync(PluginPair pair, CancellationToken token) + { + var results = new List(); + var metadata = pair.Metadata; + + try + { + var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}", + async () => results = await ((IAsyncHomeQuery)pair.Plugin).HomeQueryAsync(token).ConfigureAwait(false)); + + token.ThrowIfCancellationRequested(); + if (results == null) + return null; + UpdatePluginMetadata(results, metadata); + + token.ThrowIfCancellationRequested(); + } + catch (OperationCanceledException) + { + // null will be fine since the results will only be added into queue if the token hasn't been cancelled + return null; + } + catch (Exception e) + { + API.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e); + return null; + } + return results; + } + public static void UpdatePluginMetadata(IReadOnlyList results, PluginMetadata metadata, Query query) { foreach (var r in results) @@ -333,6 +374,16 @@ public static void UpdatePluginMetadata(IReadOnlyList results, PluginMet } } + private static void UpdatePluginMetadata(IReadOnlyList results, PluginMetadata metadata) + { + foreach (var r in results) + { + r.PluginDirectory = metadata.PluginDirectory; + r.PluginID = metadata.ID; + r.OriginQuery = null; + } + } + /// /// get specified plugin, return null if not found /// diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index b7a1d1f6367..2b5fc6bc0d4 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -158,6 +158,11 @@ public string PlaceholderText } } } + + public bool ShowHomeQuery { get; set; } = true; + public bool ShowHistoryRecordsForHomeQuery { get; set; } = false; + public int HistoryRecordsCountForHomeQuery { get; set; } = 5; + public int CustomExplorerIndex { get; set; } = 0; [JsonIgnore] diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index f0fcd48ffc0..060c0331729 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -174,6 +174,9 @@ public string BadgeIcoPath /// /// Query information associated with the result /// + /// + /// If the query is for home query, this will be null + /// internal Query OriginQuery { get; set; } /// diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 2f1ed0f5103..b5afe4b7ed9 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1198,21 +1198,31 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b _updateSource?.Cancel(); var query = await ConstructQueryAsync(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts); + var homeQuery = query == null; + ICollection plugins = Array.Empty(); if (query == null) // shortcut expanded { - // Hide and clear results again because running query may show and add some results - Results.Visibility = Visibility.Collapsed; - Results.Clear(); + if (Settings.ShowHomeQuery) + { + plugins = PluginManager.ValidPluginsForHomeQuery(query); + } + + if (plugins.Count == 0) + { + // Hide and clear results again because running query may show and add some results + Results.Visibility = Visibility.Collapsed; + Results.Clear(); - // Reset plugin icon - PluginIconPath = null; - PluginIconSource = null; - SearchIconVisibility = Visibility.Visible; + // Reset plugin icon + PluginIconPath = null; + PluginIconSource = null; + SearchIconVisibility = Visibility.Visible; - // Hide progress bar again because running query may set this to visible - ProgressBarVisibility = Visibility.Hidden; - return; + // Hide progress bar again because running query may set this to visible + ProgressBarVisibility = Visibility.Hidden; + return; + } } _updateSource = new CancellationTokenSource(); @@ -1226,27 +1236,37 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b if (_updateSource.Token.IsCancellationRequested) return; // Update the query's IsReQuery property to true if this is a re-query - query.IsReQuery = isReQuery; + if (!homeQuery) query.IsReQuery = isReQuery; // handle the exclusiveness of plugin using action keyword RemoveOldQueryResults(query); _lastQuery = query; - var plugins = PluginManager.ValidPluginsForQuery(query); - - if (plugins.Count == 1) - { - PluginIconPath = plugins.Single().Metadata.IcoPath; - PluginIconSource = await App.API.LoadImageAsync(PluginIconPath); - SearchIconVisibility = Visibility.Hidden; - } - else + if (homeQuery) { + // Do not show plugin icon if this is a home query PluginIconPath = null; PluginIconSource = null; SearchIconVisibility = Visibility.Visible; } + else + { + plugins = PluginManager.ValidPluginsForQuery(query); + + if (plugins.Count == 1) + { + PluginIconPath = plugins.Single().Metadata.IcoPath; + PluginIconSource = await App.API.LoadImageAsync(PluginIconPath); + SearchIconVisibility = Visibility.Hidden; + } + else + { + PluginIconPath = null; + PluginIconSource = null; + SearchIconVisibility = Visibility.Visible; + } + } // Do not wait for performance improvement /*if (string.IsNullOrEmpty(query.ActionKeyword)) @@ -1303,7 +1323,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b // Local function async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) { - if (searchDelay) + if (searchDelay && !homeQuery) // Do not delay for home query { var searchDelayTime = plugin.Metadata.SearchDelayTime ?? Settings.SearchDelayTime; @@ -1316,7 +1336,9 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) // Task.Yield will force it to run in ThreadPool await Task.Yield(); - var results = await PluginManager.QueryForPluginAsync(plugin, query, token); + var results = homeQuery ? + await PluginManager.QueryHomeForPluginAsync(plugin, token) : + await PluginManager.QueryForPluginAsync(plugin, query, token); if (token.IsCancellationRequested) return; @@ -1616,7 +1638,7 @@ public async void Hide() break; case LastQueryMode.ActionKeywordPreserved: case LastQueryMode.ActionKeywordSelected: - var newQuery = _lastQuery.ActionKeyword; + var newQuery = _lastQuery?.ActionKeyword; if (!string.IsNullOrEmpty(newQuery)) newQuery += " "; From 54994ddb7b264c51452e13dac7f7306b9fc44f41 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 17:02:39 +0800 Subject: [PATCH 06/31] Initialize home query when window is loaded --- Flow.Launcher/MainWindow.xaml.cs | 3 +++ Flow.Launcher/ViewModel/MainViewModel.cs | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index ae7b098a206..546f32cc5fa 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -292,6 +292,9 @@ private async void OnLoaded(object sender, RoutedEventArgs _) DependencyPropertyDescriptor .FromProperty(VisibilityProperty, typeof(StackPanel)) .AddValueChanged(History, (s, e) => UpdateClockPanelVisibility()); + + // Initialize query state + _viewModel.InitializeQuery(); } private async void OnClosing(object sender, CancelEventArgs e) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index b5afe4b7ed9..8244d5765ee 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1074,6 +1074,14 @@ private bool QueryResultsPreviewed() #region Query + public void InitializeQuery() + { + if (Settings.ShowHomeQuery) + { + _ = QueryResultsAsync(false); + } + } + public void Query(bool searchDelay, bool isReQuery = false) { if (QueryResultsSelected()) From e9ef26a8dde26530f21e0ce244c0e03e9cf8d60b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 18:17:00 +0800 Subject: [PATCH 07/31] Change related setting names --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 6 +++--- Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 2b5fc6bc0d4..b630a4ecc7c 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -159,9 +159,9 @@ public string PlaceholderText } } - public bool ShowHomeQuery { get; set; } = true; - public bool ShowHistoryRecordsForHomeQuery { get; set; } = false; - public int HistoryRecordsCountForHomeQuery { get; set; } = 5; + public bool ShowHomePage { get; set; } = true; + public bool ShowHistoryResultsForHomePage { get; set; } = false; + public int MaxHistoryResultsToShowForHomePage { get; set; } = 5; public int CustomExplorerIndex { get; set; } = 0; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 8244d5765ee..06cce302611 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1076,7 +1076,7 @@ private bool QueryResultsPreviewed() public void InitializeQuery() { - if (Settings.ShowHomeQuery) + if (Settings.ShowHomePage) { _ = QueryResultsAsync(false); } @@ -1211,7 +1211,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b if (query == null) // shortcut expanded { - if (Settings.ShowHomeQuery) + if (Settings.ShowHomePage) { plugins = PluginManager.ValidPluginsForHomeQuery(query); } From e8333331b0a348c9ba2eceb995943faea21130d0 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 18:17:07 +0800 Subject: [PATCH 08/31] Add ui in general page --- Flow.Launcher/Languages/en.xaml | 4 ++ .../SettingsPaneGeneralViewModel.cs | 15 +++++- .../Views/SettingsPaneGeneral.xaml | 51 +++++++++++++++---- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index ca0ed33b514..af718946db0 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -126,6 +126,10 @@ Open Use Previous Korean IME You can change the Previous Korean IME settings directly from here + Home Page + Show home page results when query text is empty. + Show History Results in Home Page + Maximum History Results Shown in Home Page Search Plugin diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs index 1a887c4b7f3..840269b037e 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs @@ -154,11 +154,22 @@ public int SearchDelayTimeValue { Settings.SearchDelayTime = value; OnPropertyChanged(); - OnPropertyChanged(nameof(SearchDelayTimeDisplay)); } } } - public string SearchDelayTimeDisplay => $"{SearchDelayTimeValue}ms"; + + public int MaxHistoryResultsToShowValue + { + get => Settings.MaxHistoryResultsToShowForHomePage; + set + { + if (Settings.MaxHistoryResultsToShowForHomePage != value) + { + Settings.MaxHistoryResultsToShowForHomePage = value; + OnPropertyChanged(); + } + } + } private void UpdateEnumDropdownLocalizations() { diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index d45d28d8bba..c0c5613de04 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -217,17 +217,46 @@ Title="{DynamicResource searchDelayTime}" Sub="{DynamicResource searchDelayTimeToolTip}" Type="InsideFit"> - - - + + + + + + + + + + + + + + From d6704ed5da47077b0751176d0e3185fb77ef320b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 22:09:25 +0800 Subject: [PATCH 09/31] Support history items --- Flow.Launcher/ViewModel/MainViewModel.cs | 81 ++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 06cce302611..d850e0f7c41 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -50,6 +50,12 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private readonly IReadOnlyList _emptyResult = new List(); + private readonly PluginMetadata _historyMetadata = new() + { + ID = "298303A65D128A845D28A7B83B3968C2", + Priority = 0 + }; + #endregion #region Constructor @@ -1300,11 +1306,30 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b // plugins are ICollection, meaning LINQ will get the Count and preallocate Array - var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch + Task[] tasks; + if (homeQuery) { - false => QueryTaskAsync(plugin, _updateSource.Token), - true => Task.CompletedTask - }).ToArray(); + var homeTasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch + { + false => QueryTaskAsync(plugin, _updateSource.Token), + true => Task.CompletedTask + }).ToList(); + + if (Settings.ShowHistoryResultsForHomePage) + { + homeTasks.Add(QueryHistoryTaskAsync()); + } + + tasks = homeTasks.ToArray(); + } + else + { + tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch + { + false => QueryTaskAsync(plugin, _updateSource.Token), + true => Task.CompletedTask + }).ToArray(); + } try { @@ -1377,6 +1402,54 @@ await PluginManager.QueryHomeForPluginAsync(plugin, token) : App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } } + + async Task QueryHistoryTaskAsync() + { + // Since it is wrapped within a ThreadPool Thread, the synchronous context is null + // Task.Yield will force it to run in ThreadPool + await Task.Yield(); + + // Select last history results and revert its order to make sure last history results are on top + var lastHistoryResults = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + + var historyResults = new List(); + foreach (var h in lastHistoryResults) + { + var title = App.API.GetTranslation("executeQuery"); + var time = App.API.GetTranslation("lastExecuteTime"); + var result = new Result + { + Title = string.Format(title, h.Query), + SubTitle = string.Format(time, h.ExecutedDateTime), + IcoPath = "Images\\history.png", + Preview = new Result.PreviewInfo + { + PreviewImagePath = Constant.HistoryIcon, + Description = string.Format(time, h.ExecutedDateTime) + }, + OriginQuery = new Query { RawQuery = h.Query }, + Action = _ => + { + SelectedResults = Results; + App.API.ChangeQuery(h.Query); + return false; + } + }; + historyResults.Add(result); + } + + // No need to make copy of results and update badge ico property + + if (_updateSource.Token.IsCancellationRequested) return; + + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(historyResults, _historyMetadata, query, + _updateSource.Token))) + { + App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); + } + + await Task.CompletedTask; + } } private async Task ConstructQueryAsync(string queryText, IEnumerable customShortcuts, From f2f4ebf0ac641eb1feafdb7f0f8feccabbd6d283 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 22:34:58 +0800 Subject: [PATCH 10/31] Support home state change & Add ui --- Flow.Launcher.Core/Plugin/PluginManager.cs | 6 +++ .../UserSettings/PluginSettings.cs | 3 ++ Flow.Launcher.Plugin/PluginMetadata.cs | 5 +++ Flow.Launcher/Languages/en.xaml | 6 +++ .../Controls/InstalledPluginDisplay.xaml | 11 +++++- .../SettingsPanePluginsViewModel.cs | 38 ++++++++++++++++++- Flow.Launcher/ViewModel/PluginViewModel.cs | 11 ++++++ 7 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index b0f8962145f..caa3fd00b13 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -221,6 +221,7 @@ public static async Task InitializePluginsAsync() { API.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e); pair.Metadata.Disabled = true; + pair.Metadata.HomeDisabled = true; failedPlugins.Enqueue(pair); } })); @@ -429,6 +430,11 @@ public static List GetContextMenusForPlugin(Result result) return results; } + public static bool IsHomePlugin(string id) + { + return _homePlugins.Any(p => p.Metadata.ID == id); + } + public static bool ActionKeywordRegistered(string actionKeyword) { // this method is only checking for action keywords (defined as not '*') registration diff --git a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs index 7fb9b895a24..837d0ebb61b 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs @@ -67,6 +67,7 @@ public void UpdatePluginSettings(List metadatas) metadata.Disabled = settings.Disabled; metadata.Priority = settings.Priority; metadata.SearchDelayTime = settings.SearchDelayTime; + metadata.HomeDisabled = settings.HomeDiabled; } else { @@ -79,6 +80,7 @@ public void UpdatePluginSettings(List metadatas) DefaultActionKeywords = metadata.ActionKeywords, // metadata provides default values ActionKeywords = metadata.ActionKeywords, // use default value Disabled = metadata.Disabled, + HomeDiabled = metadata.HomeDisabled, Priority = metadata.Priority, DefaultSearchDelayTime = metadata.SearchDelayTime, // metadata provides default values SearchDelayTime = metadata.SearchDelayTime, // use default value @@ -128,5 +130,6 @@ public class Plugin /// Used only to save the state of the plugin in settings /// public bool Disabled { get; set; } + public bool HomeDiabled { get; set; } } } diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index da10bc6a504..09803cbd7cc 100644 --- a/Flow.Launcher.Plugin/PluginMetadata.cs +++ b/Flow.Launcher.Plugin/PluginMetadata.cs @@ -50,6 +50,11 @@ public class PluginMetadata : BaseModel /// public bool Disabled { get; set; } + /// + /// Whether plugin is disabled in home query. + /// + public bool HomeDisabled { get; set; } + /// /// Plugin execute file path. /// diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index af718946db0..22ab2016cc0 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -130,6 +130,7 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + This can only be edited if plugin supports Home feature and Home Page is enabled. Search Plugin @@ -152,6 +153,7 @@ Enabled Priority Search Delay + Home Page Current Priority New Priority Priority @@ -405,6 +407,10 @@ Search Delay Time Setting Input the search delay time in ms you like to use for the plugin. Input empty if you don't want to specify any, and the plugin will use default search delay time. + + Home Page + Enable the plugin home page state if you like to show the plugin results when query is empty. + Custom Query Hotkey Press a custom hotkey to open Flow Launcher and input the specified query automatically. diff --git a/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml b/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml index 619da22dc64..0842a64f345 100644 --- a/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml +++ b/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml @@ -100,10 +100,19 @@ ToolTipService.InitialShowDelay="0" ToolTipService.ShowOnDisabled="True" Value="{Binding PluginSearchDelayTime, Mode=TwoWay}" /> - + + _isHomeOnOffSelected; + set + { + if (_isHomeOnOffSelected != value) + { + _isHomeOnOffSelected = value; + OnPropertyChanged(); + } + } + } + public SettingsPanePluginsViewModel(Settings settings) { _settings = settings; @@ -152,6 +166,18 @@ private async Task OpenHelperAsync(Button button) { Text = (string)Application.Current.Resources["searchDelayTimeTips"], TextWrapping = TextWrapping.Wrap + }, + new TextBlock + { + Text = (string)Application.Current.Resources["homeTitle"], + FontSize = 18, + Margin = new Thickness(0, 24, 0, 10), + TextWrapping = TextWrapping.Wrap + }, + new TextBlock + { + Text = (string)Application.Current.Resources["homeTips"], + TextWrapping = TextWrapping.Wrap } } }, @@ -176,16 +202,25 @@ private void UpdateDisplayModeFromSelection() IsOnOffSelected = false; IsPrioritySelected = true; IsSearchDelaySelected = false; + IsHomeOnOffSelected = false; break; case DisplayMode.SearchDelay: IsOnOffSelected = false; IsPrioritySelected = false; IsSearchDelaySelected = true; + IsHomeOnOffSelected = false; + break; + case DisplayMode.HomeOnOff: + IsOnOffSelected = false; + IsPrioritySelected = false; + IsSearchDelaySelected = false; + IsHomeOnOffSelected = true; break; default: IsOnOffSelected = true; IsPrioritySelected = false; IsSearchDelaySelected = false; + IsHomeOnOffSelected = false; break; } } @@ -195,5 +230,6 @@ public enum DisplayMode { OnOff, Priority, - SearchDelay + SearchDelay, + HomeOnOff } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 64a7f3db84e..09289601905 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -75,6 +75,16 @@ public bool PluginState } } + public bool PluginHomeState + { + get => !PluginPair.Metadata.HomeDisabled; + set + { + PluginPair.Metadata.HomeDisabled = !value; + PluginSettingsObject.HomeDiabled = !value; + } + } + public bool IsExpanded { get => _isExpanded; @@ -154,6 +164,7 @@ public Control SettingControl public Infrastructure.UserSettings.Plugin PluginSettingsObject{ get; init; } public bool SearchDelayEnabled => Settings.SearchQueryResultsWithDelay; public string DefaultSearchDelay => Settings.SearchDelayTime.ToString(); + public bool HomeEnabled => Settings.ShowHomePage && PluginManager.IsHomePlugin(PluginPair.Metadata.ID); public void OnActionKeywordsTextChanged() { From 96bb62af27932df8e0afab3940ffc97cda28d349 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 3 May 2025 22:54:46 +0800 Subject: [PATCH 11/31] Refresh interface when Home Page is changed --- .../UserSettings/Settings.cs | 15 ++++++++++++++- Flow.Launcher/MainWindow.xaml.cs | 16 +++++++++++++++- Flow.Launcher/ViewModel/MainViewModel.cs | 7 ++----- Flow.Launcher/ViewModel/PluginViewModel.cs | 3 +++ 4 files changed, 34 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index b630a4ecc7c..34bf4f90e5c 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -159,7 +159,20 @@ public string PlaceholderText } } - public bool ShowHomePage { get; set; } = true; + private bool _showHomePage { get; set; } = true; + public bool ShowHomePage + { + get => _showHomePage; + set + { + if (_showHomePage != value) + { + _showHomePage = value; + OnPropertyChanged(); + } + } + } + public bool ShowHistoryResultsForHomePage { get; set; } = false; public int MaxHistoryResultsToShowForHomePage { get; set; } = 5; diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 546f32cc5fa..6dcd8d22dcd 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -277,6 +277,17 @@ private async void OnLoaded(object sender, RoutedEventArgs _) case nameof(Settings.SettingWindowFont): InitializeContextMenu(); break; + case nameof(Settings.ShowHomePage): + // We should refresh results when these two settings are changed but we cannot do that + // Because the order of the results will change, making the interface look weird + // So we would better refresh results when query text is changed next time + /*case nameof(Settings.ShowHistoryResultsForHomePage): + case nameof(Settings.MaxHistoryResultsToShowForHomePage):*/ + if (string.IsNullOrEmpty(_viewModel.QueryText)) + { + _viewModel.QueryResults(); + } + break; } }; @@ -294,7 +305,10 @@ private async void OnLoaded(object sender, RoutedEventArgs _) .AddValueChanged(History, (s, e) => UpdateClockPanelVisibility()); // Initialize query state - _viewModel.InitializeQuery(); + if (_settings.ShowHomePage && string.IsNullOrEmpty(_viewModel.QueryText)) + { + _viewModel.QueryResults(); + } } private async void OnClosing(object sender, CancelEventArgs e) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d850e0f7c41..993cc3ba9b2 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1080,12 +1080,9 @@ private bool QueryResultsPreviewed() #region Query - public void InitializeQuery() + public void QueryResults() { - if (Settings.ShowHomePage) - { - _ = QueryResultsAsync(false); - } + _ = QueryResultsAsync(false); } public void Query(bool searchDelay, bool isReQuery = false) diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 09289601905..61f6dea33da 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -82,6 +82,9 @@ public bool PluginHomeState { PluginPair.Metadata.HomeDisabled = !value; PluginSettingsObject.HomeDiabled = !value; + // We should refresh results when these two settings are changed but we cannot do that + // Because the order of the results will change, making the interface look weird + // So we would better refresh results when query text is changed next time } } From 13cfbe54306d5eabe76d4f0e3f89c979e69a5f11 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 09:07:14 +0800 Subject: [PATCH 12/31] Check query results --- Flow.Launcher/MainWindow.xaml.cs | 7 +------ Flow.Launcher/ViewModel/PluginViewModel.cs | 3 --- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 6dcd8d22dcd..e2948c54043 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -278,12 +278,7 @@ private async void OnLoaded(object sender, RoutedEventArgs _) InitializeContextMenu(); break; case nameof(Settings.ShowHomePage): - // We should refresh results when these two settings are changed but we cannot do that - // Because the order of the results will change, making the interface look weird - // So we would better refresh results when query text is changed next time - /*case nameof(Settings.ShowHistoryResultsForHomePage): - case nameof(Settings.MaxHistoryResultsToShowForHomePage):*/ - if (string.IsNullOrEmpty(_viewModel.QueryText)) + if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText)) { _viewModel.QueryResults(); } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 61f6dea33da..09289601905 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -82,9 +82,6 @@ public bool PluginHomeState { PluginPair.Metadata.HomeDisabled = !value; PluginSettingsObject.HomeDiabled = !value; - // We should refresh results when these two settings are changed but we cannot do that - // Because the order of the results will change, making the interface look weird - // So we would better refresh results when query text is changed next time } } From 4500f1deebccad17076628174050a71e95881efa Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 09:14:57 +0800 Subject: [PATCH 13/31] Fix history items context menu issue --- Flow.Launcher/ViewModel/MainViewModel.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 993cc3ba9b2..8e708fbc4a8 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1127,9 +1127,20 @@ private void QueryContextMenu() if (selected != null) // SelectedItem returns null if selection is empty. { - var results = PluginManager.GetContextMenusForPlugin(selected); - results.Add(ContextMenuTopMost(selected)); - results.Add(ContextMenuPluginInfo(selected.PluginID)); + List results; + if (selected.PluginID == null) // SelectedItem from history in home page. + { + results = new() + { + ContextMenuTopMost(selected) + }; + } + else + { + results = PluginManager.GetContextMenusForPlugin(selected); + results.Add(ContextMenuTopMost(selected)); + results.Add(ContextMenuPluginInfo(selected.PluginID)); + } if (!string.IsNullOrEmpty(query)) { From 19d70592a8f66f5a4f16f3f840019c232865c1a3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 09:38:35 +0800 Subject: [PATCH 14/31] Add empty & global query for home page --- Flow.Launcher.Core/Plugin/PluginManager.cs | 5 +-- Flow.Launcher.Core/Plugin/QueryBuilder.cs | 21 +++++++-- Flow.Launcher/ViewModel/MainViewModel.cs | 51 ++++++++++------------ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index caa3fd00b13..c2265173877 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -278,11 +278,8 @@ public static ICollection ValidPluginsForQuery(Query query) }; } - public static ICollection ValidPluginsForHomeQuery(Query query) + public static ICollection ValidPluginsForHomeQuery() { - if (query is not null) - return Array.Empty(); - return _homePlugins.ToList(); } diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs index 0ef3f30f5e1..fae821736fb 100644 --- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs +++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs @@ -8,10 +8,23 @@ public static class QueryBuilder { public static Query Build(string text, Dictionary nonGlobalPlugins) { + // home query + if (string.IsNullOrEmpty(text)) + { + return new Query() + { + Search = string.Empty, + RawQuery = string.Empty, + SearchTerms = Array.Empty(), + ActionKeyword = string.Empty + }; + } + // replace multiple white spaces with one white space var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries); if (terms.Length == 0) - { // nothing was typed + { + // nothing was typed return null; } @@ -21,13 +34,15 @@ public static Query Build(string text, Dictionary nonGlobalP string[] searchTerms; if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled) - { // use non global plugin for query + { + // use non global plugin for query actionKeyword = possibleActionKeyword; search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty; searchTerms = terms[1..]; } else - { // non action keyword + { + // non action keyword actionKeyword = string.Empty; search = rawQuery.TrimStart(); searchTerms = terms; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 8e708fbc4a8..517cf5323a6 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1220,31 +1220,21 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b _updateSource?.Cancel(); var query = await ConstructQueryAsync(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts); - var homeQuery = query == null; - ICollection plugins = Array.Empty(); if (query == null) // shortcut expanded { - if (Settings.ShowHomePage) - { - plugins = PluginManager.ValidPluginsForHomeQuery(query); - } - - if (plugins.Count == 0) - { - // Hide and clear results again because running query may show and add some results - Results.Visibility = Visibility.Collapsed; - Results.Clear(); + // Hide and clear results again because running query may show and add some results + Results.Visibility = Visibility.Collapsed; + Results.Clear(); - // Reset plugin icon - PluginIconPath = null; - PluginIconSource = null; - SearchIconVisibility = Visibility.Visible; + // Reset plugin icon + PluginIconPath = null; + PluginIconSource = null; + SearchIconVisibility = Visibility.Visible; - // Hide progress bar again because running query may set this to visible - ProgressBarVisibility = Visibility.Hidden; - return; - } + // Hide progress bar again because running query may set this to visible + ProgressBarVisibility = Visibility.Hidden; + return; } _updateSource = new CancellationTokenSource(); @@ -1258,16 +1248,22 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b if (_updateSource.Token.IsCancellationRequested) return; // Update the query's IsReQuery property to true if this is a re-query - if (!homeQuery) query.IsReQuery = isReQuery; + query.IsReQuery = isReQuery; // handle the exclusiveness of plugin using action keyword RemoveOldQueryResults(query); _lastQuery = query; + var homeQuery = query.RawQuery == string.Empty; + ICollection plugins = Array.Empty(); if (homeQuery) { - // Do not show plugin icon if this is a home query + if (Settings.ShowHomePage) + { + plugins = PluginManager.ValidPluginsForHomeQuery(); + } + PluginIconPath = null; PluginIconSource = null; SearchIconVisibility = Visibility.Visible; @@ -1317,18 +1313,17 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b Task[] tasks; if (homeQuery) { - var homeTasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch + tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch { false => QueryTaskAsync(plugin, _updateSource.Token), true => Task.CompletedTask - }).ToList(); + }).ToArray(); + // Query history results for home page firstly so it will be put on top of the results if (Settings.ShowHistoryResultsForHomePage) { - homeTasks.Add(QueryHistoryTaskAsync()); + await QueryHistoryTaskAsync(); } - - tasks = homeTasks.ToArray(); } else { @@ -1465,7 +1460,7 @@ private async Task ConstructQueryAsync(string queryText, IEnumerable Date: Sun, 4 May 2025 10:28:20 +0800 Subject: [PATCH 15/31] Fix topmost issue in home page --- Flow.Launcher.Core/Plugin/PluginManager.cs | 14 ++------------ Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index c2265173877..a3e80a73f74 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -327,7 +327,7 @@ public static async Task> QueryForPluginAsync(PluginPair pair, Quer return results; } - public static async Task> QueryHomeForPluginAsync(PluginPair pair, CancellationToken token) + public static async Task> QueryHomeForPluginAsync(PluginPair pair, Query query, CancellationToken token) { var results = new List(); var metadata = pair.Metadata; @@ -340,7 +340,7 @@ public static async Task> QueryHomeForPluginAsync(PluginPair pair, token.ThrowIfCancellationRequested(); if (results == null) return null; - UpdatePluginMetadata(results, metadata); + UpdatePluginMetadata(results, metadata, query); token.ThrowIfCancellationRequested(); } @@ -372,16 +372,6 @@ public static void UpdatePluginMetadata(IReadOnlyList results, PluginMet } } - private static void UpdatePluginMetadata(IReadOnlyList results, PluginMetadata metadata) - { - foreach (var r in results) - { - r.PluginDirectory = metadata.PluginDirectory; - r.PluginID = metadata.ID; - r.OriginQuery = null; - } - } - /// /// get specified plugin, return null if not found /// diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 517cf5323a6..eb22dc3e28e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1373,7 +1373,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) await Task.Yield(); var results = homeQuery ? - await PluginManager.QueryHomeForPluginAsync(plugin, token) : + await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : await PluginManager.QueryForPluginAsync(plugin, query, token); if (token.IsCancellationRequested) return; From 35e4bfc937158f5a180188626fdd351daf3f188b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 11:05:23 +0800 Subject: [PATCH 16/31] Improve code quality --- Flow.Launcher/ViewModel/MainViewModel.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index eb22dc3e28e..64284d7668c 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1413,10 +1413,10 @@ async Task QueryHistoryTaskAsync() await Task.Yield(); // Select last history results and revert its order to make sure last history results are on top - var lastHistoryResults = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyResults = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); - var historyResults = new List(); - foreach (var h in lastHistoryResults) + var results = new List(); + foreach (var h in historyResults) { var title = App.API.GetTranslation("executeQuery"); var time = App.API.GetTranslation("lastExecuteTime"); @@ -1438,14 +1438,12 @@ async Task QueryHistoryTaskAsync() return false; } }; - historyResults.Add(result); + results.Add(result); } - // No need to make copy of results and update badge ico property - if (_updateSource.Token.IsCancellationRequested) return; - if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(historyResults, _historyMetadata, query, + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, _historyMetadata, query, _updateSource.Token))) { App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); From 2ab007b3b6db29ad4347a3f6b84e4f2459cecabc Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 11:26:00 +0800 Subject: [PATCH 17/31] Fix typos --- Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs | 6 +++--- Flow.Launcher/ViewModel/PluginViewModel.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs index 837d0ebb61b..920abc28426 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs @@ -67,7 +67,7 @@ public void UpdatePluginSettings(List metadatas) metadata.Disabled = settings.Disabled; metadata.Priority = settings.Priority; metadata.SearchDelayTime = settings.SearchDelayTime; - metadata.HomeDisabled = settings.HomeDiabled; + metadata.HomeDisabled = settings.HomeDisabled; } else { @@ -80,7 +80,7 @@ public void UpdatePluginSettings(List metadatas) DefaultActionKeywords = metadata.ActionKeywords, // metadata provides default values ActionKeywords = metadata.ActionKeywords, // use default value Disabled = metadata.Disabled, - HomeDiabled = metadata.HomeDisabled, + HomeDisabled = metadata.HomeDisabled, Priority = metadata.Priority, DefaultSearchDelayTime = metadata.SearchDelayTime, // metadata provides default values SearchDelayTime = metadata.SearchDelayTime, // use default value @@ -130,6 +130,6 @@ public class Plugin /// Used only to save the state of the plugin in settings /// public bool Disabled { get; set; } - public bool HomeDiabled { get; set; } + public bool HomeDisabled { get; set; } } } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 09289601905..01fa3d20326 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -81,7 +81,7 @@ public bool PluginHomeState set { PluginPair.Metadata.HomeDisabled = !value; - PluginSettingsObject.HomeDiabled = !value; + PluginSettingsObject.HomeDisabled = !value; } } From eaea38c13ab7c6536ee3b92bf8ad9b8ff436c599 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Sun, 4 May 2025 11:40:45 +0800 Subject: [PATCH 18/31] Fix typos Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs b/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs index f3c9cfcad97..129f43b8567 100644 --- a/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs +++ b/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs @@ -8,7 +8,7 @@ namespace Flow.Launcher.Plugin /// Synchronous Query Model for Flow Launcher When Query Text is Empty /// /// If the Querying method requires high IO transmission - /// or performaing CPU intense jobs (performing better with cancellation), please try the IAsyncHomeQuery interface + /// or performing CPU intense jobs (performing better with cancellation), please try the IAsyncHomeQuery interface /// /// public interface IHomeQuery : IAsyncHomeQuery From 78f606f2fcb74467962bb582cd70f65c2d35104e Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Sun, 4 May 2025 11:40:57 +0800 Subject: [PATCH 19/31] Fix typos Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs b/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs index 129f43b8567..81186fca2de 100644 --- a/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs +++ b/Flow.Launcher.Plugin/Interfaces/IHomeQuery.cs @@ -17,7 +17,7 @@ public interface IHomeQuery : IAsyncHomeQuery /// Querying When Query Text is Empty /// /// This method will be called within a Task.Run, - /// so please avoid synchrously wait for long. + /// so please avoid synchronously wait for long. /// /// /// From 72bd1e60dbe7bdef77704e88641b818d1bb8f98f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 11:44:41 +0800 Subject: [PATCH 20/31] Remove code comments with issues --- Flow.Launcher.Plugin/Result.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 060c0331729..f0fcd48ffc0 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -174,9 +174,6 @@ public string BadgeIcoPath /// /// Query information associated with the result /// - /// - /// If the query is for home query, this will be null - /// internal Query OriginQuery { get; set; } /// From 0d9fb29f12948253a956f80fedae0d3a9473091e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 16:37:15 +0800 Subject: [PATCH 21/31] Improve code quality --- Flow.Launcher/ViewModel/MainViewModel.cs | 64 +++++++++--------------- 1 file changed, 23 insertions(+), 41 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 6d7b4a8a47a..f79596c96de 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1192,8 +1192,27 @@ private void QueryHistory() var query = QueryText.ToLower().Trim(); History.Clear(); + var results = GetHistoryItems(_history.Items); + + if (!string.IsNullOrEmpty(query)) + { + var filtered = results.Where + ( + r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || + App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() + ).ToList(); + History.AddResults(filtered, id); + } + else + { + History.AddResults(results, id); + } + } + + private static List GetHistoryItems(IEnumerable historyItems) + { var results = new List(); - foreach (var h in _history.Items) + foreach (var h in historyItems) { var title = App.API.GetTranslation("executeQuery"); var time = App.API.GetTranslation("lastExecuteTime"); @@ -1217,20 +1236,7 @@ private void QueryHistory() }; results.Add(result); } - - if (!string.IsNullOrEmpty(query)) - { - var filtered = results.Where - ( - r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || - App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() - ).ToList(); - History.AddResults(filtered, id); - } - else - { - History.AddResults(results, id); - } + return results; } private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) @@ -1431,33 +1437,9 @@ async Task QueryHistoryTaskAsync() await Task.Yield(); // Select last history results and revert its order to make sure last history results are on top - var historyResults = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); - var results = new List(); - foreach (var h in historyResults) - { - var title = App.API.GetTranslation("executeQuery"); - var time = App.API.GetTranslation("lastExecuteTime"); - var result = new Result - { - Title = string.Format(title, h.Query), - SubTitle = string.Format(time, h.ExecutedDateTime), - IcoPath = "Images\\history.png", - Preview = new Result.PreviewInfo - { - PreviewImagePath = Constant.HistoryIcon, - Description = string.Format(time, h.ExecutedDateTime) - }, - OriginQuery = new Query { RawQuery = h.Query }, - Action = _ => - { - SelectedResults = Results; - App.API.ChangeQuery(h.Query); - return false; - } - }; - results.Add(result); - } + var results = GetHistoryItems(historyItems); if (_updateSource.Token.IsCancellationRequested) return; From 67facb8f18f4325def9572e37ccf7f25fbb7a8fa Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 16:44:05 +0800 Subject: [PATCH 22/31] Use non-async version --- Flow.Launcher/ViewModel/MainViewModel.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index f79596c96de..5fd8d395f89 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1346,7 +1346,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b // Query history results for home page firstly so it will be put on top of the results if (Settings.ShowHistoryResultsForHomePage) { - await QueryHistoryTaskAsync(); + QueryHistoryTask(); } } else @@ -1430,12 +1430,8 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : } } - async Task QueryHistoryTaskAsync() + void QueryHistoryTask() { - // Since it is wrapped within a ThreadPool Thread, the synchronous context is null - // Task.Yield will force it to run in ThreadPool - await Task.Yield(); - // Select last history results and revert its order to make sure last history results are on top var historyItems = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); @@ -1448,8 +1444,6 @@ async Task QueryHistoryTaskAsync() { App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } - - await Task.CompletedTask; } } From 21d6ec20d45597ad872341afbcb82ef85a85ee87 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 18:29:39 +0800 Subject: [PATCH 23/31] Use null to distinguish between home query and global query --- Flow.Launcher.Core/Plugin/QueryBuilder.cs | 3 ++- Flow.Launcher.Plugin/Query.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs index fae821736fb..82745c2394f 100644 --- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs +++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs @@ -16,7 +16,8 @@ public static Query Build(string text, Dictionary nonGlobalP Search = string.Empty, RawQuery = string.Empty, SearchTerms = Array.Empty(), - ActionKeyword = string.Empty + // must use null because we need to distinguish between home query and global query + ActionKeyword = null }; } diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index c3eede4c6b6..7d98a4afe8a 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -53,6 +53,7 @@ public class Query /// /// The action keyword part of this query. /// For global plugins this value will be empty. + /// For home query this value will be null. /// public string ActionKeyword { get; init; } From 28b8cb6013fb56de9d9946acc6a300af1e0883cf Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 4 May 2025 21:43:48 +0800 Subject: [PATCH 24/31] Improve distinguish between home query and global query --- Flow.Launcher.Core/Plugin/QueryBuilder.cs | 3 +-- Flow.Launcher.Plugin/Query.cs | 1 - Flow.Launcher/ViewModel/MainViewModel.cs | 17 +++++++++++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs index 82745c2394f..fae821736fb 100644 --- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs +++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs @@ -16,8 +16,7 @@ public static Query Build(string text, Dictionary nonGlobalP Search = string.Empty, RawQuery = string.Empty, SearchTerms = Array.Empty(), - // must use null because we need to distinguish between home query and global query - ActionKeyword = null + ActionKeyword = string.Empty }; } diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index 7d98a4afe8a..c3eede4c6b6 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -53,7 +53,6 @@ public class Query /// /// The action keyword part of this query. /// For global plugins this value will be empty. - /// For home query this value will be null. /// public string ActionKeyword { get; init; } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 5fd8d395f89..30df8250cea 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -33,6 +33,7 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private bool _isQueryRunning; private Query _lastQuery; + private bool _lastHomeQuery; private string _queryTextBeforeLeaveResults; private string _ignoredQueryText = null; @@ -1261,6 +1262,8 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b return; } + var homeQuery = query.RawQuery == string.Empty; + _updateSource = new CancellationTokenSource(); ProgressBarVisibility = Visibility.Hidden; @@ -1275,11 +1278,11 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b query.IsReQuery = isReQuery; // handle the exclusiveness of plugin using action keyword - RemoveOldQueryResults(query); + RemoveOldQueryResults(query, homeQuery); _lastQuery = query; + _lastHomeQuery = homeQuery; - var homeQuery = query.RawQuery == string.Empty; ICollection plugins = Array.Empty(); if (homeQuery) { @@ -1524,9 +1527,15 @@ private async Task BuildQueryAsync(IEnumerable builtIn } } - private void RemoveOldQueryResults(Query query) + private void RemoveOldQueryResults(Query query, bool homeQuery) { - if (_lastQuery?.ActionKeyword != query?.ActionKeyword) + // If last or current query is home query, we need to clear the results + if (_lastHomeQuery || homeQuery) + { + Results.Clear(); + } + // If last and current query are not home query, we need to check action keyword + else if (_lastQuery?.ActionKeyword != query?.ActionKeyword) { Results.Clear(); } From b9aa5a88cf5350ca7165fa570de225428472bd3f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 08:30:53 +0800 Subject: [PATCH 25/31] Change variable name for code quality --- Flow.Launcher/ViewModel/MainViewModel.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 566cb6814c5..476c10e747b 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 _lastHomeQuery; + private bool _lastIsHomeQuery; private string _queryTextBeforeLeaveResults; private string _ignoredQueryText = null; @@ -1268,7 +1268,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 homeQuery = query.RawQuery == string.Empty; + var isHomeQuery = query.RawQuery == string.Empty; _updateSource = new CancellationTokenSource(); @@ -1284,13 +1284,13 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b query.IsReQuery = isReQuery; // handle the exclusiveness of plugin using action keyword - RemoveOldQueryResults(query, homeQuery); + RemoveOldQueryResults(query, isHomeQuery); _lastQuery = query; - _lastHomeQuery = homeQuery; + _lastIsHomeQuery = isHomeQuery; ICollection plugins = Array.Empty(); - if (homeQuery) + if (isHomeQuery) { if (Settings.ShowHomePage) { @@ -1347,7 +1347,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 (homeQuery) + if (isHomeQuery) { tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch { @@ -1397,7 +1397,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) { App.API.LogDebug(ClassName, $"Wait for querying plugin <{plugin.Metadata.Name}>"); - if (searchDelay && !homeQuery) // Do not delay for home query + if (searchDelay && !isHomeQuery) // Do not delay for home query { var searchDelayTime = plugin.Metadata.SearchDelayTime ?? Settings.SearchDelayTime; @@ -1410,7 +1410,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) // Task.Yield will force it to run in ThreadPool await Task.Yield(); - var results = homeQuery ? + var results = isHomeQuery ? await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : await PluginManager.QueryForPluginAsync(plugin, query, token); @@ -1542,10 +1542,10 @@ private async Task BuildQueryAsync(IEnumerable builtIn } } - private void RemoveOldQueryResults(Query query, bool homeQuery) + private void RemoveOldQueryResults(Query query, bool isHomeQuery) { // If last or current query is home query, we need to clear the results - if (_lastHomeQuery || homeQuery) + if (_lastIsHomeQuery || isHomeQuery) { Results.Clear(); } From 2713c5babfaaf1a7989043f04b42b34b712116ca Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 08:35:20 +0800 Subject: [PATCH 26/31] Add code comments --- Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 476c10e747b..23958ca7060 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -54,8 +54,8 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private readonly PluginMetadata _historyMetadata = new() { - ID = "298303A65D128A845D28A7B83B3968C2", - Priority = 0 + ID = "298303A65D128A845D28A7B83B3968C2", // ID is for ResultsForUpdate constructor + Priority = 0 // Priority is for calculating scores in UpdateResultView }; #endregion From 41211e8cd380df56a44dc9df996ac2833b431dc1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 08:44:08 +0800 Subject: [PATCH 27/31] Improve code comments --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 23958ca7060..dc35a6aa998 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -54,7 +54,7 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private readonly PluginMetadata _historyMetadata = new() { - ID = "298303A65D128A845D28A7B83B3968C2", // ID is for ResultsForUpdate constructor + ID = "298303A65D128A845D28A7B83B3968C2", // ID is for identifying the update plugin in UpdateActionAsync Priority = 0 // Priority is for calculating scores in UpdateResultView }; From 16404bc2a780430028e3515f19f02b2568f57b5e Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 12:54:15 +0800 Subject: [PATCH 28/31] Improve log information --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index dc35a6aa998..25c39ac7aec 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1547,13 +1547,13 @@ private void RemoveOldQueryResults(Query query, bool isHomeQuery) // If last or current query is home query, we need to clear the results 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) { App.API.LogDebug(ClassName, $"Remove old results"); - Results.Clear(); } } From 36a4f4176778253f00c09a7675ec43b07953282a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 17:32:43 +0800 Subject: [PATCH 29/31] Do not need to clear the result when last and current query are home query --- Flow.Launcher/ViewModel/MainViewModel.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 25c39ac7aec..a8e431d9990 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1544,8 +1544,13 @@ private async Task BuildQueryAsync(IEnumerable builtIn private void RemoveOldQueryResults(Query query, bool isHomeQuery) { + // If last and current query are home query, we don't need to clear the results + if (_lastIsHomeQuery && isHomeQuery) + { + return; + } // If last or current query is home query, we need to clear the results - if (_lastIsHomeQuery || isHomeQuery) + else if (_lastIsHomeQuery || isHomeQuery) { App.API.LogDebug(ClassName, $"Remove old results"); Results.Clear(); From 0882378988b72615118150db4c011eafd59ceca9 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 18:53:40 +0800 Subject: [PATCH 30/31] Add Glyph for history items & topmost items --- Flow.Launcher/ViewModel/MainViewModel.cs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index a8e431d9990..a98172f0ac1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1221,19 +1221,15 @@ private static List GetHistoryItems(IEnumerable historyItem { Title = string.Format(title, h.Query), SubTitle = string.Format(time, h.ExecutedDateTime), - IcoPath = "Images\\history.png", - Preview = new Result.PreviewInfo - { - PreviewImagePath = Constant.HistoryIcon, - Description = string.Format(time, h.ExecutedDateTime) - }, + IcoPath = Constant.HistoryIcon, OriginQuery = new Query { RawQuery = h.Query }, Action = _ => { App.API.BackToQueryResults(); App.API.ChangeQuery(h.Query); return false; - } + }, + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") }; results.Add(result); } @@ -1579,7 +1575,8 @@ private Result ContextMenuTopMost(Result result) App.API.ShowMsg(App.API.GetTranslation("success")); App.API.ReQuery(); return false; - } + }, + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE74B") }; } else @@ -1588,7 +1585,6 @@ private Result ContextMenuTopMost(Result result) { Title = App.API.GetTranslation("setAsTopMostInThisQuery"), IcoPath = "Images\\up.png", - Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xeac2"), PluginDirectory = Constant.ProgramDirectory, Action = _ => { @@ -1596,7 +1592,8 @@ private Result ContextMenuTopMost(Result result) App.API.ShowMsg(App.API.GetTranslation("success")); App.API.ReQuery(); return false; - } + }, + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE74A") }; } From 7083849d149f4262b478f29d5c0c6834c78fd3c6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 5 May 2025 19:11:46 +0800 Subject: [PATCH 31/31] Remove unused codes --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index a98172f0ac1..6c4236db9d1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -790,8 +790,6 @@ private ResultsViewModel SelectedResults } } } - - _selectedResults.Visibility = Visibility.Visible; } }