diff --git a/Flow.Launcher/Images/mainsearch.png b/Doc/mainsearch.png
similarity index 100%
rename from Flow.Launcher/Images/mainsearch.png
rename to Doc/mainsearch.png
diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs
index 3dba35f8d..de6ed1b29 100644
--- a/Flow.Launcher.Infrastructure/Constant.cs
+++ b/Flow.Launcher.Infrastructure/Constant.cs
@@ -30,7 +30,7 @@ namespace Flow.Launcher.Infrastructure
public static string PythonPath;
- public static readonly string QueryTextBoxIconImagePath = $"{ProgramDirectory}\\Images\\mainsearch.png";
+ public static readonly string QueryTextBoxIconImagePath = $"{ProgramDirectory}\\Images\\mainsearch.svg";
public const string DefaultTheme = "Darker";
diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs
index 4abf0e832..4212a1ab2 100644
--- a/Flow.Launcher.Infrastructure/Http/Http.cs
+++ b/Flow.Launcher.Infrastructure/Http/Http.cs
@@ -76,23 +76,31 @@ namespace Flow.Launcher.Infrastructure.Http
};
}
- public static async Task Download([NotNull] string url, [NotNull] string filePath)
+ public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath)
{
- using var response = await client.GetAsync(url);
- if (response.StatusCode == HttpStatusCode.OK)
+ try
{
- await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
- await response.Content.CopyToAsync(fileStream);
+ using var response = await client.GetAsync(url);
+ if (response.StatusCode == HttpStatusCode.OK)
+ {
+ await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
+ await response.Content.CopyToAsync(fileStream);
+ }
+ else
+ {
+ throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>");
+ }
}
- else
+ catch (HttpRequestException e)
{
- throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>");
+ Log.Exception("Infrastructure.Http", "Http Request Error", e, "DownloadAsync");
+ throw;
}
}
///
/// Asynchrously get the result as string from url.
- /// When supposing the result is long and large, try using GetStreamAsync to avoid reading as string
+ /// When supposing the result larger than 83kb, try using GetStreamAsync to avoid reading as string
///
///
/// The Http result as string. Null if cancellation requested
diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj
index 39b2087aa..0f8e6a767 100644
--- a/Flow.Launcher/Flow.Launcher.csproj
+++ b/Flow.Launcher/Flow.Launcher.csproj
@@ -82,6 +82,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/Flow.Launcher/Images/mainsearch.svg b/Flow.Launcher/Images/mainsearch.svg
new file mode 100644
index 000000000..5d28abdb3
--- /dev/null
+++ b/Flow.Launcher/Images/mainsearch.svg
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index adb49b65d..6ee28e3ba 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -72,7 +72,7 @@
Are you sure you want to delete {0} plugin hotkey?
Query window shadow effect
Shadow effect has a substantial usage of GPU.
- Not recommended if you computer performance is limited.
+ Not recommended if your computer performance is limited.
HTTP Proxy
diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml
index 07bb96339..a2cfe569d 100644
--- a/Flow.Launcher/MainWindow.xaml
+++ b/Flow.Launcher/MainWindow.xaml
@@ -6,6 +6,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
+ xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
mc:Ignorable="d"
Title="Flow Launcher"
Topmost="True"
@@ -92,7 +93,8 @@
-
+
-
+
diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index f9c152046..da977f11f 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -285,7 +285,7 @@ namespace Flow.Launcher.ViewModel
public string OpenResultCommandModifiers { get; private set; }
- public ImageSource Image => ImageLoader.Load(Constant.QueryTextBoxIconImagePath);
+ public string Image => Constant.QueryTextBoxIconImagePath;
#endregion
diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs
index 00a0e1ae5..4c65f2b9f 100644
--- a/Flow.Launcher/ViewModel/ResultViewModel.cs
+++ b/Flow.Launcher/ViewModel/ResultViewModel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
@@ -12,9 +13,9 @@ namespace Flow.Launcher.ViewModel
{
public class ResultViewModel : BaseModel
{
- public class LazyAsync : Lazy>
+ public class LazyAsync : Lazy>
{
- private T defaultValue;
+ private readonly T defaultValue;
private readonly Action _updateCallback;
public new T Value
@@ -23,21 +24,27 @@ namespace Flow.Launcher.ViewModel
{
if (!IsValueCreated)
{
- base.Value.ContinueWith(_ =>
- {
- _updateCallback();
- });
+ _ = Exercute(); // manually use callback strategy
return defaultValue;
}
-
- if (!base.Value.IsCompleted || base.Value.IsFaulted)
+
+ if (!base.Value.IsCompletedSuccessfully)
return defaultValue;
return base.Value.Result;
+
+ // If none of the variables captured by the local function are captured by other lambdas,
+ // the compiler can avoid heap allocations.
+ async ValueTask Exercute()
+ {
+ await base.Value.ConfigureAwait(false);
+ _updateCallback();
+ }
+
}
}
- public LazyAsync(Func> factory, T defaultValue, Action updateCallback) : base(factory)
+ public LazyAsync(Func> factory, T defaultValue, Action updateCallback) : base(factory)
{
if (defaultValue != null)
{
@@ -55,13 +62,13 @@ namespace Flow.Launcher.ViewModel
Result = result;
Image = new LazyAsync(
- SetImage,
+ SetImage,
ImageLoader.DefaultImage,
() =>
{
OnPropertyChanged(nameof(Image));
});
- }
+ }
Settings = settings;
}
@@ -82,7 +89,7 @@ namespace Flow.Launcher.ViewModel
public LazyAsync Image { get; set; }
- private async Task SetImage()
+ private async ValueTask SetImage()
{
var imagePath = Result.IcoPath;
if (string.IsNullOrEmpty(imagePath) && Result.Icon != null)
@@ -94,7 +101,7 @@ namespace Flow.Launcher.ViewModel
catch (Exception e)
{
Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e);
- imagePath = Constant.MissingImgIcon;
+ return ImageLoader.DefaultImage;
}
}
diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
index c122f8037..c43167e09 100644
--- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
+++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
@@ -438,7 +438,7 @@ namespace Flow.Launcher.ViewModel
}
}
- public ImageSource ThemeImage => ImageLoader.Load(Constant.QueryTextBoxIconImagePath);
+ public string ThemeImage => Constant.QueryTextBoxIconImagePath;
#endregion
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
index 880157a77..68df5bc1f 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
@@ -127,7 +127,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
Context.API.GetTranslation("plugin_pluginsmanager_please_wait"));
- await Http.Download(plugin.UrlDownload, filePath).ConfigureAwait(false);
+ await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
Context.API.GetTranslation("plugin_pluginsmanager_download_success"));
@@ -214,11 +214,23 @@ namespace Flow.Launcher.Plugin.PluginsManager
Task.Run(async delegate
{
- await Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath).ConfigureAwait(false);
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
+ Context.API.GetTranslation("plugin_pluginsmanager_please_wait"));
+
+ await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath).ConfigureAwait(false);
+
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
+ Context.API.GetTranslation("plugin_pluginsmanager_download_success"));
+
Install(x.PluginNewUserPlugin, downloadToFilePath);
Context.API.RestartApp();
- });
+ }).ContinueWith(t =>
+ {
+ Log.Exception("PluginsManager", $"Update failed for {x.Name}", t.Exception.InnerException, "RequestUpdate");
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_install_error_title"),
+ string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"), x.Name));
+ }, TaskContinuationOptions.OnlyOnFaulted);
return true;
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
index f5bbf3f6b..ef2c1255a 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
@@ -6,7 +6,7 @@
"Name": "Plugins Manager",
"Description": "Management of installing, uninstalling or updating Flow Launcher plugins",
"Author": "Jeremy Wu",
- "Version": "1.4.0",
+ "Version": "1.4.1",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll",