diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 44c34968c55..8f0de798cc5 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -87,7 +87,7 @@ public async Task UpdateApp(IPublicAPI api, bool silentUpdate = true) UpdateManager.RestartApp(Constant.ApplicationFileName); } } - catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException) + catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException || e is TaskCanceledException) { Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e); api.ShowMsg(api.GetTranslation("update_flowlauncher_fail"), diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index de2e823590b..b3a507c9060 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -9,6 +9,8 @@ using System; using System.ComponentModel; using System.Threading; +using System.Windows.Interop; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Infrastructure.Http { @@ -18,6 +20,8 @@ public static class Http private static HttpClient client = new HttpClient(); + public static IPublicAPI API { get; set; } + static Http() { // need to be added so it would work on a win10 machine @@ -50,25 +54,36 @@ public static HttpProxy Proxy /// public static void UpdateProxy(ProxyProperty property) { - (WebProxy.Address, WebProxy.Credentials) = property switch + if (string.IsNullOrEmpty(Proxy.Server)) + return; + + try { - ProxyProperty.Enabled => Proxy.Enabled switch + (WebProxy.Address, WebProxy.Credentials) = property switch { - true => Proxy.UserName switch + ProxyProperty.Enabled => Proxy.Enabled 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)) + true when !string.IsNullOrEmpty(Proxy.Server) => 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)) + }, + _ => (null, null) }, - false => (null, null) - }, - ProxyProperty.Server => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), WebProxy.Credentials), - ProxyProperty.Port => (new Uri($"http://{Proxy.Server}:{Proxy.Port}"), WebProxy.Credentials), - ProxyProperty.UserName => (WebProxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), - ProxyProperty.Password => (WebProxy.Address, new NetworkCredential(Proxy.UserName, Proxy.Password)), - _ => throw new ArgumentOutOfRangeException() - }; + 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() + }; + } + catch(UriFormatException e) + { + API.ShowMsg("Please try again", "Unable to parse Http Proxy"); + Log.Exception("Flow.Launcher.Infrastructure.Http", "Unable to parse Uri", e); + } } public static async Task DownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default) diff --git a/Flow.Launcher.Test/HttpTest.cs b/Flow.Launcher.Test/HttpTest.cs new file mode 100644 index 00000000000..637747a0785 --- /dev/null +++ b/Flow.Launcher.Test/HttpTest.cs @@ -0,0 +1,33 @@ +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Text; +using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Infrastructure.Http; + +namespace Flow.Launcher.Test +{ + [TestFixture] + class HttpTest + { + [Test] + public void GivenHttpProxy_WhenUpdated_ThenWebProxyShouldAlsoBeUpdatedToTheSame() + { + HttpProxy proxy = new HttpProxy(); + Http.Proxy = proxy; + + proxy.Enabled = true; + proxy.Server = "127.0.0.1"; + Assert.AreEqual(Http.WebProxy.Address, new Uri($"http://{proxy.Server}:{proxy.Port}")); + Assert.IsNull(Http.WebProxy.Credentials); + + proxy.UserName = "test"; + Assert.NotNull(Http.WebProxy.Credentials); + Assert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").UserName, proxy.UserName); + Assert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").Password, ""); + + proxy.Password = "test password"; + Assert.AreEqual(Http.WebProxy.Credentials.GetCredential(Http.WebProxy.Address, "Basic").Password, proxy.Password); + } + } +} diff --git a/Flow.Launcher.Test/UrlPluginTest.cs b/Flow.Launcher.Test/Plugins/UrlPluginTest.cs similarity index 100% rename from Flow.Launcher.Test/UrlPluginTest.cs rename to Flow.Launcher.Test/Plugins/UrlPluginTest.cs diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 7c4c6a36716..a2907c927e2 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -61,7 +61,6 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => _settingsVM = new SettingWindowViewModel(_updater, _portable); _settings = _settingsVM.Settings; - Http.Proxy = _settings.Proxy; _alphabet.Initialize(_settings); _stringMatcher = new StringMatcher(_alphabet); @@ -71,6 +70,10 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => PluginManager.LoadPlugins(_settings.PluginSettings); _mainVM = new MainViewModel(_settings); API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet); + + Http.API = API; + Http.Proxy = _settings.Proxy; + await PluginManager.InitializePlugins(API); var window = new MainWindow(_settings, _mainVM); diff --git a/Flow.Launcher/ViewModel/ResultsViewModel.cs b/Flow.Launcher/ViewModel/ResultsViewModel.cs index feab3a7513d..344dad58e54 100644 --- a/Flow.Launcher/ViewModel/ResultsViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultsViewModel.cs @@ -1,16 +1,13 @@ -using System; +using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Collections.Specialized; 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 Flow.Launcher.Infrastructure.UserSettings; -using Flow.Launcher.Plugin; namespace Flow.Launcher.ViewModel { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 2af09bf2cbb..d5f882d5ca6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -22,9 +22,24 @@ public SearchManager(Settings settings, PluginInitContext context) this.settings = settings; } + private class PathEqualityComparator : IEqualityComparer + { + private static PathEqualityComparator instance; + public static PathEqualityComparator Instance => instance ??= new PathEqualityComparator(); + public bool Equals(Result x, Result y) + { + return x.SubTitle == y.SubTitle; + } + + public int GetHashCode(Result obj) + { + return obj.SubTitle.GetHashCode(); + } + } + internal async Task> SearchAsync(Query query, CancellationToken token) { - var results = new List(); + var results = new HashSet(PathEqualityComparator.Instance); var querySearch = query.Search; @@ -38,7 +53,7 @@ internal async Task> SearchAsync(Query query, CancellationToken tok var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, settings.QuickAccessLinks); if (quickaccessLinks.Count > 0) - results.AddRange(quickaccessLinks); + results.UnionWith(quickaccessLinks); var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch); @@ -50,9 +65,9 @@ internal async Task> SearchAsync(Query query, CancellationToken tok if (!querySearch.IsLocationPathString() && !isEnvironmentVariablePath) { - results.AddRange(await WindowsIndexFilesAndFoldersSearchAsync(query, querySearch, token).ConfigureAwait(false)); + results.UnionWith(await WindowsIndexFilesAndFoldersSearchAsync(query, querySearch, token).ConfigureAwait(false)); - return results; + return results.ToList(); } var locationPath = querySearch; @@ -62,7 +77,7 @@ internal async Task> SearchAsync(Query query, CancellationToken tok // Check that actual location exists, otherwise directory search will throw directory not found exception if (!FilesFolders.LocationExists(FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath))) - return results; + return results.ToList(); var useIndexSearch = UseWindowsIndexForDirectorySearch(locationPath); @@ -79,9 +94,9 @@ internal async Task> SearchAsync(Query query, CancellationToken tok token.ThrowIfCancellationRequested(); - results.AddRange(directoryResult); + results.UnionWith(directoryResult); - return results; + return results.ToList(); } private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString, CancellationToken token) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index 9aa54fb8392..63ca66a1e50 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.7.0", + "Version": "1.7.1", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll", diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 90d103bc712..7baa08a7b8c 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -212,7 +212,7 @@ where existingPlugin.Metadata.Version.CompareTo(pluginFromManifest.Version) < Context.API.GetTranslation("plugin_pluginsmanager_update_title"), MessageBoxButton.YesNo) == MessageBoxResult.Yes) { - Uninstall(x.PluginExistingMetadata); + Uninstall(x.PluginExistingMetadata, false); var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip"); @@ -399,10 +399,13 @@ internal List RequestUninstall(string search) return Search(results, uninstallSearch); } - private void Uninstall(PluginMetadata plugin) + private void Uninstall(PluginMetadata plugin, bool removedSetting = true) { - PluginManager.Settings.Plugins.Remove(plugin.ID); - PluginManager.AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID); + if (removedSetting) + { + PluginManager.Settings.Plugins.Remove(plugin.ID); + PluginManager.AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID); + } // Marked for deletion. Will be deleted on next start up using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 4cba7ec83e8..66b438fd5ad 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.6.4", + "Version": "1.6.5", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", diff --git a/SolutionAssemblyInfo.cs b/SolutionAssemblyInfo.cs index 7f13f41306a..bcddbd1bddf 100644 --- a/SolutionAssemblyInfo.cs +++ b/SolutionAssemblyInfo.cs @@ -16,6 +16,6 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.7.1")] -[assembly: AssemblyFileVersion("1.7.1")] -[assembly: AssemblyInformationalVersion("1.7.1")] \ No newline at end of file +[assembly: AssemblyVersion("1.7.2")] +[assembly: AssemblyFileVersion("1.7.2")] +[assembly: AssemblyInformationalVersion("1.7.2")] \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 6340318d474..299a829bac5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.7.1.{build}' +version: '1.7.2.{build}' init: - ps: |