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.Core/Plugin/JsonRPCPlugin.cs b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
index 31bf04286..3d4522498 100644
--- a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
+++ b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
+using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
-using Newtonsoft.Json;
using Flow.Launcher.Infrastructure.Exception;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;
@@ -65,7 +65,7 @@ namespace Flow.Launcher.Core.Plugin
{
List results = new List();
- JsonRPCQueryResponseModel queryResponseModel = JsonConvert.DeserializeObject(output);
+ JsonRPCQueryResponseModel queryResponseModel = JsonSerializer.Deserialize(output);
if (queryResponseModel.Result == null) return null;
foreach (JsonRPCResult result in queryResponseModel.Result)
@@ -84,7 +84,7 @@ namespace Flow.Launcher.Core.Plugin
else
{
string actionReponse = ExecuteCallback(result1.JsonRPCAction);
- JsonRPCRequestModel jsonRpcRequestModel = JsonConvert.DeserializeObject(actionReponse);
+ JsonRPCRequestModel jsonRpcRequestModel = JsonSerializer.Deserialize(actionReponse);
if (jsonRpcRequestModel != null
&& !String.IsNullOrEmpty(jsonRpcRequestModel.Method)
&& jsonRpcRequestModel.Method.StartsWith("Flow.Launcher."))
diff --git a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs
index b9b878a7b..273698b86 100644
--- a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs
+++ b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs
@@ -20,7 +20,7 @@ namespace Flow.Launcher.Core.Plugin
dependencyResolver = new AssemblyDependencyResolver(assemblyFilePath);
assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyFilePath));
- referencedPluginPackageDependencyResolver =
+ referencedPluginPackageDependencyResolver =
new AssemblyDependencyResolver(Path.Combine(Constant.ProgramDirectory, "Flow.Launcher.Plugin.dll"));
}
@@ -38,15 +38,15 @@ namespace Flow.Launcher.Core.Plugin
// that use Newtonsoft.Json
if (assemblyPath == null || ExistsInReferencedPluginPackage(assemblyName))
return null;
-
+
return LoadFromAssemblyPath(assemblyPath);
}
- internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, Type type)
+ internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, params Type[] types)
{
var allTypes = assembly.ExportedTypes;
- return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(type));
+ return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Intersect(types).Any());
}
internal bool ExistsInReferencedPluginPackage(AssemblyName assemblyName)
diff --git a/Flow.Launcher.Core/Plugin/PluginConfig.cs b/Flow.Launcher.Core/Plugin/PluginConfig.cs
index b946fa44d..46f79c60c 100644
--- a/Flow.Launcher.Core/Plugin/PluginConfig.cs
+++ b/Flow.Launcher.Core/Plugin/PluginConfig.cs
@@ -2,10 +2,10 @@
using System.Collections.Generic;
using System.Linq;
using System.IO;
-using Newtonsoft.Json;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin;
+using System.Text.Json;
namespace Flow.Launcher.Core.Plugin
{
@@ -61,7 +61,7 @@ namespace Flow.Launcher.Core.Plugin
PluginMetadata metadata;
try
{
- metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath));
+ metadata = JsonSerializer.Deserialize(File.ReadAllText(configPath));
metadata.PluginDirectory = pluginDirectory;
// for plugins which doesn't has ActionKeywords key
metadata.ActionKeywords = metadata.ActionKeywords ?? new List { metadata.ActionKeyword };
diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs
index 3b697a1ee..26167e945 100644
--- a/Flow.Launcher.Core/Plugin/PluginManager.cs
+++ b/Flow.Launcher.Core/Plugin/PluginManager.cs
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Logger;
@@ -52,13 +53,14 @@ namespace Flow.Launcher.Core.Plugin
}
}
- public static void ReloadData()
+ public static async Task ReloadData()
{
- foreach(var plugin in AllPlugins)
+ await Task.WhenAll(AllPlugins.Select(plugin => plugin.Plugin switch
{
- var reloadablePlugin = plugin.Plugin as IReloadable;
- reloadablePlugin?.ReloadData();
- }
+ IReloadable p => Task.Run(p.ReloadData),
+ IAsyncReloadable p => p.ReloadDataAsync(),
+ _ => Task.CompletedTask,
+ }).ToArray());
}
static PluginManager()
@@ -86,50 +88,62 @@ namespace Flow.Launcher.Core.Plugin
/// Call initialize for all plugins
///
/// return the list of failed to init plugins or null for none
- public static void InitializePlugins(IPublicAPI api)
+ public static async Task InitializePlugins(IPublicAPI api)
{
API = api;
var failedPlugins = new ConcurrentQueue();
- Parallel.ForEach(AllPlugins, pair =>
+
+ var InitTasks = AllPlugins.Select(pair => Task.Run(async delegate
{
try
{
- var milliseconds = Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", () =>
+ var milliseconds = pair.Plugin switch
{
- pair.Plugin.Init(new PluginInitContext
- {
- CurrentPluginMetadata = pair.Metadata,
- API = API
- });
- });
+ IAsyncPlugin plugin
+ => await Stopwatch.DebugAsync($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>",
+ () => plugin.InitAsync(new PluginInitContext(pair.Metadata, API))),
+ IPlugin plugin
+ => Stopwatch.Debug($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>",
+ () => plugin.Init(new PluginInitContext(pair.Metadata, API))),
+ _ => throw new ArgumentException(),
+ };
pair.Metadata.InitTime += milliseconds;
- Log.Info($"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
+ Log.Info(
+ $"|PluginManager.InitializePlugins|Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
}
catch (Exception e)
{
Log.Exception(nameof(PluginManager), $"Fail to Init plugin: {pair.Metadata.Name}", e);
- pair.Metadata.Disabled = true;
+ pair.Metadata.Disabled = true;
failedPlugins.Enqueue(pair);
}
- });
+ }));
+
+ await Task.WhenAll(InitTasks);
_contextMenuPlugins = GetPluginsForInterface();
foreach (var plugin in AllPlugins)
{
- if (IsGlobalPlugin(plugin.Metadata))
- GlobalPlugins.Add(plugin);
-
- // Plugins may have multiple ActionKeywords, eg. WebSearch
- plugin.Metadata.ActionKeywords
- .Where(x => x != Query.GlobalPluginWildcardSign)
- .ToList()
- .ForEach(x => NonGlobalPlugins[x] = plugin);
+ foreach (var actionKeyword in plugin.Metadata.ActionKeywords)
+ {
+ switch (actionKeyword)
+ {
+ case Query.GlobalPluginWildcardSign:
+ GlobalPlugins.Add(plugin);
+ break;
+ default:
+ NonGlobalPlugins[actionKeyword] = plugin;
+ break;
+ }
+ }
}
if (failedPlugins.Any())
{
var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
- API.ShowMsg($"Fail to Init Plugins", $"Plugins: {failed} - fail to load and would be disabled, please contact plugin creator for help", "", false);
+ API.ShowMsg($"Fail to Init Plugins",
+ $"Plugins: {failed} - fail to load and would be disabled, please contact plugin creator for help",
+ "", false);
}
}
@@ -146,24 +160,46 @@ namespace Flow.Launcher.Core.Plugin
}
}
- public static List QueryForPlugin(PluginPair pair, Query query)
+ public static async Task> QueryForPlugin(PluginPair pair, Query query, CancellationToken token)
{
var results = new List();
try
{
var metadata = pair.Metadata;
- var milliseconds = Stopwatch.Debug($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}", () =>
+
+ long milliseconds = -1L;
+
+ switch (pair.Plugin)
{
- results = pair.Plugin.Query(query) ?? new List();
- UpdatePluginMetadata(results, metadata, query);
- });
+ case IAsyncPlugin plugin:
+ milliseconds = await Stopwatch.DebugAsync($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}",
+ async () => results = await plugin.QueryAsync(query, token).ConfigureAwait(false));
+ break;
+ case IPlugin plugin:
+ await Task.Run(() => milliseconds = Stopwatch.Debug($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}",
+ () => results = plugin.Query(query)), token).ConfigureAwait(false);
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ token.ThrowIfCancellationRequested();
+ UpdatePluginMetadata(results, metadata, query);
+
metadata.QueryCount += 1;
- metadata.AvgQueryTime = metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2;
+ metadata.AvgQueryTime =
+ metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2;
+ token.ThrowIfCancellationRequested();
+ }
+ catch (OperationCanceledException)
+ {
+ // null will be fine since the results will only be added into queue if the token hasn't been cancelled
+ return results = null;
}
catch (Exception e)
{
Log.Exception($"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", e);
}
+
return results;
}
@@ -182,11 +218,6 @@ namespace Flow.Launcher.Core.Plugin
}
}
- private static bool IsGlobalPlugin(PluginMetadata metadata)
- {
- return metadata.ActionKeywords.Contains(Query.GlobalPluginWildcardSign);
- }
-
///
/// get specified plugin, return null if not found
///
@@ -222,16 +253,19 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- Log.Exception($"|PluginManager.GetContextMenusForPlugin|Can't load context menus for plugin <{pluginPair.Metadata.Name}>", e);
+ Log.Exception(
+ $"|PluginManager.GetContextMenusForPlugin|Can't load context menus for plugin <{pluginPair.Metadata.Name}>",
+ e);
}
}
+
return results;
}
public static bool ActionKeywordRegistered(string actionKeyword)
{
return actionKeyword != Query.GlobalPluginWildcardSign
- && NonGlobalPlugins.ContainsKey(actionKeyword);
+ && NonGlobalPlugins.ContainsKey(actionKeyword);
}
///
@@ -249,6 +283,7 @@ namespace Flow.Launcher.Core.Plugin
{
NonGlobalPlugins[newActionKeyword] = plugin;
}
+
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
}
@@ -262,16 +297,16 @@ namespace Flow.Launcher.Core.Plugin
if (oldActionkeyword == Query.GlobalPluginWildcardSign
&& // Plugins may have multiple ActionKeywords that are global, eg. WebSearch
plugin.Metadata.ActionKeywords
- .Where(x => x == Query.GlobalPluginWildcardSign)
- .ToList()
- .Count == 1)
+ .Where(x => x == Query.GlobalPluginWildcardSign)
+ .ToList()
+ .Count == 1)
{
GlobalPlugins.Remove(plugin);
}
-
+
if (oldActionkeyword != Query.GlobalPluginWildcardSign)
NonGlobalPlugins.Remove(oldActionkeyword);
-
+
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
}
diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs
index 224dbd85e..fcf178445 100644
--- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs
+++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs
@@ -37,56 +37,59 @@ namespace Flow.Launcher.Core.Plugin
foreach (var metadata in metadatas)
{
- var milliseconds = Stopwatch.Debug($"|PluginsLoader.DotNetPlugins|Constructor init cost for {metadata.Name}", () =>
- {
-
+ var milliseconds = Stopwatch.Debug(
+ $"|PluginsLoader.DotNetPlugins|Constructor init cost for {metadata.Name}", () =>
+ {
#if DEBUG
- var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
- var assembly = assemblyLoader.LoadAssemblyAndDependencies();
- var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly, typeof(IPlugin));
- var plugin = (IPlugin)Activator.CreateInstance(type);
-#else
- Assembly assembly = null;
- IPlugin plugin = null;
-
- try
- {
var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
- assembly = assemblyLoader.LoadAssemblyAndDependencies();
+ var assembly = assemblyLoader.LoadAssemblyAndDependencies();
+ var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly, typeof(IPlugin),
+ typeof(IAsyncPlugin));
- var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly, typeof(IPlugin));
+ var plugin = Activator.CreateInstance(type);
+#else
+ Assembly assembly = null;
+ object plugin = null;
- plugin = (IPlugin)Activator.CreateInstance(type);
- }
- catch (Exception e) when (assembly == null)
- {
- Log.Exception($"|PluginsLoader.DotNetPlugins|Couldn't load assembly for the plugin: {metadata.Name}", e);
- }
- catch (InvalidOperationException e)
- {
- Log.Exception($"|PluginsLoader.DotNetPlugins|Can't find the required IPlugin interface for the plugin: <{metadata.Name}>", e);
- }
- catch (ReflectionTypeLoadException e)
- {
- Log.Exception($"|PluginsLoader.DotNetPlugins|The GetTypes method was unable to load assembly types for the plugin: <{metadata.Name}>", e);
- }
- catch (Exception e)
- {
- Log.Exception($"|PluginsLoader.DotNetPlugins|The following plugin has errored and can not be loaded: <{metadata.Name}>", e);
- }
+ try
+ {
+ var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
+ assembly = assemblyLoader.LoadAssemblyAndDependencies();
- if (plugin == null)
- {
- erroredPlugins.Add(metadata.Name);
- return;
- }
+ var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly, typeof(IPlugin),
+ typeof(IAsyncPlugin));
+
+ plugin = Activator.CreateInstance(type);
+ }
+ catch (Exception e) when (assembly == null)
+ {
+ Log.Exception($"|PluginsLoader.DotNetPlugins|Couldn't load assembly for the plugin: {metadata.Name}", e);
+ }
+ catch (InvalidOperationException e)
+ {
+ Log.Exception($"|PluginsLoader.DotNetPlugins|Can't find the required IPlugin interface for the plugin: <{metadata.Name}>", e);
+ }
+ catch (ReflectionTypeLoadException e)
+ {
+ Log.Exception($"|PluginsLoader.DotNetPlugins|The GetTypes method was unable to load assembly types for the plugin: <{metadata.Name}>", e);
+ }
+ catch (Exception e)
+ {
+ Log.Exception($"|PluginsLoader.DotNetPlugins|The following plugin has errored and can not be loaded: <{metadata.Name}>", e);
+ }
+
+ if (plugin == null)
+ {
+ erroredPlugins.Add(metadata.Name);
+ return;
+ }
#endif
- plugins.Add(new PluginPair
- {
- Plugin = plugin,
- Metadata = metadata
+ plugins.Add(new PluginPair
+ {
+ Plugin = plugin,
+ Metadata = metadata
+ });
});
- });
metadata.InitTime += milliseconds;
}
@@ -95,15 +98,15 @@ namespace Flow.Launcher.Core.Plugin
var errorPluginString = String.Join(Environment.NewLine, erroredPlugins);
var errorMessage = "The following "
- + (erroredPlugins.Count > 1 ? "plugins have " : "plugin has ")
- + "errored and cannot be loaded:";
+ + (erroredPlugins.Count > 1 ? "plugins have " : "plugin has ")
+ + "errored and cannot be loaded:";
Task.Run(() =>
{
MessageBox.Show($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
- $"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" +
- $"Please refer to the logs for more information","",
- MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ $"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" +
+ $"Please refer to the logs for more information", "",
+ MessageBoxButtons.OK, MessageBoxIcon.Warning);
});
}
@@ -179,6 +182,5 @@ namespace Flow.Launcher.Core.Plugin
Metadata = metadata
});
}
-
}
-}
\ No newline at end of file
+}
diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs
index 20df23e40..b203967de 100644
--- a/Flow.Launcher.Core/Updater.cs
+++ b/Flow.Launcher.Core/Updater.cs
@@ -8,15 +8,14 @@ using System.Threading.Tasks;
using System.Windows;
using JetBrains.Annotations;
using Squirrel;
-using Newtonsoft.Json;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Infrastructure.Logger;
-using System.IO;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Core
{
@@ -29,101 +28,80 @@ namespace Flow.Launcher.Core
GitHubRepository = gitHubRepository;
}
- public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true)
+ public async Task UpdateApp(IPublicAPI api, bool silentUpdate = true)
{
- UpdateManager updateManager;
- UpdateInfo newUpdateInfo;
-
- if (!silentUpdate)
- api.ShowMsg("Please wait...", "Checking for new update");
-
try
{
- updateManager = await GitHubUpdateManager(GitHubRepository);
- }
- catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
- {
- Log.Exception($"|Updater.UpdateApp|Please check your connection and proxy settings to api.github.com.", e);
- return;
- }
+ UpdateInfo newUpdateInfo;
- try
- {
- // UpdateApp CheckForUpdate will return value only if the app is squirrel installed
- newUpdateInfo = await updateManager.CheckForUpdate().NonNull();
- }
- catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
- {
- Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to api.github.com.", e);
- updateManager.Dispose();
- return;
- }
-
- var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString());
- var currentVersion = Version.Parse(Constant.Version);
-
- Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>");
-
- if (newReleaseVersion <= currentVersion)
- {
if (!silentUpdate)
- MessageBox.Show("You already have the latest Flow Launcher version");
- updateManager.Dispose();
- return;
- }
+ api.ShowMsg("Please wait...", "Checking for new update");
- if (!silentUpdate)
- api.ShowMsg("Update found", "Updating...");
+ using var updateManager = await GitHubUpdateManager(GitHubRepository).ConfigureAwait(false);
- try
- {
- await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply);
+
+ // UpdateApp CheckForUpdate will return value only if the app is squirrel installed
+ newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false);
+
+ var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString());
+ var currentVersion = Version.Parse(Constant.Version);
+
+ Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>");
+
+ if (newReleaseVersion <= currentVersion)
+ {
+ if (!silentUpdate)
+ MessageBox.Show("You already have the latest Flow Launcher version");
+ return;
+ }
+
+ if (!silentUpdate)
+ api.ShowMsg("Update found", "Updating...");
+
+ await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply).ConfigureAwait(false);
+
+ await updateManager.ApplyReleases(newUpdateInfo).ConfigureAwait(false);
+
+ if (DataLocation.PortableDataLocationInUse())
+ {
+ var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}";
+ FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination);
+ if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination))
+ MessageBox.Show("Flow Launcher was not able to move your user profile data to the new update version. Please manually " +
+ $"move your profile data folder from {DataLocation.PortableDataPath} to {targetDestination}");
+ }
+ else
+ {
+ await updateManager.CreateUninstallerRegistryEntry().ConfigureAwait(false);
+ }
+
+ var newVersionTips = NewVersinoTips(newReleaseVersion.ToString());
+
+ Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
+
+ if (MessageBox.Show(newVersionTips, "New Update", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ {
+ UpdateManager.RestartApp(Constant.ApplicationFileName);
+ }
}
catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException)
{
Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e);
- updateManager.Dispose();
+ api.ShowMsg("Update Failed", "Check your connection and try updating proxy settings to github-cloud.s3.amazonaws.com.");
return;
}
-
- await updateManager.ApplyReleases(newUpdateInfo);
-
- if (DataLocation.PortableDataLocationInUse())
- {
- var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}";
- FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination);
- if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination))
- MessageBox.Show("Flow Launcher was not able to move your user profile data to the new update version. Please manually " +
- $"move your profile data folder from {DataLocation.PortableDataPath} to {targetDestination}");
- }
- else
- {
- await updateManager.CreateUninstallerRegistryEntry();
- }
-
- var newVersionTips = NewVersinoTips(newReleaseVersion.ToString());
-
- Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}");
-
- // always dispose UpdateManager
- updateManager.Dispose();
-
- if (MessageBox.Show(newVersionTips, "New Update", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- UpdateManager.RestartApp(Constant.ApplicationFileName);
- }
}
[UsedImplicitly]
private class GithubRelease
{
- [JsonProperty("prerelease")]
+ [JsonPropertyName("prerelease")]
public bool Prerelease { get; [UsedImplicitly] set; }
- [JsonProperty("published_at")]
+ [JsonPropertyName("published_at")]
public DateTime PublishedAt { get; [UsedImplicitly] set; }
- [JsonProperty("html_url")]
+ [JsonPropertyName("html_url")]
public string HtmlUrl { get; [UsedImplicitly] set; }
}
@@ -133,13 +111,13 @@ namespace Flow.Launcher.Core
var uri = new Uri(repository);
var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases";
- var json = await Http.Get(api);
+ var jsonStream = await Http.GetStreamAsync(api).ConfigureAwait(false);
- var releases = JsonConvert.DeserializeObject>(json);
+ var releases = await System.Text.Json.JsonSerializer.DeserializeAsync>(jsonStream).ConfigureAwait(false);
var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First();
var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/");
- var client = new WebClient { Proxy = Http.WebProxy() };
+ var client = new WebClient { Proxy = Http.WebProxy };
var downloader = new FileDownloader(client);
var manager = new UpdateManager(latestUrl, urlDownloader: downloader);
diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs
index df1464048..de6ed1b29 100644
--- a/Flow.Launcher.Infrastructure/Constant.cs
+++ b/Flow.Launcher.Infrastructure/Constant.cs
@@ -30,10 +30,12 @@ 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";
public const string Themes = "Themes";
+
+ public const string Website = "https://flow-launcher.github.io";
}
}
diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
index 28d4c0e1f..8153de6c8 100644
--- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
+++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
@@ -49,7 +49,6 @@
-
diff --git a/Flow.Launcher.Infrastructure/Helper.cs b/Flow.Launcher.Infrastructure/Helper.cs
index fa7e18533..faa4c93b5 100644
--- a/Flow.Launcher.Infrastructure/Helper.cs
+++ b/Flow.Launcher.Infrastructure/Helper.cs
@@ -1,12 +1,18 @@
using System;
using System.IO;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Infrastructure
{
public static class Helper
{
+ static Helper()
+ {
+ jsonFormattedSerializerOptions.Converters.Add(new JsonStringEnumConverter());
+ }
+
///
/// http://www.yinwang.org/blog-cn/2015/11/21/programming-philosophy
///
@@ -65,13 +71,18 @@ namespace Flow.Launcher.Infrastructure
}
}
+ private static readonly JsonSerializerOptions jsonFormattedSerializerOptions = new JsonSerializerOptions
+ {
+ WriteIndented = true
+ };
+
public static string Formatted(this T t)
{
- var formatted = JsonConvert.SerializeObject(
- t,
- Formatting.Indented,
- new StringEnumConverter()
- );
+ var formatted = JsonSerializer.Serialize(t, new JsonSerializerOptions
+ {
+ WriteIndented = true
+ });
+
return formatted;
}
}
diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs
index 1d5f240e1..5af50bc6d 100644
--- a/Flow.Launcher.Infrastructure/Http/Http.cs
+++ b/Flow.Launcher.Infrastructure/Http/Http.cs
@@ -6,6 +6,9 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
+using System;
+using System.ComponentModel;
+using System.Threading;
namespace Flow.Launcher.Infrastructure.Http
{
@@ -13,6 +16,14 @@ namespace Flow.Launcher.Infrastructure.Http
{
private const string UserAgent = @"Mozilla/5.0 (Trident/7.0; rv:11.0) like Gecko";
+ private static HttpClient client;
+
+ private static SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler()
+ {
+ UseProxy = true,
+ Proxy = WebProxy
+ };
+
static Http()
{
// need to be added so it would work on a win10 machine
@@ -20,58 +31,117 @@ namespace Flow.Launcher.Infrastructure.Http
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12;
+
+ client = new HttpClient(socketsHttpHandler, false);
+ client.DefaultRequestHeaders.Add("User-Agent", UserAgent);
}
- public static HttpProxy Proxy { private get; set; }
- public static IWebProxy WebProxy()
+ private static HttpProxy proxy;
+
+ public static HttpProxy Proxy
{
- if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server))
+ private get { return proxy; }
+ set
{
- if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password))
+ proxy = value;
+ proxy.PropertyChanged += UpdateProxy;
+ }
+ }
+
+ public static WebProxy WebProxy { get; } = new WebProxy();
+
+ ///
+ /// Update the Address of the Proxy to modify the client Proxy
+ ///
+ public static void UpdateProxy(ProxyProperty property)
+ {
+ (WebProxy.Address, WebProxy.Credentials) = property switch
+ {
+ ProxyProperty.Enabled => Proxy.Enabled switch
{
- var webProxy = new WebProxy(Proxy.Server, Proxy.Port);
- return webProxy;
+ true => Proxy.UserName switch
+ {
+ var userName when !string.IsNullOrEmpty(userName) =>
+ (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), null),
+ _ => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"),
+ new NetworkCredential(Proxy.UserName, Proxy.Password))
+ },
+ false => (null, null)
+ },
+ ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), WebProxy.Credentials),
+ ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), WebProxy.Credentials),
+ ProxyProperty.UserName => (WebProxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)),
+ ProxyProperty.Password => (WebProxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ }
+
+ public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default)
+ {
+ try
+ {
+ using var response = await client.GetAsync(url, token);
+ if (response.StatusCode == HttpStatusCode.OK)
+ {
+ await using var fileStream = new FileStream(filePath, FileMode.CreateNew);
+ await response.Content.CopyToAsync(fileStream);
}
else
{
- var webProxy = new WebProxy(Proxy.Server, Proxy.Port)
- {
- Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password)
- };
- return webProxy;
+ throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>");
}
}
+ catch (HttpRequestException e)
+ {
+ Log.Exception("Infrastructure.Http", "Http Request Error", e, "DownloadAsync");
+ throw;
+ }
+ }
+
+ ///
+ /// Asynchrously get the result as string from url.
+ /// When supposing the result larger than 83kb, try using GetStreamAsync to avoid reading as string
+ ///
+ ///
+ /// The Http result as string. Null if cancellation requested
+ public static Task GetAsync([NotNull] string url, CancellationToken token = default)
+ {
+ Log.Debug($"|Http.Get|Url <{url}>");
+ return GetAsync(new Uri(url.Replace("#", "%23")), token);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// The Http result as string. Null if cancellation requested
+ public static async Task GetAsync([NotNull] Uri url, CancellationToken token = default)
+ {
+ Log.Debug($"|Http.Get|Url <{url}>");
+ using var response = await client.GetAsync(url, token);
+ var content = await response.Content.ReadAsStringAsync();
+ if (response.StatusCode == HttpStatusCode.OK)
+ {
+ return content;
+ }
else
{
- return WebRequest.GetSystemWebProxy();
+ throw new HttpRequestException(
+ $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>");
}
}
- public static void Download([NotNull] string url, [NotNull] string filePath)
- {
- var client = new WebClient { Proxy = WebProxy() };
- client.Headers.Add("user-agent", UserAgent);
- client.DownloadFile(url, filePath);
- }
-
- public static async Task Get([NotNull] string url, string encoding = "UTF-8")
+ ///
+ /// Asynchrously get the result as stream from url.
+ ///
+ ///
+ ///
+ public static async Task GetStreamAsync([NotNull] string url, CancellationToken token = default)
{
Log.Debug($"|Http.Get|Url <{url}>");
- var request = WebRequest.CreateHttp(url);
- request.Method = "GET";
- request.Timeout = 1000;
- request.Proxy = WebProxy();
- request.UserAgent = UserAgent;
- var response = await request.GetResponseAsync() as HttpWebResponse;
- response = response.NonNull();
- var stream = response.GetResponseStream().NonNull();
-
- using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding));
- var content = await reader.ReadToEndAsync();
- if (response.StatusCode != HttpStatusCode.OK)
- throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>");
-
- return content;
+ var response = await client.GetAsync(url, token);
+ return await response.Content.ReadAsStreamAsync();
}
}
-}
\ No newline at end of file
+}
diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs
index 289ec5d68..91eeb183d 100644
--- a/Flow.Launcher.Infrastructure/Logger/Log.cs
+++ b/Flow.Launcher.Infrastructure/Logger/Log.cs
@@ -128,7 +128,7 @@ namespace Flow.Launcher.Infrastructure.Logger
public static void Exception(string message, System.Exception e)
{
#if DEBUG
- throw e;
+ throw e;
#else
if (FormatValid(message))
{
diff --git a/Flow.Launcher.Infrastructure/Stopwatch.cs b/Flow.Launcher.Infrastructure/Stopwatch.cs
index d39d90e81..dd6edaff9 100644
--- a/Flow.Launcher.Infrastructure/Stopwatch.cs
+++ b/Flow.Launcher.Infrastructure/Stopwatch.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
using Flow.Launcher.Infrastructure.Logger;
namespace Flow.Launcher.Infrastructure
@@ -22,7 +23,22 @@ namespace Flow.Launcher.Infrastructure
Log.Debug(info);
return milliseconds;
}
-
+
+ ///
+ /// This stopwatch will appear only in Debug mode
+ ///
+ public static async Task DebugAsync(string message, Func action)
+ {
+ var stopWatch = new System.Diagnostics.Stopwatch();
+ stopWatch.Start();
+ await action();
+ stopWatch.Stop();
+ var milliseconds = stopWatch.ElapsedMilliseconds;
+ string info = $"{message} <{milliseconds}ms>";
+ Log.Debug(info);
+ return milliseconds;
+ }
+
public static long Normal(string message, Action action)
{
var stopWatch = new System.Diagnostics.Stopwatch();
@@ -34,6 +50,20 @@ namespace Flow.Launcher.Infrastructure
Log.Info(info);
return milliseconds;
}
+
+ public static async Task NormalAsync(string message, Func action)
+ {
+ var stopWatch = new System.Diagnostics.Stopwatch();
+ stopWatch.Start();
+ await action();
+ stopWatch.Stop();
+ var milliseconds = stopWatch.ElapsedMilliseconds;
+ string info = $"{message} <{milliseconds}ms>";
+ Log.Info(info);
+ return milliseconds;
+ }
+
+
public static void StartCount(string name, Action action)
{
diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs
index 784c11110..f0e4a79fc 100644
--- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs
+++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs
@@ -1,7 +1,7 @@
using System;
using System.Globalization;
using System.IO;
-using Newtonsoft.Json;
+using System.Text.Json;
using Flow.Launcher.Infrastructure.Logger;
namespace Flow.Launcher.Infrastructure.Storage
@@ -9,9 +9,9 @@ namespace Flow.Launcher.Infrastructure.Storage
///
/// Serialize object using json format.
///
- public class JsonStrorage
+ public class JsonStrorage where T : new()
{
- private readonly JsonSerializerSettings _serializerSettings;
+ private readonly JsonSerializerOptions _serializerSettings;
private T _data;
// need a new directory name
public const string DirectoryName = "Settings";
@@ -24,10 +24,9 @@ namespace Flow.Launcher.Infrastructure.Storage
{
// use property initialization instead of DefaultValueAttribute
// easier and flexible for default value of object
- _serializerSettings = new JsonSerializerSettings
+ _serializerSettings = new JsonSerializerOptions
{
- ObjectCreationHandling = ObjectCreationHandling.Replace,
- NullValueHandling = NullValueHandling.Ignore
+ IgnoreNullValues = false
};
}
@@ -56,7 +55,7 @@ namespace Flow.Launcher.Infrastructure.Storage
{
try
{
- _data = JsonConvert.DeserializeObject(searlized, _serializerSettings);
+ _data = JsonSerializer.Deserialize(searlized, _serializerSettings);
}
catch (JsonException e)
{
@@ -77,7 +76,7 @@ namespace Flow.Launcher.Infrastructure.Storage
BackupOriginFile();
}
- _data = JsonConvert.DeserializeObject("{}", _serializerSettings);
+ _data = new T();
Save();
}
@@ -94,7 +93,8 @@ namespace Flow.Launcher.Infrastructure.Storage
public void Save()
{
- string serialized = JsonConvert.SerializeObject(_data, Formatting.Indented);
+ string serialized = JsonSerializer.Serialize(_data, new JsonSerializerOptions() { WriteIndented = true });
+
File.WriteAllText(FilePath, serialized);
}
}
diff --git a/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs b/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs
index c1b0c1dd7..213193526 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/HttpProxy.cs
@@ -1,11 +1,80 @@
-namespace Flow.Launcher.Infrastructure.UserSettings
+using System.ComponentModel;
+
+namespace Flow.Launcher.Infrastructure.UserSettings
{
+ public enum ProxyProperty
+ {
+ Enabled,
+ Server,
+ Port,
+ UserName,
+ Password
+ }
+
public class HttpProxy
{
- public bool Enabled { get; set; } = false;
- public string Server { get; set; }
- public int Port { get; set; }
- public string UserName { get; set; }
- public string Password { get; set; }
+ private bool _enabled = false;
+ private string _server;
+ private int _port;
+ private string _userName;
+ private string _password;
+
+ public bool Enabled
+ {
+ get => _enabled;
+ set
+ {
+ _enabled = value;
+ OnPropertyChanged(ProxyProperty.Enabled);
+ }
+ }
+
+ public string Server
+ {
+ get => _server;
+ set
+ {
+ _server = value;
+ OnPropertyChanged(ProxyProperty.Server);
+ }
+ }
+
+ public int Port
+ {
+ get => _port;
+ set
+ {
+ _port = value;
+ OnPropertyChanged(ProxyProperty.Port);
+ }
+ }
+
+ public string UserName
+ {
+ get => _userName;
+ set
+ {
+ _userName = value;
+ OnPropertyChanged(ProxyProperty.UserName);
+ }
+ }
+
+ public string Password
+ {
+ get => _password;
+ set
+ {
+ _password = value;
+ OnPropertyChanged(ProxyProperty.Password);
+ }
+ }
+
+ public delegate void ProxyPropertyChangedHandler(ProxyProperty property);
+ public event ProxyPropertyChangedHandler PropertyChanged;
+
+ private void OnPropertyChanged(ProxyProperty property)
+ {
+ PropertyChanged?.Invoke(property);
+ }
}
}
\ No newline at end of file
diff --git a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
index ccd9beb86..29bc11480 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
@@ -31,6 +31,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
metadata.ActionKeyword = settings.ActionKeywords[0];
}
metadata.Disabled = settings.Disabled;
+ metadata.Priority = settings.Priority;
}
else
{
@@ -40,7 +41,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
Name = metadata.Name,
Version = metadata.Version,
ActionKeywords = metadata.ActionKeywords,
- Disabled = metadata.Disabled
+ Disabled = metadata.Disabled,
+ Priority = metadata.Priority
};
}
}
@@ -52,6 +54,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public string Name { get; set; }
public string Version { get; set; }
public List ActionKeywords { get; set; } // a reference of the action keywords from plugin manager
+ public int Priority { get; set; }
///
/// Used only to save the state of the plugin in settings
diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index 832b6fbfa..769237bcb 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -1,8 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Drawing;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Converters;
+using System.Text.Json.Serialization;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Infrastructure.UserSettings
@@ -16,7 +15,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public bool ShowOpenResultHotkey { get; set; } = true;
public string Language
{
- get => language; set {
+ get => language; set
+ {
language = value;
OnPropertyChanged();
}
@@ -73,9 +73,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public int MaxResultsToShow { get; set; } = 5;
public int ActivateTimes { get; set; }
- // Order defaults to 0 or -1, so 1 will let this property appear last
- [JsonProperty(Order = 1)]
- public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
+
public ObservableCollection CustomPluginHotkeys { get; set; } = new ObservableCollection();
public bool DontPromptUpdateMsg { get; set; }
@@ -100,8 +98,12 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public HttpProxy Proxy { get; set; } = new HttpProxy();
- [JsonConverter(typeof(StringEnumConverter))]
+ [JsonConverter(typeof(JsonStringEnumConverter))]
public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected;
+
+
+ // This needs to be loaded last by staying at the bottom
+ public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
}
public enum LastQueryMode
diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
index 0f6450d18..b7b52ac35 100644
--- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
+++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
@@ -14,10 +14,10 @@
- 1.3.0
- 1.3.0
- 1.3.0
- 1.3.0
+ 1.3.1
+ 1.3.1
+ 1.3.1
+ 1.3.1
Flow.Launcher.Plugin
Flow-Launcher
MIT
@@ -62,7 +62,6 @@
-
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin/IAsyncPlugin.cs b/Flow.Launcher.Plugin/IAsyncPlugin.cs
new file mode 100644
index 000000000..b0b41cc22
--- /dev/null
+++ b/Flow.Launcher.Plugin/IAsyncPlugin.cs
@@ -0,0 +1,31 @@
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Flow.Launcher.Plugin
+{
+ ///
+ /// Asynchronous Plugin Model for Flow Launcher
+ ///
+ public interface IAsyncPlugin
+ {
+ ///
+ /// Asynchronous Querying
+ ///
+ ///
+ /// If the Querying or Init method requires high IO transmission
+ /// or performing CPU intense jobs (performing better with cancellation), please use this IAsyncPlugin interface
+ ///
+ /// Query to search
+ /// Cancel when querying job is obsolete
+ ///
+ Task> QueryAsync(Query query, CancellationToken token);
+
+ ///
+ /// Initialize plugin asynchrously (will still wait finish to continue)
+ ///
+ ///
+ ///
+ Task InitAsync(PluginInitContext context);
+ }
+}
diff --git a/Flow.Launcher.Plugin/IPlugin.cs b/Flow.Launcher.Plugin/IPlugin.cs
index 8f7d279fa..203dc9af7 100644
--- a/Flow.Launcher.Plugin/IPlugin.cs
+++ b/Flow.Launcher.Plugin/IPlugin.cs
@@ -2,9 +2,30 @@
namespace Flow.Launcher.Plugin
{
+ ///
+ /// Synchronous Plugin Model for Flow Launcher
+ ///
+ /// If the Querying or Init method requires high IO transmission
+ /// or performaing CPU intense jobs (performing better with cancellation), please try the IAsyncPlugin interface
+ ///
+ ///
public interface IPlugin
{
+ ///
+ /// Querying when user's search changes
+ ///
+ /// This method will be called within a Task.Run,
+ /// so please avoid synchrously wait for long.
+ ///
+ ///
+ /// Query to search
+ ///
List Query(Query query);
+
+ ///
+ /// Initialize plugin
+ ///
+ ///
void Init(PluginInitContext context);
}
-}
\ No newline at end of file
+}
diff --git a/Flow.Launcher.Plugin/IPublicAPI.cs b/Flow.Launcher.Plugin/IPublicAPI.cs
index ccc00d5e9..12e430e07 100644
--- a/Flow.Launcher.Plugin/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/IPublicAPI.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Threading.Tasks;
namespace Flow.Launcher.Plugin
{
@@ -34,7 +35,7 @@ namespace Flow.Launcher.Plugin
/// Plugin's in memory data with new content
/// added by user.
///
- void ReloadAllPluginData();
+ Task ReloadAllPluginData();
///
/// Check for new Flow Launcher update
diff --git a/Flow.Launcher.Plugin/Interfaces/IAsyncReloadable.cs b/Flow.Launcher.Plugin/Interfaces/IAsyncReloadable.cs
new file mode 100644
index 000000000..fc4ac4715
--- /dev/null
+++ b/Flow.Launcher.Plugin/Interfaces/IAsyncReloadable.cs
@@ -0,0 +1,20 @@
+using System.Threading.Tasks;
+
+namespace Flow.Launcher.Plugin
+{
+ ///
+ /// This interface is to indicate and allow plugins to asyncronously reload their
+ /// in memory data cache or other mediums when user makes a new change
+ /// that is not immediately captured. For example, for BrowserBookmark and Program
+ /// plugin does not automatically detect when a user added a new bookmark or program,
+ /// so this interface's function is exposed to allow user manually do the reloading after
+ /// those new additions.
+ ///
+ /// The command that allows user to manual reload is exposed via Plugin.Sys, and
+ /// it will call the plugins that have implemented this interface.
+ ///
+ public interface IAsyncReloadable
+ {
+ Task ReloadDataAsync();
+ }
+}
diff --git a/Flow.Launcher.Plugin/Interfaces/IReloadable.cs b/Flow.Launcher.Plugin/Interfaces/IReloadable.cs
index 29b3c15c9..31611519c 100644
--- a/Flow.Launcher.Plugin/Interfaces/IReloadable.cs
+++ b/Flow.Launcher.Plugin/Interfaces/IReloadable.cs
@@ -1,7 +1,7 @@
namespace Flow.Launcher.Plugin
{
///
- /// This interface is to indicate and allow plugins to reload their
+ /// This interface is to indicate and allow plugins to synchronously reload their
/// in memory data cache or other mediums when user makes a new change
/// that is not immediately captured. For example, for BrowserBookmark and Program
/// plugin does not automatically detect when a user added a new bookmark or program,
@@ -10,6 +10,10 @@
///
/// The command that allows user to manual reload is exposed via Plugin.Sys, and
/// it will call the plugins that have implemented this interface.
+ ///
+ ///
+ /// If requiring reloading data asynchronously, please use the IAsyncReloadable interface
+ ///
///
public interface IReloadable
{
diff --git a/Flow.Launcher.Plugin/PluginInitContext.cs b/Flow.Launcher.Plugin/PluginInitContext.cs
index 49366a5c6..04f20e984 100644
--- a/Flow.Launcher.Plugin/PluginInitContext.cs
+++ b/Flow.Launcher.Plugin/PluginInitContext.cs
@@ -4,6 +4,16 @@ namespace Flow.Launcher.Plugin
{
public class PluginInitContext
{
+ public PluginInitContext()
+ {
+ }
+
+ public PluginInitContext(PluginMetadata currentPluginMetadata, IPublicAPI api)
+ {
+ CurrentPluginMetadata = currentPluginMetadata;
+ API = api;
+ }
+
public PluginMetadata CurrentPluginMetadata { get; internal set; }
///
diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs
index d81b442e2..e8f5cf744 100644
--- a/Flow.Launcher.Plugin/PluginMetadata.cs
+++ b/Flow.Launcher.Plugin/PluginMetadata.cs
@@ -1,11 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin
{
- [JsonObject(MemberSerialization.OptOut)]
public class PluginMetadata : BaseModel
{
private string _pluginDirectory;
@@ -37,12 +36,15 @@ namespace Flow.Launcher.Plugin
public List ActionKeywords { get; set; }
public string IcoPath { get; set;}
-
+
public override string ToString()
{
return Name;
}
+ [JsonIgnore]
+ public int Priority { get; set; }
+
///
/// Init time include both plugin load time and init time
///
diff --git a/Flow.Launcher.Plugin/PluginPair.cs b/Flow.Launcher.Plugin/PluginPair.cs
index 910367ec6..e8954b7a0 100644
--- a/Flow.Launcher.Plugin/PluginPair.cs
+++ b/Flow.Launcher.Plugin/PluginPair.cs
@@ -2,7 +2,7 @@
{
public class PluginPair
{
- public IPlugin Plugin { get; internal set; }
+ public object Plugin { get; internal set; }
public PluginMetadata Metadata { get; internal set; }
diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
index c91144825..09c7d9a30 100644
--- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs
+++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
@@ -7,6 +7,8 @@ using Flow.Launcher.Plugin.SharedCommands;
using NUnit.Framework;
using System;
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
namespace Flow.Launcher.Test.Plugins
{
@@ -17,15 +19,15 @@ namespace Flow.Launcher.Test.Plugins
[TestFixture]
public class ExplorerTest
{
- private List MethodWindowsIndexSearchReturnsZeroResults(Query dummyQuery, string dummyString)
+ private async Task> MethodWindowsIndexSearchReturnsZeroResultsAsync(Query dummyQuery, string dummyString, CancellationToken dummyToken)
{
return new List();
}
private List MethodDirectoryInfoClassSearchReturnsTwoResults(Query dummyQuery, string dummyString)
{
- return new List
- {
+ return new List
+ {
new Result
{
Title="Result 1"
@@ -64,10 +66,10 @@ namespace Flow.Launcher.Test.Plugins
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
-
+
//When
var queryString = queryConstructor.QueryForTopLevelDirectorySearch(folderPath);
-
+
// Then
Assert.IsTrue(queryString == expectedString,
$"Expected string: {expectedString}{Environment.NewLine} " +
@@ -112,7 +114,7 @@ namespace Flow.Launcher.Test.Plugins
}
[TestCase("scope='file:'")]
- public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString)
+ public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
@@ -130,7 +132,7 @@ namespace Flow.Launcher.Test.Plugins
"FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:'")]
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryShouldUseExpectedString(
- string userSearchString, string expectedString)
+ string userSearchString, string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
@@ -145,18 +147,19 @@ namespace Flow.Launcher.Test.Plugins
}
[TestCase]
- public void GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldContinueDirectoryInfoClassSearch()
+ public async Task GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldContinueDirectoryInfoClassSearch()
{
// Given
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
-
+
// When
- var results = searchManager.TopLevelDirectorySearchBehaviour(
- MethodWindowsIndexSearchReturnsZeroResults,
- MethodDirectoryInfoClassSearchReturnsTwoResults,
- false,
+ var results = await searchManager.TopLevelDirectorySearchBehaviourAsync(
+ MethodWindowsIndexSearchReturnsZeroResultsAsync,
+ MethodDirectoryInfoClassSearchReturnsTwoResults,
+ false,
new Query(),
- "string not used");
+ "string not used",
+ default);
// Then
Assert.IsTrue(results.Count == 2,
@@ -165,18 +168,19 @@ namespace Flow.Launcher.Test.Plugins
}
[TestCase]
- public void GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldNotContinueDirectoryInfoClassSearch()
+ public async Task GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldNotContinueDirectoryInfoClassSearch()
{
// Given
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
// When
- var results = searchManager.TopLevelDirectorySearchBehaviour(
- MethodWindowsIndexSearchReturnsZeroResults,
+ var results = await searchManager.TopLevelDirectorySearchBehaviourAsync(
+ MethodWindowsIndexSearchReturnsZeroResultsAsync,
MethodDirectoryInfoClassSearchReturnsTwoResults,
true,
new Query(),
- "string not used");
+ "string not used",
+ default);
// Then
Assert.IsTrue(results.Count == 0,
@@ -223,7 +227,7 @@ namespace Flow.Launcher.Test.Plugins
var query = new Query { ActionKeyword = "doc:", Search = "search term" };
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
-
+
// When
var result = searchManager.IsFileContentSearch(query.ActionKeyword);
@@ -250,7 +254,7 @@ namespace Flow.Launcher.Test.Plugins
$"Actual check result is {result} {Environment.NewLine}");
}
-
+
[TestCase(@"C:\SomeFolder\SomeApp", true, @"C:\SomeFolder\")]
[TestCase(@"C:\SomeFolder\SomeApp\SomeFile", true, @"C:\SomeFolder\SomeApp\")]
[TestCase(@"C:\NonExistentFolder\SomeApp", false, "")]
@@ -294,7 +298,7 @@ namespace Flow.Launcher.Test.Plugins
[TestCase("c:\\SomeFolder\\>SomeName", "(System.FileName LIKE 'SomeName%' " +
"OR CONTAINS(System.FileName,'\"SomeName*\"',1033)) AND " +
"scope='file:c:\\SomeFolder'")]
- public void GivenWindowsIndexSearch_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString)
+ public void GivenWindowsIndexSearch_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
@@ -308,7 +312,7 @@ namespace Flow.Launcher.Test.Plugins
$"Actual string was: {resultString}{Environment.NewLine}");
}
- [TestCase("c:\\somefolder\\>somefile","*somefile*")]
+ [TestCase("c:\\somefolder\\>somefile", "*somefile*")]
[TestCase("c:\\somefolder\\somefile", "somefile*")]
[TestCase("c:\\somefolder\\", "*")]
public void GivenDirectoryInfoSearch_WhenSearchPatternHotKeyIsSearchAll_ThenSearchCriteriaShouldUseCriteriaString(string path, string expectedString)
diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln
index 4d8997177..21c3b47dc 100644
--- a/Flow.Launcher.sln
+++ b/Flow.Launcher.sln
@@ -20,7 +20,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc
{F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567} = {F35190AA-4758-4D9E-A193-E3BDF6AD3567}
{9B130CC5-14FB-41FF-B310-0A95B6894C37} = {9B130CC5-14FB-41FF-B310-0A95B6894C37}
{FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {FDED22C8-B637-42E8-824A-63B5B6E05A3A}
{A3DCCBCA-ACC1-421D-B16E-210896234C26} = {A3DCCBCA-ACC1-421D-B16E-210896234C26}
@@ -44,8 +43,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Sys",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Url", "Plugins\Flow.Launcher.Plugin.Url\Flow.Launcher.Plugin.Url.csproj", "{A3DCCBCA-ACC1-421D-B16E-210896234C26}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Color", "Plugins\Flow.Launcher.Plugin.Color\Flow.Launcher.Plugin.Color.csproj", "{F35190AA-4758-4D9E-A193-E3BDF6AD3567}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FFD651C7-0546-441F-BC8C-D4EE8FD01EA7}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
@@ -214,18 +211,6 @@ Global
{A3DCCBCA-ACC1-421D-B16E-210896234C26}.Release|x64.Build.0 = Release|Any CPU
{A3DCCBCA-ACC1-421D-B16E-210896234C26}.Release|x86.ActiveCfg = Release|Any CPU
{A3DCCBCA-ACC1-421D-B16E-210896234C26}.Release|x86.Build.0 = Release|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Debug|x64.Build.0 = Debug|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Debug|x86.Build.0 = Debug|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Release|Any CPU.Build.0 = Release|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Release|x64.ActiveCfg = Release|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Release|x64.Build.0 = Release|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Release|x86.ActiveCfg = Release|Any CPU
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}.Release|x86.Build.0 = Release|Any CPU
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -309,7 +294,6 @@ Global
{FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{A3DCCBCA-ACC1-421D-B16E-210896234C26} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{9B130CC5-14FB-41FF-B310-0A95B6894C37} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
diff --git a/Flow.Launcher/App.xaml b/Flow.Launcher/App.xaml
index f3347d7fb..18addac73 100644
--- a/Flow.Launcher/App.xaml
+++ b/Flow.Launcher/App.xaml
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.modernwpf.com/2019"
ShutdownMode="OnMainWindowClose"
- Startup="OnStartup">
+ Startup="OnStartupAsync">
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index 59bdbc896..06bb16e3b 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -45,9 +45,9 @@ namespace Flow.Launcher
}
}
- private void OnStartup(object sender, StartupEventArgs e)
+ private async void OnStartupAsync(object sender, StartupEventArgs e)
{
- Stopwatch.Normal("|App.OnStartup|Startup cost", () =>
+ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
{
_portable.PreStartCleanUpAfterPortabilityUpdate();
@@ -68,9 +68,10 @@ namespace Flow.Launcher
PluginManager.LoadPlugins(_settings.PluginSettings);
_mainVM = new MainViewModel(_settings);
- var window = new MainWindow(_settings, _mainVM);
API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet);
- PluginManager.InitializePlugins(API);
+ await PluginManager.InitializePlugins(API);
+ var window = new MainWindow(_settings, _mainVM);
+
Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}");
Current.MainWindow = window;
diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj
index 8548ba39e..fddaaab6a 100644
--- a/Flow.Launcher/Flow.Launcher.csproj
+++ b/Flow.Launcher/Flow.Launcher.csproj
@@ -1,4 +1,4 @@
-
+
WinExe
@@ -60,6 +60,12 @@
Designer
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
@@ -78,7 +84,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
+
@@ -87,116 +94,7 @@
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
-
-
-
-
-
\ No newline at end of file
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..1e0e6a7e0 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -43,6 +43,8 @@
Action keyword:
Current action keyword:
New action keyword:
+ Current Priority:
+ New Priority:
Plugin Directory
Author
Init time:
@@ -72,7 +74,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
@@ -104,6 +106,10 @@
Release Notes
+
+ Greater the number, the higher the result will be ranked. Try setting it as 5. If you want the results to be lower than any other plugin's, provide a negative number
+ Please provide an valid integer for Priority!
+
Old Action Keyword
New Action Keyword
diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml
index bf001d507..85fc1462c 100644
--- a/Flow.Launcher/Languages/sk.xaml
+++ b/Flow.Launcher/Languages/sk.xaml
@@ -45,8 +45,8 @@
Nová akcia skratky:
Priečinok s pluginmi
Autor
- Príprava: {0}ms
- Čas dopytu: {0}ms
+ Príprava:
+ Čas dopytu:
Motív
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/PriorityChangeWindow.xaml.cs b/Flow.Launcher/PriorityChangeWindow.xaml.cs
new file mode 100644
index 000000000..0adb1f080
--- /dev/null
+++ b/Flow.Launcher/PriorityChangeWindow.xaml.cs
@@ -0,0 +1,69 @@
+using Flow.Launcher.Core.Plugin;
+using Flow.Launcher.Core.Resource;
+using Flow.Launcher.Infrastructure.UserSettings;
+using Flow.Launcher.Plugin;
+using Flow.Launcher.ViewModel;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace Flow.Launcher
+{
+ ///
+ /// Interaction Logic of PriorityChangeWindow.xaml
+ ///
+ public partial class PriorityChangeWindow : Window
+ {
+ private readonly PluginPair plugin;
+ private Settings settings;
+ private readonly Internationalization translater = InternationalizationManager.Instance;
+ private readonly PluginViewModel pluginViewModel;
+
+ public PriorityChangeWindow(string pluginId, Settings settings, PluginViewModel pluginViewModel)
+ {
+ InitializeComponent();
+ plugin = PluginManager.GetPluginForId(pluginId);
+ this.settings = settings;
+ this.pluginViewModel = pluginViewModel;
+ if (plugin == null)
+ {
+ MessageBox.Show(translater.GetTranslation("cannotFindSpecifiedPlugin"));
+ Close();
+ }
+ }
+
+ private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
+ {
+ Close();
+ }
+
+ private void btnDone_OnClick(object sender, RoutedEventArgs e)
+ {
+ if (int.TryParse(tbAction.Text.Trim(), out var newPriority))
+ {
+ pluginViewModel.ChangePriority(newPriority);
+ Close();
+ }
+ else
+ {
+ string msg = translater.GetTranslation("invalidPriority");
+ MessageBox.Show(msg);
+ }
+
+ }
+
+ private void PriorityChangeWindow_Loaded(object sender, RoutedEventArgs e)
+ {
+ OldPriority.Text = pluginViewModel.Priority.ToString();
+ tbAction.Focus();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index 90d4fff63..17673a62a 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -78,9 +78,9 @@ namespace Flow.Launcher
ImageLoader.Save();
}
- public void ReloadAllPluginData()
+ public Task ReloadAllPluginData()
{
- PluginManager.ReloadData();
+ return PluginManager.ReloadData();
}
public void ShowMsg(string title, string subTitle = "", string iconPath = "")
@@ -92,7 +92,7 @@ namespace Flow.Launcher
{
Application.Current.Dispatcher.Invoke(() =>
{
- var msg = useMainWindowAsOwner ? new Msg {Owner = Application.Current.MainWindow} : new Msg();
+ var msg = useMainWindowAsOwner ? new Msg { Owner = Application.Current.MainWindow } : new Msg();
msg.Show(title, subTitle, iconPath);
});
}
diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml
index 32f9e9a6e..21d7e88f7 100644
--- a/Flow.Launcher/SettingWindow.xaml
+++ b/Flow.Launcher/SettingWindow.xaml
@@ -8,6 +8,7 @@
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
x:Class="Flow.Launcher.SettingWindow"
mc:Ignorable="d"
Icon="Images\app.png"
@@ -172,10 +173,14 @@
-
+
+
+ Margin="5 0 0 0"/>
-
+
@@ -429,8 +435,8 @@
-
-
+
+
diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs
index e5583da33..a922b4d67 100644
--- a/Flow.Launcher/SettingWindow.xaml.cs
+++ b/Flow.Launcher/SettingWindow.xaml.cs
@@ -206,7 +206,16 @@ namespace Flow.Launcher
{
var id = viewModel.SelectedPlugin.PluginPair.Metadata.ID;
// used to sync the current status from the plugin manager into the setting to keep consistency after save
- settings.PluginSettings.Plugins[id].Disabled = viewModel.SelectedPlugin.PluginPair.Metadata.Disabled;
+ settings.PluginSettings.Plugins[id].Disabled = viewModel.SelectedPlugin.PluginPair.Metadata.Disabled;
+ }
+
+ private void OnPluginPriorityClick(object sender, MouseButtonEventArgs e)
+ {
+ if (e.ChangedButton == MouseButton.Left)
+ {
+ PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(viewModel.SelectedPlugin.PluginPair.Metadata.ID, settings, viewModel.SelectedPlugin);
+ priorityChangeWindow.ShowDialog();
+ }
}
private void OnPluginActionKeywordsClick(object sender, MouseButtonEventArgs e)
@@ -281,5 +290,6 @@ namespace Flow.Launcher
{
FilesFolders.OpenPath(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
}
+
}
-}
+}
\ No newline at end of file
diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs
index de3bcaa22..2b2103605 100644
--- a/Flow.Launcher/Storage/QueryHistory.cs
+++ b/Flow.Launcher/Storage/QueryHistory.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using Newtonsoft.Json;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Storage
diff --git a/Flow.Launcher/Storage/TopMostRecord.cs b/Flow.Launcher/Storage/TopMostRecord.cs
index c110bdf92..c92ef4956 100644
--- a/Flow.Launcher/Storage/TopMostRecord.cs
+++ b/Flow.Launcher/Storage/TopMostRecord.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
-using Newtonsoft.Json;
+using System.Text.Json;
+using System.Text.Json.Serialization;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Storage
@@ -8,21 +9,24 @@ namespace Flow.Launcher.Storage
// todo this class is not thread safe.... but used from multiple threads.
public class TopMostRecord
{
- [JsonProperty]
- private Dictionary records = new Dictionary();
+ ///
+ /// You should not directly access this field
+ ///
+ /// It is public due to System.Text.Json limitation in version 3.1
+ ///
+ ///
+ /// TODO: Set it to private
+ public Dictionary records { get; set; } = new Dictionary();
internal bool IsTopMost(Result result)
{
- if (records.Count == 0)
+ if (records.Count == 0 || !records.ContainsKey(result.OriginQuery.RawQuery))
{
return false;
}
- // since this dictionary should be very small (or empty) going over it should be pretty fast.
- return records.Any(o => o.Value.Title == result.Title
- && o.Value.SubTitle == result.SubTitle
- && o.Value.PluginID == result.PluginID
- && o.Key == result.OriginQuery.RawQuery);
+ // since this dictionary should be very small (or empty) going over it should be pretty fast.
+ return records[result.OriginQuery.RawQuery].Equals(result);
}
internal void Remove(Result result)
@@ -54,5 +58,12 @@ namespace Flow.Launcher.Storage
public string Title { get; set; }
public string SubTitle { get; set; }
public string PluginID { get; set; }
+
+ public bool Equals(Result r)
+ {
+ return Title == r.Title
+ && SubTitle == r.SubTitle
+ && PluginID == r.PluginID;
+ }
}
}
diff --git a/Flow.Launcher/Storage/UserSelectedRecord.cs b/Flow.Launcher/Storage/UserSelectedRecord.cs
index 1fda04e9b..bc7a2da73 100644
--- a/Flow.Launcher/Storage/UserSelectedRecord.cs
+++ b/Flow.Launcher/Storage/UserSelectedRecord.cs
@@ -1,5 +1,5 @@
using System.Collections.Generic;
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Plugin;
@@ -7,15 +7,27 @@ namespace Flow.Launcher.Storage
{
public class UserSelectedRecord
{
- [JsonProperty]
- private Dictionary records = new Dictionary();
+ ///
+ /// You should not directly access this field
+ ///
+ /// It is public due to System.Text.Json limitation in version 3.1
+ ///
+ ///
+ /// TODO: Set it to private
+ [JsonPropertyName("records")]
+ public Dictionary records { get; set; }
+
+ public UserSelectedRecord()
+ {
+ records = new Dictionary();
+ }
public void Add(Result result)
{
var key = result.ToString();
- if (records.TryGetValue(key, out int value))
+ if (records.ContainsKey(key))
{
- records[key] = value + 1;
+ records[key]++;
}
else
{
diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index 7a3aa9f2f..a062f59dc 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -21,6 +21,7 @@ using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Storage;
using System.Windows.Media;
using Flow.Launcher.Infrastructure.Image;
+using Flow.Launcher.Infrastructure.Logger;
namespace Flow.Launcher.ViewModel
{
@@ -85,7 +86,7 @@ namespace Flow.Launcher.ViewModel
{
foreach (var pair in PluginManager.GetPluginsForInterface())
{
- var plugin = (IResultUpdated)pair.Plugin;
+ var plugin = (IResultUpdated) pair.Plugin;
plugin.ResultsUpdated += (s, e) =>
{
Task.Run(() =>
@@ -112,25 +113,13 @@ namespace Flow.Launcher.ViewModel
}
});
- SelectNextItemCommand = new RelayCommand(_ =>
- {
- SelectedResults.SelectNextResult();
- });
+ SelectNextItemCommand = new RelayCommand(_ => { SelectedResults.SelectNextResult(); });
- SelectPrevItemCommand = new RelayCommand(_ =>
- {
- SelectedResults.SelectPrevResult();
- });
+ SelectPrevItemCommand = new RelayCommand(_ => { SelectedResults.SelectPrevResult(); });
- SelectNextPageCommand = new RelayCommand(_ =>
- {
- SelectedResults.SelectNextPage();
- });
+ SelectNextPageCommand = new RelayCommand(_ => { SelectedResults.SelectNextPage(); });
- SelectPrevPageCommand = new RelayCommand(_ =>
- {
- SelectedResults.SelectPrevPage();
- });
+ SelectPrevPageCommand = new RelayCommand(_ => { SelectedResults.SelectPrevPage(); });
SelectFirstResultCommand = new RelayCommand(_ => SelectedResults.SelectFirstResult());
@@ -208,6 +197,7 @@ namespace Flow.Launcher.ViewModel
public ResultsViewModel History { get; private set; }
private string _queryText;
+
public string QueryText
{
get { return _queryText; }
@@ -228,10 +218,12 @@ namespace Flow.Launcher.ViewModel
QueryTextCursorMovedToEnd = true;
QueryText = queryText;
}
+
public bool LastQuerySelected { get; set; }
public bool QueryTextCursorMovedToEnd { get; set; }
private ResultsViewModel _selectedResults;
+
private ResultsViewModel SelectedResults
{
get { return _selectedResults; }
@@ -263,6 +255,7 @@ namespace Flow.Launcher.ViewModel
QueryText = string.Empty;
}
}
+
_selectedResults.Visbility = Visibility.Visible;
}
}
@@ -284,7 +277,7 @@ namespace Flow.Launcher.ViewModel
public string OpenResultCommandModifiers { get; private set; }
- public ImageSource Image => ImageLoader.Load(Constant.QueryTextBoxIconImagePath);
+ public string Image => Constant.QueryTextBoxIconImagePath;
#endregion
@@ -323,7 +316,7 @@ namespace Flow.Launcher.ViewModel
var filtered = results.Where
(
r => StringMatcher.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet()
- || StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet()
+ || StringMatcher.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet()
).ToList();
ContextMenu.AddResults(filtered, id);
}
@@ -350,7 +343,7 @@ namespace Flow.Launcher.ViewModel
Title = string.Format(title, h.Query),
SubTitle = string.Format(time, h.ExecutedDateTime),
IcoPath = "Images\\history.png",
- OriginQuery = new Query { RawQuery = h.Query },
+ OriginQuery = new Query {RawQuery = h.Query},
Action = _ =>
{
SelectedResults = Results;
@@ -396,7 +389,8 @@ namespace Flow.Launcher.ViewModel
_lastQuery = query;
Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
- { // start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
+ {
+ // start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
if (currentUpdateSource == _updateSource && _isQueryRunning)
{
ProgressBarVisibility = Visibility.Visible;
@@ -404,35 +398,56 @@ namespace Flow.Launcher.ViewModel
}, currentCancellationToken);
var plugins = PluginManager.ValidPluginsForQuery(query);
- Task.Run(() =>
+ Task.Run(async () =>
{
// so looping will stop once it was cancelled
- var parallelOptions = new ParallelOptions { CancellationToken = currentCancellationToken };
+
+ Task[] tasks = new Task[plugins.Count];
try
{
- Parallel.ForEach(plugins, parallelOptions, plugin =>
+ for (var i = 0; i < plugins.Count; i++)
{
- if (!plugin.Metadata.Disabled)
+ if (!plugins[i].Metadata.Disabled)
{
- var results = PluginManager.QueryForPlugin(plugin, query);
- UpdateResultView(results, plugin.Metadata, query);
+ tasks[i] = QueryTask(plugins[i], query, currentCancellationToken);
}
- });
+ else
+ {
+ tasks[i] = Task.CompletedTask; // Avoid Null
+ }
+ }
+
+ // Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
+ await Task.WhenAll(tasks);
}
catch (OperationCanceledException)
{
// nothing to do here
}
-
// this should happen once after all queries are done so progress bar should continue
// until the end of all querying
_isQueryRunning = false;
- if (currentUpdateSource == _updateSource)
- { // update to hidden if this is still the current query
+ if (!currentCancellationToken.IsCancellationRequested)
+ {
+ // update to hidden if this is still the current query
ProgressBarVisibility = Visibility.Hidden;
}
- }, currentCancellationToken);
+
+ // Local function
+ async Task QueryTask(PluginPair plugin, Query query, CancellationToken token)
+ {
+ // Since it is wrapped within a Task.Run, the synchronous context is null
+ // Task.Yield will force it to run in ThreadPool
+ await Task.Yield();
+
+ var results = await PluginManager.QueryForPlugin(plugin, query, token);
+ if (!currentCancellationToken.IsCancellationRequested)
+ UpdateResultView(results, plugin.Metadata, query);
+ }
+ }, currentCancellationToken).ContinueWith(
+ t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception),
+ TaskContinuationOptions.OnlyOnFaulted);
}
}
else
@@ -499,6 +514,7 @@ namespace Flow.Launcher.ViewModel
}
};
}
+
return menu;
}
@@ -544,6 +560,7 @@ namespace Flow.Launcher.ViewModel
var selected = SelectedResults == History;
return selected;
}
+
#region Hotkey
private void SetHotkey(string hotkeyStr, EventHandler action)
@@ -562,7 +579,8 @@ namespace Flow.Launcher.ViewModel
catch (Exception)
{
string errorMsg =
- string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr);
+ string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"),
+ hotkeyStr);
MessageBox.Show(errorMsg);
}
}
@@ -612,7 +630,6 @@ namespace Flow.Launcher.ViewModel
{
if (!ShouldIgnoreHotkeys())
{
-
if (_settings.LastQueryMode == LastQueryMode.Empty)
{
ChangeQueryText(string.Empty);
@@ -676,7 +693,8 @@ namespace Flow.Launcher.ViewModel
}
else
{
- result.Score += _userSelectedRecord.GetSelectedCount(result) * 5;
+ var priorityScore = metadata.Priority * 150;
+ result.Score += _userSelectedRecord.GetSelectedCount(result) * 5 + priorityScore;
}
}
diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs
index eb7e0054d..7c8814b41 100644
--- a/Flow.Launcher/ViewModel/PluginViewModel.cs
+++ b/Flow.Launcher/ViewModel/PluginViewModel.cs
@@ -26,6 +26,7 @@ namespace Flow.Launcher.ViewModel
public string InitilizaTime => PluginPair.Metadata.InitTime.ToString() + "ms";
public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms";
public string ActionKeywordsText => string.Join(Query.ActionKeywordSeperater, PluginPair.Metadata.ActionKeywords);
+ public int Priority => PluginPair.Metadata.Priority;
public void ChangeActionKeyword(string newActionKeyword, string oldActionKeyword)
{
@@ -34,6 +35,12 @@ namespace Flow.Launcher.ViewModel
OnPropertyChanged(nameof(ActionKeywordsText));
}
+ public void ChangePriority(int newPriority)
+ {
+ PluginPair.Metadata.Priority = newPriority;
+ OnPropertyChanged(nameof(Priority));
+ }
+
public bool IsActionKeywordRegistered(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
}
}
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 853925852..3c90f8712 100644
--- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
+++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
@@ -88,6 +88,7 @@ namespace Flow.Launcher.ViewModel
var id = vm.PluginPair.Metadata.ID;
Settings.PluginSettings.Plugins[id].Disabled = vm.PluginPair.Metadata.Disabled;
+ Settings.PluginSettings.Plugins[id].Priority = vm.Priority;
}
PluginManager.Save();
@@ -213,7 +214,7 @@ namespace Flow.Launcher.ViewModel
#region plugin
- public static string Plugin => "http://www.wox.one/plugin";
+ public static string Plugin => @"https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest";
public PluginViewModel SelectedPlugin { get; set; }
public IList PluginViewModels
@@ -438,7 +439,7 @@ namespace Flow.Launcher.ViewModel
}
}
- public ImageSource ThemeImage => ImageLoader.Load(Constant.QueryTextBoxIconImagePath);
+ public string ThemeImage => Constant.QueryTextBoxIconImagePath;
#endregion
@@ -450,7 +451,7 @@ namespace Flow.Launcher.ViewModel
#region about
- public string Github => _updater.GitHubRepository;
+ public string Website => Constant.Website;
public string ReleaseNotes => _updater.GitHubRepository + @"/releases/latest";
public static string Version => Constant.Version;
public string ActivatedTimes => string.Format(_translater.GetTranslation("about_activate_times"), Settings.ActivateTimes);
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
index 85b745a6b..d2a8736a6 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -40,14 +40,6 @@
-
- Always
-
-
- Designer
- MSBuild:Compile
- PreserveNewest
-
Always
@@ -60,13 +52,16 @@
-
+
-
+
MSBuild:Compile
Designer
PreserveNewest
+
+ PreserveNewest
+
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
index de4f3849b..b0c3d2e29 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
@@ -4,7 +4,7 @@
"Name": "Browser Bookmarks",
"Description": "Search your browser bookmarks",
"Author": "qianlifeng, Ioannis G.",
- "Version": "1.3.1",
+ "Version": "1.3.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj
index 9e1fefdb3..1090926fc 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj
@@ -11,6 +11,7 @@
true
false
false
+ en
@@ -43,57 +44,14 @@
-
+
-
- PreserveNewest
-
-
-
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
index 949911229..5b23ceacc 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
@@ -91,7 +91,7 @@ namespace Flow.Launcher.Plugin.Caculator
};
}
}
- catch
+ catch (Exception)
{
// ignored
}
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
index 709757d1a..7d9ca58d5 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
@@ -4,7 +4,7 @@
"Name": "Calculator",
"Description": "Provide mathematical calculations.(Try 5*3-2 in Flow Launcher)",
"Author": "cxfksword",
- "Version": "1.1.3",
+ "Version": "1.1.4",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Caculator.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj b/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj
deleted file mode 100644
index c7fe8271a..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj
+++ /dev/null
@@ -1,101 +0,0 @@
-
-
-
- Library
- netcoreapp3.1
- {F35190AA-4758-4D9E-A193-E3BDF6AD3567}
- Properties
- Flow.Launcher.Plugin.Color
- Flow.Launcher.Plugin.Color
- true
- false
- false
-
-
-
- true
- full
- false
- ..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.Color\
- DEBUG;TRACE
- prompt
- 4
- false
-
-
-
- pdbonly
- true
- ..\..\Output\Release\Plugins\Flow.Launcher.Plugin.Color\
- TRACE
- prompt
- 4
- false
-
-
-
-
- PreserveNewest
-
-
-
-
-
- PreserveNewest
-
-
-
-
-
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Images/color.png b/Plugins/Flow.Launcher.Plugin.Color/Images/color.png
deleted file mode 100644
index da28583b1..000000000
Binary files a/Plugins/Flow.Launcher.Plugin.Color/Images/color.png and /dev/null differ
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/de.xaml
deleted file mode 100644
index 3244dee14..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/de.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Farben
- Stellt eine HEX-Farben Vorschau bereit. (Versuche #000 in Flow Launcher)
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/en.xaml
deleted file mode 100644
index 85e2830db..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/en.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Colors
- Allows to preview colors using hex values.(Try #000 in Flow Launcher)
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/pl.xaml
deleted file mode 100644
index 15525cfe9..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/pl.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Kolory
- Podgląd kolorów po wpisaniu ich kodu szesnastkowego. (Spróbuj wpisać #000 w oknie Flow Launchera)
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/sk.xaml
deleted file mode 100644
index 4b208691a..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/sk.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Farby
- Zobrazuje náhľad farieb v HEX formáte. (Skúste #000 vo Flow Launcheri)
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/tr.xaml
deleted file mode 100644
index f56e73526..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/tr.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- Renkler
- Hex kodunu girdiğiniz renkleri görüntülemeye yarar.(#000 yazmayı deneyin)
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/zh-cn.xaml
deleted file mode 100644
index 39ede4844..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/zh-cn.xaml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
- 颜色
- 提供在Flow Launcher查询hex颜色。(尝试在Flow Launcher中输入#000)
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Color/Languages/zh-tw.xaml
deleted file mode 100644
index 4e7062a22..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Languages/zh-tw.xaml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
- 顏色
- 提供在 Flow Launcher 查詢 hex 顏色。(試著在 Flow Launcher 中輸入 #000)
-
diff --git a/Plugins/Flow.Launcher.Plugin.Color/Main.cs b/Plugins/Flow.Launcher.Plugin.Color/Main.cs
deleted file mode 100644
index a15483ebc..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/Main.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.IO;
-using System.Linq;
-using System.Windows;
-
-namespace Flow.Launcher.Plugin.Color
-{
- public sealed class ColorsPlugin : IPlugin, IPluginI18n
- {
- private string DIR_PATH = Path.Combine(Path.GetTempPath(), @"Plugins\Colors\");
- private PluginInitContext context;
- private const int IMG_SIZE = 32;
-
- private DirectoryInfo ColorsDirectory { get; set; }
-
- public ColorsPlugin()
- {
- if (!Directory.Exists(DIR_PATH))
- {
- ColorsDirectory = Directory.CreateDirectory(DIR_PATH);
- }
- else
- {
- ColorsDirectory = new DirectoryInfo(DIR_PATH);
- }
- }
-
- public List Query(Query query)
- {
- var raw = query.Search;
- if (!IsAvailable(raw)) return new List(0);
- try
- {
- var cached = Find(raw);
- if (cached.Length == 0)
- {
- var path = CreateImage(raw);
- return new List
- {
- new Result
- {
- Title = raw,
- IcoPath = path,
- Action = _ =>
- {
- Clipboard.SetText(raw);
- return true;
- }
- }
- };
- }
- return cached.Select(x => new Result
- {
- Title = raw,
- IcoPath = x.FullName,
- Action = _ =>
- {
- Clipboard.SetText(raw);
- return true;
- }
- }).ToList();
- }
- catch (Exception exception)
- {
- // todo: log
- return new List(0);
- }
- }
-
- private bool IsAvailable(string query)
- {
- // todo: rgb, names
- var length = query.Length - 1; // minus `#` sign
- return query.StartsWith("#") && (length == 3 || length == 6);
- }
-
- public FileInfo[] Find(string name)
- {
- var file = string.Format("{0}.png", name.Substring(1));
- return ColorsDirectory.GetFiles(file, SearchOption.TopDirectoryOnly);
- }
-
- private string CreateImage(string name)
- {
- using (var bitmap = new Bitmap(IMG_SIZE, IMG_SIZE))
- using (var graphics = Graphics.FromImage(bitmap))
- {
- var color = ColorTranslator.FromHtml(name);
- graphics.Clear(color);
-
- var path = CreateFileName(name);
- bitmap.Save(path, ImageFormat.Png);
- return path;
- }
- }
-
- private string CreateFileName(string name)
- {
- return string.Format("{0}{1}.png", ColorsDirectory.FullName, name.Substring(1));
- }
-
- public void Init(PluginInitContext context)
- {
- this.context = context;
- }
-
-
- public string GetTranslatedPluginTitle()
- {
- return context.API.GetTranslation("flowlauncher_plugin_color_plugin_name");
- }
-
- public string GetTranslatedPluginDescription()
- {
- return context.API.GetTranslation("flowlauncher_plugin_color_plugin_description");
- }
- }
-}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Color/plugin.json b/Plugins/Flow.Launcher.Plugin.Color/plugin.json
deleted file mode 100644
index 8c0c483ba..000000000
--- a/Plugins/Flow.Launcher.Plugin.Color/plugin.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "ID": "9B36CE6181FC47FBB597AA2C29CD9B0A",
- "ActionKeyword": "*",
- "Name": "Colors",
- "Description": "Provide hex color preview.(Try #000 in Flow Launcher)",
- "Author": "qianlifeng",
- "Version": "1.1.1",
- "Language": "csharp",
- "Website": "https://github.com/Flow-Launcher/Flow.Launcher",
- "ExecuteFileName": "Flow.Launcher.Plugin.Color.dll",
- "IcoPath": "Images\\color.png"
-}
diff --git a/Plugins/Flow.Launcher.Plugin.ControlPanel/ControlPanelList.cs b/Plugins/Flow.Launcher.Plugin.ControlPanel/ControlPanelList.cs
index fdcffb0b3..70afda536 100644
--- a/Plugins/Flow.Launcher.Plugin.ControlPanel/ControlPanelList.cs
+++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/ControlPanelList.cs
@@ -38,7 +38,7 @@ namespace Flow.Launcher.Plugin.ControlPanel
int cxDesired, int cyDesired, uint fuLoad);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
- extern static bool DestroyIcon(IntPtr handle);
+ static extern bool DestroyIcon(IntPtr handle);
[DllImport("kernel32.dll")]
static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType);
diff --git a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj
index 699737634..06969a135 100644
--- a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj
+++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj
@@ -45,53 +45,10 @@
-
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
+
MSBuild:Compile
Designer
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.ControlPanel/plugin.json b/Plugins/Flow.Launcher.Plugin.ControlPanel/plugin.json
index 4f552a014..23f35e9ac 100644
--- a/Plugins/Flow.Launcher.Plugin.ControlPanel/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/plugin.json
@@ -4,7 +4,7 @@
"Name": "Control Panel",
"Description": "Search within the Control Panel.",
"Author": "CoenraadS",
- "Version": "1.1.1",
+ "Version": "1.1.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.ControlPanel.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
index a1a08843a..9f0b46d93 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
@@ -7,6 +7,7 @@
true
true
false
+ en
@@ -26,73 +27,10 @@
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- Always
-
-
-
+
PreserveNewest
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- PreserveNewest
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
+
MSBuild:Compile
Designer
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
index 30a06e882..7b56df691 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
@@ -3,11 +3,13 @@ using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.ViewModels;
using Flow.Launcher.Plugin.Explorer.Views;
using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
using System.Windows.Controls;
namespace Flow.Launcher.Plugin.Explorer
{
- public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n
+ public class Main : ISettingProvider, IAsyncPlugin, ISavable, IContextMenu, IPluginI18n
{
internal PluginInitContext Context { get; set; }
@@ -17,17 +19,21 @@ namespace Flow.Launcher.Plugin.Explorer
private IContextMenu contextMenu;
+ private SearchManager searchManager;
+
public Control CreateSettingPanel()
{
return new ExplorerSettings(viewModel);
}
- public void Init(PluginInitContext context)
+ public async Task InitAsync(PluginInitContext context)
{
Context = context;
viewModel = new SettingsViewModel(context);
+ await viewModel.LoadStorage();
Settings = viewModel.Settings;
contextMenu = new ContextMenu(Context, Settings);
+ searchManager = new SearchManager(Settings, Context);
}
public List LoadContextMenus(Result selectedResult)
@@ -35,9 +41,9 @@ namespace Flow.Launcher.Plugin.Explorer
return contextMenu.LoadContextMenus(selectedResult);
}
- public List Query(Query query)
+ public async Task> QueryAsync(Query query, CancellationToken token)
{
- return new SearchManager(Settings, Context).Search(query);
+ return await searchManager.SearchAsync(query, token);
}
public void Save()
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
index 02de0eeae..88d7d6927 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
@@ -22,7 +22,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
if (search.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > search.LastIndexOf(Constants.DirectorySeperator))
return DirectorySearch(SearchOption.AllDirectories, query, search, criteria);
-
+
return DirectorySearch(SearchOption.TopDirectoryOnly, query, search, criteria);
}
@@ -57,9 +57,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
try
{
var directoryInfo = new System.IO.DirectoryInfo(path);
- var fileSystemInfos = directoryInfo.GetFileSystemInfos(searchCriteria, searchOption);
- foreach (var fileSystemInfo in fileSystemInfos)
+ foreach (var fileSystemInfo in directoryInfo.EnumerateFileSystemInfos(searchCriteria, searchOption))
{
if ((fileSystemInfo.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden) continue;
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/FolderLink.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/FolderLink.cs
index 379b5848f..43ecdad97 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/FolderLink.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/FolderLink.cs
@@ -1,15 +1,15 @@
-using Newtonsoft.Json;
-using System;
+using System;
using System.Linq;
+using System.Text.Json;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin.Explorer.Search.FolderLinks
{
- [JsonObject(MemberSerialization.OptIn)]
public class FolderLink
{
- [JsonProperty]
public string Path { get; set; }
+ [JsonIgnore]
public string Nickname
{
get
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
index 5b50b7fad..6b3a96912 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
@@ -5,6 +5,8 @@ using Flow.Launcher.Plugin.SharedCommands;
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
namespace Flow.Launcher.Plugin.Explorer.Search
{
@@ -28,20 +30,20 @@ namespace Flow.Launcher.Plugin.Explorer.Search
this.settings = settings;
}
- internal List Search(Query query)
+ internal async Task> SearchAsync(Query query, CancellationToken token)
{
var results = new List();
var querySearch = query.Search;
if (IsFileContentSearch(query.ActionKeyword))
- return WindowsIndexFileContentSearch(query, querySearch);
+ return await WindowsIndexFileContentSearchAsync(query, querySearch, token).ConfigureAwait(false);
// This allows the user to type the assigned action keyword and only see the list of quick folder links
if (settings.QuickFolderAccessLinks.Count > 0
&& query.ActionKeyword == settings.SearchActionKeyword
&& string.IsNullOrEmpty(query.Search))
- return quickFolderAccess.FolderListAll(query, settings.QuickFolderAccessLinks, context);
+ return quickFolderAccess.FolderListAll(query, settings.QuickFolderAccessLinks, context);
var quickFolderLinks = quickFolderAccess.FolderListMatched(query, settings.QuickFolderAccessLinks, context);
@@ -54,11 +56,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search
return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, context);
// Query is a location path with a full environment variable, eg. %appdata%\somefolder\
- var isEnvironmentVariablePath = querySearch.Substring(1).Contains("%\\");
+ var isEnvironmentVariablePath = querySearch[1..].Contains("%\\");
if (!FilesFolders.IsLocationPathString(querySearch) && !isEnvironmentVariablePath)
{
- results.AddRange(WindowsIndexFilesAndFoldersSearch(query, querySearch));
+ results.AddRange(await WindowsIndexFilesAndFoldersSearchAsync(query, querySearch, token).ConfigureAwait(false));
return results;
}
@@ -72,29 +74,34 @@ namespace Flow.Launcher.Plugin.Explorer.Search
return results;
var useIndexSearch = UseWindowsIndexForDirectorySearch(locationPath);
-
+
results.Add(resultManager.CreateOpenCurrentFolderResult(locationPath, useIndexSearch));
- results.AddRange(TopLevelDirectorySearchBehaviour(WindowsIndexTopLevelFolderSearch,
+ if (token.IsCancellationRequested)
+ return null;
+
+ results.AddRange(await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync,
DirectoryInfoClassSearch,
useIndexSearch,
query,
- locationPath));
+ locationPath,
+ token).ConfigureAwait(false));
return results;
}
- private List WindowsIndexFileContentSearch(Query query, string querySearchString)
+ private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString, CancellationToken token)
{
var queryConstructor = new QueryConstructor(settings);
if (string.IsNullOrEmpty(querySearchString))
return new List();
- return indexSearch.WindowsIndexSearch(querySearchString,
+ return await indexSearch.WindowsIndexSearchAsync(querySearchString,
queryConstructor.CreateQueryHelper().ConnectionString,
queryConstructor.QueryForFileContentSearch,
- query);
+ query,
+ token).ConfigureAwait(false);
}
public bool IsFileContentSearch(string actionKeyword)
@@ -109,37 +116,40 @@ namespace Flow.Launcher.Plugin.Explorer.Search
return directoryInfoSearch.TopLevelDirectorySearch(query, querySearch);
}
- public List TopLevelDirectorySearchBehaviour(
- Func> windowsIndexSearch,
+ public async Task> TopLevelDirectorySearchBehaviourAsync(
+ Func>> windowsIndexSearch,
Func> directoryInfoClassSearch,
bool useIndexSearch,
Query query,
- string querySearchString)
+ string querySearchString,
+ CancellationToken token)
{
if (!useIndexSearch)
return directoryInfoClassSearch(query, querySearchString);
- return windowsIndexSearch(query, querySearchString);
+ return await windowsIndexSearch(query, querySearchString, token);
}
- private List WindowsIndexFilesAndFoldersSearch(Query query, string querySearchString)
+ private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString, CancellationToken token)
{
var queryConstructor = new QueryConstructor(settings);
- return indexSearch.WindowsIndexSearch(querySearchString,
+ return await indexSearch.WindowsIndexSearchAsync(querySearchString,
queryConstructor.CreateQueryHelper().ConnectionString,
queryConstructor.QueryForAllFilesAndFolders,
- query);
+ query,
+ token).ConfigureAwait(false);
}
-
- private List WindowsIndexTopLevelFolderSearch(Query query, string path)
+
+ private async Task> WindowsIndexTopLevelFolderSearchAsync(Query query, string path, CancellationToken token)
{
var queryConstructor = new QueryConstructor(settings);
- return indexSearch.WindowsIndexSearch(path,
+ return await indexSearch.WindowsIndexSearchAsync(path,
queryConstructor.CreateQueryHelper().ConnectionString,
queryConstructor.QueryForTopLevelDirectorySearch,
- query);
+ query,
+ token).ConfigureAwait(false);
}
private bool UseWindowsIndexForDirectorySearch(string locationPath)
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
index 4f9325c77..5b1d47ef8 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
@@ -5,19 +5,13 @@ using System.Collections.Generic;
using System.Data.OleDb;
using System.Linq;
using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{
internal class IndexSearch
{
- private readonly object _lock = new object();
-
- private OleDbConnection conn;
-
- private OleDbCommand command;
-
- private OleDbDataReader dataReaderResults;
-
private readonly ResultManager resultManager;
// Reserved keywords in oleDB
@@ -28,7 +22,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
resultManager = new ResultManager(context);
}
- internal List ExecuteWindowsIndexSearch(string indexQueryString, string connectionString, Query query)
+ internal async Task> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token)
{
var folderResults = new List();
var fileResults = new List();
@@ -36,47 +30,49 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
try
{
- using (conn = new OleDbConnection(connectionString))
+ using var conn = new OleDbConnection(connectionString);
+ await conn.OpenAsync(token);
+ token.ThrowIfCancellationRequested();
+
+ using var command = new OleDbCommand(indexQueryString, conn);
+ // Results return as an OleDbDataReader.
+ using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader;
+ token.ThrowIfCancellationRequested();
+
+ if (dataReaderResults.HasRows)
{
- conn.Open();
-
- using (command = new OleDbCommand(indexQueryString, conn))
+ while (await dataReaderResults.ReadAsync(token))
{
- // Results return as an OleDbDataReader.
- using (dataReaderResults = command.ExecuteReader())
+ token.ThrowIfCancellationRequested();
+ if (dataReaderResults.GetValue(0) != DBNull.Value && dataReaderResults.GetValue(1) != DBNull.Value)
{
- if (dataReaderResults.HasRows)
- {
- while (dataReaderResults.Read())
- {
- if (dataReaderResults.GetValue(0) != DBNull.Value && dataReaderResults.GetValue(1) != DBNull.Value)
- {
- // # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
- var encodedFragmentPath = dataReaderResults
- .GetString(1)
- .Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
-
- var path = new Uri(encodedFragmentPath).LocalPath;
+ // # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
+ var encodedFragmentPath = dataReaderResults
+ .GetString(1)
+ .Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
- if (dataReaderResults.GetString(2) == "Directory")
- {
- folderResults.Add(resultManager.CreateFolderResult(
- dataReaderResults.GetString(0),
- path,
- path,
- query, true, true));
- }
- else
- {
- fileResults.Add(resultManager.CreateFileResult(path, query, true, true));
- }
- }
- }
+ var path = new Uri(encodedFragmentPath).LocalPath;
+
+ if (dataReaderResults.GetString(2) == "Directory")
+ {
+ folderResults.Add(resultManager.CreateFolderResult(
+ dataReaderResults.GetString(0),
+ path,
+ path,
+ query, true, true));
+ }
+ else
+ {
+ fileResults.Add(resultManager.CreateFileResult(path, query, true, true));
}
}
}
}
}
+ catch (OperationCanceledException)
+ {
+ return new List(); // The source code indicates that without adding members, it won't allocate an array
+ }
catch (InvalidOperationException e)
{
// Internal error from ExecuteReader(): Connection closed.
@@ -91,18 +87,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
return results.Concat(folderResults.OrderBy(x => x.Title)).Concat(fileResults.OrderBy(x => x.Title)).ToList(); ;
}
- internal List WindowsIndexSearch(string searchString, string connectionString, Func constructQuery, Query query)
+ internal async Task> WindowsIndexSearchAsync(string searchString, string connectionString,
+ Func constructQuery, Query query,
+ CancellationToken token)
{
var regexMatch = Regex.Match(searchString, reservedStringPattern);
if (regexMatch.Success)
return new List();
- lock (_lock)
- {
- var constructedQuery = constructQuery(searchString);
- return ExecuteWindowsIndexSearch(constructedQuery, connectionString, query);
- }
+ var constructedQuery = constructQuery(searchString);
+ return await ExecuteWindowsIndexSearchAsync(constructedQuery, connectionString, query, token);
+
}
internal bool PathIsIndexed(string path)
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
index 5b12870c8..e62ea93fc 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
@@ -1,28 +1,22 @@
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
-using Newtonsoft.Json;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin.Explorer
{
public class Settings
{
- [JsonProperty]
public int MaxResult { get; set; } = 100;
- [JsonProperty]
public List QuickFolderAccessLinks { get; set; } = new List();
- [JsonProperty]
public bool UseWindowsIndexForDirectorySearch { get; set; } = true;
- [JsonProperty]
public List IndexSearchExcludedSubdirectoryPaths { get; set; } = new List();
- [JsonProperty]
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
- [JsonProperty]
public string FileContentSearchActionKeyword { get; set; } = Constants.DefaultContentSearchActionKeyword;
}
}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
index 7fcd77f07..21bc49741 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
@@ -3,6 +3,7 @@ using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
using System.Diagnostics;
+using System.Threading.Tasks;
namespace Flow.Launcher.Plugin.Explorer.ViewModels
{
@@ -21,6 +22,11 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
Settings = storage.Load();
}
+ public Task LoadStorage()
+ {
+ return Task.Run(() => Settings = storage.Load());
+ }
+
public void Save()
{
storage.Save();
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json
index 2c57ac668..aa44c4413 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json
@@ -7,7 +7,7 @@
"Name": "Explorer",
"Description": "Search and manage files and folders. Explorer utilises Windows Index Search",
"Author": "Jeremy Wu",
- "Version": "1.2.5",
+ "Version": "1.2.6",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj
index e6bfa7aa3..cc280b9a9 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj
+++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj
@@ -10,6 +10,7 @@
true
false
false
+ en
@@ -46,55 +47,12 @@
-
- PreserveNewest
-
-
-
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json
index 80900a445..7f73263a8 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json
@@ -4,7 +4,7 @@
"Name": "Plugin Indicator",
"Description": "Provide plugin actionword suggestion",
"Author": "qianlifeng",
- "Version": "1.1.1",
+ "Version": "1.1.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.PluginIndicator.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs
index d26c1ead4..7bc357be4 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs
@@ -1,4 +1,5 @@
using Flow.Launcher.Infrastructure.UserSettings;
+using Flow.Launcher.Plugin.PluginsManager.Models;
using System;
using System.Collections.Generic;
using System.Text;
@@ -9,21 +10,67 @@ namespace Flow.Launcher.Plugin.PluginsManager
{
private PluginInitContext Context { get; set; }
- private Settings Settings { get; set; }
-
- public ContextMenu(PluginInitContext context, Settings settings)
+ public ContextMenu(PluginInitContext context)
{
Context = context;
- Settings = settings;
}
public List LoadContextMenus(Result selectedResult)
{
- // Open website
- // Go to source code
- // Report an issue?
- // Request a feature?
- return new List();
+ var pluginManifestInfo = selectedResult.ContextData as UserPlugin;
+
+ return new List
+ {
+ new Result
+ {
+ Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_openwebsite_title"),
+ SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_openwebsite_subtitle"),
+ IcoPath = "Images\\website.png",
+ Action = _ =>
+ {
+ SharedCommands.SearchWeb.NewTabInBrowser(pluginManifestInfo.Website);
+ return true;
+ }
+ },
+ new Result
+ {
+ Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_gotosourcecode_title"),
+ SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_gotosourcecode_subtitle"),
+ IcoPath = "Images\\sourcecode.png",
+ Action = _ =>
+ {
+ SharedCommands.SearchWeb.NewTabInBrowser(pluginManifestInfo.UrlSourceCode);
+ return true;
+ }
+ },
+ new Result
+ {
+ Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_newissue_title"),
+ SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_newissue_subtitle"),
+ IcoPath = "Images\\request.png",
+ Action = _ =>
+ {
+ // standard UrlSourceCode format in PluginsManifest's plugins.json file: https://github.com/jjw24/WoxDictionary/tree/master
+ var link = pluginManifestInfo.UrlSourceCode.StartsWith("https://github.com")
+ ? pluginManifestInfo.UrlSourceCode.Replace("/tree/master", "/issues/new/choose")
+ : pluginManifestInfo.UrlSourceCode;
+
+ SharedCommands.SearchWeb.NewTabInBrowser(link);
+ return true;
+ }
+ },
+ new Result
+ {
+ Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_title"),
+ SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_subtitle"),
+ IcoPath = selectedResult.IcoPath,
+ Action = _ =>
+ {
+ SharedCommands.SearchWeb.NewTabInBrowser("https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest");
+ return true;
+ }
+ }
+ };
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj
index cc1a931ce..2e352d832 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj
@@ -27,15 +27,12 @@
PreserveNewest
-
-
-
- PreserveNewest
-
-
-
+
+ PreserveNewest
+
+
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/request.png b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/request.png
new file mode 100644
index 000000000..a9126cb9b
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/request.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/sourcecode.png b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/sourcecode.png
new file mode 100644
index 000000000..8efbdaa48
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/sourcecode.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/website.png b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/website.png
new file mode 100644
index 000000000..f96ba15b2
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/website.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
index 7f8557c28..3017f39c3 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml
@@ -1,4 +1,4 @@
-
@@ -11,6 +11,15 @@
Plugin Install
Plugin Uninstall
Install failed: unable to find the plugin.json metadata file from the new plugin
+ Error installing plugin
+ Error occured while trying to install {0}
+ No update available
+ All plugins are up to date
+ {0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart.
+ Plugin Update
+ This plugin has an update, would you like to see it?
+ This plugin is already installed
+
@@ -18,5 +27,13 @@
Management of installing, uninstalling or updating Flow Launcher plugins
+ Open website
+ Visit the plugin's website
+ See source code
+ See the plugin's source code
+ Suggest an enhancement or submit an issue
+ Suggest an enhancement or submit an issue to the plugin developer
+ Go to Flow's plugins repository
+ Visit the PluginsManifest repository to see comunity-made plugin submissions
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml
new file mode 100644
index 000000000..211f2b430
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml
@@ -0,0 +1,39 @@
+
+
+
+ Sťahovanie pluginu
+ Čakajte, prosím…
+ Úspešne stiahnuté
+ {0} od {1} {2}{3}Chcete odinštalovať tento plugin? Po odinštalovaní sa Flow automaticky reštartuje.
+ {0} by {1} {2}{3}Chcete nainštalovať tento plugin? Po odinštalovaní sa Flow automaticky reštartuje.
+ Inštalovať plugin
+ Odinštalovať plugin
+ Inštalácia zlyhala: nepodarilo sa nájsť metadáta súboru plugin.json nového pluginu
+ Chyba inštalácie pluginu
+ Nastala chyba počas inštaláciu pluginu {0}
+ Nie je k dispozícii žiadna aktualizácia
+ Všetky pluginy sú aktuálne
+ {0} od {1} {2}{3}Chcete aktualizovať tento plugin? Po odinštalovaní sa Flow automaticky reštartuje.
+ Aktualizácia pluginu
+ Tento plugin má dostupnú aktualizáciu, chcete ju zobraziť?
+ Tento plugin je už nainštalovaný
+
+
+
+
+ Správca pluginov
+ Správa inštalácie, odinštalácie alebo aktualizácie pluginov programu Flow Launcher
+
+
+ Prejsť na webovú stránku
+ Prejsť na webovú stránku pluginu
+ Zobraziť zdrojový kód
+ Zobraziť zdrojový kód pluginu
+ Navrhnúť vylepšenie alebo nahlásiť chybu
+ Navrhnúť vylepšenie alebo nahlásiť chybu vývojárovi pluginu
+ Prejsť na repozitár pluginov spúšťača Flow
+ Prejsť na repozitár pluginov spúšťača Flow a zobraziť príspevky komunity
+
+
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs
index 58ec5005f..40579e6e5 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs
@@ -1,13 +1,17 @@
using Flow.Launcher.Infrastructure.Storage;
-using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin.PluginsManager.ViewModels;
using Flow.Launcher.Plugin.PluginsManager.Views;
using System.Collections.Generic;
+using System.Linq;
using System.Windows.Controls;
+using Flow.Launcher.Infrastructure;
+using System;
+using System.Threading.Tasks;
+using System.Threading;
namespace Flow.Launcher.Plugin.PluginsManager
{
- public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n
+ public class Main : ISettingProvider, IAsyncPlugin, ISavable, IContextMenu, IPluginI18n, IAsyncReloadable
{
internal PluginInitContext Context { get; set; }
@@ -17,17 +21,24 @@ namespace Flow.Launcher.Plugin.PluginsManager
private IContextMenu contextMenu;
+ internal PluginsManager pluginManager;
+
+ private DateTime lastUpdateTime = DateTime.MinValue;
+
public Control CreateSettingPanel()
{
return new PluginsManagerSettings(viewModel);
}
- public void Init(PluginInitContext context)
+ public async Task InitAsync(PluginInitContext context)
{
Context = context;
viewModel = new SettingsViewModel(context);
Settings = viewModel.Settings;
- contextMenu = new ContextMenu(Context, Settings);
+ contextMenu = new ContextMenu(Context);
+ pluginManager = new PluginsManager(Context, Settings);
+ await pluginManager.UpdateManifest();
+ lastUpdateTime = DateTime.Now;
}
public List LoadContextMenus(Result selectedResult)
@@ -35,17 +46,30 @@ namespace Flow.Launcher.Plugin.PluginsManager
return contextMenu.LoadContextMenus(selectedResult);
}
- public List Query(Query query)
+ public async Task> QueryAsync(Query query, CancellationToken token)
{
var search = query.Search.ToLower();
- var pluginManager = new PluginsManager(Context, Settings);
+ if (string.IsNullOrWhiteSpace(search))
+ return pluginManager.GetDefaultHotKeys();
- if (!string.IsNullOrEmpty(search)
- && ($"{Settings.UninstallHotkey} ".StartsWith(search) || search.StartsWith($"{Settings.UninstallHotkey} ")))
- return pluginManager.RequestUninstall(search);
-
- return pluginManager.RequestInstallOrUpdate(search);
+ if ((DateTime.Now - lastUpdateTime).TotalHours > 12) // 12 hours
+ {
+ await pluginManager.UpdateManifest();
+ lastUpdateTime = DateTime.Now;
+ }
+
+ return search switch
+ {
+ var s when s.StartsWith(Settings.HotKeyInstall) => pluginManager.RequestInstallOrUpdate(s),
+ var s when s.StartsWith(Settings.HotkeyUninstall) => pluginManager.RequestUninstall(s),
+ var s when s.StartsWith(Settings.HotkeyUpdate) => pluginManager.RequestUpdate(s),
+ _ => pluginManager.GetDefaultHotKeys().Where(hotkey =>
+ {
+ hotkey.Score = StringMatcher.FuzzySearch(search, hotkey.Title).Score;
+ return hotkey.Score > 0;
+ }).ToList()
+ };
}
public void Save()
@@ -62,5 +86,11 @@ namespace Flow.Launcher.Plugin.PluginsManager
{
return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description");
}
+
+ public async Task ReloadDataAsync()
+ {
+ await pluginManager.UpdateManifest();
+ lastUpdateTime = DateTime.Now;
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs
index 290221710..145aadc98 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs
@@ -1,32 +1,24 @@
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Infrastructure.Logger;
-using Newtonsoft.Json;
using System;
using System.Collections.Generic;
+using System.Text.Json;
using System.Threading.Tasks;
namespace Flow.Launcher.Plugin.PluginsManager.Models
{
internal class PluginsManifest
{
- internal List UserPlugins { get; private set; }
- internal PluginsManifest()
- {
- DownloadManifest();
- }
+ internal List UserPlugins { get; private set; } = new List();
- private void DownloadManifest()
+ internal async Task DownloadManifest()
{
- var json = string.Empty;
try
{
- var t = Task.Run(
- async () =>
- json = await Http.Get("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"));
+ await using var jsonStream = await Http.GetStreamAsync("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json")
+ .ConfigureAwait(false);
- t.Wait();
-
- UserPlugins = JsonConvert.DeserializeObject>(json);
+ UserPlugins = await JsonSerializer.DeserializeAsync>(jsonStream).ConfigureAwait(false);
}
catch (Exception e)
{
@@ -34,7 +26,6 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models
UserPlugins = new List();
}
-
}
}
-}
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs
index 3bc44e0f6..c1af3014b 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
+
namespace Flow.Launcher.Plugin.PluginsManager.Models
{
public class UserPlugin
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
index c141916aa..68df5bc1f 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs
@@ -7,18 +7,35 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Threading.Tasks;
using System.Windows;
namespace Flow.Launcher.Plugin.PluginsManager
{
internal class PluginsManager
{
- private readonly PluginsManifest pluginsManifest;
+ private PluginsManifest pluginsManifest;
private PluginInitContext Context { get; set; }
private Settings Settings { get; set; }
+ private bool shouldHideWindow = true;
+
+ private bool ShouldHideWindow
+ {
+ set { shouldHideWindow = value; }
+ get
+ {
+ var setValue = shouldHideWindow;
+ // Default value for hide main window is true. Revert after get call.
+ // This ensures when set by another method to false, it is only used once.
+ shouldHideWindow = true;
+
+ return setValue;
+ }
+ }
+
private readonly string icoPath = "Images\\pluginsmanager.png";
internal PluginsManager(PluginInitContext context, Settings settings)
@@ -27,47 +44,202 @@ namespace Flow.Launcher.Plugin.PluginsManager
Context = context;
Settings = settings;
}
- internal void InstallOrUpdate(UserPlugin plugin)
+
+ internal async Task UpdateManifest()
+ {
+ await pluginsManifest.DownloadManifest();
+ }
+
+ internal List GetDefaultHotKeys()
+ {
+ return new List()
+ {
+ new Result()
+ {
+ Title = Settings.HotKeyInstall,
+ IcoPath = icoPath,
+ Action = _ =>
+ {
+ Context.API.ChangeQuery("pm install ");
+ return false;
+ }
+ },
+ new Result()
+ {
+ Title = Settings.HotkeyUninstall,
+ IcoPath = icoPath,
+ Action = _ =>
+ {
+ Context.API.ChangeQuery("pm uninstall ");
+ return false;
+ }
+ },
+ new Result()
+ {
+ Title = Settings.HotkeyUpdate,
+ IcoPath = icoPath,
+ Action = _ =>
+ {
+ Context.API.ChangeQuery("pm update ");
+ return false;
+ }
+ }
+ };
+ }
+
+ internal async Task InstallOrUpdate(UserPlugin plugin)
{
if (PluginExists(plugin.ID))
{
- Context.API.ShowMsg("Plugin already installed");
+ if (Context.API.GetAllPlugins()
+ .Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version.CompareTo(plugin.Version) < 0))
+ {
+ if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"),
+ Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ Context
+ .API
+ .ChangeQuery(
+ $"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.HotkeyUpdate} {plugin.Name}");
+
+ Application.Current.MainWindow.Show();
+ shouldHideWindow = false;
+
+ return;
+ }
+
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_alreadyexists"));
return;
}
var message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_prompt"),
- plugin.Name, plugin.Author,
- Environment.NewLine, Environment.NewLine);
+ plugin.Name, plugin.Author,
+ Environment.NewLine, Environment.NewLine);
- if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_install_title"), MessageBoxButton.YesNo) == MessageBoxResult.No)
+ if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_install_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.No)
return;
- var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip");
+ var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}.zip");
try
{
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
- Context.API.GetTranslation("plugin_pluginsmanager_please_wait"));
+ Context.API.GetTranslation("plugin_pluginsmanager_please_wait"));
- Http.Download(plugin.UrlDownload, filePath);
+ 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"));
+ Context.API.GetTranslation("plugin_pluginsmanager_download_success"));
+
+ Install(plugin, filePath);
}
catch (Exception e)
{
- Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"),
- Context.API.GetTranslation("plugin_pluginsmanager_download_success"));
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_install_error_title"),
+ string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"), plugin.Name));
- Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload");
+ Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "InstallOrUpdate");
+
+ return;
}
- Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath));
+ Context.API.RestartApp();
}
- internal void Update()
+ internal List RequestUpdate(string search)
{
- throw new NotImplementedException();
+ var autocompletedResults = AutoCompleteReturnAllResults(search,
+ Settings.HotkeyUpdate,
+ "Update",
+ "Select a plugin to update");
+
+ if (autocompletedResults.Any())
+ return autocompletedResults;
+
+ var uninstallSearch = search.Replace(Settings.HotkeyUpdate, string.Empty).TrimStart();
+
+
+ var resultsForUpdate =
+ from existingPlugin in Context.API.GetAllPlugins()
+ join pluginFromManifest in pluginsManifest.UserPlugins
+ on existingPlugin.Metadata.ID equals pluginFromManifest.ID
+ where existingPlugin.Metadata.Version.CompareTo(pluginFromManifest.Version) < 0 // if current version precedes manifest version
+ select
+ new
+ {
+ pluginFromManifest.Name,
+ pluginFromManifest.Author,
+ CurrentVersion = existingPlugin.Metadata.Version,
+ NewVersion = pluginFromManifest.Version,
+ existingPlugin.Metadata.IcoPath,
+ PluginExistingMetadata = existingPlugin.Metadata,
+ PluginNewUserPlugin = pluginFromManifest
+ };
+
+ if (!resultsForUpdate.Any())
+ return new List
+ {
+ new Result
+ {
+ Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"),
+ SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"),
+ IcoPath = icoPath
+ }
+ };
+
+
+ var results = resultsForUpdate
+ .Select(x =>
+ new Result
+ {
+ Title = $"{x.Name} by {x.Author}",
+ SubTitle = $"Update from version {x.CurrentVersion} to {x.NewVersion}",
+ IcoPath = x.IcoPath,
+ Action = e =>
+ {
+ string message = string.Format(
+ Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"),
+ x.Name, x.Author,
+ Environment.NewLine, Environment.NewLine);
+
+ if (MessageBox.Show(message,
+ Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ {
+ Uninstall(x.PluginExistingMetadata);
+
+ var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory,
+ $"{x.Name}-{x.NewVersion}.zip");
+
+ Task.Run(async delegate
+ {
+ 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;
+ }
+
+ return false;
+ }
+ });
+
+ return Search(results, uninstallSearch);
}
internal bool PluginExists(string id)
@@ -75,51 +247,46 @@ namespace Flow.Launcher.Plugin.PluginsManager
return Context.API.GetAllPlugins().Any(x => x.Metadata.ID == id);
}
- internal void PluginsManifestSiteOpen()
- {
- //Open from context menu https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest
- throw new NotImplementedException();
- }
-
- internal List Search(List results, string searchName)
+ internal List Search(IEnumerable results, string searchName)
{
if (string.IsNullOrEmpty(searchName))
- return results;
+ return results.ToList();
return results
- .Where(x =>
- {
- var matchResult = StringMatcher.FuzzySearch(searchName, x.Title);
- if (matchResult.IsSearchPrecisionScoreMet())
- x.Score = matchResult.Score;
+ .Where(x =>
+ {
+ var matchResult = StringMatcher.FuzzySearch(searchName, x.Title);
+ if (matchResult.IsSearchPrecisionScoreMet())
+ x.Score = matchResult.Score;
- return matchResult.IsSearchPrecisionScoreMet();
- })
- .ToList();
+ return matchResult.IsSearchPrecisionScoreMet();
+ })
+ .ToList();
}
internal List RequestInstallOrUpdate(string searchName)
{
+ var searchNameWithoutKeyword = searchName.Replace(Settings.HotKeyInstall, string.Empty).Trim();
+
var results =
pluginsManifest
- .UserPlugins
- .Select(x =>
- new Result
- {
- Title = $"{x.Name} by {x.Author}",
- SubTitle = x.Description,
- IcoPath = icoPath,
- Action = e =>
+ .UserPlugins
+ .Select(x =>
+ new Result
{
- Application.Current.MainWindow.Hide();
- InstallOrUpdate(x);
+ Title = $"{x.Name} by {x.Author}",
+ SubTitle = x.Description,
+ IcoPath = icoPath,
+ Action = e =>
+ {
+ Application.Current.MainWindow.Hide();
+ _ = InstallOrUpdate(x); // No need to wait
+ return ShouldHideWindow;
+ },
+ ContextData = x
+ });
- return true;
- }
- })
- .ToList();
-
- return Search(results, searchName);
+ return Search(results, searchNameWithoutKeyword);
}
private void Install(UserPlugin plugin, string downloadedFilePath)
@@ -153,32 +320,82 @@ namespace Flow.Launcher.Plugin.PluginsManager
return;
}
- string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}");
+ string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}");
Directory.Move(pluginFolderPath, newPluginPath);
-
- Context.API.RestartApp();
}
internal List RequestUninstall(string search)
+ {
+ var autocompletedResults = AutoCompleteReturnAllResults(search,
+ Settings.HotkeyUninstall,
+ "Uninstall",
+ "Select a plugin to uninstall");
+
+ if (autocompletedResults.Any())
+ return autocompletedResults;
+
+ var uninstallSearch = search.Replace(Settings.HotkeyUninstall, string.Empty).TrimStart();
+
+ var results = Context.API
+ .GetAllPlugins()
+ .Select(x =>
+ new Result
+ {
+ Title = $"{x.Metadata.Name} by {x.Metadata.Author}",
+ SubTitle = x.Metadata.Description,
+ IcoPath = x.Metadata.IcoPath,
+ Action = e =>
+ {
+ string message = string.Format(
+ Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
+ x.Metadata.Name, x.Metadata.Author,
+ Environment.NewLine, Environment.NewLine);
+
+ if (MessageBox.Show(message,
+ Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
+ MessageBoxButton.YesNo) == MessageBoxResult.Yes)
+ {
+ Application.Current.MainWindow.Hide();
+ Uninstall(x.Metadata);
+ Context.API.RestartApp();
+
+ return true;
+ }
+
+ return false;
+ }
+ });
+
+ return Search(results, uninstallSearch);
+ }
+
+ private void Uninstall(PluginMetadata plugin)
+ {
+ // Marked for deletion. Will be deleted on next start up
+ using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
+ }
+
+ private List AutoCompleteReturnAllResults(string search, string hotkey, string title, string subtitle)
{
if (!string.IsNullOrEmpty(search)
- && Settings.UninstallHotkey.StartsWith(search)
- && (Settings.UninstallHotkey != search || !search.StartsWith(Settings.UninstallHotkey)))
+ && hotkey.StartsWith(search)
+ && (hotkey != search || !search.StartsWith(hotkey)))
{
- return
+ return
new List
{
new Result
{
- Title = "Uninstall",
+ Title = title,
IcoPath = icoPath,
- SubTitle = "Select a plugin to uninstall",
+ SubTitle = subtitle,
Action = e =>
{
Context
- .API
- .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UninstallHotkey} ");
+ .API
+ .ChangeQuery(
+ $"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} ");
return false;
}
@@ -186,42 +403,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
};
}
- var uninstallSearch = search.Replace(Settings.UninstallHotkey, string.Empty).TrimStart();
-
- var results= Context.API
- .GetAllPlugins()
- .Select(x =>
- new Result
- {
- Title = $"{x.Metadata.Name} by {x.Metadata.Author}",
- SubTitle = x.Metadata.Description,
- IcoPath = x.Metadata.IcoPath,
- Action = e =>
- {
- Application.Current.MainWindow.Hide();
- Uninstall(x.Metadata);
-
- return true;
- }
- })
- .ToList();
-
- return Search(results, uninstallSearch);
- }
-
- private void Uninstall(PluginMetadata plugin)
- {
- string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
- plugin.Name, plugin.Author,
- Environment.NewLine, Environment.NewLine);
-
- if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
- MessageBoxButton.YesNo) == MessageBoxResult.Yes)
- {
- using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
-
- Context.API.RestartApp();
- }
+ return new List();
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs
index 0c647e6ae..9c5b0d29f 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs
@@ -6,6 +6,9 @@ namespace Flow.Launcher.Plugin.PluginsManager
{
internal class Settings
{
- internal string UninstallHotkey { get; set; } = "uninstall";
+ internal string HotKeyInstall { get; set; } = "install";
+ internal string HotkeyUninstall { get; set; } = "uninstall";
+
+ internal string HotkeyUpdate { get; set; } = "update";
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json
index 0353fffcc..60ab7ab18 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.1.0",
+ "Version": "1.5.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
index cf9c96294..a643ebf86 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
@@ -36,14 +36,14 @@
-
- PreserveNewest
-
-
+
Designer
MSBuild:Compile
PreserveNewest
+
+ PreserveNewest
+
Always
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json
index d769397a8..2bb40c644 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json
@@ -4,7 +4,7 @@
"Name":"Process Killer",
"Description":"kill running processes from Flow",
"Author":"Flow-Launcher",
- "Version":"1.2.1",
+ "Version":"1.2.2",
"Language":"csharp",
"Website":"https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller",
"IcoPath":"Images\\app.png",
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj
index d2e56931b..5de32e832 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj
@@ -49,52 +49,12 @@
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- Always
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs
index 8f124f3a4..d7413874b 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using Flow.Launcher.Infrastructure.Logger;
@@ -12,9 +13,8 @@ using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
namespace Flow.Launcher.Plugin.Program
{
- public class Main : ISettingProvider, IPlugin, IPluginI18n, IContextMenu, ISavable, IReloadable
+ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISavable, IAsyncReloadable
{
- private static readonly object IndexLock = new object();
internal static Win32[] _win32s { get; set; }
internal static UWP.Application[] _uwps { get; set; }
internal static Settings _settings { get; set; }
@@ -30,33 +30,6 @@ namespace Flow.Launcher.Plugin.Program
public Main()
{
_settingsStorage = new PluginJsonStorage();
- _settings = _settingsStorage.Load();
-
- Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
- {
- _win32Storage = new BinaryStorage("Win32");
- _win32s = _win32Storage.TryLoad(new Win32[] { });
- _uwpStorage = new BinaryStorage("UWP");
- _uwps = _uwpStorage.TryLoad(new UWP.Application[] { });
- });
- Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
- Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
-
- var a = Task.Run(() =>
- {
- if (IsStartupIndexProgramsRequired || !_win32s.Any())
- Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32Programs);
- });
-
- var b = Task.Run(() =>
- {
- if (IsStartupIndexProgramsRequired || !_uwps.Any())
- Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUWPPrograms);
- });
-
- Task.WaitAll(a, b);
-
- _settings.LastIndexTime = DateTime.Today;
}
public void Save()
@@ -66,7 +39,7 @@ namespace Flow.Launcher.Plugin.Program
_uwpStorage.Save(_uwps);
}
- public List Query(Query query)
+ public async Task> QueryAsync(Query query, CancellationToken token)
{
Win32[] win32;
UWP.Application[] uwps;
@@ -74,20 +47,81 @@ namespace Flow.Launcher.Plugin.Program
win32 = _win32s;
uwps = _uwps;
- var result = win32.Cast()
- .Concat(uwps)
- .AsParallel()
- .Where(p => p.Enabled)
- .Select(p => p.Result(query.Search, _context.API))
- .Where(r => r?.Score > 0)
- .ToList();
+ try
+ {
+ var result = await Task.Run(delegate
+ {
+ try
+ {
+ return win32.Cast()
+ .Concat(uwps)
+ .AsParallel()
+ .WithCancellation(token)
+ .Where(p => p.Enabled)
+ .Select(p => p.Result(query.Search, _context.API))
+ .Where(r => r?.Score > 0)
+ .ToList();
+ }
+ catch (OperationCanceledException)
+ {
+ return null;
+ }
+ }, token).ConfigureAwait(false);
- return result;
+ token.ThrowIfCancellationRequested();
+
+ return result;
+ }
+ catch (OperationCanceledException)
+ {
+ return null;
+ }
}
- public void Init(PluginInitContext context)
+ public async Task InitAsync(PluginInitContext context)
{
_context = context;
+
+ await Task.Run(() =>
+ {
+ _settings = _settingsStorage.Load();
+
+ Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
+ {
+ _win32Storage = new BinaryStorage("Win32");
+ _win32s = _win32Storage.TryLoad(new Win32[] { });
+ _uwpStorage = new BinaryStorage("UWP");
+ _uwps = _uwpStorage.TryLoad(new UWP.Application[] { });
+ });
+ Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
+ Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
+ });
+
+ bool indexedWinApps = false;
+ bool indexedUWPApps = false;
+
+ var a = Task.Run(() =>
+ {
+ if (IsStartupIndexProgramsRequired || !_win32s.Any())
+ {
+ Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32Programs);
+ indexedWinApps = true;
+ }
+ });
+
+ var b = Task.Run(() =>
+ {
+ if (IsStartupIndexProgramsRequired || !_uwps.Any())
+ {
+ Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
+ indexedUWPApps = true;
+ }
+ });
+
+ await Task.WhenAll(a, b);
+
+ if (indexedWinApps && indexedUWPApps)
+ _settings.LastIndexTime = DateTime.Today;
}
public static void IndexWin32Programs()
@@ -95,10 +129,9 @@ namespace Flow.Launcher.Plugin.Program
var win32S = Win32.All(_settings);
_win32s = win32S;
-
}
- public static void IndexUWPPrograms()
+ public static void IndexUwpPrograms()
{
var windows10 = new Version(10, 0);
var support = Environment.OSVersion.Version.Major >= windows10.Major;
@@ -106,16 +139,15 @@ namespace Flow.Launcher.Plugin.Program
var applications = support ? UWP.All() : new UWP.Application[] { };
_uwps = applications;
-
}
- public static void IndexPrograms()
+ public static async Task IndexPrograms()
{
- var t1 = Task.Run(() => IndexWin32Programs());
+ var t1 = Task.Run(IndexWin32Programs);
- var t2 = Task.Run(() => IndexUWPPrograms());
+ var t2 = Task.Run(IndexUwpPrograms);
- Task.WaitAll(t1, t2);
+ await Task.WhenAll(t1, t2);
_settings.LastIndexTime = DateTime.Today;
}
@@ -145,19 +177,21 @@ namespace Flow.Launcher.Plugin.Program
}
menuOptions.Add(
- new Result
- {
- Title = _context.API.GetTranslation("flowlauncher_plugin_program_disable_program"),
- Action = c =>
- {
- DisableProgram(program);
- _context.API.ShowMsg(_context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
- _context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success_message"));
- return false;
- },
- IcoPath = "Images/disable.png"
- }
- );
+ new Result
+ {
+ Title = _context.API.GetTranslation("flowlauncher_plugin_program_disable_program"),
+ Action = c =>
+ {
+ DisableProgram(program);
+ _context.API.ShowMsg(
+ _context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
+ _context.API.GetTranslation(
+ "flowlauncher_plugin_program_disable_dlgtitle_success_message"));
+ return false;
+ },
+ IcoPath = "Images/disable.png"
+ }
+ );
return menuOptions;
}
@@ -168,21 +202,25 @@ namespace Flow.Launcher.Plugin.Program
return;
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
- _uwps.Where(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier).FirstOrDefault().Enabled = false;
+ _uwps.Where(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
+ .FirstOrDefault()
+ .Enabled = false;
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
- _win32s.Where(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier).FirstOrDefault().Enabled = false;
+ _win32s.Where(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
+ .FirstOrDefault()
+ .Enabled = false;
_settings.DisabledProgramSources
- .Add(
- new Settings.DisabledProgramSource
- {
- Name = programToDelete.Name,
- Location = programToDelete.Location,
- UniqueIdentifier = programToDelete.UniqueIdentifier,
- Enabled = false
- }
- );
+ .Add(
+ new Settings.DisabledProgramSource
+ {
+ Name = programToDelete.Name,
+ Location = programToDelete.Location,
+ UniqueIdentifier = programToDelete.UniqueIdentifier,
+ Enabled = false
+ }
+ );
}
public static void StartProcess(Func runProcess, ProcessStartInfo info)
@@ -200,9 +238,9 @@ namespace Flow.Launcher.Plugin.Program
}
}
- public void ReloadData()
+ public async Task ReloadDataAsync()
{
- IndexPrograms();
+ await IndexPrograms();
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json
index 7d7a42e03..6c2c18e47 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Program/plugin.json
@@ -4,7 +4,7 @@
"Name": "Program",
"Description": "Search programs in Flow.Launcher",
"Author": "qianlifeng",
- "Version": "1.2.2",
+ "Version": "1.2.3",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj
index 178d95010..c542dc89b 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj
@@ -33,32 +33,6 @@
4
false
-
-
-
- Always
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
@@ -72,20 +46,12 @@
-
- PreserveNewest
-
-
-
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
- MSBuild:Compile
- Designer
+
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
index 63e74d678..4ad572cf6 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
@@ -4,7 +4,7 @@
"Name": "Shell",
"Description": "Provide executing commands from Flow Launcher. Commands should start with >",
"Author": "qianlifeng",
- "Version": "1.1.1",
+ "Version": "1.1.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Shell.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
index bdab40457..8ef4dc0fb 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
@@ -40,46 +40,12 @@
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
@@ -93,39 +59,4 @@
PreserveNewest
-
-
-
- PreserveNewest
-
-
-
-
-
- PreserveNewest
-
-
-
-
-
- PreserveNewest
-
-
-
-
-
- PreserveNewest
-
-
-
-
-
- PreserveNewest
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index 5642b62ed..624fe05bc 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
@@ -67,13 +68,15 @@ namespace Flow.Launcher.Plugin.Sys
{
c.TitleHighlightData = titleMatch.MatchData;
}
- else
+ else
{
c.SubTitleHighlightData = subTitleMatch.MatchData;
}
+
results.Add(c);
}
}
+
return results;
}
@@ -94,13 +97,15 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\shutdown.png",
Action = c =>
{
- var reuslt = MessageBox.Show(context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_shutdown_computer"),
- context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
+ var reuslt = MessageBox.Show(
+ context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_shutdown_computer"),
+ context.API.GetTranslation("flowlauncher_plugin_sys_shutdown_computer"),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (reuslt == MessageBoxResult.Yes)
{
Process.Start("shutdown", "/s /t 0");
}
+
return true;
}
},
@@ -111,13 +116,15 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\restart.png",
Action = c =>
{
- var result = MessageBox.Show(context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_restart_computer"),
- context.API.GetTranslation("flowlauncher_plugin_sys_restart_computer"),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
+ var result = MessageBox.Show(
+ context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_restart_computer"),
+ context.API.GetTranslation("flowlauncher_plugin_sys_restart_computer"),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
Process.Start("shutdown", "/r /t 0");
}
+
return true;
}
},
@@ -164,13 +171,14 @@ namespace Flow.Launcher.Plugin.Sys
// FYI, couldn't find documentation for this but if the recycle bin is already empty, it will return -2147418113 (0x8000FFFF (E_UNEXPECTED))
// 0 for nothing
var result = SHEmptyRecycleBin(new WindowInteropHelper(Application.Current.MainWindow).Handle, 0);
- if (result != (uint) HRESULT.S_OK && result != (uint)0x8000FFFF)
+ if (result != (uint) HRESULT.S_OK && result != (uint) 0x8000FFFF)
{
MessageBox.Show($"Error emptying recycle bin, error code: {result}\n" +
"please refer to https://msdn.microsoft.com/en-us/library/windows/desktop/aa378137",
- "Error",
- MessageBoxButton.OK, MessageBoxImage.Error);
+ "Error",
+ MessageBoxButton.OK, MessageBoxImage.Error);
}
+
return true;
}
},
@@ -229,9 +237,13 @@ namespace Flow.Launcher.Plugin.Sys
{
// Hide the window first then show msg after done because sometimes the reload could take a while, so not to make user think it's frozen.
Application.Current.MainWindow.Hide();
- context.API.ReloadAllPluginData();
- context.API.ShowMsg(context.API.GetTranslation("flowlauncher_plugin_sys_dlgtitle_success"),
- context.API.GetTranslation("flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded"));
+
+ context.API.ReloadAllPluginData().ContinueWith(_ =>
+ context.API.ShowMsg(
+ context.API.GetTranslation("flowlauncher_plugin_sys_dlgtitle_success"),
+ context.API.GetTranslation(
+ "flowlauncher_plugin_sys_dlgtext_all_applicableplugins_reloaded")));
+
return true;
}
},
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json
index 8d4b9a238..cf8ed6041 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json
@@ -4,7 +4,7 @@
"Name": "System Commands",
"Description": "Provide System related commands. e.g. shutdown,lock,setting etc.",
"Author": "qianlifeng",
- "Version": "1.1.1",
+ "Version": "1.1.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Sys.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj
index 7d802d815..671a8b1c2 100644
--- a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj
@@ -44,49 +44,14 @@
-
+
-
- PreserveNewest
-
-
-
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
-
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
diff --git a/Plugins/Flow.Launcher.Plugin.Url/plugin.json b/Plugins/Flow.Launcher.Plugin.Url/plugin.json
index be64f6708..89dc20a33 100644
--- a/Plugins/Flow.Launcher.Plugin.Url/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Url/plugin.json
@@ -4,7 +4,7 @@
"Name": "URL",
"Description": "Open the typed URL from Flow Launcher",
"Author": "qianlifeng",
- "Version": "1.1.1",
+ "Version": "1.1.2",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Url.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
index 431ca9ce8..af86af842 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
@@ -35,88 +35,12 @@
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
-
+
MSBuild:Compile
Designer
PreserveNewest
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
- PreserveNewest
-
-
- MSBuild:Compile
- Designer
+
PreserveNewest
@@ -134,12 +58,6 @@
PreserveNewest
-
-
-
- PreserveNewest
-
-
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
index 3c4d4c67d..f76e28112 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
@@ -13,14 +14,12 @@ using Flow.Launcher.Plugin.SharedCommands;
namespace Flow.Launcher.Plugin.WebSearch
{
- public class Main : IPlugin, ISettingProvider, IPluginI18n, ISavable, IResultUpdated
+ public class Main : IAsyncPlugin, ISettingProvider, IPluginI18n, ISavable, IResultUpdated
{
private PluginInitContext _context;
private readonly Settings _settings;
private readonly SettingsViewModel _viewModel;
- private CancellationTokenSource _updateSource;
- private CancellationToken _updateToken;
internal const string Images = "Images";
internal static string DefaultImagesDirectory;
@@ -33,7 +32,7 @@ namespace Flow.Launcher.Plugin.WebSearch
_viewModel.Save();
}
- public List Query(Query query)
+ public async Task> QueryAsync(Query query, CancellationToken token)
{
if (FilesFolders.IsLocationPathString(query.Search))
return new List();
@@ -41,102 +40,94 @@ namespace Flow.Launcher.Plugin.WebSearch
var searchSourceList = new List();
var results = new List();
- _updateSource?.Cancel();
- _updateSource = new CancellationTokenSource();
- _updateToken = _updateSource.Token;
-
- _settings.SearchSources.Where(o => (o.ActionKeyword == query.ActionKeyword || o.ActionKeyword == SearchSourceGlobalPluginWildCardSign)
- && o.Enabled)
- .ToList()
- .ForEach(x => searchSourceList.Add(x));
-
- if (searchSourceList.Any())
+ foreach (SearchSource searchSource in _settings.SearchSources.Where(o => (o.ActionKeyword == query.ActionKeyword ||
+ o.ActionKeyword == SearchSourceGlobalPluginWildCardSign)
+ && o.Enabled))
{
- foreach (SearchSource searchSource in searchSourceList)
+ string keyword = string.Empty;
+ keyword = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? query.ToString() : query.Search;
+ var title = keyword;
+ string subtitle = _context.API.GetTranslation("flowlauncher_plugin_websearch_search") + " " + searchSource.Title;
+
+ if (string.IsNullOrEmpty(keyword))
{
- string keyword = string.Empty;
- keyword = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? query.ToString() : query.Search;
- var title = keyword;
- string subtitle = _context.API.GetTranslation("flowlauncher_plugin_websearch_search") + " " + searchSource.Title;
-
- if (string.IsNullOrEmpty(keyword))
+ var result = new Result
{
- var result = new Result
- {
- Title = subtitle,
- SubTitle = string.Empty,
- IcoPath = searchSource.IconPath
- };
- results.Add(result);
- }
- else
- {
- var result = new Result
- {
- Title = title,
- SubTitle = subtitle,
- Score = 6,
- IcoPath = searchSource.IconPath,
- ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword,
- Action = c =>
- {
- if (_settings.OpenInNewBrowser)
- {
- searchSource.Url.Replace("{q}", Uri.EscapeDataString(keyword)).NewBrowserWindow(_settings.BrowserPath);
- }
- else
- {
- searchSource.Url.Replace("{q}", Uri.EscapeDataString(keyword)).NewTabInBrowser(_settings.BrowserPath);
- }
-
- return true;
- }
- };
-
- results.Add(result);
- ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs
- {
- Results = results,
- Query = query
- });
-
- UpdateResultsFromSuggestion(results, keyword, subtitle, searchSource, query);
- }
+ Title = subtitle,
+ SubTitle = string.Empty,
+ IcoPath = searchSource.IconPath
+ };
+ results.Add(result);
}
+ else
+ {
+ var result = new Result
+ {
+ Title = title,
+ SubTitle = subtitle,
+ Score = 6,
+ IcoPath = searchSource.IconPath,
+ ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword,
+ Action = c =>
+ {
+ if (_settings.OpenInNewBrowser)
+ {
+ searchSource.Url.Replace("{q}", Uri.EscapeDataString(keyword)).NewBrowserWindow(_settings.BrowserPath);
+ }
+ else
+ {
+ searchSource.Url.Replace("{q}", Uri.EscapeDataString(keyword)).NewTabInBrowser(_settings.BrowserPath);
+ }
+
+ return true;
+ }
+ };
+
+ results.Add(result);
+ }
+
+ ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs
+ {
+ Results = results,
+ Query = query
+ });
+
+ await UpdateResultsFromSuggestionAsync(results, keyword, subtitle, searchSource, query, token).ConfigureAwait(false);
+
+ if (token.IsCancellationRequested)
+ return null;
+
}
return results;
}
- private void UpdateResultsFromSuggestion(List results, string keyword, string subtitle,
- SearchSource searchSource, Query query)
+ private async Task UpdateResultsFromSuggestionAsync(List results, string keyword, string subtitle,
+ SearchSource searchSource, Query query, CancellationToken token)
{
if (_settings.EnableSuggestion)
{
- const int waittime = 300;
- var task = Task.Run(async () =>
- {
- var suggestions = await Suggestions(keyword, subtitle, searchSource);
- results.AddRange(suggestions);
- }, _updateToken);
+ var suggestions = await SuggestionsAsync(keyword, subtitle, searchSource, token).ConfigureAwait(false);
+ if (token.IsCancellationRequested || !suggestions.Any())
+ return;
- if (!task.Wait(waittime))
- {
- task.ContinueWith(_ => ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs
- {
- Results = results,
- Query = query
- }), _updateToken);
- }
+
+ results.AddRange(suggestions);
+
+ token.ThrowIfCancellationRequested();
}
}
- private async Task> Suggestions(string keyword, string subtitle, SearchSource searchSource)
+ private async Task> SuggestionsAsync(string keyword, string subtitle, SearchSource searchSource, CancellationToken token)
{
var source = _settings.SelectedSuggestion;
if (source != null)
{
- var suggestions = await source.Suggestions(keyword);
+ var suggestions = await source.Suggestions(keyword, token);
+
+ if (token.IsCancellationRequested)
+ return null;
+
var resultsFromSuggestion = suggestions.Select(o => new Result
{
Title = o,
@@ -169,19 +160,24 @@ namespace Flow.Launcher.Plugin.WebSearch
_settings = _viewModel.Settings;
}
- public void Init(PluginInitContext context)
+ public Task InitAsync(PluginInitContext context)
{
- _context = context;
- var pluginDirectory = _context.CurrentPluginMetadata.PluginDirectory;
- var bundledImagesDirectory = Path.Combine(pluginDirectory, Images);
-
- // Default images directory is in the WebSearch's application folder
- DefaultImagesDirectory = Path.Combine(pluginDirectory, Images);
- Helper.ValidateDataDirectory(bundledImagesDirectory, DefaultImagesDirectory);
+ return Task.Run(Init);
- // Custom images directory is in the WebSearch's data location folder
- var name = Path.GetFileNameWithoutExtension(_context.CurrentPluginMetadata.ExecuteFileName);
- CustomImagesDirectory = Path.Combine(DataLocation.PluginSettingsDirectory, name, "CustomIcons");
+ void Init()
+ {
+ _context = context;
+ var pluginDirectory = _context.CurrentPluginMetadata.PluginDirectory;
+ var bundledImagesDirectory = Path.Combine(pluginDirectory, Images);
+
+ // Default images directory is in the WebSearch's application folder
+ DefaultImagesDirectory = Path.Combine(pluginDirectory, Images);
+ Helper.ValidateDataDirectory(bundledImagesDirectory, DefaultImagesDirectory);
+
+ // Custom images directory is in the WebSearch's data location folder
+ var name = Path.GetFileNameWithoutExtension(_context.CurrentPluginMetadata.ExecuteFileName);
+ CustomImagesDirectory = Path.Combine(DataLocation.PluginSettingsDirectory, name, "CustomIcons");
+ };
}
#region ISettingProvider Members
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs
index c7ccb4d51..98e9376fb 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs
@@ -1,10 +1,10 @@
using System.IO;
using System.Windows.Media;
using JetBrains.Annotations;
-using Newtonsoft.Json;
using Flow.Launcher.Infrastructure.Image;
using Flow.Launcher.Infrastructure;
using System.Reflection;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin.WebSearch
{
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs
index 555ee4647..8a1700415 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs
@@ -1,6 +1,6 @@
using System;
using System.Collections.ObjectModel;
-using Newtonsoft.Json;
+using System.Text.Json.Serialization;
using Flow.Launcher.Plugin.WebSearch.SuggestionSources;
namespace Flow.Launcher.Plugin.WebSearch
@@ -196,7 +196,8 @@ namespace Flow.Launcher.Plugin.WebSearch
[JsonIgnore]
public SuggestionSource[] Suggestions { get; set; } = {
new Google(),
- new Baidu()
+ new Baidu(),
+ new Bing()
};
[JsonIgnore]
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs
index 57db223bc..b7e2017f9 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs
@@ -2,12 +2,13 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
+using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Infrastructure.Logger;
+using System.Net.Http;
+using System.Threading;
namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
{
@@ -15,16 +16,20 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
{
private readonly Regex _reg = new Regex("window.baidu.sug\\((.*)\\)");
- public override async Task> Suggestions(string query)
+ public override async Task> Suggestions(string query, CancellationToken token)
{
string result;
try
{
const string api = "http://suggestion.baidu.com/su?json=1&wd=";
- result = await Http.Get(api + Uri.EscapeUriString(query), "GB2312");
+ result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false);
}
- catch (WebException e)
+ catch (TaskCanceledException)
+ {
+ return null;
+ }
+ catch (HttpRequestException e)
{
Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e);
return new List();
@@ -34,25 +39,20 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
Match match = _reg.Match(result);
if (match.Success)
{
- JContainer json;
+ JsonDocument json;
try
{
- json = JsonConvert.DeserializeObject(match.Groups[1].Value) as JContainer;
+ json = JsonDocument.Parse(match.Groups[1].Value);
}
- catch (JsonSerializationException e)
+ catch(JsonException e)
{
Log.Exception("|Baidu.Suggestions|can't parse suggestions", e);
return new List();
}
- if (json != null)
- {
- var results = json["s"] as JArray;
- if (results != null)
- {
- return results.OfType().Select(o => o.Value).OfType().ToList();
- }
- }
+ var results = json?.RootElement.GetProperty("s");
+
+ return results?.EnumerateArray().Select(o => o.GetString()).ToList() ?? new List();
}
return new List();
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs
new file mode 100644
index 000000000..ffde2fda2
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs
@@ -0,0 +1,66 @@
+using Flow.Launcher.Infrastructure.Http;
+using Flow.Launcher.Infrastructure.Logger;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Http;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Text.Json;
+using System.Linq;
+using System.Threading;
+
+namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
+{
+ class Bing : SuggestionSource
+ {
+ public override async Task> Suggestions(string query, CancellationToken token)
+ {
+ JsonElement json;
+
+ try
+ {
+ const string api = "https://api.bing.com/qsonhs.aspx?q=";
+
+ using var resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false);
+
+ if (resultStream.Length == 0)
+ return new List(); // this handles the cancellation
+
+ json = (await JsonDocument.ParseAsync(resultStream, cancellationToken: token)).RootElement.GetProperty("AS");
+
+ }
+ catch (TaskCanceledException)
+ {
+ return null;
+ }
+ catch (HttpRequestException e)
+ {
+ Log.Exception("|Bing.Suggestions|Can't get suggestion from Bing", e);
+ return new List();
+ }
+ catch (JsonException e)
+ {
+ Log.Exception("|Bing.Suggestions|can't parse suggestions", e);
+ return new List();
+ }
+
+ if (json.GetProperty("FullResults").GetInt32() == 0)
+ return new List();
+
+ return json.GetProperty("Results")
+ .EnumerateArray()
+ .SelectMany(r => r.GetProperty("Suggests")
+ .EnumerateArray()
+ .Select(s => s.GetProperty("Txt").GetString()))
+ .ToList();
+
+ }
+
+ public override string ToString()
+ {
+ return "Bing";
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs
index 81878bd8b..c33ebd7e1 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs
@@ -3,49 +3,52 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Infrastructure.Logger;
+using System.Net.Http;
+using System.Threading;
+using System.Text.Json;
+using System.IO;
namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
{
public class Google : SuggestionSource
{
- public override async Task> Suggestions(string query)
+ public override async Task> Suggestions(string query, CancellationToken token)
{
- string result;
+ JsonDocument json;
+
try
{
const string api = "https://www.google.com/complete/search?output=chrome&q=";
- result = await Http.Get(api + Uri.EscapeUriString(query));
+
+ using var resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false);
+
+ if (resultStream.Length == 0)
+ return new List();
+
+ json = await JsonDocument.ParseAsync(resultStream);
+
}
- catch (WebException e)
+ catch (TaskCanceledException)
+ {
+ return null;
+ }
+ catch (HttpRequestException e)
{
Log.Exception("|Google.Suggestions|Can't get suggestion from google", e);
return new List();
- ;
}
- if (string.IsNullOrEmpty(result)) return new List();
- JContainer json;
- try
- {
- json = JsonConvert.DeserializeObject(result) as JContainer;
- }
- catch (JsonSerializationException e)
+ catch (JsonException e)
{
Log.Exception("|Google.Suggestions|can't parse suggestions", e);
return new List();
}
- if (json != null)
- {
- var results = json[1] as JContainer;
- if (results != null)
- {
- return results.OfType().Select(o => o.Value).OfType().ToList();
- }
- }
- return new List();
+
+ var results = json?.RootElement.EnumerateArray().ElementAt(1);
+
+ return results?.EnumerateArray().Select(o => o.GetString()).ToList() ?? new List();
+
}
public override string ToString()
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs
index d6d89415f..c58e61141 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs
@@ -1,10 +1,11 @@
using System.Collections.Generic;
+using System.Threading;
using System.Threading.Tasks;
namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources
{
public abstract class SuggestionSource
{
- public abstract Task> Suggestions(string query);
+ public abstract Task> Suggestions(string query, CancellationToken token);
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
index 329f1c41d..c036fbf8b 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
@@ -25,7 +25,7 @@
"Name": "Web Searches",
"Description": "Provide the web search ability",
"Author": "qianlifeng",
- "Version": "1.1.2",
+ "Version": "1.2.1",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll",
diff --git a/README.md b/README.md
index f0c08d8a0..ac8611298 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
-
+
[](https://ci.appveyor.com/project/JohnTheGr8/flow-launcher/branch/dev)
[](https://github.com/Flow-Launcher/Flow.Launcher/releases)
[](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest)
@@ -26,6 +26,8 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be
- Support of wide range of plugins.
- Fully portable.
+[
**SOFTPEDIA EDITOR'S PICK**](https://www.softpedia.com/get/System/Launchers-Shutdown-Tools/Flow-Launcher.shtml)
+
## Running Flow Launcher
| [Windows 7 and up](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) |
@@ -45,7 +47,7 @@ Windows may complain about security due to code not being signed, this will be c
- Open flow's search window: Alt+Space is the default hotkey.
- Open context menu: Ctrl+O/Shift+Enter.
- Cancel/Return to previous screen: Esc.
-- Install/Uninstall plugins: in the search window, type `wpm install/uninstall` + the plugin name.
+- Install/Uninstall/Update plugins: in the search window, type `pm install`/`pm uninstall`/`pm update` + the plugin name.
- Saved user settings are located:
- If using roaming: `%APPDATA%\FlowLauncher`
- If using portable, by default: `%localappdata%\FlowLauncher\app-\UserData`
diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1
index 18ce33c4f..b08fac8f6 100644
--- a/Scripts/post_build.ps1
+++ b/Scripts/post_build.ps1
@@ -1,13 +1,13 @@
param(
[string]$config = "Release",
- [string]$solution,
- [string]$targetpath
+ [string]$solution = (Join-Path $PSScriptRoot ".." -Resolve)
)
Write-Host "Config: $config"
function Build-Version {
if ([string]::IsNullOrEmpty($env:flowVersion)) {
- $v = (Get-Command ${TargetPath}).FileVersionInfo.FileVersion
+ $targetPath = Join-Path $solution "Output/Release/Flow.Launcher.dll" -Resolve
+ $v = (Get-Command ${targetPath}).FileVersionInfo.FileVersion
} else {
$v = $env:flowVersion
}
@@ -31,22 +31,18 @@ function Build-Path {
return $p
}
-function Copy-Resources ($path, $config) {
- $project = "$path\Flow.Launcher"
- $output = "$path\Output"
- $target = "$output\$config"
- Copy-Item -Recurse -Force $project\Images\* $target\Images\
- Copy-Item -Recurse -Force $path\JsonRPC $target\JsonRPC
+function Copy-Resources ($path) {
# making version static as multiple versions can exist in the nuget folder and in the case a breaking change is introduced.
- Copy-Item -Force $env:USERPROFILE\.nuget\packages\squirrel.windows\1.5.2\tools\Squirrel.exe $output\Update.exe
+ Copy-Item -Force $env:USERPROFILE\.nuget\packages\squirrel.windows\1.5.2\tools\Squirrel.exe $path\Output\Update.exe
}
function Delete-Unused ($path, $config) {
$target = "$path\Output\$config"
$included = Get-ChildItem $target -Filter "*.dll"
foreach ($i in $included){
- Remove-Item -Path $target\Plugins -Include $i -Recurse
- Write-Host "Deleting duplicated $i"
+ $deleteList = Get-ChildItem $target\Plugins -Include $i -Recurse | Where { $_.VersionInfo.FileVersion -eq $i.VersionInfo.FileVersion -And $_.Name -eq "$i" }
+ $deleteList | ForEach-Object{ Write-Host Deleting duplicated $_.Name with version $_.VersionInfo.FileVersion at location $_.Directory.FullName }
+ $deleteList | Remove-Item
}
Remove-Item -Path $target -Include "*.xml" -Recurse
}
@@ -55,17 +51,6 @@ function Validate-Directory ($output) {
New-Item $output -ItemType Directory -Force
}
-function Zip-Release ($path, $version, $output) {
- Write-Host "Begin zip release"
-
- $content = "$path\Output\Release\*"
- $zipFile = "$output\Flow-Launcher-v$version.zip"
-
- Compress-Archive -Force -Path $content -DestinationPath $zipFile
-
- Write-Host "End zip release"
-}
-
function Pack-Squirrel-Installer ($path, $version, $output) {
# msbuild based installer generation is not working in appveyor, not sure why
Write-Host "Begin pack squirrel installer"
@@ -75,6 +60,8 @@ function Pack-Squirrel-Installer ($path, $version, $output) {
Write-Host "Packing: $spec"
Write-Host "Input path: $input"
+ # making version static as multiple versions can exist in the nuget folder and in the case a breaking change is introduced.
+ New-Alias Nuget $env:USERPROFILE\.nuget\packages\NuGet.CommandLine\5.4.0\tools\NuGet.exe -Force
# TODO: can we use dotnet pack here?
nuget pack $spec -Version $version -BasePath $input -OutputDirectory $output -Properties Configuration=Release
@@ -100,40 +87,30 @@ function Pack-Squirrel-Installer ($path, $version, $output) {
Write-Host "End pack squirrel installer"
}
-function IsDotNetCoreAppSelfContainedPublishEvent{
- return Test-Path $solution\Output\Release\coreclr.dll
-}
+function Publish-Self-Contained ($p) {
-function FixPublishLastWriteDateTimeError ($solutionPath) {
- #Fix error from publishing self contained app, when nuget tries to pack core dll references throws the error 'The DateTimeOffset specified cannot be converted into a Zip file timestamp'
- gci -path "$solutionPath\Output\Release" -rec -file *.dll | Where-Object {$_.LastWriteTime -lt (Get-Date).AddYears(-20)} | % { try { $_.LastWriteTime = '01/01/2000 00:00:00' } catch {} }
+ $csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve
+ $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml" -Resolve
+
+ # we call dotnet publish on the main project.
+ # The other projects should have been built in Release at this point.
+ dotnet publish -c Release $csproj /p:PublishProfile=$profile
}
function Main {
$p = Build-Path
$v = Build-Version
- Copy-Resources $p $config
+ Copy-Resources $p
if ($config -eq "Release"){
- if(IsDotNetCoreAppSelfContainedPublishEvent) {
- FixPublishLastWriteDateTimeError $p
- }
-
Delete-Unused $p $config
+
+ Publish-Self-Contained $p
+
$o = "$p\Output\Packages"
Validate-Directory $o
- # making version static as multiple versions can exist in the nuget folder and in the case a breaking change is introduced.
- New-Alias Nuget $env:USERPROFILE\.nuget\packages\NuGet.CommandLine\5.4.0\tools\NuGet.exe -Force
Pack-Squirrel-Installer $p $v $o
-
- $isInCI = $env:APPVEYOR
- if ($isInCI) {
- Zip-Release $p $v $o
- }
-
- Write-Host "List output directory"
- Get-ChildItem $o
}
}
diff --git a/SolutionAssemblyInfo.cs b/SolutionAssemblyInfo.cs
index 018084a66..afd76b5d7 100644
--- a/SolutionAssemblyInfo.cs
+++ b/SolutionAssemblyInfo.cs
@@ -16,6 +16,6 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
-[assembly: AssemblyVersion("1.5.0")]
-[assembly: AssemblyFileVersion("1.5.0")]
-[assembly: AssemblyInformationalVersion("1.5.0")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.7.0")]
+[assembly: AssemblyFileVersion("1.7.0")]
+[assembly: AssemblyInformationalVersion("1.7.0")]
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index f5841da3e..2c2f43b66 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: '1.5.0.{build}'
+version: '1.7.0.{build}'
init:
- ps: |
@@ -26,17 +26,42 @@ before_build:
build:
project: Flow.Launcher.sln
verbosity: minimal
+after_build:
+ - ps: .\Scripts\post_build.ps1
artifacts:
-- path: 'Output\Packages\Flow-Launcher-*.zip'
- name: Zip
- path: 'Output\Release\Flow.Launcher.Plugin.*.nupkg'
name: Plugin nupkg
+- path: 'Output\Packages\Flow-Launcher-*.exe'
+ name: Squirrel Installer
+- path: 'Output\Packages\FlowLauncher-*-full.nupkg'
+ name: Squirrel nupkg
+- path: 'Output\Packages\RELEASES'
+ name: Squirrel RELEASES
deploy:
- provider: NuGet
- artifact: /.*\.nupkg/
- api_key:
- secure: n80IeWR3pN81p0w4uXq4mO0TdTXoJSHHFL+yTB9YBJ0Wni2DjZGYwOFdaWzW4hRi
- on:
- branch: master
\ No newline at end of file
+ - provider: NuGet
+ artifact: Plugin nupkg
+ api_key:
+ secure: n80IeWR3pN81p0w4uXq4mO0TdTXoJSHHFL+yTB9YBJ0Wni2DjZGYwOFdaWzW4hRi
+ on:
+ branch: master
+
+ - provider: GitHub
+ release: v$(flowVersion)
+ auth_token:
+ secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv
+ artifact: Squirrel Installer, Squirrel nupkg, Squirrel RELEASES
+ draft: true
+ force_update: true
+ on:
+ branch: master
+
+ - provider: GitHub
+ release: v$(flowVersion)
+ auth_token:
+ secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv
+ artifact: Squirrel Installer, Squirrel nupkg, Squirrel RELEASES
+ force_update: true
+ on:
+ APPVEYOR_REPO_TAG: true
\ No newline at end of file