diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index c8d3ffbc470..01abf8995fc 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -284,7 +284,7 @@ public static bool TryGetValue(string path, bool loadFullImage, out ImageSource return ImageCache.TryGetValue(path, loadFullImage, out image); } - public static async ValueTask LoadAsync(string path, bool loadFullImage = false) + public static async ValueTask LoadAsync(string path, bool loadFullImage = false, bool cacheImage = true) { var imageResult = await LoadInternalAsync(path, loadFullImage); @@ -300,16 +300,18 @@ public static async ValueTask LoadAsync(string path, bool loadFullI // image already exists img = ImageCache[key, loadFullImage] ?? img; } - else + else if (cacheImage) { - // new guid - + // save guid key GuidToKey[hash] = path; } } - // update cache - ImageCache[path, loadFullImage] = img; + if (cacheImage) + { + // update cache + ImageCache[path, loadFullImage] = img; + } } return img; diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index eeb3f5de3ae..1620d373a3c 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -8,6 +8,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; namespace Flow.Launcher.Plugin { @@ -346,6 +347,20 @@ public interface IPublicAPI public void StopLoadingBar(); /// + /// Load image from path. Support local, remote and data:image url. + /// If image path is missing, it will return a missing icon. + /// + /// The path of the image. + /// + /// Load full image or not. + /// + /// + /// Cache the image or not. Cached image will be stored in FL cache. + /// If the image is just used one time, it's better to set this to false. + /// + /// + ValueTask LoadImageAsync(string path, bool loadFullImage = false, bool cacheImage = true); + /// Update the plugin manifest /// /// diff --git a/Flow.Launcher/MessageBoxEx.xaml.cs b/Flow.Launcher/MessageBoxEx.xaml.cs index e9b434fd97b..3d94769d002 100644 --- a/Flow.Launcher/MessageBoxEx.xaml.cs +++ b/Flow.Launcher/MessageBoxEx.xaml.cs @@ -156,7 +156,7 @@ private static async Task SetImageOfMessageBoxAsync(MessageBoxImage icon) private async Task SetImageAsync(string imageName) { var imagePath = Path.Combine(Constant.ProgramDirectory, "Images", imageName); - var imageSource = await ImageLoader.LoadAsync(imagePath); + var imageSource = await App.API.LoadImageAsync(imagePath); Img.Source = imageSource; } diff --git a/Flow.Launcher/Msg.xaml.cs b/Flow.Launcher/Msg.xaml.cs index 94184ff6377..ff9accd62f2 100644 --- a/Flow.Launcher/Msg.xaml.cs +++ b/Flow.Launcher/Msg.xaml.cs @@ -43,7 +43,7 @@ public Msg() private async System.Threading.Tasks.Task LoadImageAsync() { - imgClose.Source = await ImageLoader.LoadAsync(Path.Combine(Infrastructure.Constant.ProgramDirectory, "Images\\close.png")); + imgClose.Source = await App.API.LoadImageAsync(Path.Combine(Constant.ProgramDirectory, "Images\\close.png")); } void imgClose_MouseUp(object sender, MouseButtonEventArgs e) @@ -71,11 +71,11 @@ public async void Show(string title, string subTitle, string iconPath) if (!File.Exists(iconPath)) { - imgIco.Source = await ImageLoader.LoadAsync(Path.Combine(Constant.ProgramDirectory, "Images\\app.png")); + imgIco.Source = await App.API.LoadImageAsync(Path.Combine(Constant.ProgramDirectory, "Images\\app.png")); } else { - imgIco.Source = await ImageLoader.LoadAsync(iconPath); + imgIco.Source = await App.API.LoadImageAsync(iconPath); } Show(); diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index c40e40ebbae..e3bbc2eeea7 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Media; using CommunityToolkit.Mvvm.DependencyInjection; using Squirrel; using Flow.Launcher.Core; @@ -355,6 +356,9 @@ public MessageBoxResult ShowMsgBox(string messageBoxText, string caption = "", M public Task ShowProgressBoxAsync(string caption, Func, Task> reportProgressAsync, Action cancelProgress = null) => ProgressBoxEx.ShowAsync(caption, reportProgressAsync, cancelProgress); + public ValueTask LoadImageAsync(string path, bool loadFullImage = false, bool cacheImage = true) => + ImageLoader.LoadAsync(path, loadFullImage, cacheImage); + public Task UpdatePluginManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default) => PluginsManifest.UpdateManifestAsync(usePrimaryUrlOnly, token); diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 17e4b55b71e..bfa5bd5042a 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1168,7 +1168,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b else if (plugins.Count == 1) { PluginIconPath = plugins.Single().Metadata.IcoPath; - PluginIconSource = await ImageLoader.LoadAsync(PluginIconPath); + PluginIconSource = await App.API.LoadImageAsync(PluginIconPath); SearchIconVisibility = Visibility.Hidden; } else diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index e91badb3894..93a595de41e 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -45,7 +45,7 @@ private static string PluginManagerActionKeyword private async Task LoadIconAsync() { - Image = await ImageLoader.LoadAsync(PluginPair.Metadata.IcoPath); + Image = await App.API.LoadImageAsync(PluginPair.Metadata.IcoPath); OnPropertyChanged(nameof(Image)); } diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index db124e0788a..9aab71a328e 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -199,7 +199,7 @@ private async Task LoadImageInternalAsync(string imagePath, Result. } } - return await ImageLoader.LoadAsync(imagePath, loadFullImage).ConfigureAwait(false); + return await App.API.LoadImageAsync(imagePath, loadFullImage).ConfigureAwait(false); } private async Task LoadImageAsync() diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index 878832e4fb8..aaf1efdc1fd 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -7,7 +7,6 @@ using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; -using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Plugin.Explorer.Search; namespace Flow.Launcher.Plugin.Explorer.Views; @@ -89,7 +88,7 @@ public PreviewPanel(Settings settings, string filePath) private async Task LoadImageAsync() { - PreviewImage = await ImageLoader.LoadAsync(FilePath, true).ConfigureAwait(false); + PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false); } public event PropertyChangedEventHandler? PropertyChanged; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs index 9c5e81cb537..6554edd837b 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Infrastructure.Image; -using System; +using System; using System.IO; using System.Threading.Tasks; #pragma warning disable IDE0005 @@ -41,8 +40,8 @@ public void CopyNewImageToUserDataDirectoryIfRequired( #if DEBUG throw; #else - Main._context.API.ShowMsgBox(string.Format("Copying the selected image file to {0} has failed, changes will now be reverted", destinationFileNameFullPath)); - UpdateIconAttributes(selectedSearchSource, fullPathToOriginalImage); + Main._context.API.ShowMsgBox(string.Format("Copying the selected image file to {0} has failed, changes will now be reverted", destinationFileNameFullPath)); + UpdateIconAttributes(selectedSearchSource, fullPathToOriginalImage); #endif } } @@ -61,7 +60,7 @@ internal bool ShouldProvideHint(string fullPathToSelectedImage) internal async ValueTask LoadPreviewIconAsync(string pathToPreviewIconImage) { - return await ImageLoader.LoadAsync(pathToPreviewIconImage); + return await Main._context.API.LoadImageAsync(pathToPreviewIconImage); } } } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index 51f81b718f5..65be06b53ee 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -4,8 +4,6 @@ using System.Text.Json; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Flow.Launcher.Infrastructure.Http; -using Flow.Launcher.Infrastructure.Logger; using System.Net.Http; using System.Threading; @@ -22,11 +20,11 @@ public override async Task> SuggestionsAsync(string query, Cancella try { const string api = "http://suggestion.baidu.com/su?json=1&wd="; - result = await Http.GetAsync(api + Uri.EscapeDataString(query), token).ConfigureAwait(false); + result = await Main._context.API.HttpGetStringAsync(api + Uri.EscapeDataString(query), token).ConfigureAwait(false); } catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { - Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); + Main._context.API.LogException(nameof(Baidu), "Can't get suggestion from Baidu", e); return null; } @@ -41,7 +39,7 @@ public override async Task> SuggestionsAsync(string query, Cancella } catch (JsonException e) { - Log.Exception("|Baidu.Suggestions|can't parse suggestions", e); + Main._context.API.LogException(nameof(Baidu), "Can't parse suggestions", e); return new List(); } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index 640674243e2..9efc36263c2 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -1,6 +1,4 @@ -using Flow.Launcher.Infrastructure.Http; -using Flow.Launcher.Infrastructure.Logger; -using System; +using System; using System.Collections.Generic; using System.Net.Http; using System.Threading.Tasks; @@ -10,16 +8,15 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { - class Bing : SuggestionSource + public class Bing : SuggestionSource { public override async Task> SuggestionsAsync(string query, CancellationToken token) { - try { const string api = "https://api.bing.com/qsonhs.aspx?q="; - await using var resultStream = await Http.GetStreamAsync(api + Uri.EscapeDataString(query), token).ConfigureAwait(false); + await using var resultStream = await Main._context.API.HttpGetStreamAsync(api + Uri.EscapeDataString(query), token).ConfigureAwait(false); using var json = (await JsonDocument.ParseAsync(resultStream, cancellationToken: token)); var root = json.RootElement.GetProperty("AS"); @@ -33,18 +30,15 @@ public override async Task> SuggestionsAsync(string query, Cancella .EnumerateArray() .Select(s => s.GetProperty("Txt").GetString())) .ToList(); - - - } catch (Exception e) when (e is HttpRequestException or { InnerException: TimeoutException }) { - Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); + Main._context.API.LogException(nameof(Bing), "Can't get suggestion from Bing", e); return null; } catch (JsonException e) { - Log.Exception("|Bing.Suggestions|can't parse suggestions", e); + Main._context.API.LogException(nameof(Bing), "Can't parse suggestions", e); return new List(); } } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/DuckDuckGo.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/DuckDuckGo.cs index 8fafb44cce1..1d248caf37a 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/DuckDuckGo.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/DuckDuckGo.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Flow.Launcher.Infrastructure.Http; -using Flow.Launcher.Infrastructure.Logger; using System.Net.Http; using System.Threading; using System.Text.Json; @@ -25,7 +23,7 @@ public override async Task> SuggestionsAsync(string query, Cancella { const string api = "https://duckduckgo.com/ac/?type=list&q="; - await using var resultStream = await Http.GetStreamAsync(api + Uri.EscapeDataString(query), token: token).ConfigureAwait(false); + await using var resultStream = await Main._context.API.HttpGetStreamAsync(api + Uri.EscapeDataString(query), token: token).ConfigureAwait(false); using var json = await JsonDocument.ParseAsync(resultStream, cancellationToken: token); @@ -36,12 +34,12 @@ public override async Task> SuggestionsAsync(string query, Cancella } catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { - Log.Exception("|DuckDuckGo.Suggestions|Can't get suggestion from DuckDuckGo", e); + Main._context.API.LogException(nameof(DuckDuckGo), "Can't get suggestion from DuckDuckGo", e); return null; } catch (JsonException e) { - Log.Exception("|DuckDuckGo.Suggestions|can't parse suggestions", e); + Main._context.API.LogException(nameof(DuckDuckGo), "Can't parse suggestions", e); return new List(); } } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 265de4a982c..ad8fb508f09 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Flow.Launcher.Infrastructure.Http; -using Flow.Launcher.Infrastructure.Logger; using System.Net.Http; using System.Threading; using System.Text.Json; @@ -18,7 +16,7 @@ public override async Task> SuggestionsAsync(string query, Cancella { const string api = "https://www.google.com/complete/search?output=chrome&q="; - await using var resultStream = await Http.GetStreamAsync(api + Uri.EscapeDataString(query), token: token).ConfigureAwait(false); + await using var resultStream = await Main._context.API.HttpGetStreamAsync(api + Uri.EscapeDataString(query), token: token).ConfigureAwait(false); using var json = await JsonDocument.ParseAsync(resultStream, cancellationToken: token); @@ -29,12 +27,12 @@ public override async Task> SuggestionsAsync(string query, Cancella } catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { - Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); + Main._context.API.LogException(nameof(Google), "Can't get suggestion from Google", e); return null; } catch (JsonException e) { - Log.Exception("|Google.Suggestions|can't parse suggestions", e); + Main._context.API.LogException(nameof(Google), "Can't parse suggestions", e); return new List(); } }