From 4ea5dd5ad2ad6d4869d57c8aed1e187d81662135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 13 Oct 2020 20:54:00 +0800 Subject: [PATCH 001/267] Move Old HttpWebRequest to HttpClient Instance (solve connection timeout) --- Flow.Launcher.Core/Updater.cs | 2 +- Flow.Launcher.Infrastructure/Http/Http.cs | 77 ++++++++++++++--------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 99d48275a..4ad8b19be 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -139,7 +139,7 @@ namespace Flow.Launcher.Core 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/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b7d274205..038362a0d 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -13,6 +13,13 @@ 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,36 +27,55 @@ namespace Flow.Launcher.Infrastructure.Http ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + + client.DefaultRequestHeaders.Add("User-Agent", UserAgent); + + } + private static HttpProxy proxy; + public static HttpProxy Proxy + { + private get + { + return proxy; + } + set + { + proxy = value; + UpdateProxy(); + } } - public static HttpProxy Proxy { private get; set; } - public static IWebProxy WebProxy() + public static WebProxy WebProxy { get; private set; } + + /// + /// Update the Address of the Proxy to modify the client Proxy + /// + public static void UpdateProxy() + // TODO: need test with a proxy { if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server)) { if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password)) { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port); - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = null; } else { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port) - { - Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password) - }; - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password); } } else { - return WebRequest.GetSystemWebProxy(); + WebProxy.Address = new WebProxy().Address; + WebProxy.Credentials = null; } } public static void Download([NotNull] string url, [NotNull] string filePath) { - var client = new WebClient { Proxy = WebProxy() }; + var client = new WebClient { Proxy = WebProxy }; client.Headers.Add("user-agent", UserAgent); client.DownloadFile(url, filePath); } @@ -57,26 +83,17 @@ namespace Flow.Launcher.Infrastructure.Http public static async Task Get([NotNull] string url, string encoding = "UTF-8") { 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 response = await client.GetAsync(url); + using var stream = await response.Content.ReadAsStreamAsync(); + using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); + var content = await reader.ReadToEndAsync(); + if (response.StatusCode == HttpStatusCode.OK) { - var content = await reader.ReadToEndAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - return content; - } - else - { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); - } + return content; + } + else + { + throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } } From a16cc5be8db3b5d52acf12565b029439c8d1a921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 13 Oct 2020 20:54:00 +0800 Subject: [PATCH 002/267] Move Old HttpWebRequest to HttpClient Instance (solve connection timeout) --- Flow.Launcher.Core/Updater.cs | 2 +- Flow.Launcher.Infrastructure/Http/Http.cs | 78 ++++++++++++++--------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 99d48275a..4ad8b19be 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -139,7 +139,7 @@ namespace Flow.Launcher.Core 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/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b7d274205..81c07eff7 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using System; namespace Flow.Launcher.Infrastructure.Http { @@ -13,6 +14,13 @@ 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,36 +28,55 @@ namespace Flow.Launcher.Infrastructure.Http ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + + client.DefaultRequestHeaders.Add("User-Agent", UserAgent); + + } + private static HttpProxy proxy; + public static HttpProxy Proxy + { + private get + { + return proxy; + } + set + { + proxy = value; + UpdateProxy(); + } } - public static HttpProxy Proxy { private get; set; } - public static IWebProxy WebProxy() + public static WebProxy WebProxy { get; private set; } + + /// + /// Update the Address of the Proxy to modify the client Proxy + /// + public static void UpdateProxy() + // TODO: need test with a proxy { if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server)) { if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password)) { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port); - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = null; } else { - var webProxy = new WebProxy(Proxy.Server, Proxy.Port) - { - Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password) - }; - return webProxy; + WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); + WebProxy.Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password); } } else { - return WebRequest.GetSystemWebProxy(); + WebProxy.Address = new WebProxy().Address; + WebProxy.Credentials = null; } } public static void Download([NotNull] string url, [NotNull] string filePath) { - var client = new WebClient { Proxy = WebProxy() }; + var client = new WebClient { Proxy = WebProxy }; client.Headers.Add("user-agent", UserAgent); client.DownloadFile(url, filePath); } @@ -57,26 +84,17 @@ namespace Flow.Launcher.Infrastructure.Http public static async Task Get([NotNull] string url, string encoding = "UTF-8") { 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 response = await client.GetAsync(url); + using var stream = await response.Content.ReadAsStreamAsync(); + using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); + var content = await reader.ReadToEndAsync(); + if (response.StatusCode == HttpStatusCode.OK) { - var content = await reader.ReadToEndAsync(); - if (response.StatusCode == HttpStatusCode.OK) - { - return content; - } - else - { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); - } + return content; + } + else + { + throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } } From c55e889f4fb37aa2624eec4523cbcd94cadc3293 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 14 Oct 2020 11:29:12 +0800 Subject: [PATCH 003/267] Change Download to HttpClient as well (which change it to async as well) --- Flow.Launcher.Infrastructure/Http/Http.cs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 81c07eff7..34665217c 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -29,6 +29,7 @@ namespace Flow.Launcher.Infrastructure.Http | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; + client = new HttpClient(socketsHttpHandler, false); client.DefaultRequestHeaders.Add("User-Agent", UserAgent); } @@ -46,7 +47,7 @@ namespace Flow.Launcher.Infrastructure.Http } } - public static WebProxy WebProxy { get; private set; } + public static WebProxy WebProxy { get; private set; } = new WebProxy(); /// /// Update the Address of the Proxy to modify the client Proxy @@ -74,11 +75,18 @@ namespace Flow.Launcher.Infrastructure.Http } } - public static void Download([NotNull] string url, [NotNull] string filePath) + public async static Task Download([NotNull] string url, [NotNull] string filePath) { - var client = new WebClient { Proxy = WebProxy }; - client.Headers.Add("user-agent", UserAgent); - client.DownloadFile(url, filePath); + using var response = await client.GetAsync(url); + if (response.StatusCode == HttpStatusCode.OK) + { + using var fileStream = new FileStream(filePath, FileMode.CreateNew); + await response.Content.CopyToAsync(fileStream); + } + else + { + throw new WebException($"Error code <{response.StatusCode}> returned from <{url}>"); + } } public static async Task Get([NotNull] string url, string encoding = "UTF-8") From 424d757add58ccb38b50332b8a7597e8768b84bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 14 Oct 2020 11:29:38 +0800 Subject: [PATCH 004/267] Add Task.Run due to the change of async download --- .../Main.cs | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs index e1b631517..0255216a0 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs @@ -144,7 +144,7 @@ namespace Flow.Launcher.Plugin.PluginManagement IcoPath = "Images\\plugin.png", TitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.name).MatchData, SubTitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.description).MatchData, - Action = c => + Action = _ => { MessageBoxResult result = MessageBox.Show("Are you sure you wish to install the \'" + r.name + "\' plugin", "Install plugin", MessageBoxButton.YesNo); @@ -157,17 +157,19 @@ namespace Flow.Launcher.Plugin.PluginManagement string pluginUrl = APIBASE + "/media/" + r1.plugin_file; - try + Task.Run(async () => { - Http.Download(pluginUrl, filePath); - } - catch (WebException e) - { - context.API.ShowMsg($"PluginManagement.ResultForInstallPlugin: download failed for <{r.name}>"); - Log.Exception($"|PluginManagement.ResultForInstallPlugin|download failed for <{r.name}>", e); - return false; - } - context.API.InstallPlugin(filePath); + try + { + await Http.Download(pluginUrl, filePath); + context.API.InstallPlugin(filePath); + } + catch (WebException e) + { + context.API.ShowMsg($"PluginManagement.ResultForInstallPlugin: download failed for <{r.name}>"); + Log.Exception($"|PluginManagement.ResultForInstallPlugin|download failed for <{r.name}>", e); + } + }); } return false; } From 9d2164962292104aa9f33bdaef74fb8871208549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 10 Nov 2020 17:13:45 +0800 Subject: [PATCH 005/267] Change UI rendering logic Co-authored-by: Bao-Qian --- Flow.Launcher/ResultListBox.xaml | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 24 +++++- Flow.Launcher/ViewModel/ResultsForUpdate.cs | 36 +++++++++ Flow.Launcher/ViewModel/ResultsViewModel.cs | 89 ++++++++------------- 4 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 Flow.Launcher/ViewModel/ResultsForUpdate.cs diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 3280dc457..60d94a37b 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -42,7 +42,7 @@ + Source="{Binding Image}" /> diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index f18b74022..ac2cc79d5 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 System.Collections.Concurrent; namespace Flow.Launcher.ViewModel { @@ -47,6 +48,8 @@ namespace Flow.Launcher.ViewModel private bool _saved; private readonly Internationalization _translator = InternationalizationManager.Instance; + private BlockingCollection _resultsUpdateQueue; + #endregion @@ -76,6 +79,8 @@ namespace Flow.Launcher.ViewModel InitializeKeyCommands(); RegisterResultsUpdatedEvent(); + RegisterResultUpdate(); + SetHotkey(_settings.Hotkey, OnHotkey); SetCustomPluginHotkey(); SetOpenResultModifiers(); @@ -91,12 +96,27 @@ namespace Flow.Launcher.ViewModel Task.Run(() => { PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); - UpdateResultView(e.Results, pair.Metadata, e.Query); + _resultsUpdateQueue.Add(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); }, _updateToken); }; } } + private void RegisterResultUpdate() + { + _resultsUpdateQueue = new BlockingCollection(); + + Task.Run(() => + { + while (true) + { + var resultToUpdate = _resultsUpdateQueue.Take(); + if (!resultToUpdate.Token.IsCancellationRequested) + UpdateResultView(resultToUpdate.Results, resultToUpdate.Metadata, resultToUpdate.Query); + } + }); + } + private void InitializeKeyCommands() { @@ -415,7 +435,7 @@ namespace Flow.Launcher.ViewModel if (!plugin.Metadata.Disabled) { var results = PluginManager.QueryForPlugin(plugin, query); - UpdateResultView(results, plugin.Metadata, query); + _resultsUpdateQueue.Add(new ResultsForUpdate(results, plugin.Metadata, query, _updateToken)); } }); } diff --git a/Flow.Launcher/ViewModel/ResultsForUpdate.cs b/Flow.Launcher/ViewModel/ResultsForUpdate.cs new file mode 100644 index 000000000..29f626285 --- /dev/null +++ b/Flow.Launcher/ViewModel/ResultsForUpdate.cs @@ -0,0 +1,36 @@ +using Flow.Launcher.Plugin; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Flow.Launcher.ViewModel +{ + class ResultsForUpdate + { + public List Results { get; } + + public PluginMetadata Metadata { get; } + public string ID { get; } + + public Query Query { get; } + public CancellationToken Token { get; } + + public ResultsForUpdate(List results, string resultID, CancellationToken token) + { + Results = results; + ID = resultID; + Token = token; + } + + + public ResultsForUpdate(List results, PluginMetadata metadata, Query query, CancellationToken token) + { + Results = results; + Metadata = metadata; + Query = query; + Token = token; + ID = metadata.ID; + } + } +} diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index d30854180..ac435c494 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -17,7 +17,6 @@ namespace Flow.Launcher.ViewModel public ResultCollection Results { get; } - private readonly object _addResultsLock = new object(); private readonly object _collectionLock = new object(); private readonly Settings _settings; private int MaxResults => _settings?.MaxResultsToShow ?? 6; @@ -134,70 +133,37 @@ namespace Flow.Launcher.ViewModel /// public void AddResults(List newRawResults, string resultId) { - lock (_addResultsLock) + var newResults = NewResults(newRawResults, resultId); + + // update UI in one run, so it can avoid UI flickering + Results.Update(newResults); + + if (Results.Count > 0) { - var newResults = NewResults(newRawResults, resultId); - - // update UI in one run, so it can avoid UI flickering - Results.Update(newResults); - - if (Results.Count > 0) - { - Margin = new Thickness { Top = 8 }; - SelectedIndex = 0; - } - else - { - Margin = new Thickness { Top = 0 }; - } + Margin = new Thickness { Top = 8 }; + SelectedIndex = 0; + } + else + { + Margin = new Thickness { Top = 0 }; } } private List NewResults(List newRawResults, string resultId) { - var results = Results.ToList(); + if (newRawResults.Count == 0) + return Results.ToList(); + + var results = Results as IEnumerable; + var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings)).ToList(); - var oldResults = results.Where(r => r.Result.PluginID == resultId).ToList(); - // Find the same results in A (old results) and B (new newResults) - var sameResults = oldResults - .Where(t1 => newResults.Any(x => x.Result.Equals(t1.Result))) - .ToList(); - // remove result of relative complement of B in A - foreach (var result in oldResults.Except(sameResults)) - { - results.Remove(result); - } - - // update result with B's score and index position - foreach (var sameResult in sameResults) - { - int oldIndex = results.IndexOf(sameResult); - int oldScore = results[oldIndex].Result.Score; - var newResult = newResults[newResults.IndexOf(sameResult)]; - int newScore = newResult.Result.Score; - if (newScore != oldScore) - { - var oldResult = results[oldIndex]; - - oldResult.Result.Score = newScore; - oldResult.Result.OriginQuery = newResult.Result.OriginQuery; - - results.RemoveAt(oldIndex); - int newIndex = InsertIndexOf(newScore, results); - results.Insert(newIndex, oldResult); - } - } - - // insert result in relative complement of A in B - foreach (var result in newResults.Except(sameResults)) - { - int newIndex = InsertIndexOf(result.Result.Score, results); - results.Insert(newIndex, result); - } - - return results; + return results.Where(r => r.Result.PluginID != resultId) + .Concat(newResults) + .OrderByDescending(r => r.Result.Score) + .Take(MaxResults * 2) + .ToList(); } #endregion @@ -254,6 +220,17 @@ namespace Flow.Launcher.ViewModel /// public void Update(List newItems) { + ClearItems(); + + foreach (var item in newItems) + { + Add(item); + } + + + + return; + int newCount = newItems.Count; int oldCount = Items.Count; int location = newCount > oldCount ? oldCount : newCount; From 0e0f24f635bcbe4723692fe649c6ae475da34786 Mon Sep 17 00:00:00 2001 From: Qian Bao Date: Fri, 23 Oct 2020 10:45:22 +0800 Subject: [PATCH 006/267] Lazy Load Image --- Flow.Launcher/ResultListBox.xaml | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 60d94a37b..072196605 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -42,7 +42,7 @@ + Source="{Binding Image.Value}" /> diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index a4fe2ede4..a64836285 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -18,6 +18,7 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; + Image = new Lazy(() => SetImage); } Settings = settings; @@ -36,8 +37,10 @@ namespace Flow.Launcher.ViewModel public string ShowSubTitleToolTip => string.IsNullOrEmpty(Result.SubTitleToolTip) ? Result.SubTitle : Result.SubTitleToolTip; + + public Lazy Image { get; set; } - public ImageSource Image + private ImageSource SetImage { get { @@ -75,6 +78,7 @@ namespace Flow.Launcher.ViewModel } } + public override int GetHashCode() { return Result.GetHashCode(); From 52887aacf04e2f98de33e7caf21d2226924a0535 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 11 Nov 2020 18:36:01 +0800 Subject: [PATCH 007/267] Batch process ui change with interval 50ms --- Flow.Launcher/ViewModel/MainViewModel.cs | 46 +++++++-- Flow.Launcher/ViewModel/ResultsForUpdate.cs | 2 +- Flow.Launcher/ViewModel/ResultsViewModel.cs | 107 ++++++++++---------- 3 files changed, 93 insertions(+), 62 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ac2cc79d5..0a1ef8d81 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -106,13 +106,25 @@ namespace Flow.Launcher.ViewModel { _resultsUpdateQueue = new BlockingCollection(); - Task.Run(() => + Task.Run(async () => { while (true) { - var resultToUpdate = _resultsUpdateQueue.Take(); - if (!resultToUpdate.Token.IsCancellationRequested) - UpdateResultView(resultToUpdate.Results, resultToUpdate.Metadata, resultToUpdate.Query); + List queue = new List() { _resultsUpdateQueue.Take() }; + await Task.Delay(50); + + while (_resultsUpdateQueue.TryTake(out var resultsForUpdate)) + { + queue.Add(resultsForUpdate); + } + + //foreach (var update in queue) + //{ + // UpdateResultView(update.Results, update.Metadata, update.Query); + //} + + UpdateResultView(queue.Where(r => !r.Token.IsCancellationRequested)); + } }); } @@ -412,7 +424,7 @@ namespace Flow.Launcher.ViewModel if (query != null) { // handle the exclusiveness of plugin using action keyword - RemoveOldQueryResults(query); + // RemoveOldQueryResults(query); _lastQuery = query; Task.Delay(200, currentCancellationToken).ContinueWith(_ => @@ -443,7 +455,7 @@ namespace Flow.Launcher.ViewModel { // nothing to do here } - + // this should happen once after all queries are done so progress bar should continue // until the end of all querying @@ -459,6 +471,7 @@ namespace Flow.Launcher.ViewModel { Results.Clear(); Results.Visbility = Visibility.Collapsed; + } } @@ -683,6 +696,23 @@ namespace Flow.Launcher.ViewModel } } + public void UpdateResultView(IEnumerable resultsForUpdates) + { + foreach (var result in resultsForUpdates.SelectMany(u => u.Results)) + { + if (_topMostRecord.IsTopMost(result)) + { + result.Score = int.MaxValue; + } + else + { + result.Score += _userSelectedRecord.GetSelectedCount(result) * 5; + } + } + + Results.AddResults(resultsForUpdates); + } + /// /// To avoid deadlock, this method should not called from main thread /// @@ -705,10 +735,6 @@ namespace Flow.Launcher.ViewModel Results.AddResults(list, metadata.ID); } - if (Results.Visbility != Visibility.Visible && list.Count > 0) - { - Results.Visbility = Visibility.Visible; - } } #endregion diff --git a/Flow.Launcher/ViewModel/ResultsForUpdate.cs b/Flow.Launcher/ViewModel/ResultsForUpdate.cs index 29f626285..2257d35b0 100644 --- a/Flow.Launcher/ViewModel/ResultsForUpdate.cs +++ b/Flow.Launcher/ViewModel/ResultsForUpdate.cs @@ -6,7 +6,7 @@ using System.Threading; namespace Flow.Launcher.ViewModel { - class ResultsForUpdate + public class ResultsForUpdate { public List Results { get; } diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index ac435c494..d06a390c5 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Linq; using System.Windows; using System.Windows.Controls; @@ -115,19 +116,20 @@ namespace Flow.Launcher.ViewModel public void Clear() { - Results.Clear(); + Results.RemoveAll(); } public void RemoveResultsExcept(PluginMetadata metadata) { - Results.RemoveAll(r => r.Result.PluginID != metadata.ID); + //Results.RemoveAll(r => r.Result.PluginID != metadata.ID); } public void RemoveResultsFor(PluginMetadata metadata) { - Results.RemoveAll(r => r.Result.PluginID == metadata.ID); + //Results.RemoveAll(r => r.Result.PluginID == metadata.ID); } + /// /// To avoid deadlock, this method should not called from main thread /// @@ -138,16 +140,44 @@ namespace Flow.Launcher.ViewModel // update UI in one run, so it can avoid UI flickering Results.Update(newResults); - if (Results.Count > 0) + if (Visbility != Visibility.Visible && Results.Count > 0) { Margin = new Thickness { Top = 8 }; SelectedIndex = 0; + Visbility = Visibility.Visible; } else { Margin = new Thickness { Top = 0 }; + Visbility = Visibility.Collapsed; } } + /// + /// To avoid deadlock, this method should not called from main thread + /// + public void AddResults(IEnumerable resultsForUpdates) + { + var newResults = NewResults(resultsForUpdates); + lock (_collectionLock) + { + Results.Update(newResults); + } + + switch (Visbility) + { + case Visibility.Collapsed when Results.Count > 0: + Margin = new Thickness { Top = 8 }; + SelectedIndex = 0; + Visbility = Visibility.Visible; + break; + case Visibility.Visible when Results.Count == 0: + Margin = new Thickness { Top = 0 }; + Visbility = Visibility.Collapsed; + break; + + } + } + private List NewResults(List newRawResults, string resultId) { @@ -165,8 +195,25 @@ namespace Flow.Launcher.ViewModel .Take(MaxResults * 2) .ToList(); } + + private List NewResults(IEnumerable resultsForUpdates) + { + if (!resultsForUpdates.Any()) + return Results.ToList(); + + var results = Results as IEnumerable; + + return results.Where(r => !resultsForUpdates.Any(u => u.Metadata.ID == r.Result.PluginID)) + .Concat(resultsForUpdates + .SelectMany(u => u.Results) + .Select(r => new ResultViewModel(r, _settings))) + .OrderByDescending(rv => rv.Result.Score) + .Take(MaxResults * 2) + .ToList(); + } #endregion + #region FormattedText Dependency Property public static readonly DependencyProperty FormattedTextProperty = DependencyProperty.RegisterAttached( "FormattedText", @@ -198,20 +245,12 @@ namespace Flow.Launcher.ViewModel } #endregion - public class ResultCollection : ObservableCollection + public class ResultCollection : ObservableCollection, INotifyCollectionChanged { - - public void RemoveAll(Predicate predicate) + public event NotifyCollectionChangedEventHandler CollectionChanged; + public void RemoveAll() { - CheckReentrancy(); - - for (int i = Count - 1; i >= 0; i--) - { - if (predicate(this[i])) - { - RemoveAt(i); - } - } + ClearItems(); } /// @@ -226,44 +265,10 @@ namespace Flow.Launcher.ViewModel { Add(item); } + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - - return; - int newCount = newItems.Count; - int oldCount = Items.Count; - int location = newCount > oldCount ? oldCount : newCount; - - for (int i = 0; i < location; i++) - { - ResultViewModel oldResult = this[i]; - ResultViewModel newResult = newItems[i]; - if (!oldResult.Equals(newResult)) - { // result is not the same update it in the current index - this[i] = newResult; - } - else if (oldResult.Result.Score != newResult.Result.Score) - { - this[i].Result.Score = newResult.Result.Score; - } - } - - - if (newCount >= oldCount) - { - for (int i = oldCount; i < newCount; i++) - { - Add(newItems[i]); - } - } - else - { - for (int i = oldCount - 1; i >= newCount; i--) - { - RemoveAt(i); - } - } } } } From ebddf19ba21beccd961c3ad245640053e50fda3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 11 Nov 2020 19:06:05 +0800 Subject: [PATCH 008/267] Fix not canceled token and adding comment Co-authored-by: bao-qian --- Flow.Launcher/ViewModel/MainViewModel.cs | 6 ++++-- Flow.Launcher/ViewModel/ResultsViewModel.cs | 7 +++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 0a1ef8d81..f71674774 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -469,9 +469,9 @@ namespace Flow.Launcher.ViewModel } else { + _updateSource?.Cancel(); Results.Clear(); Results.Visbility = Visibility.Collapsed; - } } @@ -695,7 +695,9 @@ namespace Flow.Launcher.ViewModel _saved = true; } } - + /// + /// To avoid deadlock, this method should not called from main thread + /// public void UpdateResultView(IEnumerable resultsForUpdates) { foreach (var result in resultsForUpdates.SelectMany(u => u.Results)) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index d06a390c5..635b20ec6 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -174,7 +174,6 @@ namespace Flow.Launcher.ViewModel Margin = new Thickness { Top = 0 }; Visbility = Visibility.Collapsed; break; - } } @@ -247,7 +246,7 @@ namespace Flow.Launcher.ViewModel public class ResultCollection : ObservableCollection, INotifyCollectionChanged { - public event NotifyCollectionChangedEventHandler CollectionChanged; + public override event NotifyCollectionChangedEventHandler CollectionChanged; public void RemoveAll() { ClearItems(); @@ -259,12 +258,16 @@ namespace Flow.Launcher.ViewModel /// public void Update(List newItems) { + + ClearItems(); foreach (var item in newItems) { Add(item); } + + // wpf use directx / double buffered already, so just reset all won't cause ui flickering CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); return; From 1b76da175fa210e77dfc178e7007ea7aa2bf5721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 12 Nov 2020 15:37:04 +0800 Subject: [PATCH 009/267] Add remove previous query result back to keep different action word distinct --- Flow.Launcher/ViewModel/MainViewModel.cs | 8 ++++---- Flow.Launcher/ViewModel/ResultsViewModel.cs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index f71674774..cd2913570 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -424,7 +424,7 @@ namespace Flow.Launcher.ViewModel if (query != null) { // handle the exclusiveness of plugin using action keyword - // RemoveOldQueryResults(query); + RemoveOldQueryResults(query); _lastQuery = query; Task.Delay(200, currentCancellationToken).ContinueWith(_ => @@ -483,18 +483,18 @@ namespace Flow.Launcher.ViewModel { if (!string.IsNullOrEmpty(keyword)) { - Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata); + Results.KeepResultsFor(PluginManager.NonGlobalPlugins[keyword].Metadata); } } else { if (string.IsNullOrEmpty(keyword)) { - Results.RemoveResultsFor(PluginManager.NonGlobalPlugins[lastKeyword].Metadata); + Results.KeepResultsExcept(PluginManager.NonGlobalPlugins[lastKeyword].Metadata); } else if (lastKeyword != keyword) { - Results.RemoveResultsExcept(PluginManager.NonGlobalPlugins[keyword].Metadata); + Results.KeepResultsFor(PluginManager.NonGlobalPlugins[keyword].Metadata); } } } diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 635b20ec6..3b48c2d32 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -119,14 +119,14 @@ namespace Flow.Launcher.ViewModel Results.RemoveAll(); } - public void RemoveResultsExcept(PluginMetadata metadata) + public void KeepResultsFor(PluginMetadata metadata) { - //Results.RemoveAll(r => r.Result.PluginID != metadata.ID); + Results.Update(Results.Where(r => r.Result.PluginID == metadata.ID).ToList()); } - public void RemoveResultsFor(PluginMetadata metadata) + public void KeepResultsExcept(PluginMetadata metadata) { - //Results.RemoveAll(r => r.Result.PluginID == metadata.ID); + Results.Update(Results.Where(r => r.Result.PluginID != metadata.ID).ToList()); } From f51d2c57c75dd77fbf30e3c3a26922f906fed792 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 12 Nov 2020 15:46:24 +0800 Subject: [PATCH 010/267] keep all result in result list view --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 3b48c2d32..038cfb4e3 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -191,7 +191,6 @@ namespace Flow.Launcher.ViewModel return results.Where(r => r.Result.PluginID != resultId) .Concat(newResults) .OrderByDescending(r => r.Result.Score) - .Take(MaxResults * 2) .ToList(); } @@ -207,7 +206,6 @@ namespace Flow.Launcher.ViewModel .SelectMany(u => u.Results) .Select(r => new ResultViewModel(r, _settings))) .OrderByDescending(rv => rv.Result.Score) - .Take(MaxResults * 2) .ToList(); } #endregion From 4b2abfc7082764325c9fcee407ef7a202cba84a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 13 Nov 2020 13:41:59 +0800 Subject: [PATCH 011/267] Reduce batch time to speed up view update change selected index update place to fix not first selection issue --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- Flow.Launcher/ViewModel/ResultsViewModel.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index cd2913570..48e621126 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -111,7 +111,7 @@ namespace Flow.Launcher.ViewModel while (true) { List queue = new List() { _resultsUpdateQueue.Take() }; - await Task.Delay(50); + await Task.Delay(30); while (_resultsUpdateQueue.TryTake(out var resultsForUpdate)) { diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 038cfb4e3..3e464afe1 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -158,6 +158,11 @@ namespace Flow.Launcher.ViewModel public void AddResults(IEnumerable resultsForUpdates) { var newResults = NewResults(resultsForUpdates); + + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf + // fix selected index flow + SelectedIndex = 0; + lock (_collectionLock) { Results.Update(newResults); @@ -167,7 +172,6 @@ namespace Flow.Launcher.ViewModel { case Visibility.Collapsed when Results.Count > 0: Margin = new Thickness { Top = 8 }; - SelectedIndex = 0; Visbility = Visibility.Visible; break; case Visibility.Visible when Results.Count == 0: @@ -175,6 +179,7 @@ namespace Flow.Launcher.ViewModel Visbility = Visibility.Collapsed; break; } + } From e625c192ee5b64acba3195a6f7e0b16f0d6f7800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 13 Nov 2020 19:49:11 +0800 Subject: [PATCH 012/267] remove unused code --- Flow.Launcher/ViewModel/MainViewModel.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 48e621126..c093495e3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -118,11 +118,6 @@ namespace Flow.Launcher.ViewModel queue.Add(resultsForUpdate); } - //foreach (var update in queue) - //{ - // UpdateResultView(update.Results, update.Metadata, update.Query); - //} - UpdateResultView(queue.Where(r => !r.Token.IsCancellationRequested)); } From e34a52c74e778d06e1e538f1cd585c73142bf84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 14 Nov 2020 12:04:10 +0800 Subject: [PATCH 013/267] Don't change selected index unless collection is not empty --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 23 +++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 3e464afe1..d62e0d0c3 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -137,8 +137,16 @@ namespace Flow.Launcher.ViewModel { var newResults = NewResults(newRawResults, resultId); - // update UI in one run, so it can avoid UI flickering - Results.Update(newResults); + lock (_collectionLock) + { + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf + // fix selected index flow + if (Results.Count > 0) + SelectedIndex = 0; + + // update UI in one run, so it can avoid UI flickering + Results.Update(newResults); + } if (Visbility != Visibility.Visible && Results.Count > 0) { @@ -159,12 +167,14 @@ namespace Flow.Launcher.ViewModel { var newResults = NewResults(resultsForUpdates); - // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf - // fix selected index flow - SelectedIndex = 0; - lock (_collectionLock) { + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf + // fix selected index flow + if (Results.Count > 0) + SelectedIndex = 0; + + Results.Update(newResults); } @@ -172,6 +182,7 @@ namespace Flow.Launcher.ViewModel { case Visibility.Collapsed when Results.Count > 0: Margin = new Thickness { Top = 8 }; + SelectedIndex = 0; Visbility = Visibility.Visible; break; case Visibility.Visible when Results.Count == 0: From a4147f52c93d8ecd5af31f1b7e8e5130ff26693d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 14 Nov 2020 12:36:29 +0800 Subject: [PATCH 014/267] Block Notifychange unless all the element is added into the observablecollection This should improve the response speed. --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 36 ++++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index d62e0d0c3..6210dc54f 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -260,7 +260,30 @@ namespace Flow.Launcher.ViewModel public class ResultCollection : ObservableCollection, INotifyCollectionChanged { + private bool _suppressNotification = false; + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (!_suppressNotification) + base.OnCollectionChanged(e); + } + public override event NotifyCollectionChangedEventHandler CollectionChanged; + + public void AddRange(IEnumerable Items) + { + _suppressNotification = true; + + foreach (var item in Items) + { + Add(item); + } + + + // wpf use directx / double buffered already, so just reset all won't cause ui flickering + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + return; + + } public void RemoveAll() { ClearItems(); @@ -272,20 +295,9 @@ namespace Flow.Launcher.ViewModel /// public void Update(List newItems) { - - ClearItems(); - foreach (var item in newItems) - { - Add(item); - } - - // wpf use directx / double buffered already, so just reset all won't cause ui flickering - CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - - return; - + AddRange(newItems); } } } From dab8c5da957b3d3ad2b34f65ee6c0dcb35b106d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 14 Nov 2020 12:36:29 +0800 Subject: [PATCH 015/267] Block Notifychange unless all the element is added into the observablecollection This should improve the response speed. --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 37 ++++++++++++++------- 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index d62e0d0c3..4acf71edd 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -260,7 +260,31 @@ namespace Flow.Launcher.ViewModel public class ResultCollection : ObservableCollection, INotifyCollectionChanged { + private bool _suppressNotification = false; + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (!_suppressNotification) + base.OnCollectionChanged(e); + } + public override event NotifyCollectionChangedEventHandler CollectionChanged; + + // https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ + public void AddRange(IEnumerable Items) + { + _suppressNotification = true; + + foreach (var item in Items) + { + Add(item); + } + + + // wpf use directx / double buffered already, so just reset all won't cause ui flickering + CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + return; + + } public void RemoveAll() { ClearItems(); @@ -272,20 +296,9 @@ namespace Flow.Launcher.ViewModel /// public void Update(List newItems) { - - ClearItems(); - foreach (var item in newItems) - { - Add(item); - } - - // wpf use directx / double buffered already, so just reset all won't cause ui flickering - CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - - return; - + AddRange(newItems); } } } From 4cf143d435eeaabe61cfe64ade7e47bcbc352a17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 14 Nov 2020 15:07:56 +0800 Subject: [PATCH 016/267] Don't notify change until finishing up adding new result --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 4acf71edd..438b64d92 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -296,7 +296,7 @@ namespace Flow.Launcher.ViewModel /// public void Update(List newItems) { - ClearItems(); + Clear(); AddRange(newItems); } From 3076e501bfe629e10f96532d4a957187c7a3bb01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 14 Nov 2020 17:09:37 +0800 Subject: [PATCH 017/267] add null check when processing result update --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 438b64d92..5d6887a3f 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -217,10 +217,9 @@ namespace Flow.Launcher.ViewModel var results = Results as IEnumerable; - return results.Where(r => !resultsForUpdates.Any(u => u.Metadata.ID == r.Result.PluginID)) - .Concat(resultsForUpdates - .SelectMany(u => u.Results) - .Select(r => new ResultViewModel(r, _settings))) + return results.Where(r => r != null && !resultsForUpdates.Any(u => u.Metadata.ID == r.Result.PluginID)) + .Concat( + resultsForUpdates.SelectMany(u => u.Results, (u, r) => new ResultViewModel(r, _settings))) .OrderByDescending(rv => rv.Result.Score) .ToList(); } From 7dc247333ce6fece537e99912f7210b4f453cc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 14 Nov 2020 17:20:48 +0800 Subject: [PATCH 018/267] remove check of empty of Results when change selected index --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 5d6887a3f..1db6ac624 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -171,9 +171,7 @@ namespace Flow.Launcher.ViewModel { // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow - if (Results.Count > 0) - SelectedIndex = 0; - + SelectedIndex = 0; Results.Update(newResults); } From c89ee33c5b6c72fab2aee25f6584b83c776dec03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 15 Nov 2020 20:39:02 +0800 Subject: [PATCH 019/267] Use Virtualizing StackPanel instead of GridView to greatly reduce the loading resources. --- Flow.Launcher/ResultListBox.xaml | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 072196605..350ef018e 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -16,6 +16,7 @@ Style="{DynamicResource BaseListboxStyle}" Focusable="False" KeyboardNavigation.DirectionalNavigation="Cycle" SelectionMode="Single" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Standard" + ScrollViewer.IsDeferredScrollingEnabled="True" SelectionChanged="OnSelectionChanged" IsSynchronizedWithCurrentItem="True" PreviewMouseDown="ListBox_PreviewMouseDown"> @@ -29,26 +30,20 @@ - - + + - - - - - - + - + - + @@ -60,7 +55,7 @@ - + @@ -81,7 +76,7 @@ - + From dc982e277f3c7beff59a71675cde74853e7e0420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 15 Nov 2020 20:45:00 +0800 Subject: [PATCH 020/267] Use a default image to list when the image hasn't been loaded in cache. Co-authored-by: Bao-Qian --- .../Image/ImageCache.cs | 13 +++++---- .../Image/ImageLoader.cs | 11 +++++++- Flow.Launcher/ViewModel/ResultViewModel.cs | 28 +++++++++++++------ Flow.Launcher/ViewModel/ResultsViewModel.cs | 3 +- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 80c6684f5..7482ac1cf 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -26,7 +26,7 @@ namespace Flow.Launcher.Infrastructure.Image private const int MaxCached = 50; public ConcurrentDictionary Data { get; private set; } = new ConcurrentDictionary(); private const int permissibleFactor = 2; - + public void Initialization(Dictionary usage) { foreach (var key in usage.Keys) @@ -44,14 +44,14 @@ namespace Flow.Launcher.Infrastructure.Image value.usage++; return value.imageSource; } - + return null; } set { Data.AddOrUpdate( - path, - new ImageUsage(0, value), + path, + new ImageUsage(0, value), (k, v) => { v.imageSource = value; @@ -67,7 +67,8 @@ namespace Flow.Launcher.Infrastructure.Image // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. - foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) + foreach (var key in Data.Where(x => x.Key != Constant.MissingImgIcon) + .OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) { if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon))) { @@ -80,7 +81,7 @@ namespace Flow.Launcher.Infrastructure.Image public bool ContainsKey(string key) { - var contains = Data.ContainsKey(key); + var contains = Data.ContainsKey(key) && Data[key] != null; return contains; } diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index edfb88cbf..bc924926c 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -61,7 +61,7 @@ namespace Flow.Launcher.Infrastructure.Image { lock (_storage) { - _storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, y => y.usage)); + _storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, x => x.usage)); } } @@ -211,6 +211,15 @@ namespace Flow.Launcher.Infrastructure.Image option); } + public static bool CacheContainImage(string path) + { + return ImageCache.ContainsKey(path); + } + public static ImageSource LoadDefault(bool loadFullImage = false) + { + return LoadInternal(Constant.MissingImgIcon, loadFullImage).ImageSource; + } + public static ImageSource Load(string path, bool loadFullImage = false) { var imageResult = LoadInternal(path, loadFullImage); diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index a64836285..76c2a3e48 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using System.Windows; using System.Windows.Media; using System.Windows.Threading; @@ -26,18 +27,18 @@ namespace Flow.Launcher.ViewModel public Settings Settings { get; private set; } - public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden; + public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden; public string OpenResultModifiers => Settings.OpenResultModifiers; public string ShowTitleToolTip => string.IsNullOrEmpty(Result.TitleToolTip) - ? Result.Title + ? Result.Title : Result.TitleToolTip; public string ShowSubTitleToolTip => string.IsNullOrEmpty(Result.SubTitleToolTip) - ? Result.SubTitle + ? Result.SubTitle : Result.SubTitleToolTip; - + public Lazy Image { get; set; } private ImageSource SetImage @@ -57,9 +58,20 @@ namespace Flow.Launcher.ViewModel imagePath = Constant.MissingImgIcon; } } - - // will get here either when icoPath has value\icon delegate is null\when had exception in delegate - return ImageLoader.Load(imagePath); + + if (ImageLoader.CacheContainImage(imagePath)) + // will get here either when icoPath has value\icon delegate is null\when had exception in delegate + return ImageLoader.Load(imagePath); + else + { + Task.Run(() => + { + Image = new Lazy(() => ImageLoader.Load(imagePath)); + OnPropertyChanged(nameof(Image)); + }); + + return ImageLoader.LoadDefault(); + } } } @@ -78,7 +90,7 @@ namespace Flow.Launcher.ViewModel } } - + public override int GetHashCode() { return Result.GetHashCode(); diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 1db6ac624..eb40e75de 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -201,9 +201,10 @@ namespace Flow.Launcher.ViewModel var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings)).ToList(); + return results.Where(r => r.Result.PluginID != resultId) - .Concat(newResults) + .Concat(results.Intersect(newResults).Union(newResults)) .OrderByDescending(r => r.Result.Score) .ToList(); } From 4dd4cdafbf24c7437785cf01407aa7f6ce4086c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 15 Nov 2020 21:00:31 +0800 Subject: [PATCH 021/267] Revert "Use Virtualizing StackPanel instead of GridView to greatly reduce the loading resources." This reverts commit c89ee33c5b6c72fab2aee25f6584b83c776dec03. Revert it because it is not useful so just keep the original code. --- Flow.Launcher/ResultListBox.xaml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 350ef018e..072196605 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -16,7 +16,6 @@ Style="{DynamicResource BaseListboxStyle}" Focusable="False" KeyboardNavigation.DirectionalNavigation="Cycle" SelectionMode="Single" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Standard" - ScrollViewer.IsDeferredScrollingEnabled="True" SelectionChanged="OnSelectionChanged" IsSynchronizedWithCurrentItem="True" PreviewMouseDown="ListBox_PreviewMouseDown"> @@ -30,20 +29,26 @@ - - + + - + + + + + + - + - + @@ -55,7 +60,7 @@ - + @@ -76,7 +81,7 @@ - + From b1dd7b418136c791e0331ec7711421f285a2a54c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 15 Nov 2020 21:03:39 +0800 Subject: [PATCH 022/267] Move Image Cache filtering earlier --- Flow.Launcher.Infrastructure/Image/ImageCache.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 7482ac1cf..cce0aaace 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -26,7 +26,7 @@ namespace Flow.Launcher.Infrastructure.Image private const int MaxCached = 50; public ConcurrentDictionary Data { get; private set; } = new ConcurrentDictionary(); private const int permissibleFactor = 2; - + public void Initialization(Dictionary usage) { foreach (var key in usage.Keys) @@ -65,15 +65,13 @@ namespace Flow.Launcher.Infrastructure.Image if (Data.Count > permissibleFactor * MaxCached) { // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. - - - foreach (var key in Data.Where(x => x.Key != Constant.MissingImgIcon) + foreach (var key in Data + .Where(x => x.Key != Constant.MissingImgIcon + && x.Key != Constant.ErrorIcon + && x.Key != Constant.DefaultIcon) .OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) { - if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon))) - { - Data.TryRemove(key, out _); - } + Data.TryRemove(key, out _); } } } From 2161f27a88180c74ffc13046e8557a94b498a426 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 08:32:11 +0800 Subject: [PATCH 023/267] fix unintended token argument pass --- Flow.Launcher/ViewModel/MainViewModel.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index c093495e3..21243a793 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -22,6 +22,7 @@ using Flow.Launcher.Storage; using System.Windows.Media; using Flow.Launcher.Infrastructure.Image; using System.Collections.Concurrent; +using Flow.Launcher.Infrastructure.Logger; namespace Flow.Launcher.ViewModel { @@ -442,7 +443,7 @@ namespace Flow.Launcher.ViewModel if (!plugin.Metadata.Disabled) { var results = PluginManager.QueryForPlugin(plugin, query); - _resultsUpdateQueue.Add(new ResultsForUpdate(results, plugin.Metadata, query, _updateToken)); + _resultsUpdateQueue.Add(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)); } }); } @@ -695,6 +696,20 @@ namespace Flow.Launcher.ViewModel /// public void UpdateResultView(IEnumerable resultsForUpdates) { + if (!resultsForUpdates.Any()) + return; + + try + { + var token = resultsForUpdates.Select(r => r.Token).Distinct().Single(); + } + catch (Exception e) + { + Log.Debug("Illegal token information"); + } + + + foreach (var result in resultsForUpdates.SelectMany(u => u.Results)) { if (_topMostRecord.IsTopMost(result)) From e7c02dac7201c347ae9aa03ce2d100b29f3e2ca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 10:12:32 +0800 Subject: [PATCH 024/267] change SetImage to method instead of property to avoid unintended use --- Flow.Launcher/ViewModel/ResultViewModel.cs | 49 ++++++++++------------ 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 76c2a3e48..8ce35227f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -19,7 +19,7 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; - Image = new Lazy(() => SetImage); + Image = new Lazy(SetImage); } Settings = settings; @@ -41,38 +41,35 @@ namespace Flow.Launcher.ViewModel public Lazy Image { get; set; } - private ImageSource SetImage + private ImageSource SetImage() { - get + var imagePath = Result.IcoPath; + if (string.IsNullOrEmpty(imagePath) && Result.Icon != null) { - var imagePath = Result.IcoPath; - if (string.IsNullOrEmpty(imagePath) && Result.Icon != null) + try { - try - { - return Result.Icon(); - } - 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 Result.Icon(); } - - if (ImageLoader.CacheContainImage(imagePath)) - // will get here either when icoPath has value\icon delegate is null\when had exception in delegate - return ImageLoader.Load(imagePath); - else + catch (Exception e) { - Task.Run(() => - { - Image = new Lazy(() => ImageLoader.Load(imagePath)); - OnPropertyChanged(nameof(Image)); - }); - - return ImageLoader.LoadDefault(); + Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e); + imagePath = Constant.MissingImgIcon; } } + + if (ImageLoader.CacheContainImage(imagePath)) + // will get here either when icoPath has value\icon delegate is null\when had exception in delegate + return ImageLoader.Load(imagePath); + else + { + Task.Run(() => + { + Image = new Lazy(() => ImageLoader.Load(imagePath)); + OnPropertyChanged(nameof(Image)); + }); + + return ImageLoader.LoadDefault(); + } } public Result Result { get; } From 0a9bad3ffa25a2069f4e736e65b8a65a37ae44b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 12:46:39 +0800 Subject: [PATCH 025/267] Use Customized LazyAsync class to load image instead of the weird way of updating lazy class async --- .../Image/ImageLoader.cs | 12 ++-- Flow.Launcher/ViewModel/ResultViewModel.cs | 56 +++++++++++++++---- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index bc924926c..f61d4615a 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -18,6 +18,8 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly ConcurrentDictionary GuidToKey = new ConcurrentDictionary(); private static IImageHashGenerator _hashGenerator; private static bool EnableImageHash = true; + public static ImageSource defaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon)); + private static readonly string[] ImageExtensions = { @@ -37,6 +39,7 @@ namespace Flow.Launcher.Infrastructure.Image var usage = LoadStorageToConcurrentDictionary(); + foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon }) { ImageSource img = new BitmapImage(new Uri(icon)); @@ -213,13 +216,10 @@ namespace Flow.Launcher.Infrastructure.Image public static bool CacheContainImage(string path) { - return ImageCache.ContainsKey(path); - } - public static ImageSource LoadDefault(bool loadFullImage = false) - { - return LoadInternal(Constant.MissingImgIcon, loadFullImage).ImageSource; + return ImageCache.ContainsKey(path) && ImageCache[path] != null; } + public static ImageSource Load(string path, bool loadFullImage = false) { var imageResult = LoadInternal(path, loadFullImage); @@ -230,7 +230,7 @@ namespace Flow.Launcher.Infrastructure.Image string hash = EnableImageHash ? _hashGenerator.GetHashFromImage(img) : null; if (hash != null) { - + if (GuidToKey.TryGetValue(hash, out string key)) { // image already exists img = ImageCache[key] ?? img; diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 8ce35227f..511df5e59 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -8,18 +8,57 @@ using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; - +using Microsoft.FSharp.Core; namespace Flow.Launcher.ViewModel { public class ResultViewModel : BaseModel { + public class LazyAsync : Lazy> + { + private T defaultValue; + + + private readonly Action _updateCallback; + public T Value + { + get + { + if (!IsValueCreated) + { + base.Value.ContinueWith(_ => + { + _updateCallback(); + }); + return defaultValue; + } + else if (!base.Value.IsCompleted) + { + return defaultValue; + } + else return base.Value.Result; + } + } + public LazyAsync(Func> factory, T defaultValue, Action updateCallback) : base(factory) + { + if (defaultValue != null) + { + this.defaultValue = defaultValue; + } + _updateCallback = updateCallback; + + } + } + public ResultViewModel(Result result, Settings settings) { if (result != null) { Result = result; - Image = new Lazy(SetImage); + Image = new LazyAsync(SetImage, ImageLoader.defaultImage, () => + { + OnPropertyChanged(nameof(Image)); + }); } Settings = settings; @@ -39,9 +78,9 @@ namespace Flow.Launcher.ViewModel ? Result.SubTitle : Result.SubTitleToolTip; - public Lazy Image { get; set; } + public LazyAsync Image { get; set; } - private ImageSource SetImage() + private async Task SetImage() { var imagePath = Result.IcoPath; if (string.IsNullOrEmpty(imagePath) && Result.Icon != null) @@ -62,14 +101,9 @@ namespace Flow.Launcher.ViewModel return ImageLoader.Load(imagePath); else { - Task.Run(() => - { - Image = new Lazy(() => ImageLoader.Load(imagePath)); - OnPropertyChanged(nameof(Image)); - }); - - return ImageLoader.LoadDefault(); + return await Task.Run(() => ImageLoader.Load(imagePath)); } + } public Result Result { get; } From d9ef68272b1b98d727d00096203ddd3fea1abfbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 12:58:53 +0800 Subject: [PATCH 026/267] change default image property name --- Flow.Launcher.Infrastructure/Image/ImageLoader.cs | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index f61d4615a..fb2f426a0 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -18,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly ConcurrentDictionary GuidToKey = new ConcurrentDictionary(); private static IImageHashGenerator _hashGenerator; private static bool EnableImageHash = true; - public static ImageSource defaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon)); + public static ImageSource DefaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon)); private static readonly string[] ImageExtensions = diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 511df5e59..f4a51070f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -55,7 +55,7 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; - Image = new LazyAsync(SetImage, ImageLoader.defaultImage, () => + Image = new LazyAsync(SetImage, ImageLoader.DefaultImage, () => { OnPropertyChanged(nameof(Image)); }); From 71cac9cb2335bdd409a08bd8a2c0b30459889a6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 13:04:16 +0800 Subject: [PATCH 027/267] change the way of checking whether cache exist --- Flow.Launcher.Infrastructure/Image/ImageCache.cs | 3 +-- Flow.Launcher.Infrastructure/Image/ImageLoader.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index cce0aaace..c3d7e5cfa 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -79,8 +79,7 @@ namespace Flow.Launcher.Infrastructure.Image public bool ContainsKey(string key) { - var contains = Data.ContainsKey(key) && Data[key] != null; - return contains; + return Data.ContainsKey(key) && Data[key].imageSource != null; } public int CacheSize() diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index fb2f426a0..92cf9ac3f 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -216,7 +216,7 @@ namespace Flow.Launcher.Infrastructure.Image public static bool CacheContainImage(string path) { - return ImageCache.ContainsKey(path) && ImageCache[path] != null; + return ImageCache.ContainsKey(path); } From 23d9e253baed19786806f9236c5b74db7cdc56ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 19:20:52 +0800 Subject: [PATCH 028/267] Add some cancellationtoken check --- Flow.Launcher/ViewModel/MainViewModel.cs | 15 +++------------ Flow.Launcher/ViewModel/ResultsViewModel.cs | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 21243a793..ccc351cd3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -698,16 +698,7 @@ namespace Flow.Launcher.ViewModel { if (!resultsForUpdates.Any()) return; - - try - { - var token = resultsForUpdates.Select(r => r.Token).Distinct().Single(); - } - catch (Exception e) - { - Log.Debug("Illegal token information"); - } - + CancellationToken token = resultsForUpdates.Select(r => r.Token).Distinct().Single(); foreach (var result in resultsForUpdates.SelectMany(u => u.Results)) @@ -722,10 +713,10 @@ namespace Flow.Launcher.ViewModel } } - Results.AddResults(resultsForUpdates); + Results.AddResults(resultsForUpdates, token); } - /// + /// U /// To avoid deadlock, this method should not called from main thread /// public void UpdateResultView(List list, PluginMetadata metadata, Query originQuery) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index eb40e75de..cce532965 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Linq; +using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Data; @@ -136,7 +137,6 @@ namespace Flow.Launcher.ViewModel public void AddResults(List newRawResults, string resultId) { var newResults = NewResults(newRawResults, resultId); - lock (_collectionLock) { // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf @@ -163,9 +163,11 @@ namespace Flow.Launcher.ViewModel /// /// To avoid deadlock, this method should not called from main thread /// - public void AddResults(IEnumerable resultsForUpdates) + public void AddResults(IEnumerable resultsForUpdates, CancellationToken token) { var newResults = NewResults(resultsForUpdates); + if (token.IsCancellationRequested) + return; lock (_collectionLock) { @@ -173,7 +175,7 @@ namespace Flow.Launcher.ViewModel // fix selected index flow SelectedIndex = 0; - Results.Update(newResults); + Results.Update(newResults, token); } switch (Visbility) @@ -201,7 +203,7 @@ namespace Flow.Launcher.ViewModel var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings)).ToList(); - + return results.Where(r => r.Result.PluginID != resultId) .Concat(results.Intersect(newResults).Union(newResults)) @@ -292,10 +294,17 @@ namespace Flow.Launcher.ViewModel /// Update the results collection with new results, try to keep identical results /// /// + public void Update(List newItems, CancellationToken token) + { + Clear(); + if (token.IsCancellationRequested) + return; + AddRange(newItems); + } + public void Update(List newItems) { Clear(); - AddRange(newItems); } } From 2b423d9d80b3c6ced13c78feeec7d867eb3e3b8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 17 Nov 2020 16:46:36 +0800 Subject: [PATCH 029/267] Use single add notify for each element when the new Item is small or the collection hasn't been buffer a lot. This seems solve the startup stunt and potentially make render faster. (Need Testing) --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 47 ++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index cce532965..3a4b07fd6 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; +using System.Configuration; using System.Linq; using System.Threading; using System.Windows; @@ -137,6 +139,7 @@ namespace Flow.Launcher.ViewModel public void AddResults(List newRawResults, string resultId) { var newResults = NewResults(newRawResults, resultId); + lock (_collectionLock) { // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf @@ -258,30 +261,38 @@ namespace Flow.Launcher.ViewModel } #endregion - public class ResultCollection : ObservableCollection, INotifyCollectionChanged + public class ResultCollection : ObservableCollection { private bool _suppressNotification = false; + + private long editTime = 0; + + // https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { if (!_suppressNotification) base.OnCollectionChanged(e); } - public override event NotifyCollectionChangedEventHandler CollectionChanged; - - // https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ - public void AddRange(IEnumerable Items) + public void BulkAddRange(IEnumerable resultViews) { _suppressNotification = true; + foreach (var item in resultViews) + { + Add(item); + } + _suppressNotification = false; + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + public void AddRange(IEnumerable Items) + { foreach (var item in Items) { Add(item); } - // wpf use directx / double buffered already, so just reset all won't cause ui flickering - CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); return; } @@ -296,16 +307,32 @@ namespace Flow.Launcher.ViewModel /// public void Update(List newItems, CancellationToken token) { - Clear(); + if (token.IsCancellationRequested) return; - AddRange(newItems); + Update(newItems); } public void Update(List newItems) { + if (editTime == 0) + { + AddRange(newItems); + editTime++; + return; + } + else if (editTime < 15 || newItems.Count < 50) + { + ClearItems(); + AddRange(newItems); + editTime++; + return; + } Clear(); - AddRange(newItems); + + BulkAddRange(newItems); + editTime++; + } } } From 6863b412e3060f3ff1d69a08c40891fb5d5182ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 20 Nov 2020 22:45:33 +0800 Subject: [PATCH 030/267] Use TPL's BufferBlock instead of BlockingCollection, which will block the current Thread. This should make the Task.Run works better. --- Flow.Launcher/ViewModel/MainViewModel.cs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ccc351cd3..b6bb6703a 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -23,6 +23,7 @@ using System.Windows.Media; using Flow.Launcher.Infrastructure.Image; using System.Collections.Concurrent; using Flow.Launcher.Infrastructure.Logger; +using System.Threading.Tasks.Dataflow; namespace Flow.Launcher.ViewModel { @@ -49,7 +50,7 @@ namespace Flow.Launcher.ViewModel private bool _saved; private readonly Internationalization _translator = InternationalizationManager.Instance; - private BlockingCollection _resultsUpdateQueue; + private BufferBlock _resultsUpdateQueue; #endregion @@ -94,10 +95,10 @@ namespace Flow.Launcher.ViewModel var plugin = (IResultUpdated)pair.Plugin; plugin.ResultsUpdated += (s, e) => { - Task.Run(() => + Task.Run(async () => { PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); - _resultsUpdateQueue.Add(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); + await _resultsUpdateQueue.SendAsync(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); }, _updateToken); }; } @@ -105,20 +106,14 @@ namespace Flow.Launcher.ViewModel private void RegisterResultUpdate() { - _resultsUpdateQueue = new BlockingCollection(); + _resultsUpdateQueue = new BufferBlock(); Task.Run(async () => { - while (true) + while (await _resultsUpdateQueue.OutputAvailableAsync()) { - List queue = new List() { _resultsUpdateQueue.Take() }; await Task.Delay(30); - - while (_resultsUpdateQueue.TryTake(out var resultsForUpdate)) - { - queue.Add(resultsForUpdate); - } - + _resultsUpdateQueue.TryReceiveAll(out var queue); UpdateResultView(queue.Where(r => !r.Token.IsCancellationRequested)); } @@ -443,7 +438,7 @@ namespace Flow.Launcher.ViewModel if (!plugin.Metadata.Disabled) { var results = PluginManager.QueryForPlugin(plugin, query); - _resultsUpdateQueue.Add(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)); + _resultsUpdateQueue.Post(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)); } }); } From ea5e9a0fae49a9e9bdeee4791509764ffe07452e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 20 Nov 2020 23:05:12 +0800 Subject: [PATCH 031/267] Use New keyword for customized lazyAsync Value property --- Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index f4a51070f..0909b342f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -20,7 +20,7 @@ namespace Flow.Launcher.ViewModel private readonly Action _updateCallback; - public T Value + public new T Value { get { From 4fb884cf570da817d6286883050308b31313f505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 20 Nov 2020 23:21:04 +0800 Subject: [PATCH 032/267] Wait 50 ms for query staying same when updating view. --- Flow.Launcher/ViewModel/MainViewModel.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index b6bb6703a..6f67ffcf5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -229,6 +229,7 @@ namespace Flow.Launcher.ViewModel public ResultsViewModel Results { get; private set; } public ResultsViewModel ContextMenu { get; private set; } public ResultsViewModel History { get; private set; } + private string _lastQueryText; private string _queryText; public string QueryText @@ -427,8 +428,14 @@ namespace Flow.Launcher.ViewModel }, currentCancellationToken); var plugins = PluginManager.ValidPluginsForQuery(query); - Task.Run(() => + Task.Run(async () => { + // Wait 50 millisecond for query change + // if query stay the same, update the view + await Task.Delay(50); + if (!(_lastQuery.RawQuery == QueryText)) + return; + // so looping will stop once it was cancelled var parallelOptions = new ParallelOptions { CancellationToken = currentCancellationToken }; try From f11b302c37381c65ed50aa95ac07dc54b383ce7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 21 Nov 2020 12:01:57 +0800 Subject: [PATCH 033/267] slighly reduce the delay time --- Flow.Launcher/ViewModel/MainViewModel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 6f67ffcf5..fe1062cbb 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -112,7 +112,7 @@ namespace Flow.Launcher.ViewModel { while (await _resultsUpdateQueue.OutputAvailableAsync()) { - await Task.Delay(30); + await Task.Delay(20); _resultsUpdateQueue.TryReceiveAll(out var queue); UpdateResultView(queue.Where(r => !r.Token.IsCancellationRequested)); @@ -430,9 +430,9 @@ namespace Flow.Launcher.ViewModel var plugins = PluginManager.ValidPluginsForQuery(query); Task.Run(async () => { - // Wait 50 millisecond for query change + // Wait 45 millisecond for query change // if query stay the same, update the view - await Task.Delay(50); + await Task.Delay(45); if (!(_lastQuery.RawQuery == QueryText)) return; From 34dc0d0220e73c9ebe59a6efc1cf232828f68bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 21 Nov 2020 16:42:15 +0800 Subject: [PATCH 034/267] move progressbar task position and change the way of comparison --- Flow.Launcher/ViewModel/MainViewModel.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index fe1062cbb..4e0285d9e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -419,13 +419,6 @@ namespace Flow.Launcher.ViewModel RemoveOldQueryResults(query); _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 - if (currentUpdateSource == _updateSource && _isQueryRunning) - { - ProgressBarVisibility = Visibility.Visible; - } - }, currentCancellationToken); var plugins = PluginManager.ValidPluginsForQuery(query); Task.Run(async () => @@ -433,9 +426,18 @@ namespace Flow.Launcher.ViewModel // Wait 45 millisecond for query change // if query stay the same, update the view await Task.Delay(45); - if (!(_lastQuery.RawQuery == QueryText)) + if (!(_lastQuery.Search == query.Search)) return; + _ = 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 + if (currentUpdateSource == _updateSource && _isQueryRunning) + { + ProgressBarVisibility = Visibility.Visible; + } + }, currentCancellationToken); + // so looping will stop once it was cancelled var parallelOptions = new ParallelOptions { CancellationToken = currentCancellationToken }; try From 81ec3ef3d5e623f24d38ce9b5ae10d89c29c4306 Mon Sep 17 00:00:00 2001 From: kubalav Date: Sun, 22 Nov 2020 10:41:13 +0100 Subject: [PATCH 035/267] - Flow Launcher Slovak translation polish - Calculator plugin string shortened - Program plugin add missing strings --- Flow.Launcher/Languages/sk.xaml | 12 ++++++------ .../Languages/sk.xaml | 2 +- .../Flow.Launcher.Plugin.Program/Languages/sk.xaml | 7 ++++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index 8b9487b21..bf001d507 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -5,8 +5,8 @@ Nepodarilo sa registrovať klávesovú skratku {0} Nepodarilo sa spustiť {0} Neplatný formát súboru pre plugin Flow Launchera - Pri tomto dopyte umiestniť navrchu - Zrušiť umiestnenie navrchu pri tomto dopyte + Pri tomto zadaní umiestniť navrchu + Zrušiť umiestnenie navrchu pri tomto zadaní Spustiť dopyt: {0} Posledný čas realizácie: {0} Otvoriť @@ -22,7 +22,7 @@ Nezobrazovať upozornenia na novú verziu Zapamätať si posledné umiestnenie Jazyk - Posledný dopyt + Posledné vyhľadávanie Ponechať Označiť Vymazať @@ -34,7 +34,7 @@ Schovať Flow Launcher po spustení Schovať ikonu z oblasti oznámení Presnosť vyhľadávania - Dá sa použiť Pinyin + Použiť Pinyin Plugin @@ -96,11 +96,11 @@ Verzia Flow Launcher bol aktivovaný {0}-krát Skontrolovať aktualizácie - Je dostupná nová verzia {0}, prosím, reštartujte Flow Launcher. + Je dostupná nová verzia {0}, chcete reštartovať Flow Launcher, aby sa mohol aktualizovať? Kontrola aktualizácií zlyhala, prosím, skontrolujte pripojenie na internet a nastavenie proxy k api.github.com. Sťahovanie aktualizácií zlyhalo, skontrolujte pripojenie na internet a nastavenie proxy k github-cloud.s3.amazonaws.com, - alebo prejdite na https://github.com/Flow-Launcher/Flow.Launcher/releases pre manuálne stiahnutie aktualizácií. + alebo prejdite na https://github.com/Flow-Launcher/Flow.Launcher/releases pre manuálne stiahnutie aktualizácie. Poznámky k vydaniu diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml index dd52d5279..c08f0265c 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml @@ -12,5 +12,5 @@ Použiť podľa systému Čiarka (,) Bodka (.) - Max. desatinných miest + Desatinné miesta \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/sk.xaml index ece9fea81..851233407 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/sk.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/sk.xaml @@ -40,7 +40,12 @@ Vyhľadávanie programov vo Flow Launcheri Neplatná cesta - + + Vlastný správca súborov + Arg. + Môžete si prispôsobiť otváranie umiestnenia priečinka vložením Premenných prostredia, ktoré chcete použiť. Dostupnosť premenných prostredia môžete vyskúšať cez príkazový riadok. + Zadajte argumenty, ktoré chcete pridať pre správcu súborov. %s pre rodičovský priečinok, %f pre celú cestu (funguje iba pre win32). Pre podrobnosti pozrite webovú stránku správcu súborov. + Úspešné Úspešne zakázané zobrazovanie tohto programu vo výsledkoch vyhľadávania From 9bc58fe9dacfd5b78e2c75be53e3ad2bd72dfe21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 22 Nov 2020 18:24:27 +0800 Subject: [PATCH 036/267] Only stop querying for global query --- Flow.Launcher/ViewModel/MainViewModel.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 4e0285d9e..1f8e72b8c 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -79,9 +79,10 @@ namespace Flow.Launcher.ViewModel _selectedResults = Results; InitializeKeyCommands(); - RegisterResultsUpdatedEvent(); RegisterResultUpdate(); + RegisterResultsUpdatedEvent(); + SetHotkey(_settings.Hotkey, OnHotkey); SetCustomPluginHotkey(); @@ -423,11 +424,14 @@ namespace Flow.Launcher.ViewModel var plugins = PluginManager.ValidPluginsForQuery(query); Task.Run(async () => { - // Wait 45 millisecond for query change - // if query stay the same, update the view - await Task.Delay(45); - if (!(_lastQuery.Search == query.Search)) - return; + if (plugins.Count > 1) + { + // Wait 45 millisecond for query change in global query + // if query changes, return so that it won't be calculated + await Task.Delay(45); + if (!(_lastQuery.Search == query.Search)) + return; + } _ = Task.Delay(200, currentCancellationToken).ContinueWith(_ => { From 341275fbbdda51d7c9bb1f1e80134895d499f2ed Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 23 Nov 2020 13:30:45 +1100 Subject: [PATCH 037/267] version bump for Calculator & Program plugins --- Plugins/Flow.Launcher.Plugin.Calculator/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Program/plugin.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json index 5ec1ac002..709757d1a 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.2", + "Version": "1.1.3", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Caculator.dll", diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json index 9b5af94fb..7d7a42e03 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.1", + "Version": "1.2.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Program.dll", From 81a02c6e64ed67825b547d64393b83911cefdf08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 24 Nov 2020 17:38:24 +0800 Subject: [PATCH 038/267] Don't add result to queue unless the query match (plugin event driven update) Remove the Task.Run because updating result metadata and adding result to queue should not be time wasted. --- Flow.Launcher/ViewModel/MainViewModel.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 3d3792c54..f398df92b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -96,11 +96,9 @@ namespace Flow.Launcher.ViewModel var plugin = (IResultUpdated)pair.Plugin; plugin.ResultsUpdated += (s, e) => { - Task.Run(async () => - { - PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); - await _resultsUpdateQueue.SendAsync(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); - }, _updateToken); + PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); + if (e.Query.Search == _lastQuery.Search) + _resultsUpdateQueue.Post(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); }; } } @@ -428,13 +426,13 @@ namespace Flow.Launcher.ViewModel { // Wait 45 millisecond for query change in global query // if query changes, return so that it won't be calculated - await Task.Delay(45); + await Task.Delay(45, currentCancellationToken); if (!(_lastQuery.Search == query.Search)) return; } _ = 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 if (currentUpdateSource == _updateSource && _isQueryRunning) { From c1107494344977f51865dbfba96ec5dd13b4ee5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 24 Nov 2020 17:41:57 +0800 Subject: [PATCH 039/267] Add more cancellation --- Flow.Launcher/ViewModel/MainViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index f398df92b..fdae8ecd4 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -449,7 +449,8 @@ namespace Flow.Launcher.ViewModel if (!plugin.Metadata.Disabled) { var results = PluginManager.QueryForPlugin(plugin, query); - _resultsUpdateQueue.Post(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)); + if (!currentCancellationToken.IsCancellationRequested) + _resultsUpdateQueue.Post(new ResultsForUpdate(results, plugin.Metadata, query, currentCancellationToken)); } }); } From 69e11e2861622d85b957e983e6c736ff745eb5d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 24 Nov 2020 18:59:16 +0800 Subject: [PATCH 040/267] Use CancellationToken.IsCancellationRequested wherever is possible to use, check equality of query whererever token is unaccessiable. Dispose CancellationTokenSourse manually --- Flow.Launcher/ViewModel/MainViewModel.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index fdae8ecd4..9316cd62e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -404,6 +404,8 @@ namespace Flow.Launcher.ViewModel if (!string.IsNullOrEmpty(QueryText)) { _updateSource?.Cancel(); + _updateSource?.Dispose(); + var currentUpdateSource = new CancellationTokenSource(); _updateSource = currentUpdateSource; var currentCancellationToken = _updateSource.Token; @@ -427,14 +429,14 @@ namespace Flow.Launcher.ViewModel // Wait 45 millisecond for query change in global query // if query changes, return so that it won't be calculated await Task.Delay(45, currentCancellationToken); - if (!(_lastQuery.Search == query.Search)) + if (currentCancellationToken.IsCancellationRequested) return; } _ = 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 - if (currentUpdateSource == _updateSource && _isQueryRunning) + if (!currentCancellationToken.IsCancellationRequested && _isQueryRunning) { ProgressBarVisibility = Visibility.Visible; } @@ -463,7 +465,7 @@ namespace Flow.Launcher.ViewModel // 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) + if (!currentCancellationToken.IsCancellationRequested) { // update to hidden if this is still the current query ProgressBarVisibility = Visibility.Hidden; } From 2c14c2120f83eb4761efc91dd5190daac0f60e51 Mon Sep 17 00:00:00 2001 From: Qian Bao Date: Fri, 23 Oct 2020 10:45:22 +0800 Subject: [PATCH 041/267] Lazy Load Image --- Flow.Launcher/ResultListBox.xaml | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 3280dc457..072196605 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -42,7 +42,7 @@ + Source="{Binding Image.Value}" /> diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index a4fe2ede4..a64836285 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -18,6 +18,7 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; + Image = new Lazy(() => SetImage); } Settings = settings; @@ -36,8 +37,10 @@ namespace Flow.Launcher.ViewModel public string ShowSubTitleToolTip => string.IsNullOrEmpty(Result.SubTitleToolTip) ? Result.SubTitle : Result.SubTitleToolTip; + + public Lazy Image { get; set; } - public ImageSource Image + private ImageSource SetImage { get { @@ -75,6 +78,7 @@ namespace Flow.Launcher.ViewModel } } + public override int GetHashCode() { return Result.GetHashCode(); From 1439ee7e9ed6adbcc5f17221dca1eb406c00ae58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 15 Nov 2020 20:45:00 +0800 Subject: [PATCH 042/267] Use a default image to list when the image hasn't been loaded in cache. Co-authored-by: Bao-Qian --- .../Image/ImageCache.cs | 13 +++++---- .../Image/ImageLoader.cs | 11 +++++++- Flow.Launcher/ViewModel/ResultViewModel.cs | 28 +++++++++++++------ 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 80c6684f5..7482ac1cf 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -26,7 +26,7 @@ namespace Flow.Launcher.Infrastructure.Image private const int MaxCached = 50; public ConcurrentDictionary Data { get; private set; } = new ConcurrentDictionary(); private const int permissibleFactor = 2; - + public void Initialization(Dictionary usage) { foreach (var key in usage.Keys) @@ -44,14 +44,14 @@ namespace Flow.Launcher.Infrastructure.Image value.usage++; return value.imageSource; } - + return null; } set { Data.AddOrUpdate( - path, - new ImageUsage(0, value), + path, + new ImageUsage(0, value), (k, v) => { v.imageSource = value; @@ -67,7 +67,8 @@ namespace Flow.Launcher.Infrastructure.Image // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. - foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) + foreach (var key in Data.Where(x => x.Key != Constant.MissingImgIcon) + .OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) { if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon))) { @@ -80,7 +81,7 @@ namespace Flow.Launcher.Infrastructure.Image public bool ContainsKey(string key) { - var contains = Data.ContainsKey(key); + var contains = Data.ContainsKey(key) && Data[key] != null; return contains; } diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index edfb88cbf..bc924926c 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -61,7 +61,7 @@ namespace Flow.Launcher.Infrastructure.Image { lock (_storage) { - _storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, y => y.usage)); + _storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, x => x.usage)); } } @@ -211,6 +211,15 @@ namespace Flow.Launcher.Infrastructure.Image option); } + public static bool CacheContainImage(string path) + { + return ImageCache.ContainsKey(path); + } + public static ImageSource LoadDefault(bool loadFullImage = false) + { + return LoadInternal(Constant.MissingImgIcon, loadFullImage).ImageSource; + } + public static ImageSource Load(string path, bool loadFullImage = false) { var imageResult = LoadInternal(path, loadFullImage); diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index a64836285..76c2a3e48 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using System.Windows; using System.Windows.Media; using System.Windows.Threading; @@ -26,18 +27,18 @@ namespace Flow.Launcher.ViewModel public Settings Settings { get; private set; } - public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden; + public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden; public string OpenResultModifiers => Settings.OpenResultModifiers; public string ShowTitleToolTip => string.IsNullOrEmpty(Result.TitleToolTip) - ? Result.Title + ? Result.Title : Result.TitleToolTip; public string ShowSubTitleToolTip => string.IsNullOrEmpty(Result.SubTitleToolTip) - ? Result.SubTitle + ? Result.SubTitle : Result.SubTitleToolTip; - + public Lazy Image { get; set; } private ImageSource SetImage @@ -57,9 +58,20 @@ namespace Flow.Launcher.ViewModel imagePath = Constant.MissingImgIcon; } } - - // will get here either when icoPath has value\icon delegate is null\when had exception in delegate - return ImageLoader.Load(imagePath); + + if (ImageLoader.CacheContainImage(imagePath)) + // will get here either when icoPath has value\icon delegate is null\when had exception in delegate + return ImageLoader.Load(imagePath); + else + { + Task.Run(() => + { + Image = new Lazy(() => ImageLoader.Load(imagePath)); + OnPropertyChanged(nameof(Image)); + }); + + return ImageLoader.LoadDefault(); + } } } @@ -78,7 +90,7 @@ namespace Flow.Launcher.ViewModel } } - + public override int GetHashCode() { return Result.GetHashCode(); From 99086e26444498bc5ebe0a7ca5654eeedb99dc9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 10:12:32 +0800 Subject: [PATCH 043/267] change SetImage to method instead of property to avoid unintended use --- Flow.Launcher/ViewModel/ResultViewModel.cs | 49 ++++++++++------------ 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 76c2a3e48..8ce35227f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -19,7 +19,7 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; - Image = new Lazy(() => SetImage); + Image = new Lazy(SetImage); } Settings = settings; @@ -41,38 +41,35 @@ namespace Flow.Launcher.ViewModel public Lazy Image { get; set; } - private ImageSource SetImage + private ImageSource SetImage() { - get + var imagePath = Result.IcoPath; + if (string.IsNullOrEmpty(imagePath) && Result.Icon != null) { - var imagePath = Result.IcoPath; - if (string.IsNullOrEmpty(imagePath) && Result.Icon != null) + try { - try - { - return Result.Icon(); - } - 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 Result.Icon(); } - - if (ImageLoader.CacheContainImage(imagePath)) - // will get here either when icoPath has value\icon delegate is null\when had exception in delegate - return ImageLoader.Load(imagePath); - else + catch (Exception e) { - Task.Run(() => - { - Image = new Lazy(() => ImageLoader.Load(imagePath)); - OnPropertyChanged(nameof(Image)); - }); - - return ImageLoader.LoadDefault(); + Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e); + imagePath = Constant.MissingImgIcon; } } + + if (ImageLoader.CacheContainImage(imagePath)) + // will get here either when icoPath has value\icon delegate is null\when had exception in delegate + return ImageLoader.Load(imagePath); + else + { + Task.Run(() => + { + Image = new Lazy(() => ImageLoader.Load(imagePath)); + OnPropertyChanged(nameof(Image)); + }); + + return ImageLoader.LoadDefault(); + } } public Result Result { get; } From a7310d5d22663af9119bc0d96b7fd0fa849afbf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 12:46:39 +0800 Subject: [PATCH 044/267] Use Customized LazyAsync class to load image instead of the weird way of updating lazy class async --- .../Image/ImageLoader.cs | 12 ++-- Flow.Launcher/ViewModel/ResultViewModel.cs | 56 +++++++++++++++---- 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index bc924926c..f61d4615a 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -18,6 +18,8 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly ConcurrentDictionary GuidToKey = new ConcurrentDictionary(); private static IImageHashGenerator _hashGenerator; private static bool EnableImageHash = true; + public static ImageSource defaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon)); + private static readonly string[] ImageExtensions = { @@ -37,6 +39,7 @@ namespace Flow.Launcher.Infrastructure.Image var usage = LoadStorageToConcurrentDictionary(); + foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon }) { ImageSource img = new BitmapImage(new Uri(icon)); @@ -213,13 +216,10 @@ namespace Flow.Launcher.Infrastructure.Image public static bool CacheContainImage(string path) { - return ImageCache.ContainsKey(path); - } - public static ImageSource LoadDefault(bool loadFullImage = false) - { - return LoadInternal(Constant.MissingImgIcon, loadFullImage).ImageSource; + return ImageCache.ContainsKey(path) && ImageCache[path] != null; } + public static ImageSource Load(string path, bool loadFullImage = false) { var imageResult = LoadInternal(path, loadFullImage); @@ -230,7 +230,7 @@ namespace Flow.Launcher.Infrastructure.Image string hash = EnableImageHash ? _hashGenerator.GetHashFromImage(img) : null; if (hash != null) { - + if (GuidToKey.TryGetValue(hash, out string key)) { // image already exists img = ImageCache[key] ?? img; diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 8ce35227f..511df5e59 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -8,18 +8,57 @@ using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; - +using Microsoft.FSharp.Core; namespace Flow.Launcher.ViewModel { public class ResultViewModel : BaseModel { + public class LazyAsync : Lazy> + { + private T defaultValue; + + + private readonly Action _updateCallback; + public T Value + { + get + { + if (!IsValueCreated) + { + base.Value.ContinueWith(_ => + { + _updateCallback(); + }); + return defaultValue; + } + else if (!base.Value.IsCompleted) + { + return defaultValue; + } + else return base.Value.Result; + } + } + public LazyAsync(Func> factory, T defaultValue, Action updateCallback) : base(factory) + { + if (defaultValue != null) + { + this.defaultValue = defaultValue; + } + _updateCallback = updateCallback; + + } + } + public ResultViewModel(Result result, Settings settings) { if (result != null) { Result = result; - Image = new Lazy(SetImage); + Image = new LazyAsync(SetImage, ImageLoader.defaultImage, () => + { + OnPropertyChanged(nameof(Image)); + }); } Settings = settings; @@ -39,9 +78,9 @@ namespace Flow.Launcher.ViewModel ? Result.SubTitle : Result.SubTitleToolTip; - public Lazy Image { get; set; } + public LazyAsync Image { get; set; } - private ImageSource SetImage() + private async Task SetImage() { var imagePath = Result.IcoPath; if (string.IsNullOrEmpty(imagePath) && Result.Icon != null) @@ -62,14 +101,9 @@ namespace Flow.Launcher.ViewModel return ImageLoader.Load(imagePath); else { - Task.Run(() => - { - Image = new Lazy(() => ImageLoader.Load(imagePath)); - OnPropertyChanged(nameof(Image)); - }); - - return ImageLoader.LoadDefault(); + return await Task.Run(() => ImageLoader.Load(imagePath)); } + } public Result Result { get; } From b3df2fd590bf81883a03f17a955a0d13541ed284 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 16 Nov 2020 12:58:53 +0800 Subject: [PATCH 045/267] change default image property name --- Flow.Launcher.Infrastructure/Image/ImageLoader.cs | 2 +- Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index f61d4615a..fb2f426a0 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -18,7 +18,7 @@ namespace Flow.Launcher.Infrastructure.Image private static readonly ConcurrentDictionary GuidToKey = new ConcurrentDictionary(); private static IImageHashGenerator _hashGenerator; private static bool EnableImageHash = true; - public static ImageSource defaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon)); + public static ImageSource DefaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon)); private static readonly string[] ImageExtensions = diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 511df5e59..f4a51070f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -55,7 +55,7 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; - Image = new LazyAsync(SetImage, ImageLoader.defaultImage, () => + Image = new LazyAsync(SetImage, ImageLoader.DefaultImage, () => { OnPropertyChanged(nameof(Image)); }); From dd8a31ccd87bb71d5fc3d3ab74a170e96d2aa0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 25 Nov 2020 23:26:35 +0800 Subject: [PATCH 046/267] Add new to Value Property of the LazyAsync clas --- Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index f4a51070f..0909b342f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -20,7 +20,7 @@ namespace Flow.Launcher.ViewModel private readonly Action _updateCallback; - public T Value + public new T Value { get { From efcb6a7833e030f9463e6792fdc63579a8c787d5 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 26 Nov 2020 20:47:04 +1100 Subject: [PATCH 047/267] add status check when base.Value has faulted --- .../Image/ImageCache.cs | 6 +++--- .../Image/ImageLoader.cs | 2 -- Flow.Launcher/ViewModel/ResultViewModel.cs | 19 ++++++++----------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 7482ac1cf..3c819236b 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -66,9 +66,10 @@ namespace Flow.Launcher.Infrastructure.Image { // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. - foreach (var key in Data.Where(x => x.Key != Constant.MissingImgIcon) - .OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) + .OrderBy(x => x.Value.usage) + .Take(Data.Count - MaxCached) + .Select(x => x.Key)) { if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon))) { @@ -98,5 +99,4 @@ namespace Flow.Launcher.Infrastructure.Image return Data.Values.Select(x => x.imageSource).Distinct().Count(); } } - } \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index fb2f426a0..ac333d567 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -39,7 +39,6 @@ namespace Flow.Launcher.Infrastructure.Image var usage = LoadStorageToConcurrentDictionary(); - foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon }) { ImageSource img = new BitmapImage(new Uri(icon)); @@ -219,7 +218,6 @@ namespace Flow.Launcher.Infrastructure.Image return ImageCache.ContainsKey(path) && ImageCache[path] != null; } - public static ImageSource Load(string path, bool loadFullImage = false) { var imageResult = LoadInternal(path, loadFullImage); diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 0909b342f..6e00d3421 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -2,13 +2,11 @@ using System.Threading.Tasks; using System.Windows; using System.Windows.Media; -using System.Windows.Threading; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Image; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; -using Microsoft.FSharp.Core; namespace Flow.Launcher.ViewModel { @@ -18,7 +16,6 @@ namespace Flow.Launcher.ViewModel { private T defaultValue; - private readonly Action _updateCallback; public new T Value { @@ -30,13 +27,14 @@ namespace Flow.Launcher.ViewModel { _updateCallback(); }); + return defaultValue; } - else if (!base.Value.IsCompleted) - { + + if (!base.Value.IsCompleted || base.Value.IsFaulted) return defaultValue; - } - else return base.Value.Result; + + return base.Value.Result; } } public LazyAsync(Func> factory, T defaultValue, Action updateCallback) : base(factory) @@ -45,8 +43,8 @@ namespace Flow.Launcher.ViewModel { this.defaultValue = defaultValue; } + _updateCallback = updateCallback; - } } @@ -97,13 +95,14 @@ namespace Flow.Launcher.ViewModel } if (ImageLoader.CacheContainImage(imagePath)) + { // will get here either when icoPath has value\icon delegate is null\when had exception in delegate return ImageLoader.Load(imagePath); + } else { return await Task.Run(() => ImageLoader.Load(imagePath)); } - } public Result Result { get; } @@ -121,7 +120,6 @@ namespace Flow.Launcher.ViewModel } } - public override int GetHashCode() { return Result.GetHashCode(); @@ -131,6 +129,5 @@ namespace Flow.Launcher.ViewModel { return Result.ToString(); } - } } From ac945f48147c8901861bb1ed9f2c9d2d7966e044 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 27 Nov 2020 07:04:39 +1100 Subject: [PATCH 048/267] revert unneeded condition on Constant.MissingImgIcon --- Flow.Launcher.Infrastructure/Image/ImageCache.cs | 5 +---- Flow.Launcher/ViewModel/ResultViewModel.cs | 12 ++++++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 3c819236b..0cb5779d2 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -66,10 +66,7 @@ namespace Flow.Launcher.Infrastructure.Image { // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. - foreach (var key in Data.Where(x => x.Key != Constant.MissingImgIcon) - .OrderBy(x => x.Value.usage) - .Take(Data.Count - MaxCached) - .Select(x => x.Key)) + foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) { if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon))) { diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 6e00d3421..00a0e1ae5 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -53,10 +53,14 @@ namespace Flow.Launcher.ViewModel if (result != null) { Result = result; - Image = new LazyAsync(SetImage, ImageLoader.DefaultImage, () => - { - OnPropertyChanged(nameof(Image)); - }); + + Image = new LazyAsync( + SetImage, + ImageLoader.DefaultImage, + () => + { + OnPropertyChanged(nameof(Image)); + }); } Settings = settings; From 1c6769cbcc78b2988ded5f7b22e60a1590d1b382 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 27 Nov 2020 07:43:03 +1100 Subject: [PATCH 049/267] fix merge --- Flow.Launcher/ViewModel/ResultViewModel.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 6805f31aa..3a1b7fee4 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -100,17 +100,10 @@ namespace Flow.Launcher.ViewModel } if (ImageLoader.CacheContainImage(imagePath)) - { // will get here either when icoPath has value\icon delegate is null\when had exception in delegate return ImageLoader.Load(imagePath); - else - { - return await Task.Run(() => ImageLoader.Load(imagePath)); - } - else - { - return await Task.Run(() => ImageLoader.Load(imagePath)); - } + + return await Task.Run(() => ImageLoader.Load(imagePath)); } public Result Result { get; } From 05aa7062d7104b6d2bbb900ad26607f5f5db8a49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 27 Nov 2020 08:46:59 +0800 Subject: [PATCH 050/267] Change ErrorIcon to MissingImgIcon in ImageCache check since we don't use ErrorIcon anymore --- Flow.Launcher.Infrastructure/Image/ImageCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index fdbdddb2d..b8da3b030 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -66,7 +66,7 @@ namespace Flow.Launcher.Infrastructure.Image { // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. foreach (var key in Data - .Where(x => x.Key != Constant.ErrorIcon + .Where(x => x.Key != Constant.MissingImgIcon && x.Key != Constant.DefaultIcon) .OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) { From f20c721ad1adba428602290efe45a4c351ed233b Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 27 Nov 2020 13:12:09 +1100 Subject: [PATCH 051/267] allow MissingImgIcon and DefaultIcon to be removed from image cache --- Flow.Launcher.Infrastructure/Image/ImageCache.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 0cb5779d2..b1c09024f 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -65,14 +65,8 @@ namespace Flow.Launcher.Infrastructure.Image if (Data.Count > permissibleFactor * MaxCached) { // To delete the images from the data dictionary based on the resizing of the Usage Dictionary. - foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) - { - if (!(key.Equals(Constant.ErrorIcon) || key.Equals(Constant.DefaultIcon))) - { - Data.TryRemove(key, out _); - } - } + Data.TryRemove(key, out _); } } } From 813e9b5439592fb3057bf5ff8af76d50d2df8f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 28 Nov 2020 13:25:49 +0800 Subject: [PATCH 052/267] fix selected item doesn't always be the first item issue. Method: Not only update selected index, but also update selected item when adding results. --- Flow.Launcher/ResultListBox.xaml | 2 +- Flow.Launcher/ViewModel/ResultsViewModel.cs | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index 072196605..2f9d06d81 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -9,7 +9,7 @@ d:DataContext="{d:DesignInstance vm:ResultsViewModel}" MaxHeight="{Binding MaxHeight}" SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" - SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}" + SelectedItem="{Binding SelectedItem, Mode=TwoWay}" HorizontalContentAlignment="Stretch" ItemsSource="{Binding Results}" Margin="{Binding Margin}" Visibility="{Binding Visbility}" diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 3a4b07fd6..384647395 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -144,11 +144,10 @@ namespace Flow.Launcher.ViewModel { // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow - if (Results.Count > 0) - SelectedIndex = 0; // update UI in one run, so it can avoid UI flickering Results.Update(newResults); + SelectedItem = newResults[0]; } if (Visbility != Visibility.Visible && Results.Count > 0) @@ -176,9 +175,11 @@ namespace Flow.Launcher.ViewModel { // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow - SelectedIndex = 0; Results.Update(newResults, token); + SelectedItem = newResults[0]; + + } switch (Visbility) @@ -321,13 +322,6 @@ namespace Flow.Launcher.ViewModel editTime++; return; } - else if (editTime < 15 || newItems.Count < 50) - { - ClearItems(); - AddRange(newItems); - editTime++; - return; - } Clear(); BulkAddRange(newItems); From a640eadf1b99fd53787a32c5b4921cac38870914 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 29 Nov 2020 14:56:08 +0800 Subject: [PATCH 053/267] Use List instead of ObservableCollection as base class for resultcollection for better customized control of event --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 62 +++++++++++---------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 384647395..6d476ec63 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -12,6 +12,7 @@ using System.Windows.Data; using System.Windows.Documents; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; +using Microsoft.FSharp.Control; namespace Flow.Launcher.ViewModel { @@ -177,6 +178,8 @@ namespace Flow.Launcher.ViewModel // fix selected index flow Results.Update(newResults, token); + if (token.IsCancellationRequested) + return; SelectedItem = newResults[0]; @@ -262,35 +265,33 @@ namespace Flow.Launcher.ViewModel } #endregion - public class ResultCollection : ObservableCollection + public class ResultCollection : List, INotifyCollectionChanged { - private bool _suppressNotification = false; + + public event NotifyCollectionChangedEventHandler CollectionChanged; private long editTime = 0; + // https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ - protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - if (!_suppressNotification) - base.OnCollectionChanged(e); + if (CollectionChanged != null && CollectionChanged.GetInvocationList().Length == 1) + CollectionChanged.Invoke(this, e); } - public void BulkAddRange(IEnumerable resultViews) + public void BulkAddRange(IEnumerable resultViews, CancellationToken? token) { - _suppressNotification = true; - foreach (var item in resultViews) - { - Add(item); - } - _suppressNotification = false; + AddRange(resultViews); OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - public void AddRange(IEnumerable Items) + public void AddAll(IEnumerable Items, CancellationToken? token) { foreach (var item in Items) { + if (token?.IsCancellationRequested ?? false) return; Add(item); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } // wpf use directx / double buffered already, so just reset all won't cause ui flickering @@ -299,33 +300,34 @@ namespace Flow.Launcher.ViewModel } public void RemoveAll() { - ClearItems(); + Clear(); + OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } /// /// Update the results collection with new results, try to keep identical results /// - /// - public void Update(List newItems, CancellationToken token) + /// New Items to add into the list view + /// Cancellation Token + public void Update(List newItems, CancellationToken? token = null) { - - if (token.IsCancellationRequested) + if (newItems.Count == 0 || (token?.IsCancellationRequested ?? false)) return; - Update(newItems); - } + - public void Update(List newItems) - { - if (editTime == 0) + if (editTime < 5 || newItems.Count < 30) { - AddRange(newItems); + if (Count > 0) RemoveAll(); + if (token?.IsCancellationRequested ?? false) return; + AddAll(newItems, token); + editTime++; + } + else + { + Clear(); + BulkAddRange(newItems, token); editTime++; - return; } - Clear(); - - BulkAddRange(newItems); - editTime++; } } From c1ca76dd15800ad72f540cffc521a9790493288d Mon Sep 17 00:00:00 2001 From: YFdyh000 Date: Sun, 29 Nov 2020 16:11:58 +0800 Subject: [PATCH 054/267] fix tray menu translation --- Flow.Launcher/MainWindow.xaml.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 2c0beaaab..28ad80603 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -53,11 +53,12 @@ namespace Flow.Launcher private void OnInitialized(object sender, EventArgs e) { // show notify icon when flowlauncher is hided - InitializeNotifyIcon(); } private void OnLoaded(object sender, RoutedEventArgs _) { + InitializeNotifyIcon(); + // todo is there a way to set blur only once? ThemeManager.Instance.SetBlurForWindow(); WindowsInteropHelper.DisableControlBox(this); From 9bc89ea2784384ea9755ffde4acfd148a9ea36b7 Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 29 Nov 2020 17:01:51 +0800 Subject: [PATCH 055/267] :see_no_evil: ignore some files/folders --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 28366cd03..a293100e6 100644 --- a/.gitignore +++ b/.gitignore @@ -300,4 +300,8 @@ migrateToAutomaticPackageRestore.ps1 *.pyc *.diagsession Output-Performance.txt -*.diff \ No newline at end of file +*.diff + +# vscode +.vscode +.history \ No newline at end of file From 835b9214af0d17137fb7ac3613f2197834ec35ac Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 29 Nov 2020 17:09:27 +0800 Subject: [PATCH 056/267] :art: :recycle: format & rebuild json rpc python script - :art: format source via formatter - :recycle: more informations see https://github.com/Flow-Launcher/Flow.Launcher.JsonRPC.Python --- JsonRPC/wox.py | 115 ------------------------------------------------- README.md | 24 ++++++----- 2 files changed, 14 insertions(+), 125 deletions(-) delete mode 100644 JsonRPC/wox.py diff --git a/JsonRPC/wox.py b/JsonRPC/wox.py deleted file mode 100644 index 1beaa1d7e..000000000 --- a/JsonRPC/wox.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import print_function -import json -import sys -import inspect - -class FlowLauncher(object): - """ - Flow.Launcher python plugin base - """ - - def __init__(self): - rpc_request = json.loads(sys.argv[1]) - # proxy is not working now - self.proxy = rpc_request.get("proxy",{}) - request_method_name = rpc_request.get("method") - request_parameters = rpc_request.get("parameters") - methods = inspect.getmembers(self, predicate=inspect.ismethod) - - request_method = dict(methods)[request_method_name] - results = request_method(*request_parameters) - - if request_method_name == "query" or request_method_name == "context_menu": - print(json.dumps({"result": results})) - - def query(self,query): - """ - sub class need to override this method - """ - return [] - - def context_menu(self, data): - """ - optional context menu entries for a result - """ - return [] - - def debug(self,msg): - """ - alert msg - """ - print("DEBUG:{}".format(msg)) - sys.exit() - -class FlowLauncherAPI(object): - - @classmethod - def change_query(cls,query,requery = False): - """ - change flowlauncher query - """ - print(json.dumps({"method": "Flow.Launcher.ChangeQuery","parameters":[query,requery]})) - - @classmethod - def shell_run(cls,cmd): - """ - run shell commands - """ - print(json.dumps({"method": "Flow.Launcher.ShellRun","parameters":[cmd]})) - - @classmethod - def close_app(cls): - """ - close flowlauncher - """ - print(json.dumps({"method": "Flow.Launcher.CloseApp","parameters":[]})) - - @classmethod - def hide_app(cls): - """ - hide flowlauncher - """ - print(json.dumps({"method": "Flow.Launcher.HideApp","parameters":[]})) - - @classmethod - def show_app(cls): - """ - show flowlauncher - """ - print(json.dumps({"method": "Flow.Launcher.ShowApp","parameters":[]})) - - @classmethod - def show_msg(cls,title,sub_title,ico_path=""): - """ - show messagebox - """ - print(json.dumps({"method": "Flow.Launcher.ShowMsg","parameters":[title,sub_title,ico_path]})) - - @classmethod - def open_setting_dialog(cls): - """ - open setting dialog - """ - print(json.dumps({"method": "Flow.Launcher.OpenSettingDialog","parameters":[]})) - - @classmethod - def start_loadingbar(cls): - """ - start loading animation in flowlauncher - """ - print(json.dumps({"method": "Flow.Launcher.StartLoadingBar","parameters":[]})) - - @classmethod - def stop_loadingbar(cls): - """ - stop loading animation in flowlauncher - """ - print(json.dumps({"method": "Flow.Launcher.StopLoadingBar","parameters":[]})) - - @classmethod - def reload_plugins(cls): - """ - reload all flowlauncher plugins - """ - print(json.dumps({"method": "Flow.Launcher.ReloadPlugins","parameters":[]})) diff --git a/README.md b/README.md index d7f8dd7ba..94d59bb93 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be ![The Flow](https://user-images.githubusercontent.com/26427004/82151677-fa9c7100-989f-11ea-9143-81de60aaf07d.gif) - Search everything from applications, files, bookmarks, YouTube, Twitter and more. All from the comfort of your keyboard without ever touching the mouse. -- Search for file contents +- Search for file contents. - Support search using environment variable paths - Run batch and PowerShell commands as Administrator or a different user. - Support languages from Chinese to Italian and more. @@ -26,20 +26,24 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be ## Running Flow Launcher -| [Windows 7 and up](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) -| ------------- | +| [Windows 7 and up](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) | +| ---------------------------------------------------------------------------------- | Windows may complain about security due to code not being signed, this will be completed at a later stage. If you downloaded from this repo, you are good to continue the set up. -**Integrations:** - - If you use python plugins, install [python3](https://www.python.org/downloads/): `.exe` installer + add it to `%PATH%` or set it in flow's settings - - Flow searches files and contents via Windows Index Search, to use Everything, download the plugin [here](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.Everything/releases/latest) +**Integrations** + - If you use Python plugins: + - Install [Python3](https://www.python.org/downloads/), download `.exe` installer. + - Add Python to `%PATH%` or set it in flow's settings. + - Use `pip` to install `flowlauncher`, cmd in `pip install flowlauncher`. + - Start to launch your Python plugins. + - Flow searches files and contents via Windows Index Search, to use Everything, download the plugin [here](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.Everything/releases/latest). **Usage** -- 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 +- 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. - Saved user settings are located: - If using roaming: `%APPDATA%\FlowLauncher` - If using portable, by default: `%localappdata%\FlowLauncher\app-\UserData` From 5a9c631577cba212869cd6388fba57cd084f7dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 29 Nov 2020 20:50:28 +0800 Subject: [PATCH 057/267] Use PropertyChange event to change text when language has changed. --- .../Resource/Internationalization.cs | 3 ++- .../UserSettings/Settings.cs | 10 ++++++- Flow.Launcher/MainWindow.xaml.cs | 27 ++++++++++++++++--- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 1df6f2a04..9c5bb9cc3 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Windows; +using Flow.Launcher; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; @@ -88,7 +89,6 @@ namespace Flow.Launcher.Core.Resource { language = language.NonNull(); - Settings.Language = language.LanguageCode; RemoveOldLanguageFiles(); if (language != AvailableLanguages.English) @@ -96,6 +96,7 @@ namespace Flow.Launcher.Core.Resource LoadLanguage(language); } UpdatePluginMetadataTranslations(); + Settings.Language = language.LanguageCode; } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 837fe3b71..832b6fbfa 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -9,10 +9,18 @@ namespace Flow.Launcher.Infrastructure.UserSettings { public class Settings : BaseModel { + private string language = "en"; + public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}"; public string OpenResultModifiers { get; set; } = KeyConstant.Alt; public bool ShowOpenResultHotkey { get; set; } = true; - public string Language { get; set; } = "en"; + public string Language + { + get => language; set { + language = value; + OnPropertyChanged(); + } + } public string Theme { get; set; } = Constant.DefaultTheme; public bool UseDropShadowEffect { get; set; } = false; public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name; diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 28ad80603..558388762 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -52,11 +52,12 @@ namespace Flow.Launcher private void OnInitialized(object sender, EventArgs e) { - // show notify icon when flowlauncher is hided + } private void OnLoaded(object sender, RoutedEventArgs _) { + // show notify icon when flowlauncher is hidden InitializeNotifyIcon(); // todo is there a way to set blur only once? @@ -88,11 +89,19 @@ namespace Flow.Launcher }; _settings.PropertyChanged += (o, e) => { - if (e.PropertyName == nameof(Settings.HideNotifyIcon)) + switch (e.PropertyName) { - _notifyIcon.Visible = !_settings.HideNotifyIcon; + case nameof(Settings.HideNotifyIcon): + _notifyIcon.Visible = !_settings.HideNotifyIcon; + break; + case nameof(Settings.Language): + UpdateNotifyIconText(); + break; } }; + + + InitializePosition(); } @@ -104,6 +113,18 @@ namespace Flow.Launcher _settings.WindowLeft = Left; } + private void UpdateNotifyIconText() + { + var menu = _notifyIcon.ContextMenuStrip; + var open = menu.Items[0]; + var setting = menu.Items[1]; + var exit = menu.Items[2]; + + open.Text = InternationalizationManager.Instance.GetTranslation("iconTrayOpen"); + setting.Text = InternationalizationManager.Instance.GetTranslation("iconTraySettings"); + exit.Text = InternationalizationManager.Instance.GetTranslation("iconTrayExit"); + } + private void InitializeNotifyIcon() { _notifyIcon = new NotifyIcon From ac6dea1322a319e282c4233449ca02e0507d510a Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 30 Nov 2020 07:31:38 +1100 Subject: [PATCH 058/267] clear whitespaces, no code changes --- Flow.Launcher.Core/Resource/Internationalization.cs | 1 - Flow.Launcher/MainWindow.xaml.cs | 5 ----- 2 files changed, 6 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 9c5bb9cc3..64b949cbb 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -4,7 +4,6 @@ using System.IO; using System.Linq; using System.Reflection; using System.Windows; -using Flow.Launcher; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 558388762..993eb76c5 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -100,8 +100,6 @@ namespace Flow.Launcher } }; - - InitializePosition(); } @@ -201,7 +199,6 @@ namespace Flow.Launcher } } - private void OnDrop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) @@ -316,7 +313,5 @@ namespace Flow.Launcher _viewModel.QueryTextCursorMovedToEnd = false; } } - - } } \ No newline at end of file From e11daa0867ea6fdf75fb1a793d4338fd03f52db1 Mon Sep 17 00:00:00 2001 From: Zero Date: Mon, 30 Nov 2020 09:52:25 +0800 Subject: [PATCH 059/267] Update LICENSE --- LICENSE | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index cb4b563c0..0b9ce01e4 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,44 @@ +FlowLauncher are licensed under the terms of the MIT license, reproduced below. + + +A. HISTORY OF THE SOFTWARE +========================== + +- Copyright (c) 2015-2019 Wox. All rights reserved. +- Copyright (c) 2019-2020+ Flow-Launcher. All rights reserved. + + +B. FlowLauncher LICENSE +========================== + The MIT License (MIT) -Copyright (c) 2015 Wox +Copyright (c) 2019-2020+ Flow-Launcher. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +C. Wox LICENSE +========================== + +The MIT License (MIT) + +Copyright (c) 2020 Wox https://github.com/Wox-launcher/Wox Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 1ddf83fc86d4b9a54ed93fdc8f5a359f8fb0e0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 30 Nov 2020 11:33:31 +0800 Subject: [PATCH 060/267] Update to DotNet5 --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 4 ++-- .../Flow.Launcher.Infrastructure.csproj | 5 ++--- Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 6 +++--- Flow.Launcher.Test/Flow.Launcher.Test.csproj | 3 +-- Flow.Launcher/Flow.Launcher.csproj | 4 ++-- .../NetCore3.1-SelfContained.pubxml | 2 +- .../Flow.Launcher.Plugin.BrowserBookmark.csproj | 14 ++++---------- .../Flow.Launcher.Plugin.Calculator.csproj | 4 ++-- .../Flow.Launcher.Plugin.Color.csproj | 4 ++-- .../Flow.Launcher.Plugin.ControlPanel.csproj | 4 ++-- .../Flow.Launcher.Plugin.Explorer.csproj | 4 ++-- .../Flow.Launcher.Plugin.PluginIndicator.csproj | 4 ++-- .../Flow.Launcher.Plugin.PluginManagement.csproj | 4 ++-- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +- .../Flow.Launcher.Plugin.Program.csproj | 5 ++--- .../Flow.Launcher.Plugin.Shell.csproj | 5 ++--- .../Flow.Launcher.Plugin.Sys.csproj | 4 ++-- .../Flow.Launcher.Plugin.Url.csproj | 4 ++-- .../Flow.Launcher.Plugin.WebSearch.csproj | 14 +++----------- Scripts/flowlauncher.nuspec | 2 +- global.json | 2 +- 21 files changed, 41 insertions(+), 59 deletions(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 9f146a457..370f2015b 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -1,7 +1,7 @@ - + - netcoreapp3.1 + net5.0-windows true true Library diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 28d4c0e1f..48d9486cf 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -1,7 +1,6 @@ - - + - netcoreapp3.1 + net5.0-windows {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} Library true diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 0f6450d18..38ae6898f 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -1,7 +1,7 @@ - - + + - netcoreapp3.1 + net5.0-windows {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} true Library diff --git a/Flow.Launcher.Test/Flow.Launcher.Test.csproj b/Flow.Launcher.Test/Flow.Launcher.Test.csproj index e970c47b9..fb972d7d4 100644 --- a/Flow.Launcher.Test/Flow.Launcher.Test.csproj +++ b/Flow.Launcher.Test/Flow.Launcher.Test.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0-windows10.0.19041.0 {FF742965-9A80-41A5-B042-D6C7D3A21708} Library Properties @@ -54,7 +54,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - \ No newline at end of file diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 8548ba39e..f959f3aa1 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -1,8 +1,8 @@ - + WinExe - netcoreapp3.1 + net5.0-windows10.0.19041.0 true true Flow.Launcher.App diff --git a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml index 2794a0cea..cad0fd462 100644 --- a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml @@ -7,7 +7,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. FileSystem Release Any CPU - netcoreapp3.1 + net5.0-windows ..\Output\Release\ win-x64 true 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..ee78f78c4 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -1,8 +1,9 @@ - + Library - netcoreapp3.1 + net5.0-windows + true {9B130CC5-14FB-41FF-B310-0A95B6894C37} Properties Flow.Launcher.Plugin.BrowserBookmark @@ -68,14 +69,7 @@ PreserveNewest - - - - MSBuild:Compile - Designer - - - + 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..bc637be54 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {59BD9891-3837-438A-958D-ADC7F91F6F7E} Properties Flow.Launcher.Plugin.Caculator diff --git a/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj b/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj index c7fe8271a..18f81e3ff 100644 --- a/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj +++ b/Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {F35190AA-4758-4D9E-A193-E3BDF6AD3567} Properties Flow.Launcher.Plugin.Color 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..be62c31cd 100644 --- a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj +++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} Properties Flow.Launcher.Plugin.ControlPanel 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..99e9c784b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows true true true 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..a904a9272 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {FDED22C8-B637-42E8-824A-63B5B6E05A3A} Properties Flow.Launcher.Plugin.PluginIndicator diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj b/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj index 08e89d861..4a5df0b3a 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {049490F0-ECD2-4148-9B39-2135EC346EBE} Properties Flow.Launcher.Plugin.PluginManagement 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..1aef8f58e 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -2,7 +2,7 @@ Library - netcoreapp3.1 + net5.0-windows Flow.Launcher.Plugin.ProcessKiller Flow.Launcher.Plugin.ProcessKiller Flow-Launcher 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 3802297c7..61d8b7b6c 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows10.0.19041.0 {FDB3555B-58EF-4AE6-B5F1-904719637AB4} Properties Flow.Launcher.Plugin.Program @@ -109,7 +109,6 @@ - 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..12ee6833e 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -1,8 +1,7 @@ - - + Library - netcoreapp3.1 + net5.0-windows {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} Properties Flow.Launcher.Plugin.Shell 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..6618ca775 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} Properties Flow.Launcher.Plugin.Sys 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..d5a056825 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj +++ b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj @@ -1,8 +1,8 @@ - + Library - netcoreapp3.1 + net5.0-windows {A3DCCBCA-ACC1-421D-B16E-210896234C26} true Properties 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..ed2c5107c 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj @@ -1,8 +1,8 @@ - - + Library - netcoreapp3.1 + net5.0-windows + true {403B57F2-1856-4FC7-8A24-36AB346B763E} Properties Flow.Launcher.Plugin.WebSearch @@ -119,14 +119,6 @@ Designer PreserveNewest - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - diff --git a/Scripts/flowlauncher.nuspec b/Scripts/flowlauncher.nuspec index 6c5deb86b..f1f58f2d1 100644 --- a/Scripts/flowlauncher.nuspec +++ b/Scripts/flowlauncher.nuspec @@ -11,6 +11,6 @@ Flow Launcher - a launcher for windows - + diff --git a/global.json b/global.json index c3efffd40..2ad4d9100 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.201", + "version": "5.0.100", "rollForward": "latestFeature" } } \ No newline at end of file From 3607bfde078af0f08dc4666fa1adede255e26f30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 1 Dec 2020 10:37:05 +0800 Subject: [PATCH 061/267] Change name for publish file --- .../NetCore3.1-SelfContained.pubxml | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml diff --git a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml deleted file mode 100644 index cad0fd462..000000000 --- a/Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - FileSystem - Release - Any CPU - net5.0-windows - ..\Output\Release\ - win-x64 - true - False - False - False - - \ No newline at end of file From e973e1d0bb6b97c4e86fcac380b536bfc9464fcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 2 Dec 2020 13:26:05 +0800 Subject: [PATCH 062/267] Update ModernWPF so that the app can run --- Flow.Launcher/Flow.Launcher.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index f959f3aa1..2f58abab0 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -72,7 +72,7 @@ - + all From 19c7446552f6242cc43981948ea5eb24783f5dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 2 Dec 2020 13:56:50 +0800 Subject: [PATCH 063/267] Add Lock to the place we directly update the ResultCollection --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 6d476ec63..d373b0fda 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -120,17 +120,20 @@ namespace Flow.Launcher.ViewModel public void Clear() { - Results.RemoveAll(); + lock (_collectionLock) + Results.RemoveAll(); } public void KeepResultsFor(PluginMetadata metadata) { - Results.Update(Results.Where(r => r.Result.PluginID == metadata.ID).ToList()); + lock (_collectionLock) + Results.Update(Results.Where(r => r.Result.PluginID == metadata.ID).ToList()); } public void KeepResultsExcept(PluginMetadata metadata) { - Results.Update(Results.Where(r => r.Result.PluginID != metadata.ID).ToList()); + lock (_collectionLock) + Results.Update(Results.Where(r => r.Result.PluginID != metadata.ID).ToList()); } @@ -148,7 +151,8 @@ namespace Flow.Launcher.ViewModel // update UI in one run, so it can avoid UI flickering Results.Update(newResults); - SelectedItem = newResults[0]; + if (newResults.Any()) + SelectedItem = newResults[0]; } if (Visbility != Visibility.Visible && Results.Count > 0) @@ -304,6 +308,9 @@ namespace Flow.Launcher.ViewModel OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } + + + /// /// Update the results collection with new results, try to keep identical results /// @@ -311,9 +318,9 @@ namespace Flow.Launcher.ViewModel /// Cancellation Token public void Update(List newItems, CancellationToken? token = null) { - if (newItems.Count == 0 || (token?.IsCancellationRequested ?? false)) + if (token?.IsCancellationRequested ?? false) return; - + if (editTime < 5 || newItems.Count < 30) { From 98e6a1ab8a203201d08de9a8f1bc5273c81a7789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 2 Dec 2020 20:57:23 +0800 Subject: [PATCH 064/267] Revert using List instead of observablecollection --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 66 ++++++++++----------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index d373b0fda..5a9043c23 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -12,7 +12,6 @@ using System.Windows.Data; using System.Windows.Documents; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; -using Microsoft.FSharp.Control; namespace Flow.Launcher.ViewModel { @@ -182,8 +181,6 @@ namespace Flow.Launcher.ViewModel // fix selected index flow Results.Update(newResults, token); - if (token.IsCancellationRequested) - return; SelectedItem = newResults[0]; @@ -269,33 +266,35 @@ namespace Flow.Launcher.ViewModel } #endregion - public class ResultCollection : List, INotifyCollectionChanged + public class ResultCollection : ObservableCollection { - - public event NotifyCollectionChangedEventHandler CollectionChanged; + private bool _suppressNotification = false; private long editTime = 0; - // https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ - protected void OnCollectionChanged(NotifyCollectionChangedEventArgs e) + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - if (CollectionChanged != null && CollectionChanged.GetInvocationList().Length == 1) - CollectionChanged.Invoke(this, e); + if (!_suppressNotification) + base.OnCollectionChanged(e); } - public void BulkAddRange(IEnumerable resultViews, CancellationToken? token) + public void BulkAddRange(IEnumerable resultViews) { - AddRange(resultViews); + _suppressNotification = true; + foreach (var item in resultViews) + { + Add(item); + } + _suppressNotification = false; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } - public void AddAll(IEnumerable Items, CancellationToken? token) + public void AddRange(IEnumerable Items) { foreach (var item in Items) { - if (token?.IsCancellationRequested ?? false) return; Add(item); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); } // wpf use directx / double buffered already, so just reset all won't cause ui flickering @@ -304,8 +303,7 @@ namespace Flow.Launcher.ViewModel } public void RemoveAll() { - Clear(); - OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + ClearItems(); } @@ -314,27 +312,27 @@ namespace Flow.Launcher.ViewModel /// /// Update the results collection with new results, try to keep identical results /// - /// New Items to add into the list view - /// Cancellation Token - public void Update(List newItems, CancellationToken? token = null) + /// + public void Update(List newItems, CancellationToken token) { - if (token?.IsCancellationRequested ?? false) + + if (token.IsCancellationRequested) return; + Update(newItems); + } + public void Update(List newItems) + { + if (editTime == 0) + { + AddRange(newItems); + editTime++; + return; + } + Clear(); - if (editTime < 5 || newItems.Count < 30) - { - if (Count > 0) RemoveAll(); - if (token?.IsCancellationRequested ?? false) return; - AddAll(newItems, token); - editTime++; - } - else - { - Clear(); - BulkAddRange(newItems, token); - editTime++; - } + BulkAddRange(newItems); + editTime++; } } From e7dd8676ec247f3a670867f4cb75a4263228cb4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 2 Dec 2020 23:37:23 +0800 Subject: [PATCH 065/267] Change some code and check out what cause those error --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 65 ++++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 5a9043c23..e05e3c153 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -141,17 +141,18 @@ namespace Flow.Launcher.ViewModel /// public void AddResults(List newRawResults, string resultId) { - var newResults = NewResults(newRawResults, resultId); lock (_collectionLock) { + var newResults = NewResults(newRawResults, resultId); + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow // update UI in one run, so it can avoid UI flickering Results.Update(newResults); - if (newResults.Any()) - SelectedItem = newResults[0]; + if (Results.Any()) + SelectedItem = Results[0]; } if (Visbility != Visibility.Visible && Results.Count > 0) @@ -171,17 +172,20 @@ namespace Flow.Launcher.ViewModel /// public void AddResults(IEnumerable resultsForUpdates, CancellationToken token) { - var newResults = NewResults(resultsForUpdates); - if (token.IsCancellationRequested) - return; - lock (_collectionLock) { + var newResults = NewResults(resultsForUpdates); + if (token.IsCancellationRequested) + return; + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow Results.Update(newResults, token); - SelectedItem = newResults[0]; + if (token.IsCancellationRequested) + return; + if (Results.Any()) + SelectedItem = Results[0]; } @@ -268,33 +272,38 @@ namespace Flow.Launcher.ViewModel public class ResultCollection : ObservableCollection { - private bool _suppressNotification = false; private long editTime = 0; - // https://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/ + private bool _suppressNotifying = false; + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - if (!_suppressNotification) - base.OnCollectionChanged(e); + if (_suppressNotifying) + return; + base.OnCollectionChanged(e); } public void BulkAddRange(IEnumerable resultViews) { - _suppressNotification = true; + _suppressNotifying = true; + foreach (var item in resultViews) { Add(item); } - _suppressNotification = false; + _suppressNotifying = false; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); - } - public void AddRange(IEnumerable Items) + public void AddRange(IEnumerable Items, CancellationToken? token) { foreach (var item in Items) { + if (token?.IsCancellationRequested ?? false) + return; + Add(item); + } // wpf use directx / double buffered already, so just reset all won't cause ui flickering @@ -313,27 +322,25 @@ namespace Flow.Launcher.ViewModel /// Update the results collection with new results, try to keep identical results /// /// - public void Update(List newItems, CancellationToken token) + public void Update(List newItems, CancellationToken? token = null) { - if (token.IsCancellationRequested) + if (token?.IsCancellationRequested ?? false) return; - Update(newItems); - } - public void Update(List newItems) - { - if (editTime == 0) + if (editTime < 5 || newItems.Count < 30) { - AddRange(newItems); + if (Count != 0) ClearItems(); + AddRange(newItems, token); editTime++; return; } - Clear(); - - BulkAddRange(newItems); - editTime++; - + else + { + Clear(); + BulkAddRange(newItems); + editTime++; + } } } } From 25bc2a70e3091de08f1a4a74050151c008c97bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 3 Dec 2020 10:33:19 +0800 Subject: [PATCH 066/267] Add timeout for waiting collectionchange event, although seems the deadlock isn't caused by this. --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 51 ++++++++++++--------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index e05e3c153..40021690b 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -6,10 +6,12 @@ using System.ComponentModel; using System.Configuration; using System.Linq; using System.Threading; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; +using System.Windows.Forms; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; @@ -172,12 +174,11 @@ namespace Flow.Launcher.ViewModel /// public void AddResults(IEnumerable resultsForUpdates, CancellationToken token) { + var newResults = NewResults(resultsForUpdates); + if (token.IsCancellationRequested) + return; lock (_collectionLock) { - var newResults = NewResults(resultsForUpdates); - if (token.IsCancellationRequested) - return; - // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow @@ -186,8 +187,6 @@ namespace Flow.Launcher.ViewModel return; if (Results.Any()) SelectedItem = Results[0]; - - } switch (Visbility) @@ -277,38 +276,46 @@ namespace Flow.Launcher.ViewModel private bool _suppressNotifying = false; + private CancellationToken _token; + protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) { - if (_suppressNotifying) - return; - base.OnCollectionChanged(e); + if (!_suppressNotifying) + { + var notifyChangeTask = Task.Run(() => base.OnCollectionChanged(e)); + if (notifyChangeTask.Wait(300)) + return; + else + { + notifyChangeTask.Dispose(); + throw new TimeoutException(); + } + } } public void BulkAddRange(IEnumerable resultViews) { + // suppress notifying before adding all element _suppressNotifying = true; - foreach (var item in resultViews) { Add(item); } _suppressNotifying = false; + // manually update event + // wpf use directx / double buffered already, so just reset all won't cause ui flickering + if (_token.IsCancellationRequested) + return; OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } - public void AddRange(IEnumerable Items, CancellationToken? token) + public void AddRange(IEnumerable Items) { foreach (var item in Items) { - if (token?.IsCancellationRequested ?? false) + if (_token.IsCancellationRequested) return; - Add(item); - } - - // wpf use directx / double buffered already, so just reset all won't cause ui flickering - return; - } public void RemoveAll() { @@ -322,16 +329,16 @@ namespace Flow.Launcher.ViewModel /// Update the results collection with new results, try to keep identical results /// /// - public void Update(List newItems, CancellationToken? token = null) + public void Update(List newItems, CancellationToken token = default) { - - if (token?.IsCancellationRequested ?? false) + _token = token; + if (_token.IsCancellationRequested) return; if (editTime < 5 || newItems.Count < 30) { if (Count != 0) ClearItems(); - AddRange(newItems, token); + AddRange(newItems); editTime++; return; } From eb13a18d52d1e0659e8896d3bfc4dc3961fad445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 3 Dec 2020 15:38:00 +0800 Subject: [PATCH 067/267] Use task.run in addresult instead of CollectionChange event. --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 45 +++++++++++++-------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 40021690b..924fd7ffc 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -150,11 +150,20 @@ namespace Flow.Launcher.ViewModel // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow + var updateTask = Task.Run(() => + { + // update UI in one run, so it can avoid UI flickering + + Results.Update(newResults); + if (Results.Any()) + SelectedItem = Results[0]; + }); + if (!updateTask.Wait(300)) + { + updateTask.Dispose(); + throw new TimeoutException("Update result use too much time."); + } - // update UI in one run, so it can avoid UI flickering - Results.Update(newResults); - if (Results.Any()) - SelectedItem = Results[0]; } if (Visbility != Visibility.Visible && Results.Count > 0) @@ -179,14 +188,23 @@ namespace Flow.Launcher.ViewModel return; lock (_collectionLock) { + // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf // fix selected index flow + var updateTask = Task.Run(() => + { + // update UI in one run, so it can avoid UI flickering + + Results.Update(newResults, token); + if (Results.Any()) + SelectedItem = Results[0]; + }); + if (!updateTask.Wait(300)) + { + updateTask.Dispose(); + throw new TimeoutException("Update result use too much time."); + } - Results.Update(newResults, token); - if (token.IsCancellationRequested) - return; - if (Results.Any()) - SelectedItem = Results[0]; } switch (Visbility) @@ -282,14 +300,7 @@ namespace Flow.Launcher.ViewModel { if (!_suppressNotifying) { - var notifyChangeTask = Task.Run(() => base.OnCollectionChanged(e)); - if (notifyChangeTask.Wait(300)) - return; - else - { - notifyChangeTask.Dispose(); - throw new TimeoutException(); - } + base.OnCollectionChanged(e); } } From 01158fdc66bff9b8a64ff132e50807d4e317cc95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 21:53:34 +0800 Subject: [PATCH 068/267] Add error handling for the resultUpdateTask to make sure result update can continue when error throw. --- Flow.Launcher/ViewModel/MainViewModel.cs | 41 ++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 9316cd62e..dd790a98b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -24,6 +24,7 @@ using Flow.Launcher.Infrastructure.Image; using System.Collections.Concurrent; using Flow.Launcher.Infrastructure.Logger; using System.Threading.Tasks.Dataflow; +using NLog; namespace Flow.Launcher.ViewModel { @@ -51,6 +52,7 @@ namespace Flow.Launcher.ViewModel private readonly Internationalization _translator = InternationalizationManager.Instance; private BufferBlock _resultsUpdateQueue; + private Task _resultsViewUpdateTask; #endregion @@ -80,7 +82,7 @@ namespace Flow.Launcher.ViewModel InitializeKeyCommands(); - RegisterResultUpdate(); + RegisterViewUpdate(); RegisterResultsUpdatedEvent(); @@ -103,20 +105,31 @@ namespace Flow.Launcher.ViewModel } } - private void RegisterResultUpdate() + private void RegisterViewUpdate() { _resultsUpdateQueue = new BufferBlock(); + _resultsViewUpdateTask = Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted); - Task.Run(async () => + + async Task updateAction() { while (await _resultsUpdateQueue.OutputAvailableAsync()) { await Task.Delay(20); _resultsUpdateQueue.TryReceiveAll(out var queue); UpdateResultView(queue.Where(r => !r.Token.IsCancellationRequested)); - } - }); + }; + + void continueAction(Task t) + { +#if DEBUG + throw t.Exception; +#else + Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}"); + _resultsViewUpdateTask = Task.Run(updateAction).ContinueWith(continuationAction, TaskContinuationOptions.OnlyOnFaulted); +#endif + } } @@ -707,7 +720,23 @@ namespace Flow.Launcher.ViewModel { if (!resultsForUpdates.Any()) return; - CancellationToken token = resultsForUpdates.Select(r => r.Token).Distinct().Single(); + CancellationToken token; + + try + { + token = resultsForUpdates.Select(r => r.Token).Distinct().Single(); + } +#if DEBUG + catch + { + throw new ArgumentException("Unacceptable token"); + } +#else + catch + { + + } +#endif foreach (var result in resultsForUpdates.SelectMany(u => u.Results)) From aa20d505fe5b42fe198461fa7f77513ec9e36138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 21:54:22 +0800 Subject: [PATCH 069/267] Revert creating a new task when adding result. --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index 924fd7ffc..f12ea23e9 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -188,22 +188,12 @@ namespace Flow.Launcher.ViewModel return; lock (_collectionLock) { + // update UI in one run, so it can avoid UI flickering - // https://social.msdn.microsoft.com/Forums/vstudio/en-US/5ff71969-f183-4744-909d-50f7cd414954/binding-a-tabcontrols-selectedindex-not-working?forum=wpf - // fix selected index flow - var updateTask = Task.Run(() => - { - // update UI in one run, so it can avoid UI flickering + Results.Update(newResults, token); + if (Results.Any()) + SelectedItem = Results[0]; - Results.Update(newResults, token); - if (Results.Any()) - SelectedItem = Results[0]; - }); - if (!updateTask.Wait(300)) - { - updateTask.Dispose(); - throw new TimeoutException("Update result use too much time."); - } } From 6267fa9a50f9454e9bdd85ed3dc4015f95822874 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 22:18:51 +0800 Subject: [PATCH 070/267] fix typo. --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index dd790a98b..3e1580e38 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -127,7 +127,7 @@ namespace Flow.Launcher.ViewModel throw t.Exception; #else Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}"); - _resultsViewUpdateTask = Task.Run(updateAction).ContinueWith(continuationAction, TaskContinuationOptions.OnlyOnFaulted); + _resultsViewUpdateTask = Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted); #endif } } From c3d5d4c0cecddc41a5fcdf7b18c1ccd7de87df84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 22:24:25 +0800 Subject: [PATCH 071/267] Don't update collection when both newItems and collection is empty --- Flow.Launcher/ViewModel/ResultsViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index f12ea23e9..fc77327cc 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -333,7 +333,7 @@ namespace Flow.Launcher.ViewModel public void Update(List newItems, CancellationToken token = default) { _token = token; - if (_token.IsCancellationRequested) + if (Count == 0 && newItems.Count == 0 || _token.IsCancellationRequested) return; if (editTime < 5 || newItems.Count < 30) From 756c5bce3deb3af5df9e9554e930e20609083e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 22:30:14 +0800 Subject: [PATCH 072/267] fix using unintialized variable in release. --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 3e1580e38..1329421c3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -734,7 +734,7 @@ namespace Flow.Launcher.ViewModel #else catch { - + token = default; } #endif From 4ea40ab9aa7907b6648315cf42e4813b96df491d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 4 Dec 2020 22:46:23 +0800 Subject: [PATCH 073/267] Add the new publish profile file --- .../PublishProfiles/Net5-SelfContained.pubxml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml new file mode 100644 index 000000000..124792e3e --- /dev/null +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -0,0 +1,18 @@ + + + + + FileSystem + Release + Any CPU + net5.0-windows10.0.19041.0 + ..\Output\Release\ + win-x64 + true + False + False + False + + \ No newline at end of file From b8d3b42295d557784e5ab990a927e612f7fd4872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 5 Dec 2020 15:48:36 +0800 Subject: [PATCH 074/267] use singleordefault instead of single since sometims the queue may be empty but method doesn't return --- Flow.Launcher/ViewModel/MainViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 1329421c3..25768a25e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -724,7 +724,8 @@ namespace Flow.Launcher.ViewModel try { - token = resultsForUpdates.Select(r => r.Token).Distinct().Single(); + // Don't know why sometimes even resultsForUpdates is empty, the method won't return; + token = resultsForUpdates.Select(r => r.Token).Distinct().SingleOrDefault(); } #if DEBUG catch From a460aefa1f6faca89a47491c86598365a5c9ea1c Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 6 Dec 2020 19:58:27 +1100 Subject: [PATCH 075/267] add PluginsManager --- Flow.Launcher.sln | 16 +++++++ ...Flow.Launcher.Plugin.PluginsManager.csproj | 30 ++++++++++++ .../Main.cs | 10 ++++ .../Plugins.cs | 13 ++++++ .../PluginsManager.cs | 46 +++++++++++++++++++ .../PluginsManifest.cs | 35 ++++++++++++++ .../plugin.json | 14 ++++++ 7 files changed, 164 insertions(+) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/plugin.json diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln index 6196aa5df..22086b0bd 100644 --- a/Flow.Launcher.sln +++ b/Flow.Launcher.sln @@ -20,6 +20,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc {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} + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE} = {70CB72BC-1CD6-453D-9CA5-F7E2441426FE} {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} @@ -71,6 +72,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Explor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.ProcessKiller", "Plugins\Flow.Launcher.Plugin.ProcessKiller\Flow.Launcher.Plugin.ProcessKiller.csproj", "{588088F4-3262-4F9F-9663-A05DE12534C3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flow.Launcher.Plugin.PluginsManager", "Plugins\Flow.Launcher.Plugin.PluginManager\Flow.Launcher.Plugin.PluginsManager.csproj", "{70CB72BC-1CD6-453D-9CA5-F7E2441426FE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -298,6 +301,18 @@ Global {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x64.Build.0 = Release|Any CPU {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.ActiveCfg = Release|Any CPU {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.Build.0 = Release|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x64.ActiveCfg = Debug|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x64.Build.0 = Debug|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x86.ActiveCfg = Debug|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x86.Build.0 = Debug|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|Any CPU.Build.0 = Release|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x64.ActiveCfg = Release|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x64.Build.0 = Release|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x86.ActiveCfg = Release|Any CPU + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -316,6 +331,7 @@ Global {59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {588088F4-3262-4F9F-9663-A05DE12534C3} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {70CB72BC-1CD6-453D-9CA5-F7E2441426FE} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj new file mode 100644 index 000000000..b1d0c6f68 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -0,0 +1,30 @@ + + + + Library + netcoreapp3.1 + true + true + true + false + + + + ..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.PluginsManager + + + + ..\..\Output\Release\Plugins\Flow.Launcher.Plugin.PluginsManager + + + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs new file mode 100644 index 000000000..36e40bf1b --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + class Main + { + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs new file mode 100644 index 000000000..f6538b7ef --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + internal class Plugin + { + public string Name { get; set; } + public string Url { get; set; } + public string Version { get; set; } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs new file mode 100644 index 000000000..055e027ad --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -0,0 +1,46 @@ +using Flow.Launcher.Infrastructure.Http; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + internal class PluginsManager + { + internal void PluginInstall(Plugin plugin) + { + if (PluginExists()) + { + //prompt user if want to install + + return; + } + + PluginDowload(plugin.Url, ""); + } + + private void PluginDowload(string downloadUrl, string toFilePath) + { + using (var wc = new WebClient { Proxy = Http.WebProxy() }) + { + wc.DownloadFile(downloadUrl, toFilePath); + } + } + + internal void PluginUpdate() + { + + } + + internal bool PluginExists() + { + return false; + } + + internal void PluginsManifestSiteOpen() + { + + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs new file mode 100644 index 000000000..d470a996c --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs @@ -0,0 +1,35 @@ +using Flow.Launcher.Infrastructure.Http; +using Flow.Launcher.Infrastructure.Logger; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + class PluginsManifest + { + public List Plugins { get; private set; } + public PluginsManifest() + { + var json = string.Empty; + + using (var wc = new WebClient { Proxy = Http.WebProxy() }) + { + try + { + json = wc.DownloadString("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"); + } + catch (Exception e) + { + Log.Exception("|PluginManagement.GetManifest|Encountered error trying to download plugins manifest", e); + + Plugins = new List(); + } + } + + Plugins = !string.IsNullOrEmpty(json) ? JsonConvert.DeserializeObject>(json) : new List(); + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginManager/plugin.json new file mode 100644 index 000000000..327011ac3 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/plugin.json @@ -0,0 +1,14 @@ +{ + "ID": "9f8f9b14-2518-4907-b211-35ab6290dee7", + "ActionKeywords": [ + "pm" + ], + "Name": "Plugins Manager", + "Description": "Management of installing, uninstalling or updating Flow Launcher plugins", + "Author": "Jeremy Wu", + "Version": "1.0.0", + "Language": "csharp", + "Website": "https://github.com/Flow-Launcher/Flow.Launcher", + "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", + "IcoPath": "Images\\pluginsmanager.png" +} From 9ae9d69a570fa2073979b9dbeb31dc23112c5d07 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 6 Dec 2020 20:39:26 +1100 Subject: [PATCH 076/267] update Plugin json mapping --- .../Flow.Launcher.Plugin.PluginManager/Plugins.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs index f6538b7ef..56f01e86b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs @@ -6,8 +6,14 @@ namespace Flow.Launcher.Plugin.PluginsManager { internal class Plugin { - public string Name { get; set; } - public string Url { get; set; } - public string Version { get; set; } + internal string ID { get; set; } + internal string Name { get; set; } + internal string Description { get; set; } + internal string Author { get; set; } + internal string Version { get; set; } + internal string Language { get; set; } + internal string Website { get; set; } + internal string UrlDownload { get; set; } + internal string UrlSourceCode { get; set; } } } From cc1d049cad8efe8298e07aa6a094dbe2d773b0ce Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 6 Dec 2020 21:10:22 +1100 Subject: [PATCH 077/267] Plugins Manager scaffolding --- .../ContextMenu.cs | 29 ++++++++++ ...Flow.Launcher.Plugin.PluginsManager.csproj | 8 +++ .../Languages/en.xaml | 15 ++++++ .../Main.cs | 54 +++++++++++++++++-- .../{ => Models}/Plugins.cs | 2 +- .../{ => Models}/PluginsManifest.cs | 2 +- .../ViewModels/SettingsViewModel.cs | 26 +++++++++ .../Views/PluginsManagerSettings.xaml | 12 +++++ .../Views/PluginsManagerSettings.xaml.cs | 22 ++++++++ 9 files changed, 165 insertions(+), 5 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/ContextMenu.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml rename Plugins/Flow.Launcher.Plugin.PluginManager/{ => Models}/Plugins.cs (90%) rename Plugins/Flow.Launcher.Plugin.PluginManager/{ => Models}/PluginsManifest.cs (95%) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/ViewModels/SettingsViewModel.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/ContextMenu.cs new file mode 100644 index 000000000..d26c1ead4 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/ContextMenu.cs @@ -0,0 +1,29 @@ +using Flow.Launcher.Infrastructure.UserSettings; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + internal class ContextMenu : IContextMenu + { + private PluginInitContext Context { get; set; } + + private Settings Settings { get; set; } + + public ContextMenu(PluginInitContext context, Settings settings) + { + Context = context; + Settings = settings; + } + + public List LoadContextMenus(Result selectedResult) + { + // Open website + // Go to source code + // Report an issue? + // Request a feature? + return new List(); + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj index b1d0c6f68..43a1e089b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -27,4 +27,12 @@ PreserveNewest + + + + + + + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml new file mode 100644 index 000000000..75caf81ec --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml @@ -0,0 +1,15 @@ + + + + + + + + Plugins Manager + Management of installing, uninstalling or updating Flow Launcher plugins + + + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs index 36e40bf1b..73d3f954c 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs @@ -1,10 +1,58 @@ -using System; +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.Text; +using System.Windows.Controls; namespace Flow.Launcher.Plugin.PluginsManager { - class Main + public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n { + internal PluginInitContext Context { get; set; } + + internal Settings Settings; + + private SettingsViewModel viewModel; + + private IContextMenu contextMenu; + + public Control CreateSettingPanel() + { + return new PluginsManagerSettings(viewModel); + } + + public void Init(PluginInitContext context) + { + Context = context; + viewModel = new SettingsViewModel(context); + Settings = viewModel.Settings; + contextMenu = new ContextMenu(Context, Settings); + } + + public List LoadContextMenus(Result selectedResult) + { + return contextMenu.LoadContextMenus(selectedResult); + } + + public List Query(Query query) + { + return new List(); + } + + public void Save() + { + viewModel.Save(); + } + + public string GetTranslatedPluginTitle() + { + return Context.API.GetTranslation("plugin_pluginsmanager_plugin_name"); + } + + public string GetTranslatedPluginDescription() + { + return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description"); + } } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs similarity index 90% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs rename to Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs index 56f01e86b..d2f6348af 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Plugins.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Flow.Launcher.Plugin.PluginsManager +namespace Flow.Launcher.Plugin.PluginsManager.Models { internal class Plugin { diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs similarity index 95% rename from Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs rename to Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs index d470a996c..3609aba7d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Net; using System.Text; -namespace Flow.Launcher.Plugin.PluginsManager +namespace Flow.Launcher.Plugin.PluginsManager.Models { class PluginsManifest { diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/ViewModels/SettingsViewModel.cs new file mode 100644 index 000000000..f3cf117d3 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/ViewModels/SettingsViewModel.cs @@ -0,0 +1,26 @@ +using Flow.Launcher.Infrastructure.Storage; +using Flow.Launcher.Infrastructure.UserSettings; + +namespace Flow.Launcher.Plugin.PluginsManager.ViewModels +{ + public class SettingsViewModel + { + private readonly PluginJsonStorage storage; + + internal Settings Settings { get; set; } + + internal PluginInitContext Context { get; set; } + + public SettingsViewModel(PluginInitContext context) + { + Context = context; + storage = new PluginJsonStorage(); + Settings = storage.Load(); + } + + public void Save() + { + storage.Save(); + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml b/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml new file mode 100644 index 000000000..7f6d7ba82 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml @@ -0,0 +1,12 @@ + + + + + diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml.cs new file mode 100644 index 000000000..14204eda9 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml.cs @@ -0,0 +1,22 @@ + +using Flow.Launcher.Plugin.PluginsManager.ViewModels; + +namespace Flow.Launcher.Plugin.PluginsManager.Views +{ + /// + /// Interaction logic for PluginsManagerSettings.xaml + /// + public partial class PluginsManagerSettings + { + private readonly SettingsViewModel viewModel; + + public PluginsManagerSettings(SettingsViewModel viewModel) + { + InitializeComponent(); + + this.viewModel = viewModel; + + //RefreshView(); + } + } +} From 42f8bbe6972db523540ddd74a63533ba3b9250fc Mon Sep 17 00:00:00 2001 From: Zero Date: Sun, 6 Dec 2020 19:18:57 +0800 Subject: [PATCH 078/267] Update LICENSE --- LICENSE | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/LICENSE b/LICENSE index 0b9ce01e4..b4ba8d542 100644 --- a/LICENSE +++ b/LICENSE @@ -4,8 +4,15 @@ FlowLauncher are licensed under the terms of the MIT license, reproduced below. A. HISTORY OF THE SOFTWARE ========================== -- Copyright (c) 2015-2019 Wox. All rights reserved. -- Copyright (c) 2019-2020+ Flow-Launcher. All rights reserved. +- Copyright (c) 2015-2019 Wox +- Copyright (c) 2019-2020+ Flow-Launcher + +Flow's roots came from a rebrand of the JJW24/Wox fork and WoX. +A big thank you and all credits to Bao, the author of WoX, +and its contrbutors for all the amazing work. +The JJW24/Wox fork started adding new changes on top of +main WoX repo's code base from release v1.3.524. +Flow is a continuation of the work from JJW24/Wox B. FlowLauncher LICENSE @@ -13,7 +20,7 @@ B. FlowLauncher LICENSE The MIT License (MIT) -Copyright (c) 2019-2020+ Flow-Launcher. All rights reserved. +Copyright (c) 2019-2020+ Flow-Launcher Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -38,7 +45,7 @@ C. Wox LICENSE The MIT License (MIT) -Copyright (c) 2020 Wox https://github.com/Wox-launcher/Wox +Copyright (c) 2015 Wox Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 158701012623e0a95bf53638654609a4efc18164 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 7 Dec 2020 07:40:42 +1100 Subject: [PATCH 079/267] add plugin search --- .../Main.cs | 6 +- .../Models/Plugins.cs | 19 ------- .../Models/PluginsManifest.cs | 10 ++-- .../Models/UserPlugin.cs | 19 +++++++ .../PluginsManager.cs | 57 ++++++++++++++++++- 5 files changed, 83 insertions(+), 28 deletions(-) delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Models/UserPlugin.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs index 73d3f954c..829bb9715 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs @@ -37,7 +37,11 @@ namespace Flow.Launcher.Plugin.PluginsManager public List Query(Query query) { - return new List(); + var search = query.Search; + + var pluginManager = new PluginsManager(); + + return pluginManager.PluginsSearch(search); } public void Save() diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs deleted file mode 100644 index d2f6348af..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/Plugins.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Flow.Launcher.Plugin.PluginsManager.Models -{ - internal class Plugin - { - internal string ID { get; set; } - internal string Name { get; set; } - internal string Description { get; set; } - internal string Author { get; set; } - internal string Version { get; set; } - internal string Language { get; set; } - internal string Website { get; set; } - internal string UrlDownload { get; set; } - internal string UrlSourceCode { get; set; } - } -} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs index 3609aba7d..134ad7bd0 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs @@ -8,10 +8,10 @@ using System.Text; namespace Flow.Launcher.Plugin.PluginsManager.Models { - class PluginsManifest + internal class PluginsManifest { - public List Plugins { get; private set; } - public PluginsManifest() + internal List UserPlugins { get; private set; } + internal PluginsManifest() { var json = string.Empty; @@ -25,11 +25,11 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models { Log.Exception("|PluginManagement.GetManifest|Encountered error trying to download plugins manifest", e); - Plugins = new List(); + UserPlugins = new List(); } } - Plugins = !string.IsNullOrEmpty(json) ? JsonConvert.DeserializeObject>(json) : new List(); + UserPlugins = !string.IsNullOrEmpty(json) ? JsonConvert.DeserializeObject>(json) : new List(); } } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/UserPlugin.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/UserPlugin.cs new file mode 100644 index 000000000..3bc44e0f6 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Models/UserPlugin.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager.Models +{ + public class UserPlugin + { + public string ID { get; set; } + public string Name { get; set; } + public string Description { get; set; } + public string Author { get; set; } + public string Version { get; set; } + public string Language { get; set; } + public string Website { get; set; } + public string UrlDownload { get; set; } + public string UrlSourceCode { get; set; } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs index 055e027ad..1f3321d6a 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -1,6 +1,9 @@ -using Flow.Launcher.Infrastructure.Http; +using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.Http; +using Flow.Launcher.Plugin.PluginsManager.Models; using System; using System.Collections.Generic; +using System.Linq; using System.Net; using System.Text; @@ -8,7 +11,12 @@ namespace Flow.Launcher.Plugin.PluginsManager { internal class PluginsManager { - internal void PluginInstall(Plugin plugin) + private PluginsManifest pluginsManifest; + internal PluginsManager() + { + pluginsManifest = new PluginsManifest(); + } + internal void PluginInstall(UserPlugin plugin) { if (PluginExists()) { @@ -17,7 +25,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return; } - PluginDowload(plugin.Url, ""); + PluginDowload(plugin.UrlDownload, ""); } private void PluginDowload(string downloadUrl, string toFilePath) @@ -42,5 +50,48 @@ namespace Flow.Launcher.Plugin.PluginsManager { } + + internal List PluginsSearch(string searchName) + { + var results = new List(); + + if (string.IsNullOrEmpty(searchName)) + { + pluginsManifest.UserPlugins + .ForEach(x => results.Add( + new Result + { + Title = $"{x.Name} by {x.Author}", + SubTitle = x.Description, + IcoPath = "Images\\plugin.png", + Action = e => + { + PluginInstall(x); + return false; + } + })); + + return results; + } + + pluginsManifest.UserPlugins + .Where(x => StringMatcher.FuzzySearch(searchName, x.Name).IsSearchPrecisionScoreMet()) + .Select(x => x) + .ToList() + .ForEach(x => results.Add( + new Result + { + Title = $"{x.Name} by {x.Author}", + SubTitle = x.Description, + IcoPath = "Images\\plugin.png", + Action = e => + { + PluginInstall(x); + return false; + } + })); + + return results; + } } } From 8d96899a8225212afb93d17d444e0d2032a6c7c3 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 7 Dec 2020 07:42:23 +1100 Subject: [PATCH 080/267] update icoPath --- .../Flow.Launcher.Plugin.PluginManager/PluginsManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs index 1f3321d6a..5457c1562 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -12,6 +12,9 @@ namespace Flow.Launcher.Plugin.PluginsManager internal class PluginsManager { private PluginsManifest pluginsManifest; + + private string icoPath = "Images\\plugin.png"; + internal PluginsManager() { pluginsManifest = new PluginsManifest(); @@ -63,7 +66,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { Title = $"{x.Name} by {x.Author}", SubTitle = x.Description, - IcoPath = "Images\\plugin.png", + IcoPath = icoPath, Action = e => { PluginInstall(x); @@ -83,7 +86,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { Title = $"{x.Name} by {x.Author}", SubTitle = x.Description, - IcoPath = "Images\\plugin.png", + IcoPath = icoPath, Action = e => { PluginInstall(x); From a72750dc65d6bf446eec7bb7eb3197445e34a4c6 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 7 Dec 2020 21:21:14 +1100 Subject: [PATCH 081/267] add plugin download behaviour --- ...Flow.Launcher.Plugin.PluginsManager.csproj | 8 ++- .../Languages/en.xaml | 4 +- .../Main.cs | 2 +- .../PluginsManager.cs | 67 +++++++++++-------- 4 files changed, 48 insertions(+), 33 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj index 43a1e089b..84cc5ffb1 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -29,10 +29,14 @@ - + + PreserveNewest + - + + PreserveNewest + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml index 75caf81ec..7930eb743 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml @@ -3,7 +3,9 @@ xmlns:system="clr-namespace:System;assembly=mscorlib"> - + Downloading plugin + Please wait... + Successfully downloaded diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs index 829bb9715..1a21f6026 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs @@ -39,7 +39,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { var search = query.Search; - var pluginManager = new PluginsManager(); + var pluginManager = new PluginsManager(Context); return pluginManager.PluginsSearch(search); } diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs index 5457c1562..6a9da4eea 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -1,23 +1,29 @@ -using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Http; +using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Text; +using System.Windows; namespace Flow.Launcher.Plugin.PluginsManager { internal class PluginsManager { private PluginsManifest pluginsManifest; + private PluginInitContext context { get; set; } private string icoPath = "Images\\plugin.png"; - internal PluginsManager() + internal PluginsManager(PluginInitContext context) { pluginsManifest = new PluginsManifest(); + this.context = context; } internal void PluginInstall(UserPlugin plugin) { @@ -28,14 +34,28 @@ namespace Flow.Launcher.Plugin.PluginsManager return; } - PluginDowload(plugin.UrlDownload, ""); + var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip"); + PluginDownload(plugin.UrlDownload, filePath); } - private void PluginDowload(string downloadUrl, string toFilePath) + private void PluginDownload(string downloadUrl, string toFilePath) { - using (var wc = new WebClient { Proxy = Http.WebProxy() }) + try { - wc.DownloadFile(downloadUrl, toFilePath); + using (var wc = new WebClient { Proxy = Http.WebProxy() }) + { + wc.DownloadFile(downloadUrl, toFilePath); + } + + context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), + context.API.GetTranslation("plugin_pluginsmanager_download_success")); + } + catch(Exception e) + { + context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), + context.API.GetTranslation("plugin_pluginsmanager_download_success")); + + Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } } @@ -58,9 +78,8 @@ namespace Flow.Launcher.Plugin.PluginsManager { var results = new List(); - if (string.IsNullOrEmpty(searchName)) - { - pluginsManifest.UserPlugins + pluginsManifest + .UserPlugins .ForEach(x => results.Add( new Result { @@ -69,32 +88,22 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = icoPath, Action = e => { + context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), + context.API.GetTranslation("plugin_pluginsmanager_please_wait")); + Application.Current.MainWindow.Hide(); PluginInstall(x); - return false; + + return true; } })); + if (string.IsNullOrEmpty(searchName)) return results; - } - pluginsManifest.UserPlugins - .Where(x => StringMatcher.FuzzySearch(searchName, x.Name).IsSearchPrecisionScoreMet()) - .Select(x => x) - .ToList() - .ForEach(x => results.Add( - new Result - { - Title = $"{x.Name} by {x.Author}", - SubTitle = x.Description, - IcoPath = icoPath, - Action = e => - { - PluginInstall(x); - return false; - } - })); - - return results; + return results + .Where(x => StringMatcher.FuzzySearch(searchName, x.Title).IsSearchPrecisionScoreMet()) + .Select(x => x) + .ToList(); } } } From 8c136580e29e8f58acca7432ae131e47da8f5dbb Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 8 Dec 2020 21:59:45 +1100 Subject: [PATCH 082/267] remove InstallPlugin method from API - do not allow InstallPlugin method to be called via API - move InstallPlugin functionality to PluginsManager for use exclusively --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 1 - Flow.Launcher.Core/Plugin/PluginInstaller.cs | 169 ------------------ Flow.Launcher.Core/Plugin/PluginManager.cs | 5 - Flow.Launcher.Plugin/IPublicAPI.cs | 6 - Flow.Launcher/PublicAPIInstance.cs | 5 - ...Flow.Launcher.Plugin.PluginsManager.csproj | 4 + .../PluginsManager.cs | 157 ++++++++++++++++ 7 files changed, 161 insertions(+), 186 deletions(-) delete mode 100644 Flow.Launcher.Core/Plugin/PluginInstaller.cs diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 9f146a457..189a6669e 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -55,7 +55,6 @@ - diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs deleted file mode 100644 index 7b980a3ee..000000000 --- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs +++ /dev/null @@ -1,169 +0,0 @@ -using System; -using System.IO; -using System.Windows; -using ICSharpCode.SharpZipLib.Zip; -using Newtonsoft.Json; -using Flow.Launcher.Plugin; -using Flow.Launcher.Infrastructure; -using Flow.Launcher.Infrastructure.Logger; - -namespace Flow.Launcher.Core.Plugin -{ - internal class PluginInstaller - { - internal static void Install(string path) - { - if (File.Exists(path)) - { - string tempFolder = Path.Combine(Path.GetTempPath(), "flowlauncher", "plugins"); - if (Directory.Exists(tempFolder)) - { - Directory.Delete(tempFolder, true); - } - UnZip(path, tempFolder, true); - - string jsonPath = Path.Combine(tempFolder, Constant.PluginMetadataFileName); - if (!File.Exists(jsonPath)) - { - MessageBox.Show("Install failed: plugin config is missing"); - return; - } - - PluginMetadata plugin = GetMetadataFromJson(tempFolder); - if (plugin == null || plugin.Name == null) - { - MessageBox.Show("Install failed: plugin config is invalid"); - return; - } - - string pluginFolderPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory; - - string newPluginName = plugin.Name - .Replace("/", "_") - .Replace("\\", "_") - .Replace(":", "_") - .Replace("<", "_") - .Replace(">", "_") - .Replace("?", "_") - .Replace("*", "_") - .Replace("|", "_") - + "-" + Guid.NewGuid(); - - string newPluginPath = Path.Combine(pluginFolderPath, newPluginName); - - string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"Version: {plugin.Version}{Environment.NewLine}" + - $"Author: {plugin.Author}"; - PluginPair existingPlugin = PluginManager.GetPluginForId(plugin.ID); - - if (existingPlugin != null) - { - content = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"Old Version: {existingPlugin.Metadata.Version}" + - $"{Environment.NewLine}New Version: {plugin.Version}" + - $"{Environment.NewLine}Author: {plugin.Author}"; - } - - var result = MessageBox.Show(content, "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.Yes) - { - if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory)) - { - //when plugin is in use, we can't delete them. That's why we need to make plugin folder a random name - File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close(); - } - - Directory.Move(tempFolder, newPluginPath); - - //exsiting plugins may be has loaded by application, - //if we try to delelte those kind of plugins, we will get a error that indicate the - //file is been used now. - //current solution is to restart Flow Launcher. Ugly. - //if (MainWindow.Initialized) - //{ - // Plugins.Initialize(); - //} - if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" + - "Restart Flow Launcher to take effect?", - "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) - { - PluginManager.API.RestartApp(); - } - } - } - } - - private static PluginMetadata GetMetadataFromJson(string pluginDirectory) - { - string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName); - PluginMetadata metadata; - - if (!File.Exists(configPath)) - { - return null; - } - - try - { - metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginDirectory = pluginDirectory; - } - catch (Exception e) - { - Log.Exception($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid json format", e); - return null; - } - - if (!AllowedLanguage.IsAllowed(metadata.Language)) - { - Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid language {metadata.Language}"); - return null; - } - if (!File.Exists(metadata.ExecuteFilePath)) - { - Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: file {metadata.ExecuteFilePath} doesn't exist"); - return null; - } - - return metadata; - } - - /// - /// unzip plugin contents to the given directory. - /// - /// The path to the zip file. - /// The output directory. - /// overwirte - private static void UnZip(string zipFile, string strDirectory, bool overWrite) - { - if (strDirectory == "") - strDirectory = Directory.GetCurrentDirectory(); - - using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFile))) - { - ZipEntry theEntry; - - while ((theEntry = zipStream.GetNextEntry()) != null) - { - var pathToZip = theEntry.Name; - var directoryName = String.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip); - var fileName = Path.GetFileName(pathToZip); - var destinationDir = Path.Combine(strDirectory, directoryName); - var destinationFile = Path.Combine(destinationDir, fileName); - - Directory.CreateDirectory(destinationDir); - - if (String.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overWrite)) - continue; - - using (FileStream streamWriter = File.Create(destinationFile)) - { - zipStream.CopyTo(streamWriter); - } - } - } - } - } -} diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 5cde9de83..3b697a1ee 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -133,11 +133,6 @@ namespace Flow.Launcher.Core.Plugin } } - public static void InstallPlugin(string path) - { - PluginInstaller.Install(path); - } - public static List ValidPluginsForQuery(Query query) { if (NonGlobalPlugins.ContainsKey(query.ActionKeyword)) diff --git a/Flow.Launcher.Plugin/IPublicAPI.cs b/Flow.Launcher.Plugin/IPublicAPI.cs index 681973905..ccc00d5e9 100644 --- a/Flow.Launcher.Plugin/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/IPublicAPI.cs @@ -63,12 +63,6 @@ namespace Flow.Launcher.Plugin /// void OpenSettingDialog(); - /// - /// Install Flow Launcher plugin - /// - /// Plugin path (ends with .flowlauncher) - void InstallPlugin(string path); - /// /// Get translation of current language /// You need to implement IPluginI18n if you want to support multiple languages for your plugin diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 0cc5a0e5d..90d4fff63 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -115,11 +115,6 @@ namespace Flow.Launcher _mainVM.ProgressBarVisibility = Visibility.Collapsed; } - public void InstallPlugin(string path) - { - Application.Current.Dispatcher.Invoke(() => PluginManager.InstallPlugin(path)); - } - public string GetTranslation(string key) { return InternationalizationManager.Instance.GetTranslation(key); diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj index 84cc5ffb1..cc1a931ce 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -39,4 +39,8 @@ PreserveNewest + + + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs index 6a9da4eea..5484fdf85 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -3,6 +3,7 @@ using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; +using ICSharpCode.SharpZipLib.Zip; using System; using System.Collections.Generic; using System.IO; @@ -36,6 +37,7 @@ namespace Flow.Launcher.Plugin.PluginsManager var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip"); PluginDownload(plugin.UrlDownload, filePath); + context.API.InstallPlugin(filePath); } private void PluginDownload(string downloadUrl, string toFilePath) @@ -105,5 +107,160 @@ namespace Flow.Launcher.Plugin.PluginsManager .Select(x => x) .ToList(); } + + private void Install(string path) + { + if (File.Exists(path)) + { + string tempFolder = Path.Combine(Path.GetTempPath(), "flowlauncher", "plugins"); + if (Directory.Exists(tempFolder)) + { + Directory.Delete(tempFolder, true); + } + UnZip(path, tempFolder, true); + + string jsonPath = Path.Combine(tempFolder, Constant.PluginMetadataFileName); + if (!File.Exists(jsonPath)) + { + MessageBox.Show("Install failed: plugin config is missing"); + return; + } + + PluginMetadata plugin = GetMetadataFromJson(tempFolder); + if (plugin == null || plugin.Name == null) + { + MessageBox.Show("Install failed: plugin config is invalid"); + return; + } + + string pluginFolderPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory; + + string newPluginName = plugin.Name + .Replace("/", "_") + .Replace("\\", "_") + .Replace(":", "_") + .Replace("<", "_") + .Replace(">", "_") + .Replace("?", "_") + .Replace("*", "_") + .Replace("|", "_") + + "-" + Guid.NewGuid(); + + string newPluginPath = Path.Combine(pluginFolderPath, newPluginName); + + string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" + + $"Name: {plugin.Name}{Environment.NewLine}" + + $"Version: {plugin.Version}{Environment.NewLine}" + + $"Author: {plugin.Author}"; + PluginPair existingPlugin = PluginManager.GetPluginForId(plugin.ID); + + if (existingPlugin != null) + { + content = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" + + $"Name: {plugin.Name}{Environment.NewLine}" + + $"Old Version: {existingPlugin.Metadata.Version}" + + $"{Environment.NewLine}New Version: {plugin.Version}" + + $"{Environment.NewLine}Author: {plugin.Author}"; + } + + var result = MessageBox.Show(content, "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) + { + if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory)) + { + //when plugin is in use, we can't delete them. That's why we need to make plugin folder a random name + File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close(); + } + + Directory.Move(tempFolder, newPluginPath); + + //exsiting plugins may be has loaded by application, + //if we try to delelte those kind of plugins, we will get a error that indicate the + //file is been used now. + //current solution is to restart Flow Launcher. Ugly. + //if (MainWindow.Initialized) + //{ + // Plugins.Initialize(); + //} + if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" + + "Restart Flow Launcher to take effect?", + "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) + { + PluginManager.API.RestartApp(); + } + } + } + } + + private PluginMetadata GetMetadataFromJson(string pluginDirectory) + { + string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName); + PluginMetadata metadata; + + if (!File.Exists(configPath)) + { + return null; + } + + try + { + metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); + metadata.PluginDirectory = pluginDirectory; + } + catch (Exception e) + { + Log.Exception($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid json format", e); + return null; + } + + if (!AllowedLanguage.IsAllowed(metadata.Language)) + { + Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid language {metadata.Language}"); + return null; + } + if (!File.Exists(metadata.ExecuteFilePath)) + { + Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: file {metadata.ExecuteFilePath} doesn't exist"); + return null; + } + + return metadata; + } + + /// + /// unzip plugin contents to the given directory. + /// + /// The path to the zip file. + /// The output directory. + /// overwirte + private void UnZip(string zipFile, string strDirectory, bool overWrite) + { + if (strDirectory == "") + strDirectory = Directory.GetCurrentDirectory(); + + using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFile))) + { + ZipEntry theEntry; + + while ((theEntry = zipStream.GetNextEntry()) != null) + { + var pathToZip = theEntry.Name; + var directoryName = String.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip); + var fileName = Path.GetFileName(pathToZip); + var destinationDir = Path.Combine(strDirectory, directoryName); + var destinationFile = Path.Combine(destinationDir, fileName); + + Directory.CreateDirectory(destinationDir); + + if (String.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overWrite)) + continue; + + using (FileStream streamWriter = File.Create(destinationFile)) + { + zipStream.CopyTo(streamWriter); + } + } + } + } } } From eaf3267353710db159eac311af8983ad7ad60667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 8 Dec 2020 19:48:42 +0800 Subject: [PATCH 083/267] Add space for pinyin translation --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 38f1ab879..9396226c7 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -36,8 +36,8 @@ namespace Flow.Launcher.Infrastructure { if (WordsHelper.HasChinese(content)) { - var result = WordsHelper.GetPinyin(content, ";"); - result = GetFirstPinyinChar(result) + result.Replace(";", ""); + var result = WordsHelper.GetPinyin(content, " "); + result = GetFirstPinyinChar(result) + result; _pinyinCache[content] = result; return result; } @@ -59,7 +59,7 @@ namespace Flow.Launcher.Infrastructure private string GetFirstPinyinChar(string content) { - return string.Concat(content.Split(';').Select(x => x.First())); + return string.Concat(content.Split(' ').Select(x => x.First())); } } } \ No newline at end of file From d8191f71bf0e24e91f5135d1c4e0537a82b7b922 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 9 Dec 2020 05:28:58 +1100 Subject: [PATCH 084/267] adjust temporary working directory path --- .../PluginsManager.cs | 129 ++++++++---------- 1 file changed, 54 insertions(+), 75 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs index 5484fdf85..4290767c3 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -4,6 +4,7 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; using ICSharpCode.SharpZipLib.Zip; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -37,7 +38,7 @@ namespace Flow.Launcher.Plugin.PluginsManager var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip"); PluginDownload(plugin.UrlDownload, filePath); - context.API.InstallPlugin(filePath); + Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath)); } private void PluginDownload(string downloadUrl, string toFilePath) @@ -108,51 +109,62 @@ namespace Flow.Launcher.Plugin.PluginsManager .ToList(); } - private void Install(string path) + private void Install(UserPlugin plugin, string downloadedFilePath) { - if (File.Exists(path)) + if (File.Exists(downloadedFilePath)) { - string tempFolder = Path.Combine(Path.GetTempPath(), "flowlauncher", "plugins"); - if (Directory.Exists(tempFolder)) + var tempFolderPath = Path.Combine(Path.GetTempPath(), "flowlauncher"); + var tempPluginFolderPath = Path.Combine(tempFolderPath, "plugin"); + + if (Directory.Exists(tempFolderPath)) { - Directory.Delete(tempFolder, true); + Directory.Delete(tempFolderPath, true); } - UnZip(path, tempFolder, true); - string jsonPath = Path.Combine(tempFolder, Constant.PluginMetadataFileName); - if (!File.Exists(jsonPath)) + Directory.CreateDirectory(tempFolderPath); + + var zipFilePath = Path.Combine(tempFolderPath, Path.GetFileName(downloadedFilePath)); + + File.Move(downloadedFilePath, zipFilePath); + + UnZip(zipFilePath, tempPluginFolderPath, true); + + var unzippedParentFolderPath = tempPluginFolderPath; + + var metadataJsonFilePath = string.Empty; + + var pluginFolderPath = string.Empty; + + var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length; + var unzippedFilesCount = Directory.GetFiles(unzippedParentFolderPath).Length; + + // addjust path depending on how the plugin is zipped up + // the recommended should be to zip up the folder not the contents + if (unzippedFolderCount == 1 && unzippedFilesCount == 0) + // folder is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/pluginFolderName/ + pluginFolderPath = Directory.GetDirectories(unzippedParentFolderPath)[0]; + + if (unzippedFilesCount > 1) + // content is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/ + pluginFolderPath = unzippedParentFolderPath; + + if (File.Exists(Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName))) + metadataJsonFilePath = Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName); + + if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath)) { - MessageBox.Show("Install failed: plugin config is missing"); + MessageBox.Show("Install failed: unable to find the plugin.json metadata file"); return; } - PluginMetadata plugin = GetMetadataFromJson(tempFolder); - if (plugin == null || plugin.Name == null) - { - MessageBox.Show("Install failed: plugin config is invalid"); - return; - } - - string pluginFolderPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory; - - string newPluginName = plugin.Name - .Replace("/", "_") - .Replace("\\", "_") - .Replace(":", "_") - .Replace("<", "_") - .Replace(">", "_") - .Replace("?", "_") - .Replace("*", "_") - .Replace("|", "_") - + "-" + Guid.NewGuid(); - - string newPluginPath = Path.Combine(pluginFolderPath, newPluginName); + string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}"); string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" + $"Name: {plugin.Name}{Environment.NewLine}" + $"Version: {plugin.Version}{Environment.NewLine}" + $"Author: {plugin.Author}"; - PluginPair existingPlugin = PluginManager.GetPluginForId(plugin.ID); + + var existingPlugin = context.API.GetAllPlugins().Where(x => x.Metadata.ID == plugin.ID).FirstOrDefault(); if (existingPlugin != null) { @@ -172,7 +184,7 @@ namespace Flow.Launcher.Plugin.PluginsManager File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close(); } - Directory.Move(tempFolder, newPluginPath); + Directory.Move(pluginFolderPath, newPluginPath); //exsiting plugins may be has loaded by application, //if we try to delelte those kind of plugins, we will get a error that indicate the @@ -186,73 +198,38 @@ namespace Flow.Launcher.Plugin.PluginsManager "Restart Flow Launcher to take effect?", "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { - PluginManager.API.RestartApp(); + context.API.RestartApp(); } } } } - private PluginMetadata GetMetadataFromJson(string pluginDirectory) - { - string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName); - PluginMetadata metadata; - - if (!File.Exists(configPath)) - { - return null; - } - - try - { - metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginDirectory = pluginDirectory; - } - catch (Exception e) - { - Log.Exception($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid json format", e); - return null; - } - - if (!AllowedLanguage.IsAllowed(metadata.Language)) - { - Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid language {metadata.Language}"); - return null; - } - if (!File.Exists(metadata.ExecuteFilePath)) - { - Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: file {metadata.ExecuteFilePath} doesn't exist"); - return null; - } - - return metadata; - } - /// /// unzip plugin contents to the given directory. /// - /// The path to the zip file. + /// The path to the zip file. /// The output directory. - /// overwirte - private void UnZip(string zipFile, string strDirectory, bool overWrite) + /// overwrite + private void UnZip(string zipFilePath, string strDirectory, bool overwrite) { if (strDirectory == "") strDirectory = Directory.GetCurrentDirectory(); - using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFile))) + using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFilePath))) { ZipEntry theEntry; while ((theEntry = zipStream.GetNextEntry()) != null) { var pathToZip = theEntry.Name; - var directoryName = String.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip); + var directoryName = string.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip); var fileName = Path.GetFileName(pathToZip); var destinationDir = Path.Combine(strDirectory, directoryName); var destinationFile = Path.Combine(destinationDir, fileName); Directory.CreateDirectory(destinationDir); - if (String.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overWrite)) + if (string.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overwrite)) continue; using (FileStream streamWriter = File.Create(destinationFile)) @@ -262,5 +239,7 @@ namespace Flow.Launcher.Plugin.PluginsManager } } } + + //delete the zip file when done } } From 519342178f0bc1730e2df34b8605f8e6e3bcab13 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 13:29:47 +1100 Subject: [PATCH 085/267] move download and unzip to utilities class --- .../PluginsManager.cs | 61 +++---------------- .../Utilities.cs | 50 +++++++++++++++ 2 files changed, 57 insertions(+), 54 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginManager/Utilities.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs index 4290767c3..e7e61460e 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs @@ -3,14 +3,11 @@ using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; -using ICSharpCode.SharpZipLib.Zip; -using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Text; using System.Windows; namespace Flow.Launcher.Plugin.PluginsManager @@ -37,29 +34,23 @@ namespace Flow.Launcher.Plugin.PluginsManager } var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip"); - PluginDownload(plugin.UrlDownload, filePath); - Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath)); - } - - private void PluginDownload(string downloadUrl, string toFilePath) - { + try { - using (var wc = new WebClient { Proxy = Http.WebProxy() }) - { - wc.DownloadFile(downloadUrl, toFilePath); - } + Utilities.Download(plugin.UrlDownload, filePath); context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), - context.API.GetTranslation("plugin_pluginsmanager_download_success")); + context.API.GetTranslation("plugin_pluginsmanager_download_success")); } - catch(Exception e) + catch (Exception e) { context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), context.API.GetTranslation("plugin_pluginsmanager_download_success")); Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } + + Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath)); } internal void PluginUpdate() @@ -127,7 +118,7 @@ namespace Flow.Launcher.Plugin.PluginsManager File.Move(downloadedFilePath, zipFilePath); - UnZip(zipFilePath, tempPluginFolderPath, true); + Utilities.UnZip(zipFilePath, tempPluginFolderPath, true); var unzippedParentFolderPath = tempPluginFolderPath; @@ -203,43 +194,5 @@ namespace Flow.Launcher.Plugin.PluginsManager } } } - - /// - /// unzip plugin contents to the given directory. - /// - /// The path to the zip file. - /// The output directory. - /// overwrite - private void UnZip(string zipFilePath, string strDirectory, bool overwrite) - { - if (strDirectory == "") - strDirectory = Directory.GetCurrentDirectory(); - - using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFilePath))) - { - ZipEntry theEntry; - - while ((theEntry = zipStream.GetNextEntry()) != null) - { - var pathToZip = theEntry.Name; - var directoryName = string.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip); - var fileName = Path.GetFileName(pathToZip); - var destinationDir = Path.Combine(strDirectory, directoryName); - var destinationFile = Path.Combine(destinationDir, fileName); - - Directory.CreateDirectory(destinationDir); - - if (string.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overwrite)) - continue; - - using (FileStream streamWriter = File.Create(destinationFile)) - { - zipStream.CopyTo(streamWriter); - } - } - } - } - - //delete the zip file when done } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginManager/Utilities.cs new file mode 100644 index 000000000..1ff42fdbd --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginManager/Utilities.cs @@ -0,0 +1,50 @@ +using Flow.Launcher.Infrastructure.Http; +using ICSharpCode.SharpZipLib.Zip; +using System.IO; +using System.Net; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + internal static class Utilities + { + /// + /// Unzip contents to the given directory. + /// + /// The path to the zip file. + /// The output directory. + /// overwrite + internal static void UnZip(string zipFilePath, string strDirectory, bool overwrite) + { + if (strDirectory == "") + strDirectory = Directory.GetCurrentDirectory(); + + using var zipStream = new ZipInputStream(File.OpenRead(zipFilePath)); + + ZipEntry theEntry; + + while ((theEntry = zipStream.GetNextEntry()) != null) + { + var pathToZip = theEntry.Name; + var directoryName = string.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip); + var fileName = Path.GetFileName(pathToZip); + var destinationDir = Path.Combine(strDirectory, directoryName); + var destinationFile = Path.Combine(destinationDir, fileName); + + Directory.CreateDirectory(destinationDir); + + if (string.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overwrite)) + continue; + + using var streamWriter = File.Create(destinationFile); + zipStream.CopyTo(streamWriter); + } + } + + internal static void Download(string downloadUrl, string toFilePath) + { + using var wc = new WebClient { Proxy = Http.WebProxy() }; + + wc.DownloadFile(downloadUrl, toFilePath); + } + } +} From 311222ecd57ae602abf6665c6603b24b795783bc Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 19:54:30 +1100 Subject: [PATCH 086/267] update file name update method name --- Flow.Launcher.sln | 30 +++++++++---------- .../ContextMenu.cs | 0 ...Flow.Launcher.Plugin.PluginsManager.csproj | 0 .../Languages/en.xaml | 0 .../Main.cs | 2 +- .../Models/PluginsManifest.cs | 0 .../Models/UserPlugin.cs | 0 .../PluginsManager.cs | 12 ++++---- .../Utilities.cs | 0 .../ViewModels/SettingsViewModel.cs | 0 .../Views/PluginsManagerSettings.xaml | 0 .../Views/PluginsManagerSettings.xaml.cs | 0 .../plugin.json | 0 13 files changed, 22 insertions(+), 22 deletions(-) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/ContextMenu.cs (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Flow.Launcher.Plugin.PluginsManager.csproj (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Languages/en.xaml (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Main.cs (96%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Models/PluginsManifest.cs (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Models/UserPlugin.cs (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/PluginsManager.cs (95%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Utilities.cs (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/ViewModels/SettingsViewModel.cs (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Views/PluginsManagerSettings.xaml (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/Views/PluginsManagerSettings.xaml.cs (100%) rename Plugins/{Flow.Launcher.Plugin.PluginManager => Flow.Launcher.Plugin.PluginsManager}/plugin.json (100%) diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln index 22086b0bd..c873bc147 100644 --- a/Flow.Launcher.sln +++ b/Flow.Launcher.sln @@ -15,12 +15,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc ProjectSection(ProjectDependencies) = postProject {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} + {4792A74A-0CEA-4173-A8B2-30E6764C6217} = {4792A74A-0CEA-4173-A8B2-30E6764C6217} {FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4} {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} - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE} = {70CB72BC-1CD6-453D-9CA5-F7E2441426FE} {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} @@ -72,7 +72,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Explor EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.ProcessKiller", "Plugins\Flow.Launcher.Plugin.ProcessKiller\Flow.Launcher.Plugin.ProcessKiller.csproj", "{588088F4-3262-4F9F-9663-A05DE12534C3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Flow.Launcher.Plugin.PluginsManager", "Plugins\Flow.Launcher.Plugin.PluginManager\Flow.Launcher.Plugin.PluginsManager.csproj", "{70CB72BC-1CD6-453D-9CA5-F7E2441426FE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.PluginsManager", "Plugins\Flow.Launcher.Plugin.PluginsManager\Flow.Launcher.Plugin.PluginsManager.csproj", "{4792A74A-0CEA-4173-A8B2-30E6764C6217}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -301,18 +301,18 @@ Global {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x64.Build.0 = Release|Any CPU {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.ActiveCfg = Release|Any CPU {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.Build.0 = Release|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x64.ActiveCfg = Debug|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x64.Build.0 = Debug|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x86.ActiveCfg = Debug|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Debug|x86.Build.0 = Debug|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|Any CPU.Build.0 = Release|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x64.ActiveCfg = Release|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x64.Build.0 = Release|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x86.ActiveCfg = Release|Any CPU - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE}.Release|x86.Build.0 = Release|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x64.ActiveCfg = Debug|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x64.Build.0 = Debug|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x86.ActiveCfg = Debug|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x86.Build.0 = Debug|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|Any CPU.Build.0 = Release|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x64.ActiveCfg = Release|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x64.Build.0 = Release|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x86.ActiveCfg = Release|Any CPU + {4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -331,7 +331,7 @@ Global {59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {588088F4-3262-4F9F-9663-A05DE12534C3} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} - {70CB72BC-1CD6-453D-9CA5-F7E2441426FE} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {4792A74A-0CEA-4173-A8B2-30E6764C6217} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/ContextMenu.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Flow.Launcher.Plugin.PluginsManager.csproj rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Languages/en.xaml rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs similarity index 96% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 1a21f6026..70ff7915c 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -41,7 +41,7 @@ namespace Flow.Launcher.Plugin.PluginsManager var pluginManager = new PluginsManager(Context); - return pluginManager.PluginsSearch(search); + return pluginManager.Search(search); } public void Save() diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Models/PluginsManifest.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Models/UserPlugin.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Models/UserPlugin.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs similarity index 95% rename from Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index e7e61460e..d35c8c16b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -17,14 +17,14 @@ namespace Flow.Launcher.Plugin.PluginsManager private PluginsManifest pluginsManifest; private PluginInitContext context { get; set; } - private string icoPath = "Images\\plugin.png"; + private readonly string icoPath = "Images\\plugin.png"; internal PluginsManager(PluginInitContext context) { pluginsManifest = new PluginsManifest(); this.context = context; } - internal void PluginInstall(UserPlugin plugin) + internal void InstallOrUpdate(UserPlugin plugin) { if (PluginExists()) { @@ -53,7 +53,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath)); } - internal void PluginUpdate() + internal void Update() { } @@ -65,10 +65,10 @@ namespace Flow.Launcher.Plugin.PluginsManager internal void PluginsManifestSiteOpen() { - + //Open https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest } - internal List PluginsSearch(string searchName) + internal List Search(string searchName) { var results = new List(); @@ -85,7 +85,7 @@ namespace Flow.Launcher.Plugin.PluginsManager context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), context.API.GetTranslation("plugin_pluginsmanager_please_wait")); Application.Current.MainWindow.Hide(); - PluginInstall(x); + InstallOrUpdate(x); return true; } diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Utilities.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ViewModels/SettingsViewModel.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/ViewModels/SettingsViewModel.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/ViewModels/SettingsViewModel.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/Views/PluginsManagerSettings.xaml.cs rename to Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json similarity index 100% rename from Plugins/Flow.Launcher.Plugin.PluginManager/plugin.json rename to Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json From 1a59da4adc757653cbb014c3803208abf785fbac Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 21:28:01 +1100 Subject: [PATCH 087/267] add plugin uninstall method --- .../Languages/en.xaml | 1 + .../Main.cs | 9 +- .../PluginsManager.cs | 91 +++++++++++++------ 3 files changed, 73 insertions(+), 28 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index 7930eb743..01a9052ed 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -6,6 +6,7 @@ Downloading plugin Please wait... Successfully downloaded + Do you want to uninstall the following plugin? diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 70ff7915c..f763826a8 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -39,9 +39,14 @@ namespace Flow.Launcher.Plugin.PluginsManager { var search = query.Search; - var pluginManager = new PluginsManager(Context); + var uninstallCmd = "uninstall"; - return pluginManager.Search(search); + var pluginManager = new PluginsManager(Context); + + if (search.ToLower().StartsWith($"{uninstallCmd} ") || search.ToLower() == uninstallCmd) + return pluginManager.RequestUninstall(search.Replace(uninstallCmd, string.Empty).Trim()); + + return pluginManager.RequestInstallOrUpdate(search); } public void Save() diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index d35c8c16b..ad62ac7b7 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -15,14 +15,14 @@ namespace Flow.Launcher.Plugin.PluginsManager internal class PluginsManager { private PluginsManifest pluginsManifest; - private PluginInitContext context { get; set; } + private PluginInitContext Context { get; set; } private readonly string icoPath = "Images\\plugin.png"; internal PluginsManager(PluginInitContext context) { pluginsManifest = new PluginsManifest(); - this.context = context; + Context = context; } internal void InstallOrUpdate(UserPlugin plugin) { @@ -39,13 +39,13 @@ namespace Flow.Launcher.Plugin.PluginsManager { Utilities.Download(plugin.UrlDownload, filePath); - 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_downloading_plugin"), + Context.API.GetTranslation("plugin_pluginsmanager_download_success")); } 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_downloading_plugin"), + Context.API.GetTranslation("plugin_pluginsmanager_download_success")); Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } @@ -68,7 +68,18 @@ namespace Flow.Launcher.Plugin.PluginsManager //Open https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest } - internal List Search(string searchName) + internal List Search(List results, string searchName) + { + if (string.IsNullOrEmpty(searchName)) + return results; + + return results + .Where(x => StringMatcher.FuzzySearch(searchName, x.Title).IsSearchPrecisionScoreMet()) + .Select(x => x) + .ToList(); + } + + internal List RequestInstallOrUpdate(string searchName) { var results = new List(); @@ -82,8 +93,8 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = icoPath, Action = e => { - context.API.ShowMsg(context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), - context.API.GetTranslation("plugin_pluginsmanager_please_wait")); + Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), + Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); Application.Current.MainWindow.Hide(); InstallOrUpdate(x); @@ -91,13 +102,7 @@ namespace Flow.Launcher.Plugin.PluginsManager } })); - if (string.IsNullOrEmpty(searchName)) - return results; - - return results - .Where(x => StringMatcher.FuzzySearch(searchName, x.Title).IsSearchPrecisionScoreMet()) - .Select(x => x) - .ToList(); + return Search(results, searchName); } private void Install(UserPlugin plugin, string downloadedFilePath) @@ -155,7 +160,7 @@ namespace Flow.Launcher.Plugin.PluginsManager $"Version: {plugin.Version}{Environment.NewLine}" + $"Author: {plugin.Author}"; - var existingPlugin = context.API.GetAllPlugins().Where(x => x.Metadata.ID == plugin.ID).FirstOrDefault(); + var existingPlugin = Context.API.GetAllPlugins().Where(x => x.Metadata.ID == plugin.ID).FirstOrDefault(); if (existingPlugin != null) { @@ -177,22 +182,56 @@ namespace Flow.Launcher.Plugin.PluginsManager Directory.Move(pluginFolderPath, newPluginPath); - //exsiting plugins may be has loaded by application, - //if we try to delelte those kind of plugins, we will get a error that indicate the - //file is been used now. - //current solution is to restart Flow Launcher. Ugly. - //if (MainWindow.Initialized) - //{ - // Plugins.Initialize(); - //} if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" + "Restart Flow Launcher to take effect?", "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) { - context.API.RestartApp(); + Context.API.RestartApp(); } } } } + + internal List RequestUninstall(string search) + { + var results = new List(); + + Context.API.GetAllPlugins() + .ForEach(x => results.Add( + new Result + { + Title = $"{x.Metadata.Name} by {x.Metadata.Author}", + SubTitle = x.Metadata.Description, + IcoPath = icoPath, + Action = e => + { + Application.Current.MainWindow.Hide(); + Uninstall(x.Metadata); + + return true; + } + })); + + return Search(results, search); + } + + private void Uninstall(PluginMetadata plugin) + { + string message = Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt")+ + $"{Environment.NewLine}{Environment.NewLine}" + + $"{plugin.Name} by {plugin.Author}"; + + if (MessageBox.Show(message, "Flow Launcher", MessageBoxButton.YesNo) == MessageBoxResult.Yes) + { + File.Create(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")).Close(); + var result = MessageBox.Show($"You have uninstalled plugin {plugin.Name} successfully.{Environment.NewLine}" + + "Restart Flow Launcher to take effect?", + "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); + if (result == MessageBoxResult.Yes) + { + Context.API.RestartApp(); + } + } + } } } From 402e2da061fa82258d024b7be718f8319ddd3738 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 21:31:21 +1100 Subject: [PATCH 088/267] use plugin icopath when displaying uninstall plugins --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index ad62ac7b7..5a3304912 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -14,7 +14,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { internal class PluginsManager { - private PluginsManifest pluginsManifest; + private readonly PluginsManifest pluginsManifest; private PluginInitContext Context { get; set; } private readonly string icoPath = "Images\\plugin.png"; @@ -202,7 +202,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { Title = $"{x.Metadata.Name} by {x.Metadata.Author}", SubTitle = x.Metadata.Description, - IcoPath = icoPath, + IcoPath = x.Metadata.IcoPath, Action = e => { Application.Current.MainWindow.Hide(); From 712a1456a2fde36a65b03ed58fc234a05c81eb42 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 22:09:27 +1100 Subject: [PATCH 089/267] add plugin icopath --- .../Images/pluginsmanager.png | Bin 0 -> 496093 bytes .../PluginsManager.cs | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Images/pluginsmanager.png diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/pluginsmanager.png b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/pluginsmanager.png new file mode 100644 index 0000000000000000000000000000000000000000..65f0e41dc144cc1e332f181332c86031dfb37a11 GIT binary patch literal 496093 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 OK+Pm{Am42@dKRN*4Q22h_@G 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/t)Li`SQ4z>PGiq@V!DQWEKy3bH|%yH z20%iC;2)$4sz5;jC(r#}ZFDlV>g+WIqGJ+d8V=&c`ZXw%-asl5`7cuYZ4O+$%P3WI zHtx%1IP8_Q)=!z4!h_oc^F#>i;MV&R{MWS2xZD>f%NpM1zm5EN5C~}R?P|(!r$Vto zU?(a-TRen(UOs_Xr_mR+{^iXsa!^pFeXMaA)@dc283A$~>EmJISNE}9wy*(+C-unC zruG{M!3DCoT&TzslYVBONgzFOGo)04j%R&@Lf^~RYY;0MqE*fzCc}OEEe=YG;*jRK zAWq;)=8L_0r9SeGMz$;|T1unGyn^LEpP0KQ%E+f!N$xSI<23ZBz!SQ!DcD?^8svym z23~SH<0L7B9H$Tkc$`~!(so^~pa<+HcLyM^a3Q!uSeQabJv{oyA>SXP=HL)O*-~6i80ax^=*Qpuy-ULjH%9)H zX^}WxB4wuFfFq%CLK6ZT_TVq<2?CyIgj(7rAnBZ6O@AFB_I2H%0%z%}ogaFG+l5-% zu9Mpzsz?WAbv3)TarEY~i2lOImOG$(r#=Bic6G9v{8ZAsA_T;Y+Hay+^MPa%fX+bR z2^=NzJ;eMg3@h$>75|U;=RXuw{KLm_j{t&n`J*CfQiMYLI7r&OT}Um2fRaHXsn8Np z2JhQz$-{;W-ddQN1jZ`>c8pboJPk&11=FCz!#ZJG^Yr;hnZDHeu}b_U%))T1nI!yH zCiO4xi3}_$-eB-zHCE~k2Q+59GGga z#{Mir_$etDH=#l^#oPRstc>|ZWs{vIki#+(W?o4{^;%uWb%c1$7{PJKM; zI`*m7UKhNepC<-r4P3z{^O8eAysA~W`qV28N9G@3qUi_Ary|h~>GkphQn;#SaBn@~ z47CF@w$43>CpmMaO<|deCb7h6pl=?P;r% zua#YA%BHX-Yek5;oOt5g_1t@~a-FtU?LvSL{`^=0OoQn@ucJI~y&GNb>YEkCtas)& z9#z;L&8F`yy9KeE>O0*r(RJ=wGABnAdD0;<&|^}3Kv z&=7Um!0Q;!_e^&a?PoBLs|#&Xl#--8Ukw?&>NFXIYPW-Hj_In=o?E3ByO2X+f9>cB zDGz|(J_jpor&MKfXQFU-fT>f(7g9Vq6HUy*(>n@Mys(ty4L1ewnbuOuN?xqA- zdM_T=q(vt$BTz~hElVO;!=z#E^TI$nXy+I$UR5z4^{gHCM_2ijXln5{1Zooi;z79$;sukX?DMLTcmr8rUmoiX$ngz}m9AiTo=`@!wbhEgm1Rt?@)<>1>zp95>ssHe){|){^ zA;9bs5Q`N1U73ow8s#?>stXN^7lduSr$OA{RKQ3l{Mpd3T%Z?}owOxfydTIoK@GJ#Uv@^;aDN#K>KyDd?AWw|t3&`aj0(19W zrP)mHt=X!;(!-^+m`zxUnb#!6fCGj7W=AJEwRRf4)2!5x_R$ZvGTPbDM>r&ki0wAJ z4`$#~v`@d;_XMfyG|aWgj?OoUS~L8uYOy;hF+=L^Ph?WZpOtsja!pWn*&6P0{blf^ zQw%D#r#cGe!Ro2=X3+B>S#o=wHvMg2!N70&!l69vIM!`LWu2Lgvt00gAnUW(WiQh% zRrXAK^J}!=LftpIRd(5i%FDLy@KXYH^Qc1=r96VtITyGUtCg8`s=Q{@o)*P`0;Lfmo&uQ~Jv1@670f7UK%5 zuvZN8I^{ytSdRmL$16(rWqo(m$DQHJxnk9FIb^&def!FwAX~MA_siw$K7{oNYVJ22 z#)4dwg8XJ{q;Uxi3-}0xsXU8zNdJ7?GJtPtIfMYh9YbS-PJ_2(Nc|fERw0J!U*Hfr z0ot(Id&-^BWnIwg>gUtp7jaN0C^;%9*%<$EZXx8U|4EbOxYeGIFIQ;`dqUD?;q9+L#jn|wYd8U4euCd9g%+uWcc zf?K;}dn~!;+dFQ?w;mr}(pCe6esY!u?P5#CI_nDp0sp6TRNix6v~}x;R-1zr2OQJ+ zZC(R3sm~T1>wor``Zf$)OPGeqe7f;u9B^18v1>C7DYhcKbz2t>(f{lPmSI7M~bBxRJWMJ?n6Zqp-{v6tn459y^Ez;i}t(*l_ zEq|7cmsUE)QYxRB+?QEnP7bO4tzCY?*2q#ph2CTmuUAb&Uzm?Up_ZOSrMCOFuPz>m z&QO?Edag#A>Z_Typl?}3>E~b6ZH}DwaX2;WF%erYyuB7I1VJ38)j{efPb{pUENaI3 zjg9o3(RTwjBO!^uTa~t;{Kl?lNOel_f}1K8{}S!{tYRfE#JuO;q1X4nLu&el|MSNK z_->pP-V({R8WTYEOtilb7y@_s0>8Dp7cEO`K%CIF!>);zdd2-6tD|w-R_#^eLik$ z?~mgS!5#r>FvXs=-0;W>a2$|IT6Vr?guH_~K=t(dvDdC|kor!AoXSWM4$Xy;432H% zsV}oCdJRjr4Yo1vz@4CuAfIjPttMrbwmCD)H z-9iMsl2e7`c9xm|@iw=^PouR9R)NYGp0c*mDLprg${^@fsKYjy@={Ynx5|pR0Cm#B zkJj`>md{T>MbC_9M0)OTi;faW}1O3mk%8Qe?W$0#V>xn8gf!eVSAx zzlbN2QxKYK4GwDNymC_i_~A_qj5}`1Il|nu@vd6VV;?kpIgYCkhL9A9M|B~`frX8M zrpVD_G>(pOkn0!OS^t$L#0HHyK=5{T=8NF&$m-s~tWmv`yz)`r1A>|AunQaBcOEZF zbkx$GI48M|pMQTW>~Dob(yoC&&f{|6um`3GF|;4`nvx&qiv>dyRf8$e1H;KffWlCM zE2Q*S8$&Vu!N5Q$Aw8;`4eH~%nipuA?1-z^b@_mCf&7cjL>`A!H>iqFO1gB9?4P91 z+Qa`E*lT0D+ynLrM7)?=-S8}rF`;foZ&}InO}`M9PF|OJl+#$R8+;_3`qqm>V9miP zp*fQma-9R}-dUQ(4ZA5U#i>8OSALyeH}vs2nK{Td`rbeJ>ePmax|n|ajKh|5N7+?@y6C?vt)kFyZGS5nF$^Vvgz;Ic)`b6CGm zzY0YIx;~lBNADQ6fqb=0VEb_2xVA5OckdFcjQBEItyI}Hip>h9>HM^@$KN^HUQtxe zgC>PB_{&4#il*xg@Adf7`!mpIb$vRM5gB7JClJ9{X%G0A;5oIkiJO(JIp)fbEwQMM zC)nixn}L(MpiD!jZ-zT}Eb^||jxJwuVwYZ$~gLc#893aW87Nxc75clz;Cz45{z5k4hfDgPfK$Dm`MR8tJ*gmnLZ2}!rUyW`|e#{~utUy6ev0A0eZ*#5Fhg?mxxuz-_{B5jn z_gsTTYDTL>eRdsLG~?Hi+xL4X?oz0~i}csiiN`s%$6CAymEzPDDfhmI5tX!uPB$W4 zG4Qg)D|ftBXRRc=trP0s=PDH43H=RQ6v;y|x*UV6`8UinnIi@9g)tXfnkOqz(%3mm z7EyAKqB*?fWF9-PIm(EI05X8gx(zL;fY#al2vk+>RZN36MebbZFxg7Xw!j=ErQ%c5 zpU<|vuPG$ug<`x<8k&S^5;b3Z-1YQXy3l8`+q#Iqjy_i?8HGWUP2up7C0&1X;a~13 zc6s7=-$RI67x>*l)k1$?*|8x7xK}wnAvV0VYEb51BI$7Gw6O80di%xRl&tm(TPMo` zA?@|Yfkd;ef5!!kH`PK8{6U}Q z>sASuAn1wvPbA$R_1#5EL){;9UpW>btXOe(h@(uyht2kY+DTl>F;;6v>62TAI6&7e zzwD!D^}EO;Kim&lEHyeN&IwrmQ2$01*{Wuw&aA(Z%sF-;{-@Kfy}#5JOb0|{IN*r^ zVu1bMv?e}!F@Z9WFTpAN!ppl-g~gmSk{w}008a~h;+NC2auNLaG|1x*#_%ViDaNI% z#toI9hRPLpzzQxywf`MVN13RX&aDI|)fvzG)Qd9;U6~a}%<(sw0FdG0c`+U{q&tem z@AGaz1HS#k`^vwA@4rI-4Gh;`a0}-3P|)6Dqc)RTIGvIuhu2grYswVr6xNaI>v&lo z#zIT|^d-~UcY>&2we!7uxhL+;#rfU(kQZ0|G|FSAe?W71n7Hmj)!}SuYPAaUoTynd zhF_6`H8Ewy#X$$SrRCzSak-n;S3Zn-8-a*%foaegFsnpDGJTHO8`tHQ6*BWyBEE^) z@|dWoKVL2S?|x5N(ke#591#qAA^I+xXS7Br?jBv$Qc)?JD8 z&%)WSs^R#gk=x3PPW58Q`|{S}@$#*Q?^+cY00mYAR6{cxpLrvh4omguir>V61z!#4 zUI17_m~rhmKt3@d*g&pR47nwaB*ZM0I}m6h9!An+^|xaudf1!bx_m*miquHD)Re9K zDe=xOzmFHuWae&J?$(`Dz=g{*+sDHS7Gxbgm2HL4gD31CqD-kcs2u04>nkiv$J=2Q zsWqI#RI5^U4b)QGg`9V6>8cBwC7l+@3Hi@h=;IXW(RC})aVS?2*d{dqIaX%!pRf7-5`iCCNEV$et^n@K%_f-W|g|6(J95UM6=s?8rik{pJS*G z=jZ-~ZoHJhKl+fkf1-2_FE^DEKu-a=Zg$AeR zJwcDe*g4Bgh-?1U^5ipTN4^i|ygp8=wYAK20gu<`PKg?tAIs_{9qV6N@ zC7S72*XhJBUp1(^;v{-U*I0ny>rGJ?KIV~lG1PG#PZz9e{R$8rHdjfHEH|ofdd1Ch z10r!{q}4t^pCF&9byF|tK;yKop-Xx~1TXx1fbIZ+5hWmQ3oE{Jh{CKC2D z!ZiHedbsXS^xe_pF`YS9SoqXkop|V__mtl&IN)miahwk*EWWLdc~VMy`YgkMEteA> z-sc1S_;g&W1{0Wv#0~{-Xjuo3Bmvu%_fO(o@YJipCN(pbkwsMJ5=#?G@ImG3`1KOu zyjJJK_4rrxrgXeDlR2=&@4QrNvvfE4Iyk#{4*%qB%^el&I{Q)7r=;oC54%;4595D# zC|LY)HTCg~914+nzs1@7@1JA!<7o3~jo4z)u9D3oT0-2I9^1AMxC>nxRedprDD!a> zFgf{CEl2_i;p9jEM|S52a+96hRDaFo$KlHMS)#*5SM$rpsvjR9Mv_`M5Za6#&_{`g ziHiuISTtc2pYUCmVR;|>JVDP{hPkZnUm;D&ozY9L1Qq}%ML5t1Gv|n28I}(7Xf3A4 zp1sXs({*ygCiVl|KVll2s7ns*PuDj>;L)(@{yXeAz1Nxi`a>T}$?rSS^N z$nLNuP^b?SFlVCyhQXz0CX`w=E2U59+Sc0tXQdQ6GV?>CLApcJ$)s$)6uXLA&iAH} z3^qss09J@|@?OjN&aq79(@HeM@%DT2G2?Mn3_aFOj1~m;FY6Ve8TcxzeZ|mjn)it8 z!XeWoDB>fjWq~ylyib(1OR5rQ+TL(MbatW0JIVusS{bmbrUN}knPhPM(R#8SM#i-6 zUiR($on`7;D(BAnUS$2rHb1rg*W0fO^OXIf*=2;qxwWz0N2Gu|Qvok7o=?4u z;Wrmm>DwPemz|v3Mq4;E)};Eibc``@rV17CL>n6B3g8SNY$rm3`B8Vc9<9=c!4yYmjqKI^NG)_46<7aqwYp`3~K zgbC%kqh)2#6;6}w>C2NO7=rt2l`x~??1-W6?j8@E{UDZX{yRiTzQroN<>f*=z@H=Z zg~oDHz3So2&|!-Xlu1%egPlPdd8bM8l#8t2%xy?G(kcu(WQhaj`nksbs_qH{ZG15J zLu?fTNZG5%gLrHsk=bl8Xv00iFwnJuqJ5MYYRiE|P&~QH*^dC3Wbf~$!IXkPbi6c; zi1mku<58?EUcNSs-WeLIc*1PsIkw>w#Hy!-MOCdLE>`!vLl%YB-6}q$A4z=^dM6xb zJ6|yFT9fBRh%+NryjNWm(*}D=nnQi@)ie#Vvet8;eoJTu zA~snL;qL5?JUqg$4-nG{%g3(VPpsgc8FxBPv0Ze*`4-fre(}OtdCZ{wV)-kEEb3-hwtE+uC@Ih9f#te-!#P{4d z=JK}|`+POzR{p**+#MBgfA9tEaD}gQqHpa71(o4f99|vJ@QiusxD0(&d7Zr(qKB+2 z<*%uMOc(EuJ=5RpAblcT2R<7c5w`T$-ZYK96g1|NIhvnf{%^!jx2a{n-3cBt`{pSB z9`#(GW_SH%u)~%uS1hW?kgX448@KZ|Qzw*b~$2V4})zJ3} zcj(aw+ii_2qV3Y>nf8p(B)_sq-1OfOK6!fihD3C+qS zCOA7l#9Oq_MU&$1>B!ZbGSxxy1*xWk8MC|6EQc4Hb)y)q<}+jIX|UG|4dP#hqy)_i z5i7WxorH6q%Ch8i7Ptz9xeEJ4$%tfoHWGlP=2yM2etPOwZT^nr!RsDE^V&4GV1c(u zJ*eZ+U5`<3+s@d9>EEsX;nch+9rcZlf8AkPZqwzJs9Zp0bkg&#Og`smq>q?mRul=-#|IY$XsE1bwLw3eG4( z?cpZtLusy^ zN1qdi_M`|-a1F)YhLP&}UrZ|yN8{i_F@*f00uDU{<1YO+J8KUAz6a|E6b4Vrb=w@* zkdyaxsgzY*Wnt??mQXp&XfKPedkY7b2GK~Ovm0%{x?WlSdfqrT{HiB~Tv@o!c^3d4lsfnLm@ob- z3oc}=Y`bB!vyyACwUgkNeru3pI;+*<20(^Uy2ZKy8kkqAgZL zMurs0wsY#wsc;t_dgSjfBPZ5IwtYX7Xd zheqX>y4&{OKC+3@(N<7Xc0|2}=jQLOLQ|kX?rcxfsKnl$KhBreMMpXFLkm@w{nkE) zycbCQ-n1{$1s=~Tc-7pDm{d|RFx6lQBa5)5y&qw`s0q_q2i)4^jXu2hWU#yUHOM`o z6ej#G<-I5#1jFV0#`97ii!=13$W2O^;+k_$8%eKrFS0uFSuhRZSRMZA^v^f!YO{i}r# zP9-g;(SD0_4N!~1n&gqTdpD@(j9VlB8`u1{aMtLxU6>ZDtA&uz7kMX;`!*?0jyyk* zmBqazAfcS=ccrtQjovCOi&3{S9$OriYks!vuM#pY8n2& zzX!DRAFe2k1wBna;qiX9Di4M2`ZUFs_<4;`fBhy!dm`G>Q-GQ;G&V-hd{$DEhOHk8 zgFq9uu-N43D)B5JZ&?K^HhuJ(_PU8|ipF&uh5RsMn4}==jixs9cJ+a;I|PR%vWh&9 z_+vd!zuK5-aoU4KME+Nt@136!=9j1|&+0c3jm#zTZz=Q1L~x3!e{b$Lrc&hFLxmK?1!%#29xf(oE40h zceOsGRvvHIrOKgrFkZMPR|Ti*lEBUW!aMA3jU&3W-}!emOm@Or<3MI{~WANRuz>^%F?$wLC`ynPVp zq7=#GP{fM_QA*EGTGVo7b0e80BOrW%T4MIH8E+lWon0{|-2>jrIrO@#IPTiQe|YY3 zQq!J~{ii5)XZLKtS5RC8DeH`6$Z-x1WkpyZV!!ZASx-+^e@R}Wy{K?jfneNq3Fh|R zQmaAlW6I2=XYHR+g??C#OK}xk<_1+-^*jmL=gF=gM{11S*c>W&>eXk8;TIs+7n2K; z_V(8F*xb`;570OYVA~okvOYUdxNI%j}@qut4QqzR%@$pI}uJyAn|r3o1G19iH&G+L7NJ>wjTKAWKERuCSC^^eHZ$ z=u#}qDtt?3Y$yv!JC!8;PJli#jQqfE8@jn6=@1H%cQIvH*6LokoC0MVwkWa~)-q{? zOw2sPuX(i{gPCb?-ciDr|HsoihF8`#U8AvW+vrX@wsvgWwr$(!*mlyft?t;i%^m0D z{+{G^sy(%WI>HoDy(}lv!!pIQb)B4gS=<`SC70yESgY%-bqw1-6=bl|`Fek(2+D0UyUl-Z1ilOPrms%! z5v&g$%fNk<+QCs{eDW2y%%Bpej-~oB3(Exla|0~5x2AncJPD#;g;v7S*UI<@Ri_IR z4XeC-sfXEu?zv^~Bh@@Q4Zm?W>^T_rnjkG(l1d^ewCP{VPX;MlWI6t03fi<+))MsI=c>dV)f zb<{_8k5cS!k$dbTU2J<)Jsn2FF(X90``?Y%2o#%A`cc_&1@_nJSj2DR@~2;)#P4f= zq^EygO4|IL`13vO+_Xpqo%+V5)m^MFy*z~#lNww;2+Y-|RSpQ|keF3Z(C^kx&bX?1 zxZtk@bbWCU{l)D=+nu8TkzTl)34yChac&tACDLNJL_{kKEU-z$HU3*^b&@RcI5X&K z>qMS0)Dr~in^+_u;| zSpiKnD0V#T;q6`-k8*I^V^u*xC10lWR49b9)7mpuV^ZLPce-E?q~z&B#uf9_XC%%dF#l=d=OORJ_tQRn70{N|i^9uk z*yYpOf2v3X^BBsa^|UPkMyphQWj49?H(PRATz-$cAN+o=o*O_96E6v@!ju|4(OEdH z@G&acb=Z5=!+oQG1H}~ z(9=Rh3!gqxNXR9M{!Ri(=edSj<{@^d?PgD>ZZ>z0_#Cu5v6*MqCF38du(RieGpUwf zkdFC>>x^-k!PHBuB=>n=$NRb0dpn<}`ES33&(T&gfWg+1qwS;9ABgVmq#j%qSZSN7 z64Ll{hfAjfjl=;Hkb2H#gy$k?wSd(#H$#CGc)U!xhlDBm?u(E;7Jw?1sVoeMFU&?I zFwnqwsZKSeZsBL5>ajZ{gfgj;z`Z=$=GDKc$X*_D_46GDGmQ}1-YsGwSrXs92C@1ZBk zX4>)w!T_h$ZnfZ|>X}+2g37HIo^h_PeaYc1#GQL|ijWtL(uIB1{aQ_Y{`6iJaB}Bk zCGK+Vk^71@1B+DmjxfXt3CSi{`R1HyN2P4=Ra#qoCe6!hV2S;X5WYIEeUP?4_i`XY z1E=&>%iL$(ec~U=YjC09_7h0;ST~i7OUBK-3HKCo%myF-UKrZT(}r04HbztYqgsgi zIA1+{Mt81t=f(@6UI(tPz{`U%s$pI-v#eryN#Y(r&WHBxJ!!If?CX5D8!xaQ&H})f z?OwoS+EZ~8C1~S!Mc8>-T6>@7WlUACPB(H1+3ABguB+A|BWqe)iEZ6uE2qb#cu*8* ziwXr~1p%t2jOd0m5BCUvIY*W64HEaPCoI*-C;k9)oKYWP(IYxK25e<4<@e4PTK8LmkGow zoM_Ewc2r>U2r_zN2DZw9kGhbjEzbGkmCrDmrXJr!g2^SqgSQea6Gam*{#?;16mVHx z_pP|4pl>q!mWi@&Hh#g1JE$gC>d&=C1(w7IPeWQemP%er>*A4frS#mQaXIAlTrW6f zDY5~@=mx7G0OV?0sXCpmMW4ZihAo+O7lO>yO-Lk^rX!zpXV)^gOb#}7o>3aLxEt02 z`{4E@x%fbd}pbR`gzp(6sXMGV_KDwne7e$?5)m#Vu>-T3M5LSy!Y4}#v(k8rG?gW(-60N1rC7J09sZn_rM@(HA`jU zup)(x$lVFZuAPfA;Zd-TpOD-U{rE8s#va(vGOI126fIe;lo})!>8dc0kj3G}*4Q%t z^nA}TBx!KbLy;7C;HV8Kk4u8u;N2F6MA{G%gMH#XpQb3d^;Kgr1IGjaQD3G)$LXky zK?zvcWEl6z4r0meWmXIva14pF@(H|=;6Fur)TY|x9~0~EMyaIfTY2YYCJnPEPsf6Frw2mX@%>nVtCsQNrB!mGAMj+q|iJ(bif+1!DE#=AK4wzse{F9n6vMgk&kSMfglS%}ypb+vfwu zIec-_5;-16R3zEmi4*)XB^G{k4ieF>i7cnCL-rg+X8*%^;D+fM%Jg(*?4#uhELh=p zMhVqwpnkpRMR*Zf-#njrQIicOexC7t&)R^^Ye*1N077h??Q=Fb7=5 zer=R17}CU4X<)bvYYjq<0CR4*O#PCeI6aqP$7!1+vK0)i^O0T(&apb|X8HZ_x8H4v z`_7(eEc`Vl=qHl!2oL_#v3LgLujykxguC)n%nzQhwB+_UBM4T>!EENgqMM1455^rm zYKV8WlPt&m-Ec_MkfwVsuRg$s6_$g&k$K_O?rcGbvwd6VIWY*Y&$q{Asi!-4GdNk30zYh)^q4x@XVH~o=U8ZZVTY=ZrETrio( zE2K8>lA+e+GUhjvGPEW)di?{9=nyAo6_4^8KF`e}ezuNgADgqY(?%na)?P!j6PL>A zOW6+K*y@4~k|F~G9c-#CjFCd}b83PW1c%i4wFXB&bxK#kiU(hTek9613WhyGO35v^ z0obSilAVh;qCW&P4PbE-87M;$yx^&=%ZGbk{nUYd#4L#{P>FH4MEfBY;1>JzjeUON z0I#ZuA5J`|DR;JKk8`(gupZ8xTaY&U$B(<)UU=jwTsl+DpvB?}-6yLct6|iB4_GS|YhftoQI4FL!|4*n zKup(iN2JZGjPGdSCK4V5k%*G0tJ_UpBQMC6SaxO4HfOL%MW1udu{l;<wU3LO9Fn=1jIbSfh`005YFhWuZqS`y79l6eu1lAVBYErrg`s&q7n=`S9llZe2d zSA?T(h%!q_AyahK@e9Hx8q&u2E|YR^;Z9QNE|WwewL#}zyn9go772xg z%u(Z$c3TTBi#55lF_Q}do^!w5gYv%j@SLVW^rOP(|B#@#^2pYJ!DA+obq$YfBA|Ui zz3-k{nB^LZE{b6h+y%}VZFcq*;AL+Wd)uk9e9xAg0 zU7G*eg7y|fUwo}Ym5xV5L&*vNSccyC3f#he-1~ny_gXjT{&t(^P5gfkgj<;SBqDJW z^>x=QZ*V<@#6*?fJ~eiSQ>qw5M2QfL>WW3a6yXPwY&Kke74vMRivltI-d3?lJ9LNr2gl$Pwsr^@a-x1m~UW9m5s1&I3wm|*H!8jKNc!o<|a3!Y8Hu1E+Qoc3G1(= zN>=2Faf9uiJK1ReR>wK2*wEawJFQSJN$C?dwfw3sc}pFej2>1?2`XHX88z+zyD z6-nIPqSB+5fCHl%F(8JKRS_~Ksc7U3K4Em{Mu_TXy?^4}uIqwLxBKOaav#bb`SMXF z%5xqwv9;u1+pBKnw)*grxP`*A&KSI5SKupb*X+va1Mx7x;k`%NVepI}7L?e3e-Ha} zXIlqi?zda;K#?@|e^cq74{w3DadKquE1RAO$%KdQ2H!0VeG64?%(&wpeVc-_`H@*w z)`%FwLF^F@)}q$J`2?}}@}Q|yFcStklb&+H6zmEpu?UNx-pfOKV|81Xod77rtxx!e$yc>Ecph#r2cDu5nz)rNFF_}8F9zs6i9I+ zggCD&m9!@_QZ~FrV541dd{X5tOg1BSR_1Qua;ED3DwjS=4%Wf2ojGB9jO?FAZ0z%$WQP7`hBNtEV(`6N^g-6(dGX}tpP;w6YUk%MI8+~BI^5bv; zBzi$Q4W8LJJo&Mh^6+GOSrZ@V-~ynp4{siX-JEll5nb6&+ryS8s933Ib;keQ&i$b} zr^6Vvx;eZ+I*IOo$MJV&e9p~#A4-DIT#L1k1~d8Q)e0_a;60fY018ADeG$RSKuubB z#ll}Hu<@*An^uB3+YMm!wv|Zs4uE25M>ec^95nIPQMb}y4;X={p)m@MQvVm1F=S)u zyh0QLNvC*(r!RR3P-SY0eDI{=h=_b!?JSx^EUW6LaDKlSZEEr7KIrW%$ZWMSR{?G> z!XJve6*L#qXp?cdeW@UtN#szxO|AYB0dKAGo%=RHv}^|uNUFKSK?OSdX;0HFj&WJo zL$cSWJ78Uz(=R=h=jRI(x4Avnd5OsNVFoz~C7|RL{AEtO^ooR^S4*II3R5VW%D!cU z2&kFp7ge09k5LQEf08%|wu4kUC4T0J%TrA!mbd}~B)l~Xq_S{9BrR#c8;6uxrewxO zAYw24HZL>aHw~;8Fz8*I!cdgfuN~1|Z%;e>P89*uXg)7(5D(%-eTst~yKceQSBJ|L zu%?zhBV*66N-NyH!0sl#%TQBCnRqCP_aD<@ zIZj0cfGU_kIlT9AdtWGGk5>pr41|_f+hO1zvNj5?xvJQ7Dv|PrVG>~j%|Myrb7?mJ zAdL=b8x2+oV|bD3ss+An1n|)_Y|YG`f;?HFd)p$(mWHog_{b5sD6=zxi*@2gnv~6a zu2SAQUF_~yHJVC~PWlG3WIqlb>4XAY4_J6Kn2FQD2u+I0I!gnmCW~DM#j1g;mYR&Ir+`&5!|g z75I)LTf4!71U5OuXqo>V@d`Q|*E1GFBE=ZkfNbZbBqRQ&z~RAzp>WP`U-3CoYb}d_ zL z9eKa``RATxA}E$v6+;yRmA=rCa6xdq;Gk2pg5z86&ek*_X@QK7`8bLy4NeW57G|e< z@NASYWFT5q7p~-0!?kHL2c@uydy0g!B7(A?I^U9twzb&|53f0pj+SPAdY(0ItV@c zSE2Sx1l>Zc=@Utt)nDEstqBYC=NT2yU;Q#S)aNKu8eQm9Jt7{0h(9|Bpg8Ln~uQ=`4u#r1zmy~`nxKj>Mt7Z zK{TV76s76{g%*@mX&MU0MRbfs59(PYdi?3307vO?LOJOkm5+%~5k7O23fJX9q6K7f zZz2W+aDdppCPtZcFlat)c~ez>xcWwaGXKewYHSy(XN9GUgQL==SFJ9EmRiHAnT)jyu%&6(Xys2E?O>=Y zlBWi6q=P31gBpGu_ghOXGr)l+c<3F;p0u>Fh=rHq*kMpV5`jBf`V*1~ys-Dj>*@}c z0O5yU3PIvvJdU2=NbpfiQRMIjyswD&U)EdJI4Gjrou*w5KeoOD>;6cj_pKIqrbjIP%#+g(ytu|FgJ-007HA2D}mv9d|(U$to2%bUUKcaG04 zkF80#!O@srlvsQ&+R>{(m&I;^YXZXo6-*P#$GpUnGL6_<)7nk6MC0wKZj)=0P`QBW zu1Bt{&>YPY&T9@nPm~0*m&xzDW5dm!FXNS=-}wqOPza^DA=-wN!2dTVe~alv`ulQr zXdZBllB`rTtlO7K=?UW|E1xJir-_m-xfr+(SFr0!NCW0I^JQdo|L`=W%1b)@?z&HY z5}!Xrz=B&)XFDGMvR;@Kr}QHE%!Fw9>YDGjg2d_u-Ds&%7R0u&&c|k~*9*qqvF<%p z1=#u6?}W>_sYoX=0QYo5^`K{Xye#uOsqFOj@2Sa9z@?&+OZ!(X(aYIo3X#bbs?ms^ z= z=bEa(hf~q@$yHuX#^V+hJHDGc^L4i9Up(7-4B?meU#{CQj#xX`l?3m)2Hn4M%;>Xq z`(!90dH+y?jRR{5;A?s)!9_pU%C(YLSufx)-O4E4UCAwwulp%WzXhGVv`O#_*u7%24CG4 zEWsPn>?-B2zkV<&bD*#qlXWcI2Yf%Ee)xL*_NUuyNq4gU9|Py+Hocz8fl2ZBiiTKI zpBuoPVLmpVe>$8mXt^kg1W*y(39NzQEF|gRc)mZc;gqJG?sodN*ujNo)Gt&j=snV8 z76{^C3~vvg25>%vM+j;`Y6ZLbB7I8$f!(jXYLkwbK{-~Q&r2)c!R|P zcQ6E=E~ocDEt9bmxH4B$1}e>hn|?^{p;IQ!ok%G;2!f;&l6A8(_$mQ}Ca@IgbIGK^ z=}Zx;(D!H?An+`Ve1nRz7VZE=f-(M@ahtnsy{O*WPH8z-aR>4oh^y{|ARC zcyKRHje+Zt<}d8yL`VnW1RlCy&T^fwAcTcZ&2b-R&+Gac6=BHLIXH?%Rp2GUn~un+ z$>-of(sEd%a4!X%(A2Htm$Mfbklm(O<)95|7z%&2xY;0we&|p#e?!)GtM{s8Sb4I|-h@ zHZ2M5QX%N8M9^3jM~Aqu$mXP>1LMd!X6n#UWP|50Pm}}+Go8;zr9A5%qfBX+d~Tr~ z;w7t$u7|C3d6!$zpI0DUHL6m2BvqKDwKH?Xzw;(YeNIk|yL|E-{~_I~eSG=>?EjK{ zlGa+Qn{q5D5Li030)9N4QS%8&QW0m%T&|IRv}^Ug^&qAwl6|yTn%)bf!1;xV8gw~y z_UC;PPOraQnzhmbrrv5>$+?lv!!rQ#s6slr!UIFZ+OJRQrq(QYRq$kFD1&m;fN$oZ z=rck-YQd)V6AaCq<4VH*N@|u&RM;fTJJad1g#YBnl2#>wKCr3x!dMoIMr$sn!Eg?z z+_GKg1@ZR1PMIN_g6utd+wVP9;Hj0r7iUzO$7kK(H0VF5OF6qpD}RzA64r3)0TcwH zp|j$+R##-Aj@Yu=34DVb4WKl;D7@hdMyWmuS^D}Ye#;3f=K9ndLKi<)J=gZJ7xSuN`nZK zN%pKmHD;j@GxKeG+uJ&IG+KGx{$6V)d~!nLfz#cqMg%LXLyZ@{;Q2KD#Z=YaRQJa) zray|TMym{s?Zxg=VgXmexgN?gb%lKj-2FmO%xd1#uG!?PFID?i{SLO9_oYFl^5>=4T41#WC-Q>Ap?4Ftl`vVi z)6g;L)Wsat)0>JdpY(8SUU9P&O<7mwnLWa4!k^HipP(I@^z}Q5(lZ0%o*w5gU+4DT zpk?AAO2-{tlR^|_Yf=tr5lE7kpMnjC5DS(GW>E$k_F9ljMkJL?KVZRVQ99S(h z>55o2(dg1CYGUU8S%$u?H(lu)_tDKfLLT`1M`GyTyVeEqG%-K!=a|t@=2FZSIrF1y& zpc8vd(qAuTyeEC&0-3zT*DXK)el1ApK+VO{FpBdukruMG?8;^b;yt~}M zLj0&;BF^n+=ubgupWj1eFqvTrFhit5N1Lsj5PUncBv>H5Y8s9%``4;}c6?tZ9{I}m zk0&#nPrI_d-W+ukbF|(-G3Njs)gkOv^Xh#3o+ffDHXC*w6ASR#NaV0{;Zcn&baMl- zf3_{J`8_=Gdl!HQ6)IYM+oWVZuanWlU!Qre2aS zGYuB|9;#(r6FpL0BDQE~a4}+>epfW*VFYkgpauBvc%5HpuePzmz|I8;lG6w2QxCya zs3~4ZHBNCEIS6Wsindz}Rfkt%6xWfSk6h*vD#<0r^Z@Mbdl?CsVRJKdevI<44r$*L z{wpd@JQ@v33Ta;6R_Wlw!!X-EW}mC8+o_sG6Lb$Ip%Dy(zgyeb{kZ%)YtL)lPn%iH zM>}AcdjGcK94q;Eo#LPjZ%7YjOrS|Zqn&|&D#QzBq1m{dJd2g&vJ=Y16IZ!@3dvKy zqI441-4D}+L$11C0!q)F%wrj!po?LTiBi-vvuS3@AJ5anennY#k5{zoG`87aeruU) zQ)@J;91z_w#A9=G<1aH(>wmZ7Pqokg)q=hwDaltOCA9g6FXO$a`-L9TXpx#M@L|Wm zN>(m&dX5N2PZkWCrkEGvlkt#*)XsA-+O=0F>66vtl6kqY}t#h z@v{1A?|gHcYCrN@(0$-#C2v8H0 z`x05kW{Uq=-{TQd_b~$8Jve{>oar5el+g-}v;HX9r2}%I5?mRx8^N)vvh{dtZ<=O% ziW{O!z8zHj*$=_9>@-73Rxe2dAuk)fMcK$q_K*T=ee!5Lr zD5VrSFCQz&I5GVS&TfE}$z^k&8=pj_62ByCLWi!RtfEFcCJ3Jpg9LIP;3_FKPC&D?Mt;;1B)>sMXpa z=iX*oQO7G5+jMTboqB{-&2}F5;MVp8YIUekamG*~VAM!GFO%~loMEo7ev$5!hNuA2 zhpMfBQUjLgI##mE)n>gZ>|WdM(%NlmlV5w?#_#RdKG?bKz7UJ7tGk;S6a{7s!bOMu*a_Aq^XIpvC;(NIwDB>Jgu#I6F6cK&1T9lb2ktE)er6)z(6MA!kf|9!;my6!Y zgxVbV-n5k-2Akux$d4hCnXI__)g}%)kNoklZrbJuGI*D$4d<3(MQ-^IYlWnwy~Ai# z-b^miTH9+}Ar7ID@lD%h@u`z?j&vIq!@i2d1X{qefz7ut*~07U8;Hi#eVkb1#`HR7QWwKu9zAvF zq&l4zI~xhQm)CUNuBwa*1&DS6WrCcz^w>B%UAuGx$l9l%QX+lUij%sJ)0~dul`m0- zi_co=Vf!e6%Ss_KzkO?|A*_2?! zt%A(Xca?i8Kp!eFn^(DYs#gy^=Hpgu&}m#=U!9S<<-E2$erVEor9A=IbZZ^w{QNlG z|8h)B0$~y554Fw%mELNbq)W-xI6Sv9gPUf?^?;iC;eXdP$f{ z>{Vm4t(vW|DWer6lQ3h+q~%QZod-dj^@G@@Lu_cPyDg1KOLDhlLA5w$i&s|;6Ri(( zw)c;6yjWZWj@CciZ2W-o3@#edJVP`ibKjGC)^XF+VfrPkk({#vjI~(4v=kvG9fE+c z`fqZ!G|m$JyIxa!z??;4(e-!imT|GnncuQHyJnyREGv68R`)=tVV07<=L&mh6xO5# z>;M;mcwL>%9SzEtRjjDr^KU(vwR`xkhY5I#IGlru$~gdvayS(!6smGjd?SgyR=d#- z8Xh_VyTAU(=5n_-eZs%+qOvJ#sqKV0P0bo~r0EeJOCr%kRZ?B_7U(4{1$A-JCS+q< zN!oxmG7`(}c;|Js`pPX=wSgxdPSS?6*LiA+j@NTYGTD~v_n6!tjuJc)ffSm> zJTTR>?8{Yege=Ziw7Nf~6%QO$!V&buBdPFvkluWqEOHyHHU4w5N%mt-0_SGgEaI(K zd(cRolbcaL+#dJ(J3D~C0t+A)XBH}5Ik(A0tBz8nS@H02;VbRYEQlM`s{&1CXT5Vf z1uD>pwzvoK-lp7lpBe~7VyRA~PoX|E6AMHKN)rA_xh&)sMdUxipc}hJDCwf3Y9EwT zs`=<%(Chtuc1|x8(ZuewOH$7^=cl>0H4u?(&@Xr#3p;aB8>h#VtWz?0thUdj5*8cL zjrW;!yH^by0T8A=ymDI{=7tz;H!CokTW#O}gJ~!9ut?EVZ)1;td4jwIjsUN7aSA}c zZB1CR-vwUj-Soc({_?2#>*iQML``RjOT-9-nIx5=O&p0%2k%Ka=coM`&L{^yUAFRm z5}Gai^}l~i1Xf65Q7bo~jSsJXLDXY^M5EuAO9r*)){elDaIiO!-V!a~m#m69GQHNY zY#o|Dt&v$e2)L5%B$JFpcWzqW(Gy31Ai{R&WMrP4a zg0l|ug~xv3JGAE;SsQx+pHr$s z&T}UFWxp|xv!^FUsQa5Hm*4t^+HVw|q)|n^XJShLT06_^0}EVs@767iRwkd}DtS19 zCh>DfLhcwp`kxBpVn*cvjKeHd2MJyGu$}5cn8Y=3fF)tgJ_jdKLaZRO=UY6=Uf%Kf zd=TNE`cP!)xX>qp6oFpMS}8|9sHB(y3Xu4sq0BkOw5_vcR7T5m z)r^bwiYp=i0Kl)US7rgNxTgw3{vvRql((CC-Cu$2T*AH&HEa3FXeZ4L>U-6NVzQeSZ`_ zzgf#ov(lHB>wI)AA+N{OvEK5#BYwZ_-{*jjwW4v$ys)SxZXp3n+4gw1Io``Hfx3=s zne07}?rDC*e7T?+?G#glc>Q-v2S?`9Diuv~6OLdIA(de@TwBq+;aJbtz$W?on0Vf> zqwyoI&m4L4FdtnAz!_a^rQO@}wL$%7PzO+zidH5pq5c(i#45! z1%WQpF+&$bI?z;q&5#yGi%jWVJLdkuluGU+;0Nj{l{Y1p(9(5c=XaO|yuVN4fr@sU zj93^&v&E;B4|v|tNe|SC6I-My$m(^NZ}2-$F{j7ShadJzaj%41M{wyl@z+ zT0h|D_d`&!S-(_Up*XK~AkG9>!85|37g4%eiAC^Mx2-k^V1p^-kuDeU$HdAdf=fdB z$G4h}Nu^|rnF^mVC80Q(%FQcVfs01xn-EQ|bb!XF9b%`@F^rREhwM9`PEm1Ili>Qp5 zL$WBlzvLJ^zi(D1ro1{GyJBuV0dFu-8LG5aBx30c`bpZ+er}(DybV$nUTIHskTEBI z=w9v=OT_p)8r^D?bfXD+A+l9@cvs0`#9Bv0*!013oSuTupyGvHZ?sMm-gt!cI-=CE z+a5jpK}+hpw@F??a$Pt-*gQ(Avkqo!W8l5Rd~}X?oG*WA3?h#O1@hx=}@VmCD`r>gNRjxG!*u-92>w6$5FK{uVIijzR*b@ChU*8h7>WDbM-Ba#j@gx z%py7SBnjz4E_$Wp){O$T;LuM7x#~^wLg!WX&Uw z2&OK)%JN`kV%wOC)C7uLTGDY6b#+Xm*O{5TT%1{5GF~RPDZb@{$D*l-#;9WYYpJdO zV`}=`><;WC2N%@a^X}ZdM9iE-Tj1fENxm0^n#0#Xxtm56EwL#nIo>{ei3I*sy`*6Tv>R86TkJ6dpV%aLGy_`K&Cti?27@y0BKTgvyWguf}46D{28|I3WSM!*rzjoSH zYKg#-npD5qKreFCB3`J8l2>5KT`F-L-4nJR?rj@&>2h~#d$nz$$xUP(d{Em zsDLVg(FzgXiOfRyH;cJ9kH79$$W@pX#aPs)z@o-uNM0AP=a!v>K7a1c5!F!9x4jaQ zn4{cGS0TfeST+7`+mkbaMUIqrrU2y%c|Mi)dWfTrN*PgZcCdRwveGW<1OCV)k?tJ$ zKjq?z*6@829-R!Ik>LX3jIzL}*YFxBs0Hj)gqExmgOY@I9*YKByd)ViBYgxWqUGpm z{s5`eWL{W@qLVziDfTcoq?%=$L{zq;DqRc!BBy+iTAHf;MsN)!iodL;oQU~W zsG1Df6t^zRrM`~LDduCsE?0^X&Il8hV3@kOU(GAh zNbD6F*i=vS;xDL~3*o72oG@{mp_5^e{sN#^qmSOFRYN6OY@k^pF=V}^}HPMeMY zI@X9)X2$Mn(U0OZHt>w96F$QF?9uheJZ-$8nfPs_-Fw>f;)w>Kc+qbEaL#j5=lP}9 z0jKqNexbZNw|D>k#-G?t^3B<~Vy*voEAW?p#P}U=z!fX;6tQN9S$I*M8 zGCwGdwf-F2)ci*wpH)1A7FHyl^u9VYkdchIQ}O(j3JWkXbnftz|r>0u{Gsv zq(DFdV@?azB^AqMb|5=%-}l-dbx6{c**%$f%i%A5u`*7hS}6JaaYkHLM2ciRvF3o} z?Ly8zk-6iST$kdhyF&%PU#)fDZ7Gx#rY;?m{H4lA&#a~~J!b=XoXpvUmFW)zF7eg( zjGgBMIrsb#3;vPp4az>f3wpi}E>#H*XLxw-RMrT!w+n~Lue2wMW|0!*jZ!H;<=BQy z7`Kb^TL^Fc1Ro2;xI9m7Iz*E))d?Ml_}uC=tYZ1od0phb57;$%g6qP#yKt{DGible z_jQgaMydc4)dD=Y`b>f*v4Z2Ql6uVAVM_d&0dm86pB+9`eZVxEB%TZ zV^3iU(Lexk^bB0S6}(go3#BH84TUkc1Ug{}&0A@xByMQhTH!CZ2X(9hgJwd>K=#@E z`xtPEE^7Ilj`3GD5eOi;hgH!CDWL0`9zr5ne(oR@OEJw&Aw2Ex%V)Q>X=obHBKc{d zUFoU+!!%({t?1j9^&jCH@IUaEB?<#$OYXKR6J253>)v$6pea6Pqf5Z|A#O%#tw<{Mcgld8M;^gFwJn5M)YOR&bhb48HYJfgZf; z2Nr_Si4{;FxgLn7?u1E|IB{Z2nMY^RcsPNZTfO4Xp0O~GXpFTm7w7}D(wlwx9vAp{ zA0PPW$HZl4$*f!U zLOtz&y|>E0`ebLq(|PdPej)wEo~i4#P(hZI zwNSq8b7KGW5j7qKi86d$aCtgI3yq-nj=}0;FHk>XAwCa4QvrwZdMMzSQ+gyuxmFQaiANXf;K6FyHnQ)%}Qc@gZ7INez9DA)|{l&MG;ghcI>=5lfosyu5kocGgGbSK||r?QBfR_kX(s{ zOo@$}&zA5+;M6d(?0XN*=!>bnR!QPl+y3W|k$2xpS!T^sioy|1)|7K?Y4MyjV~_vW z5-KZ9MbWb6W(7-zuD!sv-(=sz^lb-}XPxnkO8J$6+tGgU&cjg$0pYW!P_n9P9~2me zGyRZ8r;EF%DP9apPf*C9S{of-oPL!DnC1x;Yut9BdwWbdcjk7!eJoNBwB(5D|iu6tAc z)GCPgEMs`42R^c>c*6=0Xwing2ouzVHF*3dnj*{F|BfVp;6mSERqbi~DhB+FXy_>_ zmyV&C<{m{+s;GM|Op}TEG6%kw3x>ElgMK3}C|Tf3qlxYGWRir<@iX5fR9_o04vzY8aIDKKg0u3ZIl1d~EZ5g`6_$$heQ z6)~8Qk@@14k5l8cT3PMP-q`m;N3c|?5!0QgUP|YG|84u^=7+ zlX~fB$uifV5}LDK01c0(z7s));+5F*hQ$u)P;GW6;xZZ7@f`<&n?BFQIR8jS>7!46 z7a1Gt*%^F#yB7{_ZlcF|3)mmnPTq|Cpi;L`A9W~)?>x2;G?anm{kHg|1fQ%DTQC02 z$>(sQ5NsDirYwWzxH}VD@5PqUtponj4@yV0_pN0%JR@)gEZ$xPXB5;+QOpdFm>u>C2ODmXRw-f|stB^|Iuo zfy5Ydm7N*dCMv$sS#2sNo2c)sl$8J$D|OnmeB)Y<)y&#Qx4y*$8XiY1dIK@d$V09aYz2B0(?iso{F~42M`ga$O2dTP#+C+FES5QzDdoHEb$`kvEZq z`BgJcgB*az5;u|QYB6l5mT9k!LEy4_dh45wu{qxu83~aHMXTvbj-gqxsB(W_);b6h z<0q2ntfqkuqh36061nss3K6R@5iHGjYJuDZs9QSH5NueNinNkhqAE+2B4zTqb!Vq@g?mzGcm&Y;}7&wr0~1vhy( zG4fhFnh=A^pgnYCHAEy;qYHw5JgrX@&-yA+y%=p67|a6^ZcVeI%}Qf5x|fR>T61!P zaXQ)=5U9+JTv6Cd zWv*p=6=5ZjE3%s{bJPl)4p@vhpSeifOkqM>jz-q@l1uT1LWwM8yw!h?468rS6tL*D zjs^P4+kpG)Jb1--I{CHO7pk~pz85k-um27;#+exrp;P})k~Pk z(1DR7=;%4$I*>}=$X4A%07cD1`!i6hub^%;V}NAN*vWR`&l{CF)Kbu=+03YB(A8pGs!$Ojvf4_ADMe(9wW3 zn}LK%6+N>BTs42qn)EZ+*FXN9gZx%ACUdv)kf@unDY$;kA#OFSx0^*Wv2SOrV-yxv zf&%)PrxHmknVHnW1+^BNNHJ6c!+MB;!qJCL5i=MWI@4yEUTH##e;IlmG!!tTA!MHfq% zrl*`KzMNGu2eS3Qup05A?D+k=tUb+W*amhNfY<^}C)cjjnJ$dTR6$|OqNwm7%W}b| z;buA2u{AfMXc(c(0D`I!0i!f0uKM9Wbm2u+B@9Q^NSU>AZ9VQf37*6sglCn*wp05S z6kz=yA=i+?l5KQ~^SU*QNIc@ArDusmd~-ZJ&+Y404cBMB8Au9O6ZKPgR`v&}zaCtU zs`cMm3&ew-Ww#32$iUM+$UpQ>{oURZ*?GAm63}=CzS&+GDy8er-wjlJg0V{B@&b-F zv!kON>3idQ<3N5<07G>1*Z?nCAjY#Fu{YH8HeV3L7ioFpEid*~-dKK@C=HnqE07wd zf-1=UNmcwH0*=0_Sdt@cMkn(+K$I@f`Lp0VcC(z?qc5Txg>XIc3)LXB&Zz4Pc<`I3 zNV^jUqTkIJR`f(OthC^4?q`r(ZBsx6cUeHr-@zLLKBy3ls-vk9Y^Wr}(!ifll&cD= zp*}$-haHTYoE4y}fcSESM_>)Gr(VUUa71YJK`@O#Xc75!LJvFO1o?9k@_Y30lax;X zkM!3~`CGLd+op~McV;10ACIfVPcF`@k5>Rpfn?!4_&jerRcuB;;HO+ifwx5{#=!29 z$30a37y-;l$I=1};__cJL~Cv$y~y?VQWu1`ALO&vin$e8N$F%dvLDE3aYczH9Ue0D zw33r}YrnlN!y-Tc(H^{15~Dl>{Z7)f4%$f?xaI*oAz8HdBB}WQJP-h5gikpMT8Qyl z7_V&T&g46^6q*rLis4oKj>*)og_=)mXXA8#R9n)B1NtEsH!8{5b6+@!e#oUXi0y{Z zErhBNxv{z&EN3+EAm)!e{H0V6<`Uozc(4t03(d%1cr4Lan(oodea`(`lu;z`;eWmc z9yhUoE4cxiW$q)7Vo!uba^W$(W6J|Q9!Oy=5|p+Q-XESXqsK?fS}!n`n0K_K&?o&X zOZp?v`fc+bAmN{xrz^`_Y^3<5EgY&TKE-p>hDK`!wba0iQ3X}9H#kr8Y?r6&840EX zYlZXNL+l4fhn<0~#)JnCoK7a4T9iEwRDtRz^!p_>S-ySulbrt2QD$&nu8mSeDiqre zO*{-O+B{v`IijVd_t(}kQ1;7PQM4YTiwIr*DT_h}XlYw^ca>&|?Ib_Tv`WuEI;Kk( z@^p%e{BPx+BFl^|dtrob+h@_M<9wvHtf4VlDRKlML-=pMzhfLgmihLxKG90xRyEE=>%Z^h(#5bfhG}HFe*M3XYYJ-0De-Ka}gx=PD})f zzPx=5T$XdAmnOcXhPrXJuRy@{>`3x$og||*yz}`56#A}x@h<8m)w~Zr456D=Q}oy3 zp_xhNwahyXdH$BLDsU0V@QQPduS^4$6EuVBAUz%UGf0qV&={_)7K>-C`m#_b*i_mas?(GE^%|9dBOYYU&AR$SNTMtiHnUPNh`3)PbOejf^JoJW z&Mtc;?MVy|#eWz6DkI=4|NS3Y^^diwb=HdiXiIp)(kU3l+3||-;%>>L4Wn_rJ2)|$ zgZu<}t?;w8kjulgz+0n$6b-k^#>BV#c0~7T&(}I0Ih*#92q2W2@>od=tVU0QIA6&E zZ$mh>NF1i17WseTuZF@)M_!K|Z(dI^)08cm$%S@1V592yLY@Fc+ZjvP5gfL@xlbXR zz~=o$dT7^E?RCAtD3hkD8oRDX{PuYK`3Nt+lV{TLA zX(~b0O{mO*?PbC*1ZT1-!@B`O-+iAezE|Uu6@p)2+-(%G=`!?gd>CbQ_DRx(GIX5% zyXZv0iB_X^EDDhruz{Kcr#}*(O;||#8K1MLn2Ww>$s81wr5!@kq_gd|q($${-FRy~ZlkRFcegtr>}fJL*|D zH@>CT*j@sdjy4olC_#%~Fsa&P%BC~FgVTTbab=~I-q2V(jYB9Nm&*=jvSCQqL^Hjm ziVzAlhaURek8sK)RI^fYeHTw)-F>VLS(qFemkehx4%8Z54<5BCnB&@R%5455NI|d( zK!DV=3BphcOYE^Zayr^7VfqCaJ*-u0luh~Lo4I%V2UlHFQFr6j(9#nB8DO*991}sOY3}riatW17?r( ziV_J^d(l2^G_6=S1jv<)grDxaCdP1NmB&3kS%)QTzU!xyMV(UnErE9-~8Te{d-6@2CQYQN&mB{~W7q0Hb*p8|s#^dY9M+z$X!CWcA*jpTbQ+P5f z_Vd04&S!RSRXiJ=Aq2FondqSWFTF~BGBdE#;hT$Ow&QM*DS?l3?<4_zzV$~5(D}}i z2y`JXD3{*woHnnUo@u_I<9DRL2U0YT0{^buz5dCtn#PDs?WD-7H|l(s788w-5F$c1 zd)SjW;H%$%J;s%u5nRvMX8tX-Nwdf1Wl95@ySO`a{_s}UKh;KlJQF51{5e-C9b6%g z;Nj!QU)Zz8{*wN9h(@xp*{S~arLTT4(^&uK19_ER2@EHg5=!dd?*^r9acE8ZRtNj@ zd*{J)kF7Zmu8233tx{sA$kgc7R>jU1Z*?m$rV9NwsyT86l?<5?M(kHKFhmhO*_c|i z-D6hLWYy9?j(mxU0_gTx7yV$ue7P{_gl?UH-HwSK}WV|NN}W z*hvm^uKXp_EFV9jG*nsxM>S>2bFZ(lM(}Znb116J_nkG-5q_+BoT+a6&`~+Ucpzpt2OF_2#p}maJ)S< z=JAq^FhIEoNmSamy@Te5D>*<6r-1UA6?r=T+JN}yPjxObg~*J9Z|gI6ry<891so2n z3_7@QB-q^OS9adWnWtBw`~1ycG+H`Si5)!{U8)I#wB1`fXw_HGJzsv8ip0xaEt_D7 z@j8SPk;_gyR=^^X%t$O8rY!~ZCUO_lc*VBiYei}PLOHnV+Fq-V`~%xvriM+ZJ{G34 z#9h;=76Nf`7f}l#VPZAC__~si?2uvR1T^>Tc;$MmLKM9F*;@YddcMJb_QC9UL(8|} zXqZE(nB_MM=ay!;M`&A_u&l($EU|nZD{a_#bZw_hPW41a(NFi9GIcd+bh0^x*a;^a z*N>nBzp=0kHA@PPomkleG6odtOz@(lYR*!W=J56)oi=9sn4|5x8nK^N$=rKLe&}?( znUOWyKgo#v(nemExm9}AH#*#N9_UP)`}#GYf1FBoRkO+s9@mdRDfWoO*rMp3^pdk0 z%Uh$U=c9M8nbnjnCi|&tA9~teUC7J#V6fyQN>|=^Dt-79zdBmK=_E9~bFmnSUNAEgj9ASgeqY z-Az=SB#eD-FBy`NBjd+KW0hye(h(d7bxN-xyaZ=m94~8#R(_vy(WutRaOLXL<07jm zeKEn1&ky@?;?I}g`aedn9Hd~tqRV_5 z7}JZeS)_j-n4SStY!(eY(DjJPQ#)y2+F^vqy7O}+#Pq+A2 z`a9E~6PEsVtGVgF{oel@6h^9&cXqO2R}lln+D51lGAgvmg`=WQH#A}wRD~;NojFdy zH5cxz5obh9P|xXhI95LDeT{>XA%MuYD~zqjaso>#!UXM$ZoaIJjFp3sfv-U<=?Scx zzS;B1gC9${X0nwGzzh`>(9cra=WHuccR8(Ag=xV8NUwkJwb9#9os_HEIXm$a1wu*3 zy-pNcoLhK((2Bgh-X_lS9F*{SqC#ZuqfELWSi!*#O|C+Z_o-)zGpaz!6*#547G}nV z&(yqXN`d32Kjg@E8BO7w6s7!jnvfEUj}XN2@IfGKcq&^mc}6;7erjJpb{+uoEI2-|`vpA_X7=CS`>9kz&&m!Vv5y&DtttfE8 z*Wv5$jo%`3!INiAEkv_x#Du&+hBBuHw{4bdxVzxDY7(I60y8j&P0=PXBPp_y7_hB< zyc4=snBKR7B$@R)u70hDTyeFJwu;c1z0G*Xz9BpP)me2T7lfLq4FO9KHzn&=By3Eg zE!I~>(kKr60X;}PW0MV#QqBFl*5lN)O(quq+}lK*#R=dAIrBL*r5ExqIX8(=pBFCF zp!^x9OUzs>f-V|k9D3}w&eIllcZF2?)PA(m-Q(A*F`B}sZvE%!lFAhS^LG@=R5ZcU z;a`JaA3%5^`pp0h&*pTSLn6V4;n$J$O>gV<-;4hzVIkVtfHX-a!Ac51tI!k~!vRF^ z-J<9ZmQ>?qOC*{sbbg2^UHUu%jGzmD|0=Y|YwrmU9r*=2Tyc2P#xK8E0v|$xkpjAT z$~uKG%U__hJDvuT#@?vHmfksrT&#E}rch;vbh{`bPg1-)^{qotRXT?^vK`|WTg4eM zKs7lydw7H&8G1n-Sl6vUA8isMkO=Y?LNrNoId@}~jytA_{UR$+T*&g6h%KLrSFSe6 zif+MO@Lmn8xJMAHHEl0+7<~0XM`a)6;Q%9+Bx$d?T(>lGwH$GGa&h5GBzO6T{|v?Q ztXc=nDMAf0+r6_Ee_Z)bGqiMLW1Xv!9aCVsnaN2&(tT(G^g^@q+7xsp%&P31ZT_mI zEGRztAJvN;%tI1o<7-95@7a(WJdNK!(<~r`?>Ka3D1tLtpqqPjLETu^dsGm}={&%8 zPBWoHcSA!9aZ*c@Or!JvqzTF=uvlgmj(090zDirjdFL`Ojq4iJ@bI=+AW$s8tyQ}v zIO8Kk0$_=<8^XO?3Zd3hozZQ<{(j2kkL_HFH254XY=(2L^jYFWt5q$JocHi}SWn{P zob9jW@wU{z;o9U(YxpancN%C+GWJh7&39xjDB2GlETdP1Da0Ru@OBbE8p=Fkm79V! zx^<#dfJCRw?>A%xSyCbTZ*z4A0w1@(!tXFSFiO%s7Se0l&a}`^O4}dxX((|cosO2^ z+VBTz_c1RCINDuh+uav-reOCgj0xEGy@t32Ob8l-X9DqeV1(s*ab!WvBSEms!cb#M zyt|3iScZ zM)apC=gvCkj$?(gE2O`gco-gY=2|qn#9)L|sCj-OfeYQ{ILf-~1#CWxUwJPvh5YDm`=y|WDjc@hM9+29Cr$l`3tuebpAM;~n z%ZiqfvL-7w@nT5|)3SZxXGk^Jv?Q~4Ql3)OyyX5fZI3K?wFpfe<1BYTdx}&7=P$dh zP&qn9XJTEChg=#0ob(P2l$`gj$^=KoMA3`TMBfa(^lqyrx$;3$3!PV^8rhnD2RYR4 z8?MKtVJJe>r`op28=Ry!Nh#8uNkgO%!eTQ2>YsE8P?$}5^qw6&c;PQ!{)cVfK*?`? zNF+<<76NyWLS?S)WPt|I&k%0y-_R>gn!ZmSc4iRHg&v9S_(jpN0OhuU$GrgEDn7pQ z@iHhSjceuuub0hK+)nCA=s@tOOfiYL=a$?7i)+^V&tq1l@RdspcKiEB7fE+Q;G;4s zv6{`qYyZRRDURyFnU~VsY}@hu6+t_{P`C-6eO6iA!jm;e+w+&x)QEQp`k}lKEr3f| z>F3H9evF{gE5YisiinXrJ5c8yTbLoS4Nl3hVV1@a_Wgyb17!5m0frLz{{GSLpJuvr6FMpW9W4TX6R=b$HZ@QGsHD@lkHe{lP1N``!4B7hG%7(>lqZ-BJ*y|lymub8T6n{ zeQM#P*_BZw!tL##KY@*#L+rX-N19#wOE}vzo~Gj0(!3jC|58i-L#O1~d&qx4 z|0l%W?#|yvQRb?Hbe*P{%rS9+%s-Uod}Jc= z59A3KkSVf*An0C!{Fce~5jPB%R>b^Ua#oeY$alykY&Z-A#x~BEi+dUjYM0=*e|VLo zY=w=>k~Q%J_i;cZx*#?<=HJq43&duJo6qGRP1I(Q!zRZ#Eqmo6Gvn@nCu}HD*q3W2n8jAx^W7eC^M1{S=F;ay+9c7O~@bA z(Et$S^d-N@sP(vpQ2-^mr0x7&!t+kKcL_KR zhc>X^y3TgW|%P+SRB^>$4rLyKKl_K~1cQ_M;pz zKii@=RwkWehe5#%!6W4qC&M_Tph(l-{%Nu0f4Jtn6zC?rr_KTe4}_+bdkvc$0WYmA z^y{{9a%suB&yG7U1BELOsZhp1Om$2*rk>`+S#=Rkzl$E_Ev&&v=GtAQ72T_`@cosA zthYMEi%8g586s?UWmvJ7kpuzX=|TMBldZv^&~aL6+CJfP&Wfyhx@8rfT3KJsksFol zU>(aSXD#EaZyzHajZmnP34gdky`0+H%Cyb~m}8jA9`T=kS{|KmDSd@F@Z@kz?vUmi z^_oFij-khqKtuac+N;A6$(LM^)%m#cfK36Q$je@^PSug4`9VIy5|OiKyEmMZ6AyJE zMAFJ+`c<*@o+d+GDj-_YQX7qb<$+|c{!kOj8>Z+ftXSCADgSeknbv1XCcl{(vn#@w z?s7;4nD{SMOSf6h=auwL4`TrJMeXwK$253B;C*B#=4tXQ5>M6naXrpiNyY${n+`?? zUU?;HUq~}%@57?c^Gm?XVFro9u(mD6lLO&C`4#VF=2A_ znug7=V^(t5l5ke0GkY*`4aF9hWj9e|VU;2h#ja-YhpAF0z6vo|zC~f^aJ7SZ@;ZRW zL%F1Mk9jz>%9iE(5U^s> z<$oK$1APHahiGI%cE7A=ypySQ5GV7DOv33V97&{MQ@+~Z^&i-e_>g=QeBh$wA}8HF zru!pJ1~!PljQ|&4M7MWFBL0XfpR*;@y~qQ`kk31aj|xLa&Ft(rQLesjT<%W5(#gI$Rzx)UD1u zM8r7_Df`~CL^zjM(MyZ&tkpVheZS{1dfD)XW4BiKt>1Sc0p z9~=S_34lqIW}z=)j)wR^1qXr&$7&l4Ym%Bs#ofTLHKvZpqEUB?+c_`mB1mJ9#bOh0 z45)d=-;^#-JAc`QY2|f}X<33N4cky`Kh!Bn#pDe8?-GUNg0 zcf!^Yd(RHvKmwPEao^Xn6K+nHiT6_sc}IXhE#o|=FefVGB#_SQMLfxx*C*h<$ z56rwzRh5NUS@gbeVuZjLgDcSr2EbF1%FOYkKmH9i-==`o2nK=vfW7LI8G^-`Lyh{X zR|EIn*UY)u=FP)WfLPbDckjW8F}s=iU3QEZFoE{4OVg-(X7RJp746O7JIIP{TQki> zf_=n%gl)C$3xDL;8@K(jxgGh`{R-wK@qO=Mf-C$%LNuxLulbCi97DzLJ0LS27;_~X zj{`#GDbm#^K7nnQ1n+BvU=wW(M^nMH+biT3rOW-ehf9t>xlZkGvb`ZNq9NGH zxmI^$$L!N+)&IMqOyBsgB@IcIVPy`RelkZ0@6(4$5sVo@1sU^T!F>RQZl@JxVngci zdd{Om@?}tSzA&0V7d`S{!4_GYFT#K$5P3mDs~o;#8Y$68-^lm;P46No&GqE?RjV;T zpQB6(#(n8IZh0*__Yj?UoH6-dRSdeBYzgneX-4)>g;K=jHc6)1F6b99g6#yT56}?> zQ?Qhy>@ra4O!s%0?e(#e9L}qMF6#o@W*SR3A+ohGhSYW=KO=Mzzw0u4p$0+fYL(NNgF-zlyKEyjL|{ zoMl*3rV*?bHPX5fZRn0k@Q^kPMqyxEagF<43d2At4mtn5!Lvd;s4z20Dc30c5l8MUYVV@Qi|t9sOeN30XfIWcvol<{+bC0$FI|Ai zndHOU?a5VL-Jpu?Z3c`&IBd~O>+6rEO9m(V1r?NDSWce%c!28cRt3Q-luag)GqvU3 z5qUE+;pFD6Qz~K5R?APDSj7&%rPG5p|8+isCtra+{m>l`m3->>J!wBBIEJRW2{5;L zn(WCd2uY@7pf;>&k;h9Zb&XnF`V=rdap%{t+QtC{$)a1y+F#4&!N679XDjt(A6%`C zo;F``HO7TQ&px)Kq#*f4)ed61C%cIN$vcEqq&yG7bIzk1UAi11ljn+`Bx-1jm-idl zdvYL8^-#;Nb|3g*YT@SAe9284oku_EZp<*Sfs~@amVFuZ)G>luqtS`KYa%!(9 zF4VfuwphNyokpv!JS)gsw|nB5WcXa;#tCFi#}ud$$_g!m)D6h;4^*<9gKlQHZfDhlf+zifHxYst3_^bHTVA@=|5|Jv``zI$!D zW3re1-vl5fUtg^0U6Q9ehEKPLP`5Dy1Ij%@D(ApPdFgW6ti%ie%lPrmiK8yFQ_vJ6 zu@6zZNm4mBIQW*+tg1D5oA~y(AULZKKjW_d^L_;Ovi=mqr^EWx%qZCSm=ad|7g?f|d zUjzI>IBBk}7ci%*b2FEGM{}V{#A-MsArN3!;O-&shu=>`vG5~}&3(!s9I`4~NFM0e zM>nA^m`)rme!t3`J{sE4lIG9!vu4UX)41M-sxK8QVTRrDkBPKK?|PK%-$k7Bp*ZLW z`IN$SA}t%x?MLUZG#q8EawZ_aaHC^<%hVa*bEwcH#zjS;P{l2wP~KD8d&W;~(gGFO zsQBJNWWJx7DC!jVaLGzNoQ~_EH~o3x5y6{M4t}T_QW56)aZ3KFA3sWI5Fu&Nybk5! z+DjE+J`}uW+}HBK*XezhgjTI18;CH{$7>UZ2PF{+QGi#;35s2$Kf3N{sF`e<_Irs4 z8H*y(0!BhPG>R%R`^Y-GSkiQh)e(BPdfW`Jm9wfWsnSmV1nOm=4j`F5U=dC zZWq951=0vx--5O>9L1gS4i>T>?!0hK!v8aJj_eHk^m9us43-_A>wLVMGpO58GDf-x zRAmRe`|_5z7Qn!(xRTm;WR7!}awQiriUYUqzzAkIZ1w^Q}cFTC=hx>6dT zWh&Y=gHG+PJRG1r3*Fy7(`tD1wzOMlbeY;zSFR$)8KUzi8}T=~opO z_Yo0G#M6V#TB4@^dv*b3KKCR5S<*)FTQ9(^?_Y-J%q3n)Mu=#2sP!VH*O;~43Y_ib zR!lV%7BxwClA@fs(NIa#JP8Q>rlsQSo*h#Os2u1FVBlcNgJ2c>*Wie}UMY2GX7Fn! z-)~DyIy)nr(zUQw0WFUo_>)7vY43iX3JMX-IEw=~Ob(ZNS?@3yYUZuo<+JXeN~7oy zU*Lr#@JJ7ZHj9Mn{C*nu*@HBNm0)BH1#~eGDq+q)iDUy?z>FawwCM_JMG^Y@LI+2} zP%ep4|3l}-z9QZa>l)$yLAn9YBQz-7ShNvv9lT;{t1I|*q+Ft6?w2U@ThjAf&f-$} zHnuGGsU{Icw_|G8kAe_euyGpn#Swln3v>UE(sn;|es4%Z&lLgieaQ9w`w|^s3OGSs zDw7D&2+pFj^C7h|4fc@Ab34tiA~eiVZcQV<_@%y_%U(DeAzicDl>G{L*k%dDT8qL} zUjhfNnX%`qPTiYdz(gQsK2^=kllYG%8@fatwtSba(enHaeQLF_R<#s!_x(NE)6a_;)L4 z>9@(olPqJ|%BuxHY;;4-FFU6bEh?vNlVWAP9}>yR)@tedMnC+Cbx1V)Z2& z1MOj=N`wrBHsy>{j+iuANqnFBpIekn9#s*yfVkzLJZS=x%BAv>7vKx8DwH3$dY3o2 zLGlhsatApri3J@=wpYInq?N>kO3!XR!4e}y9q;1H+XD+%1e9$B6D71&P?fL;vAJ$O zN+&>MhUFqO>)P$2>+lIneM}ImOO!6Wq{1VGJfh+dYCR)WQUydR6)&jnbX z6|$g$c26mhm?X-=j2(NP?%;yqBEMB$QCCl#e-V^_4Rj;8;JC^3&W-^4(3txU7`tiS zPkBexOz9E8V^m0{bJn-c1j^qQfUWM6@jSJDwTQF9 zJMf4?P8Rki-!d*>|Ly}CFDmG$evJ60@_32E>b;R4qptUj26IEQ#kC|^8$O~}C?%RX_%`_%r*Aheq?5g69t!MF z%0mE=;FlLEyyGlPc}CW;%c`y< zP2%Kjj53L+QG=CwsWAMc`zYJS33#c<9&483A7RQjrp~Z7a6AQ-CR^*hw;i*e1z048 zm*9SJdux_)|B78_N?*tW7~i`%-t8YDf8Ceg*T3()VLcgHhx~7Menf14fxgUsJqeuw z=zR}SX-MLN4LFGY;Ei?!;x6a<2MCvSn(Dh|d+bn7xYlR4pi4`Z7YGtjLNv*b=<#rDCj_-Juut0AIvFcD6=Wb;uCyv7 z9g?MiaGeLi8^xW}=nVV=YxfI}9alY<2jI=r8fP9 zHEjV6I-U!a{{Dpsg{mX~8mZH|C zJKrnP$(ss)50i1O8qy8LrJ-F)aF3NnbM}p)V!Ig^x&19iLZ{zeC3qKgVjUA$WN`-= zMs3ds)N`lj=73b5kQiNbzjs*hx+BP$=Js$v>s!WtHv3V6WtI zUI6MOO^TVHl`u8XCf5_LNMw&(55f_cFaw?k-E{fKr}Mlp6$sK(ItcZ-JHhNG zPDkfvgA|ENPGK}av+27mFo5|#EL<%&fFgUJkMQil7V4vup)@T9po?41>m{^fw< zm;@*F15GYuIjU@2A!LSM!wBkExiOa|&=LoXj-GD7g4m(0$mE+=Q50oFlF(E%umW_# z@a(CN**LB_LJzdj@Y8#!oh-jr{r z(QRlN!aWOFtvoEh-tX|NyoIby2Nt-Z2Oy*n;I z!UZm*;fZfQ0@j!}B?NWLkNC^ybBty7wMq@|<92l4fLnt>X# zsdM7 z*pDH;4ocTDudNRsR!dz(v3+A{b}#C{jsy-5+POxHzxNc*-$Smzib~0937brTSsa zjWGU#s&BM2&id@9Ykp zMlB`UG}p67S3AYi+x_W6_c&k2YK}YDf?u4mYXFY|yVek-H7iZ)=|x?Mm``dUDi!Hu z99TaM-|6wmnhi^DR#i-96!wDtRyoRV+7j^UZhd$J#uUk=`S-AXnB++BMUhyyq{n^$ z!*}PdZT?*TYY05%(%k9)zpE=gDuJIj!0*3bCVy$&p>^y&;Lm;3EX>_=ukTqo)~B3q zLl-r})SXC8f}k~U@X?!0S5qt2P7$}<$N2dTPEj%E1}RKEf5ii}Ar<0BA{nB5glfnp z_7bBp8X}fUR8fmfQ^IGJX=+D7FA30JDZpI4P?Drp1bl#PnjZo5FDnTeHPgFufqUan z(vG}LCgwdi$^%b)0?tS^W&^pi%%c85_Z8o#?t2dnp&~2kT?8#V`C-OAFPk8@bK296 z_udEh!z(RUX#I1y8VK*g9P2~7L;V!DVI5p$m`*~!W%MoECRFuO z!AdgeQ`4S=@WS6;;XWQP8sS{h}`jYlsBH@)zOK(*?!?&e?~JdUv;&m;Fl=myysls_`jjs3g1At zI{`ExV9^ZWXQ(FnpbZXIr(8JcOya@}gt0>;=nY=P?}G6_62%dEO2NQZYO_s~S~wka zMz^?>@SEMEsq21AMdvTgc^yA-h(ViHGFgRaw@v4K8A+e?M|5nz#nKeQ^L6mNh>ddd z6L@RNl^=eiV)?3tbHK+pB0Zq;g5=8%uy`NQ~}1GXLh%|@nT{vw2eJYtLKGrZP($!eUbt;rgszXn^ksY7njzN<4a=e7I*H^IKPQ>b#|fzQidv zUkv?P)=Dx&+5hV{7nh~5q5igo&34gcu)Dwty5}xbY)VZuwu|7w1ZP#*!0u#MKJ4@8 zDdK#%-Mo}L_+(HdCSEX1CK$_NMVu?P#Bg8|_n7PH^f`?0^;o(7e7XHbsLjF2;y#F& zg&DLukcGcTqS#I5G2j^*zJGTUr%X+5>8Pp!5%>eEPdMk$?DcZ$|yqy>NO}V&v8#ca@OHQCW>%2C&jIdv{z<+pO$E)B3Z% z^+-?_uvrqQDTS~C&36|F_jFFBBNBPkXc@zAzY5jcTwqpEIJZ@x=Y19JUsZkirnW>M zoam66YM{H(HLx<{+tUoTe$z}>yh9)xXoddI+}Z~L6Aj_Qd44^|&z*O3(aaEHLj-;q zb*3X=*LvU1X!#ATF;JG2*@}KmOg~x2{s9=-*Mg=@Jj`-l7dL>@KeT4V5WP+}%+>9N zP3-l!fHlAp(sBW)ckS#v=!A|DE`vyE+rXBztLhl3qMYMesV;l|jjz-UdheT0r14^~ zsJl1WN4*Ptd&hsy2Hx^+=^T9)dJOiyJ)yg26~qk&cd82ayye|b=_y4W!h>-c>~qih z(Ilv#M-b~#Rj3irqA!tj=m@T0QVQ98Zp?IBN8UVrUE9W#H?%~5_55FDqwVS^lhBvW zXX&;em-Jw3ZJ`|@LZrzit>8y#n~^RgmnK9`P_%~cM;?j`CsqGx7!wthy2ikpK{ealY>6^qjVb%GjByPW9u70kj;)BGV0|)(VM-zX!?fR=pmV<&CibPQw!NXT4gJu! zUoVLJYz^=5@Srk+_Ax^;`{j+a@$gLGf%d|rpaUhDB%O${6Y_xo42_cD^!%;_%y~&X z5?936_`FzTMxNJdF*v6((0Y03P_kr7L`4MWN<#^fQkv%_N7ZXDID}q@_jb$}c~p6Z zr3!I;z`jO)q33K2(y9oUnPF7I6iywtfVnEQ>icmVwrMwNEtfG%oeF5A0{22PypK!b z8@u$tgH3;>;N#P;pt{}{=1$K}h)AtTRSkB*)%wi?xW<1l*vX=%p|_T-g~;z&B4&_j zmh;ODu%q9l&yUX57Oo>B6{}mGi?E6873rrs_mI%#YrnD+>QCNIH#7>Ea4x3xian}d z#Amk)giBK?gaA_UA=!Wv;|GX~Cq#L8oYvlC=e>W}wS5&u26}!8PyF0N5qSbbK14a9 zc&#US(H|;;K$W*>0D^F>U_>?iFQW0=)GJunE|C=>b0Y+;`@Ojvh-`kQ5$!A#YPyF>y=sU(5xe5fdK}03EY6q7DdHb=!ufP6|O@gou@_9#vUBJ9y!pW+^ zGiMEM9a+tgm4k+Q2h0b!(gettaXeDtG|h?d*XxBkYrMFF$L;x!B!YG!0n!?*Nu3kP zHfbRx>ca*_jZ)AAvB;4G@gaHgBT!tyi4q#y|6+`FOfJ@t^EK8NkD=#lT)g=v%$slH z5B#x@;ntl~G$deNVZ}hxG-$|bfpDWCfkEU%P@6>D)N%C_MMKyJBE50hc)`~q0TQ06 z0%xa3c-Mn7%P+e_yDTIOxa%y}&>#_+l8dSzk|UF8gY*P~L<9|SxQAMm*uD+mnvnI> zbB+oBruTGR1KySrtO(#1bUPvW=@3cUlK`pJT#xq1ju0TFGq+7bWc0TK0q-y#W&|I` zG@p7Yu$Cmt;k8W@AS0-ZnvKzmw%F96?<7ZTQe_D7*Io3z&YBBA^<9rYJ|!Zyo2(5L zWJ$R;EbTB_nyd&F(G}alYwOjjll^#Sb-_hvtL-HL(zg+4*N!RefjkjX4-48NqTzjQ z%TU?0=hC(L;at(Q_M+G|EumT9){wXkFNko?#tc|W!2&Ch|K`@@?)CZQPS3A$OWGOQB}P0c8lM9;~l6p zPUOu7^O~l~Huk1roEj}@$&A!kP^C-+eJJr! zqrXxi5L;)0$wI(`lj##8A^=l>hPF6bX>D zDzq;FlK%VBy<0fFb(9&iyVxIw0_onE_22Oc0|T3YJM{gjm%>XUIwaE!aRIVJxz1fV zS=ZM9LN$0_OQ@#k1|7NYRJUiiGk22!5wg?+LvgEZ<6c!~s0?^3hjk{M`$Ky`mQ1W@ z?2KM-C19ch0TjJP0hVjo(j;Py{%Ptw=p;dMWM=vIM)PSf0g{Z*WW4m!AJ*25lK)=g z@jGis`rE1ZQMvvgXuAyV%Nz1NVG|) z{pfw<{pjZcPrU1~eK4*wu^K-nKdgdJ*vH&6?+BYyd{Ewo5W#5TL#08hZ9s>JNJxIP zMqvzLZ48V7)@^GOAH2eMymlL}KD46dbGma=ZLQk+cS!d6d|#qFA5yyL(!Y(`E)liB z35~S(bGT|;$>?>e_lK07mL)>c&1f8lSxlgUlC1gF@g0}QGuBW3!W-xK|NOHr;3LnwV2+l_-uO3ODYcRmKt^Q|;J;r^Y%U zy^nN#nvw*G^Aq^lA6=3lOH1vuB>}Rur5$Yhzx|iLLI3nij|FP1GwpOfGzs`e6asa$ zDZC*rYsHt}S>sD@JdT?JD^~0anQdak2hLXwqiG1YR)lA7HCQ$50#q?j6)3QJsxs$j zf0P2I3KRY=9jp#5i%@3ZiIPp&Aab4t<3bdM8W>rJ1W7Og1Dt>Dk|4=vCKqK-(H|m$ zMs4+z`oxGRq%}~9iIDS07tr+u%*8p(+mCVa_FH)QrKj<2-}OIt)5wGB5+G&8^-05c`I)g=AL^QxoAOL^97 z^R_duNOFq39p1x|0J)s~qeNiLwOPja{O1JscE0va97LTpyRwJuJMn>meYLkA2ks}o zha}-q>~}^ZMQXiBD;7?qR99BCyrS_T5h)@DPT#{mTjL6=i~za;pW=wAA34dK-3MWN1i~RDK)QBlH<{sm&MNIG#09q{JbNNbN!&QGar?Jq zRKoL`?93M^j}bIJ#QIT21;*`9cC1ANN;+=Czka;Bq{}D2bdI0<)K~B?zx1fGWm9#{ zBQy|}-u1BWcQvGiO@i3xHzyHNTPKH6ATqkHq)CuD$==x%lUM0W9k9T8?Rie^&-dMH ze(=Y?|JA>>ST0KgfYs6kOIzCEwSW6(Kl63J@pk)5O%gRD2#h91Em`9?-MYOIY7-ps z|9k{Ib#{bSfiHjc9h>M7vS^7Wm^^{zr8U;bZVg+*`qm1kE5Z>ont-CFj<+>t%uPyu zsAk7y5VR+pN6PjyqELNI&gerBjgC#AB58q#2v)?s3F2)7LSv|qYO-XO z_*%cd16^qxe0uU@TGch@Hna0HgbZLBCkxhB{L(~iMj#15i_`2#5aq-WAuDGnK8|g>ytDgsgd0+ z3s%&)$EwN1T)_yiR)rykDbNb!zRpm98+`DYV|?(b7x2Z$27mc~{33qk%jW?RV%ZZK zfZAkDuzohV#9b8~CvHv@h9L8QqpJATudaW3aS@gl?UV%pvb3cgO#6#J_xT5(e)HlhD+bi>+-fp`Zf{ik zMO_mCa22u|4nvPUqRsvu4b^AUng$ZlgDo?7OLO@JZ9Dt#KRLOI`QT6S_fajEW)UI?uHu>E? zMA%EGY*%_Sx;Z+PbN8 zf65$NkRMmq%HUitook|p=IKdW7xXIy&L^MS*{A9F0{RmoN&=E*y75x6xl6*BFTZ}wkfi4-vT8l)VkhKBSH1BI^pzpuPEpn&@DiH{(3t}9%a3qTvR(gGkD zW6&C#09hMF+ZwD}!P*d>J!|ka@4kiiKXV(zCPQ?DaaRjI&kQbBHHt=lv&kOYH+Heb zal@Vw0`yTEQA8};f!Z>=hSVYJr%k;4x%0r7Z7biA3FCSDz02xQ<$kW$SEPh;TA(nh zFbcGi)3A}J<`aP^;j^!w-w71bmXcC?X`zPJhCb2pq2Huq#DA~0W{y!| z0g`-YED@DcOYhr%+`E592G=U;rVZ$*VAV!{1?Cf)x}C$+JXRC+R_f8{n@|! z=^uOjLVg?oR_vX8bs++FOTGQKUfGi*L<$2qY@7rf9TT3ubA)qa@aWMRDhwqBQLN0h zVra24sbPXq;H`7PA~M<-A+U|5x!fa`f>3En zHHBQ@{nCO|Vx#*R*Eojx#itnBLply+UtJeNx^HbFk}A!guj0+B=4STe&it55o+_pI z`emGdjBaf*-*WQIuag&a2uT?1^cuDuG(6!+>rUpDBBGIqDC|*F=A;ho%UjI9sR@*& zUA@iFHP=(CR2@3g1{i(C^xW}5v&S`0TjYUWd%+8cZ-X4T4B9K%;5qq#Zs}uyIHK$| z+TX?{uq;(EGSr7hfwY3)!>N)DFpDi*YZVX`r%h;JJPN;c0qIuoxHVWCi$?#B_ua+U zyz4BkrOI83zEZRqn~kZyM9;Qku%QL;3*jw}d}r7i8s+Q0R4pZmHmzP;$V@w?>^k|9&-S)hSEMD=jm$2lB**NrD@q&EGSJceEfWc>){oi#4regpS!pWyfW(05qD zbG8YAqvOV*a3~W%Z@hu$xO=_+M-V>;0|_c5MSui@sYd|){@F2}yK`!(s0Qe1Hr`|s z=gAw!wd03`K|womNC=P&CO(n?IrQLvp9aIG{c-(`q5ga1l?_x>`_QdZrDnyPfOSn5 zWJ(2aU&R}5k(ii*<|q>&bALZ)ER|twC9%omO8@S9JnlZ|f4#3`-bM37Cw#_lXN=)Z z$N$`UG9`f9H#l74GN^u;>raWo zvA%@~yC#FNA_kL9cvyk*W^`l_Yu7jJ351tgFPo3T-Pug}SeEW{BIhg1(IDETJpNh* ztpQpU2wY+hz{kJ*2>;b*-@-rrSC1^cbI)2Z#n(vnA9EG}4atz9aW*8jUiv{^&GbD7B6sDQ-XPpiN``lIh(ETt#BEeMdME$s^0 z|K{&~?#I4-AwTX#)D(bG1;c=qph!fZy-;Q<$migzX_bw-t?7At80R)`Sbj0|C*QNao;*a{10*c*nd6pav87^c1I+tebmgF<3sEWnc< z-{gR4G(I5&O$c2DB$Ne^H1PPY0BN1JNNFVc1QP==y-r?cu!$9WYaI<%sx6|95(~}& z5@`Wr@Z1acb3=@Cqo&mQfYSmg$AYbJO3F=V7>0o0!P#-ph1f?zyjDG5UYD&V^c+ox zYnMIJaCXEm{H^ZCEAEG zVy^Sd6$gbc5tXqUCw+JEvk8`=oV;u+}xH&xMx-TQav$W0DxPSoFR1-vd12@|wKWghir=}>ZjT08E0@9~4 zyiWJhLpuMXzG>0SSvEZxD#aX`L>bpfesHFzV2{Ot;x_)KoBT*oA8WCni}7fB>wkzb zP@ydGp#rpGLgM416&NEpzi814W5t4RcK0#UU`7s&>@2_Vf7fQ=#=J z=5GDl)hN{$Icfoaj3Z(ktt@YVz{UdBs`#2`@8E+^pW!QyTKw0adlSF-`8V;#W9NV&S_=&*90xuN2JrLh5@*dPTA56^uwXcgGLiv1+B)}txw&ei!)GHi=o0_w#V z?fUa|3i68a(}(7nwzeanomK?=g@5q5SN_xQdGBWy>*dL9O9EtROS{DOfBwgxZ~o<1 z*KI=tw&{wnP;<6u6IMo@n75}V^5S9)f^mjbM1rsr=TjIctpGJ)<5ukoU*A4n;o%)d z`^MYWNDq#iH3~=oBaCKctoR%I>I?_hFSJI6j3}*H#;!W4mtVHryapU3A=^K;S3OF@ z8c9Ya3dws1#k8?oOM}r1tGk3n=45Db--X~gOQgT@*H3NK2vH+YvxXRhyZ7%ThDZ|) zZXuvC5b*-_F6ifk+*zs0LmCq%K6#TTPgEoKEzp1zI9jc6)NE?#?1o}wtb(u>aAXj! zBKDIxdp!vRB~(Shp$O=g%QAZB1XqSMS8ign<0((71|m4k`$S+mfu9V?l%kaiM{aoi z>YsaQpe#M#7&3&g9b|t>&}is8S% zST#a1S){^s`*NcD(W(TU51SMb8=e<+bXNiq>$e%P#XoIp1Jn(q9JOx8W~JSY|BM!R;vPGOqAvZ&K02xufFrivUn*qY z^*430y*#A-R%%8Lj>hD?RlnfUd;rchaTeVpTC8_ z^YJ(F@h`oF$1;Wbs-S9|C%py@tJTcnqF=}Cojxjd-&gL$k! zjbh&{6p|s{IZ%RiLa0Q0MAV0RfQ1$Yt2eF$-Kr5!@02D;+{XS`JUy1B#Zn`Xb&IE; zd)grhnxG9~|5i{)h`4)37a*~0gh|bKmY&LLkG9K={(9n0i=c#` zx2Z_22B&VCmaIly1dw9?Yv$Bxi%7 z*(jiPd2MJSmI1@gBh2^J?^2f^fu)6JiLr zxc%%I-v96xzHSQNX+kMq_7lWdf7IgVQ4zqxkKwKDOTx0@$E+7J>7DlNNS8xLyb99 z06yVry5&9Ra~#-L3k~a8{(2Ess4v=MkQ8; zIsRXQz%W@1ys^3<$H&LGd-p6PJgibRg1&=MhOeX3ma}3M0mf z#CJ6}^6MJX@|f#Dbq(G$s6dw%#F*vqO`w5D$9M?H9WctGx<*V0Qi7}~XG-s-9Q9|e zTk}p6l?hOx!8JH5n7MXU^O13mD&9n?^#sQpb3FcfdLp`;iN#y zibUtSAC3ak5LyzDu%ojwP_c;>ag?r#NO{$&^_z?cL=>%2v@PMH1=i*Q=WB&&?RmcY zLl5zRXU?2YAdb2y>J$=MOXpNsyXgwXe$AdAe?or!wmwpRjPCE4fFmL_r3scH}75*0=c@97H;ivKUKK?rX-X~tig(}$l z)D(Tx%m;MEplO1EsJ0$-5oB2sBpCzc`drh_tF0HQSh}ilC^>;@{kdny+0f71m4CQP zt)G1!mlNN3AL~+i&AxyC`Ij#i6vz|Y77_HNEp1Qj5B>C~duwsC;JTz-hYA%Ao2Po? zz*QVUyFvZ1uq#KQbQdUMSZxt+DwKlW0H7_fHU_`_PK&R;`8XsSxB-MIByMO098&{j zplKSMoF3u!-Luh6yh9nJ+}Wr)v5Hy(r1*^{eMA7nMBYdrtn^g{##L#F3)G6{)xzF# zDf=heFbn!C5{*LhP5>RoAv_WR^oz&m&~*!Q{ut)bBb>kaHlBaxE`Im#`8KQ?LemhM zrooDBRTKkYZmf)g2A;mZye$LyB*PtJ%C7NWr^NiD$&qV)kDTbcW z{bmoq#y-MZ$$5tM?m7GNQzs36;)fSO^e3?`2#}>MZO82o{q$#*Xd1F%+Aiae9{>y! zxWcJvgX4gh#wGx~9!6U2ni$7EuxweM1S@Lr;7nm~f;ZlH>=HBfyz0gCTA*Ett(p?) z4cyJWM;ZwR4T(4tym+xgQcx5luZpfa+LLN>#_2TlYCH4<)x?;vAsZtB{Xt?Y!R+-o zK|~S27(Dy@({2~1LRi~7s_M(@U3C=oI+oO-#Gyfl(BJ#*)1zw7cb(NVOxuS-+NE)x z8&~_L>e={OE90fFUxLW|HD1>|>PH4>yqFz51YNIc>2i$iYP|IY*?jV2Xr@&b8@tw} zh`vN@ovQoBa6BvowrAY0|8ApG)}yO(@cW&~Lr8*5Nha)5!y^O;+JGP`5aWug9O6R}6Cp+{ z@Vixov<60iwJ6%P;9_lX-Wpu270;fn@V(#s0`48JlK!`TK&UiVh7ho-Xj$xX{oPcD zVCXoK6uNbfZ$;Wu>$qXXiPLzn{?y^EHBn5w*ZMo)m2x*?-hF7D^gNMrsKNasgCF^t zr}2XydI~@H>DTd7|KiKIaJo3ed2#1(v6v(V^9t(FM8uIdL~zX8Q#}QFqq)y# zb#-L&bKb_@%nC4NJPC3Yb6^vjWr%)EnGy|{{i9dDd~UF`C$lXHkfkkcNA1u4%;$dW zt84l3hU}I&w(&&)-ITXHH(-Te#h;vq6rh6Ar75!d9O>^ZY?@Rd-iQy?>nSG$fmCtY ztnkdKg5(5mymfB5Z^hASxsAgI-~)2lG*kP*rC zHL${iaAr2ciK9DMYY=;Lfoku-WWgvPqr(!_oC{Rd_NBzrv7tyS^-aws9lF5?US*497D;J-`ROGWJGXr zNMJP82g%+~l0ahtrJdZu{^FIR=c?&>G!uW<=>G3F+tV?;ucdRVTXh>-sTDP+V1DR( z3l-L3w{nlJ1(X=nt@f>~ztKK&$bmvww;YdiMAm&Gd=&jLiRbNr`hW6eaee;M_UI4) zovtm$PNBh~x{1|kC0aOSs=Mg@Dp3N+0I-WdW_?3fS54&@2H%XAu0t8>AqY@~nPa5C{UVDJ=e9v9{qfdVo zKl`aS@cM-v10_9cejk+SnF12l3Wc$WwB+-k$w^&`G&Ee*ok)LcQauqz^~)d_PHb%D zy+1#@2W_4Nnd`4_LnGJO%RFi>VLRg@K$Gs7tbjBg^(LdopL?%bB*R&OKl;<3*1!CN zuPzqd6V{dl$kLX!W&1OK_w)bJ8^-)4zYQ9KMQIRaCWfXwBN@kKzu~~DiBn(`7Ycxw zGk(chFqTNIK%Y?kySBV0zTYU0=?D*?Fy;tvzH?!Xa-~ExmL1iU?$i*~kO`YJKggeYVfQK}Heb z1M$=|-z)2mMca&5%Eo)r-XPTwRgh1cq|{fehh0J6)iCNumu(U(+WPvidxXTkDXOkw z=GJNehu6%K51eUM@j1n6l_tFIGdLN7Zg;^ z?WS zAc{WGzS!1R_RJNRy{?bNr>6W~ecS*O{ax?R^!PPHd*s|c@P!P&_0D=Rpq{|CBtVw7 zv@O~n`CFgqthk(PtXx~z-TzCnA|k{9eUD+836qlJrXZ<1e7dp%eq`ye(v4UW`jpH$ zWX0*x5gy!K;X)J_=MqXq#RsC<8X2XAMxUWECAc!hpzcqOSSN(oR%(&&Yf=kq4;!&F zdMLeij{k~UL3O3<8ayLaDs~z5Oro=t(%OVR6@|h;U_h-vMR51QT^uzlC=0+xoz2~9 z8TZP=LlfGYZof6|8pY{T*u;emzB>UoWtmkEP0W6Y?8iB6z{2_O$q%+=5?J~2{z{+=T1;G96JBR_FPwXf+ILE%ix(MB?Fml}QzmD$=X|^9Ga7k+*K7XV;B2}kEP5N)t5xT@r>{y- z9iTY=^D(DeCpRXA4{2z@r=9o7zW3SPv>hZrT+l5&R+``f#G*8^-;ynLa)nV*^Uor) z4XoCOYD9fl{SQlrWsE|_z_|anMsd*!S`l2F3(nV;ZslKl?Os5AG;RQrryABc&Q#-C zo%&dl*8M5Sj2+tWqvul!g6As$4Z$McDbBk57~>imdI@XDgc;m#cU=NHVES6v%$P-+ z_7%el!y}`R6SXW8C{V~A9dfh+e%}Wk;9r0F9)98TU%}6O@@;(KQR@mo%W;|{Md{8p0K6e`}p~+~IG68mHfY`r{RSszsw?TO3?kT=PkMa22z-p`8 zK)DJ-NgaA3-v~R}8jjRxEC8a2njXPXb${13!c-KU$kI;vN-ukUb^%CohLG(yX)Fq) z!v-Uo7;y3P=tL#=i6RjNC%ER1QBtvp2Hg=6gQp(cw}=3c74{?z5RKZktrR}p0EGo-7@50G6WJ!~r{@mZw>L0s9^m9XqrJ;b5*Sp!o z5!_^)(++y8&uP?=^RZU;o`Gt+eI-B2@94nVSfd-tzbEJyXq{NSIfK&Zs`i#cJnm5P zd{@__8&t*iB{fR)>E4qa^>3gfbiUI7<&O8#jW2OtU|1&HSBd7!G$V(gMwJKB;Migz^!U*G{6&NFUrxlnB;G%8u!Dnyb+u#2H zrvdd*-it(!l3Gid3fgGh-Cwdx5<1uE&yiqo48n>HIFK)1t%k;UAJu}{6R+JF z2DZt}XsU@VCZ#4bNQaQYgLLKIrs(mNSv`4ko)EDJgT&_(lbvsDKk(NlG|gw5_0)9A zel%=%*Tn0?vof(*vX*!f(nRZ{a&M}mT2QHdx`{7ML}p@`s0-o-p4mj>!#hNwKYO6E#tS0)3XL=fB?>V>s{)l4 zY6Q|=KwH6`hxf968a8I4P6@#~XyZY(jBU+nqo_N;iWzrLk9zgeOJgNo5j>n4 zoG-6^ETC2Df($~=E592GlI;`qjKz@(f;ia0(D0kd8eR_gPoCrkpLBw1>Gq zW!yxXP6-P=A--n|>70-`yFSz?j?Ew(k>ZH`?$Tfiy5sU259}A0pUfDd^qaiqXbb4d z^|@kqx*xl{M}kL1NEjCk!gs#=HopC(+xQ=T?QQ(O{@IuC#}5Ziy^u(ts5W8?ZyV$>Db`$MR8`Sv10@3~ zjMct=*kpfB@3HoK16zpfpUdz0D<9Xt|A#-Ypg^9Gwj@B7wzLWD|M-u8{q(bMwU0nC z`7wpBcec5aCP7@_Ov%6&-*c`#k)T2R-|RVP$gmOc~+R_`DTLEdXr zSn)Su!>8mpL^xeFU?!V5Q|ags_`majqFht>9})~q3CYMVgsHo?S{CM}GMBKZ-Xl`2pqKhpE3h$By56_ANEE%4P5imxD& zHVuewyO!-l51~p!!dTkw$M#sTXlej&%KotHfd166Ci~d7_ALByScMkT=bp^EH+Dr# zDY_k5k%p&>^vREy1W)`bYox)LgxXd#eAiN5*<^@;MSqx9(2Dhs)`qY)E!GzX=WE6J zy2Xc{JHvOp{{fDV$X*UfM1O?6U7*C4vX`Wn0ub1qdTKt@ zp+h(#!cn!bLk@7Qt6USc$^OB6z4keFai9ItrRBZMy-zUY4D{KJUWbz)mXX3GG?aiw z1mF7Z`}mf3-NDa)`VIW`kADSUeWZ@v!lx>^(=Qg~6)o_w{im;>rH@8&=vcvj_BtVz zbA=>LpwqSmFH`rIgYltA;&X&`AR5!9tMx%fXIrar$IDteACK7ti5qU0COH}YZ%-B4^NKp;NA(E6@iQuVi)7$HpK=%DfuzO zDAn3M7gSjuWzvYJ!_trdO2dEZ0(@4(#0Jz;l*CZ5EZtB`{f}&uRqj+BM;a`FF$NEw zxmP)db1q!}bAygy7afuzho-xv6Qa(D3gPsq30%m1fkN#h#ID{^k!xz4^i`eL{yyZO zSed+-`#i22dZ!kEpo%U|7@r~uXSj9+-~me=I1-#53*PT`UP^@bBiB0FRZOm=CNaF9 zcwa_C=3Zs;sC+ha=fPCuM=e;P$^Pa0qfGi!`gz6i?x0!RZ&>p_*8ZCa=ctX-K@`_6 z)*4N;odS)mLJhl4eo*zeC5qeLhZM9| zC2dcn-Ssq{tteVi2rTMDT=7aPz}it=ty_b&5v*Im`5Jh9-r}7{f=A~DB7*OD-vj*a z4?o1Jae6Xo@*|9ON%rEH{BY61&OWi}XxRjLOC_IwVkhMGp9_SN)fGHd#ThG(>CkCq zM#g0)`LTaLVG}=jEX0@6RUgt4=f{x-w1l-sqkuZQ#HHYS-gh7W_uumh{=kRsIse`` zZ658c7;&D~CrDrM0;Tdywe#xz{UtqLGL<4l z5-?=4o>o?rW5^y;sCvIcTj!JloRB0F%TB@y{O-T}tBYaygtP?#vb3f3v_Jn3KKHx6 z{8)d%8mtUqlL?%I3`o0pL{2t^F|#SF{W~~|_rMU30Lrnu`qyc)G zDl2$RkhH=`0MJTt@3eu+30{BmF;p5fY!M9|80Zksb3*HtmO5ym=aB^rdoui;%2{D3 zo4`BCg#fW}xDi_wX3L$$34H`^U@iJo5zr;UL2{KEX}~5+wm1jMjv0xxSgw++A;#(1 zX=XGv2?R8)l5ea4MyAy=*{lzT%%SE4;MPgg5jaojjV$%a{L0PCa1J&RJwAjWP|cXO zeXbb|!lBZ9F&q^fZI>Lo%4asDWl?_5e^w$RDt8o;o}z8HPb7vfbmY8K`)i-$BSp=T z?j}ALj#D@$LnxC?=NS#GlY@KG;0?&efrzk&6f~86&o*<2g}UJ`lInSD6jmvkB&BET z?6YZt-zARv^i;Gv`p3I(BoNZqgHwmb=3?@4X~C_l+B2t!AlJs=uGW~bWbW8G_icZS zC3-hPeC#ZtF^wi@sEB13mz;iPW?lRIHZ@#s?~Qtnp~>ErqCV1ovUg(XuNtQp$WU!z zJj%n_@=6RfaLEycs6~AkwTX|lDApH(i?zXp5uBeZ9-cA2_iLZV{aaQxnV79FmFa#^ z|8q_#XD<`+5%+5e3u#R&AVp()apy(^M?`2iCUtaRpT8==?QUh=k=!`rKTP?XU zr*NfLqr#1CL&nV$?tE@(xUH6^B=mOn8pp?Bn0v|_^*0wW4Q1Nt7$sQhUIPUS&)(x% z7=|TJ@QPX_+@%$$c#(DqV{BOexMen}nd32BK!e@OCqvR>a)SH_fmpKFv0}ziv%=|dgZpPkxO@8)R$$D& zsNgJSTFo-*M5YIqI+d^9@slpOOGZtFnCVv|R)F3+LxfQ%an@IwUw1%vAg_o@tHI$a zMMMPm9^S@LV@1z7rIpggF`8+1&c0_~LxR-%t*n4CI6FSd-ZL0Rzw`;7UAEJ*je~y( z!Kg8#@KBQ3;l=wRCT?hgRh5?lMJ0<{4J8W>~Qu{_nJNWVBd?PjbE z-NBS|WWirKjAZ>Gt=n_Hvrp9L*fDG4uy$?x)UxpFm{5Feb-=CL)mP8UB~B%o*oE1+ zDC-T9I)95ecXdBQDY5sIFQu4)viH^>JbF_(JgLk--O^ zJ;e`y({ncYQ6!o(O(c@~GoC^dH*wC52FfRlyS_0H(CW-MX2EHrXgJk!sM`m=YX9nO zKc9G#!6Ju4^BHE_M0C&~vuqy6aUsdRV6w4E3cPT3f=*{#L#W6hH7&pIA^JPe5A`AWK_X(*CWV|NPf|`5pX{ag)OeB-uy} zD?!Kv(XCW`oJWk(NE=g6lqif9kW;pL3#stA=UL2P+x^r6Rl!$pSf>uIDu`VeLcOuf zU>Fz@08J46VPk!^zRUR0)4>DDUSdJPv6hyDPd zl8J2**)&b-f?47ogb;&ZatE7oQCAW`H1bfULg}gSxew@x7eptr9G6KY8LQ&qGxq@z z=!z34tUZw`p>gOL&G>(%^PpwU2ZO^ff;j$1p&Sb!iRTay6FHQ67AP(XbsoxQAs$++0nIa5^Q zlr_GZjN8GQH#HE##ki9(=+b5GQ$1YtV<@t1+q7WW_H~ppanDFKKg#ds$dA&-h^vhT zvvnzKQlgUHn^EoQQEZp>jlu6{0p{9FI~xmqj7^ zzxFSL-ai*oYAcy#6I|w;-|BZvL6_3|_PcK~-M+3q1uEvMRGv>;{B2_-0PywCo#8+E z-k0$=KmI!Y{wLprF#w^3H2;70{w!FQEjkKXT0<6+qVY*JperbXn;V2V2gt& zLZTpxq##lf2GSHoQ?x}>6fN5#Wy2z6GXhVt9pM-G$>Gq0W$Q@<&;Tb8mPCMjFcr2% zI>ZU++udjoXf(R-c+RfMT>tNfHRM_=*UF)Wy{q=g6;b!xy?0es<{JO$`#wt04>fe* zTphjAnK(c*1iCA`rZq}<5V4KmXfKS;YGVtt&^$*;wzUEH@n8H(^H1LFI%0d)G_l~aQtFIqFTEwvu}u?Z zLaetzHCmH|21`Tse6Dk}NO;m&$KG&d00y0-d9u&#>8!+_)_8bd@e17o5#gPuTd0y1 z)Q&|2^MHn0qAevE4NjFRVtqAM@(dNLK0sfK0S21{5i(XFO`Kr7D8yy2JhH^2HgZ41 z1l5=R=OD};Iqn7u7_s_!YM`crnii((@ak(XLmRe92e9jRazGvXyv%OQsbswQSvT~8 z5`6{&N}%WG?_Xv0S>sN2_|}Zp?6!i|N|#&Vt8}^dTnd=-OyTf-13Wi99&^Tr3R)Qf z1(Ks2P)C3qTNu0~Fh9qE_LNaN@yzPr`^kGr0NqSJ*HY2+CF^8Nq%z(A5ojMz6__jr zC=;hp2AWpMy=D$1>GW#K>GS3|!xG4zQy3zSS9MdIyFVRaz-B>n+od?t(_(Jeo*+1DhZGJCU|Req_ns1qp@;=Uc^{% zH4kY@X2~v}+kLX0K`_*F@#k}|pVv0gLDE23qQr-w^TkgBh!`j_M68R^iUgr^qk^pw zXh+y}f~ReV-Bz&O8GQ785AeG``3fFvY!$jf&?wo8aBk3Oy3Tsa9~zti>TN432j+EV z^251aGi@5FUbhLwfBhMM4+3@s%6)*g4@|2P6s=_hhzjufK)m4g5KcV%EVxPf(WCoG z0KoNP!*eLM5)hy=axaqX9I6DOG$!!)-aY)0&%B1;_iZoXKmYr`fnWHQ_ps6FeaYK8 zOU8CuOx=W)OhqG?9VM1aK#&ZmVT&_XZx)R=+x8NLFePWGf4<2b-tBL8@1>(6Q|6re zeVYKQ<$!`$TP0lg8;9zjq# z7z>Gwk|SU@*|@Sl4H1N(LD1`<0HqWGh!joJ^fXijp;w>}TF-Kl8bFjlaFwT`@S@zd zV!#RbD&xU@!HdM`{IiIUd=1k;-k{fryPQB(<8qE;r?Jsu2xu%~A`vJb1Q*0&J=9}$ z?41dE7)NqHOo7_UCng$)@CdY4$@jPbm!rfIRVx;+1Y@jT3XI^TS6}LbsGK?~M14gH zak`dDoQmK>L`|NFxS8*o&M81PEP8lPeg_HQ*(cvgSS4dP6_kJNrY<>JGEC@*=FW5Wb^fv`0h)OEiOIdJgsQVg(Kmn!gp8#wc12O00%Cf4 zHPHs@P}@6W(d?$PsE<}Vn6AOD>#%JNcCBK&Q+(?6hxi@e_A;&-cF$!3in{T8X|mQd z@Y`#K@<^(^OJ~SJ+iaG_NkAi+f2uZs>w~y{ja;c%#0T|+p{eiT??pjAyfo0|T9)`I z74-Ff?Tj>9l1SqESx~4pzX{~sQrjnAeW!#rqrl$=~uiKK9aE_^E&VCf?hbXw22ws_cB|W^^p}9e3|f+c_F*ko3uz zxPVMT-D|(@tHlUe+@N;8#_PpjzsU+ikA;#|b}tQa7gx6Y$+zG=UG>ibj`zwxA9 zgQIu6tqG8|J+tjE{heQvSLsLDjGgJC10f!CtNi9 zjE2ganEJ;%m?a43m}pn=zz)Wg-4YlQ-~(2KEQ1S!A@>Ykesm8#j2mU@D=(bvgEX0O z;|+#6j&Xi?NyZ!MtC0rJkG`tPs5;^4aVNcm?9j@+*rbT`j+jq^z$PqM0ppy+7hZm@ z9}_howgPWVg=gQxK(XTKxi!iFDIRPZY&Z@zSy9K>VD(NV>%0o!+X@Pl5Kl4R>a)_$ z;aQJiyxx^DE1@8kqCHA$e;-s$IS^3z-4Ot}Kt{jE{-)xFb1AY)&erK~j;H^ANWW*F zrIG`W^lZ!nN2UF82K4lYc)E*m zilN_hTFYIrjcHmi!niR45?`YM&dmhi0CwOVA0v+~}tE|8qrQo|?+4ILjAb zeop7{sIRk+UEl+Gr2X~1eJ-K!iUBd`$Oa0THxRMZIaVLY7MB<(NC>JxC#Ju?^{!x~ z1(eZB3nL6;47yIx8N#k3?AjLFR>Tj)4S)P-vW0OXP zvmy|HjXJL9d9>kcDA#6bxoZ*CYjVB6sd`KGyIVw%nF1I?Fui1pp&th&#m^ zB3HSqpoT&aU(i>24Ebf}Q5e_?3=dy+-$9%i2M*o9geNWIsWC3uv52cA4T@9*#>OgB zi}&xiBU!lqypGyRXr3_0h9`<_x zr|ST9PHmkyo5T5(B^hjxlmoXl2aslzz=45kljIirD&le|hh_*e$M=i zB&TNg9~XDbp{cq#8(EIBucSqgJZ;lW*n$1``hr!$%Mb72-~Zf)@ppgq9sH;N?Qhs5 zh&0Y#l10A782YmGyWyFdBSGfOVHrKQYyo9&GbvKaKU;$m6}HsqX%F=qNs{=JM7Dpf z(R$8FklI{$bGK@t-{r<@7p(1BYd`WcUsjH$KEnrq9hFoRgq|d*p!$0#x~95ULxc_N zzmwuuOirHY2^i`c%nafc0w{hj-s(hIQ8sQuZ|FE!j(1vCI{8gx*+ zV-#O|+Tuwk0qIe5+WIqGBV%qEoZAN${6VS(Lo!qv7#gK;2#36A)zC_i9@)RKm|D;W ziJjC4#%_@x8oo=_(qFME9z1>kPm?ti3Y^nBS>+Rzbx;z6CZbBYf3+DHs-2tr_FjF3 zu5%<+aobMMlDR?|4cet@h18zS>%~Yk4?KE`X6z>?clMk!a*X81%{q362b7f3Jt<#j z`|vFv_4y0PyCn`z)g`83ALRXT>OP-()|(D^oI{&hL$mjbM0CAJkd%aO=RUiFZO}(K zyB-E-YyR(;u7s~9O#9fjcUjs;z9|L-lkp#uuVE2+_$=tcIdphnI#OxX2d)&PW6rcUjbNEZY=bP}YFWv9gr*fICVq_m4OK>c+=Ox=E`E0SOy_;=CfUNDA zX@BCcf9WUQHTvTX`2&b!doyv2b>SgbV>3{7mYC> zvF%Jn$8%7bKol%APZ7aBu&#vG5Z>!rv>hT*D}*ZBY4~S<6LGcOs7P(*+#96MfFh&5 zLRwLpJJ~VdoJw>pI-bb!&Jm9pv)Oky#Aw|(d4WX{!Q;md_c)may_`8E25zY;S5>hg zPOCxOoPO?J15#H(7igo>ifKvy^@iVNBomZUl!Oseq=>tO7NZ~li^yTemDVW1s1$=) zcOmI>>8(W1G=>0~q;tB>>M31PUCFoB*T6&{9`LPr&q!}M~HTf}e?~Bj} z0Z~NB{c8OGG#(5o1sFuc>C|}rF^&X`wNhD$!P)3(H|;$I0!*lirNM%MN&}*1o=9-g zpYt^>X6wadd;Zva4o!a4?4%_DmnH8X>rWyI_T8xxrtz98*~Fup$qfZw#*&ohQ3Oyc zgyE{ca|oTy=-eyNyZBoRRJuY?GD!kN)gn8@eb~}r5nv2d2wUj@Wf)NyW6*ZMw%wua z6xUAgW48r9^Wo?4+rRB)01}E)Ot94?P{$sM{y4q%N31=WE`fU>Y+$T!NkdzJ&Y~{m z5L@HC0!y5^@rlYOw+nrYB*Y8Y>wNUK(1)JC!hiI;KY;(o-~R@F z=9j(>X14U2(g4)WUO%-$f!TX>@a3g=jZ)FX)cPJ{LZF2yR271<8Gav0PYqv~Z>$T> zw*2$Aj0%|^JHp@n^`~20LM7|t67rRFZ7*8!1)2E_+F0Wd+->U3x&IKc1~99J0y%Sp0>by zU5CzBGKqRt7WWxRT%v(fEdKTG#A+}< zcM^{1G#t7N@G9boZ9_k_}-WfOQ%ZV6WT3* zU~+Zt#v;=^MF;1u>8ZBB6!o8gxf#$(&D|S%i-(=?ut0>Np4w~HytIiEXHj8F6Xei< z^%5ypV;s~P6RbbRTsq#lOx3+SUPV&di;u8Q ze6ll6t_G?Xf}`&RRGW~TRYz$hVm0{0Xh40408l|Eu++ywFr7gsip~Jr)?m9c*mc15 z){3D2bDw+(pZd@v+aCf)3l-a5T(!lPXnzpVY{cj>k{^CQZV0#{aW?d&*k3$hdz^>; zJ~o!+WFaRJh5CBRqYlSJe#qYIR-EDnojAbl*Gc$S$Q4jHYUyB*F@Eebuj13MJ;49< z|MQ!8d)or!HG;~|Tv}Tq612qpzhmcezsK7EN>2DVhAf$r_^9nFtV18e)AQ=c{9%dq zFp~cB9_hQ#Ej<6)KCKG78m7 z0Ds5X9NdDZMDEpwP zk$jiM-tP*EW$YaAewpDkI4A`wt#m>h;82br_fFex1|2dyO8MY0&U6rp6Lezj^HVlK z9PpyO#EH{Muqds{?FqEidPYeSMOGL&~JrN4-4lNe) z<;wqG&i+`cEWOS1y7u#pZxSa)ebfVD)1N!9^SuvL6;bUc3OxC>Thl!2QNMjaE+ErF z^20z31-%bnprk@DqJR-}sy6x20o%62t`$7p8tjaMRPe8T-|Kkg@f9o@&7k2d+2IS6 zm;p6d!s$>!p6zW4o)@$nzHhyUZ>{&jru?QQ@5LcvU`-7(ykmuhyMBG|8c zyg!XUj39!wCTPgh&+htj(w`~OZr!9`J+u8+zw(~^#T5l|=h~V8S=*g$fAp_>SuL%C z4K%qEED>z-C=Mz>6XSww!L-lp6BiWfEBAFVxOX)&VbJI#u5RivbxtukLVeh#72s(r zcxqbrupBP!gUPi+$1j>VRq)A|$ zVbL@`h!cm*0_r5L+>4Bkgs(XIP8Ne5{NGwT8;s!5<9ldSg2P5s79~~~ur}rSCc~h9 zY?P4@*zt8K`s%|+_nJ^yW~r_0zfuSjst~w9HE`~MX|j{C56Im?I;fWn9*0I`e&y-u9n;%)kB>2?wLn##3`n`Wr-M*azpL5}YGrjob&K94#ievbSI&n9v5!>)S+>nqsghr)EO zV9HUtst`I5MATAViJ&ua@tQ%C=)SgORRL|J;O)mKKWD5=(PziklCvPA5Ok(H1%^`7y_CI<}1_ z@X!X%tcd>pg*!k9FJ3kHkN>$3<3IoVU&GIR;cXXZDW!Fn7w**8M4Xrz>Nbv1VD0M* zmn z){OH4`I4&;aA%?qG7PFHxNJmK5+SwsXoXkAB0+|*^WY%m2W?#CT5(D#GDdo>40k<| z)L22E1VTiAMFfa+4yj>9(8U-$e*8QHzy??D0h*}qX`uU1G%DFTDjL!AdRT6l-+|Q1 zCiRFF&po(b9A_@|KZzZ40zCR-->TD_sABY7%pu@ap&+;`h>4VT&+37UjnActir4mu zJ0WUM%LLKq2Eywa5(!yhV$|nrVorE?X;6|dB=@U<_v35Vm}zX^O$R;vwMzXw*E!Ec z-L=ry@wLXrH5Di=J=63xs?VCAV|&iau$N*;)leGO9D%t{uv#6WF*PvUIW2VXzLD-3 zYx3i!+thp>n=^Cf)8rJ<8o}q0pL1bl@G;MmX#rXMp4uK-v(=7aulA{I>F>+=FqZDh>J<*ZM`qo_ zP1|FAFtVHT{3pe7!X@#^f**$r$TI%{L%p`%GupPzeqB9_RUu%o(@u z#q{fAdz?)UGyd>T{j&bwf9T_DHslVqH371=JJtU9U;FY;ZjJmgB6po{>5^|LZ1*a&ja#g7KAj^=i6YNF8$t5d>eLm7LPb05D_6>KSxpC>iuj7^+4VI7`r;|KyR zR$9gD!qY5L5;(!Yky+}*6w~XDuN_e(zYmU$_lbnWudC^Edom6BfsZhb$@mre+TX_< zA@*ZcL@uGp8bcrDbCU`*Y_&PH;waX3Q}%NycyXg&IK!492Fiav4&_Phk&a(wT}SC1 z`V^()hrezTG$Z%j;);=?y-5OHEj#~V1E9Chz1X>dv%59Y{4mDqeW*=@7$F$3V&}U~ z(HeuNJA>V}!*-|m#0MVX_k8M=QNK=A`x>U?iKg|6Xu`&sYdepAM<`GukQ(bZQDadb z5D*Bew{O2M^`-0cmPd;jZ^AxZVu#QL9irCmn%Y}A{Ht^>&zGTDND|b|=RWitzWK!s z{*%A`Yxu^sNybJU3xeIZ44O!{Q`L+jQJ48DV-%Z`#YALra+E{^3Z$7B!$XVZ#-4ea z4(kSHL-3z;;kq{X$`irb?pEWq3)Xg5+K>Fq7jk`^t-0j4NvfRm^>| z!-c8_8jh<+d-P6}q5-*tMtI1=y*k1&DF~sf!mz74gTbRmkI-z`AvhT90@suCf@*N& z>8;yV!!aIST`iugmx!3~L&Zob6Xw#aU1E#JNkq^P2kM;|$#l++?UMa)iaO++=3yy# zmD3{4osr3YTYFFCJI0b9OV>q8NVIUSjs<=uFWA!*=-@fr^NCCJ91&I@)0GW)=udFn zIeg(u0}K8;O7aK!eeAD8vbMX{gwE~yGHs0?apLBCWX)bvIi2S)C7yipIe_DZlZ!|X zIQppQd3#44`JA)_J9j>akbw2R;KK{es@nL-1OZUTk^MCUR1J)rLt~S38E7X$7op+ykO`<`Q zZS34V#hHIj2&jGT#joLw68_!4_Qq#c%kb{B6#=rgi*Nt_&wuHqU%%FGG!!2q^Nc1H zsv5Fmf7{C#nm}`uxbFuvCB@*hg*TTz--+Vwr!89L5VBb=0^0X0DW|~{k`Qki3(gOP zPIM38Y9Kq-Z?s)l5Uh`2bK?kz^abZoCh#l-(PXRrSnEcj4z;5ivm#q53l$r z^Yt8CiDDz>em|5)^%9;Re(upQDVZDPmyCiDks_r)g4jBf#N8akN6=8x!tW=jn-Ur( zHwC0dgQdM7WNokYw2e8^VURqF`g{q!1H}%WE14z;bV&`4dya%E%RdLD-c5}{EAQv2 z-_O-dP7+iz5Fx&@aLzos743qNXHeiyAj;M@W6!121~QffT==w+wZh)Gq!NFYadJsx zf5d*Qp9{8%+7Ke2KnqFk{{MYZl0|-Kmi*|f;JMTIfC$7PKf2C9pib{Yux$;tJA-Yj z;s1ZvCtk*9KJ-HGtB^-ZII1fi20ml@tJE$j)6GoI2uIONM;JkSJ`(PMaGxjYo(tmV zC%0c?{YVU{jBS;@E}nCz43t;5fj4Kc#~dz(dP_9ax=k6T;-N zB&*!^bE7E8eFvVIHJ#%^)A~ZUHVvs9_?W8VF9qEV*L5Vc@Y&+^$AqtAT_g9Js<4}T zJbDL6;psRSgl1XtBYJNWC7Z)|t4V)%qAF;0M0_efX{qJrCmEuL^!alRcB8qTx|WS{}6r=8TMD zJl;FUukxsm$Sz&dpZc(8wagdT8mz}(XM66#GvB3qU-x#OQD%-Eg*XK% z@TWfe8vgljc_Fp63k8RBg}^;h&BsCZIDrqIcOkYQ8eZXeaxszkj8~?kuM4X949B)D zXr^x1(!TR;!z&Heow9G&E?C>8wm7lo*2+s!B>Is=Lr?Ny@ugp-t+7AMVBO=ipR|o{57wH0*WHAQvgn zNd1}Uz_?pj3vtp`r^OEECK+Nho=r>}8$i-NAmGoU@gPxpc9FUSv2u8ZAZ$2ueN)!Y z#l+zmtR2-_UR`G+Mc@3X>{Sm+fa-3!o zgxe`OV~90Le%RmVLfkrO4=l0i7WKXRcLU%Ntl)WR#N&cGtC!N*#L=x52(i0!zS#Ai z4?Su6Iye8}xMR(|ZFUJ`MG7SbqXC1!r1&?#=T-cX&%6&RO=4?`bbH24e37c)s7XBK z83?;Ny*TM9=RvuZP$-99FMb)03oP_VlwN7S{9B*@r8ic);cm2*0&8s-*?#zEzZmLO zVnftd-`8p)a|r5KoP>Cc-}ksih`;|Ofmu~WLj8CvT>&#(irhd2E)GxIz|T3I2<-M#PguF#8g|Lfheu||7ONOjFe>sI#rM=8nGhb z-r>qAXiSNM%T-3_qU)*(NdNo5UF?$|Aqhfw_~?EG-E){eMNa<{)`7d+y-jn{V1Eq) ze6vO@P4cnEeRCJ+pvIi9v0A^-51JyMF3qWAW*B4ao=`x>RnZa^5$Lhsox&lWqx%ql z&Tw?j<)0rp-%3uC-%sY%%%9e9lPefft4|qo;Z;_MbEaj%WtJ%!59VB zK6626&jnHW%w0ipmiqK&)>==sqJyHZ`Lr!Hs?nnE2gN83XFoEfc8g@RSJ)&ve2A#9 zI; zTcf_3V@I4z3qCAO^y9+)_0)-vw3#>G*qvZt~p{NTr4#5-+=zxI#c!cHv3Dxrzi z4A0vChJW{;n_|Yuh0&$@{9}8CqMih)+OSN3IZi*v-%+wJ3}xIcx_mw~pfHB&_USQ{ zDGSdQLGQ=A|J@hgm5;2};@xO#NzK|Ws{K#?#;^Q=AN!d%3SixGKy#_laT`VoGY2%s zlws$QAHHoJ;^S-Yb$HU{0YFT;Re*WI38gDJy$ub#rm>J(Dzca*Vvy3r_<3TlBQ`-2(NlRU z8C3y6A==@&7ak8BP9h2wW>v$Er1Cee7(czU(0~d8=yMPL%Yk~18O1rL@Lda-UD6g?a*Lrjs~2Q7(c=217L`Im2Aml*<-QYn%=??1s%|c4k2Rs*d>Uct15P#ac7A| zf_UVI2C;L4wj*pi#nZOM)9Y(I*%>^&ZgIaM{GsprAU^ogBY;fsPhy+eqf~4#m=hf> zAp~D+_{=<@s`Y2o)UiQY4_XfTIvy_t8YmvI;)=v+HQ9eTLwf-G1(T;x@%w$AQD!HY zo`W^b$XmBtX}YlB9Q~!G?~{1+%WrD}WNjDI{`BAc%4gnb%}3Vow>Gvs2^hH%hO2D=iyt@;$YK`4-=SM~ls~UWAK+7dsH!NJ>o$}|>>3;D^ ziuj-!>R@OvR?3bw4;+l)cQxoC)sfI*p3qPl!Xv$r;O@&F=9%GuRQJOgBt7co{(}e6 zcu=4!VkU^BPRk%r$>iYosVk*Ih>^IY2v|*4TlIDSicqE?8&;&lgVm*~ z(>ax>B|-J#d?^Kal7vY44Ag}IJf@A``DO(_6e)FBes+xt#;{`W>U5nk;;C|EK5B@VB!mH2SOU?~) zd@;rIAc&sZ_cqlNR037j)R{cf0-F3g5pbUbjY`jXb41&*ryZLc=$=At&~b0_2JGiK z$QK`%h(9Bh`9wNrY){doV#{&y-!kYdUKJp?y@aR7N)4%&q z@w8J2aoEMYuWx;YD0w0K_>k$2+s`>&Hm)=M*BUL>e$>cPJ~fnkTOiu|dfh?4U%GgX z}b}IAp1C@CH;uGea#W&R;j<$@5%1fBQvOoBC!>#-nn&W-vIp)SHV%8 z(#<;OrxNLWMDj1`b{0>5B#lW=2*)J4q zn@)gM6s8jxQFN`KZ4Iuw4o`Q$)2+d7s}N!QE1!KGFF$wB*|jm`pCWCmAxff5HCre& z)4rO!N`rJHyMm#3Oo|P3v4-SQ`*=9^bHYb`K;0*>#yySmOKlGKB}R?Oprl9FuY=nR zw@JzZF`_$13b3Hcl5o>L+4y|fKlEv7yXM)|-}$~r_@90M>tNF0XL}t*i)!${R@@ijQFX<2eXW4bD#YCrkk#p32H9FXM0KFNN?n%)-) zJSJtIdFh`WB>4CK#uq-iT9KFC)&$7f&bIxTpa1elf9z-8P>MwX16qKOQk`%J|KPsH zYt2Z?H(Pd_b}Ndvt_|M2Zf6{9^N=62H~eCeQ;OK=uPp^bna5Ek8FD0c5GaS3Qs+MB zQU=rqbxUKI(sT((2{njplK6=s&QS%L!12)Q5Js*{14^t07LI@a!BwS$d7k5eG8ZaM zSg7|ljH`whI?V&Kd0@1V9&Tivvx9Tj5H0a@dZWD72l3u?3H>m}vm9Xb&KYUkV>5H0 zxH#n;-X~C$2h>g#Jabx)qji|0wZ*jmI!or2awYg70F2##X(-64HhP;D3A)2UGsNDU zzMtynC7K^=Tidy|SkvY#?q?!sdkM+-CHu&UdU3)dkZ3n&s5G{a2hCpg(XunG4;BYh z2bFDaYi?75q>d?-I#P(SHjMGVbIA`8z;qS~(sqKjRcwvHZVPO;TU>8G4(K4UyBP@_tQIqb(kz#4HsPQJsSE7}I2=JWI%V{_B*S{lwRvnlJdxhLj*px=ETFoV~2%k|mUKBQHEi za#TnOEn*MW20Jl$Z>RXi(+*oBvzPO+s<;!n5*h}@WTdL4R4p~&hmS>>sYibR2*FBn zB351p#NUPHeVhNAIT=Lcg86+P*$Vj7NFh-e!a&e1=~L$ zR9ewisxC__6QpYJs2Ps0WYyC5udb$MX604>PJjPOcQ;9J_YQa(=+lfDx%-I@-cBGd z4oa7TQZaf#2yR{DxRsKkL;aA2{T2(@pF#w;c2rp!K1YW|^FHUFGuOl@y{EL-d+m>@ zAOb0ej-d=f4-#+_1#yY`^T44{=8mz91Tb&Dl6!4yyV+pVNhfyY+UhhsxMHiu0e7j{ zV7JtFOS|fJlco-Zpaj)ka94cckWev5S3~10?kinL!y>Nu$nWV9%MF?kB#wXwR0Dtm(Ukk;NgY_y3 zQmM}Gq%h0TV-L|qrFFtM=WuPJ$G7MHGU^-ceIC(X_cgFrDD_2bZ0ypAIM;@YIEB{s zOt(MwSHAehdpq;v@nL7wfW!yL_Y`r%GPK9B41zHVtdbtb288#_4&S&|yw`RELudLB zSdRXfOSwW*QKS(ErzG$lk4X}YiiN$U06otRv{?sZQO86EP9Qt2i-9(K;k*33v(ZFU z%)abtz;ubSsf6~K6D+Uoj|pN%_v=&E@rvw2Vw7{vFi$}^M-wB~Dp_(%<=_b-VacK6 zOROMP2uvby?)TXyx)08)c3t&w9MUR1R}nc#^O8DiTid0yX%W*CY|ML}vzKxv$;?XX zbf;aqr|`sU?7e*wBBf38_b)KU95u1j5B)U#?Eqbj9_<`c(E8+uF$N-Vlve`d&>-sm z?K*+kDRxftW49ITS^<;dU;k|%49E|kAh#4)y&hnEo_pQJu`@$T8VVx;)_4Z&Gs7FU zqU-lyaFqpv2UJxzZVUT+=`at`aXG=meZ-|xd+F3+wvo9&bN83&7{RSJnie;&_4AnC zO3&^vLN%2k48G^}$M`ef{~GRXI4Lem=vu`70jynx&b(Z9XjqKp2EDp>KU909#=i^Z z302TB>|BaU@VYo&9QwctpdZId5LYX%uAlOXh_#*R0l(+?oSGi$*8C`k1S^Uz796J- z-C>2}dl-AHArh~L{By?|r+tzjb3fDZv6|f3aB~gtXk0@YrE7oSW{;JX*%a{&s@E!S$np|nI}%NP&%vs1^dtj1q#=RJ(8$N zp84o~S)kDk8dDPWFW8}I?S)5E`Oj&vPL$J}B^UXGS{K@$Y0}?Dn%!@}DiLL-2?dS5ZL=p=V;@W4LTpvDZmg*Jp33tz7;v=S+o3oxT%YU1uzKRhcJ>r8W zVmvzgn|=Gf4?c%K_FG=HcC9E9%^$L;4mJi*_p0vS?*2$7*GPRmmk}qie{v|IZ}!@e zOx*k!KAV=+ZuvImE~RWH|Lw28XRx-*jgPEdu(oq)Km2*C_u&sD)-*UTWW{V_r|y(a zW7x|NtVpW`=i`IQs93tIYlF^cVw}VkRU%Rqp4M>C&Np%vi9pL(k|aJD%2iM`k+`t{ zRycHGQQa68J96mzi{$qt*hKdgp&Y_@OY+QuUO&M*BDKD3oG>G)<%m&LY_6KJ;IHR8 z=9(CD>S$?RaaN(1@P@(tt9u7fg^ncI?$Dm|EK+&RF@o<}@*{}zB6dz=s+DqeF3nsS z$EHj;wPTr6{$V)QCGHHlz-5Fn&fU{V=k073&IwpWX&3&JL- znmV7hcb`$$v*taUsCQnO6M-Gyt)%~T_wC=>nzwtbxL3dD8nOjF zDoqgnUha~Y&>;1|Q&PaC{Waoy-6uHUpQ)(zm;H*x+SSI-Jy!rEU?@X@l z@01N`%!c?}<>`~{`L<)kALywFZQ;jcp7W&V>I6W6w3B^|MIbnO*C(& z65I37%#uHHV@VJk3sqQ7Q3=mWvK(U{EMG(Mw8PpixUC70wcUFAvp@gk*Z%O&eo>o| z1c48Z_)1dN(+2Xq)(2xgfBruApsKiT1#evg@3mbK2|!V$5fK#=5vem&Hj1h=E_nr1 zF4RT!U`-D@9TW7XqQlDt${5Zlfvxrj`U;6C`4J9usn9Y}eE1uv7r3Q$}v_+zD15^q3?%lJWagJWOav?I9MuKT2$10~81AwcB(9j`O5?VE2#MyhQ zWs&qtYIm8+>sSWip+Ws~K$A?ZgPKlCA0wh9=rGnFaYE(Pf$n{snh>zk@pHkyr%9@H z%grZAO4pN&j%tWhnD*W;=k76=vj6VuM4wXNJEyfOy(aI^*)2^FbET6whUcK&F-PNP zX<=28I2LOM`aqWwN8dNJ&Dq(tF}Hm$`aSPeOgPMnJjMYyDef0CYk$$|c{E6NQGYgi zI#q8I8z?9sV-(7i&|X>O2Ox%R@F;5n)fjw|BW~I{VJoRB?z7?%>lr1?W&HOvtVk~v0iIof$jJSa zsEakBA>-6eiF9K2AGi6aul_sd*}*w7;+S(QrkeF@z4kh(O;foy|J{4}GMOXsW8e82 ze($%w7{wrH^u9@9nIVd{0Y~SD9%)UE+ajm(*;NQCd^8luK0e(s_ZhD(==}|kP9!4y zPygx{e&-s+z09^IK-PAv?N9vmFa5+znr!pMUK;Yn8dRzr}&S^1(uj4&d16_q_MH_<2cRqrX|HIPrA{ zB3z4m#DqP|Xn-yX2e(?PCq*;ZC}W;cRRtLW3p?~p8kFGP^-%x)4JZ?GUvNmv zc+k^;aMc`ZYuAZaZ$uqcT>3&Bqr2YXy*8X0PjliVjclKYT==15T+JpNid898vIlRHzw99Is>e^NN= z0=skPfzd;qFP~I8=KQV(MkYQ_j$$mY)`yX*ZF8(W^HR=>u_W-mNsg)=H-}P=W&}fA z5ziPWiZ3V<^vMq*f|(f@sR?HvJFv1((%vT;Yy0vcL6y?_B5IQBn;WnjVkF#HpYKgM z7Teqf`&$~#l00SIk;HCwNRgQO)fcn{RAy)CWW^z>)zQ*=hnVeHUky>lag(b-b;F&`vf$kC*Ldc z#Kc%2Hx{R#+=I@1?_ai8NtX0TSJzDzfSr23y^C$%q{rwSW`jTa9q+^Uedtlo{18#( zmX2OuWV)AaaHKVJQ)rN0yuP@b9?^hPI~{>kO*W;4CDE+>a@? zj4c!I_41TLF;pjtR{P{fCqOIOCqIm!69efCwq1+11Fm<1>urbYox$(?)GPSTZ+bCQ z=n_$q{IHKwuw|5s^M3K(pH9rl(x!B7_k~&y0bG%Q^D8Xi*Y_GP^Vb<2uGf(jiJfzR ze%U_9g`Z0lbaU6(Ws6=P;!hkHsab5d%E^eE8HN;p{Chrt4?TZ1I{q=`)+~LNB5I0` zI!>kH;$yDWP}D?ny!n3<$&auXb9HRI?R1~l#N(y5H371=TWLS`GjHgdTm6NxX?fEI zQ)5}g?Tf4fvjNZ$5;1m$CO?PYGmi!hNF|^?o^+;o2<-28au8u#w5%f}M3G)gYLr_g zzE`e}UH-EKdZq}5D=GSe(Hr_nzl>>rWIvNQ%BxJbgCs>S#AlcluGBz(=3hqppb-rM zBRwS-!%?w_+Bvk@gx~khF^{=TMKSv^<0%c^0S}wz#@BSIB8fE8(z$RuA@s4Fug=3U zoWNXAvqoF6@3Y@VfNhR2q-OudpB*?QTEBMB`<_vXoDvC=Z`%h@450G-bEvZN&*k!k z2|MsH5FN$c(|&hN*xlc2f;cHTK~k^KCn6}9(Ga8hDDEXE2neN`1NIDU1PQg(9G#kw z{1BbBA0F}?a}oiZYGPx>R342m2oDknVF39-#4`2mRy*Ud8GLEZK_( z1voybBT}RmRR~1yhW=+s|H9Mx^?UmW#VZrQ)KjZ?y(yU+q&_WjRuY?i`5s%M4GY&& z9u!c8pCjEZq6XsoR0t&6?}hFL#VACq9%5L7LXHMY&>3U@ZWOx?c+z#)?gUS_2HRbW z>+25R_2I|(-jBZMY;3CZg(PdQw4TQ+uzBg`G7k+x{XzQ>K*N&w70KB&^Q_d$8qMwW zey&PXG)5JafsBNZ(mBt}!7o0?f|(`vL3H)=?W0rnQ<4O!B`@YCHBOoQ z80@R_P;9D-zwqCDd5xuCU|R=mZ8zTj*kAeL8#D?frrE~Hu{Q0R$kA~U?$!W&(h|P@ zbO&)FdL^iF5}cqDKDT7L5iZ~{><5|Xue!M1Tn8}!d|o}PLbf7T3(1wp7-UTy4D00N z)e~ @rv38m$KwWad0k0$5D)%od=RqQ<6l^b0VC8+fbJ-J*S;;u(8CeVKJ_@idq0jRB*A(g_(NM$k zF!vlPj$~i7d|5$1U3Q1qW!>bMc)Mr0{tAfum_}w)h#LX~!(=NumQZ#IeWF?bAjcn>Q&8Q)tu+W~6N z>HqHfM(+m2?wr0|hTN3{|DN67k?n|6p+A&v+6R*2K7CvJapUZrPrP~`fAV|ZhpuEZ z$*{P!w!g$^D?9!&IIZW{HplRHk0K)OuO(F90jZ1j-}v`ZUmb_e=L3BauV4H1w!_*k zudNA?wcS|z!=HacH&MkxEPC!aS>wRcsYT!7*CE&ObOw2#P@s5f6yLZuFiG%hQ(b=P z0WQ^pqi4s=3-E0*`*aPX}6Pa;q*~qk-b;syT}_->)rl zJs&gRUzU?J*T}o{R!g3iD!%WM03&O~p^B+*2nmhNoNFd~rw`uA@ewdSc)jt|6(_6? zq=}yc1=xv`0JT8oRNuzq(tt+BGCeEP0tF0&E|&&KNsr^S7ZI2=umAiwv8J|BOl{*G zc%kWp$T{z8OZTcN03ku%zWTppo{6F(9kokhy%0Y>C6vcJt&cuF5S|T|0*k~}r{;y0 ziQ}GGMfoe4Ah+nCQiMqIN$R;2BC!>n=Y-BBk#UOiQwF`r?t4uCtd72F5?x2bYe8u6 z`|vrn$&c`SZXz2DH9tfw)JBX#J4-WbRMD!X#!_L3ONO*&hh1lrAJ;p<)3(F)uEoQK z@Gt(B*Q123-_wTH^DHf}i8E`jv5I}F!k;%xc#ds?p{G(hm3^6~IeDhP$rCe9s@J(R zTeoH_92Qc$o0=b|wE^mLO6h$1(*$%g~)^D zSYk&BSB#iQbeserQ%`=>M9NS00QG_aHi|~pQ2Iss{A(Ai?Izlf{mdJhSIs6otTGhP zUb>mzM8%~?g7}x$mJmvz@U0Nuyf%2!x(bub-R$)`MvRImiLf6X7|#kE`O4&;MoG)u z&qzh}C^1qTA8>@YASWW51PtbGLnP(uoS1{P^876w$hWbn6r$B;(G zVJaaqXB?q9?RqrvmZOljte z#;YnM>a&0tUXb_*Wi~7zb|FpCJLS}wI8h^!UB}DqVL@51>C^$Ao3{qD9witO*l&G{ex z_V?ivuRctueg}mkR0L=iV*t69Pkr8TasHf}Pa2~ELtJN2sZpzlt!Vb0V18SA_=&a4 z*4X}+{)>OKs-a(4TN5B_J9+!z&%Y6X$RyKyL@tg!`d;pPgt&J?R8* zZ9C@(Ea8&P_f;KmFfU)mDIaU80wE4q#fR&#(vu1lQr$=Brhcq5|2f^UY0r(bH=o!FXH!sD#GfNW4r)9 z9}5`HyOHoE~@P4oPslBzCBrq~A{6^xvh9+kS1z(Jd z&!y41m?J;(zVKDbKKVi73$5&T+hi(-M2HcE(GHzabRE#P9on7ZY1?79HQ2R^-}&vY z;QoUqTw_B#%kD^!nL2!G$14_1$Ai+=2mPzw3l!I<+RqQPs~}J5Rd1i}1RuZB2lz?PTqL^9x^T zel*ZtalxoqzG1|Wz`mN8pvvwwtsioXO?=492yBhw%`Na=OGoEmoLebbsvJ`1IL1O; z$8hL!vA|&xVLT96s#2|ePYABmZ*cHluP>5+lK0pO$%(}K?}{~E65}HLtv6hF)42cd z4c$ZoWbo`9)pWjxJ2F@o#m!FT*wVVJ}0BQuXiP{Zx9+lJIqQ9Vy!}9sw06KVq9l zlH`X*njeZz6as<>p%cI;!5HJTJ_N=Xbe*7W4YqBE>#gF+&fxlKi>KEe{@G8xf{(rS z$UTMq?x3%;fc~+hUv#XwFL99*YoBDH4$O>)Bw&;iN2fJ3j<-Xcl&X4x%`^+iu|Q9y z-^)*%2pu9tF2iq|pFH-@RQlcW=k*DlIH_}!$&b?bGKPt`kG*&w|Ksm@KQ@uwV08s~ z5IbQEZ9BVHOBx4=P<7)cf@Dc`uiL{_ioIi>`Adp<#30oNRJP}YaPqs!WW=%F6z>^~-_C|-oxa1uLEt1jd zWek%|$-QKvtoJv^fzO|06(#*%cRcTku0$>Hb1u&26a@QJ5bF3jZp(SOEvIpGt;hW= zz0N>Ry%bYxsip$!gT%QLwSJb9ALlmyb&maVkXT}>q-VIlZ{u7jQeTbSL!1oBUvu8; zX~t9l6^AYcg(N2{rPNTkd8Ef;q|(T^)#kGtX?-nsi7(A9uA?q$h{`0HDw+tIm&UAy zo*`qABysX%fU=N2`O%Bvx!U9KM1g-jt{5)U&PX^{V|zK!v5;U%+A=Lz;`-hpIeJ{sFyRpdjq?TeLEX-u7X^B= z$pB#P^OgQCr`PzZ^t(qM#II!StA?Vq_zX2F$-fC&c3=bhK>JOtV;S0TbYAvV-1qaI zr*=v$^;5WrWV!ABDa8@u_K8;?;`e^*i=kMziRYNxca#7VQVs2wo;yAGeo)J{x% zJovSH9Udw&y{siQrea>odCn*gu3P5}=jy#xx$`k1j6MhX66uQsAy+A*DPqp@>ivX1 zF8^J~ewUCx9PKqX1?P!W&@@fu-piT-I>OZw#z!=%a*MC=VAEXWzA{{@Asx^ANwRD&(d^zrLZ*_9vZ%dM- zy!fn&_aWilN>;CNk=SsAj!dul;k9p6ARu(m9vvbABbExwsG#kDU8mT!22ZyJ+uaVk zYl9EIcn`n#yIyze1Tak^CK=WyPx(%sj*4|)^B-${Gf{7+Qv;CTiU<$g7#WZgY$x1= zg5_NM+iS4YKX)^0r5G5k+FHGz8Y=B8$EJ@5>xCp;$l zG8-db6~AH&{}xbf_bMvV+@6<#|_Y92G8R8d>a}d zH{~!c4b1s!e_v&%yFm4Kn}LVY9(k-L zWYMG~_H`(Y+8k6!$(k&O)A&~U{Mcu*OswCzul-%%^W7B3=*@H{+I_s=WL6(mgHf4o zhPVWW{auel_6ZIZYyXKufLOtEwLd#M-3VYh!md+XZ(CgN1lz8|c57fd#SebZ2f$7L zY{8!(dp{NtdHVgfM1!2KO-a^@;2sF~owg&RvA&3=dJp@pO)BhxGJ7Y9eG>ap1bNL{ zBH2@zfU5UeGqri@gXE+e>yycJAiYE}nrch%!j(CF4pk9W@$aHFc}{lK@sZlo^m}84 znoEjDPVL7G?^ggZAR*k}5dQ4vJ{TyHY@%4w&xnFWhp1p5fESA-tIr8`NfCA^5w=K@ z5z4G{XIao=-1ojze~B3T44cR$w%+Pi+x(K+ngChb(b`}5Tff5p=&jb2H?TfvY?Bkm z(c!2$kYkSJp@N!5fp@QM^5YN(a%qNp+`;G3C7lQFYeBQ)1t4V*NQlQ}G0MZ=-wdaG z3ON&t!Iy;HtKY3rm0R{6VzmO3aq`BYL#WBc6=R2Rh&Gwheo>X84nUX*e6HJiAtAaZ zIL;^7azclTVIAv+hT?_nsvzS%N$yxo_)uro_m|=Nz8xd`!v5mv@w6A7C9>6>x$yQ~ zO+u~hZnjfX3g*|o*+i8Vtf+iXksIyn8?g{>#vx^Z2=nl*lWv@~1ovV%C-y1t!CfiR@wb;)T=m5NR-Qh`R03Hge$CV^h5V&3v z>>vAEE(V|ISY(@WIGhUs{lNjgm!TtjZzp4@n51uok{MIFr#QJ%6;o$U=L%a#I8KU` zsLFE6slh!eK$b16 z@HfI$d&1KZm!3cMp#;s$;yl%{WQHVjuOZ+*OVMW>vxDaQzFL{@cOgVoLv!#Tlr@gZ zNqzG;*`Y^djF`03BP7eYBUP88!qWLa9H%A8kJ7y)T4-k;xQ`{YRS7@%tuNt|?|T%U z#S~&6QrfS5f00xVwVW^KbXnWl4r>3azxCy-FTQKGN)$xMi6}~Xu_=0P$%D zeEmslDX+M%s!b0tcL0ciL?Uea7*Y9il@TKmjgxLBD;oE7&nrg$JmWk+(1XK7b?uLR z9X}CCc)N2AmtF(JJ8LE}5Au7L*a3`w&sp_!T#eat=L%S?7&Mx=BpnO1iI2d;#Li&v6z^0x%J|ib7 zN-(aW;}fv4Sm3%F5p9EQ$ zP~mWD6N|!t61@-qlw!PZWYHhuv_8ZkKa4TxIziVGy3SzN8tir*w!0SBTZ50k{usaI zW6uL*hT~ThFPF;yFSE_2*Z;^Ia(W~U0grfyz~6VB72iv;?B32eB;^xmQ}^G~RPn6@ z#cAQ3I`)2d6DaA!`;(8B>=}yGpTEt(*?IG)zyJMs?tT+=ucr2zUN?!55c@^cSXBlK zDvV{uV6l%+denKN*)ts-)k;7_JwBOm+2i|zAL|z6KYDBX)lO8;*^grP64*Cf*sD5(Ig(Xg|PvQsxZ*B!|ZN&=NjTo}Wc)l94 zrF^JF=!5sjIGGn(i0nz~5UvM6J1@%6+T*qde88o3pHYS-T2Bih?#1d@ zJ)iYIFCewHwOvm0_T^;M=fn$<0avJDU&jcB@W{S)Q&rDI^+KGb!HzLSg?(T9^=cIG zHFDrM$&7ELqUIdbBYiXLbCX?*Prt1|DiWEKKMtdMd9mdxQoPnIj4(!NZ2oFjvtZ^Cxpg z@f8WaLpK=GAYTR{eQx8=OFm`D0=ijWz}E6Ct9lQbZii4dM#z5EY^XY!MX zz?r<3&I>5bL)ds%t~}N`QX;hnvSi1C!){chykI!xhKOqYx$^2Y6IDZV{@u=yVfKeL zTigZ#q!#(4l{x4gtK|0yj9&&ueq6s18-)HEP19>EoF9#l9(i31ouwXqbN)^r<6QaY zkH3%k%F(cg&Ul_FEuXdR=b$ZdIPIc39kt5R=UFv_)^^S2lmTp7k0N=XnFKDiH3vOAVfCOPaqT1S8q593ZHJISb^BOPckiU>NP z5C>Y@WwmwG*0xvs-~QsS(m#B2XY9Ej%GcfhTY)EYqICT+tA~Zs1KU^blPKP41#f0T z=R`ESl4tIH9$Xnw3KVKV^J7AEeSRXvqZn-8cn5(CNDF)T){Wip|1=_Cs9bfeRkc`k zHh4Det6P}4SannmwsF`bRSSnXnebjRl=O)bI|1S{a%H$YdS^(5ssin$v4vVUbkjKf zowJP->(SSHkGMH!0r=rFjX48zlAY(849M40JU(&qV{AVfqtJWS+f*=dQB@+KG-2V8PAWB7KlJ*P=LRY;ijw zSIrPP;dLsyD@qeAL{3^fs-_i3VU_kz)7v#7E+8aOK|p_~5(GB+VX0dIBe2Mjok7>C zO@4GX`LWw}_+8)eems7_!>Lbo4t!2*3mMoOJ!*oFwk}!I>oF-F5&+YMF=HAcyT@i! z*}jWuapMB1%MRsS&Ur4g?49F26Bj{%Jq1|&J3bq#s3{+3x~Da~ZfkxVdOi~SM3Sfb zwdc{l^;=%Y3->AWcVwQ;Et&REiNYyD=LKz4@T89FTtDm>ZI=H!2f;*w7=cm#`}7*k z$GQCM8c-i0=77H6{qO$tU;X9JtQPV4w>1H>w!PXv`1)2TuI~4nP%^pN^Ire~c}U(| z20(awt9a6?lkTm%K6yZLZh&&>!CHUsureeLIL<9-r2Wl#I zLZT&_s+kXuR3v=iwk1wDT_{27zGB zHA=KTHt4@MF}_8Ut$f3j(rOmR(DP#6mgAwt=iS$th=b~vf|_8|5g;WRfB;(-xh$tq zbTs%@dd4w?h^_#TlbnBJ{hIT@@8duo%b}dl&Azs^-QYGy^+i$D#ws6+u{NB5Eb|FUO}|2{X7kz4*p5q@1dx3Zs(i2zB^;96i@4KPX>6y_>r>}Mwa`R#_WVt3PS_yyW743r6=*-rvh#1~b5SL1^Qukr`r!oiH>y5PSagY(O$>NhC`ATy-&=C(SXzK&c|boVSnCeNN*4kp1TM9 z(5GGvquNkk{7723hg_dRbb9Seo^Z8s8IJ~`lda2n{oAA0Ci=TLuk+v0^1YD8>DfxL zJXN^+j=#A{-=`b=lQ-MHw_3#);Qy{&u(qY`M?e1s4M9}$i=GFrADvKS&~8|?=jR4n zU4U`J0AIWA@I<=kX}Efgn+ie_HM5s*9&9f;JNaQ$5_I<)`Zx^<2M6CKMH~&3_M%Yv z=f-tIO5c%ER_)PyVI&h_Mw!Q-OaW106EPbZ8fgX|3F3Jr6|C)`dZj*hXr@tC9}hx` zZXwMnASgkxq`y1Qy=Iz%Z8%?VdTs9OM0GSmzd%%8!xt9#om(ka4Qyu#lsrf?=KRVU zBVXjW<^i?1|3VT(j!yx(I8eJLLDqIodpV6;9XB1c*}GbG&&uIr1*>AzMtJ3!qwM8B z(|>Ndc`Bwk8XYA~lr$lb>fy}|Y|nj_`r3~XgUUAj5j9piiT$|VUKa8Q@7^{S5x_Xq zhj{%DtNUTk4nhZoh_pKTgLbFb?RIE8#jaI6y5HdYzwH(HLaI_e*4B8S?J={)C?uv(mYEKjv2{F>)vJQ+Xm(dY1?=dZ%(_I_V8yidOe$4nWb<&pD= z5)y|5VGL=?`PRo`@pY+yoXgQ2)a`Mt(#?4dkkpbPFZnV;w>k~oIO zR~!eQJP>H;S5mfIkZ$e=(mlcmhMW26j_n8>3&gsz#cXp<`x`fXg(PcYCo1UwCaJZ?bK}|-d=ni_rRm^R~!JK+Y4kKE6AQEFy?o| zUf=Bk6h72Sb8TNu1GM$TD;Lf-8octvNj3PJbCc6NQR6wq0dYUq`rMxZTG($%YypRA z(-%=is1RRC-nwdV5ukGgIbQT!I)Z5pwqEz66>QrMyXy`=@R|2x!vt!?+TPJ&6zF95 zIKhng`BWyeN5{k8OYcP1VdR z=qVsW_O_Yzusu3Qro@y|bRb1l>HcU2qIl{%551?QbMVw>XnKys<3soZpL)fzj*ukt ztauIO!rI|Mf$s3bCSlP?&qKYnwOXSrkgj}PXads9;NcIV(GI@$Zm0OhwaLWlq61xMlqPA6 zOYp`FzF1T|a$-m^OUQPwgO9{kOJP`n=N$^GGga39DC)BKgn>9gdL2^a_=n^Pp3IPp zQ=2FdvBm|VL4$gAz2^~*sb3^A&JuC=B=YVm_ZtQ^jdco*3GeZrA67As2luLa2^u9X zRIuTuNA%FL3bRXcNQhE82KyTCud@rb?MVT4sg>_@=hu*5e7JT(;2m`bX0<_=Im>e$ zd+}#WL{k&`+WqdByv@hf4_VvYZHFW$E&(ytYlJaWmVNG6`^2e|9;Z5G_v&9S;7u0g zkX~`DVtpd1vBVvZ174*n?j!Dh`E^w&L2#?8v-8!xC`rb6w1-N6CU;)xhkHHaKDH5Md%*IvHz{*oB=ex4LJZ!k#A|N&2iI!f*TVbNJ*d_tPXs z1)Xs4J!gA~julp3@|vZJF3O;9UF>9#^cd}h^nBJ7p+yQvLn}J{LfV=DS=+4kqo4nR zHtec%X+&^{`C>LoRYhwA-?%n-XJ^J?^h~#2aja_UeLFM3v5#17{ck+WNS~Y!nIko+ zVWJ9F3apy(cf^(Bq_K08(&!{ZThJyMe!tbYAxIKfO;8%rCu&G~1c_-oTWjF&DbhUf zG+YvNN`{7$Pqs*r5`rehm?;#ca zwFL7T6hGXt9d%GCJ#Rc;f3o)IcynVBT5xU8Y^xh|>d^J3je)P2qE;Io4?`&YRu~ z`MqD#xf&-wIwebaWeki_bkbti3ASyE?T)Z*J8XAW_v4#hy@%iNsrN89D|Gmfb z$G4FLJ4OQIuGw}q{X8G*_;-KX>v+E5Vmu@rT(N&EXo2YAH+ebZ6jM|AzM4v4igmcQwN=_5{`?zmm+h;|p#_mECcsf1 z9qM$=*afqVn5w~=l4DG2tC`+54YtNn93A0)$Mh`@y*^R1;2M$~kfi|E{#0DnQS2Q9 znbi+f{foqL=np4~1Rryw0no?`l0m=NF(>ru82*gUzQ^(R#xVZcGlakCuu^Y~YAm2c zB>s65#1RM1U8a8$_fZ(b5P$?c7=qk&jOt#|3QvRODF)83iorov$siU|SCxy}Pv;EH zRNvo)V1J29@L6`0E@5uQqUoi;+d;yY1L_amdwrbRp}mB;cbBWs`bu;y(ra>^cn`5ONB5sU5VVM*mu8+ zg@%pFKzukxG{$1frM<^eV#SnKl8kYZ;NannHd@&;vVx=yJcoVberKF(p@H%$7W*|J zp=8G#qCq&;h`@9Wj1icQuvJ#ve(f-%7|ghxh;HdYjOj`qbsKj++A+UGZUrtYJmniip) zvVRZLUn%W-K6!E%?UoXP&$pNE-NWa;<+*Hal=tOC6g_mNT0JZoq8SE07E(HQO()M} zA|$s>PCZt2adMg5%a3~_T(?^syNIfS(LlgpRs7m}?Jukz<$1R?0kXEy_HX{|8ycub zXk1iVC=HT`$llaTGt7f*LmX1X`1>eT_-~EDH?9R;*A+MNxH^B1X!lgW=CEV~BFAHa z!zentg0@z1KK9vK#bx~OzSZu5Ls4jO9V@=rPrwpIR-mXNDg?;2Hv+PQyd)fNlN%IO zTV&N%BxnRdb0s)T&ROfaU1Dgc56l>v9Fr2Qm}H3|-+#;uX0ooufyVPW3!~3@j(LU| zo$dYWU4tdBZEctAz+NEw>MrgLo`xs31xoaQQgU%dlN}MK2kEW2M@vGXV-DSzF!pT( ze#V1weAIsO+8+M3bZ(_KEl-}wq;=8h*njW=zIdu}#r}xLs$5vZy(U)p4uVo&h!Z&e z1HyRd%fytDHQFmC0*GKhnXXB1ASzNiN)fO1VG|xArq}%t#AL?YQ}6c(7{*$miqTT3m#k{Dc}m!xkRIM$i+gZ z>iQ^&{?-GX=Ne+_wNcLYguxJDb8}~DC>}j9n0s1rct-|(VR?#kwBc-gLGVMLdo?mFj92tkE`=ppgKV$I!jdSc`2QhY> zJ=c9qGc|NbC5xp*RX9xW`I0_?ICN(EO27WvCgRcWE64I@0mM!0EAA<@=n&3Yz5D=L za7IV_LC@wsZ`#pX+uEMBRtkcRo!@tja_-W{&Yy=lH4Qtu4;3ut0wO5{ubq}b5^Eg0 zZUrte$8o2TzwP6kN%UDhi*ege>%&r1mC+m}`#k=f5{389S;MJlv4OzAkb$7>Q5lh_ zar`@hR?*$@?*bC0fUe2;^wXbny@=lax9Efh3buA>R0Ztssc|}VCE@E(sDoyJ`Vg@J zeo=){9<}RZw2E=GR~j@w#L{00AOh^V4#o(!U5njTvF!|YTZ3==;Pd#zho6g}zwnRm{xSk%rMd3^-v|{EA-C-`9#z0}4bZOrv9{TB;!<>i=DhBD^N5ceT|DeB z8Xk<3hn_;vfR(^XXoQl}*ep6CoUNubI=AxQ%XH{zFGtQN5DrIvXtA&Ti%lx3GSt*q z8W8HAy9eZy=XzYUGPW*MsYOWZ|r^4NgH?nkVj0t#iV$|LoLjuNRzqy{3Y)9q_sINXJLbnr&s6s z*N1<9!Jj*;Vdl&~KQFrBIaI-yVv~OE!!P2a&)=K1M!TAV9+DtL56oaYLt6`9+DnX1`OzzlpO&)KhL%=Vw}lH7301zj^~o z;rC|P=bfeyQgzxTa~x+#$`8HC*4kkv#$`BLCGC`$dZ1wi5kn-UB#4n;w`l+$%fVfP z{^kC77K6rX!>piGjRx{I&i;MB`>xLE5QxpFFRT5ljn%>`Qd!k}SG9Bn$=TamAEYzK z&+CQw^IvK9SRd2wJ+^+k3oA$Woh3DtVR-&`&e7_q+Vq7r!Xvh*Ql#}kR@ZERv?z#b z`!N?NI$DO#%==$>dQ9RVaekfJ-{)9pF{M?E3{fFiCS4jNKVrnO{kdF#WGh@L_!*Yk zi$kJGg(0d?V|7lnYtX4J1lqL*+g8!;1YIZCZ4G|#vme594{YEse1FAn?1w~W`3Q40 zrDod_j-uuzl5 zv*c4BQ<8@8<+r+TtRC3;w$0iFYm3{T|F6D$@4Z%j9L#_S)QA;|hJx4%MtkmB!$2eD z&7FvPBUb80t*t^rJ)ttX)gsw+tdq>JDGvfj9qpCk?X5wpg{CrH4cng6W*HQ&gvrMx#jr6siY%antXcuKo3F&Vjpj4>eKBFtS~>V7oSh26nfDhR+TT>EoabOe)ej#zcvMIgGBIz{bFD`Pi1s4k zeWF0atqBbi9)h90=XD}bNKzz0Jwh^P$Xk-38kYuk?GhWfHoh7O4j*MFAqv+~)r7{D zL#+<=fvn7~wscz>Dqd9yoeD(AAwP_zy;6awMSirRXgkH$0K2Y5+itOI1t0ssLwwr@ zo`V>G*hEE14eT%bvEzkn(T*t{v`^&Cz~DJ%Fc|<1`anAEF#$nDc7$%6e+ zk1Q3)L*JK{?-#e%Ujm=RTJ62V?=e328rtBue(-sG%ZtB>FTdSdEsjI&H4>;Y2o=gK zp@EU5B!T;d(i>0Ckm^?sANVMA5@$QM1v)ZS1q<-&UAG5t-oNef_$_PV#EWo2fq8ra7N48B;Jhq6@6=Zw2%%JILZXBFu}5uf3v;yyWRm&NyO6f} zK~%%FYjj}&OyaU3LI~A?r9h3XR8Tu6Ko~>SOgN63fmpdkuJodmLTN}woCsyfq1aG^ z;~_ULJ232nCQidMTVHSvYZHPebisn}C1ZMRhwQn}F6Gc&8^6&V?u6^*w&u$*zVjG! z|EAVc2$(X4<@S}bdK<(wGn^v#{sjFwe(ht~mScTYLlpRczqb=@rFH+R(W?%t*Lm^S zEJ1XXLTkBLczlmU4F+_uJ^)Xg^hpf>DkBz{_P+KYh_$C>H#Uw$ zG_cbRD2RSjX-=Z2Y4sFjopv_y5!qL&V#m?|odCPeplubqU5DM);JPEUJHhYxj@RsG znshyi%ncmX6CA3hx5bat9x&q`mwm_*rR}qH{>EB4@m>|_@Is_K_!}zvt~CB2Rdj~} zGtR5K?@K8d8>~L#Ikz_p38%uLUBM0CZ9hOX2CQct{k@z&H z2^%5Cu2a0d?QGz>@I9x7Y#x3f%S1p$1{I3)8K&p862d1IAk7`{)L5GC2aOUC@jds+ z2uiM<&c&(zr9@mkuaKv>y3C1}bL}28BQ@@qq5_FaTo3@$S|dYqLsv9BufI>#Y|I0% zwr2Nl!ZrNwnKeEsar3tZi+V=wz*J<~}!~|8;0EFOiE*hXMRp zCnMMUP!M{sOOJR^X@ZuDPmCC~$&c0$j4?1f#kMtQcOBZ+z+AWZ?vKBOmml5>b2q>5 z(wb()s5av%&+UeRN0AR}^#Gf!|Kq~I!^10QkJy`_zZ(ne-}X6q%C;w# zdIPa;1ad$Jj6WZTXA7oI7QhYtl~jZ`vvoLfhlhyJfMB?%46t~UF4;E5IJ%3x#f9%R zj?zn29i>2zf*8D)9r9(&CQyQq_B@)7Rx3Q4<6P?z@~K`xpidGRqF#g{+V#$5)t2mq zu=>h54TdTOssSB1btC{95Brau(|D{m_DVsxOu_86Nha$zM$c|lMDf_V<{~PZjmnhTV6Oc2wwEGvx<6PQZfs3PA^Z5I}IqH6jG#M z<1lXhxihqzOE#|3;d87;3pZAsTl(Fk0PisDm4R&p3Q6R10{=F-F?vt;C`;2YiP;|$AF_iUf z9LgyfJ6HTBeqL#qTi|A3^LYbXgN`2ugoynP9`vOUuz}z?PX8vVmU}jt&;3{&qpJU= z&KPg)FGf8aC@O#RP3m-!G~9cq5|FiI$FV4)Vv4MZry4mO_ut*)=a4h>2QNkBd~%#Q zrNsVMKlKX!lVAL`ur~!CEk9FA^GrF4Ph{~Wl6q{we@EgiCssxAGh_5t8rvxG`?T4+ zPvdjq_8SA#75aE>m(W%O$l6@;Bds}Nb1MSBMQVyx0+<^)~nlqJy4U+JD2N;Y)r!A{&OHd#Merfj{F+#w(mxE^- zem1@jD)yx@ruWv|SQQaZLQt~Fo808c#lMU(gJ1zSx#_XYpb!^$l7b^G7ayn9MeFvi zv>KFps#wZUdC*62<)M+M&A8NAcpP7rIJGu&4UO>&eM4?8LTy(|KLSYW~g zE@pertej}Ts8aYj{*EQVawTyUSz4_!7!yPt&K;*!lkix_XaEJdzX>!ICO2uqPf5!C zSfGe1RVI+yfJD371;Zk)qDd?2;<^jB#=MgrS3Qzc=UubMnv4@=?8dIi`m{!Qc3F+0 z7e-CFyB63_syQn(Bx8w^nA&1U#kSHyt!-_qBY*pQ00ZI7RA*la&A&gsz`nFe4?YUr z&Y}IDCzk^HHBfj`qVwVDtm5|rJ-yW^y>8)r+K0oRG);8$uc&g>BY07MuXv=3Dmc<6 ziD|{WmWkIh$^V8zps5ygiuD0=TC4fRDjevWk|3MoX(fjs5=m_b|Jg8(BEcS3RkUi8 zTAd1v5t{_r8Faf2Z3pbO2H*MN=kS3S@9php`9h`mo~5>SxPgG8XUx_~lnn7S%CTmM z5b%%{q!JQEO0@)lT=f23N&=o|!egn*kOY7Gc;^(~nx=^_cuO^tY70ju`ljCpORum` zuQvWk&hT8HC?2if{gFo)vVBN#Osf>~m4r#+`<35N{hL4*qldAI$? z>xwwfwkANH;r3^L{>!f!V*uvC)~2dxw6tl;=)pY4N!fQJA>yhbECAkY1y8%1?ZY`@ zRi!0osjp~q$r=7en7f6{LyDE2XU*z_@aRF!Ypdt4@%2grba%dvO~mBZzgJ~v|986UR;vM zMD)!v^u>g1!Y9*H5dy9VxXPFid?4~}BRJ1d2e7a+Q8(L;Klt0JrbT%ZPp&6SMwHQQ zg7c;LJZHab*?n>Kr{D9@m+*;K9|r2Hu5CNox%z`tuU$)mDAPQT+!YLj zlEfp^TAt0^5XD!Y>PJ>D;apF-wLO#VFaE7x;a`8Z{VJ3}7}7;C^MF6HM}i1$M;{={ z9%mF!@9YFyqc=XSmmkDDDX1C4=YwIdDQYCA2S`3U#Z9~ris+pxFFL8x3_eFF_S)QfY>DwQ31W!$ma7~R}?SH05;wWqD5*tATcU(p+z$O%I;_1wG^MdK5-;s?N%bK3c>qiO+OAXiYh~&7(m_g zTPiGpXlIij#$ekSY}*c9C)lR-PcZOT6#r78aVbTgzZ`d3k7JyWx@;-kw*T?0w0jNkdp`DJ z6xV5zepqxi)coLy_!VK9nkdOk>g~$C9OR1@e!l&!l< zK1VVzA*Low;=COB5KT8U%Mol8cylYb?o#g6Q&(v0SAk%Y7<0wllm4R$^%eEbQz;NJ z=N{)ji$i|6gqhFwAAHcL4vf{{SYuwQ%~D4B#D`XoTPxd0ATSJB+9*$h#ULjCPV|ssETsuO z^CN@|mLzL^vd0@y<#BlSS{ytmCEDV>YE66`dQPluZEIVw$8XXiq1e{iZ#HdB{mn3U)P&t6|6L0F6=HzX2ZpQ4nSvImv~ zVwS$9u3JKkB;!Z%i<6h{I~zEYC|O03JsD|!L_sJGsBRn7GD;9|pGEZHulh2*G$&i#9>NICXP7P@2CdQVF zXVN+OI+sS3v`^AnlDXFZ^tlf|k9$lZc2uI!E{#>Ouawh7i1K_}rAASn2%GC7oe$m9 zW}0Jbop!EpF)mkY_joO!JlD1+K%T+&qd)b_N=nmI#`Y*a9p% z3&?f=-q|U(1=PbBl>R0h+mZn_N9a37erWaYX@VqV=|%TC6!PD*mgs9DL)2~PdA8qb z2<{s!mLV5$7Tz$>qUK1iT{DZZ(g`?fFC4D`p$Yx!g&hep+K(xcM+N~IhuJ~5Yr}6< z;3&A7w9*f8b%%s&_+(SU6-tsJW$gbqq!|UmJm;MUb4;BOI}%=R8VJbGH(oELjX{YQ zSKZvvw)Vrb>)fqvZ90KwyxF--XWK`4UzJ|u1i!uQcFMw?DUo-7-Y54M(Ng&UpbxA| zK_ftk2ihK~tI0FZ-JW*U>v1$j6Y7jHB*mOrL&^BiqL%^ni3TguwwHT7nh+rg$&Fs; zgWOBeQ7Yoz2j^4Ew}v?PHYhv_+S7LV51KUKW|J{4;B5M!tuX>I2+5C~0K1)_H5UER zwjFj`!S{di9njJF3$S|?q2d^ z*x#pbGUNZ#*g`GFP)fKSN*Cx04wnc}FFsFi^cb^L&!jev6DMBc^?nXE{-xT*^ZQPm z@7@>N#d=;1DSp>CKM$X*CG8VbB^2M3T^4jfl1IsjI|&Bsb5ks+r(|@K&L+V8ZU5F1vL#MuKq0qz{h^B8yNEp1P{p$$d8?1 zCz^cTQ$WR#>Dvxe1;dGY0rdTsWcvAVKho=Qj2%9;U_}iQZ^yAu1dtB<#Q)BJHxUiS zz7!B3iUlhevHV6UDN{pbD7s=$MB{2UwdfC(`2EhXC3RyXLF|x0(D3&<(uE*y9dWoZ zrz#SVBu}0^fiVUWRZ%2!N%M-yp2Exi>LRial>EQ6D5wEmY=D5-wEe0Qy9eVSlf~ zS*t>Y0?e{QKgFMY`XE{G>i52fyBzeNm4q%(q2)=jefIxnu`QvDS=-vqb)PuDIjg}% z6<6JTj>wPE&mS1H6U<9?*!^3Rq=yu2bJCK|hD&(l=Y8Z82oD22wlX_UC}`CN_CXhM zg7!(0;{fDEj1U>`HT#N@76yeR5f}!;=PD&nl8a@}o%D%vQQyPU@Z<@pd^|8g?Ij{< zUpjPeem)s(QW1OOkV^`P7#M*SJ?|7&b`>F)~&sG7UfZqHtecPLJN&ez$=JOlvj zKoh^6@ZDiGB9H&%_2)V?IA`XtKdd(TS@{D4A6^;%?8jeB5PRO|nnS;6bxLjOd>F{D zSx_c?_vE^f5cJ8v*q$ktcX6~@@>VU#xKC=Y+WQx@KmT)Y+*@b)`L#6x@(i^<^K)PP zD1!izev=#QM%-^nQ6|`Dr~3&*Np(0dtmc_h-BY7fiQbVIW~vH9gm>BwMk>zZfuie6 zq3UxT+QoZwVY%jg8Y&1gBX+qcyA66b0(4YMoN#!KB)Cn!2(C|Z)VLrM(MV0<<;3*^ zGSOtvew^*!y(kzZzwdjn7I>G;L8=?WrT#Q9iGE0IQ4%4Dts7&|wk8vw>=PWx=SBNx zi42gKBo{sQb3*JlLa ztr4_si$;O(|HP}#uaIP333b)`D;983hDvrt88R`;rLbo5BuJw+G4mX|c^vsC$+%bS z#)}UI>8bbT+72|m8=X2(Z?Av1!eLEeT?q9F?N#LbbbeFy-UsLk9{(H(KJvmneE5ZX z$vWVvH9}(j^Fp9LBt=Hh9&;_2AbPIT@t!gCi2uJvBZMGTSZWp|AVefRFXPW0n9vlO zXMYe8e)ZjMyIT9_*EVYxJR9xL{@j;d`;BY;LT~)>Vk#3-g_2EtC=|-xHJMqN4-1Ar|_InvaLpc<>?Mg!Wdk57V&eDkRoLABi36AvGb##Fpt>^qx*TOl2pYF z@e*1bVE#txd^J=k~6Z>T^*+%Pw}~RY}R(s>tg2gE!r4L zM-5rc3DA%IKL5NN*dLRcA0&fwSr$JZ&+Z$O*&F^IjYDR~6)Y5h$tBctq-RGBL_G4K z*L|bN-m24DF+_BxO`(z9*}xWK*!z%J%Pz7PdqgsUjlC1auoLp?U7e_Qwf3xg0``7b zN*^oK_rcP0q%>Ct*NKKgBf!5Z0wP(!mJZeHeyF9o0&I1;|5*e!>Cp+=R5}G9zUSrd`rZ|=dYH1ksfm5?K>fW7>_q%slnvg5Uw5D6ONyBkZcaf z(e0(WPhIoDWpF=-QeE9VrPW;TM$kw^qqLfiM_oUs@(~5VAO6nQ@W1~%UjY+`Q>Y1) zS(Kc)v+sw*?!j>qgtBwG^m`X1(0x4mIKbeTLgE;NM2Tlh&lr8bzn3NJlLTDSJt3zR zE8|6cC3`2VEge_{gJz&;jN(i0tXP9{Y-YJhu5;;DNk;|C1+~i?_cuFJb9MtY$Ji< z!!R82P4#oEX#%8bD2NogFg~Vrw13HE1p=*C5aRUrLAE+h;_))6!9Wi65&XRkgbCey zPl49}2t!Ei(^3ae;}Rj$|mn6j0q?I$T0L|6tob)s%u}{W9i(`30F1MQpRJ5@*EdA{Xe04ZN^27EKg6@Z< zJat7mMj?*+N(@0n(HfvL1k(vxBiL;XR0N;-_={lP^r#)RRaS>scrhZnnM8o}JAL!F9%}e zm?CId-A#I6k`p_mXd|g@Fu5^8S;jXNZ7#!}TT#62lOKviC~E29bn2wXA;#Je1>yy{ zvjda~Eam+3oadS+eBO_bE}SRD!7QkQMB?LAQK8q; zs&UUiom~+mfLhLAag~AZz5BLJ*+pm)(FW`~*jOU3?BI?OR^HimhqkZ4P)Y^TQ9ro% zIm}PFMm+L`v+9a-NPhVFG?grVRs#LCO4K|#5<}N(m6{>A@QgWMhZG*HZEeqX^kLqb zIcD-BUaMnk_q1mKAK>7}=P6aLEyd^XAMy4YMVerdWm*UrGN#IM#!wA0NhJw|Fidz} z?Y}#>bz*_o#FkY8$G=x^H)Zz~AwE>|KANGYXG&vIF`iimg#*DZ%nGw|?X9`b`Vbq}paYRs>c&2{K{il4Zc<&3OE{-(4Ux{?8>)63_=E&dds59X z9T9rY0okDxX}joVu(urIek28-Cn*GygWp#Z(O%oB=6<%a_Ml!es`%VDJ;YD{qic6r zn;7s{FD60an8n;ANb+7uk`H6aiN(w$6{-p2&T|?B3i$B-B!A?}(X2ExUQ#IDEL;tM zV6(!l&a$lukUQS~_~+mF$zaq|Dn?{T7Q;PbqtOaQkG)r>p=A14poD99aTVSf1>wk5^$(K+BbpR@Bs!KDjK|>cw=l+7sNEgeLeaRnu~vc>4mabR z$aJoh9RYHOw{>tNJ?yCLB=p)MHeq5pg{634dR>n+0mA?~KsNx4wI4{LBpu<&yH72; zq(R`&zLEw?3Xah)t~yS{B-%JiWJTN^UBY1QMpcZQ(SAwcKtD!x!!cu9bcT6^0dnaX zcNj`Rz!IN!>HTs44U(46NIS)|u1S@(-RXxr1^cP*G>x=hJm0y`09VA!ZkSY3pC&NLJ*_(MGW$4o`}9HwvA>{hM1$y zp)k5x#7L?4mAu*77h!ngtw+$Pj6`+3e^wY%jRsC+cqR+MAw7DH4}n6&X@H1?-v>c- zA+&~^@VQNd?6wB4K7NGn`PfS?c|ia>LRVMx!U{-Ju?H8fUEagb^957FiWfF?w!Yzb z3~nCszC05nHkuRd+)K^+uqW*E;R*kGxVQ42d-RyEdko*Zwr3s^_~o3RH@|NWb2n$9MU(I?D#YR}RcNti(rgv;kPQY46tP3+aFgLqC%&3%+T zNvIY;gGMotT{)r5Gjioa&+1V;yg}lK$bo`O6P@~k9&Cd`^%SuwFUrziD0xpyaEiKq-vD+ z2pwyfC`^AZOi(6VzxTu%6VkX-w?U_ZjTeIyn=nyTFcDN7Tt7a516QR_7^Mb8eBhSG zXzb_PH7L<2R(;izpdtvHQQ{`Mz!}Tgfxh+d%MS@7t%r$2{+t- zK8;G~MEp>YA}x$67!ra_gX&n<&!kNsJR)&LJmo}|M*T`eP-FXo64c4C@IoaY)7+p7 zq88y6wK5HQ3eq&VW0a7}@44z;gI=pn6l%QixfMj;8bQ~J6Fvvp>kiva@h^P$OL%zy zD!SvoWKNkN9@$cuLv#GL{nufHdLrN<0}WCe<wm02|*m=5( z9;)?m+IyE-Yhmtr(vQ7hZRd2>&zT1{dH12`8Q=Qy6~6RVgh+H}phSD(tTjCc6%x*X z^qM6kh);s>LY>-DNQI+ZLydB4L6C2B9m$Ee`ExDqT$^oc0^|<2uRWE&M+23_m}+NP z(qdTorqMo3kpW;g?J8|d!KtEbOH=}OB6#cC^0TV;@MK@Lb~#-0oH>X?M>9E?)L17` zx$cn4a>_4E7^J+1$hu_Wjn(gR?@{q7D@mNJ{vp$f1A9+2sxd-JL5!+LeGDDoL;%Klby&ccrhOh{sZBXkeTZ3M963l+W+Ja;Gt;$SUoTYg^lG&Ch+#hIQ_) z?d0zKY@TSk(KT}l$9I1lF>=|d@VkQTIEDD|)VGwFL)zPsR7rMdJ)r9ETQ!y`kN%%} zZH%7f)*%SsX-Rv14|}Gj)KKsu=MkbeD90Ji&S8e9j1Bk2DXJpzIUE9@*O!xGy|n}s zh#5RP!$hcKiToj#z(GaLMI;oY!P7>%Vi^(*S{x~Qk|Q6&A(b0PbCuDE^|X|PDY0qe zD6Ya-z(BQusxSJ{ka6=`j4)RCTtr}u!LAcafweVgJH_)47$154aepSEOowUhydM2R z6T*fxQ}cf8EVScJAXaQd@rc!@+wQ~}IJQ=A;;bJ~>1F#BRRXVq6VmNQ{&bQEqI8A& zV#K9E%TwNaaSfn^XpzF$$H))4(fd4?v-mvjB|a0EjCE8TtBfD`=!^Kz{=Z+1{+=cV zmTLT}4d9HvcNS%_JL6^HzEUhkt=+pi*x=H_?dp-is9RSqhBC2UJQGcA-%ZgVYdg2L zO4Hxb_9H*}OM`79S)f$rwcYoiP?hMQ<*M^rbAWsPf4d2_s(5Q_5A4*4mkZxih5`P8 z<2hx3$+>VB@eD&PH4-U$Sc=s&!|zigopk;W{)BN755ljdT%E{YZR?f z>^i}&6ST%A3d8`Nh}F&r6jJ0!f*4{$?+^iCJVmO8vFl&PyeE#21yRzD1fTon=kef*lNb!CR&D=d#B=6oq!qv4 zzG1oD6vbflMC-_ve`MEBpWn>*_PKinGvhz_n{PZ=SJ!#96#;Sw+aLMqFKDqkS*JI< zL!3O-sLGzF1F$82K_W$~u*eT7k-=V;p<03v#)gaGtiq0@8UfC$_>OmQOD}ewRTA0) z0m^>vs~N`7ADW{M$ZB4AngnYk8&{1OCq^^~h8wP*f;Ay@OBZD+35dvY9T%RNVX3F= zd%Q5CU_*?Zt7@dkNo*YI!XM1GLLlPFbbTRAPCv|wc(OLwZnxNO4VvZ(jT=KX3fi!v z-`c={oH66!tR5{y&eS#_+VsyX1j{TzK~%FBqc#9>(l6yTSU=b&<4`kUw6oWW*s469 zz4z!51k<@_cFs4|hA6sciH_*d=bREuzp49pR-L#iO7j^&HeC*a^m1DjUxvnd%* ztpsI4g2^RMtgfD;8`HQyDHT9>R99Z_qf>zxh8Ua7={i9tincW{JA++o@ZzI;`1X&! z9G;zn>HSmw-BR3p^a%aUGx_-Y8aqkQAMxLNokW@Jzj*)gK2V(4JL-8g5vMWa zMX<|po_TZR`15#fKiqB9M;2?_!&g=t6$o?g9y7l81CQ}{zWk0mi~2nRB(Do{K%Xj8s$->Ws}ZPwzWM!_zqc89`;_ff$6U(- z#k*VceE@!O^$O0XtqG7j*8aV}`K6DVnCJHv&KD1xR;B=PE*oOQ-*rOx#?!mQQ(1C= zlWkaBkRN3O<`jP$4k8|Bn!^fs49iY)Z_FED$;j z?mjCGk?jZ467}Lo6V%MLpiv^0Zc}_8B`Edku-d zL!n|5KRfDd-+PK4)S;VqRNbNeIdP`N}TwJ`(D-Bq(&9S zM~GD%8b)B$B3!lx=yn~pM$on$+E(#{-}|bYA!R!#o+CXCtDJQICs0Izq-aR-=!~Kt z-tU>StxfG+H-q+AcK^55uT=Uu6+$PCq^d`{HXtZ;t`BtjBeBu*8-vvjKTX`m2mHVH zL(k)Hf9Y*^HaXi%83eH>qDy#iI5wjqT;<8+V<@hi3`EuKzT^1|(RWZ!n@;|Bdj7(p zN;b~-w4?tUfRC=T`h41&0J&rB*WTHEfw@5tJ->m)O$IM zvV^;FnAQv&DfA614=X1fSMZWC%`5q)5+4@w*B>~NAx>iSN3Q)*IPqWCQ5yCC13@HQys9Ji$Aw-L}bQ(92IVOdK;2JWfhPs#LhN!!TbU`L_{I( zdI>!fv6Gx2kO&k_Z+EG}S8f`ZD0puX#Kt8oL_Jz#I35BGHliRGy>rjR;(|trAqwaw zAWn$bmR~#F2x1KgRx;D`i_uu*hY&=2jS+HMa|D7R0g-(sPer!roE;AXB?7C$5Lpd7 z^n&qP(Y`2;vsdM_cDe{flvR*1|lGAlaP1_maL^*#=La{0OKk=a&wVA2-!{ zgh~F~p5Ds;UMCV2Q^&_i=%ZZF`Y2~I^x|BuXAk``uTZ3VFJxm2pMLEgt{O%s+MlW< z{fZEay7MMjPnc!`D@J~g>eo?0WU1HYisCd%w!o84<1hHwPcbG0$tzQDH3<^Nt5U$n zAP6b`>67*&tM_nTZB2mOq4vXn`JX6rBrJFW1jrnpHq>Sj70m{}G1_V->kM?F`1*Ah zGSqjAQ(tTn$OYSjNPGmx9uqegCssK&mU9m9QyLsK+5}QxJVx$towyFts+Kw5D}nNg zhK9%VDGN9;bX$d|XrM5*3~xaBFciWZ4}cgjh#G8&@$NhCgak*Yf{ieg6y*L@1v*w- zDWJljrl-NOm7Wxzvwe^S2IPYiBchi*%scP#)VwH<%7l@3tV$?C7VtUy0*}c#u(q|` zm3F98a}EiJ+e*ePr2%+eFJhuOeUG< zB3W@#&@nJB$)gZa7-w6n_{0grbOx$c??hTc*L5&PvD+G4w}RjC>Guuhdy~yQCYrte z^4L}>v6P1ulk18BI6^3q-~j_yXSDS%Ng(8b_?tz0$Z-F=#UOT0XEog~3z3RAvA8+8 zc*hLU`pL8C!fJ<}iR8!8?}b5V@Q4-P|KaBx3WN)D+Z9Jrc}D3deH8cfQXVl!f}E;w zzP}&e*Yfo@``Tw5Ebw;OlkV;?+uW75CP3~;`?r7gji0c|4{rb{8sb?(J_j#w%6TWJ zlOKN1YFq`=+gl4_w;Y9Dz)Q{&RvQonv+ga1@O92m;lx18lOK829&5RpjP-CKxPDy7 z2IF;z##mC!nI}I;EWWs^TN3K9h7=4YVs0$yeI)lLQQ|M6F7Op^q*?GQL4sKA4HX47 z3>Y(;71%mtY`J4SDYQ!g+NwSG@20Ur=+Z%CV=Mi{@^cy}HVQx+G`{QAQY2___7%!( z*`))g0!5W_mXmpDd#wXW^1v_mEYPaU zcIc+pjZSq&ma&P^%}o?|7Xo zEOgW)J4Y^=a;$_1mxBklWz$QAiqtdVtPBTd*VY8c9cX{<=fC*io!0z#@6=H$)OBmd znsaohEILUrFvR%Ht$`?k9Fwm_Ox%^x;eo+Gj)ORM@Tg?RIPpPDR!Qj*jg2@lW6SF_ zLJsIchdLMBELS!52O%vqoQOQ9W$GC91pz6E^O(U#MChVY#36NCD)<-ohjmcPlwd-H zMu2zTelO|YPOad&r)FSP82B6p!Kk1~D)$7;3=z)-ErIXTu6K%@y(|ThSE7==|C&)W zOpNraHXWQJ3!&@y@6SJ8sl~pEpDU(;Slf99N7pv5uS@&sB^mnboS9+7ji3sL@4J~X zyRrE}OYe&d=Rn!YQW0n<6ym)C0yQ*~H$^1SP{m@vW10d(aZ}BIuIZ|vM|&uGT@ML# zkOUZsxbzzssH5x1}hdkr4mYw*HD!hLGcWCceyP%ai3;*c)Poa}W&ZMoiH(uk^7lL}qOUrvOr z>F{JHcxS7)?hM}EDW2|tr=8lQ2s_kMLJ zIieVg6GRp~VW1(oWQ;(JpcRA85ZYabuCv-7W=r_K?|R7<{ScarX+9N+&i7nS){E_< zGJWqHN@S(n z({gcQpXB?`IgG`CQo69_FU=-A{$xFV<^N~i{}9hVxQBPQCL|g9!bl#sZM6{B&Mx42LloTEuQ-&!$83;B}OcxnEl>{R-gae+L{2l1MQ3Nn5Pyw(ey40 z$t1tLyUK}p077{9vOFMuaKd$s0^TS35K$P;1lO#hfNLr zv9GZ~uELI$t?;4y?vma|{PS24$;M77a~7lPj2vuJhAOEOJ}(B8QzVLx^h*F;IPrA@ zIPDH(G+3J4Tk)FO8x2APqQ>$wQ-i1Pylb6zC8#iz6>1!h=O)%m@dBb9K)vHlMCe4Y zVQ)w{9%@IK5TjjqBxEItW0=mR@jj=raTkoHHL&0JlTXUg==!{ClwY^$h%I%v*1-4S zeLnSb^<3EFj5^hLJ0g6$H|V8 zy-r$NgHHP`Q~cH_cu`uv{{K7s;XwVR1Q-R#p*pOt27zGpBy0fQ*+OJd6k^3W93_)O zxhh#IrXbEu0aYSml^s+SDh-~yPk8PD6CfAfe(WcI$<@S*Weu62uYnR9aK>{jX;-O zRv0i73>1yy?S1!Jv8_0A1evAdaQ=Qb_ri$^_@k&7X+yc}U5+o_S~doT6^lYxWOUbz zG*+N%XtV&rSJ%l1{Z;<_;s3q%N0|G)`Q~?#YAg%jd$qJFmyIpOY=nI)A@SIlwY?#0xQh;Z2J4yNrh7+Dvo*0ISHVf zPPELX$Sj=|qYB?T{@z&N46a}z6!KAT+UYWMYkY>^gpm2%PS!onO_>>{D$SV~#ZfCp znu84X=!GC|j#6@?fC{m~Ac2a?YkzcJ)>n*83P=M5p;K`P0~dUjzM@ovNV-dMfJ32( z2w+sKXu1fD3OWHcP`vc`K3;ja!AlPtyz<~4o_n~#1`0zQk}k28=Mx!Bt~kL@La}yN zpzRHP+qh#pF5sD#Js|XjB$lJy!*N}*B4{*v3RAl_nufp%+;4yv?p@jE2cY@@JEM5F zHF)Q#;JvoP+gruXh`XevYy~@QMGz=d+S;F$v{)2t|CKOrti9Qy3;O3S`C$x<2)a(u z8i)Ka0@=3MZGrFp*z>*hr#^vH-j7Nee+kNi8h8>k@)|6M?9-x9ZtxuIz&bmN^Rp=4 zp6(L)n!m9|0!{e;Z=1)S_u6IW-v9BLGs?-2QXFOOd^t;6@C4!2|1Kne*S6>Msa3f$ zzU%$Z;qU&+li+__zuC`uwu+?_MM(L0X>@LSYHh#&-lo45)0)ptgq(>l7*HUqYkGEV zO@Lf@lgeRq?2XAAUjffSV-6&_ja!2e-bb**iz-9BEev=Kk#+ zcMXvLWqo9?!b%YBE9x{(^!aN#ng@~I;X`IPYbNBv%n)L{_tx8Z;pLZ{lh}lFI(}}O z;P8CjY_(oIm4!#;h#)U0u$<215^g+cu;fW4Aoaz{`XF=EU!8hqj)Is;mqjx$>g7a8 zN-KAI7F=EUUYc#A`2f?3Qds7It?h2NV+)usz0Q#OW_|)_>31E2RqB{JVR0YuME(Qn zv<)=22_t*e7sfL!a<0ehjj<4v6vjrNllI88{Y|4s;-O<0s^qh?AP%UNzN4zWlOR^? zIb*fMXt2I)>?;0!f4;`r9s-L-ZB?8AIzfm*#)^I01dFqCpb5=VK#Mp8jfkbY>eN7t z4WRABA`zau$N0eW_wnkZE4=tgS-Kp#}=z;fC0ou-ZN*uCFO=CNiVi>{KIs97Fho13uuX`Fpfw89DLQcpk)5FJfUXsMkl#wTar%3zIp6i99Z3M|b?Of&D3S`SFEVM(-W zZrWxjon0lZ%&}nk0Ve^5sD$a=O_Gh}_Ji4n^??+Aqx+lm6W1348sWkBl@Ls^ua%%w zINg_LWngb8?!*)4*t9>?=iFPd8dNz{*!R`` z#|`k*g9$@iZ%=6;uIehkh7G=ZUT4Y;Ri4}SLCz>bGly`NmTpN1Sll^I5i{nyyUgm`2|L-zMfXf{`P^Q&LOYajh4ureT) z_JI_R2fMMz4vG$H5_GC)bOR*=!o~$5ToQ<))h23%NQoyGX)kZ0?pY~y0Nex1OwQc& z;hsi7aYB-k-L-;b5};OyS1 zXdihyum5>E{ABGZ%03tLWsVeblah_;iWc&|pEsuSE1~maSY|ls`J540{RTF;ca=>GW$Q2=*^ay$!3Q>uY9U2fPqK;xo z0izv^u?P>VJwbTs0psQ8uke8v?&J06u5fST69)#M#v!U*0%~AeIBF%OunzJy#+oh} zA#4A!*6s0lZUTL2&!V+P5hX`#Pil-dCMfrMANF?&cJ!x@?-3qc-Ny%>vnb%}&fu-5 zimzYq@a9vXGwPB*oCvoMic6wkUFXKE6$MG>5+NOosvQ%f*mVZ&uEVY~*mWItyAH3v z`UtPRbl;8#(;%Rwu!ygL9qG^yB7(*R-n?y__fJd%>&MrMyF2@|`DdkoqeguAr#0zhzw_=QX|GC8e_BEFGzo3*wUP37$3GL< zq;#V^^k+w?4$svly6t62uXk#{Wld$qFI|{J*h<5JQ)(FZ|r)8OcoC< zxBu57y>n}80^~y55C7$Vq612xo7m%N?qYXN6Q$eC(@t^Swyp|-tG>Y!U!umoa07V=h83;1|q=5UB@P(;^YWI6{Wv#;|v{WQx9ZiHiEz*E-Dk-)78Z$!mxty7Hv*( ziKy&08samo&X`AsRfrMv4l{~&apq*N$&qt!rMbDHSeEzSjoCdjowQ>yE=M*6Y0Ohy&N zEY)qY-p2DJpFZ)SiS3d*=)J9FKcxzEE+Y~PnyWeiR%M7NjQfnJop@rjw{x5xh5|jx zLoBtGQGs+;U*eTVSNNva9^hjy-N$qHo8s|Fv;kZ|#}*Vx2-M{3N0@p_DoyuU;}Qej z)@#0Gj>ZZ72BMc@hY|f-mNc3HV7B<--q5%P7I-3;fT7l`r(qHY2 zdkMb(+g~2q9%AVN$kifyxx?wDE&cp=8Hb{sE|S>(vGW+)#~|R|Jrj~<`>b=#^zoFA zZS~%?=H)!}$GNmak{@zIws28niIybPqx(H`GjI$)bZR?k%7(bn@2w#{W)}KYZHU5r zS5@byN8hQ8PrmN~e*N8Df4;cl4hGxvp8B|xP_MYk$}l9*$Uex&m6a2FvP45ZMp3$t zF37Yd2ql_a0J*^S=YIZ+ z4;rFdF;QYeZ7LaHwMecUz#7+6zaX&6@+5H%n&@N@^F z@!##-ktookFyT-Y$0^+hq&R4GJbC9`hX$f#9QuHVtB7L;u}dJ5)z0ys@uHEos$&BY zEAVI`$6QSOCBgID$O+D5G+yo^hEwM+i9{5CrtJSuYmjnesQB0gv7=u*+dRPhHQ;%| z8M(nZF0j5PLXPKHokDlwroQW07@v6Gj~%q5(}14Px$d1UMU&7D)#gL?9&&U{ejj%* zN}AYb5<7@A_N@br)!Z4$-mzQ|Ld%_KInn%Jx0ez%*ks+RqEWGqR2}dBo`F*(KY)}v zgcacowj-J$K_>0Ks1QIoAO}gbKQ{~F<^jDSuCPJ`;HI~`OcRnD1_mVL>_-8NqJu)j zK!nhN0ArISHtAu|c7jd?4H~@u;yrxm`Fr@#i}&&9zOBG)v=7LrL&BEq4ZGf(gkq^* zQxs`&4C!4rM3D}L4iYHo{2UM!&Dsw(#Mv#E>2Kn_zX8ESg)YRA{U#LXgu{Auwt*12 zYG1-j4+$?lc#PI`_{}E`%RE;gbF*XoujP(b^2uugG zM$mN~x~-zyb!c0I7oKbIp_d;ev_7PMAnNvsA{B)d>aFq+T*GkhiK&2m4X-$X*_f8c zcQ}*c5hM7VQ$=wDlpobXYnu9+G*8PYrtxyZEoW(`-jvn^osjBUZ`lMUo&I`NO0-&K z_9<~0Hrd@YI(hu(efy?zox~@P-YZ1-=!*~WxA6Ahyt0&;U1W9G;)fWe+bBEioJVkS zmIPt2_KYW<25W4;E5*cWT6kk|tg-!6lVXIqb8VOm(HjukqztvY>+n7RYXam<+L{2l z!1l#=x~J?ac*dN@Q)S|pNTK=UN2`iATU)KgXoA?C7YILwu@M`%xlx&mwhx^D1C5$d zdW#uDaC1fjhXbK}$jIQHnxmzvrnzSgbk?C-4jyuqrX;yW>EIu%ls)f)0QR2SY`LT;W>p9ELzh(7QlDfOyKT zATBRbJ?!mgWpqVP(_fX6Av6fooz%#X^qa)Ndk#t5ol9#HM^s1ppGMZqdS)Kt#2qU! zvGT=UrsI9;ag&I~khQPRpJ$)AYIe1>c#UAu-mBEpagx6m7eJvenh(1-Nxn0;HU zOq_b3xU-awch7SuuVUnFNk^@bJ_!=jde-iu9XpbPCEtX2FH3q7R&RFe;PJzew@8LUMy@yY{{s<4)7IXPxp^%Is zu|+1#!$h7kl%+>-WK>p-=SHVe03;nDBCn63i~Of0MFwf%RH~~GY%Ha4!wm=$>*F|0 z6J@_QaL`mVE*atzI;u7qVylK5eBcGf>n~iPZ56-zPK&R+y~Pt_iK8s#sszMEENU;t zj_b}e=(-kNYtXi8sjpgtt_8mR<1hATdlFlDOaN0eK-0u?QeZzs?jDlF2-2W%Y*F^X zKn}Dn@!4$D>WEkbN`r@uqnK6uJyXe#MF{^mxK+`1s0R3Egt(8P0kzNmscP;-^5Y`x ztxTKY(n)*olHFGwuTe+z__~uC3M(Z|D!|~|UwZ(fga(R+7!px$i?gP9hl%q2~Y(u}GRw2vck(PJ^lq=frNPP! zW>quG06vvrkaI+*f{sI>YVrsKxtWUEn%0OH_a^lRONuy_uhIJ4<0;nVzN!Bv}~H*$mvwU$~|2g<)mF~ z$0La3*?VU}5KL7_uk|5Rao_>soad@fh?FSNW{fOu3dddA18vo)o_X>^X9X%dr1TnI z12NaTIR`qjOKi0uz_E)5*5t?KImKi4)v+BvpZqu^=vA_B=3LL=2}6=U`0@v?t5cWX zE}`R;(ff@5-v&=d`^*KcR0^63``FVl#UTxgc@hLjB-NEuQe;+Cida=+={S?1fo6!0 zNZ35k5V`j_JEe0rm?~hpK2RzmHt_)i(-B$)Oxw96h@ch4i}yG9;46>tvDY5r<@*ib z^wuN_AW>w0vZD~q$BP}sRuDkT#<3Y0@f@i=x`r2^pQcXvICz!vn8)`cMLW2!SdHjP zEGMchgYh(3P7_74WQYMlptygJ@R66V@Xaq=;WxKCeD!U?uf2N>6%OC;HD2Jx%@~C- zExOL2>jc|fhuzkqKiam#w|>(LR=dvICf<&AV_2fJOHg`HAP($tV>M;a+qKNjkXClS zqeI3-g3#&{AAt&nai0~BHtg(RK4?4g!Fr{Uc~#Ml$^EUl^Y7G2h^l``r?G)b{dvyk z|GY1~*gb*G_dS42TKP1|N8?!E28ieEn$$qmt5i z6AdgN&zR8k{Ga{bmF<2UQ*D9Kz!f4;J%*6bpH}w!CF9m#XP8i`*V5xZB2k&Q2TQ~|HTK14gvEd9n*~jk*ZF%{pCA5 z&pCTM#K$r3ePRbI(tgbifRGcdNKyWfHb?BJ(7uL;j0chC^LKKX zS93oTS4_^R&&mY98jzT9_GREMFo8BN2f|5d%(GE5owu^en32B-cf6Oga1 zK{hrCav79DxvomTfAYfTUfYp^07r7H*2KqUIK;K{yoLli)%sIf9sm<}(6J76Li%6P ztRM_6OeApaJx2&0-}D*_72s1h?t{CPgHa}XXnO36^PzxhDL+5=lu0g8W8c@$U2n?> z0b(=}C>PjZxcZ>80-ah~P!T{yT&O@{JY|yDS0_Lx23;%IiU5Z2p%?GrJ3jabufMSA z?J9@b2tgB%Y~WtkEPqbczEFc2tIMG!goopBV;T=(BgC$!i@Jf5Ao{54j+5v3U7R4hhO=|7Hubq z{);iTc&#;pwiC3i35k$)r+EKM5AgiMD|b&6P{;i~LWOnFQ~X(p54J!N)-WCf0nsKy z%y_hN7IYgKheu8SttFo;?(3@df^O{nD6-^a8ffzgsIX>3qO!kk9`wH%8*V;dgHl?Q zc#M6uMn8RLnydQH*(L6B^E2w1LaWS4*xgVvi_k>Cf5E5U_Yi;k%kK;l5Pcj2$%rvx zbVxs{UK||}{iL|Ru*yJB$BL*=(J&vQrSw%}MJFk3tQ4s)mFW zMu4wgx2uzOMr}=iTu^)C?e=NN?0OA{%+5TuQ5Bn0p)y^$ngn_4TF`3r-l^;Bam0s? z)f(yVN3c(liH8PY5Fx*bpa56G7LptaLOeMxxzn($3RVVO)A46RQem;HsRPl_ka35i zfvsu`#zC#$9S^vpPDeuoL&i~9^+*s^g|dU#ldX^(1T4g%LA0md@ciSvY4FZl-+&l` zHkvq2V2iZbpyvr@w{C1ufDtr8nkK6X0d__Pb6}p4Y7HulMj)=>mAw-ow}?t$O!D8K znT0*Fmi>4*(b)mZK4;e`KR1zP^c!m%+lN<8j`J9wQ;)$|_1aAYtoRtFKyh8i3Hr+3 z;3+ti_j2HCfe<~B2GhQF6J`9@C0p|tI&rda$UI$T96iNX z;XVhXYMl58Yl_l91)&Ln{*>Oz3!OWv(87H6njoP1iAvGII*=A;D!=!b0j${Wg|&Oh zX<7suv#{SZ%t3cfp=hE6flUT&Ang1?%a;{2e8?9t5ko%dVnv# zwZm7w{uFONZ6O4Q{!mMOwbLMc-tAiKb{#(bvG)N?mRbsy{whYdlqjKMqy%S(2{AsY z$OF2USQtKKbG382$@cGithnFA)M}RArBod)Q8jc~J1_pi{ym1XXBf*d>urUL1tnVJ z*cbKw;NiuIHHtAw_SCx-I+v4;?IgQFco_ZfsYw}PEY4bhdnP6+N(RW1!KIBgcvtWyaBu^-lwm^3XX=>?{`>PK-K3_BfWz^ zcZ>=S=iu7fM6=KZ=tTiCAmMC&IIiKi@7$*;y0$&^oz92aK(n!=RWRh?_$eo`|C|Zh zBhGnn2@&HRPA2DYH2_&R@vU#X4T42{Fau~B5ENo;wOF9RB48s5G7Y%t1v`83Nbk5b z02vr#_6lUFD%dA~Mxt1ywK-2Cg!cH`L8enMoDSodpH3Lq^8L$`&mc zd-ae_nS0zn<2gH5r%l*QqQ~}5_O8f}Qv?f7`5lt!?C{wPU#{3)-`~ptlM=El{}|JZw1I=n5v3Ajgj*kkfEvy=V-qV$bf;gwntEQ(1qZ4Wkt*Z|D3{~%26T&>*K{q zfc%*#yx&>0WRn~XIMQ2J2)jg;DjJsnP)8xvkVP`E5;hNkPu{ZPD%&+ii#4b&Kszu;B)u{^+Yc;)5u&lW7owvH`XN(uEw=mCdrjxFpvm z@-IXz;s@N1zt;-!g-aamJ&&3`u@Q9nqU1+hFy-~)N_#%h|DU}-`;{$A^TV*;_w6|6 z-n=*G%*v^%GHd9n>UkuaL(7yzk+em%3Bmv&`N5D30kY&5!M5lJ!LSV&vLF0p!0>-y z_{o5pG(kxe1lb@AKiPn3TCkd|p4sfKDKl^8y(eO?^?iO=!(MCcwWo+3!#Our;Z)ue zCt}CmYxw5x_v_oJK`u1HgOFI=5?n$EJ0bl=0q;kh6mtn8yHGx-b1HU9yhU_TcH!d_0w0a7C~wVzGw+sJ--1Mlmb-@5lz~$ z4^g;Fs#;Rq+S3JuxUOuK!B`$FuRZ?|R6|EjUjMr!Rd^}UVSs4peLq>}&}&!O8i~Nm zgo{#j?x{jF+Brkwv6LGqTxFR^r{pbin2-|tH>)I82GlqLOJ=li$&0%$o?*A!;ql|g zunIKR86ZpwVv2koj`o8i!FdCpNQuUUb_r1-7%O|X;nqmfXPqy~PZcjZ@5hl-a~+K7 zIhnq{&S};Q2%6I3dERr`Pvqdxh2775-FmHzyI+GZo-c?hj<|dMAwyE=jAD;N&+tBk zxl6UI3>4tFj!~@yglnB0HX}nN@<`sEm(GPZeGx>gqVKMkaeTm6+J}x1Y5Rxugf#Y+$Rj5vW3f}M`>3c zYJE5p@^Dy;@L#5;A4m)xx6GrqckKPm&PdT=qMn?aT!97wk@Ld^bvlSF;te*9;+yY0 z!dKtA#sB+vpWz?>!85cw@<|Yj)&N^$@asSG9&Q?n9XX-XnREkgBz87ylGMToEl_Gl zyS*wdDUr-U=&lYBC>>WtS4<}W9yf|d4FX0>H{X;OKDoeNm+*e*@I}rh$+bnkr(_TL zoOXBc!S}b8oZsJ{?dC>ERM@c4vp`J0J!3+9eZO*XFAe6D zk3M|NgNe#OpZUxF$gE!T7x|b}txwu>qFQ@e%H4E5LJ8aWIO^^(pQPI;^OO$fFg7 z%z3?fdRk^3{w#C4Ki0Tj294!|{Z8ll?g;9BpBwzsqDw}^_g$!K@K?2if}e=M$#=1K zRg5`5NKizsnV(4VP83a@x}5MlTqnW}6lye}J;fG#01b6yph&)tlgdkpj$Z;rke*AX zi0efSgPM)w2cZU^{pp|L@yA~SbmPd&lw;*aTqkWH95_8ZK^Yujx^oOeeVy+ZF>+7> zlvE>RKy`5k_r7=wA#@bES?sFn^nj4V{TXRD2u@xfMF+^9EM9aS*Kr*eHx8*5)ylu; zANEVASvxqHoy1|Yfao4}^uF_v1`J3N!gHct0ZBg?=;0?sd=Z31;jN`zmk^*sT%nJV zuKPm*D3W@95Cx2ynE0?FzUV@r7O>*FKa4Th8dr_KGlExc8NdAXSMi-eb;pW+|>;~(H3 z|IVEwKHs)ztm0R`_nw2kBG*0KL7G|k+MJkhDDT~o@K*c^lB6Gqp-O1Q;--KRR&Qt# z+RqBqbmkG)|K0JE;k4nz|3p zS^_U3RH7qr7s092O;yQrD}{3im5pP&QYYGI^XC|6hE9^GJh_1q<41q|CwTX(Uj;SB5kYDn?kFU4!u`48 zEde!6#h_tWQ5X^26n|f8R>(qbm-2wg;JG;sC&>A`8q%QE{c&@yiI92nZt85D!!aED z&MS|}GP~ksF4CGqa(+pBdu|XabDC-SwU^n|^;wgo8-pqxAw=YgAu55LuGk}VeNY|l z3SEbSs=`14Ll8)k_|VAlVIhv#+$TOH{3yX%SIn|A7RD-UE7*zRhJauD_%(dzgU8s= zrqgp`UAHSJ$16u4A~h7sG$s7i#7vKMaVYowj(vDsmIN%iDpzNyHEEJd`<8TiFYIA6 zQ@KMr-&S%>6$+(59zH~*F3vtBXRE4)PF;eqf<+;XgP>}N<8^k_;GI_+{A+*aBmCSa zZ{oN9ufK<9pFhWUK7JFgzH$q4jU`F)BXrxV=e*0YnnRGS2Z=WD#Nv}T)<37SHJh%P zL`xE0!Yd7fo1C++e>`b#pYrnT5j!ZcbRY?`)Sj8vn|z>LMg~ciaXO>aBA?5QaIV$gkO*Ep59fa5?04tI~+5->zHLcb1fJSDs@blAjC3#D|Eplto-;hZTjjfDwf;2F5Ck5$ufM)!PO? z`_WT;_x&fh-Q)=iA_Xz$x|h1b4=rR>*D0C44iC{Y7O?4C4eq<@M?o7s$REj*5}tlM zz*qV?Id?>a&$kM5kI#2> zE_5iU#PjFmgvQJ=BTq)Jw}wIE;G4KNZ#83z=Om$ehKYB&SR$VBoOzO=kWU~G70*{9 zU2sUi*ubDopr#^0Wj432yfZv|2nbj!zSI4bS z%_@nC>O7oO8n3+OH5qx;%cpc|=TYT7lssQh+sib>Z;>I zadF3iIM0`o$ouP_ot0pH5X#SnvyF-Ign^sJ!(t^i-8i?zF)DI-CE01ab)$;4O!Fj{ zfCr?Roa{N{{=WxyN}ALu<+l_GrScj3{Fj$wFz++>m)u!=@LnpDcc+BDT5?}AyuOd$ zcnqV!tx8OO_Rs22^e_~AN~VK58zd!1AA+RJlL6s#rC)t4l$7xhX@3)JQCqLsku^jjOOqTMsKFVWiW~GQ9SU>kuLD zd?>)^crje3g;WVjBj7c=YosmR@!r@~z%esy!}$D%KgOdcUxl#oRc#xW1QChkk17P( zXs12J1sw#QjGZ{C>H%6a%R4&ENO~7*5Pvw8U`{FVyBBgT7W#bU3^i4e&8tb^egt)xzOi3hVMnCg%EJr!YSDO`v3k_;5wPcFOFNCZ=zdY^f+yW<^I(9D2DBYh zspn<3tPGvA!?uBdon`3ek14KCX=4Vm@l>Ccj5{g+jAl?-$=^LEO!<1&b&|}XyQaUN z*o_jn8GYdn8bopqKgSyppOo?iLgMDULHgy|C0EGV0~>B|vtc~nS?nz5_sAhhBc4}; zMytrDtr_-7mH_ue(Jxc~zu*tNcH_8la)=_h?w8uRTaBYbR=r;2^jJ+q%Zj>%_kO0! z*PC3d!NT~$49=c&+L8BdJyzdOQ+qeH4Gv6(%)Y;sk}j{`HhAwTS3- z>{HE(^<1)~`+KLGxk4cq5D%o_f=%`QY5bERxb^kP0b&wlhLFzUSl0~5MU86$=buab48+jw)@#X=*a7Qf6Zv}<#(mP+z0+@S@NU*jE+a9p2?qb zR!U_>3fK@l)>Qe@tmh!WCub1J%hSL?H?KBUcBRl!y<|$o03Dm-NR6%z%bGM`W%uXN zMkVISEh`w$-99o^H-xAG-P{1%20!`JAL5;_eF)aZKZ}KG15v~z2ob@kU;|DPBht+U z0uHmQxY!x9Fc7xRU_T$4z#UL=D1>xolHqiY11G-AK1rIC|H#3q1-Pz|CYZammT5Dmgpf!>tJ_tYk z{$u>&$FJj-8{`w8g{G8-RXW!+Y&!BV$pg+>0 zky^1#$LmLNj(c)=bWMl%Z2CMB;$OaiB&zJPnKL|70inwh?$HNq{j~(-QwN@pL&aah zcgDhZfTYjFonRp4i2Lr4sT3sSiaXSGA>Tf3@WNWW*b$5-&ae^>r^W6mU%deu9tv_gn>pHdqAu8dLC$nWWKPHbuI07>FD@!`9YEaq zbQc)E2!zgMVn_D~nqDg7-$S*z7wzLE$&cFad*9@~J7QTNOTqZo+mG@8{G%^p5rymO z7>{ptf&7px>F?s)FAiuP(wlou;x|O(iUmptxr8rQy`o&pFR3MYj_P6ixf`-Yi5#z% zP0!)g|GlVjO@LhB_&5JA|MYhcIVVGkVV{nSv5H?Mf;EaSMF4DErvX`zHc>zv*E!bA z2@6mH`xtm@-D}^N7ccl}k!2f#`{i>iX|WB;#=;_Pf$WkW?swLL$6zE7+`AwDURBpB zZ$mIX$zbS60E3cuDET)3KtvwzN6|=!x#;%sh~m+d(_?yJ9gKpnln780ntPxDzCmT+ zydkML^ev+{wuQ2*%(LvBIQQQ#o_*%NN36r>wt#ZSJEE2Q2wXc9k_s#ydY}O*VP~X6 z^=wYx(M!Py(Ru)GI>|tjj&WvOuJC|v{r3|98Kea@P_GSE^WbB&o3WXI>oxUoIC zS8>STBhAwlQ}5{68?o4jtM{Zdyq1)7Y4o3o6HcK(E)b_Xa zJzNRgajEjN!Xej=8uKbj4q{b&5Q;iDRYKQssN~9kxQE#VSRY(tRlL$PxOoITH;S!M z*X1m}f|zq(M47U^patYtc>*JpE~T$gLbmSUyA+I9nkjL|Xi}5ttZJ|eu19@-1VepD zN2OcLdG=t0bFKsfOR0TLx+MNUe36W{BZRy@w}jM65T>kq$-iN}%yNrk}FC0bQ|$D*<;Fde{{A=$6(UrWAKxMV#mx|q{I zk?Neao$Jr^6C*+XuF0EOFYvWxysNpApkLCsCO|H5Y%M;45`=9AS9I{vNd(z^r8q7m zp0yp}vk+V+c}+z~BaSdrtiX2vp%sEW`?bpjN2xRBC0Eu9DtG59_!?Dfa^{GH zVWD8zzdgMglp*nv_i60!NHC{$E|9R6r4dh>I;-=$VRECw#^gepWaxN8*e|AaumB{0 zx(c|m&4{sqhK>&=kd+RrnJGdG5I5jP&};~H)8LCAf9~Y2Ht<;HtxkpKcESTIaA~) ziSSi1@zL4eA;IAaKIR2Bvd-d)k5d1vC;RSY0g50|NJNenA82OFhxgA_pB(tnwDSQN z0`B=lq5RdPH=f*=3_Pn2$lo#PthomeijpF6iH*-}mE0W@Lj%tp`F$u9`C2yqiV6ZZ zPG`T)K-&Oc8epqk7m%-Nf+b)x2@%v;-?5vUii8Mj!nxug)*dyCTjoKZ>;g56|NrCO z+#Kkc<36Qc+^lnc4617L+NFG%w!s4GufUR% ziq&uT9hu~Z=lG=J3o2Ifl!zeqdcH4dToWJ{HUjZElB(e~1+;pO2E{x+iZO@f*-o+Z!ZZ-= zQ6-Q)6>y0{Gx@v(OxuC@ovy+uuy50yT8H-4|tujEEqrkr;F7-WzgkVgjnzgXvslFj>mub4r4Z5KO#|R$#)4{SXM% zwd=TH*vKOSB3N=T6V_V1`1}hrZ@u9PN!2Aw8sF(35+dn+x(W>LsyWr) zV{-wOKedF`s>I`~->{R7GLi%t+_R*yVp5V5=+2pXhwvQ1$#Z@0J{`XgFQ9&j4(5_1 zNG?N)3T=8=Yh@GO9^*oMS@rhbmIlo`g%V2^wGWVt_tzJSE&By?~)49Vr%R zcU2$9Uhw*(CO*e~7=m;^$OYaZAMi=KxWq^KR5g=D&cfGsTL0@o-tWGNjNnrrvr6y; zFz`a2fm9Wry!ohmp}dbGk?aEdnU@+ly=ZbyxKO_Rc;1-p+O6@NBuEZhIj3-2mCzLt zF~JEu=b zT@`!caC8CbdOKs*1%Q65xh4=-rO!{RR8o6~BvVwf$PMpd)B;Hc-Og6I<#8!#9r{t^C^XpAz@CWUX#KFn#%{xD1TphJQbC>Pyh6Xc>3n+K4<|j zht7{q*^9V@iLxglBcO>Dmo8C49_k_xq4EV7zg#&zDKUC9;4a8UZ#;yVQvcq@5+9DU zl1Ar%h+uo&S=Z4&OIN6-%NapWOV#1gM3&z7Ayk~5-^3D|>^ zA7e=>eK_ZA-$#*}ErUD>GURwy3tVVHaK|>j-Jv5L72k9q(P{6J9HHx@OMV2d55TC0 zHVQl+0*DZd5wsRC#=uy`wgq;r#V7B)g1_*sck$%WCb3~P29m?JAs$Fpctgx}3Q+PI zVMFX?gRe%7*N6a}+4UxyJ;ypnSStaLgoxbxB16FzLC38$L_W^GAd5&H%%{o>nI}a8 zXAG9|Jb`fHjThpQliK^ea0B4RKZiDMZmklm?`llKYlAxN8FNc(cLVPj2v&ZR=#8@6=S^`N3tpgwmLibg>rMc%3hk za!Zw?t{9916n1RThrz$*(L&fRX|T-4;3`i^ZX@LSxO|2+e41XtEXnoIU(mQFKrU$f z$#eNrC)Ws;53gs5LFAS1(^%k{O|VN7p-);T!9Kd;TRi5Fy2+@~6e{{DK99sX8S4Hx zwy_YQq)57|Q_cUDI_h(vz)Qfa{u8f?(-eI72*9I9<;%Am;{C0(}n7j)YMk}8Lr zZ9C{Hh3D;%`28-C5+;^1a>^98EmeRFid-UKf^8U||M*AvNWU2q9pSrG8<^JOX4AOf zh7fL(?PSCmKTWf7*C*#>-g!*vex2p{Ts-!Buz@QG4aXt`26J-s^K~nv!7GvuC3Gx~ z7%=xsc{euimzMOoj_VjX5ibQK#8i@D-!q#+G0))leuP}am zH_so%K##E1Wpuxsj{me@Ww-0J)Iy z@BaPo|3>_!@d9B0>xUN{|Eb@XsD_3Jttvh@l5}Ob*7&Sr!yBp=p16_vLX-yt+ZeHB z*$GnX3@MGBUPZo6&7e#wyrFjbtYT1kBD1}Y5s=~rrVX{== z>!_1O1IFo?Q5rC@DRwF!s7S(nQozmDZWh(y3%fS`kPwlKvm|$N`w(BDn$GPB$B7a^ zBA7QIG+<^t`^l%iiZh?9^uMYMQiT!VmIEY310u-+EUZ9l1jYz%Hx%mR&N{djyDJZ+ zcELCf?KT&1@1!%x-)52tld_9Wc~a6V%+pZ72*9;N<|NMN7?$qx>!s^=zs3-uc;5)o zMb~rsik7bnQ{NffGxxw0WVAQyzhyd1D2ZL!9)(Un;V69-g1MZB47{NEc@(92FjW_Y+ z5y$6BlON^1*XE<_6zJR*%8~_L;v>i2PP;{>iiGARKQsxHq}?C=4sz1mrD{MiCPAWL za=p5&RIK5$#0RSG+xdg?9qIP?iAn=nl5}sB`@A8G2F|WgX<$fUh(NGl-k{k4H`L&n zb(}M0_iIQj50Tvm9+FT6tZK8rJ>{Fs3`_Y}UhYvtH>fQ5OK65(lOOlV9~g!_A|Lpl z)ZfRR;~^ckX7YoiCzo9;rOEE&y;mFjlb`qkT~3Qq>q!6=$~rvb2~n=v@_m0{ninKW zq#_=ca<7ihvCjUEx*U{>K1c}P$z*e*(ty~m5{Kv)9$kIUOB&Y%$c2ngclr;@LsP>% zJzV*BM|!Dhu&VfMryf?xU8RwLZ=DkeMmUKwSnOY$179@^JFrh6VB8^|BgmA-XbbPNd+YVhLOXE56q&65Ud z8wdkN6gM6tS)gFG5Hw&_v;y34$1~BS=i0*se6cfl^Y#{ylC9>HPR88t8wv`9b)8f7 zt0NxXVaE4788z=cA;}kbP#VycaIv?BR}1mfPV&A8#D_ZgOM!>FvM>r*|bbaB5MWX;%X5CfI1jq%9f8)1)ThqfH4olgcIyamUcsI)PYaDX&?o?8Z99d;b**Oy5_=$?fk z3n~<9-7@KX1dQlGN8ZC?u~&%u@_qDnW6|}|Rrr;GoPLsH8dhZL4K&+8iNuOh+=q71 z62Yi&g$Ld10(IOF8UlTizxz3 z5QVab;j#=R_En(@sE5Q-iHQ*P9R)(}-e26cc=O5a`HWWXR&IKGOC}8ZogjPcj{#@; zcuwt{z=L+658jSFZSq5BotslTH-iu>*KxMB7~UsS3H-DYI|Rn=K~O5_(216ak_$x2 z!>`l}Z4r^cS;5P7dHHJ3N5J#ndd5?}Id#BS{+f z`UZIy1CQIXBhR0AcWMSvtDZwDcB1;khlsc?YY~VltdipZ5rU|N6?J?cMj^u3wu;ua zFfDMm6YN@ppZ?$}e(hVYj~UFSzf zcHVV+wMMz~di1 zh`2N{sZ`@PbIFfbNYuNY;4!;%Yse9yHygz*GhX;aNY-_fc7CRn)xP6MRKb!4-V{%6 zavv>66=-m&T_7$Ave3u6hvO1DEu^oaug%w!HsA5a64}#x?;@jQ;y z6%@bwbQ8^34zf}yN&c7J5Imr(mXycT=5}duFIBvVibTo`+dp<5LXY$5>u$r!GW3SOCd_^If*4&oXFe z)ZgF31wO>OqQyOJDZ!@FGCqr``R=+7x-2(qhwB(PK`c7X1@_G%Au&=`de-?ry4@JM zCK}2)K*o$588Jcwmx?CFjz|hE=HZg0|6RGk9UR%t!*Z}61PcNCBm${x0X1Ts!jnKU z>Vwo?={kOn{+vVykov(QLIWX_8wfry&&<$sN$d0`+$wV~U`wJ1~5Pj;Lz`7!&e zl%cSzR7J0}NYwz+shuGxgZPm3qH3FQ2*Rme4bCNcskTpumdspT9Zy1{i6QIM_`X_UFCy=6nhTWQulP|D$r)*OR9fEgeC zKEdbYx&u&F0pc>X5wnVOZj-K09t`w_@JrwQ3cm67qqx5vtS7sqSd2H@cuyhufxry{ z3y|OO{@FIfk;|+p3V`}a4lcAzQkXTG{HR+i6x%z76Cc6=OSga6CoUTmkd<6fRP6Hl zIoL->$t?e8?PFh(xQ_+WX89g8<(n`_WiW5Mfno#TF#|0L9l&o!3pP*Il;q)_=Yk{M#vmwWqcvT;Z7W3(q+i9n79U zugQ;DHs29#tr^^$T^0TW#MD6!+3@`>;&(dcej+L6jV9Obz1JRl)Ch{`6j}T);ROwWFm5nm9BRu!MNxu987d0t|BY7pW>N{*5i z%sC01eXFoE!`+g_4opxaU8}ifN+$AJ9I(HfvuQ`OU$uMYf^0JoE~d#92FJ?ToF~Nd zomA#A1SA08b>Wj2stV&BeXRwz_M9p#98`vapxkwJx$6_Y+_r<&%;&BtW0z9uLx=47Zq5XRZc5=W8d~T zTjPav!E@1|UJPGS3vmxWHD|I_itp2)fy$1}@`9&G&V`COa=Ic>6xHt^ny+IfZP%6H zTvvTMpZ6_5KjjW953488s7=?s&YAt7$?xjt*cw2{B|n_qVxiJF4iI&G6)yQ9KKVh| zT7fafb${#>yB7G`JCE>Je&(GRfONcj9cYMBPEH=|{~Eb@`tLM=!8*^^h>)Y0COn^K zr3@!Olz_$;$uz3i!~oF42cMYqL1^uBmJ~wGy!H(NH$-^M7LPZ;m)zhp%V5z+fNmi% zu|{a16yV7Mi=N=Mo6W&KXg&F1E0Te$iI9CszH8*<>j_ieXS@`JVMSm3P(tKm**8~n z@Iuz%SU$lDXKK!#bw~`Cmz*Rby!&_qu>dzfs}dow0xC=>@QDSl5v76?*xDqLqFi)A zOm#Kp#j$e^or^)$lO>s*zR*h@(p%HkD6eLz1{#By%ez8eU(~oJKrX;&rD%xchmRK= z+hqqbb#A!dl3)Dyi>>y^{8BQyhpeateJC+XTKbRQ#xA1@FF4jU;mTW;YJP2&?crEStOPTf4tm3M8EOKd`N?wWn(IUC>TCjS6^6RxhcUp;7_Xo&HODjwZfJZXT>TgD5&^o{01xlzC> zLs>xLWYX(5Q^6`s`b}l$_ONtLS#okoQ-8Ou{`-Ka-3*n$v#*`rw`d=@hKj&LGcTdlV268f-jT ziv**C$aSisgv1(_aS_@(GbT9so2~c^lG)m|#D*pGIPyw=cmk2Oy6@-uF8z)gofUIi zI#@3Q3h+AW3u1qeG3^cWg1tf18dW7TJjA9C^|6_YGux zGyYB|cT99=Sfmon54)UtC7VVwj&RFbP!IPT?|LQNli`O1) zyglQC3emye_&~4gc1WS)Izu**=3qwbLC&1^eGeU`d1-)nRO|gO>%9zU3lBOo3j2e#aEt*yNEinj& zKVy3WUk0j}gq$-{BRfz3&EByvq*>cx4@-EgqI-c6HqU6#tZguMb!Z>2xl0gO2PF_{{9}lG z4EU}M*9p>LNGc2jjccD5Um@z(NdPpej@{JX$BV7OtG73CUG94@AXJFv0o40h+37f9 zTnS8icKP1gM*FYBKAjpmqXPTd{jruKsH^S|vYyyBafFi4>*8EsU)N{rA=@ z8$54!F8M*u-lbUADe>$&l!_8wohtg6lQotZk;B5DrTX7$iHV_(k<|Ael~d5dJ{kV5 z{{B6D-w#Juoj??Aa2=O3t_hGcjX(O*JY%0kU}9&-cmkpB?3~7kmx@y@%y_mlXv9JG zs1N2h0{1&%v4Fnhu^*Oe#mEv}RY?vDSnibcgb`RKKWd6b3vLjSq9st9VT;yxf9Q;e z6e||G9v;7%6LKvj2Z4pa?-5A5d^Hq2ZnlTA3PkM;z#7jR0v9z=>BBX3&YVQ@Q1_Sw zv;)--#ra8;K+4ryH|K1Q`J)UC3Imh_6Ej%(pM**bhsR zAm2AF#rRi zCd%79+0p+!Ja$t;;^=Z~f)?(T`uXohLqMaZ=RMrae4$awArGH*!AEc|! zl1JTlG8zWnX2q)w<4<>roe~;y31(ITH;Ts%EnZ)x!(^a^1<+(kkn=#BaNX}b@+is7 zGZ?Lk1kh6?KkoB+tt2sK^G{spvuFuxeC+#OiSwi6_00Xs6Ij;dbw2>0_3;c|c8z4d z-+ZOPAAKH*RuM_gQyCqJ(X%4!FrUrHS_kO+sbZhuSX1iT_KD7i{m40qjIp@WbP|O2 z;tLy3f{2fmhA!BL&qa2h#x((QhVi%mi{E)n-ZcrW!UWf@K1bOd62L68^wr;)@w|1= zS4{8~o31)67(VoXimL=Vi9j}#>={aYtYyTE8AYssuq4-$sv}u;d!+YKgCq&vACV|a z2Y3K{;v;2dP|T~$ihQg|l43}$tA~t&??Q>Z9pVYW$-!H>#tZU^5chV5BM}e$A6-DB zgsYJBhLSnzUUTzJ*;j2JtAeM74&Z+z88gXhn_fZ6Rp8%7fhG9jPv(8&Ekp|nal za+EN$=Naj+&0p*!{w@`hLPo+4>sZCS+&~?9|8TRJ)T3D0p1r(I5l$V+vO{01|2$KY zKxawNF6coEuSxNo&3V4LqH{Ut#C3FQLr2&@Y4VFE;F)39U#WrI93!QKx+i8Rcx(=w7_mB*zODniofwI@8aFp9%VWr-Rlj-atmj} zQo>P#f~%}zcb0`6T!j=H2zD#a%-|1of24s4m*{I$aYG11TJZ*j(Bt%ZDWo;6bPd(f z>z1Zf6c9OMEI3avwS=R=LMHdwnJ7tCP=ZaAf`ciz*4*GVFU zF5uq1E=`0Co!!7S82*0k|G2Ed*C{yt_`}c53qsR7U}J6jr%+Vk@NTW*%Qk8GRgR9x zQ8wWj^?C?SunZfXDep&L4`?;{!Md)3b#u>vZk&=Fz5X!yd2P-q#e@`%-5;!;<0B|+ zDzR1TEv_|UwyxE)aH>j95lsUJ-A`-PV`7U79uUKl`@FI2h(oi_xJqNIDUlylD?Uj3 zi5S-Yde+w&j2f)2Luo?KCt7vSbQf->rPn5qgsPT-2dK)Yhf{HJx&BXTELTH>7!PV6>G_l)mSQqAc1~T# zgkw{#*P4?y)&Dou^`U#+482-@Doez zbZ5DACwPdDWoq9t6gO(|NDVfy)!k25xxSxGrMXR*npQMWHJi^hk6wFW<{jBfZ zA2#|7@`Gsa`>THD#Hb=u`h7~nEp}kj|Dvnv+b0HAGj_Z`_7$PYuyFk8ZbwI!#CzvQFmI+-K3uj_?*oorB&o8upprJ?7 zs$I~By_Qq8J^ldqJ7@Qt2lR7i)>R6+3c#2cNbXw)SX)UQhk^PkyfnYxONe;5s%R+1 zb_9VE_X1*p{7XH2gT^3&!YE*g(O7{cg(^FYV3oXTzJP2H5trnt@u2vmLP`RufoxrE ze;p(_8|e;V2U$@X14QJiE&vD^j1~k}2_O!KBJzPe`@xU#!6%<2NgP)R+K2+p4M5uQ ze<&bEuxU1)?46o2+PRO0M_Grdoj+JKuB8VEZWyRNdH zN1Zf<6z@wb@?^$$r-C7q^3Fqr zewbR-dz$>{*=#5wuUw&xi1-k`;{`D)AZ1u*g+Ro@ia?CQSi&wQK@{7aplvNae)|^x z($Bty4Rf#Xf|Hwd&+arjsUstAG~J^C`l|6~0g?NIh+-j3On#6I+QOyXN8vUS%{!k^ zyZd(|J2bBU{3PvsS-^tMn^@@;7NvV@ f(`8UrH!@cOj?01h`ag$cQ6(@nc;gm$ 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

|t)cS~J?bP4-^_vHP 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 Jy=NQx{{T`VG&2AI literal 0 HcmV?d00001 diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 5a3304912..29065122b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -17,7 +17,7 @@ namespace Flow.Launcher.Plugin.PluginsManager private readonly PluginsManifest pluginsManifest; private PluginInitContext Context { get; set; } - private readonly string icoPath = "Images\\plugin.png"; + private readonly string icoPath = "Images\\pluginsmanager.png"; internal PluginsManager(PluginInitContext context) { From 4365520feabd145f7736f22cab13f3ebe9da4a36 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 22:18:21 +1100 Subject: [PATCH 090/267] update settings window to user control --- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 4 +--- .../Views/PluginsManagerSettings.xaml | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 29065122b..f18d52d4c 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -1,5 +1,4 @@ using Flow.Launcher.Infrastructure; -using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; @@ -7,7 +6,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Net; using System.Windows; namespace Flow.Launcher.Plugin.PluginsManager @@ -65,7 +63,7 @@ namespace Flow.Launcher.Plugin.PluginsManager internal void PluginsManifestSiteOpen() { - //Open https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest + //Open from context menu https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest } internal List Search(List results, string searchName) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml index 7f6d7ba82..89d27f6ff 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml @@ -1,12 +1,12 @@ - + d:DesignHeight="450" d:DesignWidth="800"> - + From b17dbcc31764f9ef8eade2d3e588e3d411c3b1cd Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 22:58:18 +1100 Subject: [PATCH 091/267] refactor --- .../PluginsManager.cs | 145 +++++++----------- .../Utilities.cs | 18 +++ 2 files changed, 73 insertions(+), 90 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index f18d52d4c..776c01144 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -24,13 +24,24 @@ namespace Flow.Launcher.Plugin.PluginsManager } internal void InstallOrUpdate(UserPlugin plugin) { - if (PluginExists()) + if (PluginExists(plugin.ID)) { - //prompt user if want to install + var updateMessage = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" + + $"Name: {plugin.Name}{Environment.NewLine}" + + $"{Environment.NewLine}New Version: {plugin.Version}" + + $"{Environment.NewLine}Author: {plugin.Author}"; - return; + throw new NotImplementedException(); } + var message = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" + + $"Name: {plugin.Name}{Environment.NewLine}" + + $"Version: {plugin.Version}{Environment.NewLine}" + + $"Author: {plugin.Author}"; + + if(MessageBox.Show(message, "Install plugin", MessageBoxButton.YesNo) == MessageBoxResult.No) + return; + var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip"); try @@ -53,17 +64,18 @@ namespace Flow.Launcher.Plugin.PluginsManager internal void Update() { - + throw new NotImplementedException(); } - internal bool PluginExists() + internal bool PluginExists(string id) { - return false; + 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) @@ -105,89 +117,43 @@ namespace Flow.Launcher.Plugin.PluginsManager private void Install(UserPlugin plugin, string downloadedFilePath) { - if (File.Exists(downloadedFilePath)) + if (!File.Exists(downloadedFilePath)) + return; + + var tempFolderPath = Path.Combine(Path.GetTempPath(), "flowlauncher"); + var tempFolderPluginPath = Path.Combine(tempFolderPath, "plugin"); + + if (Directory.Exists(tempFolderPath)) + Directory.Delete(tempFolderPath, true); + + Directory.CreateDirectory(tempFolderPath); + + var zipFilePath = Path.Combine(tempFolderPath, Path.GetFileName(downloadedFilePath)); + + File.Move(downloadedFilePath, zipFilePath); + + Utilities.UnZip(zipFilePath, tempFolderPluginPath, true); + + var pluginFolderPath = Utilities.GetContainingFolderPathAfterUnzip(tempFolderPluginPath); + + var metadataJsonFilePath = string.Empty; + if (File.Exists(Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName))) + metadataJsonFilePath = Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName); + + if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath)) { - var tempFolderPath = Path.Combine(Path.GetTempPath(), "flowlauncher"); - var tempPluginFolderPath = Path.Combine(tempFolderPath, "plugin"); - - if (Directory.Exists(tempFolderPath)) - { - Directory.Delete(tempFolderPath, true); - } - - Directory.CreateDirectory(tempFolderPath); - - var zipFilePath = Path.Combine(tempFolderPath, Path.GetFileName(downloadedFilePath)); - - File.Move(downloadedFilePath, zipFilePath); - - Utilities.UnZip(zipFilePath, tempPluginFolderPath, true); - - var unzippedParentFolderPath = tempPluginFolderPath; - - var metadataJsonFilePath = string.Empty; - - var pluginFolderPath = string.Empty; - - var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length; - var unzippedFilesCount = Directory.GetFiles(unzippedParentFolderPath).Length; - - // addjust path depending on how the plugin is zipped up - // the recommended should be to zip up the folder not the contents - if (unzippedFolderCount == 1 && unzippedFilesCount == 0) - // folder is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/pluginFolderName/ - pluginFolderPath = Directory.GetDirectories(unzippedParentFolderPath)[0]; - - if (unzippedFilesCount > 1) - // content is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/ - pluginFolderPath = unzippedParentFolderPath; - - if (File.Exists(Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName))) - metadataJsonFilePath = Path.Combine(pluginFolderPath, Constant.PluginMetadataFileName); - - if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath)) - { - MessageBox.Show("Install failed: unable to find the plugin.json metadata file"); - return; - } - - string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}"); - - string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"Version: {plugin.Version}{Environment.NewLine}" + - $"Author: {plugin.Author}"; - - var existingPlugin = Context.API.GetAllPlugins().Where(x => x.Metadata.ID == plugin.ID).FirstOrDefault(); - - if (existingPlugin != null) - { - content = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"Old Version: {existingPlugin.Metadata.Version}" + - $"{Environment.NewLine}New Version: {plugin.Version}" + - $"{Environment.NewLine}Author: {plugin.Author}"; - } - - var result = MessageBox.Show(content, "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.Yes) - { - if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory)) - { - //when plugin is in use, we can't delete them. That's why we need to make plugin folder a random name - File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close(); - } - - Directory.Move(pluginFolderPath, newPluginPath); - - if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" + - "Restart Flow Launcher to take effect?", - "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) - { - Context.API.RestartApp(); - } - } + MessageBox.Show("Install failed: unable to find the plugin.json metadata file from the new plugin"); + return; } + + string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}"); + + Directory.Move(pluginFolderPath, newPluginPath); + + if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" + + "Restart Flow Launcher to take effect?", + "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) + Context.API.RestartApp(); } internal List RequestUninstall(string search) @@ -221,14 +187,13 @@ namespace Flow.Launcher.Plugin.PluginsManager if (MessageBox.Show(message, "Flow Launcher", MessageBoxButton.YesNo) == MessageBoxResult.Yes) { - File.Create(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")).Close(); + using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")); + var result = MessageBox.Show($"You have uninstalled plugin {plugin.Name} successfully.{Environment.NewLine}" + "Restart Flow Launcher to take effect?", "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) - { Context.API.RestartApp(); - } } } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs index 1ff42fdbd..4c82a855b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs @@ -40,6 +40,24 @@ namespace Flow.Launcher.Plugin.PluginsManager } } + internal static string GetContainingFolderPathAfterUnzip(string unzippedParentFolderPath) + { + var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length; + var unzippedFilesCount = Directory.GetFiles(unzippedParentFolderPath).Length; + + // addjust path depending on how the plugin is zipped up + // the recommended should be to zip up the folder not the contents + if (unzippedFolderCount == 1 && unzippedFilesCount == 0) + // folder is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/pluginFolderName/ + return Directory.GetDirectories(unzippedParentFolderPath)[0]; + + if (unzippedFilesCount > 1) + // content is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/ + return unzippedParentFolderPath; + + return string.Empty; + } + internal static void Download(string downloadUrl, string toFilePath) { using var wc = new WebClient { Proxy = Http.WebProxy() }; From 7a7815b9c1ad14338e8fb5dc029019b79657969a Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 10 Dec 2020 23:07:17 +1100 Subject: [PATCH 092/267] remove plugin PluginManagement --- Flow.Launcher.sln | 16 -- Flow.Launcher/MainWindow.xaml | 1 - Flow.Launcher/MainWindow.xaml.cs | 18 -- ...ow.Launcher.Plugin.PluginManagement.csproj | 102 ------- .../Flow.Launcher.PluginResult.cs | 11 - .../Images/plugin.png | Bin 269 -> 0 bytes .../Languages/de.xaml | 8 - .../Languages/en.xaml | 8 - .../Languages/pl.xaml | 8 - .../Languages/sk.xaml | 8 - .../Languages/tr.xaml | 8 - .../Languages/zh-cn.xaml | 8 - .../Languages/zh-tw.xaml | 8 - .../Main.cs | 258 ------------------ .../plugin.json | 12 - 15 files changed, 474 deletions(-) delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.PluginResult.cs delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Images/plugin.png delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/de.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/en.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/pl.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/sk.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/tr.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-cn.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-tw.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs delete mode 100644 Plugins/Flow.Launcher.Plugin.PluginManagement/plugin.json diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln index c873bc147..4d8997177 100644 --- a/Flow.Launcher.sln +++ b/Flow.Launcher.sln @@ -24,15 +24,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc {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} - {049490F0-ECD2-4148-9B39-2135EC346EBE} = {049490F0-ECD2-4148-9B39-2135EC346EBE} {403B57F2-1856-4FC7-8A24-36AB346B763E} = {403B57F2-1856-4FC7-8A24-36AB346B763E} {588088F4-3262-4F9F-9663-A05DE12534C3} = {588088F4-3262-4F9F-9663-A05DE12534C3} EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Infrastructure", "Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj", "{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.PluginManagement", "Plugins\Flow.Launcher.Plugin.PluginManagement\Flow.Launcher.Plugin.PluginManagement.csproj", "{049490F0-ECD2-4148-9B39-2135EC346EBE}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Core", "Flow.Launcher.Core\Flow.Launcher.Core.csproj", "{B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Program", "Plugins\Flow.Launcher.Plugin.Program\Flow.Launcher.Plugin.Program.csproj", "{FDB3555B-58EF-4AE6-B5F1-904719637AB4}" @@ -132,18 +129,6 @@ Global {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.Build.0 = Release|Any CPU {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.ActiveCfg = Release|Any CPU {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.Build.0 = Release|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x64.ActiveCfg = Debug|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x64.Build.0 = Debug|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x86.ActiveCfg = Debug|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x86.Build.0 = Debug|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|Any CPU.Build.0 = Release|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x64.ActiveCfg = Release|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x64.Build.0 = Release|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x86.ActiveCfg = Release|Any CPU - {049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x86.Build.0 = Release|Any CPU {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}.Debug|Any CPU.Build.0 = Debug|Any CPU {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -318,7 +303,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {049490F0-ECD2-4148-9B39-2135EC346EBE} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {403B57F2-1856-4FC7-8A24-36AB346B763E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 0cc671ef6..07bb96339 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -22,7 +22,6 @@ Loaded="OnLoaded" Initialized="OnInitialized" Closing="OnClosing" - Drop="OnDrop" LocationChanged="OnLocationChanged" Deactivated="OnDeactivated" PreviewKeyDown="OnKeyDown" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 993eb76c5..3812b4e1f 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -199,24 +199,6 @@ namespace Flow.Launcher } } - private void OnDrop(object sender, DragEventArgs e) - { - if (e.Data.GetDataPresent(DataFormats.FileDrop)) - { - // Note that you can have more than one file. - string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - if (files[0].ToLower().EndsWith(".flowlauncher")) - { - PluginManager.InstallPlugin(files[0]); - } - else - { - MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidFlowLauncherPluginFileFormat")); - } - } - e.Handled = false; - } - private void OnPreviewDragOver(object sender, DragEventArgs e) { e.Handled = true; diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj b/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj deleted file mode 100644 index 08e89d861..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.Plugin.PluginManagement.csproj +++ /dev/null @@ -1,102 +0,0 @@ - - - - Library - netcoreapp3.1 - {049490F0-ECD2-4148-9B39-2135EC346EBE} - Properties - Flow.Launcher.Plugin.PluginManagement - Flow.Launcher.Plugin.PluginManagement - true - true - false - false - - - - true - full - false - ..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.PluginManagement\ - DEBUG;TRACE - prompt - 4 - false - - - - pdbonly - true - ..\..\Output\Release\Plugins\Flow.Launcher.Plugin.PluginManagement\ - 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.PluginManagement/Flow.Launcher.PluginResult.cs b/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.PluginResult.cs deleted file mode 100644 index 7f5d75d4e..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Flow.Launcher.PluginResult.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Flow.Launcher.Plugin.PluginManagement -{ - public class FlowLauncherPluginResult - { - public string plugin_file; - public string description; - public int liked_count; - public string name; - public string version; - } -} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Images/plugin.png b/Plugins/Flow.Launcher.Plugin.PluginManagement/Images/plugin.png deleted file mode 100644 index 6ff9b8b1576145ac919a9e545d53b3b4d54e74e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmSQK*5Dp-y;YjHK@;M7UB8!3Q zuY)k7lg8`{prB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt)}iE{-7? zjc;#kHvTfzwzgn&H8z5?V p7Dxgm(-_V|G#}kB6xf20n;ZREG~9lkehSc444$rjF6*2UngA2gT8sby diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/de.xaml deleted file mode 100644 index 38b2f1b4b..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/de.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Flow Launcher Plugin Verwaltung - Installiere/Entferne/Aktualisiere Flow Launcher Plugins - - \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/en.xaml deleted file mode 100644 index b49f33c76..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/en.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Plugin Management - Install, remove or update Flow Launcher plugins - - \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/pl.xaml deleted file mode 100644 index 362db73e5..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/pl.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Zarządzanie wtyczkami Flow Launcher - Pozwala na instalacje, usuwanie i aktualizacje wtyczek - - \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/sk.xaml deleted file mode 100644 index b51eceb6a..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/sk.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Správca pluginov - Inštalácia, odinštalácia alebo aktualizácia pluginov Flow Launchera - - \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/tr.xaml deleted file mode 100644 index fee82a78b..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/tr.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Flow Launcher Eklenti Yöneticisi - Flow Launcher eklentilerini kurun, kaldırın ya da güncelleyin - - \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-cn.xaml deleted file mode 100644 index 009fd976c..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-cn.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Flow Launcher插件管理 - 安装/卸载/更新Flow Launcher插件 - - \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-tw.xaml deleted file mode 100644 index c93d740f1..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Languages/zh-tw.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - Flow Launcher 外掛管理 - 安裝/解除安裝/更新 Flow Launcher 外掛 - - diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs deleted file mode 100644 index e1b631517..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/Main.cs +++ /dev/null @@ -1,258 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using Newtonsoft.Json; -using Flow.Launcher.Infrastructure; -using Flow.Launcher.Infrastructure.Http; -using Flow.Launcher.Infrastructure.Logger; - -namespace Flow.Launcher.Plugin.PluginManagement -{ - public class Main : IPlugin, IPluginI18n - { - private static string APIBASE = "http://api.wox.one"; - private static string pluginSearchUrl = APIBASE + "/plugin/search/"; - private const string ListCommand = "list"; - private const string InstallCommand = "install"; - private const string UninstallCommand = "uninstall"; - private PluginInitContext context; - - public List Query(Query query) - { - List results = new List(); - - if (string.IsNullOrEmpty(query.Search)) - { - results.Add(ResultForListCommandAutoComplete(query)); - results.Add(ResultForInstallCommandAutoComplete(query)); - results.Add(ResultForUninstallCommandAutoComplete(query)); - return results; - } - - string command = query.FirstSearch.ToLower(); - if (string.IsNullOrEmpty(command)) return results; - - if (command == ListCommand) - { - return ResultForListInstalledPlugins(); - } - if (command == UninstallCommand) - { - return ResultForUnInstallPlugin(query); - } - if (command == InstallCommand) - { - return ResultForInstallPlugin(query); - } - - if (InstallCommand.Contains(command)) - { - results.Add(ResultForInstallCommandAutoComplete(query)); - } - if (UninstallCommand.Contains(command)) - { - results.Add(ResultForUninstallCommandAutoComplete(query)); - } - if (ListCommand.Contains(command)) - { - results.Add(ResultForListCommandAutoComplete(query)); - } - - return results; - } - - private Result ResultForListCommandAutoComplete(Query query) - { - string title = ListCommand; - string subtitle = "list installed plugins"; - return ResultForCommand(query, ListCommand, title, subtitle); - } - - private Result ResultForInstallCommandAutoComplete(Query query) - { - string title = $"{InstallCommand} "; - string subtitle = "list installed plugins"; - return ResultForCommand(query, InstallCommand, title, subtitle); - } - - private Result ResultForUninstallCommandAutoComplete(Query query) - { - string title = $"{UninstallCommand} "; - string subtitle = "list installed plugins"; - return ResultForCommand(query, UninstallCommand, title, subtitle); - } - - private Result ResultForCommand(Query query, string command, string title, string subtitle) - { - const string seperater = Plugin.Query.TermSeperater; - var result = new Result - { - Title = title, - IcoPath = "Images\\plugin.png", - SubTitle = subtitle, - Action = e => - { - context.API.ChangeQuery($"{query.ActionKeyword}{seperater}{command}{seperater}"); - return false; - } - }; - return result; - } - - private List ResultForInstallPlugin(Query query) - { - List results = new List(); - string pluginName = query.SecondSearch; - if (string.IsNullOrEmpty(pluginName)) return results; - string json; - try - { - json = Http.Get(pluginSearchUrl + pluginName).Result; - } - catch (WebException e) - { - //todo happlebao add option in log to decide give user prompt or not - context.API.ShowMsg("PluginManagement.ResultForInstallPlugin: Can't connect to Wox plugin website, check your conenction"); - Log.Exception("|PluginManagement.ResultForInstallPlugin|Can't connect to Wox plugin website, check your conenction", e); - return new List(); - } - List searchedPlugins; - try - { - searchedPlugins = JsonConvert.DeserializeObject>(json); - } - catch (JsonSerializationException e) - { - context.API.ShowMsg("PluginManagement.ResultForInstallPlugin: Coundn't parse api search results, Please update your Flow Launcher!"); - Log.Exception("|PluginManagement.ResultForInstallPlugin|Coundn't parse api search results, Please update your Flow Launcher!", e); - return results; - } - - foreach (FlowLauncherPluginResult r in searchedPlugins) - { - FlowLauncherPluginResult r1 = r; - results.Add(new Result - { - Title = r.name, - SubTitle = r.description, - IcoPath = "Images\\plugin.png", - TitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.name).MatchData, - SubTitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.description).MatchData, - Action = c => - { - MessageBoxResult result = MessageBox.Show("Are you sure you wish to install the \'" + r.name + "\' plugin", - "Install plugin", MessageBoxButton.YesNo); - - if (result == MessageBoxResult.Yes) - { - string folder = Path.Combine(Path.GetTempPath(), "FlowLauncherPluginDownload"); - if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); - string filePath = Path.Combine(folder, Guid.NewGuid().ToString() + ".flowlauncher"); - - string pluginUrl = APIBASE + "/media/" + r1.plugin_file; - - try - { - Http.Download(pluginUrl, filePath); - } - catch (WebException e) - { - context.API.ShowMsg($"PluginManagement.ResultForInstallPlugin: download failed for <{r.name}>"); - Log.Exception($"|PluginManagement.ResultForInstallPlugin|download failed for <{r.name}>", e); - return false; - } - context.API.InstallPlugin(filePath); - } - return false; - } - }); - } - return results; - } - - private List ResultForUnInstallPlugin(Query query) - { - List results = new List(); - List allInstalledPlugins = context.API.GetAllPlugins().Select(o => o.Metadata).ToList(); - if (!string.IsNullOrEmpty(query.SecondSearch)) - { - allInstalledPlugins = - allInstalledPlugins.Where(o => o.Name.ToLower().Contains(query.SecondSearch.ToLower())).ToList(); - } - - foreach (PluginMetadata plugin in allInstalledPlugins) - { - results.Add(new Result - { - Title = plugin.Name, - SubTitle = plugin.Description, - IcoPath = plugin.IcoPath, - TitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, plugin.Name).MatchData, - SubTitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, plugin.Description).MatchData, - Action = e => - { - UnInstallPlugin(plugin); - return false; - } - }); - } - return results; - } - - private void UnInstallPlugin(PluginMetadata plugin) - { - string content = $"Do you want to uninstall following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"Version: {plugin.Version}{Environment.NewLine}" + - $"Author: {plugin.Author}"; - if (MessageBox.Show(content, "Flow Launcher", MessageBoxButton.YesNo) == MessageBoxResult.Yes) - { - File.Create(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")).Close(); - var result = MessageBox.Show($"You have uninstalled plugin {plugin.Name} successfully.{Environment.NewLine}" + - "Restart Flow Launcher to take effect?", - "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.Yes) - { - context.API.RestartApp(); - } - } - } - - private List ResultForListInstalledPlugins() - { - List results = new List(); - foreach (PluginMetadata plugin in context.API.GetAllPlugins().Select(o => o.Metadata)) - { - string actionKeywordString = string.Join(" or ", plugin.ActionKeywords.ToArray()); - results.Add(new Result - { - Title = $"{plugin.Name} - Action Keywords: {actionKeywordString}", - SubTitle = plugin.Description, - IcoPath = plugin.IcoPath - }); - } - return results; - } - - public void Init(PluginInitContext context) - { - this.context = context; - } - - public string GetTranslatedPluginTitle() - { - return context.API.GetTranslation("flowlauncher_plugin_plugin_management_plugin_name"); - } - - public string GetTranslatedPluginDescription() - { - return context.API.GetTranslation("flowlauncher_plugin_plugin_management_plugin_description"); - } - } -} diff --git a/Plugins/Flow.Launcher.Plugin.PluginManagement/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginManagement/plugin.json deleted file mode 100644 index 7b8262f79..000000000 --- a/Plugins/Flow.Launcher.Plugin.PluginManagement/plugin.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "ID": "D2D2C23B084D422DB66FE0C79D6C2A6A", - "ActionKeyword": "wpm", - "Name": "Plugin Management", - "Description": "Install/Remove/Update Flow Launcher plugins", - "Author": "qianlifeng", - "Version": "1.1.1", - "Language": "csharp", - "Website": "https://github.com/Flow-Launcher/Flow.Launcher", - "ExecuteFileName": "Flow.Launcher.Plugin.PluginManagement.dll", - "IcoPath": "Images\\plugin.png" -} From c4b27421985f183329676f655341d1fd20f408c4 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 11 Dec 2020 07:45:01 +1100 Subject: [PATCH 093/267] add translation method for messages --- .../Languages/en.xaml | 8 ++- .../PluginsManager.cs | 50 +++++++++---------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index 01a9052ed..fc13f0c2f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -6,7 +6,13 @@ Downloading plugin Please wait... Successfully downloaded - Do you want to uninstall the following plugin? + Do you want to uninstall the following plugin?{0}{1}{2} by {3} + Do you want to install the following plugin?{0}{1}{2} by {3} + Plugin Install + Plugin Uninstall + Install failed: unable to find the plugin.json metadata file from the new plugin + You have installed plugin {0} successfully.{1}Would you like to restart Flow Launcher to take effect? + You have uninstalled plugin {0} successfully.{1}Would you like to restart Flow Launcher to take effect? diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 776c01144..6bfd246cd 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -24,28 +24,26 @@ namespace Flow.Launcher.Plugin.PluginsManager } internal void InstallOrUpdate(UserPlugin plugin) { - if (PluginExists(plugin.ID)) + if (PluginExists(plugin.ID)) { - var updateMessage = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"{Environment.NewLine}New Version: {plugin.Version}" + - $"{Environment.NewLine}Author: {plugin.Author}"; - - throw new NotImplementedException(); + Context.API.ShowMsg("Plugin already installed"); + return; } - var message = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" + - $"Name: {plugin.Name}{Environment.NewLine}" + - $"Version: {plugin.Version}{Environment.NewLine}" + - $"Author: {plugin.Author}"; + var message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_prompt"), + Environment.NewLine, Environment.NewLine, + plugin.Name, plugin.Author); - if(MessageBox.Show(message, "Install plugin", 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"); try { + Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), + Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); + Utilities.Download(plugin.UrlDownload, filePath); Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), @@ -103,8 +101,6 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = icoPath, Action = e => { - Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), - Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); Application.Current.MainWindow.Hide(); InstallOrUpdate(x); @@ -142,7 +138,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath)) { - MessageBox.Show("Install failed: unable to find the plugin.json metadata file from the new plugin"); + MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_install_errormetadatafile")); return; } @@ -150,9 +146,10 @@ namespace Flow.Launcher.Plugin.PluginsManager Directory.Move(pluginFolderPath, newPluginPath); - if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" + - "Restart Flow Launcher to take effect?", - "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) + if (MessageBox.Show(string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_successandrestart"), + plugin.Name, Environment.NewLine), + Context.API.GetTranslation("plugin_pluginsmanager_install_title"), + MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) Context.API.RestartApp(); } @@ -181,18 +178,19 @@ namespace Flow.Launcher.Plugin.PluginsManager private void Uninstall(PluginMetadata plugin) { - string message = Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt")+ - $"{Environment.NewLine}{Environment.NewLine}" + - $"{plugin.Name} by {plugin.Author}"; + string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"), + Environment.NewLine, Environment.NewLine, + plugin.Name, plugin.Author); - if (MessageBox.Show(message, "Flow Launcher", MessageBoxButton.YesNo) == MessageBoxResult.Yes) + 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")); - var result = MessageBox.Show($"You have uninstalled plugin {plugin.Name} successfully.{Environment.NewLine}" + - "Restart Flow Launcher to take effect?", - "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.Yes) + if (MessageBox.Show(string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_successandrestart"), + plugin.Name, Environment.NewLine), + Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"), + MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) Context.API.RestartApp(); } } From aaa938191ad3e69aff5ae9de1daabfc69b5a9b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 11 Dec 2020 22:08:46 +0800 Subject: [PATCH 094/267] Manually add sapce to only the cinese character and the surrounding. --- .../PinyinAlphabet.cs | 42 +++++++++++++++++-- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 9396226c7..d35250398 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -9,6 +9,7 @@ using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using ToolGood.Words.Pinyin; using System.Threading.Tasks; +using Microsoft.AspNetCore.Localization; namespace Flow.Launcher.Infrastructure { @@ -36,10 +37,43 @@ namespace Flow.Launcher.Infrastructure { if (WordsHelper.HasChinese(content)) { - var result = WordsHelper.GetPinyin(content, " "); - result = GetFirstPinyinChar(result) + result; - _pinyinCache[content] = result; - return result; + var resultList = WordsHelper.GetPinyinList(content); + + List chineseIndexs = new List(); + + for (int i = 0; i < content.Length; i++) + { + if (resultList[i].Length != 1 || !(resultList[i][0] == content[i])) + chineseIndexs.Add(i); + } + StringBuilder resultBuilder = new StringBuilder(); + resultBuilder.Append(string.Concat(resultList.Where((r, i) => chineseIndexs.Contains(i)).Select(s => s.First()))); + resultBuilder.Append(' '); + + int currentChineseIndex = 0; + int lastChineseIndex = -1; + for (int i = 0; i < resultList.Length; i++) + { + if (currentChineseIndex < chineseIndexs.Count && chineseIndexs[currentChineseIndex] == i) + { + resultBuilder.Append(' '); + + resultBuilder.Append(resultList[i]); + currentChineseIndex++; + lastChineseIndex = i; + } + else + { + if (i == lastChineseIndex + 1) + { + resultBuilder.Append(' '); + } + resultBuilder.Append(resultList[i]); + } + } + + + return _pinyinCache[content] = resultBuilder.ToString(); } else { From d64b4b5b0c27918281975f2260f8bc2d1d50c0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Fri, 11 Dec 2020 22:20:09 +0800 Subject: [PATCH 095/267] Change the way getting acronym --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index d35250398..59bd897be 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -47,7 +47,11 @@ namespace Flow.Launcher.Infrastructure chineseIndexs.Add(i); } StringBuilder resultBuilder = new StringBuilder(); - resultBuilder.Append(string.Concat(resultList.Where((r, i) => chineseIndexs.Contains(i)).Select(s => s.First()))); + + foreach (var chineseIndex in chineseIndexs) + { + resultBuilder.Append(resultList[chineseIndex].First()); + } resultBuilder.Append(' '); int currentChineseIndex = 0; @@ -90,10 +94,5 @@ namespace Flow.Launcher.Infrastructure return content; } } - - private string GetFirstPinyinChar(string content) - { - return string.Concat(content.Split(' ').Select(x => x.First())); - } } } \ No newline at end of file From 64d67c1aa58c112d457d5997b4c8c0ce17855e4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 12 Dec 2020 14:55:41 +0800 Subject: [PATCH 096/267] Update PinyinAlphabet.cs optimize Chinese character check logic Co-Authored-By: ToolGood --- .../PinyinAlphabet.cs | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 59bd897be..d5271437c 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -39,37 +39,32 @@ namespace Flow.Launcher.Infrastructure { var resultList = WordsHelper.GetPinyinList(content); - List chineseIndexs = new List(); - - for (int i = 0; i < content.Length; i++) - { - if (resultList[i].Length != 1 || !(resultList[i][0] == content[i])) - chineseIndexs.Add(i); - } StringBuilder resultBuilder = new StringBuilder(); + - foreach (var chineseIndex in chineseIndexs) - { - resultBuilder.Append(resultList[chineseIndex].First()); - } - resultBuilder.Append(' '); - - int currentChineseIndex = 0; - int lastChineseIndex = -1; for (int i = 0; i < resultList.Length; i++) { - if (currentChineseIndex < chineseIndexs.Count && chineseIndexs[currentChineseIndex] == i) + if (content[i] >= 0x3400 && content[i] <= 0x9FD5) + resultBuilder.Append(resultList[i].First()); + } + + resultBuilder.Append(' '); + + bool pre = false; + + for (int i = 0; i < resultList.Length; i++) + { + if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { resultBuilder.Append(' '); - resultBuilder.Append(resultList[i]); - currentChineseIndex++; - lastChineseIndex = i; + pre = true; } else { - if (i == lastChineseIndex + 1) + if (pre) { + pre = false; resultBuilder.Append(' '); } resultBuilder.Append(resultList[i]); From c8b251d63ac0bdac58ba2fc1221566d88e4488e9 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 08:41:18 +1100 Subject: [PATCH 097/267] use Http.Get from Infrastructure --- Flow.Launcher.Infrastructure/Http/Http.cs | 18 ++++------ .../Models/PluginsManifest.cs | 33 +++++++++++-------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b7d274205..1d5f240e1 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -66,18 +66,12 @@ namespace Flow.Launcher.Infrastructure.Http 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) - { - return content; - } - else - { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); - } - } + 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; } } } \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 134ad7bd0..290221710 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -3,8 +3,7 @@ using Flow.Launcher.Infrastructure.Logger; using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.Net; -using System.Text; +using System.Threading.Tasks; namespace Flow.Launcher.Plugin.PluginsManager.Models { @@ -12,24 +11,30 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models { internal List UserPlugins { get; private set; } internal PluginsManifest() + { + DownloadManifest(); + } + + private void DownloadManifest() { var json = string.Empty; - - using (var wc = new WebClient { Proxy = Http.WebProxy() }) + try { - try - { - json = wc.DownloadString("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"); - } - catch (Exception e) - { - Log.Exception("|PluginManagement.GetManifest|Encountered error trying to download plugins manifest", e); + var t = Task.Run( + async () => + json = await Http.Get("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json")); - UserPlugins = new List(); - } + t.Wait(); + + UserPlugins = JsonConvert.DeserializeObject>(json); + } + catch (Exception e) + { + Log.Exception("|PluginManagement.GetManifest|Encountered error trying to download plugins manifest", e); + + UserPlugins = new List(); } - UserPlugins = !string.IsNullOrEmpty(json) ? JsonConvert.DeserializeObject>(json) : new List(); } } } From ee0fc1ac478e3977fb22a81814334dd3f0775b3a Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 08:42:42 +1100 Subject: [PATCH 098/267] fix typo --- Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs index 4c82a855b..87c368f7f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs @@ -45,7 +45,7 @@ namespace Flow.Launcher.Plugin.PluginsManager var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length; var unzippedFilesCount = Directory.GetFiles(unzippedParentFolderPath).Length; - // addjust path depending on how the plugin is zipped up + // adjust path depending on how the plugin is zipped up // the recommended should be to zip up the folder not the contents if (unzippedFolderCount == 1 && unzippedFilesCount == 0) // folder is zipped up, unzipped plugin directory structure: tempPath/unzippedParentPluginFolder/pluginFolderName/ From 49b657b84ea0fa8147060106ee4dd14780c294fd Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 08:48:55 +1100 Subject: [PATCH 099/267] use Infrastructure.Http.Get to download plugins --- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 3 ++- Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 6bfd246cd..527ce99f7 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -1,4 +1,5 @@ using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; @@ -44,7 +45,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); - Utilities.Download(plugin.UrlDownload, filePath); + Http.Download(plugin.UrlDownload, filePath); Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_download_success")); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs index 87c368f7f..2853ffc9e 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs @@ -57,12 +57,5 @@ namespace Flow.Launcher.Plugin.PluginsManager return string.Empty; } - - internal static void Download(string downloadUrl, string toFilePath) - { - using var wc = new WebClient { Proxy = Http.WebProxy() }; - - wc.DownloadFile(downloadUrl, toFilePath); - } } } From b8a3ad8c427072aa82a51cee64aef4fa8376e662 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 13:46:37 +1100 Subject: [PATCH 100/267] change foreach to select --- .../PluginsManager.cs | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 527ce99f7..7d729193b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -90,24 +90,24 @@ namespace Flow.Launcher.Plugin.PluginsManager internal List RequestInstallOrUpdate(string searchName) { - var results = new List(); - - pluginsManifest + var results = + pluginsManifest .UserPlugins - .ForEach(x => results.Add( - new Result + .Select(x => + new Result + { + Title = $"{x.Name} by {x.Author}", + SubTitle = x.Description, + IcoPath = icoPath, + Action = e => { - Title = $"{x.Name} by {x.Author}", - SubTitle = x.Description, - IcoPath = icoPath, - Action = e => - { - Application.Current.MainWindow.Hide(); - InstallOrUpdate(x); + Application.Current.MainWindow.Hide(); + InstallOrUpdate(x); - return true; - } - })); + return true; + } + }) + .ToList(); return Search(results, searchName); } @@ -156,23 +156,23 @@ namespace Flow.Launcher.Plugin.PluginsManager internal List RequestUninstall(string search) { - var results = new List(); + 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); - Context.API.GetAllPlugins() - .ForEach(x => results.Add( - 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; - } - })); + return true; + } + }) + .ToList(); return Search(results, search); } From 5d7102eadb92ea117a26ae50fb09b275e5b9f3f6 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 14:11:53 +1100 Subject: [PATCH 101/267] remove select --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 7d729193b..8f1b86eef 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -84,7 +84,6 @@ namespace Flow.Launcher.Plugin.PluginsManager return results .Where(x => StringMatcher.FuzzySearch(searchName, x.Title).IsSearchPrecisionScoreMet()) - .Select(x => x) .ToList(); } From 8a86bf749665574752d4c022c0273a9fd203ab21 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 19:14:50 +1100 Subject: [PATCH 102/267] add fuzzy search score for ordering --- .../PluginsManager.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 8f1b86eef..77672e05f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -83,7 +83,14 @@ namespace Flow.Launcher.Plugin.PluginsManager return results; return results - .Where(x => StringMatcher.FuzzySearch(searchName, x.Title).IsSearchPrecisionScoreMet()) + .Where(x => + { + var matchResult = StringMatcher.FuzzySearch(searchName, x.Title); + if (matchResult.IsSearchPrecisionScoreMet()) + x.Score = matchResult.Score; + + return matchResult.IsSearchPrecisionScoreMet(); + }) .ToList(); } From d69337c17aec0a0408d374223f90233ced74e719 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 21:05:32 +1100 Subject: [PATCH 103/267] add uninstall autocomplete & move uninstall hotkey to settings --- .../Main.cs | 11 ++-- .../PluginsManager.cs | 58 ++++++++++++++----- .../Settings.cs | 11 ++++ 3 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index f763826a8..58ec5005f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -37,14 +37,13 @@ namespace Flow.Launcher.Plugin.PluginsManager public List Query(Query query) { - var search = query.Search; + var search = query.Search.ToLower(); - var uninstallCmd = "uninstall"; + var pluginManager = new PluginsManager(Context, Settings); - var pluginManager = new PluginsManager(Context); - - if (search.ToLower().StartsWith($"{uninstallCmd} ") || search.ToLower() == uninstallCmd) - return pluginManager.RequestUninstall(search.Replace(uninstallCmd, string.Empty).Trim()); + if (!string.IsNullOrEmpty(search) + && ($"{Settings.UninstallHotkey} ".StartsWith(search) || search.StartsWith($"{Settings.UninstallHotkey} "))) + return pluginManager.RequestUninstall(search); return pluginManager.RequestInstallOrUpdate(search); } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 77672e05f..fc4abc800 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -14,32 +14,36 @@ namespace Flow.Launcher.Plugin.PluginsManager internal class PluginsManager { private readonly PluginsManifest pluginsManifest; + private PluginInitContext Context { get; set; } + private Settings Settings { get; set; } + private readonly string icoPath = "Images\\pluginsmanager.png"; - internal PluginsManager(PluginInitContext context) + internal PluginsManager(PluginInitContext context, Settings settings) { pluginsManifest = new PluginsManifest(); Context = context; + Settings = settings; } internal void InstallOrUpdate(UserPlugin plugin) { - if (PluginExists(plugin.ID)) + if (PluginExists(plugin.ID)) { Context.API.ShowMsg("Plugin already installed"); return; } - var message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_prompt"), - Environment.NewLine, Environment.NewLine, + var message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_prompt"), + Environment.NewLine, Environment.NewLine, plugin.Name, plugin.Author); - 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"); - + try { Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), @@ -89,14 +93,14 @@ namespace Flow.Launcher.Plugin.PluginsManager if (matchResult.IsSearchPrecisionScoreMet()) x.Score = matchResult.Score; - return matchResult.IsSearchPrecisionScoreMet(); + return matchResult.IsSearchPrecisionScoreMet(); }) .ToList(); } internal List RequestInstallOrUpdate(string searchName) { - var results = + var results = pluginsManifest .UserPlugins .Select(x => @@ -122,10 +126,10 @@ namespace Flow.Launcher.Plugin.PluginsManager { if (!File.Exists(downloadedFilePath)) return; - + var tempFolderPath = Path.Combine(Path.GetTempPath(), "flowlauncher"); var tempFolderPluginPath = Path.Combine(tempFolderPath, "plugin"); - + if (Directory.Exists(tempFolderPath)) Directory.Delete(tempFolderPath, true); @@ -150,18 +154,44 @@ namespace Flow.Launcher.Plugin.PluginsManager } string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}"); - + Directory.Move(pluginFolderPath, newPluginPath); - if (MessageBox.Show(string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_successandrestart"), + if (MessageBox.Show(string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_successandrestart"), plugin.Name, Environment.NewLine), - Context.API.GetTranslation("plugin_pluginsmanager_install_title"), + Context.API.GetTranslation("plugin_pluginsmanager_install_title"), MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) Context.API.RestartApp(); } internal List RequestUninstall(string search) { + if (!string.IsNullOrEmpty(search) + && Settings.UninstallHotkey.StartsWith(search) + && (Settings.UninstallHotkey != search || !search.StartsWith(Settings.UninstallHotkey))) + { + return + new List + { + new Result + { + Title = "Uninstall", + IcoPath = icoPath, + SubTitle = "Select a plugin to uninstall", + Action = e => + { + Context + .API + .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UninstallHotkey} "); + + return false; + } + } + }; + } + + var uninstallSearch = search.Replace(Settings.UninstallHotkey, string.Empty).TrimStart(); + var results= Context.API .GetAllPlugins() .Select(x => @@ -180,7 +210,7 @@ namespace Flow.Launcher.Plugin.PluginsManager }) .ToList(); - return Search(results, search); + return Search(results, uninstallSearch); } private void Uninstall(PluginMetadata plugin) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs new file mode 100644 index 000000000..0c647e6ae --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Flow.Launcher.Plugin.PluginsManager +{ + internal class Settings + { + internal string UninstallHotkey { get; set; } = "uninstall"; + } +} From 4c773dbaa1842f15e4890139216637a83dacdcb2 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 14 Dec 2020 21:21:48 +1100 Subject: [PATCH 104/267] clean up, no code changes --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index d5271437c..80fd12820 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,15 +1,10 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.Linq; using System.Text; using JetBrains.Annotations; -using Flow.Launcher.Infrastructure.Logger; -using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using ToolGood.Words.Pinyin; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Localization; namespace Flow.Launcher.Infrastructure { @@ -28,7 +23,6 @@ namespace Flow.Launcher.Infrastructure _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public string Translate(string content) { if (_settings.ShouldUsePinyin) @@ -40,7 +34,6 @@ namespace Flow.Launcher.Infrastructure var resultList = WordsHelper.GetPinyinList(content); StringBuilder resultBuilder = new StringBuilder(); - for (int i = 0; i < resultList.Length; i++) { @@ -71,7 +64,6 @@ namespace Flow.Launcher.Infrastructure } } - return _pinyinCache[content] = resultBuilder.ToString(); } else From 10dea22588894f6e57e1a81d5b8430f2dbc04b5b Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 15 Dec 2020 07:17:19 +1100 Subject: [PATCH 105/267] add link to website in readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94d59bb93..206f3f7d9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@

- + + +

![Maintenance](https://img.shields.io/maintenance/yes/2020) From 24372eb76d5ddebdfa255adad791514c7d041bca Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 15 Dec 2020 20:10:59 +1100 Subject: [PATCH 106/267] installation and uninstallation restart after done --- .../Languages/en.xaml | 6 ++--- .../PluginsManager.cs | 24 +++++++------------ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index fc13f0c2f..7f8557c28 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -6,13 +6,11 @@ Downloading plugin Please wait... Successfully downloaded - Do you want to uninstall the following plugin?{0}{1}{2} by {3} - Do you want to install the following plugin?{0}{1}{2} by {3} + {0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart. + {0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart. Plugin Install Plugin Uninstall Install failed: unable to find the plugin.json metadata file from the new plugin - You have installed plugin {0} successfully.{1}Would you like to restart Flow Launcher to take effect? - You have uninstalled plugin {0} successfully.{1}Would you like to restart Flow Launcher to take effect? diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index fc4abc800..c141916aa 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -36,8 +36,8 @@ namespace Flow.Launcher.Plugin.PluginsManager } var message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_prompt"), - Environment.NewLine, Environment.NewLine, - plugin.Name, plugin.Author); + plugin.Name, plugin.Author, + Environment.NewLine, Environment.NewLine); if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_install_title"), MessageBoxButton.YesNo) == MessageBoxResult.No) return; @@ -156,12 +156,8 @@ namespace Flow.Launcher.Plugin.PluginsManager string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}"); Directory.Move(pluginFolderPath, newPluginPath); - - if (MessageBox.Show(string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_successandrestart"), - plugin.Name, Environment.NewLine), - Context.API.GetTranslation("plugin_pluginsmanager_install_title"), - MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) - Context.API.RestartApp(); + + Context.API.RestartApp(); } internal List RequestUninstall(string search) @@ -216,19 +212,15 @@ namespace Flow.Launcher.Plugin.PluginsManager private void Uninstall(PluginMetadata plugin) { string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"), - Environment.NewLine, Environment.NewLine, - plugin.Name, plugin.Author); + 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")); - - if (MessageBox.Show(string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_successandrestart"), - plugin.Name, Environment.NewLine), - Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"), - MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) - Context.API.RestartApp(); + + Context.API.RestartApp(); } } } From 1fabbe9ead0ab6abc5dba845094b0d0ba5ddba2d Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 15 Dec 2020 20:13:02 +1100 Subject: [PATCH 107/267] PluginsManager version bump --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 327011ac3..0353fffcc 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.0.0", + "Version": "1.1.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From 006eac23d4ddad8d6a7ac7ba21d0c9bd3f06862f Mon Sep 17 00:00:00 2001 From: Zero Date: Tue, 15 Dec 2020 20:36:03 +0800 Subject: [PATCH 108/267] :page_facing_up: wox -> flow, update owner --- LICENSE | 46 +--------------------------------------------- README.md | 7 ------- attribution.md | 6 ++++++ 3 files changed, 7 insertions(+), 52 deletions(-) create mode 100644 attribution.md diff --git a/LICENSE b/LICENSE index b4ba8d542..8be14c31d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,50 +1,6 @@ -FlowLauncher are licensed under the terms of the MIT license, reproduced below. - - -A. HISTORY OF THE SOFTWARE -========================== - -- Copyright (c) 2015-2019 Wox -- Copyright (c) 2019-2020+ Flow-Launcher - -Flow's roots came from a rebrand of the JJW24/Wox fork and WoX. -A big thank you and all credits to Bao, the author of WoX, -and its contrbutors for all the amazing work. -The JJW24/Wox fork started adding new changes on top of -main WoX repo's code base from release v1.3.524. -Flow is a continuation of the work from JJW24/Wox - - -B. FlowLauncher LICENSE -========================== - -The MIT License (MIT) - -Copyright (c) 2019-2020+ Flow-Launcher - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -C. Wox LICENSE -========================== - The MIT License (MIT) +Copyright (c) 2019 Flow-Launcher Copyright (c) 2015 Wox Permission is hereby granted, free of charge, to any person obtaining a copy of diff --git a/README.md b/README.md index 206f3f7d9..f0c08d8a0 100644 --- a/README.md +++ b/README.md @@ -80,10 +80,3 @@ Install .Net Core 3.1 SDK via Visual Studio installer or manually from [here](ht ## Documentation [Wiki](https://github.com/Flow-Launcher/Flow.Launcher/wiki) - -## A history of the flow -Flow's roots came from a rebrand of the [JJW24/Wox fork](https://github.com/jjw24/Wox/issues/156) and WoX. - -A big thank you and all credits to [Bao](https://github.com/bao-qian), the author of WoX, and its contrbutors for all the amazing work. - -The JJW24/Wox fork started adding new changes on top of main WoX repo's code base from release v1.3.524. Flow is a continuation of the work from JJW24/Wox diff --git a/attribution.md b/attribution.md new file mode 100644 index 000000000..c47542d6a --- /dev/null +++ b/attribution.md @@ -0,0 +1,6 @@ +Flow's roots came from a rebrand of the [JJW24/Wox fork](https://github.com/jjw24/Wox/issues/156) and [WoX](https://github.com/Wox-launcher/Wox). + +A big thank you and all credits to [Bao](https://github.com/bao-qian), the author of WoX, and its contributors for all the amazing work. + +The JJW24/Wox fork started adding new changes on top of main WoX repo's code base from release v1.3.524. +Flow is a continuation of the work from JJW24/Wox. From 88af30207c594aa99c59c17826cb3aedc6e5b849 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 16 Dec 2020 21:52:00 +1100 Subject: [PATCH 109/267] add context menu for PluginsManager --- .../ContextMenu.cs | 60 ++++++++++++++++-- .../Images/request.png | Bin 0 -> 50820 bytes .../Images/sourcecode.png | Bin 0 -> 11842 bytes .../Images/website.png | Bin 0 -> 133947 bytes .../Languages/en.xaml | 8 +++ .../PluginsManager.cs | 3 +- 6 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Images/request.png create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Images/sourcecode.png create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Images/website.png diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs index d26c1ead4..f071e0e98 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; @@ -19,11 +20,60 @@ namespace Flow.Launcher.Plugin.PluginsManager 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.NewBrowserWindow(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.NewBrowserWindow(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.NewBrowserWindow(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.NewBrowserWindow("https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest"); + return true; + } + } + }; } } } 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 0000000000000000000000000000000000000000..a9126cb9bd8e06e3a0772e6405cd0e87c053c265 GIT binary patch literal 50820 zcmeFZ`(KRt|37|JRJMaGk{H!CBP3KbAST4o|0*lulj*`o%kam99X4xi2%I`uEy(3?J(lI&aw|+&NtI{Y!g(yUwmhHDi5Ik$vC) zOqE4_zp7*CxW!Ev!u#U!i+CAX){cig+sWl!;+{*g_BSjq�~L-@m>Yh>ChJ?fcWH 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 U3ySeQFB**(xMcq6d2zq|C#DQg!2kdN literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..8efbdaa487d0ab825010fa3f3e7331824fd6f207 GIT binary patch literal 11842 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 literal 0 HcmV?d00001 diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index fc13f0c2f..14fc2d586 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -20,5 +20,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/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index fc4abc800..3ccf696cc 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -115,7 +115,8 @@ namespace Flow.Launcher.Plugin.PluginsManager InstallOrUpdate(x); return true; - } + }, + ContextData = x }) .ToList(); From 407ff8266661c67f58bd7bd0682228d0ef6476e7 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 16 Dec 2020 21:53:02 +1100 Subject: [PATCH 110/267] version bump for PluginsManager --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 0353fffcc..73e03d525 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.2.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From 919f72ba62e1b1a6fdad77d8f0c3bc74e26caed9 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 06:31:33 +1100 Subject: [PATCH 111/267] use open tab in browser --- Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs index f071e0e98..76cb0f86b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs @@ -31,7 +31,7 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = "Images\\website.png", Action = _ => { - SharedCommands.SearchWeb.NewBrowserWindow(pluginManifestInfo.Website); + SharedCommands.SearchWeb.NewTabInBrowser(pluginManifestInfo.Website); return true; } }, @@ -42,7 +42,7 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = "Images\\sourcecode.png", Action = _ => { - SharedCommands.SearchWeb.NewBrowserWindow(pluginManifestInfo.UrlSourceCode); + SharedCommands.SearchWeb.NewTabInBrowser(pluginManifestInfo.UrlSourceCode); return true; } }, From f12ea653d29fe2152293460f72483ae397551d74 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 18:54:30 +1100 Subject: [PATCH 112/267] move autocomplete to method --- .../PluginsManager.cs | 69 ++++++++++--------- 1 file changed, 38 insertions(+), 31 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index c141916aa..ea94ab6ef 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -42,7 +42,7 @@ namespace Flow.Launcher.Plugin.PluginsManager 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 { @@ -65,9 +65,9 @@ namespace Flow.Launcher.Plugin.PluginsManager Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath)); } - internal void Update() + internal void Update(string search) { - throw new NotImplementedException(); + } internal bool PluginExists(string id) @@ -75,12 +75,6 @@ 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) { if (string.IsNullOrEmpty(searchName)) @@ -162,29 +156,13 @@ namespace Flow.Launcher.Plugin.PluginsManager internal List RequestUninstall(string search) { - if (!string.IsNullOrEmpty(search) - && Settings.UninstallHotkey.StartsWith(search) - && (Settings.UninstallHotkey != search || !search.StartsWith(Settings.UninstallHotkey))) - { - return - new List - { - new Result - { - Title = "Uninstall", - IcoPath = icoPath, - SubTitle = "Select a plugin to uninstall", - Action = e => - { - Context - .API - .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UninstallHotkey} "); + var autocompletedResults = AutoCompleteReturnAllResults(search, + Settings.UninstallHotkey, + "Uninstall", + "Select a plugin to uninstall"); - return false; - } - } - }; - } + if (autocompletedResults.Any()) + return autocompletedResults; var uninstallSearch = search.Replace(Settings.UninstallHotkey, string.Empty).TrimStart(); @@ -223,5 +201,34 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.RestartApp(); } } + + private List AutoCompleteReturnAllResults(string search, string hotkey, string title, string subtitle) + { + if (!string.IsNullOrEmpty(search) + && hotkey.StartsWith(search) + && (hotkey != search || !search.StartsWith(hotkey))) + { + return + new List + { + new Result + { + Title = title, + IcoPath = icoPath, + SubTitle = subtitle, + Action = e => + { + Context + .API + .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} "); + + return false; + } + } + }; + } + + return new List(); + } } } From df454778ec2d6fedad6e3b57d1e39a5b5acc8879 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 19:00:27 +1100 Subject: [PATCH 113/267] update plugin containing folder name from id to version --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index ea94ab6ef..1b13dabf8 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -147,7 +147,7 @@ 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); From 7e8c49502e38e9473affba6f57a793a6e89e21a5 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 20:37:01 +1100 Subject: [PATCH 114/267] add plugin update call --- .../Languages/en.xaml | 5 + .../Main.cs | 8 +- .../Models/UserPlugin.cs | 5 +- .../PluginsManager.cs | 110 ++++++++++++++---- .../Settings.cs | 4 +- 5 files changed, 105 insertions(+), 27 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index 7f8557c28..f69f23f6b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -11,6 +11,11 @@ Plugin Install Plugin Uninstall Install failed: unable to find the plugin.json metadata file from the new plugin + 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 + diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 58ec5005f..43f92e7b9 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -42,9 +42,13 @@ namespace Flow.Launcher.Plugin.PluginsManager var pluginManager = new PluginsManager(Context, Settings); if (!string.IsNullOrEmpty(search) - && ($"{Settings.UninstallHotkey} ".StartsWith(search) || search.StartsWith($"{Settings.UninstallHotkey} "))) + && ($"{Settings.HotkeyUninstall} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUninstall} "))) return pluginManager.RequestUninstall(search); - + + if (!string.IsNullOrEmpty(search) + && ($"{Settings.HotkeyUpdate} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUpdate} "))) + return pluginManager.RequestUpdate(search); + return pluginManager.RequestInstallOrUpdate(search); } 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 1b13dabf8..37051e4da 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -62,12 +62,82 @@ namespace Flow.Launcher.Plugin.PluginsManager Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } - Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath)); + Application.Current.Dispatcher.Invoke(() => { Install(plugin, filePath); Context.API.RestartApp(); }); } - internal void Update(string search) + internal List RequestUpdate(string search) { + 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 != pluginFromManifest.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"); + Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); + Install(x.PluginNewUserPlugin, downloadToFilePath); + + Context.API.RestartApp(); + + return true; + } + + return false; + } + }) + .ToList(); + + return Search(results, uninstallSearch); } internal bool PluginExists(string id) @@ -150,21 +220,19 @@ namespace Flow.Launcher.Plugin.PluginsManager 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.UninstallHotkey, + Settings.HotkeyUninstall, "Uninstall", "Select a plugin to uninstall"); if (autocompletedResults.Any()) return autocompletedResults; - var uninstallSearch = search.Replace(Settings.UninstallHotkey, string.Empty).TrimStart(); + var uninstallSearch = search.Replace(Settings.HotkeyUninstall, string.Empty).TrimStart(); var results= Context.API .GetAllPlugins() @@ -176,10 +244,21 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = x.Metadata.IcoPath, Action = e => { - Application.Current.MainWindow.Hide(); - Uninstall(x.Metadata); + string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"), + x.Metadata.Name, x.Metadata.Author, + Environment.NewLine, Environment.NewLine); - return true; + 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; } }) .ToList(); @@ -189,17 +268,8 @@ namespace Flow.Launcher.Plugin.PluginsManager 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(); - } + // 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) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs index 0c647e6ae..e2e8d22e5 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -6,6 +6,8 @@ namespace Flow.Launcher.Plugin.PluginsManager { internal class Settings { - internal string UninstallHotkey { get; set; } = "uninstall"; + internal string HotkeyUninstall { get; set; } = "uninstall"; + + internal string HotkeyUpdate { get; set; } = "update"; } } From ceab9b2ecd8d4da48ff30c8fc8587d6df8138207 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 20:37:24 +1100 Subject: [PATCH 115/267] PluginsManager version bump --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 0353fffcc..e970e5a8e 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.3.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From cca53c2a7d34d6d99c6a6dcae1ec17c018e0419f Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 21:07:47 +1100 Subject: [PATCH 116/267] add hide main window override --- .../PluginsManager.cs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 37051e4da..22682cae4 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -19,6 +19,21 @@ namespace Flow.Launcher.Plugin.PluginsManager 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) @@ -178,7 +193,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Application.Current.MainWindow.Hide(); InstallOrUpdate(x); - return true; + return ShouldHideWindow; } }) .ToList(); From c2ca29dcdae315ddcf6735fb4b74ed7557eaa761 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 17 Dec 2020 21:37:38 +1100 Subject: [PATCH 117/267] add go to update section if update exists when install --- .../Languages/en.xaml | 2 ++ .../PluginsManager.cs | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index f69f23f6b..a5be6c63c 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -15,6 +15,8 @@ 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 diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 22682cae4..dad183227 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -46,7 +46,22 @@ namespace Flow.Launcher.Plugin.PluginsManager { if (PluginExists(plugin.ID)) { - Context.API.ShowMsg("Plugin already installed"); + if (Context.API.GetAllPlugins().Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version)) + { + 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; } From 5ab021f4449e19c5d935f96ec7f5cf835b5c2d9e Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 20 Dec 2020 20:08:52 +1100 Subject: [PATCH 118/267] update per comment --- .../PluginsManager.cs | 55 +++++++++---------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index bd80b3dfd..90f3277fb 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -138,34 +138,33 @@ namespace Flow.Launcher.Plugin.PluginsManager 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 => { - 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) { - string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"), - x.Name, x.Author, - Environment.NewLine, Environment.NewLine); + Uninstall(x.PluginExistingMetadata); - 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"); + Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); + Install(x.PluginNewUserPlugin, downloadToFilePath); - var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip"); - Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); - Install(x.PluginNewUserPlugin, downloadToFilePath); + Context.API.RestartApp(); - Context.API.RestartApp(); - - return true; - } - - return false; + return true; } - }) - .ToList(); + + return false; + } + }); return Search(results, uninstallSearch); } @@ -175,10 +174,10 @@ namespace Flow.Launcher.Plugin.PluginsManager return Context.API.GetAllPlugins().Any(x => x.Metadata.ID == id); } - 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 => @@ -211,8 +210,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return ShouldHideWindow; }, ContextData = x - }) - .ToList(); + }); return Search(results, searchName); } @@ -265,7 +263,7 @@ namespace Flow.Launcher.Plugin.PluginsManager var uninstallSearch = search.Replace(Settings.HotkeyUninstall, string.Empty).TrimStart(); - var results= Context.API + var results = Context.API .GetAllPlugins() .Select(x => new Result @@ -291,8 +289,7 @@ namespace Flow.Launcher.Plugin.PluginsManager return false; } - }) - .ToList(); + }); return Search(results, uninstallSearch); } From 3a6b6b721f697dd8fc163cf2e2590cfa187a01fd Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 20 Dec 2020 20:23:14 +1100 Subject: [PATCH 119/267] Flow.Launcher.Plugin version bump --- Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 0f6450d18..70013c274 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 From 110cf2a60710d0d3ad06264304859ba4a6030a7f Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 20 Dec 2020 20:28:30 +1100 Subject: [PATCH 120/267] version bump --- SolutionAssemblyInfo.cs | 6 +++--- appveyor.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SolutionAssemblyInfo.cs b/SolutionAssemblyInfo.cs index 018084a66..ccbfef5d0 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.6.0")] +[assembly: AssemblyFileVersion("1.6.0")] +[assembly: AssemblyInformationalVersion("1.6.0")] \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index f5841da3e..1f0937d6d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.5.0.{build}' +version: '1.6.0.{build}' init: - ps: | From cbfa3f354dc5c19cd84d1573853792db0b93cb41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 20 Dec 2020 17:44:46 +0800 Subject: [PATCH 121/267] Inform user when checking update fail or update fail, and wrap all code in one try catch instead of catch each exception seperately since they are all same kind of exception. Use using instead of manually dispose. --- Flow.Launcher.Core/Updater.cs | 110 ++++++++++++++-------------------- 1 file changed, 45 insertions(+), 65 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 20df23e40..3369526e0 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -29,89 +29,69 @@ 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; + + if (!silentUpdate) + api.ShowMsg("Please wait...", "Checking for new update"); + + using var updateManager = await GitHubUpdateManager(GitHubRepository); + - 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); + var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString()); + var currentVersion = Version.Parse(Constant.Version); - Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>"); + 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; + } - if (newReleaseVersion <= currentVersion) - { if (!silentUpdate) - MessageBox.Show("You already have the latest Flow Launcher version"); - updateManager.Dispose(); - return; - } + api.ShowMsg("Update found", "Updating..."); - if (!silentUpdate) - api.ShowMsg("Update found", "Updating..."); - - try - { await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply); + + 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}"); + + 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 Fail!", "Check your connection and 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] From adad5ae83bd8e036bcf93e2df174d4dbe7d2380e Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 20 Dec 2020 21:10:55 +1100 Subject: [PATCH 122/267] add url website in Settings --- Flow.Launcher.Infrastructure/Constant.cs | 2 ++ Flow.Launcher/SettingWindow.xaml | 4 ++-- Flow.Launcher/ViewModel/SettingWindowViewModel.cs | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs index df1464048..3dba35f8d 100644 --- a/Flow.Launcher.Infrastructure/Constant.cs +++ b/Flow.Launcher.Infrastructure/Constant.cs @@ -35,5 +35,7 @@ namespace Flow.Launcher.Infrastructure public const string DefaultTheme = "Darker"; public const string Themes = "Themes"; + + public const string Website = "https://flow-launcher.github.io"; } } diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 32f9e9a6e..e47f0e779 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -429,8 +429,8 @@ - - + + diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 853925852..96ee5a052 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -450,7 +450,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); From a9a62a5847b80e008ee00b6bce7b305e17822e88 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 21 Dec 2020 08:57:22 +1100 Subject: [PATCH 123/267] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0c08d8a0..5f3f7e1a7 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,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`/`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` From acd631be081c2fd044672c997eeb8998246b773d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 19:09:18 +0800 Subject: [PATCH 124/267] Change wording --- Flow.Launcher.Core/Updater.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 3369526e0..4e211c3ac 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -89,7 +89,7 @@ namespace Flow.Launcher.Core 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); - api.ShowMsg("Update Fail!", "Check your connection and proxy settings to github-cloud.s3.amazonaws.com."); + api.ShowMsg("Update Failed", "Check your connection and try updating proxy settings to github-cloud.s3.amazonaws.com."); return; } } From 85f5766022ec2282dd7cf2595c48785964e3433f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 19:30:18 +0800 Subject: [PATCH 125/267] Optimize a few code --- Flow.Launcher.Infrastructure/Http/Http.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 34665217c..4ec4f887f 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -75,12 +75,12 @@ namespace Flow.Launcher.Infrastructure.Http } } - public async static Task Download([NotNull] string url, [NotNull] string filePath) + public static async Task Download([NotNull] string url, [NotNull] string filePath) { using var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.OK) { - using var fileStream = new FileStream(filePath, FileMode.CreateNew); + await using var fileStream = new FileStream(filePath, FileMode.CreateNew); await response.Content.CopyToAsync(fileStream); } else @@ -93,7 +93,7 @@ namespace Flow.Launcher.Infrastructure.Http { Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url); - using var stream = await response.Content.ReadAsStreamAsync(); + await using var stream = await response.Content.ReadAsStreamAsync(); using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); var content = await reader.ReadToEndAsync(); if (response.StatusCode == HttpStatusCode.OK) From 96609f797e672021664c788f1d0acde1afec40ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 19:42:50 +0800 Subject: [PATCH 126/267] Change the place of Wait in PluginManifest to make code more elegent --- .../Models/PluginsManifest.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 290221710..13a5ae2ca 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -10,21 +10,19 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models internal class PluginsManifest { internal List UserPlugins { get; private set; } + internal PluginsManifest() { - DownloadManifest(); + DownloadManifest().Wait(); } - private void DownloadManifest() + private 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")); - - t.Wait(); + json = await Http.Get( + "https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"); UserPlugins = JsonConvert.DeserializeObject>(json); } @@ -34,7 +32,6 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models UserPlugins = new List(); } - } } -} +} \ No newline at end of file From 5ab8c4faa3bc858af489096e3b8f4e9f9e290d09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Mon, 21 Dec 2020 20:55:28 +0800 Subject: [PATCH 127/267] Update Proxy every time calling a http request method since the proxy setting won't update automatically without action --- Flow.Launcher.Infrastructure/Http/Http.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 4ec4f887f..a88d868a6 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -47,7 +47,14 @@ namespace Flow.Launcher.Infrastructure.Http } } - public static WebProxy WebProxy { get; private set; } = new WebProxy(); + private static WebProxy _proxy = new WebProxy(); + public static WebProxy WebProxy { + get + { + UpdateProxy(); + return _proxy; + } + } /// /// Update the Address of the Proxy to modify the client Proxy @@ -77,6 +84,7 @@ namespace Flow.Launcher.Infrastructure.Http public static async Task Download([NotNull] string url, [NotNull] string filePath) { + UpdateProxy(); using var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.OK) { @@ -91,6 +99,7 @@ namespace Flow.Launcher.Infrastructure.Http public static async Task Get([NotNull] string url, string encoding = "UTF-8") { + UpdateProxy(); Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url); await using var stream = await response.Content.ReadAsStreamAsync(); From 88fa862277eeff5a49058e72f3ec157ec817aa0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 00:31:00 +0800 Subject: [PATCH 128/267] Use event triggered update method instead of checking Proxy every time doing Http request --- Flow.Launcher.Infrastructure/Http/Http.cs | 64 +++++++-------- .../UserSettings/HttpProxy.cs | 81 +++++++++++++++++-- 2 files changed, 105 insertions(+), 40 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index a88d868a6..8fe910c0c 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -7,6 +7,7 @@ using JetBrains.Annotations; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using System; +using System.ComponentModel; namespace Flow.Launcher.Infrastructure.Http { @@ -15,6 +16,7 @@ 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, @@ -31,60 +33,54 @@ namespace Flow.Launcher.Infrastructure.Http client = new HttpClient(socketsHttpHandler, false); client.DefaultRequestHeaders.Add("User-Agent", UserAgent); - } + private static HttpProxy proxy; + public static HttpProxy Proxy { - private get - { - return proxy; - } + private get { return proxy; } set { proxy = value; - UpdateProxy(); + proxy.PropertyChanged += UpdateProxy; } } - private static WebProxy _proxy = new WebProxy(); - public static WebProxy WebProxy { - get - { - UpdateProxy(); - return _proxy; - } + private static readonly WebProxy _proxy = new WebProxy(); + + public static WebProxy WebProxy + { + get { return _proxy; } } /// /// Update the Address of the Proxy to modify the client Proxy /// - public static void UpdateProxy() - // TODO: need test with a proxy + public static void UpdateProxy(ProxyProperty property) { - if (Proxy != null && Proxy.Enabled && !string.IsNullOrEmpty(Proxy.Server)) + (_proxy.Address, _proxy.Credentials) = property switch { - if (string.IsNullOrEmpty(Proxy.UserName) || string.IsNullOrEmpty(Proxy.Password)) + ProxyProperty.Enabled => (Proxy.Enabled) switch { - WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); - WebProxy.Credentials = null; - } - else - { - WebProxy.Address = new Uri($"http://{Proxy.Server}:{Proxy.Port}"); - WebProxy.Credentials = new NetworkCredential(Proxy.UserName, Proxy.Password); - } - } - else - { - WebProxy.Address = new WebProxy().Address; - WebProxy.Credentials = null; - } + 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}"), _proxy.Credentials), + ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), + ProxyProperty.UserName => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)) + }; } public static async Task Download([NotNull] string url, [NotNull] string filePath) { - UpdateProxy(); using var response = await client.GetAsync(url); if (response.StatusCode == HttpStatusCode.OK) { @@ -99,7 +95,6 @@ namespace Flow.Launcher.Infrastructure.Http public static async Task Get([NotNull] string url, string encoding = "UTF-8") { - UpdateProxy(); Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url); await using var stream = await response.Content.ReadAsStreamAsync(); @@ -111,7 +106,8 @@ namespace Flow.Launcher.Infrastructure.Http } else { - throw new HttpRequestException($"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); + throw new HttpRequestException( + $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } } 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 From 968931e4a07246f0f15d3878dc50c535d193fdd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 13:45:11 +0800 Subject: [PATCH 129/267] return if cancellation requested before changing _isQueryRunning state --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 25768a25e..a8a8ec1d7 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -474,6 +474,8 @@ namespace Flow.Launcher.ViewModel // nothing to do here } + if (currentCancellationToken.IsCancellationRequested) + return; // this should happen once after all queries are done so progress bar should continue // until the end of all querying From b7a0ada60b72b2d5c619e455d1b615ff713776d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 21:53:59 +0800 Subject: [PATCH 130/267] Add Mapping to original string after translation. Not sure about the performance, but seems satisfying. It requires at most n times loop (n: number of translated charater) mapping once. --- .../PinyinAlphabet.cs | 81 +++++++++++++++---- Flow.Launcher.Infrastructure/StringMatcher.cs | 78 +++++++++--------- 2 files changed, 108 insertions(+), 51 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 80fd12820..4f1aedd4a 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,21 +1,77 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using System.Text; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; +using Microsoft.AspNetCore.Localization; using ToolGood.Words.Pinyin; namespace Flow.Launcher.Infrastructure { + public class TranslationMapping + { + private bool constructed; + + private List originalIndexs = new List(); + private List translatedIndexs = new List(); + private int translaedLength = 0; + + public void AddNewIndex(int originalIndex, int translatedIndex, int length) + { + if (constructed) + throw new InvalidOperationException("Mapping shouldn't be changed after constructed"); + + originalIndexs.Add(originalIndex); + translatedIndexs.Add(translatedIndex); + translatedIndexs.Add(translatedIndex + length); + translaedLength += length - 1; + } + + public int? MapToOriginalIndex(int translatedIndex) + { + if (translatedIndex > translatedIndexs.Last()) + return translatedIndex - translaedLength - 1; + + for (var i = 0; i < originalIndexs.Count; i++) + { + if (translatedIndex >= translatedIndexs[i * 2] && translatedIndex < translatedIndexs[i * 2 + 1]) + return originalIndexs[i]; + if (translatedIndex < translatedIndexs[i * 2]) + { + int indexDiff = 0; + for (int j = 0; j < i; j++) + { + indexDiff += translatedIndexs[i * 2 + 1] - translatedIndexs[i * 2] - 1; + } + + return translatedIndex - indexDiff; + } + } + + return translatedIndex; + } + + public void endConstruct() + { + if (constructed) + throw new InvalidOperationException("Mapping has already been constructed"); + constructed = true; + } + } + public interface IAlphabet { - string Translate(string stringToTranslate); + public (string translation, TranslationMapping map) Translate(string stringToTranslate); } public class PinyinAlphabet : IAlphabet { - private ConcurrentDictionary _pinyinCache = new ConcurrentDictionary(); + private ConcurrentDictionary _pinyinCache = + new ConcurrentDictionary(); + + private Settings _settings; public void Initialize([NotNull] Settings settings) @@ -23,7 +79,7 @@ namespace Flow.Launcher.Infrastructure _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public string Translate(string content) + public (string translation, TranslationMapping map) Translate(string content) { if (_settings.ShouldUsePinyin) { @@ -34,14 +90,7 @@ namespace Flow.Launcher.Infrastructure var resultList = WordsHelper.GetPinyinList(content); StringBuilder resultBuilder = new StringBuilder(); - - for (int i = 0; i < resultList.Length; i++) - { - if (content[i] >= 0x3400 && content[i] <= 0x9FD5) - resultBuilder.Append(resultList[i].First()); - } - - resultBuilder.Append(' '); + TranslationMapping map = new TranslationMapping(); bool pre = false; @@ -49,6 +98,7 @@ namespace Flow.Launcher.Infrastructure { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { + map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1); resultBuilder.Append(' '); resultBuilder.Append(resultList[i]); pre = true; @@ -60,15 +110,18 @@ namespace Flow.Launcher.Infrastructure pre = false; resultBuilder.Append(' '); } + resultBuilder.Append(resultList[i]); } } - return _pinyinCache[content] = resultBuilder.ToString(); + map.endConstruct(); + + return _pinyinCache[content] = (resultBuilder.ToString(), map); } else { - return content; + return (content, null); } } else @@ -78,7 +131,7 @@ namespace Flow.Launcher.Infrastructure } else { - return content; + return (content, null); } } } diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 96391f1d6..e885798b7 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -44,22 +44,12 @@ namespace Flow.Launcher.Infrastructure /// public MatchResult FuzzyMatch(string query, string stringToCompare, MatchOption opt) { - if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) return new MatchResult(false, UserSettingSearchPrecision); + if (string.IsNullOrEmpty(stringToCompare) || string.IsNullOrEmpty(query)) + return new MatchResult(false, UserSettingSearchPrecision); query = query.Trim(); - - stringToCompare = _alphabet?.Translate(stringToCompare) ?? stringToCompare; - - // This also can be done by spliting the query - - //(var spaceSplit, var upperSplit) = stringToCompare switch - //{ - // string s when s.Contains(' ') => (s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(w => w.First()), - // default(IEnumerable)), - // string s when s.Any(c => char.IsUpper(c)) && s.Any(c => char.IsLower(c)) => - // (null, Regex.Split(s, @"(? w.First())), - // _ => ((IEnumerable)null, (IEnumerable)null) - //}; + TranslationMapping map; + (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); var currentQueryIndex = 0; var acronymMatchData = new List(); @@ -75,19 +65,21 @@ namespace Flow.Launcher.Infrastructure switch (stringToCompare[compareIndex]) { - case char c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == char.ToLower(stringToCompare[compareIndex])) - || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) - || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(compareIndex); + case var c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == + char.ToLower(stringToCompare[compareIndex])) + || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) + || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == + queryWithoutCase[currentQueryIndex]) + || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): + acronymMatchData.Add(map?.MapToOriginalIndex(compareIndex) ?? compareIndex); currentQueryIndex++; continue; - case char c when char.IsWhiteSpace(c): + case var c when char.IsWhiteSpace(c): compareIndex++; acronymScore -= 10; break; - case char c when char.IsUpper(c) || char.IsNumber(c): + case var c when char.IsUpper(c) || char.IsNumber(c): acronymScore -= 10; break; } @@ -99,7 +91,7 @@ namespace Flow.Launcher.Infrastructure var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; - var querySubstrings = queryWithoutCase.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var querySubstrings = queryWithoutCase.Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries); int currentQuerySubstringIndex = 0; var currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; var currentQuerySubstringCharacterIndex = 0; @@ -114,9 +106,10 @@ namespace Flow.Launcher.Infrastructure var indexList = new List(); List spaceIndices = new List(); - for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) + for (var compareStringIndex = 0; + compareStringIndex < fullStringToCompareWithoutCase.Length; + compareStringIndex++) { - // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0) @@ -124,7 +117,8 @@ namespace Flow.Launcher.Infrastructure spaceIndices.Add(compareStringIndex); } - if (fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) + if (fullStringToCompareWithoutCase[compareStringIndex] != + currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; continue; @@ -148,14 +142,16 @@ namespace Flow.Launcher.Infrastructure // in order to do so we need to verify all previous chars are part of the pattern var startIndexToVerify = compareStringIndex - currentQuerySubstringCharacterIndex; - if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, fullStringToCompareWithoutCase, currentQuerySubstring)) + if (AllPreviousCharsMatched(startIndexToVerify, currentQuerySubstringCharacterIndex, + fullStringToCompareWithoutCase, currentQuerySubstring)) { matchFoundInPreviousLoop = true; // if it's the beginning character of the first query substring that is matched then we need to update start index firstMatchIndex = currentQuerySubstringIndex == 0 ? startIndexToVerify : firstMatchIndex; - indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, firstMatchIndexInWord, indexList); + indexList = GetUpdatedIndexList(startIndexToVerify, currentQuerySubstringCharacterIndex, + firstMatchIndexInWord, indexList); } } @@ -168,11 +164,13 @@ namespace Flow.Launcher.Infrastructure if (currentQuerySubstringCharacterIndex == currentQuerySubstring.Length) { // if any of the substrings was not matched then consider as all are not matched - allSubstringsContainedInCompareString = matchFoundInPreviousLoop && allSubstringsContainedInCompareString; + allSubstringsContainedInCompareString = + matchFoundInPreviousLoop && allSubstringsContainedInCompareString; currentQuerySubstringIndex++; - allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + allQuerySubstringsMatched = + AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); if (allQuerySubstringsMatched) break; @@ -182,13 +180,16 @@ namespace Flow.Launcher.Infrastructure } } + // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) { var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex); - var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); + var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, + lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - return new MatchResult(true, UserSettingSearchPrecision, indexList, score); + var resultList = indexList.Distinct().Select(x => map?.MapToOriginalIndex(x) ?? x).ToList(); + return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } return new MatchResult(false, UserSettingSearchPrecision); @@ -203,14 +204,15 @@ namespace Flow.Launcher.Infrastructure } else { - int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)).Where(item => firstMatchIndex > item).FirstOrDefault(); + int? ind = spaceIndices.OrderBy(item => (firstMatchIndex - item)) + .FirstOrDefault(item => firstMatchIndex > item); int closestSpaceIndex = ind ?? -1; return closestSpaceIndex; } } private static bool AllPreviousCharsMatched(int startIndexToVerify, int currentQuerySubstringCharacterIndex, - string fullStringToCompareWithoutCase, string currentQuerySubstring) + string fullStringToCompareWithoutCase, string currentQuerySubstring) { var allMatch = true; for (int indexToCheck = 0; indexToCheck < currentQuerySubstringCharacterIndex; indexToCheck++) @@ -225,7 +227,8 @@ namespace Flow.Launcher.Infrastructure return allMatch; } - private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, int firstMatchIndexInWord, List indexList) + private static List GetUpdatedIndexList(int startIndexToVerify, int currentQuerySubstringCharacterIndex, + int firstMatchIndexInWord, List indexList) { var updatedList = new List(); @@ -246,7 +249,8 @@ namespace Flow.Launcher.Infrastructure return currentQuerySubstringIndex >= querySubstringsLength; } - private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, bool allSubstringsContainedInCompareString) + private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen, + bool allSubstringsContainedInCompareString) { // A match found near the beginning of a string is scored more than a match found near the end // A match is scored more if the characters in the patterns are closer to each other, @@ -341,7 +345,7 @@ namespace Flow.Launcher.Infrastructure private bool IsSearchPrecisionScoreMet(int rawScore) { - return rawScore >= (int)SearchPrecision; + return rawScore >= (int) SearchPrecision; } private int ScoreAfterSearchPrecisionFilter(int rawScore) @@ -354,4 +358,4 @@ namespace Flow.Launcher.Infrastructure { public bool IgnoreCase { get; set; } = true; } -} +} \ No newline at end of file From 2c9f4149b7cbd0d86fd46e07f2fa2509917e67f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Tue, 22 Dec 2020 22:58:27 +0800 Subject: [PATCH 131/267] optimize use --- Flow.Launcher.Infrastructure/StringMatcher.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index e885798b7..22334c4bd 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -71,7 +71,7 @@ namespace Flow.Launcher.Infrastructure || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == queryWithoutCase[currentQueryIndex]) || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(map?.MapToOriginalIndex(compareIndex) ?? compareIndex); + acronymMatchData.Add(compareIndex); currentQueryIndex++; continue; @@ -86,7 +86,10 @@ namespace Flow.Launcher.Infrastructure } if (acronymMatchData.Count == query.Length && acronymScore >= 60) + { + acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; @@ -188,7 +191,7 @@ namespace Flow.Launcher.Infrastructure var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString); - var resultList = indexList.Distinct().Select(x => map?.MapToOriginalIndex(x) ?? x).ToList(); + var resultList = indexList.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); return new MatchResult(true, UserSettingSearchPrecision, resultList, score); } From 93486783e5fdb5f5e14abc1df1b4c5e8adccb1eb Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 23 Dec 2020 06:28:59 +1100 Subject: [PATCH 132/267] update plugin repo url --- Flow.Launcher/ViewModel/SettingWindowViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index 96ee5a052..c122f8037 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -213,7 +213,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 From 75b99415eb90f4ee7f8c5a30fedef4f785480cb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 26 Dec 2020 00:29:35 +0800 Subject: [PATCH 133/267] Use Binary Search instead of Linear search to reduce time complexity. Add Key Property for debugging. --- .../PinyinAlphabet.cs | 78 +++++++++++++++---- 1 file changed, 62 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 4f1aedd4a..be3c58f66 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -18,6 +18,13 @@ namespace Flow.Launcher.Infrastructure private List translatedIndexs = new List(); private int translaedLength = 0; + public string key { get; private set; } + + public void setKey(string key) + { + this.key = key; + } + public void AddNewIndex(int originalIndex, int translatedIndex, int length) { if (constructed) @@ -29,28 +36,64 @@ namespace Flow.Launcher.Infrastructure translaedLength += length - 1; } - public int? MapToOriginalIndex(int translatedIndex) + public int MapToOriginalIndex(int translatedIndex) { if (translatedIndex > translatedIndexs.Last()) return translatedIndex - translaedLength - 1; - - for (var i = 0; i < originalIndexs.Count; i++) - { - if (translatedIndex >= translatedIndexs[i * 2] && translatedIndex < translatedIndexs[i * 2 + 1]) - return originalIndexs[i]; - if (translatedIndex < translatedIndexs[i * 2]) - { - int indexDiff = 0; - for (int j = 0; j < i; j++) - { - indexDiff += translatedIndexs[i * 2 + 1] - translatedIndexs[i * 2] - 1; - } - return translatedIndex - indexDiff; + int lowerBound = 0; + int upperBound = originalIndexs.Count - 1; + + int count = 0; + + + // Corner case handle + if (translatedIndex < translatedIndexs[0]) + return translatedIndex; + if (translatedIndex > translatedIndexs.Last()) + { + int indexDef = 0; + for (int k = 0; k < originalIndexs.Count; k++) + { + indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2]; } + + return translatedIndex - indexDef - 1; } - return translatedIndex; + // Binary Search with Range + for (int i = originalIndexs.Count / 2;; count++) + { + if (translatedIndex < translatedIndexs[i * 2]) + { + // move to lower middle + upperBound = i; + i = (i + lowerBound) / 2; + } + else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1) + { + lowerBound = i; + // move to upper middle + // due to floor of integer division, move one up on corner case + i = (i + upperBound + 1) / 2; + } + else + return originalIndexs[i]; + + if (upperBound - lowerBound <= 1 && + translatedIndex > translatedIndexs[lowerBound * 2 + 1] && + translatedIndex < translatedIndexs[upperBound * 2]) + { + int indexDef = 0; + + for (int j = 0; j < upperBound; j++) + { + indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2]; + } + + return translatedIndex - indexDef - 1; + } + } } public void endConstruct() @@ -117,7 +160,10 @@ namespace Flow.Launcher.Infrastructure map.endConstruct(); - return _pinyinCache[content] = (resultBuilder.ToString(), map); + var key = resultBuilder.ToString(); + map.setKey(key); + + return _pinyinCache[content] = (key, map); } else { From 7ceb08071c6086f39911f1ff2c920e160267d41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sun, 27 Dec 2020 20:16:20 +0800 Subject: [PATCH 134/267] Use inner loop to evaluate acronym match (Big Change) Don't end loop before acronym match end since if acronym match exist, we will use that one. --- Flow.Launcher.Infrastructure/StringMatcher.cs | 99 ++++++++++++------- 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 22334c4bd..7ade76cdf 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -51,46 +51,13 @@ namespace Flow.Launcher.Infrastructure TranslationMapping map; (stringToCompare, map) = _alphabet?.Translate(stringToCompare) ?? (stringToCompare, null); - var currentQueryIndex = 0; + var currentAcronymQueryIndex = 0; var acronymMatchData = new List(); var queryWithoutCase = opt.IgnoreCase ? query.ToLower() : query; + // preset acronymScore int acronymScore = 100; - for (int compareIndex = 0; compareIndex < stringToCompare.Length; compareIndex++) - { - if (currentQueryIndex >= queryWithoutCase.Length) - break; - - - switch (stringToCompare[compareIndex]) - { - case var c when (compareIndex == 0 && queryWithoutCase[currentQueryIndex] == - char.ToLower(stringToCompare[compareIndex])) - || (char.IsUpper(c) && char.ToLower(c) == queryWithoutCase[currentQueryIndex]) - || (char.IsWhiteSpace(c) && char.ToLower(stringToCompare[++compareIndex]) == - queryWithoutCase[currentQueryIndex]) - || (char.IsNumber(c) && c == queryWithoutCase[currentQueryIndex]): - acronymMatchData.Add(compareIndex); - currentQueryIndex++; - continue; - - case var c when char.IsWhiteSpace(c): - compareIndex++; - acronymScore -= 10; - break; - case var c when char.IsUpper(c) || char.IsNumber(c): - acronymScore -= 10; - break; - } - } - - if (acronymMatchData.Count == query.Length && acronymScore >= 60) - { - acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); - return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); - } - var fullStringToCompareWithoutCase = opt.IgnoreCase ? stringToCompare.ToLower() : stringToCompare; @@ -109,24 +76,72 @@ namespace Flow.Launcher.Infrastructure var indexList = new List(); List spaceIndices = new List(); + bool spaceMet = false; + for (var compareStringIndex = 0; compareStringIndex < fullStringToCompareWithoutCase.Length; compareStringIndex++) { + if (currentAcronymQueryIndex >= queryWithoutCase.Length + || allQuerySubstringsMatched && acronymScore < (int) UserSettingSearchPrecision) + break; + + // To maintain a list of indices which correspond to spaces in the string to compare // To populate the list only for the first query substring - if (fullStringToCompareWithoutCase[compareStringIndex].Equals(' ') && currentQuerySubstringIndex == 0) + if (fullStringToCompareWithoutCase[compareStringIndex] == ' ' && currentQuerySubstringIndex == 0) { spaceIndices.Add(compareStringIndex); } - if (fullStringToCompareWithoutCase[compareStringIndex] != + // Acronym check + if (char.IsUpper(stringToCompare[compareStringIndex]) || + char.IsNumber(stringToCompare[compareStringIndex]) || + char.IsWhiteSpace(stringToCompare[compareStringIndex]) || + spaceMet) + { + if (fullStringToCompareWithoutCase[compareStringIndex] == + queryWithoutCase[currentAcronymQueryIndex]) + { + currentAcronymQueryIndex++; + + if (!spaceMet) + { + char currentCompareChar = stringToCompare[compareStringIndex]; + spaceMet = char.IsWhiteSpace(currentCompareChar); + // if is space, no need to check whether upper or digit, though insignificant + if (!spaceMet && compareStringIndex == 0 || char.IsUpper(currentCompareChar) || + char.IsDigit(currentCompareChar)) + { + acronymMatchData.Add(compareStringIndex); + } + } + else if (!(spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]))) + { + acronymMatchData.Add(compareStringIndex); + } + } + else + { + spaceMet = char.IsWhiteSpace(stringToCompare[compareStringIndex]); + // Acronym Penalty + if (!spaceMet) + { + acronymScore -= 10; + } + } + } + // Acronym end + + if (allQuerySubstringsMatched || fullStringToCompareWithoutCase[compareStringIndex] != currentQuerySubstring[currentQuerySubstringCharacterIndex]) { matchFoundInPreviousLoop = false; + continue; } + if (firstMatchIndex < 0) { // first matched char will become the start of the compared string @@ -174,8 +189,9 @@ namespace Flow.Launcher.Infrastructure allQuerySubstringsMatched = AllQuerySubstringsMatched(currentQuerySubstringIndex, querySubstrings.Length); + if (allQuerySubstringsMatched) - break; + continue; // otherwise move to the next query substring currentQuerySubstring = querySubstrings[currentQuerySubstringIndex]; @@ -183,6 +199,12 @@ namespace Flow.Launcher.Infrastructure } } + // return acronym Match if possible + if (acronymMatchData.Count == query.Length && acronymScore >= (int) UserSettingSearchPrecision) + { + acronymMatchData = acronymMatchData.Select(x => map?.MapToOriginalIndex(x) ?? x).Distinct().ToList(); + return new MatchResult(true, UserSettingSearchPrecision, acronymMatchData, acronymScore); + } // proceed to calculate score if every char or substring without whitespaces matched if (allQuerySubstringsMatched) @@ -249,6 +271,7 @@ namespace Flow.Launcher.Infrastructure private static bool AllQuerySubstringsMatched(int currentQuerySubstringIndex, int querySubstringsLength) { + // Acronym won't utilize the substring to match return currentQuerySubstringIndex >= querySubstringsLength; } From 34f51927cf5955d49174a45cbb0eee60802b7466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sun, 27 Dec 2020 21:13:25 +0800 Subject: [PATCH 135/267] 1. Move PluginsManager constuction to Init(). 2. Return HotKeys list when query is like "pm *" --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- .../Main.cs | 34 ++- .../PluginsManager.cs | 250 ++++++++++-------- .../Settings.cs | 46 +++- 4 files changed, 201 insertions(+), 131 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 1d5f240e1..2d798ec11 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -59,7 +59,7 @@ namespace Flow.Launcher.Infrastructure.Http Log.Debug($"|Http.Get|Url <{url}>"); var request = WebRequest.CreateHttp(url); request.Method = "GET"; - request.Timeout = 1000; + request.Timeout = 6000; request.Proxy = WebProxy(); request.UserAgent = UserAgent; var response = await request.GetResponseAsync() as HttpWebResponse; diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 43f92e7b9..6cf9e1608 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -3,13 +3,15 @@ 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; namespace Flow.Launcher.Plugin.PluginsManager { public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n { - internal PluginInitContext Context { get; set; } + internal static PluginInitContext Context { get; set; } internal Settings Settings; @@ -17,6 +19,8 @@ namespace Flow.Launcher.Plugin.PluginsManager private IContextMenu contextMenu; + internal PluginsManager pluginManager; + public Control CreateSettingPanel() { return new PluginsManagerSettings(viewModel); @@ -28,6 +32,7 @@ namespace Flow.Launcher.Plugin.PluginsManager viewModel = new SettingsViewModel(context); Settings = viewModel.Settings; contextMenu = new ContextMenu(Context, Settings); + pluginManager = new PluginsManager(Context, Settings); } public List LoadContextMenus(Result selectedResult) @@ -38,18 +43,21 @@ namespace Flow.Launcher.Plugin.PluginsManager public List Query(Query query) { var search = query.Search.ToLower(); + + if (string.IsNullOrWhiteSpace(search)) + return Settings.HotKeys; - var pluginManager = new PluginsManager(Context, Settings); - - if (!string.IsNullOrEmpty(search) - && ($"{Settings.HotkeyUninstall} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUninstall} "))) - return pluginManager.RequestUninstall(search); - - if (!string.IsNullOrEmpty(search) - && ($"{Settings.HotkeyUpdate} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUpdate} "))) - return pluginManager.RequestUpdate(search); - - return pluginManager.RequestInstallOrUpdate(search); + 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), + _ => Settings.HotKeys.Where(hotkey => + { + hotkey.Score = StringMatcher.FuzzySearch(search, hotkey.Title).Score; + return hotkey.Score > 0; + }).ToList() + }; } public void Save() @@ -67,4 +75,4 @@ namespace Flow.Launcher.Plugin.PluginsManager return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description"); } } -} +} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 90f3277fb..23d2756ae 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -20,7 +20,8 @@ namespace Flow.Launcher.Plugin.PluginsManager private Settings Settings { get; set; } private bool shouldHideWindow = true; - private bool ShouldHideWindow + + private bool ShouldHideWindow { set { shouldHideWindow = value; } get @@ -42,18 +43,21 @@ namespace Flow.Launcher.Plugin.PluginsManager Context = context; Settings = settings; } + internal void InstallOrUpdate(UserPlugin plugin) { if (PluginExists(plugin.ID)) { - if (Context.API.GetAllPlugins().Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version)) + if (Context.API.GetAllPlugins() + .Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version)) { 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}"); + 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; @@ -66,10 +70,11 @@ namespace Flow.Launcher.Plugin.PluginsManager } 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.Version}.zip"); @@ -77,30 +82,34 @@ namespace Flow.Launcher.Plugin.PluginsManager 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); Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), - Context.API.GetTranslation("plugin_pluginsmanager_download_success")); + Context.API.GetTranslation("plugin_pluginsmanager_download_success")); } catch (Exception e) { Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), - Context.API.GetTranslation("plugin_pluginsmanager_download_success")); + Context.API.GetTranslation("plugin_pluginsmanager_download_success")); Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } - Application.Current.Dispatcher.Invoke(() => { Install(plugin, filePath); Context.API.RestartApp(); }); + Application.Current.Dispatcher.Invoke(() => + { + Install(plugin, filePath); + Context.API.RestartApp(); + }); } internal List RequestUpdate(string search) { var autocompletedResults = AutoCompleteReturnAllResults(search, - Settings.HotkeyUpdate, - "Update", - "Select a plugin to update"); + Settings.HotkeyUpdate, + "Update", + "Select a plugin to update"); if (autocompletedResults.Any()) return autocompletedResults; @@ -108,63 +117,68 @@ namespace Flow.Launcher.Plugin.PluginsManager 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 != pluginFromManifest.Version - select - new - { - pluginFromManifest.Name, - pluginFromManifest.Author, - CurrentVersion = existingPlugin.Metadata.Version, - NewVersion = pluginFromManifest.Version, - existingPlugin.Metadata.IcoPath, - PluginExistingMetadata = existingPlugin.Metadata, - PluginNewUserPlugin = pluginFromManifest - }; + var resultsForUpdate = + from existingPlugin in Context.API.GetAllPlugins() + join pluginFromManifest in pluginsManifest.UserPlugins + on existingPlugin.Metadata.ID equals pluginFromManifest.ID + where existingPlugin.Metadata.Version != pluginFromManifest.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 - }}; + 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); + .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); + 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"); - Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); - Install(x.PluginNewUserPlugin, downloadToFilePath); + var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, + $"{x.Name}-{x.NewVersion}.zip"); + Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); + Install(x.PluginNewUserPlugin, downloadToFilePath); - Context.API.RestartApp(); + Context.API.RestartApp(); - return true; - } + return true; + } - return false; - } - }); + return false; + } + }); return Search(results, uninstallSearch); } @@ -180,37 +194,37 @@ namespace Flow.Launcher.Plugin.PluginsManager 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 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); - return ShouldHideWindow; - }, - ContextData = x - }); + return ShouldHideWindow; + }, + ContextData = x + }); return Search(results, searchName); } @@ -253,10 +267,10 @@ namespace Flow.Launcher.Plugin.PluginsManager internal List RequestUninstall(string search) { - var autocompletedResults = AutoCompleteReturnAllResults(search, - Settings.HotkeyUninstall, - "Uninstall", - "Select a plugin to uninstall"); + var autocompletedResults = AutoCompleteReturnAllResults(search, + Settings.HotkeyUninstall, + "Uninstall", + "Select a plugin to uninstall"); if (autocompletedResults.Any()) return autocompletedResults; @@ -264,32 +278,34 @@ namespace Flow.Launcher.Plugin.PluginsManager 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); + .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(); + 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 true; + } - return false; - } - }); + return false; + } + }); return Search(results, uninstallSearch); } @@ -300,6 +316,7 @@ namespace Flow.Launcher.Plugin.PluginsManager 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) @@ -317,8 +334,9 @@ namespace Flow.Launcher.Plugin.PluginsManager Action = e => { Context - .API - .ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} "); + .API + .ChangeQuery( + $"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} "); return false; } @@ -329,4 +347,4 @@ namespace Flow.Launcher.Plugin.PluginsManager return new List(); } } -} +} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs index e2e8d22e5..5fc3916c0 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -6,8 +6,52 @@ namespace Flow.Launcher.Plugin.PluginsManager { internal class Settings { + internal string HotKeyInstall { get; set; } = "install"; internal string HotkeyUninstall { get; set; } = "uninstall"; internal string HotkeyUpdate { get; set; } = "update"; + + internal readonly string icoPath = "Images\\pluginsmanager.png"; + + + internal List HotKeys + { + get + { + return new List() + { + new Result() + { + Title = HotKeyInstall, + IcoPath = icoPath, + Action = _ => + { + Main.Context.API.ChangeQuery("pm install "); + return false; + } + }, + new Result() + { + Title = HotkeyUninstall, + IcoPath = icoPath, + Action = _ => + { + Main.Context.API.ChangeQuery("pm uninstall "); + return false; + } + }, + new Result() + { + Title = HotkeyUpdate, + IcoPath = icoPath, + Action = _ => + { + Main.Context.API.ChangeQuery("pm update "); + return false; + } + } + }; + } + } } -} +} \ No newline at end of file From deaac1c7e48ff6ef370a4127247fc22cb94a8f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 27 Dec 2020 22:33:12 +0800 Subject: [PATCH 136/267] replace install from search keyword --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 23d2756ae..bd998514a 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -207,6 +207,8 @@ namespace Flow.Launcher.Plugin.PluginsManager internal List RequestInstallOrUpdate(string searchName) { + var searchNameWithoutKeyword = searchName.Replace(Settings.HotKeyInstall, string.Empty).Trim(); + var results = pluginsManifest .UserPlugins @@ -226,7 +228,7 @@ namespace Flow.Launcher.Plugin.PluginsManager ContextData = x }); - return Search(results, searchName); + return Search(results, searchNameWithoutKeyword); } private void Install(UserPlugin plugin, string downloadedFilePath) From 5a0358718cd9b76b71da0c885c853f39e7e09b60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 28 Dec 2020 23:06:47 +0800 Subject: [PATCH 137/267] Update PluginManifest if last update time is 12 hours ago --- .../Flow.Launcher.Plugin.PluginsManager/Main.cs | 16 +++++++++++++++- .../Models/PluginsManifest.cs | 10 +++------- .../PluginsManager.cs | 8 +++++++- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 6cf9e1608..9aa024fc8 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -6,6 +6,8 @@ using System.Collections.Generic; using System.Linq; using System.Windows.Controls; using Flow.Launcher.Infrastructure; +using System; +using System.Threading.Tasks; namespace Flow.Launcher.Plugin.PluginsManager { @@ -21,6 +23,8 @@ namespace Flow.Launcher.Plugin.PluginsManager internal PluginsManager pluginManager; + internal DateTime _lastUpdateTime; + public Control CreateSettingPanel() { return new PluginsManagerSettings(viewModel); @@ -33,6 +37,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Settings = viewModel.Settings; contextMenu = new ContextMenu(Context, Settings); pluginManager = new PluginsManager(Context, Settings); + _lastUpdateTime = DateTime.Now; } public List LoadContextMenus(Result selectedResult) @@ -43,10 +48,19 @@ namespace Flow.Launcher.Plugin.PluginsManager public List Query(Query query) { var search = query.Search.ToLower(); - + if (string.IsNullOrWhiteSpace(search)) return Settings.HotKeys; + if ((DateTime.Now - _lastUpdateTime).TotalSeconds > 43200) // 12 hours + { + Task.Run(async () => + { + await pluginManager.UpdateManifest(); + _lastUpdateTime = DateTime.Now; + }); + } + return search switch { var s when s.StartsWith(Settings.HotKeyInstall) => pluginManager.RequestInstallOrUpdate(s), diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 290221710..1c31432b2 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -12,19 +12,15 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models internal List UserPlugins { get; private set; } internal PluginsManifest() { - DownloadManifest(); + Task.Run(() => DownloadManifest()).Wait(); } - 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")); - - t.Wait(); + json = await Http.Get("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"); UserPlugins = JsonConvert.DeserializeObject>(json); } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index bd998514a..c6f127387 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -7,13 +7,14 @@ 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; } @@ -44,6 +45,11 @@ namespace Flow.Launcher.Plugin.PluginsManager Settings = settings; } + internal async Task UpdateManifest() + { + await pluginsManifest.DownloadManifest(); + } + internal void InstallOrUpdate(UserPlugin plugin) { if (PluginExists(plugin.ID)) From 00457ddc29aad8088eac5439d0be10f2368a82f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 12:08:41 +0800 Subject: [PATCH 138/267] change totalSeconds to Hours --- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 9aa024fc8..fe11b619e 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -52,7 +52,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (string.IsNullOrWhiteSpace(search)) return Settings.HotKeys; - if ((DateTime.Now - _lastUpdateTime).TotalSeconds > 43200) // 12 hours + if ((DateTime.Now - _lastUpdateTime).TotalHours > 12) // 12 hours { Task.Run(async () => { From bb9682f7918ec6afa8ef0441dbe09fa8306a3b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 12:14:59 +0800 Subject: [PATCH 139/267] Move get default hotkeys to pluginmanger and make Main.Context non-static --- .../Main.cs | 2 +- .../PluginsManager.cs | 37 +++++++++++++++++ .../Settings.cs | 40 ------------------- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index fe11b619e..8d99bf37d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -13,7 +13,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n { - internal static PluginInitContext Context { get; set; } + internal PluginInitContext Context { get; set; } internal Settings Settings; diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index c6f127387..29ff9cb54 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -50,6 +50,43 @@ namespace Flow.Launcher.Plugin.PluginsManager 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 void InstallOrUpdate(UserPlugin plugin) { if (PluginExists(plugin.ID)) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs index 5fc3916c0..3753056f7 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -12,46 +12,6 @@ namespace Flow.Launcher.Plugin.PluginsManager internal string HotkeyUpdate { get; set; } = "update"; internal readonly string icoPath = "Images\\pluginsmanager.png"; - - - internal List HotKeys - { - get - { - return new List() - { - new Result() - { - Title = HotKeyInstall, - IcoPath = icoPath, - Action = _ => - { - Main.Context.API.ChangeQuery("pm install "); - return false; - } - }, - new Result() - { - Title = HotkeyUninstall, - IcoPath = icoPath, - Action = _ => - { - Main.Context.API.ChangeQuery("pm uninstall "); - return false; - } - }, - new Result() - { - Title = HotkeyUpdate, - IcoPath = icoPath, - Action = _ => - { - Main.Context.API.ChangeQuery("pm update "); - return false; - } - } - }; - } } } } \ No newline at end of file From f32e202746397e6542f5a831b8b675ce5e1878c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 12:20:13 +0800 Subject: [PATCH 140/267] Use System.Text.JsonSerializer.DeserializeAsync instead of Newtonsoft.Json since our plugins.json can be large, so no need to create an extra string to store it. --- Flow.Launcher.Infrastructure/Http/Http.cs | 13 +++++++++++++ .../Models/PluginsManifest.cs | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 2d798ec11..62cacc18f 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -73,5 +73,18 @@ namespace Flow.Launcher.Infrastructure.Http return content; } + + public static async Task GetStreamAsync([NotNull] string url, string encoding = "UTF-8") + { + Log.Debug($"|Http.Get|Url <{url}>"); + var request = WebRequest.CreateHttp(url); + request.Method = "GET"; + request.Timeout = 6000; + request.Proxy = WebProxy(); + request.UserAgent = UserAgent; + var response = await request.GetResponseAsync() as HttpWebResponse; + response = response.NonNull(); + return response.GetResponseStream().NonNull(); + } } } \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 1c31432b2..2ab8806bc 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -1,8 +1,8 @@ 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 @@ -17,12 +17,12 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models internal async Task DownloadManifest() { - var json = string.Empty; try { - json = await Http.Get("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json"); + var jsonStream = await Http.GetStreamAsync("https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher.PluginsManifest/main/plugins.json") + .ConfigureAwait(false); - UserPlugins = JsonConvert.DeserializeObject>(json); + UserPlugins = await JsonSerializer.DeserializeAsync>(jsonStream).ConfigureAwait(false); } catch (Exception e) { From f0267475f520f9bd53981201dabc72e22877e2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 12:23:15 +0800 Subject: [PATCH 141/267] Change call method for default hotkeys. Remove extra whitespace add await using for stream --- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 4 ++-- .../Models/PluginsManifest.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 8d99bf37d..607b2e3f5 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -50,7 +50,7 @@ namespace Flow.Launcher.Plugin.PluginsManager var search = query.Search.ToLower(); if (string.IsNullOrWhiteSpace(search)) - return Settings.HotKeys; + return pluginManager.GetDefaultHotKeys(); if ((DateTime.Now - _lastUpdateTime).TotalHours > 12) // 12 hours { @@ -66,7 +66,7 @@ namespace Flow.Launcher.Plugin.PluginsManager 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), - _ => Settings.HotKeys.Where(hotkey => + _ => pluginManager.GetDefaultHotKeys().Where(hotkey => { hotkey.Score = StringMatcher.FuzzySearch(search, hotkey.Title).Score; return hotkey.Score > 0; diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 2ab8806bc..c854b213d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -19,7 +19,7 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models { try { - var jsonStream = await Http.GetStreamAsync("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); UserPlugins = await JsonSerializer.DeserializeAsync>(jsonStream).ConfigureAwait(false); @@ -33,4 +33,4 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models } } -} +} \ No newline at end of file From 5da8259228120ccbfed0662de1131bd3a95fed85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 13:03:38 +0800 Subject: [PATCH 142/267] fix an unintended text error add async await to download manifest task remove unused encoding name for new GetStreamAsync in Http fix unintened text error --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- .../Models/PluginsManifest.cs | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 62cacc18f..ea412759e 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -74,7 +74,7 @@ namespace Flow.Launcher.Infrastructure.Http return content; } - public static async Task GetStreamAsync([NotNull] string url, string encoding = "UTF-8") + public static async Task GetStreamAsync([NotNull] string url) { Log.Debug($"|Http.Get|Url <{url}>"); var request = WebRequest.CreateHttp(url); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index c854b213d..7b2f8e372 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -12,7 +12,7 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models internal List UserPlugins { get; private set; } internal PluginsManifest() { - Task.Run(() => DownloadManifest()).Wait(); + Task.Run(async () => await DownloadManifest()).Wait(); } internal async Task DownloadManifest() diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs index 3753056f7..d5d78d28a 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -12,6 +12,6 @@ namespace Flow.Launcher.Plugin.PluginsManager internal string HotkeyUpdate { get; set; } = "update"; internal readonly string icoPath = "Images\\pluginsmanager.png"; - } + } } \ No newline at end of file From c94a2f4c9599c49ad00b3e524b28ec044eb22868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 13:06:08 +0800 Subject: [PATCH 143/267] Use string.CompareTo instead of equal to check for update --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 29ff9cb54..2931afe30 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -164,7 +164,7 @@ namespace Flow.Launcher.Plugin.PluginsManager from existingPlugin in Context.API.GetAllPlugins() join pluginFromManifest in pluginsManifest.UserPlugins on existingPlugin.Metadata.ID equals pluginFromManifest.ID - where existingPlugin.Metadata.Version != pluginFromManifest.Version + where existingPlugin.Metadata.Version.CompareTo(pluginFromManifest.Version) > 0 select new { From a1a45a49890001150b8d4c78f8f8b3c763402565 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 17:49:11 +1100 Subject: [PATCH 144/267] add eof --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 2 +- .../Models/PluginsManifest.cs | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 3 +-- Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index ea412759e..9d2fe7860 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -87,4 +87,4 @@ namespace Flow.Launcher.Infrastructure.Http return response.GetResponseStream().NonNull(); } } -} \ 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 607b2e3f5..2d9a29a2f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -89,4 +89,4 @@ namespace Flow.Launcher.Plugin.PluginsManager return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description"); } } -} \ No newline at end of file +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs index 7b2f8e372..ad8185620 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -33,4 +33,4 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models } } -} \ No newline at end of file +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 2931afe30..d06bbf1f9 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -361,7 +361,6 @@ namespace Flow.Launcher.Plugin.PluginsManager 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) @@ -392,4 +391,4 @@ namespace Flow.Launcher.Plugin.PluginsManager return new List(); } } -} \ No newline at end of file +} diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs index d5d78d28a..a885bfd15 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -14,4 +14,4 @@ namespace Flow.Launcher.Plugin.PluginsManager internal readonly string icoPath = "Images\\pluginsmanager.png"; } -} \ No newline at end of file +} From f9349a64e96226b725500752755834ff1d493dea Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 17:49:37 +1100 Subject: [PATCH 145/267] fix condition of version compare --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index d06bbf1f9..9635648d4 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -164,7 +164,7 @@ namespace Flow.Launcher.Plugin.PluginsManager 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 + where existingPlugin.Metadata.Version.CompareTo(pluginFromManifest.Version) < 0 // if current version precedes manifest version select new { From e5b67ea10a43527c99e62317f466e2b14c467995 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 18:04:23 +1100 Subject: [PATCH 146/267] remove obsolete icoPath from settings --- Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs index a885bfd15..9c5b0d29f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs @@ -10,8 +10,5 @@ namespace Flow.Launcher.Plugin.PluginsManager internal string HotkeyUninstall { get; set; } = "uninstall"; internal string HotkeyUpdate { get; set; } = "update"; - - internal readonly string icoPath = "Images\\pluginsmanager.png"; - } } From 0a47636bc9e0427341d97aa471a67a94fef38b3c Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 18:13:52 +1100 Subject: [PATCH 147/267] remove obsolete settings property in context menu class --- Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs | 7 ++----- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs index 76cb0f86b..b9bf5ee85 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; using System; using System.Collections.Generic; @@ -10,12 +10,9 @@ 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) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 2d9a29a2f..a333b3862 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -1,5 +1,4 @@ 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; @@ -35,7 +34,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context = context; viewModel = new SettingsViewModel(context); Settings = viewModel.Settings; - contextMenu = new ContextMenu(Context, Settings); + contextMenu = new ContextMenu(Context); pluginManager = new PluginsManager(Context, Settings); _lastUpdateTime = DateTime.Now; } From a1d1c95eebb83867c4581759076b6167c7c0f65b Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 18:14:22 +1100 Subject: [PATCH 148/267] change to tab in browser --- Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs index b9bf5ee85..7bc357be4 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.PluginsManager.Models; using System; using System.Collections.Generic; @@ -55,7 +55,7 @@ namespace Flow.Launcher.Plugin.PluginsManager ? pluginManifestInfo.UrlSourceCode.Replace("/tree/master", "/issues/new/choose") : pluginManifestInfo.UrlSourceCode; - SharedCommands.SearchWeb.NewBrowserWindow(link); + SharedCommands.SearchWeb.NewTabInBrowser(link); return true; } }, @@ -66,7 +66,7 @@ namespace Flow.Launcher.Plugin.PluginsManager IcoPath = selectedResult.IcoPath, Action = _ => { - SharedCommands.SearchWeb.NewBrowserWindow("https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest"); + SharedCommands.SearchWeb.NewTabInBrowser("https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest"); return true; } } From b106688513f4d463656bd61c43034bcf71288acd Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 18:14:33 +1100 Subject: [PATCH 149/267] version bump --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index e970e5a8e..d94af71a1 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.3.0", + "Version": "1.3.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From 000bafd116910a5e8fcb919640be35f9ccfa2495 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 18:56:51 +1100 Subject: [PATCH 150/267] use camelCase and make last update time variable private --- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index a333b3862..716a424ff 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -22,7 +22,7 @@ namespace Flow.Launcher.Plugin.PluginsManager internal PluginsManager pluginManager; - internal DateTime _lastUpdateTime; + private DateTime lastUpdateTime; public Control CreateSettingPanel() { @@ -36,7 +36,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Settings = viewModel.Settings; contextMenu = new ContextMenu(Context); pluginManager = new PluginsManager(Context, Settings); - _lastUpdateTime = DateTime.Now; + lastUpdateTime = DateTime.Now; } public List LoadContextMenus(Result selectedResult) @@ -51,12 +51,12 @@ namespace Flow.Launcher.Plugin.PluginsManager if (string.IsNullOrWhiteSpace(search)) return pluginManager.GetDefaultHotKeys(); - if ((DateTime.Now - _lastUpdateTime).TotalHours > 12) // 12 hours + if ((DateTime.Now - lastUpdateTime).TotalHours > 12) // 12 hours { Task.Run(async () => { await pluginManager.UpdateManifest(); - _lastUpdateTime = DateTime.Now; + lastUpdateTime = DateTime.Now; }); } From a47f8b318510db0fe7e5edfacd91c1894e33221b Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 19:06:17 +1100 Subject: [PATCH 151/267] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5f3f7e1a7..02f488758 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,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/Update plugins: in the search window, type `pm`/`pm uninstall`/`pm update` + 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` From cfa93a2cc60808b84a131852a82f3e26ce1a4339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:13:31 +0800 Subject: [PATCH 152/267] Add GetStreamAsync method --- Flow.Launcher.Infrastructure/Http/Http.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 74e335d32..11d922aa1 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -110,5 +110,12 @@ namespace Flow.Launcher.Infrastructure.Http $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); } } + + public static async Task GetStreamAsync([NotNull] string url) + { + Log.Debug($"|Http.Get|Url <{url}>"); + var response = await client.GetAsync(url); + return await response.Content.ReadAsStreamAsync(); + } } } From a806f7d05adc9beb7419e555921192e094c10539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:14:13 +0800 Subject: [PATCH 153/267] Change exception type --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 11d922aa1..a98ead687 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -89,7 +89,7 @@ namespace Flow.Launcher.Infrastructure.Http } else { - throw new WebException($"Error code <{response.StatusCode}> returned from <{url}>"); + throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>"); } } From 4d5119f17d2f5b307dd7eb33384e63ee31b48c27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:15:34 +0800 Subject: [PATCH 154/267] Add out of bound exception for pattern matching --- Flow.Launcher.Infrastructure/Http/Http.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index a98ead687..040939e72 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -61,7 +61,7 @@ namespace Flow.Launcher.Infrastructure.Http { (_proxy.Address, _proxy.Credentials) = property switch { - ProxyProperty.Enabled => (Proxy.Enabled) switch + ProxyProperty.Enabled => Proxy.Enabled switch { true => Proxy.UserName switch { @@ -75,7 +75,8 @@ namespace Flow.Launcher.Infrastructure.Http ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), ProxyProperty.UserName => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), - ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)) + ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + _ => throw new ArgumentOutOfRangeException() }; } From e364b84b8458aa8df058fa9cf4507b2699d3224a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:16:44 +0800 Subject: [PATCH 155/267] Use auto property --- Flow.Launcher.Infrastructure/Http/Http.cs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 040939e72..3d056b28b 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -47,19 +47,14 @@ namespace Flow.Launcher.Infrastructure.Http } } - private static readonly WebProxy _proxy = new WebProxy(); - - public static WebProxy WebProxy - { - get { return _proxy; } - } + public static WebProxy WebProxy { get; } = new WebProxy(); /// /// Update the Address of the Proxy to modify the client Proxy /// public static void UpdateProxy(ProxyProperty property) { - (_proxy.Address, _proxy.Credentials) = property switch + (WebProxy.Address, WebProxy.Credentials) = property switch { ProxyProperty.Enabled => Proxy.Enabled switch { @@ -72,10 +67,10 @@ namespace Flow.Launcher.Infrastructure.Http }, false => (null, null) }, - ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), - ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), _proxy.Credentials), - ProxyProperty.UserName => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), - ProxyProperty.Password => (_proxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), + 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() }; } From 0c97db04d4b89d345ddb7908c5a6d361c11c0ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:50:56 +0800 Subject: [PATCH 156/267] 1. Change Get method Name to GetAsync 2. Manually replace "#" with "%23" to solve the similar issue in Explorer plugin 3. Add GetAsync method with Uri as argument 4. Remove unused encoding argument 5. Change exception type for WebSearch Plguin 6. Update Comment --- Flow.Launcher.Core/Updater.cs | 2 +- Flow.Launcher.Infrastructure/Http/Http.cs | 25 +++++++++++++++---- .../SuggestionSources/Baidu.cs | 5 ++-- .../SuggestionSources/Google.cs | 6 ++--- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index d8bc2b6dc..46fb6d977 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -133,7 +133,7 @@ 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 json = await Http.GetAsync(api); var releases = JsonConvert.DeserializeObject>(json); var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 3d056b28b..8e2832690 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -89,13 +89,23 @@ namespace Flow.Launcher.Infrastructure.Http } } - public static async Task Get([NotNull] string url, string encoding = "UTF-8") + /// + /// Asynchrously get the result as string from url. + /// When supposing the result is long and large, try using GetStreamAsync to avoid reading as string + /// + /// + /// + public static Task GetAsync([NotNull] string url) { Log.Debug($"|Http.Get|Url <{url}>"); - var response = await client.GetAsync(url); - await using var stream = await response.Content.ReadAsStreamAsync(); - using var reader = new StreamReader(stream, Encoding.GetEncoding(encoding)); - var content = await reader.ReadToEndAsync(); + return GetAsync(new Uri(url.Replace("#", "%23"))); + } + + public static async Task GetAsync([NotNull] Uri url) + { + Log.Debug($"|Http.Get|Url <{url}>"); + using var response = await client.GetAsync(url); + var content = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { return content; @@ -107,6 +117,11 @@ namespace Flow.Launcher.Infrastructure.Http } } + /// + /// Asynchrously get the result as stream from url. + /// + /// + /// public static async Task GetStreamAsync([NotNull] string url) { Log.Debug($"|Http.Get|Url <{url}>"); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index 57db223bc..6772acf82 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -8,6 +8,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; +using System.Net.Http; namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { @@ -22,9 +23,9 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources 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)).ConfigureAwait(false); } - catch (WebException e) + catch (HttpRequestException e) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return new List(); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 81878bd8b..5b9538091 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -7,6 +7,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; +using System.Net.Http; namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { @@ -18,13 +19,12 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources try { const string api = "https://www.google.com/complete/search?output=chrome&q="; - result = await Http.Get(api + Uri.EscapeUriString(query)); + result = await Http.GetAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); } - catch (WebException e) + 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; From efa4908f37636f3fe6122d241a5821d14a4bf6b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 17:54:39 +0800 Subject: [PATCH 157/267] Change usage of Http in Updater.cs and adding ConfigureAwait(false) for await in checking update --- Flow.Launcher.Core/Updater.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 46fb6d977..05397e906 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -29,7 +29,7 @@ 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; @@ -39,7 +39,7 @@ namespace Flow.Launcher.Core try { - updateManager = await GitHubUpdateManager(GitHubRepository); + updateManager = await GitHubUpdateManager(GitHubRepository).ConfigureAwait(false); } catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) { @@ -50,7 +50,7 @@ namespace Flow.Launcher.Core try { // UpdateApp CheckForUpdate will return value only if the app is squirrel installed - newUpdateInfo = await updateManager.CheckForUpdate().NonNull(); + newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false); } catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) { @@ -85,8 +85,8 @@ namespace Flow.Launcher.Core updateManager.Dispose(); return; } - - await updateManager.ApplyReleases(newUpdateInfo); + + await updateManager.ApplyReleases(newUpdateInfo).ConfigureAwait(false); if (DataLocation.PortableDataLocationInUse()) { @@ -98,11 +98,11 @@ namespace Flow.Launcher.Core } else { - await updateManager.CreateUninstallerRegistryEntry(); + await updateManager.CreateUninstallerRegistryEntry().ConfigureAwait(false); } var newVersionTips = NewVersinoTips(newReleaseVersion.ToString()); - + Log.Info($"|Updater.UpdateApp|Update success:{newVersionTips}"); // always dispose UpdateManager @@ -133,9 +133,9 @@ namespace Flow.Launcher.Core var uri = new Uri(repository); var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases"; - var json = await Http.GetAsync(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/"); From d4f94c66acfba5dddf0110b857519feed03eb99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 18:33:53 +0800 Subject: [PATCH 158/267] Make InstallOrUpdate to async --- Flow.Launcher.Core/Updater.cs | 8 ++++---- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 2 +- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 7 +++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 05397e906..1e4b0453c 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -8,7 +8,6 @@ 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; @@ -17,6 +16,7 @@ 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 { @@ -117,13 +117,13 @@ namespace Flow.Launcher.Core [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; } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 716a424ff..d700b9dfd 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -22,7 +22,7 @@ namespace Flow.Launcher.Plugin.PluginsManager internal PluginsManager pluginManager; - private DateTime lastUpdateTime; + private DateTime lastUpdateTime = DateTime.MinValue; public Control CreateSettingPanel() { diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 9635648d4..428610f43 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -87,7 +87,7 @@ namespace Flow.Launcher.Plugin.PluginsManager }; } - internal void InstallOrUpdate(UserPlugin plugin) + internal async Task InstallOrUpdate(UserPlugin plugin) { if (PluginExists(plugin.ID)) { @@ -127,7 +127,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); - Http.Download(plugin.UrlDownload, filePath); + await Http.Download(plugin.UrlDownload, filePath).ConfigureAwait(false); Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_download_success")); @@ -264,8 +264,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Action = e => { Application.Current.MainWindow.Hide(); - InstallOrUpdate(x); - + _ = InstallOrUpdate(x); // No need to wait return ShouldHideWindow; }, ContextData = x From d0743f627668fa5bbd55a3daef37f82064fc3a23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 18:48:00 +0800 Subject: [PATCH 159/267] Await Http.Download in Update method --- .../PluginsManager.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 428610f43..f12112382 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -140,11 +140,8 @@ namespace Flow.Launcher.Plugin.PluginsManager Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } - Application.Current.Dispatcher.Invoke(() => - { - Install(plugin, filePath); - Context.API.RestartApp(); - }); + Install(plugin, filePath); + Context.API.RestartApp(); } internal List RequestUpdate(string search) @@ -211,10 +208,14 @@ namespace Flow.Launcher.Plugin.PluginsManager var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip"); - Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath); - Install(x.PluginNewUserPlugin, downloadToFilePath); - Context.API.RestartApp(); + Task.Run(async delegate + { + await Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath).ConfigureAwait(false); + Install(x.PluginNewUserPlugin, downloadToFilePath); + + Context.API.RestartApp(); + }); return true; } From c485578cff927a1714344c0eca1ab82870673fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 29 Dec 2020 18:48:55 +0800 Subject: [PATCH 160/267] Use CompareTo to check update for InstallOrUpdate method --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index f12112382..ac15618ca 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -92,7 +92,7 @@ namespace Flow.Launcher.Plugin.PluginsManager if (PluginExists(plugin.ID)) { if (Context.API.GetAllPlugins() - .Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version)) + .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"), From e2b0386818dca21d0ce9aba69cbb5331d524e676 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 22:32:14 +1100 Subject: [PATCH 161/267] remove Color plugin from Flow as a default plugin --- Flow.Launcher.sln | 16 --- .../Flow.Launcher.Plugin.Color.csproj | 101 --------------- .../Images/color.png | Bin 1856 -> 0 bytes .../Languages/de.xaml | 8 -- .../Languages/en.xaml | 8 -- .../Languages/pl.xaml | 8 -- .../Languages/sk.xaml | 8 -- .../Languages/tr.xaml | 8 -- .../Languages/zh-cn.xaml | 8 -- .../Languages/zh-tw.xaml | 7 - Plugins/Flow.Launcher.Plugin.Color/Main.cs | 121 ------------------ .../Flow.Launcher.Plugin.Color/plugin.json | 12 -- 12 files changed, 305 deletions(-) delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Flow.Launcher.Plugin.Color.csproj delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Images/color.png delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/de.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/en.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/pl.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/sk.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/tr.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/zh-cn.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Languages/zh-tw.xaml delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/Main.cs delete mode 100644 Plugins/Flow.Launcher.Plugin.Color/plugin.json 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/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 da28583b1c9f174367acef0205f0c47f0a839ecd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1856 zcmV-G2fz4e%OapHR~QiSv}$ z`|SPw_WIV^7ZZNx5B<*d;}3xUcLaZx2=LHTUNG+g(Z&oQa{$CW^yENaxq-_Hz{8y` zB+|nR!VA?35U15cp8n}_fs_|uXnO#l4JE}f2Wac@mfsuz4{qxQDF;jmV{I>O9q2LD zR?=um5#Y|w4k*g=V0Hs=foL4e{dD9=9}hm|1EJlND8>kFJ=QUN>K-pK?EpdaHx2MO zlh)_CKj1Uf4`8m0a%ZOtN@jMwx*aq7cvt)$ve|1)4b15oU;X3{L`HVwUbbm_JuLxg zu9%7dcXjoEXiq6|kv09Hn$25QNg+5rlbrcJJi4~Jxm14)KIqx>MYn81qySml49hy2 zUj05uQO0UEZ)q@u$chKJd33EjSWK!%W+yp-iP;x$0zf>55P9N7J5vBAqF@Ff07I`{ zi%Skb7otG?5&%X#o4)8M6@4=RJ`hQ(OFqCN2&)3&d10G;AtobG7Jyz5J#Qul3fl-f zIUin605=tWXAS^;o=vCqD_^!lc?9Nbzo{fH6q%Za-{!7E#hvx7zX+flNh}8Dt}dyK z3N0kwOI$(_HU;%v>x#A)vIsC(YM+c%OIag&;Dc^J+ri013qF2zlC)Hj6>{%ST?q`? zS0}5TZak9vEOBxEuli?hTNuV4p7nor6^U~o53Ns+qKeaRn9P|e}CKHL8G?1 z0DRzxD+U?{vfE)1g=9QZ3L+Z4;E%;FwSq9_dI$}Q9X0s?iL^TN+E>xA%G5klU+a&q zs4KEnCfW<)Ewwq(3@tYSiO)kIZW0i6?P!i)LCd`5Rz30g5c}H(i*~U^0Q0tC!(C-52vto*rY;921%%@k z_${?a+Z$^s&{$(RIgxD5h+o_2hSj<-yVnHfY;$eq3vI)UUHcy$?9KnY7{Flm^Iwuh zB6jt{$t3+RR(;>B+ws6!92ifX|F6^Oh%T>N$d5(+>DWfk^TJAnQP7FNQI^&Gj90Tc z@#9ZZmoH5xD$}Z#IX)72tiH+_zHL=qL#=D|v%Z(dap;Wg-7mkp8lIS%ZD0+V1}wlbr1=*EsPVa(@V`!kr&FQJ5xP*NQELADt5K+i8pAHE zTX}Kop64Fh5`*>hJMUIce;sxvep*e?GL=k&Ef}qGU!AR6x8fh3^9_}DmhbKW$N@}P zC?_6iRd-AL?Ofddoo!j-RHygm_bM6MmHz*rB2|qltFDD?7In-dL~vi*;QT~oAH5{@ z0{pg-jY^46soKm?EE3iT%@cP&=pS0KK0WSKXzouxS`hoX6~tp$Zf}59DVl9F5T=q? z2sbLDvY9_Nb0wq_no@R0aO|0vHXJ*9PW;dD4QraU$-^NC`v{0t4&BH}Ac|&xKIe3v z%tFSBIO8tVYngaqn{ShItwQ|S9lPAB!%=(m?72+uv5jk>X>$==?w`y+RFNOmcHM={ z03v8j$2&|fWH~0WCNOiSmY8c132Wqe(f*jGetdD=9ge9D4=(sTA0XGK7X9)h(&I7I zr5-o3X%3>ouAL!5|Gr0t3~w-`yHPR7hr368KOiTgfXHDZq){ zqrC+AfkqDi3WW|=sZh1z1C1#FpbtCSukS!(#y%o8MF0wgmi=Yp$~gdsPo17DgfIob z7{Sx+*LNm9@#3ce(%G378fpyd=9h_ z!V~~-5IfsTUT#TqU`a`AAYKo`6hJwWI8#PVMB$KaF5~%}ZH#JGE)uDGEr!R_?7Pz0 zH(ZGe2OsvHaU~tIJ;v3DM-D%6dkfiYrgoG9;+=FrocfIJoBCkUy3yq+&*g3oNZ3gO zyac$J$pv7Xi2EOV{h{6$2I8V#OE18(eT}@at)c_(ed2}2ogj9DX&Quau+l55{rM9t z%>mg0mizvND!5 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" -} From 85584f40ee51d23e185ee67e4579859017dd1011 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 29 Dec 2020 22:41:21 +1100 Subject: [PATCH 162/267] remove post build script target of JsonRPC folder copy --- Scripts/post_build.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index 18ce33c4f..59036842a 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -36,7 +36,6 @@ function Copy-Resources ($path, $config) { $output = "$path\Output" $target = "$output\$config" Copy-Item -Recurse -Force $project\Images\* $target\Images\ - Copy-Item -Recurse -Force $path\JsonRPC $target\JsonRPC # 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 } From d28b14ff2d4cb9a8d58d926f9d2542fd22941758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 30 Dec 2020 13:40:42 +0800 Subject: [PATCH 163/267] Replace All use of Json.Net with System.Text.Json --- Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs | 6 ++-- Flow.Launcher.Core/Plugin/PluginConfig.cs | 4 +-- Flow.Launcher.Core/Updater.cs | 1 - Flow.Launcher.Infrastructure/Helper.cs | 28 +++++++++++++------ Flow.Launcher.Infrastructure/Logger/Log.cs | 2 +- .../Storage/JsonStorage.cs | 16 +++++------ .../UserSettings/Settings.cs | 16 ++++++----- Flow.Launcher.Plugin/PluginMetadata.cs | 3 +- Flow.Launcher/Storage/QueryHistory.cs | 1 - Flow.Launcher/Storage/TopMostRecord.cs | 3 +- Flow.Launcher/Storage/UserSelectedRecord.cs | 2 -- .../Search/FolderLinks/FolderLink.cs | 8 +++--- .../Flow.Launcher.Plugin.Explorer/Settings.cs | 8 +----- .../SearchSource.cs | 2 +- .../Settings.cs | 2 +- .../SuggestionSources/Baidu.cs | 20 +++++-------- .../SuggestionSources/Google.cs | 22 ++++++--------- 17 files changed, 67 insertions(+), 77 deletions(-) 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/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/Updater.cs b/Flow.Launcher.Core/Updater.cs index 1e4b0453c..e1aa42730 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -13,7 +13,6 @@ 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; diff --git a/Flow.Launcher.Infrastructure/Helper.cs b/Flow.Launcher.Infrastructure/Helper.cs index fa7e18533..331b3a823 100644 --- a/Flow.Launcher.Infrastructure/Helper.cs +++ b/Flow.Launcher.Infrastructure/Helper.cs @@ -1,12 +1,19 @@ -using System; +using Newtonsoft.Json.Converters; +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 +72,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/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/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 784c11110..268dc20b8 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 @@ -11,7 +11,7 @@ namespace Flow.Launcher.Infrastructure.Storage ///
public class JsonStrorage { - 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 = JsonSerializer.Deserialize("{}", _serializerSettings); 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/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 832b6fbfa..bcfe298a9 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; + + + // Order defaults to 0 or -1, so 1 will let this property appear last + public PluginsSettings PluginSettings { get; set; } = new PluginsSettings(); } public enum LastQueryMode diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index d81b442e2..4c40be53c 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; 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..09e69f6d8 100644 --- a/Flow.Launcher/Storage/TopMostRecord.cs +++ b/Flow.Launcher/Storage/TopMostRecord.cs @@ -1,6 +1,6 @@ using System.Collections.Generic; using System.Linq; -using Newtonsoft.Json; +using System.Text.Json; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage @@ -8,7 +8,6 @@ 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(); internal bool IsTopMost(Result result) diff --git a/Flow.Launcher/Storage/UserSelectedRecord.cs b/Flow.Launcher/Storage/UserSelectedRecord.cs index 1fda04e9b..c7ffe1a1d 100644 --- a/Flow.Launcher/Storage/UserSelectedRecord.cs +++ b/Flow.Launcher/Storage/UserSelectedRecord.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using Newtonsoft.Json; using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Plugin; @@ -7,7 +6,6 @@ namespace Flow.Launcher.Storage { public class UserSelectedRecord { - [JsonProperty] private Dictionary records = new Dictionary(); public void Add(Result result) 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/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.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..e8881aae9 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 diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index 6772acf82..2e385510f 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -2,10 +2,9 @@ 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; @@ -35,25 +34,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/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 5b9538091..ff0906b87 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -3,11 +3,10 @@ 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.Text.Json; namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { @@ -27,25 +26,20 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources return new List(); } if (string.IsNullOrEmpty(result)) return new List(); - JContainer json; + JsonDocument json; try { - json = JsonConvert.DeserializeObject(result) as JContainer; + json = JsonDocument.Parse(result); } - 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() From 557842e8d797c3ca0146ed77d0a45906f5c6f3d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 30 Dec 2020 13:48:06 +0800 Subject: [PATCH 164/267] remove dependency --- Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj | 1 - Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 1 - 2 files changed, 2 deletions(-) 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.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 70013c274..b7b52ac35 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -62,7 +62,6 @@ -
\ No newline at end of file From 7bbd8c6069ef038186482b50d731cec90396b987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 30 Dec 2020 19:05:02 +0800 Subject: [PATCH 165/267] remove using from Helper.cs --- Flow.Launcher.Infrastructure/Helper.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Helper.cs b/Flow.Launcher.Infrastructure/Helper.cs index 331b3a823..faa4c93b5 100644 --- a/Flow.Launcher.Infrastructure/Helper.cs +++ b/Flow.Launcher.Infrastructure/Helper.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json.Converters; -using System; +using System; using System.IO; using System.Runtime.CompilerServices; using System.Text.Json; From a0c4cc35756c42d7351bee37c795e063fd933dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 30 Dec 2020 19:09:52 +0800 Subject: [PATCH 166/267] use ParseAsync in Google --- .../SuggestionSources/Google.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index ff0906b87..f23cb66ff 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -7,6 +7,7 @@ using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; using System.Net.Http; using System.Text.Json; +using System.IO; namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { @@ -14,22 +15,22 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public override async Task> Suggestions(string query) { - string result; + Stream resultStream; try { const string api = "https://www.google.com/complete/search?output=chrome&q="; - result = await Http.GetAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); + resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); } catch (HttpRequestException e) { Log.Exception("|Google.Suggestions|Can't get suggestion from google", e); return new List(); } - if (string.IsNullOrEmpty(result)) return new List(); + if (resultStream.Length == 0) return new List(); JsonDocument json; try { - json = JsonDocument.Parse(result); + json = await JsonDocument.ParseAsync(resultStream); } catch (JsonException e) { From a139a040ecc3bca388b77c7c4ba39de35eccd638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 30 Dec 2020 20:24:01 +0800 Subject: [PATCH 167/267] add bing search suggestion --- .../Settings.cs | 3 +- .../SuggestionSources/Bing.cs | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100644 Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs index 555ee4647..1a3d9e5e5 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs @@ -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/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs new file mode 100644 index 000000000..9c4746711 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -0,0 +1,62 @@ +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; + +namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources +{ + class Bing : SuggestionSource + { + public override async Task> Suggestions(string query) + { + Stream resultStream; + + try + { + const string api = "https://api.bing.com/qsonhs.aspx?q="; + resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); + } + catch (HttpRequestException e) + { + Log.Exception("|Bing.Suggestions|Can't get suggestion from Bing", e); + return new List(); + } + + if (resultStream.Length == 0) return new List(); + + JsonElement json; + try + { + json = (await JsonDocument.ParseAsync(resultStream)).RootElement.GetProperty("AS"); + } + 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"; + } + } +} From 5c17cb6e9b823482784f7ef0dda0df35f65eb932 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 31 Dec 2020 15:44:57 +1100 Subject: [PATCH 168/267] version bump WebSearch --- Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json index 329f1c41d..99fd2210a 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.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll", From 27a0b934c612b8d3a482722c53910b7487a973d7 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 1 Jan 2021 18:39:41 +1100 Subject: [PATCH 169/267] update maintenance badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02f488758..654877f3a 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

-![Maintenance](https://img.shields.io/maintenance/yes/2020) +![Maintenance](https://img.shields.io/maintenance/yes/2021) [![Build status](https://ci.appveyor.com/api/projects/status/32r7s2skrgm9ubva?svg=true&retina=true)](https://ci.appveyor.com/project/JohnTheGr8/flow-launcher/branch/dev) [![Github All Releases](https://img.shields.io/github/downloads/Flow-Launcher/Flow.Launcher/total.svg)](https://github.com/Flow-Launcher/Flow.Launcher/releases) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Flow-Launcher/Flow.Launcher)](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) From a65e17dba00830c32c746d7dea3b737fc518fa7a Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 1 Jan 2021 18:57:58 +1100 Subject: [PATCH 170/267] fix wrong error message --- Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml | 4 +++- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index 8d24c145c..eaea9783b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -1,4 +1,4 @@ - @@ -6,6 +6,8 @@ Downloading plugin Please wait... Successfully downloaded + Error downloading plugin + Error occured while trying to download the plugin {0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart. {0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart. Plugin Install diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index ac15618ca..a378a9046 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -134,8 +134,8 @@ namespace Flow.Launcher.Plugin.PluginsManager } 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_download_error_title"), + Context.API.GetTranslation("plugin_pluginsmanager_download_error_subtitle")); Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } From 54f6858937fdf3445e8503e7da398bafd0efa4b5 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 1 Jan 2021 19:03:06 +1100 Subject: [PATCH 171/267] add plugin name to error msg popup --- Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index eaea9783b..d0370ddc3 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -7,7 +7,7 @@ Please wait... Successfully downloaded Error downloading plugin - Error occured while trying to download the plugin + Error occured while trying to download {0} {0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart. {0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart. Plugin Install diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index a378a9046..9d9d50902 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -135,7 +135,7 @@ namespace Flow.Launcher.Plugin.PluginsManager catch (Exception e) { Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_download_error_title"), - Context.API.GetTranslation("plugin_pluginsmanager_download_error_subtitle")); + string.Format(Context.API.GetTranslation("plugin_pluginsmanager_download_error_subtitle"), plugin.Name)); Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload"); } From cab1b93183d4a8170f3b589354e1159b8e92cd7c Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 1 Jan 2021 19:13:14 +1100 Subject: [PATCH 172/267] move install method into try catch --- .../Languages/en.xaml | 4 ++-- .../PluginsManager.cs | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index d0370ddc3..3017f39c3 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -6,13 +6,13 @@ Downloading plugin Please wait... Successfully downloaded - Error downloading plugin - Error occured while trying to download {0} {0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart. {0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart. 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. diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 9d9d50902..db0327111 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -131,16 +131,17 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_download_success")); + + Install(plugin, filePath); } catch (Exception e) { - Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_download_error_title"), - string.Format(Context.API.GetTranslation("plugin_pluginsmanager_download_error_subtitle"), plugin.Name)); + 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"); } - Install(plugin, filePath); Context.API.RestartApp(); } From 878f7bf5dfb154a2bf663deaf9256ce73ba3de1d Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 1 Jan 2021 19:49:19 +1100 Subject: [PATCH 173/267] version bump for PluginsManager --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index d94af71a1..7e78d65d6 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.3.1", + "Version": "1.3.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From 81cb20bf91edb292eb35445861a25acec31a2445 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Fri, 1 Jan 2021 21:54:34 +1100 Subject: [PATCH 174/267] add return to continue --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index db0327111..880157a77 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -140,6 +140,8 @@ namespace Flow.Launcher.Plugin.PluginsManager string.Format(Context.API.GetTranslation("plugin_pluginsmanager_install_error_subtitle"), plugin.Name)); Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "InstallOrUpdate"); + + return; } Context.API.RestartApp(); From 6d66aa3f4415f114f44bb6b962651f5d269783f6 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 00:06:55 +1100 Subject: [PATCH 175/267] fix script to delete with condition dll version is same --- Scripts/post_build.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index 59036842a..b20393b02 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -44,8 +44,9 @@ 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} + $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 } From 29a382085fde4f5ac5ea173b5ccf338258d0c029 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 00:09:02 +1100 Subject: [PATCH 176/267] method name update --- Scripts/post_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index b20393b02..e0868f3bb 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -45,7 +45,7 @@ function Delete-Unused ($path, $config) { $included = Get-ChildItem $target -Filter "*.dll" foreach ($i in $included){ $deleteList = Get-ChildItem $target\Plugins -Include $i -Recurse | Where {$_.VersionInfo.FileVersion -eq $i.VersionInfo.FileVersion} - $deleteList | foreach-object{ Write-Host Deleting duplicated $_.Name with version $_.VersionInfo.FileVersion at location $_.Directory.FullName } + $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 From f1badd6ae20466ab720b516d544a4b5f58b64dff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Fri, 1 Jan 2021 21:19:05 +0800 Subject: [PATCH 177/267] Add Exception Handling for Querying plugins results --- Flow.Launcher/ViewModel/MainViewModel.cs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 7a3aa9f2f..2a69635bb 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 { @@ -414,8 +415,15 @@ namespace Flow.Launcher.ViewModel { if (!plugin.Metadata.Disabled) { - var results = PluginManager.QueryForPlugin(plugin, query); - UpdateResultView(results, plugin.Metadata, query); + try + { + var results = PluginManager.QueryForPlugin(plugin, query); + UpdateResultView(results, plugin.Metadata, query); + } + catch(Exception e) + { + Log.Exception($"|MainViewModel|Exception when querying {plugin.Metadata.Name}", e); + } } }); } @@ -432,7 +440,10 @@ namespace Flow.Launcher.ViewModel { // update to hidden if this is still the current query ProgressBarVisibility = Visibility.Hidden; } - }, currentCancellationToken); + }, currentCancellationToken).ContinueWith(t => + { + Log.Exception("|MainViewModel|Error when querying plugin", t.Exception?.InnerException); + }, TaskContinuationOptions.OnlyOnFaulted); } } else From f3355c525dfbdaa46ece70cb5197826c1bf354e9 Mon Sep 17 00:00:00 2001 From: Ioannis G Date: Fri, 1 Jan 2021 23:15:37 +0200 Subject: [PATCH 178/267] fix: properly include all plugin translation files --- ...low.Launcher.Plugin.BrowserBookmark.csproj | 9 +--- .../Flow.Launcher.Plugin.Calculator.csproj | 44 +----------------- .../Flow.Launcher.Plugin.ControlPanel.csproj | 45 +------------------ .../Flow.Launcher.Plugin.Explorer.csproj | 32 +------------ ...low.Launcher.Plugin.PluginIndicator.csproj | 42 +---------------- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +- .../Flow.Launcher.Plugin.Program.csproj | 27 +---------- .../Flow.Launcher.Plugin.Shell.csproj | 39 ++-------------- .../Flow.Launcher.Plugin.Sys.csproj | 27 +---------- .../Flow.Launcher.Plugin.Url.csproj | 36 +-------------- .../Flow.Launcher.Plugin.WebSearch.csproj | 27 +---------- 11 files changed, 17 insertions(+), 313 deletions(-) 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..f308aa49a 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -43,11 +43,6 @@ Always - - Designer - MSBuild:Compile - PreserveNewest - Always @@ -60,9 +55,9 @@ - + - + MSBuild:Compile Designer PreserveNewest 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..983ac160e 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -49,49 +49,9 @@ 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/Flow.Launcher.Plugin.ControlPanel.csproj b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj index 699737634..dce54cb52 100644 --- a/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj +++ b/Plugins/Flow.Launcher.Plugin.ControlPanel/Flow.Launcher.Plugin.ControlPanel.csproj @@ -48,50 +48,7 @@ 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/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj index a1a08843a..a9f675be8 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -62,37 +62,7 @@ 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/Flow.Launcher.Plugin.PluginIndicator.csproj b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj index e6bfa7aa3..6abfc8469 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj @@ -52,47 +52,7 @@ - - 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.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj index cf9c96294..a393d8510 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -39,7 +39,7 @@ PreserveNewest - + Designer MSBuild:Compile PreserveNewest 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 3802297c7..7e1b36fc1 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -68,35 +68,10 @@ 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.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index 178d95010..316742bf6 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,18 +46,13 @@ + + Always + PreserveNewest - - - - - MSBuild:Compile - Designer - PreserveNewest - - + MSBuild:Compile Designer PreserveNewest 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..61635dd08 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -52,32 +52,7 @@ 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.Url/Flow.Launcher.Plugin.Url.csproj b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj index 7d802d815..fb40c1e17 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj +++ b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj @@ -50,41 +50,9 @@ 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.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj index 431ca9ce8..e3bb4b408 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj @@ -89,32 +89,7 @@ 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 From 8ab528c380acd0515b6576e74f76300763bd3bd6 Mon Sep 17 00:00:00 2001 From: Ioannis G Date: Sat, 2 Jan 2021 00:00:12 +0200 Subject: [PATCH 179/267] fix slovak translation --- Flow.Launcher/Languages/sk.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 From 75f5a81a31ead865464f6a11f61f4c8fcf8d7cb6 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 11:55:06 +1100 Subject: [PATCH 180/267] update exception message --- Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 2a69635bb..eed30f377 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -422,7 +422,7 @@ namespace Flow.Launcher.ViewModel } catch(Exception e) { - Log.Exception($"|MainViewModel|Exception when querying {plugin.Metadata.Name}", e); + Log.Exception("MainViewModel", $"Exception when querying the plugin {plugin.Metadata.Name}", e, "QueryResults"); } } }); @@ -442,7 +442,7 @@ namespace Flow.Launcher.ViewModel } }, currentCancellationToken).ContinueWith(t => { - Log.Exception("|MainViewModel|Error when querying plugin", t.Exception?.InnerException); + Log.Exception("MainViewModel", "Error when querying plugins", t.Exception?.InnerException, "QueryResults"); }, TaskContinuationOptions.OnlyOnFaulted); } } From 041bf4e9c4860b9114a95741fcb036d2f969d208 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 12:10:06 +1100 Subject: [PATCH 181/267] add condition to match name also --- Scripts/post_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index e0868f3bb..836e27380 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -44,7 +44,7 @@ function Delete-Unused ($path, $config) { $target = "$path\Output\$config" $included = Get-ChildItem $target -Filter "*.dll" foreach ($i in $included){ - $deleteList = Get-ChildItem $target\Plugins -Include $i -Recurse | Where {$_.VersionInfo.FileVersion -eq $i.VersionInfo.FileVersion} + $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 } From be1776fd2153f6bc9fbefbce71b313ea9ab9789e Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 12:47:20 +1100 Subject: [PATCH 182/267] version bump for plugins --- Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Calculator/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.ControlPanel/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Explorer/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json | 2 +- .../Flow.Launcher.Plugin.PluginsManager.csproj | 2 +- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Program/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Shell/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Sys/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.Url/plugin.json | 2 +- Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) 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/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.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/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/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/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj index cc1a931ce..7beb8308b 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -35,7 +35,7 @@ - + PreserveNewest diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index d94af71a1..7e78d65d6 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.3.1", + "Version": "1.3.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", 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/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/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/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/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/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json index 99fd2210a..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.2.0", + "Version": "1.2.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll", From 08f97f0ef9236e4572d7a707741488cddb568d38 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 12:57:13 +1100 Subject: [PATCH 183/267] change csproj images folder to use wildcard --- ...low.Launcher.Plugin.BrowserBookmark.csproj | 6 +- .../Flow.Launcher.Plugin.Calculator.csproj | 9 +-- .../Flow.Launcher.Plugin.ControlPanel.csproj | 4 +- .../Flow.Launcher.Plugin.Explorer.csproj | 35 +---------- ...low.Launcher.Plugin.PluginIndicator.csproj | 9 +-- ...Flow.Launcher.Plugin.PluginsManager.csproj | 9 +-- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 6 +- .../Flow.Launcher.Plugin.Program.csproj | 21 +------ .../Flow.Launcher.Plugin.Shell.csproj | 9 +-- .../Flow.Launcher.Plugin.Sys.csproj | 50 +-------------- .../Flow.Launcher.Plugin.Url.csproj | 9 +-- .../Flow.Launcher.Plugin.WebSearch.csproj | 63 +------------------ 12 files changed, 33 insertions(+), 197 deletions(-) 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 f308aa49a..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,9 +40,6 @@ - - Always - Always @@ -62,6 +59,9 @@ Designer PreserveNewest + + PreserveNewest + 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 983ac160e..06d8dea7d 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -43,12 +43,6 @@ - - - - PreserveNewest - - @@ -56,6 +50,9 @@ Designer PreserveNewest + + PreserveNewest + 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 dce54cb52..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,9 +45,9 @@ - + PreserveNewest - + MSBuild:Compile Designer 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 a9f675be8..9d9c09a93 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -26,42 +26,9 @@ - - PreserveNewest - - - - PreserveNewest - - - - PreserveNewest - - - - PreserveNewest - - - - Always - - - + PreserveNewest - - - PreserveNewest - - - - PreserveNewest - - - - PreserveNewest - - MSBuild:Compile Designer 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 6abfc8469..0140444e1 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj @@ -45,18 +45,15 @@ - - - PreserveNewest - - - MSBuild:Compile Designer PreserveNewest + + PreserveNewest +
\ No newline at end of file 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 7beb8308b..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,17 +27,14 @@ PreserveNewest - - - - PreserveNewest - - PreserveNewest + + PreserveNewest + 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 a393d8510..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.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index 7e1b36fc1..12e113855 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -52,30 +52,15 @@ - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - Always - - - MSBuild:Compile Designer PreserveNewest + + PreserveNewest + 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 316742bf6..c542dc89b 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -46,17 +46,14 @@ - - Always - - - PreserveNewest - MSBuild:Compile Designer PreserveNewest + + PreserveNewest + MSBuild:Compile Designer 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 61635dd08..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,23 +40,14 @@ - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - MSBuild:Compile Designer PreserveNewest + + PreserveNewest + MSBuild:Compile Designer @@ -68,39 +59,4 @@ PreserveNewest - - - - PreserveNewest - - - - - - PreserveNewest - - - - - - PreserveNewest - - - - - - PreserveNewest - - - - - - PreserveNewest - - - - - - -
\ No newline at end of file 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 fb40c1e17..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,12 +44,6 @@ - - - - PreserveNewest - - @@ -57,6 +51,9 @@ Designer PreserveNewest + + PreserveNewest +
\ No newline at end of file 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 e3bb4b408..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,65 +35,14 @@
- - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - MSBuild:Compile Designer PreserveNewest + + PreserveNewest + MSBuild:Compile Designer @@ -109,12 +58,6 @@ PreserveNewest - - - - PreserveNewest - - From 482988c288392af9b1bf2a911a6eb798c54f11ff Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 12:59:58 +1100 Subject: [PATCH 184/267] use wild card to include images for main project --- Flow.Launcher/Flow.Launcher.csproj | 108 +---------------------------- 1 file changed, 3 insertions(+), 105 deletions(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 8548ba39e..39b2087aa 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -60,6 +60,9 @@ Designer PreserveNewest + + PreserveNewest + @@ -87,111 +90,6 @@ - - - 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 - - - From 97ac42751717121f5db1c695b81d5aed98df191f Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 16:58:23 +1100 Subject: [PATCH 185/267] add manual reload of PluginsManifest data --- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index d700b9dfd..7c1eda3aa 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -10,7 +10,7 @@ using System.Threading.Tasks; namespace Flow.Launcher.Plugin.PluginsManager { - public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n + public class Main : ISettingProvider, IPlugin, ISavable, IContextMenu, IPluginI18n, IReloadable { internal PluginInitContext Context { get; set; } @@ -87,5 +87,14 @@ namespace Flow.Launcher.Plugin.PluginsManager { return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description"); } + + public void ReloadData() + { + Task.Run(async () => + { + await pluginManager.UpdateManifest(); + lastUpdateTime = DateTime.Now; + }); + } } } From 661c64b1c21b5e744ac4029b68e70d095a2074e2 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 17:00:10 +1100 Subject: [PATCH 186/267] version bump for PluginsManager --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 7e78d65d6..f5bbf3f6b 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.3.2", + "Version": "1.4.0", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From b4b30dd34da9426a6f512966fca780c5d5ef1437 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 2 Jan 2021 18:06:44 +1100 Subject: [PATCH 187/267] wait manifest update before proceeding --- Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index 7c1eda3aa..f10f022d7 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -90,11 +90,8 @@ namespace Flow.Launcher.Plugin.PluginsManager public void ReloadData() { - Task.Run(async () => - { - await pluginManager.UpdateManifest(); - lastUpdateTime = DateTime.Now; - }); + Task.Run(() => pluginManager.UpdateManifest()).Wait(); + lastUpdateTime = DateTime.Now; } } } From 3cd609377e7402669c8dbbf67140bb58551d8ae9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 2 Jan 2021 15:52:41 +0800 Subject: [PATCH 188/267] Plugin Async ModelAdd Full Async model, including AsyncPlugin and AsyncReloadable --- Flow.Launcher.Core/Plugin/PluginManager.cs | 150 ++++++++++++------ Flow.Launcher.Infrastructure/Stopwatch.cs | 32 +++- Flow.Launcher.Plugin/IAsyncPlugin.cs | 12 ++ Flow.Launcher.Plugin/IPlugin.cs | 1 + Flow.Launcher.Plugin/IPublicAPI.cs | 3 +- .../Interfaces/IAsyncReloadable.cs | 9 ++ Flow.Launcher.Plugin/PluginPair.cs | 2 +- Flow.Launcher/PublicAPIInstance.cs | 4 +- Flow.Launcher/ViewModel/MainViewModel.cs | 38 ++--- .../ControlPanelList.cs | 2 +- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 41 +++-- 11 files changed, 210 insertions(+), 84 deletions(-) create mode 100644 Flow.Launcher.Plugin/IAsyncPlugin.cs create mode 100644 Flow.Launcher.Plugin/Interfaces/IAsyncReloadable.cs diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 3b697a1ee..239f0499d 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; @@ -32,7 +33,7 @@ namespace Flow.Launcher.Core.Plugin /// /// Directories that will hold Flow Launcher plugin directory /// - private static readonly string[] Directories = { Constant.PreinstalledDirectory, DataLocation.PluginsDirectory }; + private static readonly string[] Directories = {Constant.PreinstalledDirectory, DataLocation.PluginsDirectory}; private static void DeletePythonBinding() { @@ -52,12 +53,19 @@ namespace Flow.Launcher.Core.Plugin } } - public static void ReloadData() + public static async Task ReloadData() { foreach(var plugin in AllPlugins) { - var reloadablePlugin = plugin.Plugin as IReloadable; - reloadablePlugin?.ReloadData(); + switch (plugin.Plugin) + { + case IReloadable p: + p.ReloadData(); + break; + case IAsyncReloadable p: + await p.ReloadDataAsync(); + break; + } } } @@ -86,24 +94,50 @@ 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}>", () => + long milliseconds; + + switch (pair.Plugin) { - pair.Plugin.Init(new PluginInitContext - { - CurrentPluginMetadata = pair.Metadata, - API = API - }); - }); + case IAsyncPlugin plugin: + milliseconds = await Stopwatch.DebugAsync( + $"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", + async delegate + { + await plugin.InitAsync(new PluginInitContext + { + CurrentPluginMetadata = pair.Metadata, + API = API + }); + }); + break; + case IPlugin plugin: + milliseconds = Stopwatch.Debug( + $"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>", + () => + { + plugin.Init(new PluginInitContext + { + CurrentPluginMetadata = pair.Metadata, + API = API + }); + }); + break; + default: + 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) { @@ -111,25 +145,33 @@ namespace Flow.Launcher.Core.Plugin 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); } } @@ -138,7 +180,7 @@ namespace Flow.Launcher.Core.Plugin if (NonGlobalPlugins.ContainsKey(query.ActionKeyword)) { var plugin = NonGlobalPlugins[query.ActionKeyword]; - return new List { plugin }; + return new List {plugin}; } else { @@ -146,25 +188,42 @@ 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}", () => - { - results = pair.Plugin.Query(query) ?? new List(); - UpdatePluginMetadata(results, metadata, query); - }); + var milliseconds = await Stopwatch.DebugAsync($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}", + async () => + { + switch (pair.Plugin) + { + case IAsyncPlugin plugin: + results = await plugin.QueryAsync(query, token).ConfigureAwait(false) ?? + new List(); + UpdatePluginMetadata(results, metadata, query); + break; + case IPlugin plugin: + results = await Task.Run(() => plugin.Query(query), token).ConfigureAwait(false) ?? + new List(); + UpdatePluginMetadata(results, metadata, query); + break; + } + }); metadata.QueryCount += 1; - metadata.AvgQueryTime = metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2; + metadata.AvgQueryTime = + metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2; } catch (Exception e) { - Log.Exception($"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", e); + Log.Exception( + $"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", + e); } - return results; + + // null will be fine since the results will only be added into queue if the token hasn't been cancelled + return token.IsCancellationRequested ? results = null : results; } public static void UpdatePluginMetadata(List results, PluginMetadata metadata, Query query) @@ -182,11 +241,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 /// @@ -208,7 +262,7 @@ namespace Flow.Launcher.Core.Plugin var pluginPair = _contextMenuPlugins.FirstOrDefault(o => o.Metadata.ID == result.PluginID); if (pluginPair != null) { - var plugin = (IContextMenu)pluginPair.Plugin; + var plugin = (IContextMenu) pluginPair.Plugin; try { @@ -222,16 +276,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 +306,7 @@ namespace Flow.Launcher.Core.Plugin { NonGlobalPlugins[newActionKeyword] = plugin; } + plugin.Metadata.ActionKeywords.Add(newActionKeyword); } @@ -262,9 +320,9 @@ 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); } @@ -285,4 +343,4 @@ namespace Flow.Launcher.Core.Plugin } } } -} +} \ No newline at end of file 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.Plugin/IAsyncPlugin.cs b/Flow.Launcher.Plugin/IAsyncPlugin.cs new file mode 100644 index 000000000..36f098e7d --- /dev/null +++ b/Flow.Launcher.Plugin/IAsyncPlugin.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace Flow.Launcher.Plugin +{ + public interface IAsyncPlugin + { + Task> QueryAsync(Query query, CancellationToken token); + Task InitAsync(PluginInitContext context); + } +} \ No newline at end of file diff --git a/Flow.Launcher.Plugin/IPlugin.cs b/Flow.Launcher.Plugin/IPlugin.cs index 8f7d279fa..4cc6d8d40 100644 --- a/Flow.Launcher.Plugin/IPlugin.cs +++ b/Flow.Launcher.Plugin/IPlugin.cs @@ -5,6 +5,7 @@ namespace Flow.Launcher.Plugin public interface IPlugin { List Query(Query query); + 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..9c922f667 --- /dev/null +++ b/Flow.Launcher.Plugin/Interfaces/IAsyncReloadable.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; + +namespace Flow.Launcher.Plugin +{ + public interface IAsyncReloadable + { + Task ReloadDataAsync(); + } +} \ No newline at end of file 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/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 90d4fff63..bcf147be7 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -78,9 +78,9 @@ namespace Flow.Launcher ImageLoader.Save(); } - public void ReloadAllPluginData() + public async Task ReloadAllPluginData() { - PluginManager.ReloadData(); + await PluginManager.ReloadData(); } public void ShowMsg(string title, string subTitle = "", string iconPath = "") diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index eed30f377..bc68eb6d6 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -405,45 +405,47 @@ namespace Flow.Launcher.ViewModel }, currentCancellationToken); var plugins = PluginManager.ValidPluginsForQuery(query); - Task.Run(() => + Task.Run(async () => { // so looping will stop once it was cancelled + + Task[] tasks = new Task[plugins.Count]; var parallelOptions = new ParallelOptions { CancellationToken = currentCancellationToken }; try { - Parallel.ForEach(plugins, parallelOptions, plugin => + Parallel.For(0, plugins.Count, parallelOptions, i => { - if (!plugin.Metadata.Disabled) + if (!plugins[i].Metadata.Disabled) { - try - { - var results = PluginManager.QueryForPlugin(plugin, query); - UpdateResultView(results, plugin.Metadata, query); - } - catch(Exception e) - { - Log.Exception("MainViewModel", $"Exception when querying the plugin {plugin.Metadata.Name}", e, "QueryResults"); - } + tasks[i] = QueryTask(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) + if (!currentCancellationToken.IsCancellationRequested) { // update to hidden if this is still the current query ProgressBarVisibility = Visibility.Hidden; } - }, currentCancellationToken).ContinueWith(t => - { - Log.Exception("MainViewModel", "Error when querying plugins", t.Exception?.InnerException, "QueryResults"); - }, TaskContinuationOptions.OnlyOnFaulted); + + async Task QueryTask(int pairIndex, Query query, CancellationToken token) + { + var result = await PluginManager.QueryForPlugin(plugins[pairIndex], query, token); + UpdateResultView(result, plugins[pairIndex].Metadata, query); + } + + }, currentCancellationToken).ContinueWith(t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception), + TaskContinuationOptions.OnlyOnFaulted); } } else 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.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 5642b62ed..7ebab91a1 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; } }, @@ -163,14 +170,16 @@ namespace Flow.Launcher.Plugin.Sys // http://www.pinvoke.net/default.aspx/shell32/SHEmptyRecycleBin.html // 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) + var result = SHEmptyRecycleBin(new WindowInteropHelper(Application.Current.MainWindow).Handle, + 0); + 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 +238,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; } }, From b8f7d899709ee4204d2a0f1cfae8722a2b80cdbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 2 Jan 2021 17:25:13 +0800 Subject: [PATCH 189/267] Allows Loading both IPlugin and IAsyncPlugin --- .../Plugin/PluginAssemblyLoader.cs | 10 +- Flow.Launcher.Core/Plugin/PluginsLoader.cs | 100 +++++++++--------- Flow.Launcher/ViewModel/MainViewModel.cs | 9 +- 3 files changed, 61 insertions(+), 58 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs index b9b878a7b..1a1b17539 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) @@ -54,4 +54,4 @@ namespace Flow.Launcher.Core.Plugin return referencedPluginPackageDependencyResolver.ResolveAssemblyToPath(assemblyName) != null; } } -} +} \ No newline at end of file diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs index 224dbd85e..8295761b5 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; + IPlugin 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/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index bc68eb6d6..3e1a4b516 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -417,7 +417,7 @@ namespace Flow.Launcher.ViewModel { if (!plugins[i].Metadata.Disabled) { - tasks[i] = QueryTask(i, query, currentCancellationToken); + tasks[i] = QueryTask(plugins[i], query, currentCancellationToken); } else tasks[i] = Task.CompletedTask; // Avoid Null }); @@ -438,10 +438,11 @@ namespace Flow.Launcher.ViewModel ProgressBarVisibility = Visibility.Hidden; } - async Task QueryTask(int pairIndex, Query query, CancellationToken token) + // Local Function + async Task QueryTask(PluginPair plugin, Query query, CancellationToken token) { - var result = await PluginManager.QueryForPlugin(plugins[pairIndex], query, token); - UpdateResultView(result, plugins[pairIndex].Metadata, query); + var results = await PluginManager.QueryForPlugin(plugin, query, token); + UpdateResultView(results, plugin.Metadata, query); } }, currentCancellationToken).ContinueWith(t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception), From f768b0890b8f784983da9cc2ae5a5f2b464a41ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 2 Jan 2021 17:58:30 +0800 Subject: [PATCH 190/267] Move Program Plugin to Async model --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 164 ++++++++++--------- 1 file changed, 88 insertions(+), 76 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 8f124f3a4..0d693d363 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,17 +30,58 @@ namespace Flow.Launcher.Plugin.Program public Main() { _settingsStorage = new PluginJsonStorage(); - _settings = _settingsStorage.Load(); + } - Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () => + public void Save() + { + _settingsStorage.Save(); + _win32Storage.Save(_win32s); + _uwpStorage.Save(_uwps); + } + + public async Task> QueryAsync(Query query, CancellationToken token) + { + Win32[] win32; + UWP.Application[] uwps; + + win32 = _win32s; + uwps = _uwps; + + + var result = await Task.Run(delegate { - _win32Storage = new BinaryStorage("Win32"); - _win32s = _win32Storage.TryLoad(new Win32[] { }); - _uwpStorage = new BinaryStorage("UWP"); - _uwps = _uwpStorage.TryLoad(new UWP.Application[] { }); + 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(); + }, token).ConfigureAwait(false); + + return result; + } + + 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}>"); }); - 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(() => { @@ -51,54 +92,22 @@ namespace Flow.Launcher.Plugin.Program var b = Task.Run(() => { if (IsStartupIndexProgramsRequired || !_uwps.Any()) - Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUWPPrograms); + Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms); }); - Task.WaitAll(a, b); + await Task.WhenAll(a, b); _settings.LastIndexTime = DateTime.Today; } - public void Save() - { - _settingsStorage.Save(); - _win32Storage.Save(_win32s); - _uwpStorage.Save(_uwps); - } - - public List Query(Query query) - { - Win32[] win32; - UWP.Application[] uwps; - - 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(); - - return result; - } - - public void Init(PluginInitContext context) - { - _context = context; - } - public static void IndexWin32Programs() { 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 +115,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 +153,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 +178,23 @@ 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 +212,9 @@ namespace Flow.Launcher.Plugin.Program } } - public void ReloadData() + public async Task ReloadDataAsync() { - IndexPrograms(); + await IndexPrograms(); } } } \ No newline at end of file From 6326d6f3d57e8a5ef6065c210f8d6db7d932ca18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 20:22:07 +0800 Subject: [PATCH 191/267] Startup async --- Flow.Launcher/App.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 59bdbc896..7417a6f2a 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 OnStartup(object sender, StartupEventArgs e) { - Stopwatch.Normal("|App.OnStartup|Startup cost", () => + await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { _portable.PreStartCleanUpAfterPortabilityUpdate(); @@ -70,7 +70,7 @@ namespace Flow.Launcher _mainVM = new MainViewModel(_settings); var window = new MainWindow(_settings, _mainVM); API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet); - PluginManager.InitializePlugins(API); + await PluginManager.InitializePlugins(API); Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}"); Current.MainWindow = window; From 7be2a956dd31aa6d48a263926ea2e70f0a4e437b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 21:20:21 +0800 Subject: [PATCH 192/267] Use cancallationToken.IsCancellationRequested instead of comparing current token with global token --- Flow.Launcher/ViewModel/MainViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 3e1a4b516..f9c152046 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -442,7 +442,8 @@ namespace Flow.Launcher.ViewModel async Task QueryTask(PluginPair plugin, Query query, CancellationToken token) { var results = await PluginManager.QueryForPlugin(plugin, query, token); - UpdateResultView(results, plugin.Metadata, query); + if (!currentCancellationToken.IsCancellationRequested) + UpdateResultView(results, plugin.Metadata, query); } }, currentCancellationToken).ContinueWith(t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception), From 280b98b47a1fbdb5cb8a493339123d9586b54ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 21:23:34 +0800 Subject: [PATCH 193/267] Move the creation of Window later due to async operation --- Flow.Launcher/App.xaml.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 7417a6f2a..0145dfa34 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -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); await PluginManager.InitializePlugins(API); + var window = new MainWindow(_settings, _mainVM); + Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}"); Current.MainWindow = window; From 4cb4aa88ef52dcab60c662a312f8b2e953b40ffc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 22:00:43 +0800 Subject: [PATCH 194/267] change onstartup name to async --- Flow.Launcher/App.xaml | 2 +- Flow.Launcher/App.xaml.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 0145dfa34..06bb16e3b 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -45,7 +45,7 @@ namespace Flow.Launcher } } - private async void OnStartup(object sender, StartupEventArgs e) + private async void OnStartupAsync(object sender, StartupEventArgs e) { await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => { From d7805d7a8cbc7eedcee7cc7a62156397f1af5172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 22:01:15 +0800 Subject: [PATCH 195/267] Make Explorer plugin completely async --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 4 +- Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 14 ++- .../DirectoryInfo/DirectoryInfoSearch.cs | 6 +- .../Search/SearchManager.cs | 54 ++++++----- .../Search/WindowsIndex/IndexSearch.cs | 90 +++++++++---------- .../ViewModels/SettingsViewModel.cs | 6 ++ 6 files changed, 96 insertions(+), 78 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index c91144825..756ceb2d6 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -151,7 +151,7 @@ namespace Flow.Launcher.Test.Plugins var searchManager = new SearchManager(new Settings(), new PluginInitContext()); // When - var results = searchManager.TopLevelDirectorySearchBehaviour( + var results = searchManager.TopLevelDirectorySearchBehaviourAsync( MethodWindowsIndexSearchReturnsZeroResults, MethodDirectoryInfoClassSearchReturnsTwoResults, false, @@ -171,7 +171,7 @@ namespace Flow.Launcher.Test.Plugins var searchManager = new SearchManager(new Settings(), new PluginInitContext()); // When - var results = searchManager.TopLevelDirectorySearchBehaviour( + var results = searchManager.TopLevelDirectorySearchBehaviourAsync( MethodWindowsIndexSearchReturnsZeroResults, MethodDirectoryInfoClassSearchReturnsTwoResults, true, 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..3253b7a7b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Windows; namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo { @@ -22,7 +23,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 +58,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/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/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(); From 43cee65c4518b01ca49ba9a267446a390d41501e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 22:21:45 +0800 Subject: [PATCH 196/267] Move PluginManagers to Async Model --- .../Main.cs | 19 +++++++++---------- .../Models/PluginsManifest.cs | 7 +------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs index f10f022d7..40579e6e5 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs @@ -7,10 +7,11 @@ 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, IReloadable + public class Main : ISettingProvider, IAsyncPlugin, ISavable, IContextMenu, IPluginI18n, IAsyncReloadable { internal PluginInitContext Context { get; set; } @@ -29,13 +30,14 @@ namespace Flow.Launcher.Plugin.PluginsManager 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); pluginManager = new PluginsManager(Context, Settings); + await pluginManager.UpdateManifest(); lastUpdateTime = DateTime.Now; } @@ -44,7 +46,7 @@ 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(); @@ -53,11 +55,8 @@ namespace Flow.Launcher.Plugin.PluginsManager if ((DateTime.Now - lastUpdateTime).TotalHours > 12) // 12 hours { - Task.Run(async () => - { - await pluginManager.UpdateManifest(); - lastUpdateTime = DateTime.Now; - }); + await pluginManager.UpdateManifest(); + lastUpdateTime = DateTime.Now; } return search switch @@ -88,9 +87,9 @@ namespace Flow.Launcher.Plugin.PluginsManager return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description"); } - public void ReloadData() + public async Task ReloadDataAsync() { - Task.Run(() => pluginManager.UpdateManifest()).Wait(); + 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 814e0764d..145aadc98 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Models/PluginsManifest.cs @@ -9,12 +9,7 @@ namespace Flow.Launcher.Plugin.PluginsManager.Models { internal class PluginsManifest { - internal List UserPlugins { get; private set; } - - internal PluginsManifest() - { - Task.Run(async () => await DownloadManifest()).Wait(); - } + internal List UserPlugins { get; private set; } = new List(); internal async Task DownloadManifest() { From 69cb8e61479d477a9f0c05a5d7f40b386af6438d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sat, 2 Jan 2021 22:30:56 +0800 Subject: [PATCH 197/267] Reload IAsyncReloadable concurrently --- Flow.Launcher.Core/Plugin/PluginManager.cs | 33 ++++++++++++---------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 239f0499d..2e938127c 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -33,7 +33,7 @@ namespace Flow.Launcher.Core.Plugin /// /// Directories that will hold Flow Launcher plugin directory /// - private static readonly string[] Directories = {Constant.PreinstalledDirectory, DataLocation.PluginsDirectory}; + private static readonly string[] Directories = { Constant.PreinstalledDirectory, DataLocation.PluginsDirectory }; private static void DeletePythonBinding() { @@ -55,18 +55,21 @@ namespace Flow.Launcher.Core.Plugin public static async Task ReloadData() { - foreach(var plugin in AllPlugins) + await Task.WhenAll(AllPlugins.Select(plugin => { - switch (plugin.Plugin) { - case IReloadable p: - p.ReloadData(); - break; - case IAsyncReloadable p: - await p.ReloadDataAsync(); - break; + switch (plugin) + { + case IReloadable p: + p.ReloadData(); // Sync reload means low time consuming + return Task.CompletedTask; + case IAsyncReloadable p: + return p.ReloadDataAsync(); + default: + throw new ArgumentOutOfRangeException(); + } } - } + })); } static PluginManager() @@ -142,7 +145,7 @@ namespace Flow.Launcher.Core.Plugin 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); } })); @@ -180,7 +183,7 @@ namespace Flow.Launcher.Core.Plugin if (NonGlobalPlugins.ContainsKey(query.ActionKeyword)) { var plugin = NonGlobalPlugins[query.ActionKeyword]; - return new List {plugin}; + return new List { plugin }; } else { @@ -262,7 +265,7 @@ namespace Flow.Launcher.Core.Plugin var pluginPair = _contextMenuPlugins.FirstOrDefault(o => o.Metadata.ID == result.PluginID); if (pluginPair != null) { - var plugin = (IContextMenu) pluginPair.Plugin; + var plugin = (IContextMenu)pluginPair.Plugin; try { @@ -326,10 +329,10 @@ namespace Flow.Launcher.Core.Plugin { GlobalPlugins.Remove(plugin); } - + if (oldActionkeyword != Query.GlobalPluginWildcardSign) NonGlobalPlugins.Remove(oldActionkeyword); - + plugin.Metadata.ActionKeywords.Remove(oldActionkeyword); } From 6e9e51ec4d674867deb283dd721dd485978cd4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 10:19:05 +0800 Subject: [PATCH 198/267] Error handling for OperationCancelledException in Program plugin --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 39 ++++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 0d693d363..954c238a9 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -47,20 +47,35 @@ namespace Flow.Launcher.Plugin.Program win32 = _win32s; uwps = _uwps; - - 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(); - }, token).ConfigureAwait(false); + 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 async Task InitAsync(PluginInitContext context) From 1c200695982e1e0ad170febf0d04498690baea59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 10:19:33 +0800 Subject: [PATCH 199/267] Rebase to Dev --- Flow.Launcher.Core/Plugin/PluginManager.cs | 47 ++++++++++++---------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 2e938127c..b34995ba6 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -197,36 +197,41 @@ namespace Flow.Launcher.Core.Plugin try { var metadata = pair.Metadata; - var milliseconds = await Stopwatch.DebugAsync($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}", - async () => - { - switch (pair.Plugin) - { - case IAsyncPlugin plugin: - results = await plugin.QueryAsync(query, token).ConfigureAwait(false) ?? - new List(); - UpdatePluginMetadata(results, metadata, query); - break; - case IPlugin plugin: - results = await Task.Run(() => plugin.Query(query), token).ConfigureAwait(false) ?? - new List(); - UpdatePluginMetadata(results, metadata, query); - break; - } - }); + + long milliseconds = -1L; + + switch (pair.Plugin) + { + 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; + token.ThrowIfCancellationRequested(); + } + catch (Exception e) when (e is OperationCanceledException || e is TaskCanceledException) + { + return results = null; } catch (Exception e) { - Log.Exception( - $"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", - e); + Log.Exception($"|PluginManager.QueryForPlugin|Exception for plugin <{pair.Metadata.Name}> when query <{query}>", e); } // null will be fine since the results will only be added into queue if the token hasn't been cancelled - return token.IsCancellationRequested ? results = null : results; + return results; } public static void UpdatePluginMetadata(List results, PluginMetadata metadata, Query query) From 731c3cdcbc23e85b38b3b652d970328adc566675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 10:37:36 +0800 Subject: [PATCH 200/267] Use OperationCancelledException instead of catch Exception and check --- Flow.Launcher.Core/Plugin/PluginManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index b34995ba6..0712908bf 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -221,7 +221,7 @@ namespace Flow.Launcher.Core.Plugin metadata.QueryCount == 1 ? milliseconds : (metadata.AvgQueryTime + milliseconds) / 2; token.ThrowIfCancellationRequested(); } - catch (Exception e) when (e is OperationCanceledException || e is TaskCanceledException) + catch (OperationCanceledException) { return results = null; } From ecf2a7a1f7cd73b787a0aa66bb588e9994e98397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 10:43:05 +0800 Subject: [PATCH 201/267] change plugin type in pluginLoader for Release --- Flow.Launcher.Core/Plugin/PluginsLoader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs index 8295761b5..b18c07e3c 100644 --- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs @@ -49,7 +49,7 @@ namespace Flow.Launcher.Core.Plugin var plugin = Activator.CreateInstance(type); #else Assembly assembly = null; - IPlugin plugin = null; + object plugin = null; try { From 63e32f1097e6ce061bf431aa6e452f3e47ac19f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 10:52:59 +0800 Subject: [PATCH 202/267] fix testing --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 48 ++++++++++++---------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index 756ceb2d6..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.TopLevelDirectorySearchBehaviourAsync( - 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.TopLevelDirectorySearchBehaviourAsync( - 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) From d369108b0b17d05c300919d7f20e296c5322b731 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 20:40:18 +0800 Subject: [PATCH 203/267] Error handling for plugin update --- .../PluginsManager.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 880157a77..4debf5598 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -214,11 +214,19 @@ namespace Flow.Launcher.Plugin.PluginsManager Task.Run(async delegate { + Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), + Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); + await Http.Download(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 fail for {x.Name}", t.Exception.InnerException), + TaskContinuationOptions.OnlyOnFaulted); return true; } From 8fa1e2e33f4355766282ca6934e3a279b8a3b8be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Sun, 3 Jan 2021 20:49:14 +0800 Subject: [PATCH 204/267] add one more message --- .../Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 4debf5598..9cef704a6 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -225,8 +225,12 @@ namespace Flow.Launcher.Plugin.PluginsManager Install(x.PluginNewUserPlugin, downloadToFilePath); Context.API.RestartApp(); - }).ContinueWith(t => Log.Exception($"|PluginsManager|Update fail for {x.Name}", t.Exception.InnerException), - TaskContinuationOptions.OnlyOnFaulted); + }).ContinueWith(t => + { + Log.Exception($"|PluginsManager|Update fail for {x.Name}", t.Exception.InnerException); + 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; } From d35a3bb43d05cf19b1fd46ef3577376941b7ed44 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 4 Jan 2021 06:40:45 +1100 Subject: [PATCH 205/267] version bump for PluginsManager --- Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index f5bbf3f6b..ef2c1255a 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json @@ -6,7 +6,7 @@ "Name": "Plugins Manager", "Description": "Management of installing, uninstalling or updating Flow Launcher plugins", "Author": "Jeremy Wu", - "Version": "1.4.0", + "Version": "1.4.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", From 6287358275e01457fabf0e2482343836a80bb9dd Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 4 Jan 2021 06:41:05 +1100 Subject: [PATCH 206/267] update error message --- Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 9cef704a6..724ddf20d 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -227,7 +227,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.RestartApp(); }).ContinueWith(t => { - Log.Exception($"|PluginsManager|Update fail for {x.Name}", t.Exception.InnerException); + 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); From a8dc1599d746d88c8ce28ac551abb0e02bf6a90d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 4 Jan 2021 10:28:33 +0800 Subject: [PATCH 207/267] Add Http Error Handling --- Flow.Launcher.Infrastructure/Http/Http.cs | 44 +++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 8e2832690..b796d807c 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -91,7 +91,7 @@ namespace Flow.Launcher.Infrastructure.Http /// /// Asynchrously get the result as string from url. - /// When supposing the result is long and large, try using GetStreamAsync to avoid reading as string + /// When supposing the result larger than 83kb, try using GetStreamAsync to avoid reading as string /// /// /// @@ -101,19 +101,33 @@ namespace Flow.Launcher.Infrastructure.Http return GetAsync(new Uri(url.Replace("#", "%23"))); } + /// + /// Asynchrously get the result as string from url. + /// When supposing the result larger than 83kb, try using GetStreamAsync to avoid reading as string + /// + /// + /// public static async Task GetAsync([NotNull] Uri url) { Log.Debug($"|Http.Get|Url <{url}>"); - using var response = await client.GetAsync(url); - var content = await response.Content.ReadAsStringAsync(); - if (response.StatusCode == HttpStatusCode.OK) + try { - return content; + using var response = await client.GetAsync(url); + var content = await response.Content.ReadAsStringAsync(); + if (response.StatusCode == HttpStatusCode.OK) + { + return content; + } + else + { + throw new HttpRequestException( + $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); + } } - else + catch (HttpRequestException e) { - throw new HttpRequestException( - $"Error code <{response.StatusCode}> with content <{content}> returned from <{url}>"); + Log.Exception("Infrastructure.Http", "Http Request Error", e, "GetAsync"); + throw; } } @@ -124,9 +138,17 @@ namespace Flow.Launcher.Infrastructure.Http /// public static async Task GetStreamAsync([NotNull] string url) { - Log.Debug($"|Http.Get|Url <{url}>"); - var response = await client.GetAsync(url); - return await response.Content.ReadAsStreamAsync(); + try + { + Log.Debug($"|Http.Get|Url <{url}>"); + var response = await client.GetAsync(url); + return await response.Content.ReadAsStreamAsync(); + } + catch (HttpRequestException e) + { + Log.Exception("Infrastructure.Http", "Http Request Error", e, "GetStreamAsync"); + throw; + } } } } From bc63b9ebfa100426176603ba6c7009b72dd3502e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 4 Jan 2021 10:31:05 +0800 Subject: [PATCH 208/267] Change Download to DownloadAsync Add error handling for download as well --- Flow.Launcher.Infrastructure/Http/Http.cs | 22 +++++++++++++------ .../PluginsManager.cs | 4 ++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b796d807c..78fa099c9 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -75,17 +75,25 @@ namespace Flow.Launcher.Infrastructure.Http }; } - public static async Task Download([NotNull] string url, [NotNull] string filePath) + public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath) { - using var response = await client.GetAsync(url); - if (response.StatusCode == HttpStatusCode.OK) + try { - await using var fileStream = new FileStream(filePath, FileMode.CreateNew); - await response.Content.CopyToAsync(fileStream); + using var response = await client.GetAsync(url); + if (response.StatusCode == HttpStatusCode.OK) + { + await using var fileStream = new FileStream(filePath, FileMode.CreateNew); + await response.Content.CopyToAsync(fileStream); + } + else + { + throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>"); + } } - else + catch (HttpRequestException e) { - throw new HttpRequestException($"Error code <{response.StatusCode}> returned from <{url}>"); + Log.Exception("Infrastructure.Http", "Http Request Error", e, "DownloadAsync"); + throw; } } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 724ddf20d..68df5bc1f 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -127,7 +127,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); - await Http.Download(plugin.UrlDownload, filePath).ConfigureAwait(false); + await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false); Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_download_success")); @@ -217,7 +217,7 @@ namespace Flow.Launcher.Plugin.PluginsManager Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_downloading_plugin"), Context.API.GetTranslation("plugin_pluginsmanager_please_wait")); - await Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath).ConfigureAwait(false); + 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")); From fb640b68c8e5a49e105e0666ce77e057c1a43735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 4 Jan 2021 11:05:59 +0800 Subject: [PATCH 209/267] Use ValueTask instead of Task --- Flow.Launcher/ViewModel/ResultViewModel.cs | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 00a0e1ae5..20d32890b 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,7 +13,7 @@ namespace Flow.Launcher.ViewModel { public class ResultViewModel : BaseModel { - public class LazyAsync : Lazy> + public class LazyAsync : Lazy> { private T defaultValue; @@ -23,21 +24,27 @@ namespace Flow.Launcher.ViewModel { if (!IsValueCreated) { - base.Value.ContinueWith(_ => - { - _updateCallback(); - }); + _ = Exercute(); return defaultValue; } - + if (!base.Value.IsCompleted || base.Value.IsFaulted) 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,7 +62,7 @@ namespace Flow.Launcher.ViewModel Result = result; Image = new LazyAsync( - SetImage, + SetImage, ImageLoader.DefaultImage, () => { @@ -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) From 7967844cf381563c362f2d91bcac73342b3f5237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 4 Jan 2021 11:10:02 +0800 Subject: [PATCH 210/267] make defaultValue readonly and edit comment --- Flow.Launcher/ViewModel/ResultViewModel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 20d32890b..d1b03f911 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -15,7 +15,7 @@ namespace Flow.Launcher.ViewModel { public class LazyAsync : Lazy> { - private T defaultValue; + private readonly T defaultValue; private readonly Action _updateCallback; public new T Value @@ -24,7 +24,7 @@ namespace Flow.Launcher.ViewModel { if (!IsValueCreated) { - _ = Exercute(); + _ = Exercute(); // manually use callback strategy return defaultValue; } @@ -34,8 +34,8 @@ namespace Flow.Launcher.ViewModel 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. + // 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); From fc015245b3392664f4b630a6a10a68b85d05bc2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 4 Jan 2021 16:22:48 +0800 Subject: [PATCH 211/267] Change the way checking successfuly --- Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index d1b03f911..9eece1a97 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -29,7 +29,7 @@ namespace Flow.Launcher.ViewModel return defaultValue; } - if (!base.Value.IsCompleted || base.Value.IsFaulted) + if (!base.Value.IsCompletedSuccessfully) return defaultValue; return base.Value.Result; From 6703e0d137b3fcd03c8fdb16644df7fa5645b24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Mon, 4 Jan 2021 16:31:48 +0800 Subject: [PATCH 212/267] Return default image when loading UWP icon fail --- Flow.Launcher/ViewModel/ResultViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 9eece1a97..4c65f2b9f 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -68,7 +68,7 @@ namespace Flow.Launcher.ViewModel { OnPropertyChanged(nameof(Image)); }); - } + } Settings = settings; } @@ -101,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; } } From e790e9474e8fab545325eaa685314ea99821d470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Tue, 5 Jan 2021 16:11:38 +0800 Subject: [PATCH 213/267] Add Plugin Priority Settings --- .../UserSettings/PluginSettings.cs | 5 +- Flow.Launcher.Plugin/PluginMetadata.cs | 5 +- Flow.Launcher/PriorityChangeWindow.xaml | 43 ++++++++++++ Flow.Launcher/PriorityChangeWindow.xaml.cs | 69 +++++++++++++++++++ Flow.Launcher/SettingWindow.xaml | 8 ++- Flow.Launcher/SettingWindow.xaml.cs | 12 +++- Flow.Launcher/ViewModel/MainViewModel.cs | 6 +- Flow.Launcher/ViewModel/PluginViewModel.cs | 7 ++ .../ViewModel/SettingWindowViewModel.cs | 1 + .../Flow.Launcher.Plugin.Calculator/Main.cs | 2 +- 10 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 Flow.Launcher/PriorityChangeWindow.xaml create mode 100644 Flow.Launcher/PriorityChangeWindow.xaml.cs 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.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index d81b442e2..8bcbcd231 100644 --- a/Flow.Launcher.Plugin/PluginMetadata.cs +++ b/Flow.Launcher.Plugin/PluginMetadata.cs @@ -37,11 +37,14 @@ 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/PriorityChangeWindow.xaml b/Flow.Launcher/PriorityChangeWindow.xaml new file mode 100644 index 000000000..51509f1ab --- /dev/null +++ b/Flow.Launcher/PriorityChangeWindow.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Flow.Launcher/PriorityChangeWindow.xaml.cs b/Flow.Launcher/PriorityChangeWindow.xaml.cs new file mode 100644 index 000000000..01c6454c9 --- /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 +{ + /// + /// 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 = "Please provide an valid integer";// translater.GetTranslation("newActionKeywordsHasBeenAssigned"); + MessageBox.Show(msg); + } + + } + + private void PriorityChangeWindow_Loaded(object sender, RoutedEventArgs e) + { + OldPriority.Text = pluginViewModel.Priority.ToString(); + tbAction.Focus(); + } + } +} diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index e47f0e779..b000db20e 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -172,10 +172,14 @@ - + + + Margin="5 0 0 0"/> 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/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index c122f8037..4ebf898ea 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(); 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 } From a2f741b376d5c00da6ad51e0d800e5f3ccf24d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 09:59:20 +0800 Subject: [PATCH 214/267] change bitmap scaling mode to Fant (High Quality) to make the search icon looks better. --- Flow.Launcher/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 07bb96339..b6782cb60 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -92,7 +92,7 @@ - + Date: Wed, 6 Jan 2021 10:34:08 +0800 Subject: [PATCH 215/267] Use SVG for search icon --- Flow.Launcher.Infrastructure/Constant.cs | 2 +- Flow.Launcher/Flow.Launcher.csproj | 1 + Flow.Launcher/Images/mainsearch.svg | 10 ++++++++++ Flow.Launcher/MainWindow.xaml | 9 +++++---- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 5 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 Flow.Launcher/Images/mainsearch.svg diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs index 3dba35f8d..de6ed1b29 100644 --- a/Flow.Launcher.Infrastructure/Constant.cs +++ b/Flow.Launcher.Infrastructure/Constant.cs @@ -30,7 +30,7 @@ namespace Flow.Launcher.Infrastructure public static string PythonPath; - public static readonly string QueryTextBoxIconImagePath = $"{ProgramDirectory}\\Images\\mainsearch.png"; + public static readonly string QueryTextBoxIconImagePath = $"{ProgramDirectory}\\Images\\mainsearch.svg"; public const string DefaultTheme = "Darker"; diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 39b2087aa..0f8e6a767 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -82,6 +82,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Flow.Launcher/Images/mainsearch.svg b/Flow.Launcher/Images/mainsearch.svg new file mode 100644 index 000000000..5d28abdb3 --- /dev/null +++ b/Flow.Launcher/Images/mainsearch.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index b6782cb60..c9db58385 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" @@ -68,8 +69,8 @@ Margin="18,0,56,0"> - - + + @@ -81,7 +82,7 @@ AllowDrop="True" Visibility="Visible" Background="Transparent" - Margin="18,0,56,0"> + Margin="18,1,0,1" HorizontalAlignment="Left" Width="660"> @@ -92,7 +93,7 @@ - + ImageLoader.Load(Constant.QueryTextBoxIconImagePath); + public string Image => Constant.QueryTextBoxIconImagePath; #endregion From 0dd6a982ad93affc9cc2d3aae8dd7a4ba31bc176 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 15:51:52 +0800 Subject: [PATCH 216/267] change setting window to svg as well --- Flow.Launcher/SettingWindow.xaml | 3 ++- Flow.Launcher/ViewModel/SettingWindowViewModel.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index e47f0e779..121b062ee 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" @@ -252,7 +253,7 @@ Text="{DynamicResource hiThere}" IsReadOnly="True" Style="{DynamicResource QueryBoxStyle}" Margin="18 0 56 0" /> - + diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs index c122f8037..c43167e09 100644 --- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs +++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs @@ -438,7 +438,7 @@ namespace Flow.Launcher.ViewModel } } - public ImageSource ThemeImage => ImageLoader.Load(Constant.QueryTextBoxIconImagePath); + public string ThemeImage => Constant.QueryTextBoxIconImagePath; #endregion From 3bfd900f054687dee90a9c9670ff55e096000116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 16:10:52 +0800 Subject: [PATCH 217/267] revert change for oneway for mutli binding --- Flow.Launcher/MainWindow.xaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index c9db58385..4373c0f0c 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -69,8 +69,8 @@ Margin="18,0,56,0"> - - + + @@ -93,7 +93,8 @@ - + Date: Wed, 6 Jan 2021 16:46:38 +0800 Subject: [PATCH 218/267] remove unintended change and change the binding mode to default --- Flow.Launcher/MainWindow.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 4373c0f0c..998bc3e9a 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -82,7 +82,7 @@ AllowDrop="True" Visibility="Visible" Background="Transparent" - Margin="18,1,0,1" HorizontalAlignment="Left" Width="660"> + Margin="18,0,56,0" HorizontalAlignment="Left" Width="660"> @@ -93,7 +93,7 @@ - Date: Wed, 6 Jan 2021 17:00:16 +0800 Subject: [PATCH 219/267] change autogenerated summary to english --- Flow.Launcher/PriorityChangeWindow.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/PriorityChangeWindow.xaml.cs b/Flow.Launcher/PriorityChangeWindow.xaml.cs index 01c6454c9..f04ad110c 100644 --- a/Flow.Launcher/PriorityChangeWindow.xaml.cs +++ b/Flow.Launcher/PriorityChangeWindow.xaml.cs @@ -18,7 +18,7 @@ using System.Windows.Shapes; namespace Flow.Launcher { /// - /// PriorityChangeWindow.xaml 的交互逻辑 + /// Interaction Logic of PriorityChangeWindow.xaml /// public partial class PriorityChangeWindow : Window { From 4973f2d979b2da3e6a66245b828105e6154676c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 17:05:10 +0800 Subject: [PATCH 220/267] remove png file --- Flow.Launcher/Images/mainsearch.png | Bin 63073 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Flow.Launcher/Images/mainsearch.png diff --git a/Flow.Launcher/Images/mainsearch.png b/Flow.Launcher/Images/mainsearch.png deleted file mode 100644 index ac5492fa62dfa1d7bf207c60823b2f9fa6f4b622..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63073 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 From 833eccc25a9ff09f7ec4bbdbecd26904bbb7ee9f Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 6 Jan 2021 20:09:41 +1100 Subject: [PATCH 221/267] archive mainsearch.png --- Doc/mainsearch.png | Bin 0 -> 63073 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 Doc/mainsearch.png diff --git a/Doc/mainsearch.png b/Doc/mainsearch.png new file mode 100644 index 0000000000000000000000000000000000000000..ac5492fa62dfa1d7bf207c60823b2f9fa6f4b622 GIT binary patch literal 63073 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 literal 0 HcmV?d00001 From e85b766f5781560facc2f3ccb89266f7bab70730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 17:17:24 +0800 Subject: [PATCH 222/267] remove extra width --- Flow.Launcher/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 998bc3e9a..a196f369f 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -82,7 +82,7 @@ AllowDrop="True" Visibility="Visible" Background="Transparent" - Margin="18,0,56,0" HorizontalAlignment="Left" Width="660"> + Margin="18,0,56,0" HorizontalAlignment="Left"> From b2fcd98f2c4fa66ef211522a3a5f0f525d8dd4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 17:18:21 +0800 Subject: [PATCH 223/267] remove extra horizontalalignment --- Flow.Launcher/MainWindow.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index a196f369f..a2cfe569d 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -82,7 +82,7 @@ AllowDrop="True" Visibility="Visible" Background="Transparent" - Margin="18,0,56,0" HorizontalAlignment="Left"> + Margin="18,0,56,0"> From 8569b44247cbc066b2916c3ea1371a5a44751746 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 6 Jan 2021 20:23:38 +1100 Subject: [PATCH 224/267] search preview consistent --- Flow.Launcher/SettingWindow.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 121b062ee..e467d9a64 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -253,7 +253,8 @@ Text="{DynamicResource hiThere}" IsReadOnly="True" Style="{DynamicResource QueryBoxStyle}" Margin="18 0 56 0" /> - + From 182cdd199a564349df5ed146200514c8b2a80631 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 6 Jan 2021 20:24:36 +1100 Subject: [PATCH 225/267] fix typo --- Flow.Launcher/Languages/en.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index adb49b65d..6ee28e3ba 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -72,7 +72,7 @@ Are you sure you want to delete {0} plugin hotkey? Query window shadow effect Shadow effect has a substantial usage of GPU. - Not recommended if you computer performance is limited. + Not recommended if your computer performance is limited. HTTP Proxy From 6b597f7516205a5057cfd4b80ab29a723c10c2de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 17:42:46 +0800 Subject: [PATCH 226/267] throw exception if debug for Log.exception(className, message, exception) --- Flow.Launcher.Infrastructure/Logger/Log.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 289ec5d68..d485f964b 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -50,14 +50,18 @@ namespace Flow.Launcher.Infrastructure.Logger return valid; } - + [MethodImpl(MethodImplOptions.Synchronized)] public static void Exception(string className, string message, System.Exception exception, [CallerMemberName] string methodName = "") { +#if DEBUG + throw exception; +#else var classNameWithMethod = CheckClassAndMessageAndReturnFullClassWithMethod(className, message, methodName); ExceptionInternal(classNameWithMethod, message, exception); +#endif } private static string CheckClassAndMessageAndReturnFullClassWithMethod(string className, string message, From 0d24aba74fbde39e894be9246e9ae297841e6440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 17:43:48 +0800 Subject: [PATCH 227/267] Use actionkeyword comparison to determine whether delay querying. --- Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 1ca44c8b9..3ecf30139 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -437,7 +437,7 @@ namespace Flow.Launcher.ViewModel var plugins = PluginManager.ValidPluginsForQuery(query); Task.Run(async () => { - if (plugins.Count > 1) + if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign) { // Wait 45 millisecond for query change in global query // if query changes, return so that it won't be calculated @@ -468,7 +468,7 @@ namespace Flow.Launcher.ViewModel var results = PluginManager.QueryForPlugin(plugin, query); UpdateResultView(results, plugin.Metadata, query); } - catch(Exception e) + catch (Exception e) { Log.Exception("MainViewModel", $"Exception when querying the plugin {plugin.Metadata.Name}", e, "QueryResults"); } From 6f43d4fdf85d0426fba0a89caf7167ac853f3d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 17:51:55 +0800 Subject: [PATCH 228/267] remove extra space --- Flow.Launcher.Plugin/PluginMetadata.cs | 1 + Flow.Launcher/PriorityChangeWindow.xaml.cs | 2 +- Flow.Launcher/SettingWindow.xaml.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index 8bcbcd231..9eed86025 100644 --- a/Flow.Launcher.Plugin/PluginMetadata.cs +++ b/Flow.Launcher.Plugin/PluginMetadata.cs @@ -42,6 +42,7 @@ namespace Flow.Launcher.Plugin { return Name; } + [JsonIgnore] public int Priority { get; set; } diff --git a/Flow.Launcher/PriorityChangeWindow.xaml.cs b/Flow.Launcher/PriorityChangeWindow.xaml.cs index f04ad110c..0c1dad1ed 100644 --- a/Flow.Launcher/PriorityChangeWindow.xaml.cs +++ b/Flow.Launcher/PriorityChangeWindow.xaml.cs @@ -66,4 +66,4 @@ namespace Flow.Launcher tbAction.Focus(); } } -} +} \ No newline at end of file diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 2402ccd24..a922b4d67 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -292,4 +292,4 @@ namespace Flow.Launcher } } -} +} \ No newline at end of file From 3ba1bf6ab0157ac48d13f62e2c85a74a4195b750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 6 Jan 2021 18:00:45 +0800 Subject: [PATCH 229/267] Use l18n instead of static string --- Flow.Launcher/Languages/en.xaml | 6 ++++++ Flow.Launcher/PriorityChangeWindow.xaml | 7 ++++--- Flow.Launcher/PriorityChangeWindow.xaml.cs | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index adb49b65d..a275a2c16 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: @@ -104,6 +106,10 @@ Release Notes + + Higher the number, the closer the result will be to the top. 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/PriorityChangeWindow.xaml b/Flow.Launcher/PriorityChangeWindow.xaml index 51509f1ab..54e5c02cc 100644 --- a/Flow.Launcher/PriorityChangeWindow.xaml +++ b/Flow.Launcher/PriorityChangeWindow.xaml @@ -19,18 +19,19 @@ + HorizontalAlignment="Left" Text="{DynamicResource currentPriority}" /> + HorizontalAlignment="Left" Text="{DynamicResource newPriority}" /> + Text="{DynamicResource priority_tips}" TextWrapping="Wrap" + Margin="0,0,20,0"/> /// /// - public static async Task GetStreamAsync([NotNull] string url) + public static async Task GetStreamAsync([NotNull] string url, CancellationToken token = default) { Log.Debug($"|Http.Get|Url <{url}>"); - var response = await client.GetAsync(url); + var response = await client.GetAsync(url, token); + if (token.IsCancellationRequested) + return Stream.Null; return await response.Content.ReadAsStreamAsync(); } } From a4edbc2cb9a97f7a82b51fca4f0b3fe9c5faf642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 11:09:08 +0800 Subject: [PATCH 242/267] Move WebSearch to Async model --- .../Flow.Launcher.Plugin.WebSearch/Main.cs | 84 +++++++++---------- .../SuggestionSources/Baidu.cs | 5 +- .../SuggestionSources/Bing.cs | 7 +- .../SuggestionSources/Google.cs | 5 +- .../SuggestionSources/SuggestionSource.cs | 3 +- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs index 3c4d4c67d..a573674ec 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,11 +40,7 @@ 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) + _settings.SearchSources.Where(o => (o.ActionKeyword == query.ActionKeyword || o.ActionKeyword == SearchSourceGlobalPluginWildCardSign) && o.Enabled) .ToList() .ForEach(x => searchSourceList.Add(x)); @@ -94,49 +89,45 @@ namespace Flow.Launcher.Plugin.WebSearch }; results.Add(result); - ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs - { - Results = results, - Query = query - }); - - UpdateResultsFromSuggestion(results, keyword, subtitle, searchSource, query); } + + ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs + { + Results = results, + Query = query + }); + + await UpdateResultsFromSuggestionAsync(results, keyword, subtitle, searchSource, query, token).ConfigureAwait(false); } } 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); + results.AddRange(suggestions); - if (!task.Wait(waittime)) + token.ThrowIfCancellationRequested(); + + ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs { - task.ContinueWith(_ => ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs - { - Results = results, - Query = query - }), _updateToken); - } + Results = results, + Query = query + }); } } - 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); 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/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index 6772acf82..0c6d95b4f 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -9,6 +9,7 @@ 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 { @@ -16,14 +17,14 @@ 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.GetAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); + result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } catch (HttpRequestException e) { diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index 9c4746711..991e45267 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -9,19 +9,20 @@ 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) + public override async Task> Suggestions(string query, CancellationToken token) { Stream resultStream; try { const string api = "https://api.bing.com/qsonhs.aspx?q="; - resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); + resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } catch (HttpRequestException e) { @@ -29,7 +30,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources return new List(); } - if (resultStream.Length == 0) return new List(); + if (resultStream.Length == 0) return new List(); // this handles the cancellation JsonElement json; try diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 5b9538091..d034679af 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -8,18 +8,19 @@ 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 { public class Google : SuggestionSource { - public override async Task> Suggestions(string query) + public override async Task> Suggestions(string query, CancellationToken token) { string result; try { const string api = "https://www.google.com/complete/search?output=chrome&q="; - result = await Http.GetAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); + result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } catch (HttpRequestException e) { diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs index d6d89415f..bf444a2f7 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 From f72b716fb4a3b9de8dab6a336825b38bdc5ae338 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 11:20:14 +0800 Subject: [PATCH 243/267] use string.empty instead of null --- Flow.Launcher.Infrastructure/Http/Http.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 173be8422..4abf0e832 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -113,7 +113,7 @@ namespace Flow.Launcher.Infrastructure.Http Log.Debug($"|Http.Get|Url <{url}>"); using var response = await client.GetAsync(url, token); if (token.IsCancellationRequested) - return null; + return string.Empty; var content = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { From e1f715e6d607455bfbdd78f0e626ae1a5089f33f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 16:52:05 +0800 Subject: [PATCH 244/267] change commnet --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index bcfe298a9..769237bcb 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -102,7 +102,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected; - // Order defaults to 0 or -1, so 1 will let this property appear last + // This needs to be loaded last by staying at the bottom public PluginsSettings PluginSettings { get; set; } = new PluginsSettings(); } From 7501a7e7e7ee597a39838ffd57ccc7f959083b62 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Thu, 7 Jan 2021 20:40:22 +1100 Subject: [PATCH 245/267] version bump --- SolutionAssemblyInfo.cs | 6 +++--- appveyor.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SolutionAssemblyInfo.cs b/SolutionAssemblyInfo.cs index ccbfef5d0..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.6.0")] -[assembly: AssemblyFileVersion("1.6.0")] -[assembly: AssemblyInformationalVersion("1.6.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 7d1da7f3f..2c2f43b66 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.6.0.{build}' +version: '1.7.0.{build}' init: - ps: | From a6609d6b2c86cc167ae15501494434294cb64dcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 21:37:45 +0800 Subject: [PATCH 246/267] Add Cancellationtoken for downloadasync Remove extra action in http for cancellation due to it will throw TaskCancelledExcpetion internally --- Flow.Launcher.Infrastructure/Http/Http.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index 4212a1ab2..5af50bc6d 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -76,11 +76,11 @@ namespace Flow.Launcher.Infrastructure.Http }; } - public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath) + public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default) { try { - using var response = await client.GetAsync(url); + using var response = await client.GetAsync(url, token); if (response.StatusCode == HttpStatusCode.OK) { await using var fileStream = new FileStream(filePath, FileMode.CreateNew); @@ -120,8 +120,6 @@ namespace Flow.Launcher.Infrastructure.Http { Log.Debug($"|Http.Get|Url <{url}>"); using var response = await client.GetAsync(url, token); - if (token.IsCancellationRequested) - return string.Empty; var content = await response.Content.ReadAsStringAsync(); if (response.StatusCode == HttpStatusCode.OK) { @@ -143,8 +141,6 @@ namespace Flow.Launcher.Infrastructure.Http { Log.Debug($"|Http.Get|Url <{url}>"); var response = await client.GetAsync(url, token); - if (token.IsCancellationRequested) - return Stream.Null; return await response.Content.ReadAsStreamAsync(); } } From 8a5f98a6a3b4b73e302c39b2c77534fa32174151 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 21:38:21 +0800 Subject: [PATCH 247/267] Manually handling TaskCancelledException in search suggestion to aviod stunt in debugging --- .../Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs | 4 ++++ .../Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs | 4 ++++ .../SuggestionSources/Google.cs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index 0c6d95b4f..dcc2b9eef 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -26,6 +26,10 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources const string api = "http://suggestion.baidu.com/su?json=1&wd="; result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } + catch (TaskCanceledException) + { + return null; + } catch (HttpRequestException e) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index 991e45267..47bd016c1 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -24,6 +24,10 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources const string api = "https://api.bing.com/qsonhs.aspx?q="; resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } + catch (TaskCanceledException) + { + return null; + } catch (HttpRequestException e) { Log.Exception("|Bing.Suggestions|Can't get suggestion from Bing", e); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index d034679af..1182013b6 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -22,6 +22,10 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources const string api = "https://www.google.com/complete/search?output=chrome&q="; result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } + catch (TaskCanceledException) + { + return null; + } catch (HttpRequestException e) { Log.Exception("|Google.Suggestions|Can't get suggestion from google", e); From 86a9cf31c5e67b61d9cb5fb74ba49e02f3b389f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 21:41:05 +0800 Subject: [PATCH 248/267] Optimize Websearch code --- .../Flow.Launcher.Plugin.WebSearch/Main.cs | 122 +++++++++--------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs index a573674ec..f76e28112 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs @@ -40,65 +40,63 @@ namespace Flow.Launcher.Plugin.WebSearch var searchSourceList = new List(); var results = new List(); - _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 - }); - - await UpdateResultsFromSuggestionAsync(results, keyword, subtitle, searchSource, query, token).ConfigureAwait(false); + 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; @@ -110,15 +108,13 @@ namespace Flow.Launcher.Plugin.WebSearch if (_settings.EnableSuggestion) { var suggestions = await SuggestionsAsync(keyword, subtitle, searchSource, token).ConfigureAwait(false); + if (token.IsCancellationRequested || !suggestions.Any()) + return; + + results.AddRange(suggestions); token.ThrowIfCancellationRequested(); - - ResultsUpdated?.Invoke(this, new ResultUpdatedEventArgs - { - Results = results, - Query = query - }); } } @@ -128,6 +124,10 @@ namespace Flow.Launcher.Plugin.WebSearch if (source != null) { var suggestions = await source.Suggestions(keyword, token); + + if (token.IsCancellationRequested) + return null; + var resultsFromSuggestion = suggestions.Select(o => new Result { Title = o, From 919d5d51ab5b8e3ffb15f10f74586e0d26681e2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 21:47:31 +0800 Subject: [PATCH 249/267] add using for Bing search source --- .../Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index 47bd016c1..e6b0438d1 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -39,7 +39,8 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources JsonElement json; try { - json = (await JsonDocument.ParseAsync(resultStream)).RootElement.GetProperty("AS"); + using (resultStream) + json = (await JsonDocument.ParseAsync(resultStream)).RootElement.GetProperty("AS"); } catch (JsonException e) { From 1003ce416093d2320892c75f50b2082a522cc2e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 21:48:55 +0800 Subject: [PATCH 250/267] move using to more specific place in Google.cs --- .../SuggestionSources/Google.cs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 17153b9a7..5c784a702 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -32,24 +32,24 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources return new List(); } - using (resultStream) + + if (resultStream.Length == 0) return new List(); + JsonDocument json; + try { - if (resultStream.Length == 0) return new List(); - JsonDocument json; - try - { + using (resultStream) json = await JsonDocument.ParseAsync(resultStream); - } - catch (JsonException e) - { - Log.Exception("|Google.Suggestions|can't parse suggestions", e); - return new List(); - } - - var results = json?.RootElement.EnumerateArray().ElementAt(1); - - return results?.EnumerateArray().Select(o => o.GetString()).ToList() ?? new List(); } + catch (JsonException e) + { + Log.Exception("|Google.Suggestions|can't parse suggestions", e); + return new List(); + } + + var results = json?.RootElement.EnumerateArray().ElementAt(1); + + return results?.EnumerateArray().Select(o => o.GetString()).ToList() ?? new List(); + } public override string ToString() From c939924ec8ec2e28e6eccf7422ac7bf9eb5f3e32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 7 Jan 2021 21:54:09 +0800 Subject: [PATCH 251/267] optimize code in searchsuggestions --- .../SuggestionSources/Bing.cs | 16 +++++----------- .../SuggestionSources/Google.cs | 17 ++++++----------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index e6b0438d1..81725c3f2 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -17,12 +17,15 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public override async Task> Suggestions(string query, CancellationToken token) { - Stream resultStream; + JsonElement json; try { const string api = "https://api.bing.com/qsonhs.aspx?q="; - resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); + 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) { @@ -33,15 +36,6 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources Log.Exception("|Bing.Suggestions|Can't get suggestion from Bing", e); return new List(); } - - if (resultStream.Length == 0) return new List(); // this handles the cancellation - - JsonElement json; - try - { - using (resultStream) - json = (await JsonDocument.ParseAsync(resultStream)).RootElement.GetProperty("AS"); - } catch (JsonException e) { Log.Exception("|Bing.Suggestions|can't parse suggestions", e); diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index 5c784a702..b150d26c1 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -16,11 +16,15 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public override async Task> Suggestions(string query, CancellationToken token) { - Stream resultStream; + JsonDocument json; + try { const string api = "https://www.google.com/complete/search?output=chrome&q="; - resultStream = await Http.GetStreamAsync(api + Uri.EscapeUriString(query)).ConfigureAwait(false); + 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 (TaskCanceledException) { @@ -31,15 +35,6 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources Log.Exception("|Google.Suggestions|Can't get suggestion from google", e); return new List(); } - - - if (resultStream.Length == 0) return new List(); - JsonDocument json; - try - { - using (resultStream) - json = await JsonDocument.ParseAsync(resultStream); - } catch (JsonException e) { Log.Exception("|Google.Suggestions|can't parse suggestions", e); From 6d5ade405694903859546b5392d5e81f349159e6 Mon Sep 17 00:00:00 2001 From: kubalav Date: Fri, 8 Jan 2021 09:44:26 +0100 Subject: [PATCH 252/267] Plugins Manager Slovak translation --- .../Languages/sk.xaml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml 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..21ec558a6 --- /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 From 49560db7f64d7535ffc7dfba41a8470a09ed8257 Mon Sep 17 00:00:00 2001 From: Ioannis G Date: Sat, 9 Jan 2021 02:49:14 +0200 Subject: [PATCH 253/267] copy svg images to output from the main project --- Flow.Launcher/Flow.Launcher.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index c3b56b904..fddaaab6a 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -63,6 +63,9 @@ PreserveNewest + + PreserveNewest + From 494312a251b03d8870e937ab3bc03f0d0936b342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 11:04:36 +0800 Subject: [PATCH 254/267] Merge dev --- .../Flow.Launcher.Plugin.PluginsManager.csproj | 2 +- .../Flow.Launcher.Plugin.Shell.csproj | 5 +---- .../Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj | 5 +---- 3 files changed, 3 insertions(+), 9 deletions(-) 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 2e352d832..d6ca96b46 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -2,7 +2,7 @@ Library - netcoreapp3.1 + net5.0-windows true true true 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 d19c41cb2..daae28cf6 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -7,6 +7,7 @@ Flow.Launcher.Plugin.Shell Flow.Launcher.Plugin.Shell true + true true false false @@ -53,10 +54,6 @@ PreserveNewest - - MSBuild:Compile - Designer - 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 1bc5230e7..894d50cea 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -8,6 +8,7 @@ Flow.Launcher.Plugin.Sys Flow.Launcher.Plugin.Sys true + true true false false @@ -48,10 +49,6 @@ PreserveNewest - - MSBuild:Compile - Designer - From dd074f41cfd07138b2e14907198c0178df97ca95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 11:30:11 +0800 Subject: [PATCH 255/267] change publish profile to Net5 one --- Scripts/post_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index b08fac8f6..58d5c6a4e 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -90,7 +90,7 @@ function Pack-Squirrel-Installer ($path, $version, $output) { function Publish-Self-Contained ($p) { $csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve - $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/NetCore3.1-SelfContained.pubxml" -Resolve + $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml" -Resolve # we call dotnet publish on the main project. # The other projects should have been built in Release at this point. From a626e7b6ee8133d2f06cc01ad2467d49013d0b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 11:30:19 +0800 Subject: [PATCH 256/267] try trim --- .../Properties/PublishProfiles/Net5-SelfContained.pubxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml index 124792e3e..f2f969aa7 100644 --- a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -13,6 +13,6 @@ https://go.microsoft.com/fwlink/?LinkID=208121. true False False - False + True \ No newline at end of file From 92be6fd3ddd1024e320aa6d0b98ab1000fe7e5df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 12:01:08 +0800 Subject: [PATCH 257/267] Use Task.Yield to avoid using Parallel.For --- Flow.Launcher/ViewModel/MainViewModel.cs | 59 +++++++++++------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index da977f11f..c3e32731b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -86,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(() => @@ -113,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()); @@ -209,6 +197,7 @@ namespace Flow.Launcher.ViewModel public ResultsViewModel History { get; private set; } private string _queryText; + public string QueryText { get { return _queryText; } @@ -229,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; } @@ -264,6 +255,7 @@ namespace Flow.Launcher.ViewModel QueryText = string.Empty; } } + _selectedResults.Visbility = Visibility.Visible; } } @@ -324,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); } @@ -351,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; @@ -397,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; @@ -410,17 +403,14 @@ namespace Flow.Launcher.ViewModel // so looping will stop once it was cancelled Task[] tasks = new Task[plugins.Count]; - var parallelOptions = new ParallelOptions { CancellationToken = currentCancellationToken }; try { - Parallel.For(0, plugins.Count, parallelOptions, i => + for (var i = 0; i < plugins.Count; i++) { if (!plugins[i].Metadata.Disabled) - { 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); @@ -434,20 +424,25 @@ namespace Flow.Launcher.ViewModel // until the end of all querying _isQueryRunning = false; if (!currentCancellationToken.IsCancellationRequested) - { // update to hidden if this is still the current query + { + // update to hidden if this is still the current query ProgressBarVisibility = Visibility.Hidden; } // 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); + }, currentCancellationToken).ContinueWith( + t => Log.Exception("|MainViewModel|Plugins Query Exceptions", t.Exception), + TaskContinuationOptions.OnlyOnFaulted); } } else @@ -514,6 +509,7 @@ namespace Flow.Launcher.ViewModel } }; } + return menu; } @@ -559,6 +555,7 @@ namespace Flow.Launcher.ViewModel var selected = SelectedResults == History; return selected; } + #region Hotkey private void SetHotkey(string hotkeyStr, EventHandler action) @@ -577,7 +574,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); } } @@ -627,7 +625,6 @@ namespace Flow.Launcher.ViewModel { if (!ShouldIgnoreHotkeys()) { - if (_settings.LastQueryMode == LastQueryMode.Empty) { ChangeQueryText(string.Empty); From 0fc9f64e8584a44e7d88f8d6579a7759bf3f44fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BC=98=E9=9F=AC?= Date: Sat, 9 Jan 2021 12:05:55 +0800 Subject: [PATCH 258/267] image not found issue in build --- Flow.Launcher/Flow.Launcher.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index a269425af..a4d2634e0 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -60,7 +60,7 @@ Designer PreserveNewest - + PreserveNewest From 16148d59d4577d3db2efefdd3d9ccb9b6dbd25f7 Mon Sep 17 00:00:00 2001 From: kubalav Date: Sat, 9 Jan 2021 13:24:18 +0100 Subject: [PATCH 259/267] Fix Plugins Manager key name in Slovak translation --- Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml index 21ec558a6..211f2b430 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/sk.xaml @@ -27,7 +27,7 @@ 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 Prejsť na webovú stránku pluginu Zobraziť zdrojový kód Zobraziť zdrojový kód pluginu From db0fcb21713f92c18263ca829c9250a2fba9df00 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sun, 10 Jan 2021 20:59:49 +1100 Subject: [PATCH 260/267] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 654877f3a..1056ec48e 100644 --- a/README.md +++ b/README.md @@ -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. +[![image](https://user-images.githubusercontent.com/26427004/104119722-9033c600-5385-11eb-9d57-4c376862fd36.png) **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) | From b97834d9bcfbe3e11bfdad97be38c4ac98f34778 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 12 Jan 2021 07:30:01 +1100 Subject: [PATCH 261/267] update message + window location --- Flow.Launcher.Plugin/PluginMetadata.cs | 1 - Flow.Launcher/Languages/en.xaml | 2 +- Flow.Launcher/PriorityChangeWindow.xaml | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs index d470b5556..e8f5cf744 100644 --- a/Flow.Launcher.Plugin/PluginMetadata.cs +++ b/Flow.Launcher.Plugin/PluginMetadata.cs @@ -45,7 +45,6 @@ namespace Flow.Launcher.Plugin [JsonIgnore] public int Priority { get; set; } - /// /// Init time include both plugin load time and init time /// diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 234fe5091..1e0e6a7e0 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -107,7 +107,7 @@ Release Notes - Higher the number, the closer the result will be to the top. If you want the results to be lower than any other plugin's, provide a negative number + 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! diff --git a/Flow.Launcher/PriorityChangeWindow.xaml b/Flow.Launcher/PriorityChangeWindow.xaml index 54e5c02cc..68b5a49b7 100644 --- a/Flow.Launcher/PriorityChangeWindow.xaml +++ b/Flow.Launcher/PriorityChangeWindow.xaml @@ -6,12 +6,13 @@ xmlns:local="clr-namespace:Flow.Launcher" Loaded="PriorityChangeWindow_Loaded" mc:Ignorable="d" + WindowStartupLocation="CenterScreen" Title="PriorityChangeWindow" Height="250" Width="300"> - + From b1642cc079c5a6490d305c349b0493d71457b78b Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 12 Jan 2021 07:31:13 +1100 Subject: [PATCH 262/267] priority score variable for clarity and seperation from original score --- Flow.Launcher/ViewModel/MainViewModel.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index af472cf06..40006ecbf 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -687,7 +687,8 @@ namespace Flow.Launcher.ViewModel } else { - result.Score += _userSelectedRecord.GetSelectedCount(result) * 5 + metadata.Priority * 50; + var priorityScore = metadata.Priority * 50 + result.Score += _userSelectedRecord.GetSelectedCount(result) * 5 + priorityScore; } } From b9158e55664a9bfd199fad9d42d26cca12ece1a9 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 12 Jan 2021 07:36:23 +1100 Subject: [PATCH 263/267] update typo --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 40006ecbf..9b274d6e7 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -687,7 +687,7 @@ namespace Flow.Launcher.ViewModel } else { - var priorityScore = metadata.Priority * 50 + var priorityScore = metadata.Priority * 50; result.Score += _userSelectedRecord.GetSelectedCount(result) * 5 + priorityScore; } } From 94a047786e3cc59506b43038abe6a1a27fd2d5f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 13 Jan 2021 07:35:48 +0800 Subject: [PATCH 264/267] fix merge issue of result update event --- Flow.Launcher/ViewModel/MainViewModel.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 68c427672..9dea039a1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -122,14 +122,14 @@ 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(() => + if (e.Query.RawQuery == QueryText) // TODO: allow cancellation { PluginManager.UpdatePluginMetadata(e.Results, pair.Metadata, e.Query); - UpdateResultView(e.Results, pair.Metadata, e.Query); - }, _updateToken); + _resultsUpdateQueue.Post(new ResultsForUpdate(e.Results, pair.Metadata, e.Query, _updateToken)); + } }; } } @@ -379,7 +379,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; From fc536aa1ed1760c409b2974c3849ccfba62e2bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Wed, 13 Jan 2021 09:39:08 +0800 Subject: [PATCH 265/267] make priority score higher --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 9b274d6e7..e83e28c33 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -687,7 +687,7 @@ namespace Flow.Launcher.ViewModel } else { - var priorityScore = metadata.Priority * 50; + var priorityScore = metadata.Priority * 150; result.Score += _userSelectedRecord.GetSelectedCount(result) * 5 + priorityScore; } } From ca7a8c2ef347dbf9b9a2006d049e81430e1a8d29 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 13 Jan 2021 19:39:54 +1100 Subject: [PATCH 266/267] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1056ec48e..ac8611298 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be - Support of wide range of plugins. - Fully portable. -[![image](https://user-images.githubusercontent.com/26427004/104119722-9033c600-5385-11eb-9d57-4c376862fd36.png) **SOFTPEDIA EDITOR'S PICK**](https://www.softpedia.com/get/System/Launchers-Shutdown-Tools/Flow-Launcher.shtml) +[ **SOFTPEDIA EDITOR'S PICK**](https://www.softpedia.com/get/System/Launchers-Shutdown-Tools/Flow-Launcher.shtml) ## Running Flow Launcher From a4c11df204663c33bb650e70452eff29bb18b9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=98=E9=9F=AC=20=E5=BC=A0?= Date: Thu, 14 Jan 2021 10:24:44 +0800 Subject: [PATCH 267/267] use ready to run --- .../Properties/PublishProfiles/Net5-SelfContained.pubxml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml index f2f969aa7..3c5dcc8b2 100644 --- a/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml +++ b/Flow.Launcher/Properties/PublishProfiles/Net5-SelfContained.pubxml @@ -12,7 +12,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. win-x64 true False - False - True + True + False \ No newline at end of file