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.
This commit is contained in:
Jack251970 2025-10-05 20:50:08 +08:00
parent f5e5fe5780
commit cb6b0a0a64

View file

@ -6,11 +6,14 @@ using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Plugin; using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.Image;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
using Flow.Launcher.Resources.Controls; using Flow.Launcher.Resources.Controls;
using Flow.Launcher.SettingPages.ViewModels; using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel; using Flow.Launcher.ViewModel;
using iNKORE.UI.WPF.Modern.Controls; using iNKORE.UI.WPF.Modern.Controls;
using System.Threading.Tasks;
using System.Windows.Media;
namespace Flow.Launcher.SettingPages.Views; namespace Flow.Launcher.SettingPages.Views;
@ -53,8 +56,10 @@ public partial class SettingsPaneHotkey
var excard = new SettingsExpander() var excard = new SettingsExpander()
{ {
Header = metadata.Name, Header = metadata.Name + " " + Localize.hotkeys(),
Margin = new Thickness(0, 4, 0, 0) Margin = new Thickness(0, 4, 0, 0),
HeaderIcon = new Image() { Source = ImageLoader.LoadingImage },
Tag = metadata
}; };
var sortedHotkeyInfo = hotkeyInfo.OrderBy(h => h.Id).ToList(); var sortedHotkeyInfo = hotkeyInfo.OrderBy(h => h.Id).ToList();
@ -96,6 +101,9 @@ public partial class SettingsPaneHotkey
} }
PluginHotkeySettings.Children.Add(excard); PluginHotkeySettings.Children.Add(excard);
} }
// Load plugin icons into SettingsExpander asynchronously
_ = LoadPluginIconsAsync();
} }
private static void ChangePluginHotkey(PluginMetadata metadata, BasePluginHotkey pluginHotkey, HotkeyModel newHotkey) private static void ChangePluginHotkey(PluginMetadata metadata, BasePluginHotkey pluginHotkey, HotkeyModel newHotkey)
@ -109,4 +117,52 @@ public partial class SettingsPaneHotkey
PluginManager.ChangePluginHotkey(metadata, windowPluginHotkey, newHotkey); PluginManager.ChangePluginHotkey(metadata, windowPluginHotkey, newHotkey);
} }
} }
private async Task LoadPluginIconsAsync()
{
// Snapshot list to avoid collection modification issues
var expanders = PluginHotkeySettings.Children
.OfType<SettingsExpander>()
.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 };
}
}
} }