From 22c0f59f202e993878ab2a0f884bb78b9a5ee75d Mon Sep 17 00:00:00 2001 From: DB p Date: Thu, 10 Apr 2025 22:06:44 +0900 Subject: [PATCH 01/19] Add badge area in xaml --- Flow.Launcher/ResultListBox.xaml | 95 +++++++++++++++++--------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 4c3bd1d120f..59a16e10cd7 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -90,62 +90,69 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + Date: Fri, 11 Apr 2025 10:37:49 +0800 Subject: [PATCH 02/19] Remove blank lines --- Flow.Launcher/ResultListBox.xaml | 2 -- Flow.Launcher/ViewModel/ResultViewModel.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 59a16e10cd7..b57cb0d40f2 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -151,8 +151,6 @@ - - Date: Fri, 11 Apr 2025 14:51:25 +0800 Subject: [PATCH 03/19] Code quality --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 61566b41571..02fb379fa07 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -19,7 +19,7 @@ public class ResultsViewModel : BaseModel public ResultCollection Results { get; } - private readonly object _collectionLock = new object(); + private readonly object _collectionLock = new(); private readonly Settings _settings; private int MaxResults => _settings?.MaxResultsToShow ?? 6; @@ -89,7 +89,7 @@ public double ItemHeightSize #region Private Methods - private int InsertIndexOf(int newScore, IList list) + private static int InsertIndexOf(int newScore, IList list) { int index = 0; for (; index < list.Count; index++) @@ -118,7 +118,6 @@ private int NewIndex(int i) } } - #endregion #region Public Methods @@ -190,10 +189,10 @@ public void AddResults(ICollection resultsForUpdates, Cancella if (token.IsCancellationRequested) return; - UpdateResults(newResults, token, reselect); + UpdateResults(newResults, reselect, token); } - private void UpdateResults(List newResults, CancellationToken token = default, bool reselect = true) + private void UpdateResults(List newResults, bool reselect = true, CancellationToken token = default) { lock (_collectionLock) { From 47398f104f316675f4193af1ff6df1865f587047 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 14:58:47 +0800 Subject: [PATCH 04/19] Add ShowPluginBadges settings --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 1 + Flow.Launcher/ResultListBox.xaml | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 5 +++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index e304a1b5040..b48f047c5ee 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -101,6 +101,7 @@ public string Theme public bool UseAnimation { get; set; } = true; public bool UseSound { get; set; } = true; public double SoundVolume { get; set; } = 50; + public bool ShowPluginBadges { get; set; } = false; public bool UseClock { get; set; } = true; public bool UseDate { get; set; } = false; diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index b57cb0d40f2..03bff03eb7d 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -146,7 +146,7 @@ VerticalAlignment="Bottom" RenderOptions.BitmapScalingMode="Fant" Source="{Binding Image, TargetNullValue={x:Null}}" - Visibility="{Binding ShowBadge, Converter={StaticResource BoolToVisibilityConverter}}" /> + Visibility="{Binding ShowBadge}" /> diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 0975398dc2e..41e5dd12e23 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -123,6 +123,11 @@ public Visibility ShowGlyph } } + public Visibility ShowBadge + { + get => Settings.ShowPluginBadges ? Visibility.Visible : Visibility.Collapsed; + } + private bool GlyphAvailable => Glyph is not null; private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPath) || Result.Icon is not null; From 579dc061718ac2b151d8b9cf1523fd4c93e0b03f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:00:46 +0800 Subject: [PATCH 05/19] Code quality --- Flow.Launcher.Plugin/Result.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 9104854389d..2e4befdc209 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -60,7 +60,7 @@ public string CopyText /// GlyphInfo is prioritized if not null public string IcoPath { - get { return _icoPath; } + get => _icoPath; set { // As a standard this property will handle prepping and converting to absolute local path for icon image processing @@ -101,7 +101,6 @@ public string IcoPath /// public GlyphInfo Glyph { get; init; } - /// /// An action to take in the form of a function call when the result has been selected. /// @@ -143,7 +142,7 @@ public string IcoPath /// public string PluginDirectory { - get { return _pluginDirectory; } + get => _pluginDirectory; set { _pluginDirectory = value; From 471c3edc6fc679ebfb5b72f5be9ed418c3575bba Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:21:11 +0800 Subject: [PATCH 06/19] Add BadgePath & BadgeIcon property --- Flow.Launcher.Plugin/Result.cs | 150 ++++++++++++++--------- Flow.Launcher/ViewModel/MainViewModel.cs | 11 +- 2 files changed, 102 insertions(+), 59 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 2e4befdc209..7e520175e7e 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -12,12 +12,19 @@ namespace Flow.Launcher.Plugin /// public class Result { + /// + /// Maximum score. This can be useful when set one result to the top by default. This is the score for the results set to the topmost by users. + /// + public const int MaxScore = int.MaxValue; + private string _pluginDirectory; private string _icoPath; private string _copyText = string.Empty; + private string _badgePath; + /// /// The title of the result. This is always required. /// @@ -80,6 +87,33 @@ public string IcoPath } } + /// + /// The image to be displayed for the badge of the result. + /// + /// Can be a local file path or a URL. + /// If null or empty, will use plugin icon + public string BadgePath + { + get => _badgePath; + set + { + // As a standard this property will handle prepping and converting to absolute local path for icon image processing + if (!string.IsNullOrEmpty(value) + && !string.IsNullOrEmpty(PluginDirectory) + && !Path.IsPathRooted(value) + && !value.StartsWith("http://", StringComparison.OrdinalIgnoreCase) + && !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase) + && !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase)) + { + _badgePath = Path.Combine(PluginDirectory, value); + } + else + { + _badgePath = value; + } + } + } + /// /// Determines if Icon has a border radius /// @@ -94,7 +128,12 @@ public string IcoPath /// /// Delegate to load an icon for this result. /// - public IconDelegate Icon; + public IconDelegate Icon { get; set; } + + /// + /// Delegate to load an icon for the badge of this result. + /// + public IconDelegate BadgeIcon { get; set; } /// /// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons) @@ -154,47 +193,6 @@ public string PluginDirectory } } - /// - public override string ToString() - { - return Title + SubTitle + Score; - } - - /// - /// Clones the current result - /// - public Result Clone() - { - return new Result - { - Title = Title, - SubTitle = SubTitle, - ActionKeywordAssigned = ActionKeywordAssigned, - CopyText = CopyText, - AutoCompleteText = AutoCompleteText, - IcoPath = IcoPath, - RoundedIcon = RoundedIcon, - Icon = Icon, - Glyph = Glyph, - Action = Action, - AsyncAction = AsyncAction, - Score = Score, - TitleHighlightData = TitleHighlightData, - OriginQuery = OriginQuery, - PluginDirectory = PluginDirectory, - ContextData = ContextData, - PluginID = PluginID, - TitleToolTip = TitleToolTip, - SubTitleToolTip = SubTitleToolTip, - PreviewPanel = PreviewPanel, - ProgressBar = ProgressBar, - ProgressBarColor = ProgressBarColor, - Preview = Preview, - AddSelectedCount = AddSelectedCount, - RecordKey = RecordKey - }; - } - /// /// Additional data associated with this result /// @@ -223,16 +221,6 @@ public Result Clone() /// public Lazy PreviewPanel { get; set; } - /// - /// Run this result, asynchronously - /// - /// - /// - public ValueTask ExecuteAsync(ActionContext context) - { - return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false); - } - /// /// Progress bar display. Providing an int value between 0-100 will trigger the progress bar to be displayed on the result /// @@ -254,11 +242,6 @@ public ValueTask ExecuteAsync(ActionContext context) /// public bool AddSelectedCount { get; set; } = true; - /// - /// Maximum score. This can be useful when set one result to the top by default. This is the score for the results set to the topmost by users. - /// - public const int MaxScore = int.MaxValue; - /// /// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records. /// This can be useful when your plugin will change the Title or SubTitle of the result dynamically. @@ -267,6 +250,59 @@ public ValueTask ExecuteAsync(ActionContext context) /// public string RecordKey { get; set; } = null; + /// + /// Run this result, asynchronously + /// + /// + /// + public ValueTask ExecuteAsync(ActionContext context) + { + return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false); + } + + /// + public override string ToString() + { + return Title + SubTitle + Score; + } + + /// + /// Clones the current result + /// + public Result Clone() + { + return new Result + { + Title = Title, + SubTitle = SubTitle, + ActionKeywordAssigned = ActionKeywordAssigned, + CopyText = CopyText, + AutoCompleteText = AutoCompleteText, + IcoPath = IcoPath, + BadgePath = BadgePath, + RoundedIcon = RoundedIcon, + Icon = Icon, + BadgeIcon = BadgeIcon, + Glyph = Glyph, + Action = Action, + AsyncAction = AsyncAction, + Score = Score, + TitleHighlightData = TitleHighlightData, + OriginQuery = OriginQuery, + PluginDirectory = PluginDirectory, + ContextData = ContextData, + PluginID = PluginID, + TitleToolTip = TitleToolTip, + SubTitleToolTip = SubTitleToolTip, + PreviewPanel = PreviewPanel, + ProgressBar = ProgressBar, + ProgressBarColor = ProgressBarColor, + Preview = Preview, + AddSelectedCount = AddSelectedCount, + RecordKey = RecordKey + }; + } + /// /// Info of the preview section of a /// diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 4a6c1d63971..38efca72b74 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1268,8 +1268,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) // Task.Yield will force it to run in ThreadPool await Task.Yield(); - IReadOnlyList results = - await PluginManager.QueryForPluginAsync(plugin, query, token); + var results = await PluginManager.QueryForPluginAsync(plugin, query, token); if (token.IsCancellationRequested) return; @@ -1285,6 +1284,14 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) resultsCopy = DeepCloneResults(results, token); } + foreach (var result in results) + { + if (string.IsNullOrEmpty(result.BadgePath)) + { + result.BadgePath = plugin.Metadata.IcoPath; + } + } + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, token, reSelect))) { From b85c2f48f9a3233991671971b9207996582b177d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:35:36 +0800 Subject: [PATCH 07/19] Add related settings in appreance page --- .../UserSettings/Settings.cs | 2 +- Flow.Launcher/Languages/en.xaml | 2 ++ .../SettingPages/Views/SettingsPaneTheme.xaml | 16 ++++++++++++++-- Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index b48f047c5ee..d97a9ed1aee 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -101,7 +101,7 @@ public string Theme public bool UseAnimation { get; set; } = true; public bool UseSound { get; set; } = true; public double SoundVolume { get; set; } = 50; - public bool ShowPluginBadges { get; set; } = false; + public bool ShowBadges { get; set; } = false; public bool UseClock { get; set; } = true; public bool UseDate { get; set; } = false; diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 609859d0dab..66721d8288d 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -283,6 +283,8 @@ Use Segoe Fluent Icons Use Segoe Fluent Icons for query results where supported Press Key + Show Result Badges + Show badges for query results where supported HTTP Proxy diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml index 49306cd2df1..574002a0525 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml @@ -698,11 +698,10 @@ - + + + + + + Settings.ShowPluginBadges ? Visibility.Visible : Visibility.Collapsed; + get => Settings.ShowBadges ? Visibility.Visible : Visibility.Collapsed; } private bool GlyphAvailable => Glyph is not null; From 9e3e0f6e3c561b1106e63e0439162ec3df33a60f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:38:00 +0800 Subject: [PATCH 08/19] Change name to BadgeIcoPath --- Flow.Launcher.Plugin/Result.cs | 12 ++++++------ Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 7e520175e7e..70d11dadd93 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -23,7 +23,7 @@ public class Result private string _copyText = string.Empty; - private string _badgePath; + private string _badgeIcoPath; /// /// The title of the result. This is always required. @@ -92,9 +92,9 @@ public string IcoPath /// /// Can be a local file path or a URL. /// If null or empty, will use plugin icon - public string BadgePath + public string BadgeIcoPath { - get => _badgePath; + get => _badgeIcoPath; set { // As a standard this property will handle prepping and converting to absolute local path for icon image processing @@ -105,11 +105,11 @@ public string BadgePath && !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase)) { - _badgePath = Path.Combine(PluginDirectory, value); + _badgeIcoPath = Path.Combine(PluginDirectory, value); } else { - _badgePath = value; + _badgeIcoPath = value; } } } @@ -279,7 +279,7 @@ public Result Clone() CopyText = CopyText, AutoCompleteText = AutoCompleteText, IcoPath = IcoPath, - BadgePath = BadgePath, + BadgeIcoPath = BadgeIcoPath, RoundedIcon = RoundedIcon, Icon = Icon, BadgeIcon = BadgeIcon, diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 38efca72b74..0abd14ec5e6 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1286,9 +1286,9 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) foreach (var result in results) { - if (string.IsNullOrEmpty(result.BadgePath)) + if (string.IsNullOrEmpty(result.BadgeIcoPath)) { - result.BadgePath = plugin.Metadata.IcoPath; + result.BadgeIcoPath = plugin.Metadata.IcoPath; } } From d338c5551d9cf136fffcf74e269f3446215a09e4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:47:41 +0800 Subject: [PATCH 09/19] Fix badge icon url issue --- Flow.Launcher.Plugin/Result.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 70d11dadd93..ac00d5af5ec 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -188,8 +188,9 @@ public string PluginDirectory // When the Result object is returned from the query call, PluginDirectory is not provided until // UpdatePluginMetadata call is made at PluginManager.cs L196. Once the PluginDirectory becomes available - // we need to update (only if not Uri path) the IcoPath with the full absolute path so the image can be loaded. + // we need to update (only if not Uri path) the IcoPath and BadgeIcoPath with the full absolute path so the image can be loaded. IcoPath = _icoPath; + BadgeIcoPath = _badgeIcoPath; } } From a1ce6b348dbc679bed986de05447e8fb86d7e21b Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:48:49 +0800 Subject: [PATCH 10/19] Fix result badge ico path update issue --- 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 0abd14ec5e6..c1a237c6ad9 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1284,7 +1284,7 @@ async Task QueryTaskAsync(PluginPair plugin, CancellationToken token) resultsCopy = DeepCloneResults(results, token); } - foreach (var result in results) + foreach (var result in resultsCopy) { if (string.IsNullOrEmpty(result.BadgeIcoPath)) { From ec99a365b9d27a708464b4506a41d55259c15961 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:49:39 +0800 Subject: [PATCH 11/19] Support badge path for result update interface --- Flow.Launcher/ViewModel/MainViewModel.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c1a237c6ad9..2155f7bf83c 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -245,6 +245,14 @@ public void RegisterResultsUpdatedEvent() // make a clone to avoid possible issue that plugin will also change the list and items when updating view model var resultsCopy = DeepCloneResults(e.Results, token); + foreach (var result in resultsCopy) + { + if (string.IsNullOrEmpty(result.BadgeIcoPath)) + { + result.BadgeIcoPath = pair.Metadata.IcoPath; + } + } + PluginManager.UpdatePluginMetadata(resultsCopy, pair.Metadata, e.Query); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, token))) From 2eda64aa7af74dad5f3cf21fda8e8a8e6230fe64 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 15:51:26 +0800 Subject: [PATCH 12/19] Support badge icon loading --- Flow.Launcher/ResultListBox.xaml | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 46 ++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 03bff03eb7d..63c461c43ea 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -145,7 +145,7 @@ HorizontalAlignment="Right" VerticalAlignment="Bottom" RenderOptions.BitmapScalingMode="Fant" - Source="{Binding Image, TargetNullValue={x:Null}}" + Source="{Binding BadgeImage, TargetNullValue={x:Null}}" Visibility="{Binding ShowBadge}" /> diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 61e228de1bc..4137d5f58ed 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -125,13 +125,21 @@ public Visibility ShowGlyph public Visibility ShowBadge { - get => Settings.ShowBadges ? Visibility.Visible : Visibility.Collapsed; + get + { + if (Settings.ShowBadges && BadgeIconAvailable) + return Visibility.Visible; + + return Visibility.Collapsed; + } } private bool GlyphAvailable => Glyph is not null; private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPath) || Result.Icon is not null; + private bool BadgeIconAvailable => !string.IsNullOrEmpty(Result.BadgeIcoPath) || Result.BadgeIcon is not null; + private bool PreviewImageAvailable => !string.IsNullOrEmpty(Result.Preview.PreviewImagePath) || Result.Preview.PreviewDelegate != null; public string OpenResultModifiers => Settings.OpenResultModifiers; @@ -145,9 +153,11 @@ public Visibility ShowBadge : Result.SubTitleToolTip; private volatile bool _imageLoaded; + private volatile bool _badgeImageLoaded; private volatile bool _previewImageLoaded; private ImageSource _image = ImageLoader.LoadingImage; + private ImageSource _badgeImage = ImageLoader.LoadingImage; private ImageSource _previewImage = ImageLoader.LoadingImage; public ImageSource Image @@ -165,6 +175,21 @@ public ImageSource Image private set => _image = value; } + public ImageSource BadgeImage + { + get + { + if (!_badgeImageLoaded) + { + _badgeImageLoaded = true; + _ = LoadBadgeImageAsync(); + } + + return _badgeImage; + } + private set => _badgeImage = value; + } + public ImageSource PreviewImage { get @@ -210,7 +235,7 @@ private async Task LoadImageAsync() { var imagePath = Result.IcoPath; var iconDelegate = Result.Icon; - if (ImageLoader.TryGetValue(imagePath, false, out ImageSource img)) + if (ImageLoader.TryGetValue(imagePath, false, out var img)) { _image = img; } @@ -221,11 +246,26 @@ private async Task LoadImageAsync() } } + private async Task LoadBadgeImageAsync() + { + var badgeImagePath = Result.BadgeIcoPath; + var badgeIconDelegate = Result.BadgeIcon; + if (ImageLoader.TryGetValue(badgeImagePath, false, out var img)) + { + _badgeImage = img; + } + else + { + // We need to modify the property not field here to trigger the OnPropertyChanged event + BadgeImage = await LoadImageInternalAsync(badgeImagePath, badgeIconDelegate, false).ConfigureAwait(false); + } + } + private async Task LoadPreviewImageAsync() { var imagePath = Result.Preview.PreviewImagePath ?? Result.IcoPath; var iconDelegate = Result.Preview.PreviewDelegate ?? Result.Icon; - if (ImageLoader.TryGetValue(imagePath, true, out ImageSource img)) + if (ImageLoader.TryGetValue(imagePath, true, out var img)) { _previewImage = img; } From 01f896a57844184fb24e883fe5939c9689d96403 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 16:11:39 +0800 Subject: [PATCH 13/19] Support global query only --- .../UserSettings/Settings.cs | 1 + Flow.Launcher/Languages/en.xaml | 2 ++ .../SettingPages/Views/SettingsPaneTheme.xaml | 23 ++++++++++++++----- Flow.Launcher/ViewModel/ResultViewModel.cs | 11 ++++++--- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index d97a9ed1aee..7c2457a72c7 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -102,6 +102,7 @@ public string Theme public bool UseSound { get; set; } = true; public double SoundVolume { get; set; } = 50; public bool ShowBadges { get; set; } = false; + public bool ShowBadgesGlobalOnly { get; set; } = false; public bool UseClock { get; set; } = true; public bool UseDate { get; set; } = false; diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 66721d8288d..87db45fbe1b 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -285,6 +285,8 @@ Press Key Show Result Badges Show badges for query results where supported + Show Result Badges Only for Global Query + Show badges only for global query results HTTP Proxy diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml index 574002a0525..57c9a5b70dc 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml @@ -711,16 +711,27 @@ - - - + + + + + + + Result.OriginQuery.ActionKeyword == Query.GlobalPluginWildcardSign; + private bool GlyphAvailable => Glyph is not null; private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPath) || Result.Icon is not null; From e6477e886b3e3589727fa8481dd92a98a6206df4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 16:13:55 +0800 Subject: [PATCH 14/19] Fix global query determination issue --- Flow.Launcher/ViewModel/MainViewModel.cs | 6 +++--- Flow.Launcher/ViewModel/ResultViewModel.cs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 2155f7bf83c..f6b9aa67c94 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1208,11 +1208,11 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b _lastQuery = query; - if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign) + if (string.IsNullOrEmpty(query.ActionKeyword)) { - // Wait 45 millisecond for query change in global query + // Wait 15 millisecond for query change in global query // if query changes, return so that it won't be calculated - await Task.Delay(45, _updateSource.Token); + await Task.Delay(15, _updateSource.Token); if (_updateSource.Token.IsCancellationRequested) return; } diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 27b385805c7..68c794aec30 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Drawing.Text; using System.IO; @@ -137,7 +138,7 @@ public Visibility ShowBadge } } - public bool IsGlobalQuery => Result.OriginQuery.ActionKeyword == Query.GlobalPluginWildcardSign; + public bool IsGlobalQuery => string.IsNullOrEmpty(Result.OriginQuery.ActionKeyword); private bool GlyphAvailable => Glyph is not null; From 8aff3c9f2ae49358d59760675c4ab552da865ad4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 11 Apr 2025 16:14:23 +0800 Subject: [PATCH 15/19] Improve strings --- Flow.Launcher/Languages/en.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 87db45fbe1b..024258f1bbc 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -285,8 +285,8 @@ Press Key Show Result Badges Show badges for query results where supported - Show Result Badges Only for Global Query - Show badges only for global query results + Show Result Badges for Global Query Only + Show badges for global query results only HTTP Proxy From c66cbae78bfa96ecbec3a627ac40bed4d2b442ca Mon Sep 17 00:00:00 2001 From: DB p Date: Sat, 12 Apr 2025 00:56:07 +0900 Subject: [PATCH 16/19] - Adjust Badge layout - Fix glyph margin in win11light --- Flow.Launcher/ResultListBox.xaml | 15 +++++---------- Flow.Launcher/Themes/Win11Light.xaml | 4 ++-- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 63c461c43ea..8231027f4d6 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -102,8 +102,6 @@ + + - +