From cb6b0a0a64f435d0ef003c64dd6ef0e3a485ffdd Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 5 Oct 2025 20:50:08 +0800 Subject: [PATCH] Add async plugin icon loading to SettingsExpander Introduced asynchronous loading of plugin icons in `SettingsPaneHotkey.xaml.cs` to enhance UI responsiveness. Added `LoadPluginIconsAsync` to load icons concurrently and apply them to `SettingsExpander` instances. Updated `SettingsExpander` to include a `HeaderIcon` property with a default image. Ensured thread safety when updating UI and handled exceptions gracefully to avoid disruptions. --- .../Views/SettingsPaneHotkey.xaml.cs | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs index ef98b921f..267d51b33 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs @@ -6,11 +6,14 @@ using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure.Hotkey; +using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Plugin; using Flow.Launcher.Resources.Controls; using Flow.Launcher.SettingPages.ViewModels; using Flow.Launcher.ViewModel; using iNKORE.UI.WPF.Modern.Controls; +using System.Threading.Tasks; +using System.Windows.Media; namespace Flow.Launcher.SettingPages.Views; @@ -53,8 +56,10 @@ public partial class SettingsPaneHotkey var excard = new SettingsExpander() { - Header = metadata.Name, - Margin = new Thickness(0, 4, 0, 0) + Header = metadata.Name + " " + Localize.hotkeys(), + Margin = new Thickness(0, 4, 0, 0), + HeaderIcon = new Image() { Source = ImageLoader.LoadingImage }, + Tag = metadata }; var sortedHotkeyInfo = hotkeyInfo.OrderBy(h => h.Id).ToList(); @@ -96,6 +101,9 @@ public partial class SettingsPaneHotkey } PluginHotkeySettings.Children.Add(excard); } + + // Load plugin icons into SettingsExpander asynchronously + _ = LoadPluginIconsAsync(); } private static void ChangePluginHotkey(PluginMetadata metadata, BasePluginHotkey pluginHotkey, HotkeyModel newHotkey) @@ -109,4 +117,52 @@ public partial class SettingsPaneHotkey PluginManager.ChangePluginHotkey(metadata, windowPluginHotkey, newHotkey); } } + + private async Task LoadPluginIconsAsync() + { + // Snapshot list to avoid collection modification issues + var expanders = PluginHotkeySettings.Children + .OfType() + .Where(e => e.Tag is PluginMetadata m && !string.IsNullOrEmpty(m.IcoPath)) + .ToList(); + + // Fire all loads concurrently + var tasks = expanders.Select(async expander => + { + if (expander.Tag is not PluginMetadata metadata) return; + try + { + var iconSource = await App.API.LoadImageAsync(metadata.IcoPath); + if (iconSource == null) return; + + // Marshal back to UI thread if needed + if (!Dispatcher.CheckAccess()) + { + await Dispatcher.InvokeAsync(() => ApplyIcon(expander, iconSource)); + } + else + { + ApplyIcon(expander, iconSource); + } + } + catch + { + // Swallow exceptions to avoid impacting UI; optionally log if logging infra exists + } + }); + + await Task.WhenAll(tasks); + } + + private static void ApplyIcon(SettingsExpander expander, ImageSource iconSource) + { + if (expander.HeaderIcon is Image img) + { + img.Source = iconSource; + } + else + { + expander.HeaderIcon = new Image { Source = iconSource }; + } + } }