Skip to content

Commit cb6b0a0

Browse files
committed
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.
1 parent f5e5fe5 commit cb6b0a0

File tree

1 file changed

+58
-2
lines changed

1 file changed

+58
-2
lines changed

Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@
66
using CommunityToolkit.Mvvm.Input;
77
using Flow.Launcher.Core.Plugin;
88
using Flow.Launcher.Infrastructure.Hotkey;
9+
using Flow.Launcher.Infrastructure.Image;
910
using Flow.Launcher.Plugin;
1011
using Flow.Launcher.Resources.Controls;
1112
using Flow.Launcher.SettingPages.ViewModels;
1213
using Flow.Launcher.ViewModel;
1314
using iNKORE.UI.WPF.Modern.Controls;
15+
using System.Threading.Tasks;
16+
using System.Windows.Media;
1417

1518
namespace Flow.Launcher.SettingPages.Views;
1619

@@ -53,8 +56,10 @@ private void PluginHotkeySettings_Loaded(object sender, RoutedEventArgs e)
5356

5457
var excard = new SettingsExpander()
5558
{
56-
Header = metadata.Name,
57-
Margin = new Thickness(0, 4, 0, 0)
59+
Header = metadata.Name + " " + Localize.hotkeys(),
60+
Margin = new Thickness(0, 4, 0, 0),
61+
HeaderIcon = new Image() { Source = ImageLoader.LoadingImage },
62+
Tag = metadata
5863
};
5964

6065
var sortedHotkeyInfo = hotkeyInfo.OrderBy(h => h.Id).ToList();
@@ -96,6 +101,9 @@ private void PluginHotkeySettings_Loaded(object sender, RoutedEventArgs e)
96101
}
97102
PluginHotkeySettings.Children.Add(excard);
98103
}
104+
105+
// Load plugin icons into SettingsExpander asynchronously
106+
_ = LoadPluginIconsAsync();
99107
}
100108

101109
private static void ChangePluginHotkey(PluginMetadata metadata, BasePluginHotkey pluginHotkey, HotkeyModel newHotkey)
@@ -109,4 +117,52 @@ private static void ChangePluginHotkey(PluginMetadata metadata, BasePluginHotkey
109117
PluginManager.ChangePluginHotkey(metadata, windowPluginHotkey, newHotkey);
110118
}
111119
}
120+
121+
private async Task LoadPluginIconsAsync()
122+
{
123+
// Snapshot list to avoid collection modification issues
124+
var expanders = PluginHotkeySettings.Children
125+
.OfType<SettingsExpander>()
126+
.Where(e => e.Tag is PluginMetadata m && !string.IsNullOrEmpty(m.IcoPath))
127+
.ToList();
128+
129+
// Fire all loads concurrently
130+
var tasks = expanders.Select(async expander =>
131+
{
132+
if (expander.Tag is not PluginMetadata metadata) return;
133+
try
134+
{
135+
var iconSource = await App.API.LoadImageAsync(metadata.IcoPath);
136+
if (iconSource == null) return;
137+
138+
// Marshal back to UI thread if needed
139+
if (!Dispatcher.CheckAccess())
140+
{
141+
await Dispatcher.InvokeAsync(() => ApplyIcon(expander, iconSource));
142+
}
143+
else
144+
{
145+
ApplyIcon(expander, iconSource);
146+
}
147+
}
148+
catch
149+
{
150+
// Swallow exceptions to avoid impacting UI; optionally log if logging infra exists
151+
}
152+
});
153+
154+
await Task.WhenAll(tasks);
155+
}
156+
157+
private static void ApplyIcon(SettingsExpander expander, ImageSource iconSource)
158+
{
159+
if (expander.HeaderIcon is Image img)
160+
{
161+
img.Source = iconSource;
162+
}
163+
else
164+
{
165+
expander.HeaderIcon = new Image { Source = iconSource };
166+
}
167+
}
112168
}

0 commit comments

Comments
 (0)