From 6e4d9a5e61c577ae684c29f6513e22b2bb339a1a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 11:10:16 +0800 Subject: [PATCH 01/24] Remove useless blank lines --- Flow.Launcher.Core/Plugin/PluginManager.cs | 1 - Flow.Launcher.Plugin/Query.cs | 1 - Flow.Launcher/ViewModel/MainViewModel.cs | 2 -- 3 files changed, 4 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 5c4eaa1da..b1f397ea2 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -229,7 +229,6 @@ namespace Flow.Launcher.Core.Plugin if (!NonGlobalPlugins.ContainsKey(query.ActionKeyword)) return GlobalPlugins; - var plugin = NonGlobalPlugins[query.ActionKeyword]; return new List { diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index e182491c2..ab3c8cfeb 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -43,7 +43,6 @@ namespace Flow.Launcher.Plugin /// public const string ActionKeywordSeparator = ";"; - /// /// Wildcard action keyword. Plugins using this value will be queried on every search. /// diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 5c3251bfc..075471367 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1118,7 +1118,6 @@ namespace Flow.Launcher.ViewModel SearchIconVisibility = Visibility.Visible; } - if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign) { // Wait 45 millisecond for query change in global query @@ -1145,7 +1144,6 @@ namespace Flow.Launcher.ViewModel true => Task.CompletedTask }).ToArray(); - try { // Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first From 8f6bed45e4f9305110f2ffc9aac47f827c7d84b4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 12:23:31 +0800 Subject: [PATCH 02/24] Remove useless * keywords --- Plugins/Flow.Launcher.Plugin.Explorer/plugin.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index 4eb6bb83b..89eaa657d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json @@ -2,10 +2,7 @@ "ID": "572be03c74c642baae319fc283e561a8", "ActionKeywords": [ "*", - "doc:", - "*", - "*", - "*" + "doc:" ], "Name": "Explorer", "Description": "Find and manage files and folders via Windows Search or Everything", From e1f1b97b7e158d015f122e02f393e6d72ae08697 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 12:27:38 +0800 Subject: [PATCH 03/24] Support allow modify action keywords & WebSearch does not let user change its keywords --- Flow.Launcher.Plugin/PluginMetadata.cs | 2 ++ Flow.Launcher/ViewModel/PluginViewModel.cs | 2 +- Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index b4e06913e..14a720203 100644 --- a/Flow.Launcher.Plugin/PluginMetadata.cs +++ b/Flow.Launcher.Plugin/PluginMetadata.cs @@ -34,6 +34,8 @@ namespace Flow.Launcher.Plugin public List ActionKeywords { get; set; } + public bool AllowModifyActionKeywords { get; set; } = true; + public string IcoPath { get; set;} public override string ToString() diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index a46b98d64..4b628f96e 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -100,7 +100,7 @@ namespace Flow.Launcher.ViewModel : null; private ImageSource _image = ImageLoader.MissingImage; - public Visibility ActionKeywordsVisibility => PluginPair.Metadata.ActionKeywords.Count == 1 ? Visibility.Visible : Visibility.Collapsed; + public Visibility ActionKeywordsVisibility => PluginPair.Metadata.AllowModifyActionKeywords ? Visibility.Visible : Visibility.Collapsed; public string InitilizaTime => PluginPair.Metadata.InitTime + "ms"; public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms"; public string Version => InternationalizationManager.Instance.GetTranslation("plugin_query_version") + " " + PluginPair.Metadata.Version; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json index 6b6792ad3..1fc9967fc 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json @@ -23,6 +23,7 @@ "yahoo", "bd" ], + "AllowModifyActionKeywords": false, "Name": "Web Searches", "Description": "Provide the web search ability", "Author": "qianlifeng", From abfeee1423a011229ec6cd9dd7e85dddc2a90ac6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 12:59:56 +0800 Subject: [PATCH 04/24] Support multiple action keywords --- Flow.Launcher.Core/Plugin/PluginManager.cs | 29 +++++++++++++++++----- Flow.Launcher.Plugin/Query.cs | 4 +-- Flow.Launcher/ActionKeywords.xaml.cs | 15 +++++++---- Flow.Launcher/ViewModel/PluginViewModel.cs | 7 +++--- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index b1f397ea2..8c62c2f02 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -340,7 +340,12 @@ namespace Flow.Launcher.Core.Plugin return results; } - public static bool ActionKeywordRegistered(string actionKeyword) + public static bool ActionKeywordRegistered(IReadOnlyList actionKeywords) + { + return actionKeywords.Any(ActionKeywordRegistered); + } + + private static bool ActionKeywordRegistered(string actionKeyword) { // this method is only checking for action keywords (defined as not '*') registration // hence the actionKeyword != Query.GlobalPluginWildcardSign logic @@ -385,19 +390,31 @@ namespace Flow.Launcher.Core.Plugin if (oldActionkeyword != Query.GlobalPluginWildcardSign) NonGlobalPlugins.Remove(oldActionkeyword); - plugin.Metadata.ActionKeywords.Remove(oldActionkeyword); } - public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword) + public static void ReplaceActionKeyword(string id, IReadOnlyList oldActionKeyword, IReadOnlyList newActionKeyword) { - if (oldActionKeyword != newActionKeyword) + if (CheckActionKeywordChanged(oldActionKeyword, newActionKeyword)) { - AddActionKeyword(id, newActionKeyword); - RemoveActionKeyword(id, oldActionKeyword); + foreach (var actionKeyword in newActionKeyword) + { + AddActionKeyword(id, actionKeyword); + } + foreach (var actionKeyword in oldActionKeyword) + { + RemoveActionKeyword(id, actionKeyword); + } } } + private static bool CheckActionKeywordChanged(IReadOnlyList oldActionKeyword, IReadOnlyList newActionKeyword) + { + if (oldActionKeyword.Count != newActionKeyword.Count) + return true; + return oldActionKeyword.Where((t, i) => t != newActionKeyword[i]).Any(); + } + private static string GetContainingFolderPathAfterUnzip(string unzippedParentFolderPath) { var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length; diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index ab3c8cfeb..15b2dd171 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -39,9 +39,9 @@ namespace Flow.Launcher.Plugin public const string TermSeparator = " "; /// - /// User can set multiple action keywords seperated by ';' + /// User can set multiple action keywords seperated by whitespace /// - public const string ActionKeywordSeparator = ";"; + public const string ActionKeywordSeparator = TermSeparator; /// /// Wildcard action keyword. Plugins using this value will be queried on every search. diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index ba47a4ded..4a6bd10a8 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -3,6 +3,7 @@ using Flow.Launcher.Core.Resource; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; using Flow.Launcher.Core; +using System.Linq; namespace Flow.Launcher { @@ -32,13 +33,17 @@ namespace Flow.Launcher private void btnDone_OnClick(object sender, RoutedEventArgs _) { - var oldActionKeyword = plugin.Metadata.ActionKeywords[0]; - var newActionKeyword = tbAction.Text.Trim(); - newActionKeyword = newActionKeyword.Length > 0 ? newActionKeyword : "*"; + var oldActionKeywords = plugin.Metadata.ActionKeywords; + + var newActionKeywords = tbAction.Text.Split(Query.ActionKeywordSeparator).ToList(); + newActionKeywords.RemoveAll(string.IsNullOrEmpty); + newActionKeywords = newActionKeywords.Distinct().ToList(); + + newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign }; - if (!PluginViewModel.IsActionKeywordRegistered(newActionKeyword)) + if (!PluginViewModel.IsActionKeywordRegistered(newActionKeywords)) { - pluginViewModel.ChangeActionKeyword(newActionKeyword, oldActionKeyword); + pluginViewModel.ChangeActionKeyword(newActionKeywords, oldActionKeywords); Close(); } else diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 4b628f96e..748490c47 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -8,6 +8,7 @@ using System.Windows.Controls; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Resource; using Flow.Launcher.Resources.Controls; +using System.Collections.Generic; namespace Flow.Launcher.ViewModel { @@ -109,9 +110,9 @@ namespace Flow.Launcher.ViewModel public int Priority => PluginPair.Metadata.Priority; public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; } - public void ChangeActionKeyword(string newActionKeyword, string oldActionKeyword) + public void ChangeActionKeyword(IReadOnlyList newActionKeywords, IReadOnlyList oldActionKeywords) { - PluginManager.ReplaceActionKeyword(PluginPair.Metadata.ID, oldActionKeyword, newActionKeyword); + PluginManager.ReplaceActionKeyword(PluginPair.Metadata.ID, oldActionKeywords, newActionKeywords); OnPropertyChanged(nameof(ActionKeywordsText)); } @@ -150,7 +151,7 @@ namespace Flow.Launcher.ViewModel PluginManager.API.ShowMainWindow(); } - public static bool IsActionKeywordRegistered(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword); + public static bool IsActionKeywordRegistered(IReadOnlyList newActionKeywords) => PluginManager.ActionKeywordRegistered(newActionKeywords); [RelayCommand] private void SetActionKeywords() From d9ba38b3221174996201f8df2b1a93a9000e00e5 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 13:09:19 +0800 Subject: [PATCH 05/24] Fix issue that plugin cannot update ActionKeyword after changing its action keywords --- Flow.Launcher.Core/Plugin/PluginManager.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 8c62c2f02..e4ecf0f40 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -405,6 +405,17 @@ namespace Flow.Launcher.Core.Plugin { RemoveActionKeyword(id, actionKeyword); } + + // Update action keyword in plugin metadata + var plugin = GetPluginForId(id); + if (newActionKeyword.Count > 0) + { + plugin.Metadata.ActionKeyword = newActionKeyword[0]; + } + else + { + plugin.Metadata.ActionKeyword = string.Empty; + } } } From f999b97de1e2a57dd11a7b8fe1ab39194936b865 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 13:25:31 +0800 Subject: [PATCH 06/24] Fix build issue --- Flow.Launcher.Core/Plugin/PluginManager.cs | 46 +++++++++++++++---- .../SearchSourceSetting.xaml.cs | 4 +- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index e4ecf0f40..c8f78767c 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -342,10 +342,17 @@ namespace Flow.Launcher.Core.Plugin public static bool ActionKeywordRegistered(IReadOnlyList actionKeywords) { - return actionKeywords.Any(ActionKeywordRegistered); + foreach (var actionKeyword in actionKeywords) + { + if (ActionKeywordRegistered(actionKeyword)) + { + return true; + } + } + return false; } - private static bool ActionKeywordRegistered(string actionKeyword) + public static bool ActionKeywordRegistered(string actionKeyword) { // this method is only checking for action keywords (defined as not '*') registration // hence the actionKeyword != Query.GlobalPluginWildcardSign logic @@ -369,6 +376,7 @@ namespace Flow.Launcher.Core.Plugin NonGlobalPlugins[newActionKeyword] = plugin; } + // Update action keywords in plugin metadata plugin.Metadata.ActionKeywords.Add(newActionKeyword); } @@ -390,27 +398,28 @@ namespace Flow.Launcher.Core.Plugin if (oldActionkeyword != Query.GlobalPluginWildcardSign) NonGlobalPlugins.Remove(oldActionkeyword); + // Update action keywords in plugin metadata plugin.Metadata.ActionKeywords.Remove(oldActionkeyword); } - public static void ReplaceActionKeyword(string id, IReadOnlyList oldActionKeyword, IReadOnlyList newActionKeyword) + public static void ReplaceActionKeyword(string id, IReadOnlyList oldActionKeywords, IReadOnlyList newActionKeywords) { - if (CheckActionKeywordChanged(oldActionKeyword, newActionKeyword)) + if (CheckActionKeywordChanged(oldActionKeywords, newActionKeywords)) { - foreach (var actionKeyword in newActionKeyword) + foreach (var actionKeyword in newActionKeywords) { AddActionKeyword(id, actionKeyword); } - foreach (var actionKeyword in oldActionKeyword) + foreach (var actionKeyword in oldActionKeywords) { RemoveActionKeyword(id, actionKeyword); } // Update action keyword in plugin metadata var plugin = GetPluginForId(id); - if (newActionKeyword.Count > 0) + if (newActionKeywords.Count > 0) { - plugin.Metadata.ActionKeyword = newActionKeyword[0]; + plugin.Metadata.ActionKeyword = newActionKeywords[0]; } else { @@ -426,6 +435,27 @@ namespace Flow.Launcher.Core.Plugin return oldActionKeyword.Where((t, i) => t != newActionKeyword[i]).Any(); } + public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword) + { + if (oldActionKeyword != newActionKeyword) + { + AddActionKeyword(id, newActionKeyword); + RemoveActionKeyword(id, oldActionKeyword); + + // Update action keyword in plugin metadata + var plugin = GetPluginForId(id); + var newActionKeywords = plugin.Metadata.ActionKeywords; + if (newActionKeywords.Count > 0) + { + plugin.Metadata.ActionKeyword = newActionKeywords[0]; + } + else + { + plugin.Metadata.ActionKeyword = string.Empty; + } + } + } + private static string GetContainingFolderPathAfterUnzip(string unzippedParentFolderPath) { var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs index a3e5630c2..f79176f99 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs @@ -80,7 +80,7 @@ namespace Flow.Launcher.Plugin.WebSearch private void AddSearchSource() { var keyword = _searchSource.ActionKeyword; - if (!PluginManager.ActionKeywordRegistered(keyword)) + if (!_context.API.ActionKeywordAssigned(keyword)) { var id = _context.CurrentPluginMetadata.ID; PluginManager.AddActionKeyword(id, keyword); @@ -100,7 +100,7 @@ namespace Flow.Launcher.Plugin.WebSearch { var newKeyword = _searchSource.ActionKeyword; var oldKeyword = _oldSearchSource.ActionKeyword; - if (!PluginManager.ActionKeywordRegistered(newKeyword) || oldKeyword == newKeyword) + if (!_context.API.ActionKeywordAssigned(newKeyword) || oldKeyword == newKeyword) { var id = _context.CurrentPluginMetadata.ID; PluginManager.ReplaceActionKeyword(id, oldKeyword, newKeyword); From 37ad5aa09bb1336ee3db27a913e6d2a51cc314c4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 13:31:46 +0800 Subject: [PATCH 07/24] Fix issue that ActionKeywordRegistered will not exclude old action key --- Flow.Launcher.Core/Plugin/PluginManager.cs | 12 +++++++++--- Flow.Launcher/ActionKeywords.xaml.cs | 3 ++- Flow.Launcher/ViewModel/PluginViewModel.cs | 2 -- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index c8f78767c..d0e6fcab0 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -340,11 +340,11 @@ namespace Flow.Launcher.Core.Plugin return results; } - public static bool ActionKeywordRegistered(IReadOnlyList actionKeywords) + public static bool ActionKeywordRegistered(IReadOnlyList newActionKeywords, IReadOnlyList oldActionKeywords) { - foreach (var actionKeyword in actionKeywords) + foreach (var actionKeyword in newActionKeywords) { - if (ActionKeywordRegistered(actionKeyword)) + if (ActionKeywordRegistered(actionKeyword, oldActionKeywords)) { return true; } @@ -352,6 +352,12 @@ namespace Flow.Launcher.Core.Plugin return false; } + private static bool ActionKeywordRegistered(string actionKeyword, IReadOnlyList oldActionKeywords) + { + if (oldActionKeywords.Contains(actionKeyword)) return false; + return ActionKeywordRegistered(actionKeyword); + } + public static bool ActionKeywordRegistered(string actionKeyword) { // this method is only checking for action keywords (defined as not '*') registration diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index 4a6bd10a8..af6dcfe90 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -4,6 +4,7 @@ using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; using Flow.Launcher.Core; using System.Linq; +using Flow.Launcher.Core.Plugin; namespace Flow.Launcher { @@ -41,7 +42,7 @@ namespace Flow.Launcher newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign }; - if (!PluginViewModel.IsActionKeywordRegistered(newActionKeywords)) + if (!PluginManager.ActionKeywordRegistered(newActionKeywords, oldActionKeywords)) { pluginViewModel.ChangeActionKeyword(newActionKeywords, oldActionKeywords); Close(); diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 748490c47..63263c768 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -151,8 +151,6 @@ namespace Flow.Launcher.ViewModel PluginManager.API.ShowMainWindow(); } - public static bool IsActionKeywordRegistered(IReadOnlyList newActionKeywords) => PluginManager.ActionKeywordRegistered(newActionKeywords); - [RelayCommand] private void SetActionKeywords() { From 300d64d66165e4cc302dcf58ce8fe908323135be Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 13:43:53 +0800 Subject: [PATCH 08/24] Remove action keyword first --- Flow.Launcher.Core/Plugin/PluginManager.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index d0e6fcab0..18519c85d 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -412,14 +412,16 @@ namespace Flow.Launcher.Core.Plugin { if (CheckActionKeywordChanged(oldActionKeywords, newActionKeywords)) { + // Fix collection modified while iterating exception + var oldActionKeywordsClone = oldActionKeywords.ToList(); + foreach (var actionKeyword in oldActionKeywordsClone) + { + RemoveActionKeyword(id, actionKeyword); + } foreach (var actionKeyword in newActionKeywords) { AddActionKeyword(id, actionKeyword); } - foreach (var actionKeyword in oldActionKeywords) - { - RemoveActionKeyword(id, actionKeyword); - } // Update action keyword in plugin metadata var plugin = GetPluginForId(id); @@ -445,8 +447,8 @@ namespace Flow.Launcher.Core.Plugin { if (oldActionKeyword != newActionKeyword) { - AddActionKeyword(id, newActionKeyword); RemoveActionKeyword(id, oldActionKeyword); + AddActionKeyword(id, newActionKeyword); // Update action keyword in plugin metadata var plugin = GetPluginForId(id); From cab3eb78fd827283e7511511fba1bce1e8bf58cd Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 13:45:02 +0800 Subject: [PATCH 09/24] Update string resource --- Flow.Launcher/Languages/en.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 4c465d61f..282d0fb47 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -335,7 +335,7 @@ This new Action Keyword is already assigned to another plugin, please choose a different one Success Completed successfully - Enter the action keyword you like to use to start the plugin. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords. + Enter the action keywords you like to use to start the plugin and use whitespace to divide them. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords. Custom Query Hotkey From 414684ce43b78452a544dcb12cef8abd1af9e5ee Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 21 Feb 2025 13:50:44 +0800 Subject: [PATCH 10/24] Replace action keyword function with api --- .../Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs | 2 +- Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs index f79176f99..fa53e5f5a 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs @@ -83,7 +83,7 @@ namespace Flow.Launcher.Plugin.WebSearch if (!_context.API.ActionKeywordAssigned(keyword)) { var id = _context.CurrentPluginMetadata.ID; - PluginManager.AddActionKeyword(id, keyword); + _context.API.AddActionKeyword(id, keyword); _searchSources.Add(_searchSource); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs index 739bc9d6b..5efe46a9d 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs @@ -40,7 +40,7 @@ namespace Flow.Launcher.Plugin.WebSearch if (result == MessageBoxResult.Yes) { var id = _context.CurrentPluginMetadata.ID; - PluginManager.RemoveActionKeyword(id, selected.ActionKeyword); + _context.API.RemoveActionKeyword(id, selected.ActionKeyword); _settings.SearchSources.Remove(selected); } } From 463293214b08e49a9a0f0d9be33aea04aecdee98 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Feb 2025 12:32:06 +0800 Subject: [PATCH 11/24] Revert "Remove useless * keywords" and do not let users change action keywords of Explorer --- Plugins/Flow.Launcher.Plugin.Explorer/plugin.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index 89eaa657d..7b067f576 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json @@ -2,8 +2,12 @@ "ID": "572be03c74c642baae319fc283e561a8", "ActionKeywords": [ "*", - "doc:" + "doc:", + "*", + "*", + "*" ], + "AllowModifyActionKeywords": false, "Name": "Explorer", "Description": "Find and manage files and folders via Windows Search or Everything", "Author": "Jeremy Wu", From 87febda78f7842ff018fe0718492e850ce164414 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Feb 2025 12:49:21 +0800 Subject: [PATCH 12/24] Add ReplaceActionKeyword api function --- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 9 ++++++++- Flow.Launcher/PublicAPIInstance.cs | 4 +++- .../Flow.Launcher.Plugin.WebSearch.csproj | 1 - .../SearchSourceSetting.xaml.cs | 3 +-- .../SettingsControl.xaml.cs | 1 - 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 8376fd07b..da6bb598b 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -151,7 +151,6 @@ namespace Flow.Launcher.Plugin /// public void RemoveGlobalKeyboardCallback(Func callback); - /// /// Fuzzy Search the string with the given query. This is the core search mechanism Flow uses /// @@ -334,5 +333,13 @@ namespace Flow.Launcher.Plugin /// When user closes the progress box manually by button or esc key, this action will be called. /// A progress box interface. public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null); + + /// + /// Replace ActionKeyword for specific plugin + /// + /// ID for plugin that needs to remove action keyword + /// The actionkeyword that is supposed to be removed + /// The actionkeyword that is supposed to be added + public void ReplaceActionKeyword(string pluginId, string oldActionKeyword, string newActionKeyword); } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 7706a64ba..b6f3b0d27 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -26,6 +26,7 @@ using System.Collections.Concurrent; using System.Diagnostics; using System.Collections.Specialized; using Flow.Launcher.Core; +using Flow.Launcher.Infrastructure.UserSettings; namespace Flow.Launcher { @@ -311,7 +312,6 @@ namespace Flow.Launcher return _mainVM.GameModeStatus; } - private readonly List> _globalKeyboardHandlers = new(); public void RegisterGlobalKeyboardCallback(Func callback) => _globalKeyboardHandlers.Add(callback); @@ -326,6 +326,8 @@ namespace Flow.Launcher public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, forceClosed); + public void ReplaceActionKeyword(string pluginId, string oldActionKeyword, string newActionKeyword) => PluginManager.ReplaceActionKeyword(pluginId, oldActionKeyword, newActionKeyword); + #endregion #region Private Methods diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj index 55d69d526..c2d0a46a0 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj @@ -51,7 +51,6 @@ - diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs index fa53e5f5a..d3d18d0d2 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs @@ -1,7 +1,6 @@ using System.Collections.Generic; using System.Windows; using Microsoft.Win32; -using Flow.Launcher.Core.Plugin; namespace Flow.Launcher.Plugin.WebSearch { @@ -103,7 +102,7 @@ namespace Flow.Launcher.Plugin.WebSearch if (!_context.API.ActionKeywordAssigned(newKeyword) || oldKeyword == newKeyword) { var id = _context.CurrentPluginMetadata.ID; - PluginManager.ReplaceActionKeyword(id, oldKeyword, newKeyword); + _context.API.ReplaceActionKeyword(id, oldKeyword, newKeyword); var index = _searchSources.IndexOf(_oldSearchSource); _searchSources[index] = _searchSource; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs index 5efe46a9d..e53f4ec75 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs @@ -1,6 +1,5 @@ using System.Windows; using System.Windows.Controls; -using Flow.Launcher.Core.Plugin; using System.ComponentModel; using System.Windows.Data; From 34cb078602f3c04ff428123415ac55e97e9b9daf Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Feb 2025 14:06:58 +0800 Subject: [PATCH 13/24] Check old action keyword out of PluginManager --- Flow.Launcher.Core/Plugin/PluginManager.cs | 18 ------------------ Flow.Launcher/ActionKeywords.xaml.cs | 22 +++++++++++++++++++++- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 18519c85d..9a37f6fe5 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -340,24 +340,6 @@ namespace Flow.Launcher.Core.Plugin return results; } - public static bool ActionKeywordRegistered(IReadOnlyList newActionKeywords, IReadOnlyList oldActionKeywords) - { - foreach (var actionKeyword in newActionKeywords) - { - if (ActionKeywordRegistered(actionKeyword, oldActionKeywords)) - { - return true; - } - } - return false; - } - - private static bool ActionKeywordRegistered(string actionKeyword, IReadOnlyList oldActionKeywords) - { - if (oldActionKeywords.Contains(actionKeyword)) return false; - return ActionKeywordRegistered(actionKeyword); - } - public static bool ActionKeywordRegistered(string actionKeyword) { // this method is only checking for action keywords (defined as not '*') registration diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index af6dcfe90..b0e4edbc1 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -5,6 +5,7 @@ using Flow.Launcher.ViewModel; using Flow.Launcher.Core; using System.Linq; using Flow.Launcher.Core.Plugin; +using System.Collections.Generic; namespace Flow.Launcher { @@ -42,7 +43,7 @@ namespace Flow.Launcher newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign }; - if (!PluginManager.ActionKeywordRegistered(newActionKeywords, oldActionKeywords)) + if (!ActionKeywordRegistered(newActionKeywords, oldActionKeywords)) { pluginViewModel.ChangeActionKeyword(newActionKeywords, oldActionKeywords); Close(); @@ -53,5 +54,24 @@ namespace Flow.Launcher MessageBoxEx.Show(msg); } } + + private static bool ActionKeywordRegistered(IReadOnlyList newActionKeywords, IReadOnlyList oldActionKeywords) + { + foreach (var actionKeyword in newActionKeywords) + { + // We need to check if this new action keyword is from the old action keywords because + // we have not changed action keyword yet so PluginManager still has the old action keywords + if (oldActionKeywords.Contains(actionKeyword)) + { + continue; + } + + if (PluginManager.ActionKeywordRegistered(actionKeyword)) + { + return true; + } + } + return false; + } } } From 4ebc19a82d1dbe8f40f434989d182e5049c76d04 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Feb 2025 19:42:43 +0800 Subject: [PATCH 14/24] Check action keywords without order --- Flow.Launcher.Core/Plugin/PluginManager.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 9a37f6fe5..54f6506d9 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -418,11 +418,15 @@ namespace Flow.Launcher.Core.Plugin } } - private static bool CheckActionKeywordChanged(IReadOnlyList oldActionKeyword, IReadOnlyList newActionKeyword) + private static bool CheckActionKeywordChanged(IReadOnlyList oldActionKeywords, IReadOnlyList newActionKeywords) { - if (oldActionKeyword.Count != newActionKeyword.Count) + if (oldActionKeywords.Count != newActionKeywords.Count) return true; - return oldActionKeyword.Where((t, i) => t != newActionKeyword[i]).Any(); + + var sortedOldActionKeywords = oldActionKeywords.OrderBy(s => s).ToList(); + var sortedNewActionKeywords = newActionKeywords.OrderBy(s => s).ToList(); + + return !sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords); } public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword) From 5d67eef57bbce11c496e60b190b3469df09ba489 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Feb 2025 19:43:25 +0800 Subject: [PATCH 15/24] Improve code quality --- Flow.Launcher/ActionKeywords.xaml.cs | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index b0e4edbc1..6ea1dae50 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -42,8 +42,8 @@ namespace Flow.Launcher newActionKeywords = newActionKeywords.Distinct().ToList(); newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign }; - - if (!ActionKeywordRegistered(newActionKeywords, oldActionKeywords)) + + if (!newActionKeywords.Except(oldActionKeywords).Any(PluginManager.ActionKeywordRegistered)) { pluginViewModel.ChangeActionKeyword(newActionKeywords, oldActionKeywords); Close(); @@ -54,24 +54,5 @@ namespace Flow.Launcher MessageBoxEx.Show(msg); } } - - private static bool ActionKeywordRegistered(IReadOnlyList newActionKeywords, IReadOnlyList oldActionKeywords) - { - foreach (var actionKeyword in newActionKeywords) - { - // We need to check if this new action keyword is from the old action keywords because - // we have not changed action keyword yet so PluginManager still has the old action keywords - if (oldActionKeywords.Contains(actionKeyword)) - { - continue; - } - - if (PluginManager.ActionKeywordRegistered(actionKeyword)) - { - return true; - } - } - return false; - } } } From 38402848aa8b5695d7f0b52e888ea793940d4ed1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 23 Feb 2025 23:06:15 +0800 Subject: [PATCH 16/24] Improve code quality for project references --- .../Flow.Launcher.Plugin.Calculator.csproj | 2 ++ .../Flow.Launcher.Plugin.PluginsManager.csproj | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj index 1b985acf9..92719fa54 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -43,6 +43,8 @@ + + diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj index b438305d6..c33c42889 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -19,7 +19,7 @@ - + From 6e763f0c3b0da96e81da29d48dd5c408fd1d68b6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 24 Feb 2025 09:53:00 +0800 Subject: [PATCH 17/24] Remove ReplaceActionKeyword api function & Add action keyword same noticification --- Flow.Launcher.Core/Plugin/PluginManager.cs | 72 ++++--------------- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 12 +--- Flow.Launcher/ActionKeywords.xaml.cs | 39 +++++++++- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/PublicAPIInstance.cs | 2 - Flow.Launcher/ViewModel/PluginViewModel.cs | 4 +- .../SearchSourceSetting.xaml.cs | 4 +- 7 files changed, 57 insertions(+), 77 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 54f6506d9..a32f1d682 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -364,8 +364,16 @@ namespace Flow.Launcher.Core.Plugin NonGlobalPlugins[newActionKeyword] = plugin; } - // Update action keywords in plugin metadata + // Update action keywords and action keyword in plugin metadata plugin.Metadata.ActionKeywords.Add(newActionKeyword); + if (plugin.Metadata.ActionKeywords.Count > 0) + { + plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0]; + } + else + { + plugin.Metadata.ActionKeyword = string.Empty; + } } /// @@ -386,67 +394,15 @@ namespace Flow.Launcher.Core.Plugin if (oldActionkeyword != Query.GlobalPluginWildcardSign) NonGlobalPlugins.Remove(oldActionkeyword); - // Update action keywords in plugin metadata + // Update action keywords and action keyword in plugin metadata plugin.Metadata.ActionKeywords.Remove(oldActionkeyword); - } - - public static void ReplaceActionKeyword(string id, IReadOnlyList oldActionKeywords, IReadOnlyList newActionKeywords) - { - if (CheckActionKeywordChanged(oldActionKeywords, newActionKeywords)) + if (plugin.Metadata.ActionKeywords.Count > 0) { - // Fix collection modified while iterating exception - var oldActionKeywordsClone = oldActionKeywords.ToList(); - foreach (var actionKeyword in oldActionKeywordsClone) - { - RemoveActionKeyword(id, actionKeyword); - } - foreach (var actionKeyword in newActionKeywords) - { - AddActionKeyword(id, actionKeyword); - } - - // Update action keyword in plugin metadata - var plugin = GetPluginForId(id); - if (newActionKeywords.Count > 0) - { - plugin.Metadata.ActionKeyword = newActionKeywords[0]; - } - else - { - plugin.Metadata.ActionKeyword = string.Empty; - } + plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0]; } - } - - private static bool CheckActionKeywordChanged(IReadOnlyList oldActionKeywords, IReadOnlyList newActionKeywords) - { - if (oldActionKeywords.Count != newActionKeywords.Count) - return true; - - var sortedOldActionKeywords = oldActionKeywords.OrderBy(s => s).ToList(); - var sortedNewActionKeywords = newActionKeywords.OrderBy(s => s).ToList(); - - return !sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords); - } - - public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword) - { - if (oldActionKeyword != newActionKeyword) + else { - RemoveActionKeyword(id, oldActionKeyword); - AddActionKeyword(id, newActionKeyword); - - // Update action keyword in plugin metadata - var plugin = GetPluginForId(id); - var newActionKeywords = plugin.Metadata.ActionKeywords; - if (newActionKeywords.Count > 0) - { - plugin.Metadata.ActionKeyword = newActionKeywords[0]; - } - else - { - plugin.Metadata.ActionKeyword = string.Empty; - } + plugin.Metadata.ActionKeyword = string.Empty; } } diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index da6bb598b..4d424dc0b 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -189,14 +189,14 @@ namespace Flow.Launcher.Plugin Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action reportProgress = null, CancellationToken token = default); /// - /// Add ActionKeyword for specific plugin + /// Add ActionKeyword and update action keyword metadata for specific plugin /// /// ID for plugin that needs to add action keyword /// The actionkeyword that is supposed to be added void AddActionKeyword(string pluginId, string newActionKeyword); /// - /// Remove ActionKeyword for specific plugin + /// Remove ActionKeyword and update action keyword metadata for specific plugin /// /// ID for plugin that needs to remove action keyword /// The actionkeyword that is supposed to be removed @@ -333,13 +333,5 @@ namespace Flow.Launcher.Plugin /// When user closes the progress box manually by button or esc key, this action will be called. /// A progress box interface. public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null); - - /// - /// Replace ActionKeyword for specific plugin - /// - /// ID for plugin that needs to remove action keyword - /// The actionkeyword that is supposed to be removed - /// The actionkeyword that is supposed to be added - public void ReplaceActionKeyword(string pluginId, string oldActionKeyword, string newActionKeyword); } } diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index 6ea1dae50..10f3cf4e9 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -45,8 +45,24 @@ namespace Flow.Launcher if (!newActionKeywords.Except(oldActionKeywords).Any(PluginManager.ActionKeywordRegistered)) { - pluginViewModel.ChangeActionKeyword(newActionKeywords, oldActionKeywords); - Close(); + if (oldActionKeywords.Count != newActionKeywords.Count) + { + ReplaceActionKeyword(plugin.Metadata.ID, oldActionKeywords, newActionKeywords); + } + + var sortedOldActionKeywords = oldActionKeywords.OrderBy(s => s).ToList(); + var sortedNewActionKeywords = newActionKeywords.OrderBy(s => s).ToList(); + + if (sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords)) + { + // User just changes the sequence of action keywords + var msg = translater.GetTranslation("newActionKeywordsSameAsOld"); + MessageBoxEx.Show(msg); + } + else + { + ReplaceActionKeyword(plugin.Metadata.ID, oldActionKeywords, newActionKeywords); + } } else { @@ -54,5 +70,24 @@ namespace Flow.Launcher MessageBoxEx.Show(msg); } } + + private void ReplaceActionKeyword(string id, IReadOnlyList oldActionKeywords, IReadOnlyList newActionKeywords) + { + // Because add & remove action keyword will change action keyword metadata, + // so we need to clone it to fix collection modified while iterating exception + var oldActionKeywordsClone = oldActionKeywords.ToList(); + foreach (var actionKeyword in oldActionKeywordsClone) + { + PluginManager.RemoveActionKeyword(id, actionKeyword); + } + foreach (var actionKeyword in newActionKeywords) + { + PluginManager.AddActionKeyword(id, actionKeyword); + } + + // Update action keywords text and close + pluginViewModel.OnActionKeywordsChanged(); + Close(); + } } } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 282d0fb47..b1575b252 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -333,6 +333,7 @@ Can't find specified plugin New Action Keyword can't be empty This new Action Keyword is already assigned to another plugin, please choose a different one + This new Action Keyword is the same as old, please choose a different one Success Completed successfully Enter the action keywords you like to use to start the plugin and use whitespace to divide them. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords. diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index b6f3b0d27..248688f76 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -326,8 +326,6 @@ namespace Flow.Launcher public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action forceClosed = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, forceClosed); - public void ReplaceActionKeyword(string pluginId, string oldActionKeyword, string newActionKeyword) => PluginManager.ReplaceActionKeyword(pluginId, oldActionKeyword, newActionKeyword); - #endregion #region Private Methods diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 63263c768..c726cc343 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -110,9 +110,8 @@ namespace Flow.Launcher.ViewModel public int Priority => PluginPair.Metadata.Priority; public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; } - public void ChangeActionKeyword(IReadOnlyList newActionKeywords, IReadOnlyList oldActionKeywords) + public void OnActionKeywordsChanged() { - PluginManager.ReplaceActionKeyword(PluginPair.Metadata.ID, oldActionKeywords, newActionKeywords); OnPropertyChanged(nameof(ActionKeywordsText)); } @@ -158,5 +157,4 @@ namespace Flow.Launcher.ViewModel changeKeywordsWindow.ShowDialog(); } } - } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs index d3d18d0d2..58577dbc1 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs @@ -15,7 +15,6 @@ namespace Flow.Launcher.Plugin.WebSearch private SearchSourceViewModel _viewModel; private string selectedNewIconImageFullPath; - public SearchSourceSettingWindow(IList sources, PluginInitContext context, SearchSource old) { _oldSearchSource = old; @@ -102,7 +101,8 @@ namespace Flow.Launcher.Plugin.WebSearch if (!_context.API.ActionKeywordAssigned(newKeyword) || oldKeyword == newKeyword) { var id = _context.CurrentPluginMetadata.ID; - _context.API.ReplaceActionKeyword(id, oldKeyword, newKeyword); + _context.API.RemoveActionKeyword(id, oldKeyword); + _context.API.AddActionKeyword(id, newKeyword); var index = _searchSources.IndexOf(_oldSearchSource); _searchSources[index] = _searchSource; From 2741366a3f3aa66da0c6d7c1f715752f9fbbe5de Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 24 Feb 2025 10:01:52 +0800 Subject: [PATCH 18/24] Improve code quality --- Flow.Launcher/ActionKeywords.xaml.cs | 25 +++++++++++----------- Flow.Launcher/ViewModel/PluginViewModel.cs | 2 -- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index 10f3cf4e9..80a4abef1 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -4,7 +4,6 @@ using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; using Flow.Launcher.Core; using System.Linq; -using Flow.Launcher.Core.Plugin; using System.Collections.Generic; namespace Flow.Launcher @@ -43,11 +42,14 @@ namespace Flow.Launcher newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign }; - if (!newActionKeywords.Except(oldActionKeywords).Any(PluginManager.ActionKeywordRegistered)) + var addedActionKeywords = newActionKeywords.Except(oldActionKeywords).ToList(); + var removedActionKeywords = oldActionKeywords.Except(newActionKeywords).ToList(); + if (!addedActionKeywords.Any(App.API.ActionKeywordAssigned)) { if (oldActionKeywords.Count != newActionKeywords.Count) { - ReplaceActionKeyword(plugin.Metadata.ID, oldActionKeywords, newActionKeywords); + ReplaceActionKeyword(plugin.Metadata.ID, removedActionKeywords, addedActionKeywords); + return; } var sortedOldActionKeywords = oldActionKeywords.OrderBy(s => s).ToList(); @@ -61,7 +63,7 @@ namespace Flow.Launcher } else { - ReplaceActionKeyword(plugin.Metadata.ID, oldActionKeywords, newActionKeywords); + ReplaceActionKeyword(plugin.Metadata.ID, removedActionKeywords, addedActionKeywords); } } else @@ -71,21 +73,18 @@ namespace Flow.Launcher } } - private void ReplaceActionKeyword(string id, IReadOnlyList oldActionKeywords, IReadOnlyList newActionKeywords) + private void ReplaceActionKeyword(string id, IReadOnlyList removedActionKeywords, IReadOnlyList addedActionKeywords) { - // Because add & remove action keyword will change action keyword metadata, - // so we need to clone it to fix collection modified while iterating exception - var oldActionKeywordsClone = oldActionKeywords.ToList(); - foreach (var actionKeyword in oldActionKeywordsClone) + foreach (var actionKeyword in removedActionKeywords) { - PluginManager.RemoveActionKeyword(id, actionKeyword); + App.API.RemoveActionKeyword(id, actionKeyword); } - foreach (var actionKeyword in newActionKeywords) + foreach (var actionKeyword in addedActionKeywords) { - PluginManager.AddActionKeyword(id, actionKeyword); + App.API.AddActionKeyword(id, actionKeyword); } - // Update action keywords text and close + // Update action keywords text and close window pluginViewModel.OnActionKeywordsChanged(); Close(); } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index c726cc343..9b717216a 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -8,7 +8,6 @@ using System.Windows.Controls; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Resource; using Flow.Launcher.Resources.Controls; -using System.Collections.Generic; namespace Flow.Launcher.ViewModel { @@ -44,7 +43,6 @@ namespace Flow.Launcher.ViewModel } } - private async void LoadIconAsync() { Image = await ImageLoader.LoadAsync(PluginPair.Metadata.IcoPath); From afce7022e92f7ad3053a8852384d480a74602195 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 25 Feb 2025 15:46:45 +0800 Subject: [PATCH 19/24] Improve documents --- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index 4d424dc0b..36c291585 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -190,6 +190,7 @@ namespace Flow.Launcher.Plugin /// /// Add ActionKeyword and update action keyword metadata for specific plugin + /// Before adding, please check if action keyword is already assigned by /// /// ID for plugin that needs to add action keyword /// The actionkeyword that is supposed to be added From f7b1190f9563e188fa4d733f1fa7d9b6c0b1c3cc Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 26 Feb 2025 22:03:26 +0800 Subject: [PATCH 20/24] Add global search panel --- Flow.Launcher/ActionKeywords.xaml.cs | 18 ++- Flow.Launcher/Languages/en.xaml | 1 + .../InstalledPluginDisplayKeyword.xaml | 106 ++++++++++++------ Flow.Launcher/ViewModel/PluginViewModel.cs | 17 +++ 4 files changed, 105 insertions(+), 37 deletions(-) diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index 80a4abef1..4b678f42d 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -77,11 +77,25 @@ namespace Flow.Launcher { foreach (var actionKeyword in removedActionKeywords) { - App.API.RemoveActionKeyword(id, actionKeyword); + if (actionKeyword == Query.GlobalPluginWildcardSign) + { + pluginViewModel.GlobalSearch = false; + } + else + { + App.API.RemoveActionKeyword(id, actionKeyword); + } } foreach (var actionKeyword in addedActionKeywords) { - App.API.AddActionKeyword(id, actionKeyword); + if (actionKeyword == Query.GlobalPluginWildcardSign) + { + pluginViewModel.GlobalSearch = true; + } + else + { + App.API.AddActionKeyword(id, actionKeyword); + } } // Update action keywords text and close window diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index b1575b252..f2eeb2de5 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -114,6 +114,7 @@ Off Action keyword Setting Action keyword + Global search Current action keyword New action keyword Change Action Keywords diff --git a/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml b/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml index ff2f14c4b..197e9ddef 100644 --- a/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml +++ b/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml @@ -4,44 +4,80 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:ui="http://schemas.modernwpf.com/2019" xmlns:viewModel="clr-namespace:Flow.Launcher.ViewModel" d:DataContext="{d:DesignInstance viewModel:PluginViewModel}" d:DesignHeight="300" d:DesignWidth="300" mc:Ignorable="d"> - - - -  - - -