diff --git a/Doc/Default Icons/app_missing_img.png b/Doc/Default Icons/app_missing_img.png new file mode 100644 index 00000000000..b07eb4262f8 Binary files /dev/null and b/Doc/Default Icons/app_missing_img.png differ diff --git a/Doc/Default Icons/app_missing_img_01.png b/Doc/Default Icons/app_missing_img_01.png new file mode 100644 index 00000000000..2cc466ed0e6 Binary files /dev/null and b/Doc/Default Icons/app_missing_img_01.png differ diff --git a/Doc/Default Icons/app_missing_img_01.svg b/Doc/Default Icons/app_missing_img_01.svg new file mode 100644 index 00000000000..88b84858a7c --- /dev/null +++ b/Doc/Default Icons/app_missing_img_01.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_02.png b/Doc/Default Icons/app_missing_img_02.png new file mode 100644 index 00000000000..285a6889078 Binary files /dev/null and b/Doc/Default Icons/app_missing_img_02.png differ diff --git a/Doc/Default Icons/app_missing_img_02.svg b/Doc/Default Icons/app_missing_img_02.svg new file mode 100644 index 00000000000..190ecf469fd --- /dev/null +++ b/Doc/Default Icons/app_missing_img_02.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_03.png b/Doc/Default Icons/app_missing_img_03.png new file mode 100644 index 00000000000..11d5466f029 Binary files /dev/null and b/Doc/Default Icons/app_missing_img_03.png differ diff --git a/Doc/Default Icons/app_missing_img_03.svg b/Doc/Default Icons/app_missing_img_03.svg new file mode 100644 index 00000000000..904380091f7 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_03.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_buttons.png b/Doc/Default Icons/app_missing_img_buttons.png new file mode 100644 index 00000000000..62de71f2103 Binary files /dev/null and b/Doc/Default Icons/app_missing_img_buttons.png differ diff --git a/Doc/Default Icons/app_missing_img_buttons.svg b/Doc/Default Icons/app_missing_img_buttons.svg new file mode 100644 index 00000000000..b9d5e125960 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_buttons.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_fluent.png b/Doc/Default Icons/app_missing_img_fluent.png new file mode 100644 index 00000000000..eafd1bb357a Binary files /dev/null and b/Doc/Default Icons/app_missing_img_fluent.png differ diff --git a/Doc/Default Icons/app_missing_img_fluent.svg b/Doc/Default Icons/app_missing_img_fluent.svg new file mode 100644 index 00000000000..7a201cdc315 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_fluent.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_huge.png b/Doc/Default Icons/app_missing_img_huge.png new file mode 100644 index 00000000000..70aea308d2e Binary files /dev/null and b/Doc/Default Icons/app_missing_img_huge.png differ diff --git a/Doc/Default Icons/app_missing_img_huge.svg b/Doc/Default Icons/app_missing_img_huge.svg new file mode 100644 index 00000000000..874a9a0cae6 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_huge.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_lightblue.png b/Doc/Default Icons/app_missing_img_lightblue.png new file mode 100644 index 00000000000..3b262fc9b7c Binary files /dev/null and b/Doc/Default Icons/app_missing_img_lightblue.png differ diff --git a/Doc/Default Icons/app_missing_img_lightblue.svg b/Doc/Default Icons/app_missing_img_lightblue.svg new file mode 100644 index 00000000000..da713b41346 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_lightblue.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_lightblue_buttons.png b/Doc/Default Icons/app_missing_img_lightblue_buttons.png new file mode 100644 index 00000000000..17de0a6fe27 Binary files /dev/null and b/Doc/Default Icons/app_missing_img_lightblue_buttons.png differ diff --git a/Doc/Default Icons/app_missing_img_lightblue_buttons.svg b/Doc/Default Icons/app_missing_img_lightblue_buttons.svg new file mode 100644 index 00000000000..7251fb9f69c --- /dev/null +++ b/Doc/Default Icons/app_missing_img_lightblue_buttons.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_minimal.png b/Doc/Default Icons/app_missing_img_minimal.png new file mode 100644 index 00000000000..e66ea6d6e65 Binary files /dev/null and b/Doc/Default Icons/app_missing_img_minimal.png differ diff --git a/Doc/Default Icons/app_missing_img_minimal.svg b/Doc/Default Icons/app_missing_img_minimal.svg new file mode 100644 index 00000000000..d2b6d22feb8 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_minimal.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/Default Icons/app_missing_img_minimal_buttons.png b/Doc/Default Icons/app_missing_img_minimal_buttons.png new file mode 100644 index 00000000000..d4f2409099e Binary files /dev/null and b/Doc/Default Icons/app_missing_img_minimal_buttons.png differ diff --git a/Doc/Default Icons/app_missing_img_minimal_buttons.svg b/Doc/Default Icons/app_missing_img_minimal_buttons.svg new file mode 100644 index 00000000000..131ffadf8c9 --- /dev/null +++ b/Doc/Default Icons/app_missing_img_minimal_buttons.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doc/app_missing_img.png b/Doc/app_missing_img.png new file mode 100644 index 00000000000..11d5466f029 Binary files /dev/null and b/Doc/app_missing_img.png differ diff --git a/Flow.Launcher.Core/Configuration/Portable.cs b/Flow.Launcher.Core/Configuration/Portable.cs index 44e4434bed7..5bca087b879 100644 --- a/Flow.Launcher.Core/Configuration/Portable.cs +++ b/Flow.Launcher.Core/Configuration/Portable.cs @@ -95,7 +95,7 @@ public void RemoveUninstallerEntry() public void MoveUserDataFolder(string fromLocation, string toLocation) { - FilesFolders.Copy(fromLocation, toLocation); + FilesFolders.CopyAll(fromLocation, toLocation); VerifyUserDataAfterMove(fromLocation, toLocation); } diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 99d48275a45..d8bc2b6dc32 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -91,7 +91,7 @@ public async Task UpdateApp(IPublicAPI api , bool silentUpdate = true) if (DataLocation.PortableDataLocationInUse()) { var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}"; - FilesFolders.Copy(DataLocation.PortableDataPath, targetDestination); + 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}"); @@ -139,7 +139,7 @@ private async Task GitHubUpdateManager(string repository) var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/"); - var client = new WebClient { Proxy = Http.WebProxy() }; + var client = new WebClient { Proxy = Http.WebProxy }; var downloader = new FileDownloader(client); var manager = new UpdateManager(latestUrl, urlDownloader: downloader); diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs index a8c72fb122f..c6a3b48f364 100644 --- a/Flow.Launcher.Infrastructure/Constant.cs +++ b/Flow.Launcher.Infrastructure/Constant.cs @@ -23,8 +23,10 @@ public static class Constant public static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location.NonNull()).ProductVersion; public static readonly int ThumbnailSize = 64; - public static readonly string DefaultIcon = Path.Combine(ProgramDirectory, "Images", "app.png"); - public static readonly string ErrorIcon = Path.Combine(ProgramDirectory, "Images", "app_error.png"); + private static readonly string ImagesDirectory = Path.Combine(ProgramDirectory, "Images"); + public static readonly string DefaultIcon = Path.Combine(ImagesDirectory, "app.png"); + public static readonly string ErrorIcon = Path.Combine(ImagesDirectory, "app_error.png"); + public static readonly string MissingImgIcon = Path.Combine(ImagesDirectory, "app_missing_img.png"); public static string PythonPath; diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs index b7d274205ad..81c07eff7ea 100644 --- a/Flow.Launcher.Infrastructure/Http/Http.cs +++ b/Flow.Launcher.Infrastructure/Http/Http.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using System; namespace Flow.Launcher.Infrastructure.Http { @@ -13,6 +14,13 @@ public static class 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 @@ static 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 @@ public static void Download([NotNull] string url, [NotNull] string filePath) 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}>"); } } } diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs index 0bf575337c7..5cf3d84a61c 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs @@ -38,7 +38,7 @@ public static void Initialize() _imageCache.Usage = LoadStorageToConcurrentDictionary(); - foreach (var icon in new[] { Constant.DefaultIcon, Constant.ErrorIcon }) + foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon }) { ImageSource img = new BitmapImage(new Uri(icon)); img.Freeze(); @@ -106,7 +106,7 @@ private static ImageResult LoadInternal(string path, bool loadFullImage = false) { if (string.IsNullOrEmpty(path)) { - return new ImageResult(_imageCache[Constant.ErrorIcon], ImageType.Error); + return new ImageResult(_imageCache[Constant.MissingImgIcon], ImageType.Error); } if (_imageCache.ContainsKey(path)) { @@ -139,7 +139,7 @@ private static ImageResult LoadInternal(string path, bool loadFullImage = false) Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e); Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2); - ImageSource image = _imageCache[Constant.ErrorIcon]; + ImageSource image = _imageCache[Constant.MissingImgIcon]; _imageCache[path] = image; imageResult = new ImageResult(image, ImageType.Error); } @@ -191,8 +191,8 @@ private static ImageResult GetThumbnailResult(ref string path, bool loadFullImag } else { - image = _imageCache[Constant.ErrorIcon]; - path = Constant.ErrorIcon; + image = _imageCache[Constant.MissingImgIcon]; + path = Constant.MissingImgIcon; } if (type != ImageType.Error) diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 0aacc321b14..5dda76bc4d7 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -14,10 +14,10 @@ - 1.2.0 - 1.2.0 - 1.2.0 - 1.2.0 + 1.2.1 + 1.2.1 + 1.2.1 + 1.2.1 Flow.Launcher.Plugin Flow-Launcher MIT diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index 13905788a90..27cd1a5584e 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -17,7 +17,7 @@ public static class FilesFolders /// /// /// - public static void Copy(this string sourcePath, string targetPath) + public static void CopyAll(this string sourcePath, string targetPath) { // Get the subdirectories for the specified directory. DirectoryInfo dir = new DirectoryInfo(sourcePath); @@ -50,7 +50,7 @@ public static void Copy(this string sourcePath, string targetPath) foreach (DirectoryInfo subdir in dirs) { string temppath = Path.Combine(targetPath, subdir.Name); - Copy(subdir.FullName, temppath); + CopyAll(subdir.FullName, temppath); } } catch (Exception e) @@ -114,7 +114,7 @@ public static bool LocationExists(this string path) return Directory.Exists(path); } - public static bool FileExits(this string filePath) + public static bool FileExists(this string filePath) { return File.Exists(filePath); } @@ -124,7 +124,7 @@ public static void OpenPath(string fileOrFolderPath) var psi = new ProcessStartInfo { FileName = FileExplorerProgramName, UseShellExecute = true, Arguments = fileOrFolderPath }; try { - if (LocationExists(fileOrFolderPath) || FileExits(fileOrFolderPath)) + if (LocationExists(fileOrFolderPath) || FileExists(fileOrFolderPath)) Process.Start(psi); } catch (Exception e) diff --git a/Flow.Launcher/Images/app_missing_img.png b/Flow.Launcher/Images/app_missing_img.png new file mode 100644 index 00000000000..11d5466f029 Binary files /dev/null and b/Flow.Launcher/Images/app_missing_img.png differ diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 4392234eba3..a4fe2ede4fc 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -51,7 +51,7 @@ public ImageSource Image 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.ErrorIcon; + imagePath = Constant.MissingImgIcon; } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index b7710d3324b..2fb16e0e1a4 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -9,6 +9,7 @@ Are you sure you want to permanently delete this {0}? Deletion successful Successfully deleted the {0} + Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword Delete diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs index db2eaa72291..38939e244a5 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs @@ -22,6 +22,8 @@ internal static class Constants internal const char AllFilesFolderSearchWildcard = '>'; + internal const string DefaultContentSearchActionKeyword = "doc:"; + internal const char DirectorySeperator = '\\'; internal const string WindowsIndexingOptions = "srchadmin.dll"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs index ebde039d680..8bd19956eab 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs @@ -6,14 +6,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.FolderLinks { public class QuickFolderAccess { - internal List FolderList(Query query, List folderLinks, PluginInitContext context) + internal List FolderListMatched(Query query, List folderLinks, PluginInitContext context) { if (string.IsNullOrEmpty(query.Search)) - return folderLinks - .Select(item => - new ResultManager(context) - .CreateFolderResult(item.Nickname, item.Path, item.Path, query)) - .ToList(); + return new List(); string search = query.Search.ToLower(); @@ -24,5 +20,11 @@ internal List FolderList(Query query, List folderLinks, Plug .CreateFolderResult(item.Nickname, item.Path, item.Path, query)) .ToList(); } + + internal List FolderListAll(Query query, List folderLinks, PluginInitContext context) + => folderLinks + .Select(item => + new ResultManager(context).CreateFolderResult(item.Nickname, item.Path, item.Path, query)) + .ToList(); } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 6c0d186f169..5b50b7fada6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -34,16 +34,19 @@ internal List Search(Query query) var querySearch = query.Search; - var quickFolderLinks = quickFolderAccess.FolderList(query, settings.QuickFolderAccessLinks, context); + if (IsFileContentSearch(query.ActionKeyword)) + return WindowsIndexFileContentSearch(query, querySearch); - if (quickFolderLinks.Count > 0 && query.ActionKeyword == settings.SearchActionKeyword) - return quickFolderLinks; + // 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); - if (string.IsNullOrEmpty(querySearch)) - return results; + var quickFolderLinks = quickFolderAccess.FolderListMatched(query, settings.QuickFolderAccessLinks, context); - if (IsFileContentSearch(query.ActionKeyword)) - return WindowsIndexFileContentSearch(query, querySearch); + if (quickFolderLinks.Count > 0) + results.AddRange(quickFolderLinks); var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch); @@ -54,7 +57,11 @@ internal List Search(Query query) var isEnvironmentVariablePath = querySearch.Substring(1).Contains("%\\"); if (!FilesFolders.IsLocationPathString(querySearch) && !isEnvironmentVariablePath) - return WindowsIndexFilesAndFoldersSearch(query, querySearch); + { + results.AddRange(WindowsIndexFilesAndFoldersSearch(query, querySearch)); + + return results; + } var locationPath = querySearch; @@ -137,15 +144,17 @@ private List WindowsIndexTopLevelFolderSearch(Query query, string path) private bool UseWindowsIndexForDirectorySearch(string locationPath) { + var pathToDirectory = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath); + if (!settings.UseWindowsIndexForDirectorySearch) return false; if (settings.IndexSearchExcludedSubdirectoryPaths - .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath) + .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory) .StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))) return false; - return indexSearch.PathIsIndexed(locationPath); + return indexSearch.PathIsIndexed(pathToDirectory); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs index 08511091e0e..4f9325c7754 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs @@ -21,7 +21,7 @@ internal class IndexSearch private readonly ResultManager resultManager; // Reserved keywords in oleDB - private readonly string reservedStringPattern = @"^[\/\\\$\%]+$"; + private readonly string reservedStringPattern = @"^[\/\\\$\%_]+$"; internal IndexSearch(PluginInitContext context) { @@ -51,7 +51,12 @@ internal List ExecuteWindowsIndexSearch(string indexQueryString, string { if (dataReaderResults.GetValue(0) != DBNull.Value && dataReaderResults.GetValue(1) != DBNull.Value) { - var path = new Uri(dataReaderResults.GetString(1)).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); + + var path = new Uri(encodedFragmentPath).LocalPath; if (dataReaderResults.GetString(2) == "Directory") { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 4e62b3cba2a..5b12870c822 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,4 +1,5 @@ -using Flow.Launcher.Plugin.Explorer.Search.FolderLinks; +using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search.FolderLinks; using Newtonsoft.Json; using System.Collections.Generic; @@ -22,6 +23,6 @@ public class Settings public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign; [JsonProperty] - public string FileContentSearchActionKeyword { get; set; } = "doc:"; + public string FileContentSearchActionKeyword { get; set; } = Constants.DefaultContentSearchActionKeyword; } } \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index e14a6ebb54e..7fcd77f0775 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -54,5 +54,7 @@ internal void UpdateActionKeyword(string newActionKeyword, string oldActionKeywo } internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword); + + internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign; } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs index b9e5373b7c5..2957283ad1f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs @@ -51,8 +51,17 @@ private void OnConfirmButtonClick(object sender, RoutedEventArgs e) return; } + + if (settingsViewModel.IsNewActionKeywordGlobal(newActionKeyword) + && currentActionKeyword.Description + == settingsViewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_filecontentsearch")) + { + MessageBox.Show(settingsViewModel.Context.API.GetTranslation("plugin_explorer_globalActionKeywordInvalid")); + + return; + } - if(!settingsViewModel.IsActionKeywordAlreadyAssigned(newActionKeyword)) + if (!settingsViewModel.IsActionKeywordAlreadyAssigned(newActionKeyword)) { settingsViewModel.UpdateActionKeyword(newActionKeyword, currentActionKeyword.Keyword); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index 67d2e731c43..7c6ef82b04c 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.2", + "Version": "1.2.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll", diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml index 2eee31745db..e7a1361147f 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml @@ -5,7 +5,8 @@ Process Killer Kill running processes from Flow Launcher - kill all "{0}" processes + kill all instances of "{0}" + kill {0} processes kill all instances \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs index 22c84b20f96..c3d9d1ab2e0 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs @@ -52,21 +52,24 @@ public List LoadContextMenus(Result result) // get all non-system processes whose file path matches that of the given result (processPath) var similarProcesses = processHelper.GetSimilarProcesses(processPath); - menuOptions.Add(new Result + if (similarProcesses.Count() > 0) { - Title = _context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_instances"), - SubTitle = processPath, - Action = _ => + menuOptions.Add(new Result { - foreach (var p in similarProcesses) + Title = _context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_instances"), + SubTitle = processPath, + Action = _ => { - processHelper.TryKill(p); - } + foreach (var p in similarProcesses) + { + processHelper.TryKill(p); + } - return true; - }, - IcoPath = processPath - }); + return true; + }, + IcoPath = processPath + }); + } return menuOptions; } @@ -86,6 +89,7 @@ private List CreateResultsFromProcesses(List processlist, SubTitle = path, TitleHighlightData = StringMatcher.FuzzySearch(termToSearch, p.ProcessName).MatchData, Score = pr.Score, + ContextData = p.ProcessName, Action = (c) => { processHelper.TryKill(p); @@ -94,16 +98,18 @@ private List CreateResultsFromProcesses(List processlist, }); } + var sortedResults = results.OrderBy(x => x.Title).ToList(); + // When there are multiple results AND all of them are instances of the same executable // add a quick option to kill them all at the top of the results. - var firstResult = results.FirstOrDefault()?.SubTitle; - if (processlist.Count > 1 && !string.IsNullOrEmpty(termToSearch) && results.All(r => r.SubTitle == firstResult)) + var firstResult = sortedResults.FirstOrDefault(x => !string.IsNullOrEmpty(x.SubTitle)); + if (processlist.Count > 1 && !string.IsNullOrEmpty(termToSearch) && sortedResults.All(r => r.SubTitle == firstResult?.SubTitle)) { - results.Insert(0, new Result() + sortedResults.Insert(1, new Result() { - IcoPath = "Images/app.png", - Title = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all"), termToSearch), - SubTitle = "", + IcoPath = firstResult?.IcoPath, + Title = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all"), firstResult?.ContextData), + SubTitle = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all_count"), processlist.Count), Score = 200, Action = (c) => { @@ -117,7 +123,7 @@ private List CreateResultsFromProcesses(List processlist, }); } - return results; + return sortedResults; } } } diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json index f2e1eca1265..894c49bdf6c 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.0.0", + "Version":"1.1.0", "Language":"csharp", "Website":"https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller", "IcoPath":"Images\\app.png", diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs index b8633f3571e..69e077ee2f6 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs @@ -536,7 +536,7 @@ private BitmapImage ImageFromPath(string path) ProgramLogger.LogException($"|UWP|ImageFromPath|{path}" + $"|Unable to get logo for {UserModelId} from {path} and" + $" located in {Package.Location}", new FileNotFoundException()); - return new BitmapImage(new Uri(Constant.ErrorIcon)); + return new BitmapImage(new Uri(Constant.MissingImgIcon)); } } @@ -586,7 +586,7 @@ private ImageSource PlatedImage(BitmapImage image) $"|Unable to convert background string {BackgroundColor} " + $"to color for {Package.Location}", new InvalidOperationException()); - return new BitmapImage(new Uri(Constant.ErrorIcon)); + return new BitmapImage(new Uri(Constant.MissingImgIcon)); } } else diff --git a/SolutionAssemblyInfo.cs b/SolutionAssemblyInfo.cs index c7c8812f236..5591de39c9f 100644 --- a/SolutionAssemblyInfo.cs +++ b/SolutionAssemblyInfo.cs @@ -16,6 +16,6 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("1.2.1")] -[assembly: AssemblyFileVersion("1.2.1")] -[assembly: AssemblyInformationalVersion("1.2.1")] \ No newline at end of file +[assembly: AssemblyVersion("1.3.0")] +[assembly: AssemblyFileVersion("1.3.0")] +[assembly: AssemblyInformationalVersion("1.3.0")] \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 703f1cb0001..f3bc7cce364 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.2.1.{build}' +version: '1.3.0.{build}' init: - ps: |