diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index d7df11f8303..9e932a5085b 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -55,6 +55,7 @@ + diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs index 431458881ec..22f547a5a75 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs @@ -11,7 +11,9 @@ using System.Windows.Forms; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Plugin; +using ICSharpCode.SharpZipLib.Zip; using JetBrains.Annotations; +using Microsoft.IO; namespace Flow.Launcher.Core.Plugin { @@ -33,9 +35,11 @@ internal abstract class JsonRPCPlugin : IAsyncPlugin, IContextMenu protected abstract string ExecuteCallback(JsonRPCRequestModel rpcRequest); protected abstract string ExecuteContextMenu(Result selectedResult); + private static readonly RecyclableMemoryStreamManager BufferManager = new(); + public List LoadContextMenus(Result selectedResult) { - string output = ExecuteContextMenu(selectedResult); + var output = ExecuteContextMenu(selectedResult); try { return DeserializedResult(output); @@ -61,12 +65,23 @@ private async Task> DeserializedResultAsync(Stream output) { if (output == Stream.Null) return null; - var queryResponseModel = await - JsonSerializer.DeserializeAsync(output, options); + try + { + var queryResponseModel = + await JsonSerializer.DeserializeAsync(output, options); - await output.DisposeAsync(); - - return ParseResults(queryResponseModel); + return ParseResults(queryResponseModel); + } + catch (JsonException e) + { + Log.Exception(GetType().FullName, "Unexpected Json Input", e); + } + finally + { + await output.DisposeAsync(); + } + + return null; } private List DeserializedResult(string output) @@ -81,7 +96,6 @@ private List DeserializedResult(string output) private List ParseResults(JsonRPCQueryResponseModel queryResponseModel) { - var results = new List(); if (queryResponseModel.Result == null) return null; if (!string.IsNullOrEmpty(queryResponseModel.DebugMessage)) @@ -89,7 +103,7 @@ private List ParseResults(JsonRPCQueryResponseModel queryResponseModel) context.API.ShowMsg(queryResponseModel.DebugMessage); } - foreach (JsonRPCResult result in queryResponseModel.Result) + foreach (var result in queryResponseModel.Result) { result.Action = c => { @@ -114,7 +128,8 @@ private List ParseResults(JsonRPCQueryResponseModel queryResponseModel) return !result.JsonRPCAction.DontHideAfterAction; } - var jsonRpcRequestModel = JsonSerializer.Deserialize(actionResponse, options); + var jsonRpcRequestModel = + JsonSerializer.Deserialize(actionResponse, options); if (jsonRpcRequestModel?.Method?.StartsWith("Flow.Launcher.") ?? false) { @@ -125,9 +140,12 @@ private List ParseResults(JsonRPCQueryResponseModel queryResponseModel) return !result.JsonRPCAction.DontHideAfterAction; }; - results.Add(result); } + var results = new List(); + + results.AddRange(queryResponseModel.Result); + return results; } @@ -217,16 +235,42 @@ protected string Execute(ProcessStartInfo startInfo) protected async Task ExecuteAsync(ProcessStartInfo startInfo, CancellationToken token = default) { + Process process = null; + bool disposed = false; try { - using var process = Process.Start(startInfo); + process = Process.Start(startInfo); if (process == null) { Log.Error("|JsonRPCPlugin.ExecuteAsync|Can't start new process"); return Stream.Null; } - var result = process.StandardOutput.BaseStream; + await using var source = process.StandardOutput.BaseStream; + + var buffer = BufferManager.GetStream(); + + token.Register(() => + { + // ReSharper disable once AccessToModifiedClosure + // Manually Check whether disposed + if (!disposed && !process.HasExited) + process.Kill(); + }); + + try + { + // token expire won't instantly trigger the exception, + // manually kill process at before + await source.CopyToAsync(buffer, token); + } + catch (OperationCanceledException) + { + await buffer.DisposeAsync(); + return Stream.Null; + } + + buffer.Seek(0, SeekOrigin.Begin); token.ThrowIfCancellationRequested(); @@ -245,7 +289,7 @@ protected async Task ExecuteAsync(ProcessStartInfo startInfo, Cancellati return Stream.Null; } - return result; + return buffer; } catch (Exception e) { @@ -254,15 +298,24 @@ protected async Task ExecuteAsync(ProcessStartInfo startInfo, Cancellati e); return Stream.Null; } + finally + { + process?.Dispose(); + disposed = true; + } } public async Task> QueryAsync(Query query, CancellationToken token) { - var output = await ExecuteQueryAsync(query, token); try { + var output = await ExecuteQueryAsync(query, token); return await DeserializedResultAsync(output); } + catch (OperationCanceledException) + { + return null; + } catch (Exception e) { Log.Exception($"|JsonRPCPlugin.Query|Exception when query <{query}>", e); diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index b3e9052fc54..c2a32100dbb 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -75,7 +75,7 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => Http.API = API; Http.Proxy = _settings.Proxy; - + await PluginManager.InitializePlugins(API); var window = new MainWindow(_settings, _mainVM); @@ -99,6 +99,8 @@ await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () => AutoStartup(); AutoUpdates(); + API.SaveAppAllSettings(); + _mainVM.MainWindowVisibility = _settings.HideOnStartup ? Visibility.Hidden : Visibility.Visible; Log.Info("|App.OnStartup|End Flow Launcher startup ---------------------------------------------------- "); }); diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index ec1b015daa6..346c708377c 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -31,12 +31,15 @@ Ignorovať klávesové skratky v režime na celú obrazovku Priečinok s Pythonom Automatická aktualizácia + Automaticky skryť posuvník + Automaticky skrývať posuvník v okne nastavení a zobraziť ho, keď naň prejdete myšou Vybrať Schovať Flow Launcher po spustení Schovať ikonu z oblasti oznámení Presnosť vyhľadávania Použiť Pinyin Umožňuje vyhľadávanie pomocou Pinyin. Pinyin je štandardný systém romanizovaného pravopisu pre transliteráciu čínštiny + Efekt tieňa nie je povolený, kým má aktuálny motív povolený efekt rozostrenia Plugin @@ -48,6 +51,7 @@ Nová akcia skratky: Aktuálna priorita: Nová priorita: + Priorita: Priečinok s pluginmi Autor Príprava: @@ -70,6 +74,7 @@ Modifikáčné klávesy na otvorenie výsledkov Zobraziť klávesovú skratku Vlastná klávesová skratka na vyhľadávanie + Dopyt Odstrániť Upraviť Pridať diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 8b81bb94abe..fcc3af5c502 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -1,4 +1,4 @@ - - { - if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused) + Dispatcher.Invoke(async () => { - await Task.Delay(50); - _progressBarStoryboard.Stop(ProgressBar); - isProgressBarStoryboardPaused = true; - } - else if (_viewModel.MainWindowVisibility == Visibility.Visible && - isProgressBarStoryboardPaused) - { - _progressBarStoryboard.Begin(ProgressBar, true); - isProgressBarStoryboardPaused = false; - } - }, System.Windows.Threading.DispatcherPriority.Render); - - break; - } + if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused) + { + await Task.Delay(50); + _progressBarStoryboard.Stop(ProgressBar); + isProgressBarStoryboardPaused = true; + } + else if (_viewModel.MainWindowVisibility == Visibility.Visible && + isProgressBarStoryboardPaused) + { + _progressBarStoryboard.Begin(ProgressBar, true); + isProgressBarStoryboardPaused = false; + } + }, System.Windows.Threading.DispatcherPriority.Render); + + break; + } case nameof(MainViewModel.QueryTextCursorMovedToEnd): if (_viewModel.QueryTextCursorMovedToEnd) { @@ -230,10 +229,10 @@ private void OnPreviewMouseButtonDown(object sender, MouseButtonEventArgs e) { if (sender != null && e.OriginalSource != null) { - var r = (ResultListBox) sender; - var d = (DependencyObject) e.OriginalSource; + var r = (ResultListBox)sender; + var d = (DependencyObject)e.OriginalSource; var item = ItemsControl.ContainerFromElement(r, d) as ListBoxItem; - var result = (ResultViewModel) item?.DataContext; + var result = (ResultViewModel)item?.DataContext; if (result != null) { if (e.ChangedButton == MouseButton.Left) diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 478e114f9ff..38168a66c92 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -38,7 +38,7 @@ - + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index a989327be26..b23931fcf78 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -10,6 +10,10 @@ 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 + The required service for Windows Index Search does not appear to be running + To fix this, start the Windows Search service. Select here to remove this warning + The warning message has been switched off. As an alternative for searching files and folders, would you like to install Everything plugin?{0}{0}Select 'Yes' to install Everything plugin, or 'No' to return + Explorer Alternative Delete diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml new file mode 100644 index 00000000000..cab8520bca1 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml @@ -0,0 +1,66 @@ + + + + Najprv vyberte položku + Vyberte odkaz na priečinok + Naozaj chcete odstrániť {0}? + Naozaj chcete natrvalo odstrániť túto položku {0}? + Odstránenie bolo úspešné + Úspešne odstránené {0} + Priradenie globálnej skratky akcie by mohlo počas vyhľadávania poskytnúť príliš veľa výsledkov. Vyberte si konkrétne kľúčové slovo akcie + Zdá sa, že požadovaná služba Windows Index Search nie je spustená + Ak to chcete opraviť, spustite službu Windows Search. Ak chcete odstrániť toto upozornenie, kliknite sem + Upozornenie bolo vypnuté. Chceli by ste ako alternatívu na vyhľadávanie súborov a priečinkov nainštalovať plugin Everything?{0}{0}Ak chcete nainštalovať plugin Everything, zvoľte 'Áno', pre návrat zvoľte 'Nie' + Alternatíva pre Explorer + + + Odstrániť + Upraviť + Pridať + Upraviť skratku akcie + Odkazy Rýchleho prístupu + Vylúčené umiestnenia indexovania + Možnosti indexovania + Vyhľadávanie: + Vyhľadávanie umiestnenia: + Vyhľadávanie obsahu súborov: + Vyhľadávanie v indexe: + Aktuálna skratka: + Hotovo + Povolené + Ak je vypnuté, Flow túto možnosť vyhľadávania nevykoná a následne sa vráti späť na "*", aby sa uvoľnila skratka akcie. + + + Explorer + Vyhľadáva a spravuje súbory a priečinky. Explorer používa indexovanie vyhľadávania vo Windowse + + + Kopírovať cestu + Kopírovať + Odstrániť + Umiestnenie: + Odstrániť vybrané + Spustiť ako iný používateľ + Spustí vybranú položku ako používateľ s iným kontom + Otvoriť umiestnenie priečinka + Otvorí umiestnenie, ktoré obsahuje súbor alebo priečinok + Otvoriť editorom: + Vylúčiť položku a jej podpriečinky z indexu vyhľadávania + Vylúčiť z indexu vyhľadávania + Otvoriť možnosti vyhľadávania vo Windowse + Správa indexovaných súborov a priečinkov + Nepodarilo sa otvoriť možnosti indexu vyhľadávania + Pridať do Rýchleho prístupu + Pridať tento {0} do Rýchleho prístupu + Úspešne pridané + Úspešne pridané do Rýchleho prístupu + Úspešne odstránené + Úspešne odstránené z Rýchleho prístupu + Pridať do Rýchleho prístupu, aby ho bolo možné otvoriť pomocou skratky akcie pluginu Explorer + Odstráni z Rýchleho prístupu + Odstrániť z Rýchleho prístupu + Odstráni {0} z Rýchleho prístupu + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index 2aa389f8950..9995f45d380 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -12,14 +12,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search { public class SearchManager { - private readonly PluginInitContext context; + internal static PluginInitContext Context; - private readonly Settings settings; + internal static Settings Settings; public SearchManager(Settings settings, PluginInitContext context) { - this.context = context; - this.settings = settings; + Context = context; + Settings = settings; } private class PathEqualityComparator : IEqualityComparer @@ -71,14 +71,14 @@ private bool ActionKeywordMatch(Query query, Settings.ActionKeyword allowedActio return allowedActionKeyword switch { - Settings.ActionKeyword.SearchActionKeyword => settings.SearchActionKeywordEnabled && - keyword == settings.SearchActionKeyword, - Settings.ActionKeyword.PathSearchActionKeyword => settings.PathSearchKeywordEnabled && - keyword == settings.PathSearchActionKeyword, + Settings.ActionKeyword.SearchActionKeyword => Settings.SearchActionKeywordEnabled && + keyword == Settings.SearchActionKeyword, + Settings.ActionKeyword.PathSearchActionKeyword => Settings.PathSearchKeywordEnabled && + keyword == Settings.PathSearchActionKeyword, Settings.ActionKeyword.FileContentSearchActionKeyword => keyword == - settings.FileContentSearchActionKeyword, - Settings.ActionKeyword.IndexSearchActionKeyword => settings.IndexOnlySearchKeywordEnabled && - keyword == settings.IndexSearchActionKeyword + Settings.FileContentSearchActionKeyword, + Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexOnlySearchKeywordEnabled && + keyword == Settings.IndexSearchActionKeyword }; } @@ -88,18 +88,18 @@ public async Task> PathSearchAsync(Query query, CancellationToken t // This allows the user to type the assigned action keyword and only see the list of quick folder links if (string.IsNullOrEmpty(query.Search)) - return QuickAccess.AccessLinkListAll(query, settings.QuickAccessLinks); + return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks); var results = new HashSet(PathEqualityComparator.Instance); - var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, settings.QuickAccessLinks); + var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks); results.UnionWith(quickaccessLinks); var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch); if (isEnvironmentVariable) - return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, context); + return EnvironmentVariables.GetEnvironmentStringPathSuggestions(querySearch, query, Context); // Query is a location path with a full environment variable, eg. %appdata%\somefolder\ var isEnvironmentVariablePath = querySearch[1..].Contains("%\\"); @@ -136,22 +136,23 @@ public async Task> PathSearchAsync(Query query, CancellationToken t private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString, CancellationToken token) { - var queryConstructor = new QueryConstructor(settings); + var queryConstructor = new QueryConstructor(Settings); if (string.IsNullOrEmpty(querySearchString)) return new List(); - return await IndexSearch.WindowsIndexSearchAsync(querySearchString, - queryConstructor.CreateQueryHelper().ConnectionString, + return await IndexSearch.WindowsIndexSearchAsync( + querySearchString, + queryConstructor.CreateQueryHelper(), queryConstructor.QueryForFileContentSearch, - settings.IndexSearchExcludedSubdirectoryPaths, + Settings.IndexSearchExcludedSubdirectoryPaths, query, token).ConfigureAwait(false); } public bool IsFileContentSearch(string actionKeyword) { - return actionKeyword == settings.FileContentSearchActionKeyword; + return actionKeyword == Settings.FileContentSearchActionKeyword; } private List DirectoryInfoClassSearch(Query query, string querySearch, CancellationToken token) @@ -176,12 +177,13 @@ public async Task> TopLevelDirectorySearchBehaviourAsync( private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString, CancellationToken token) { - var queryConstructor = new QueryConstructor(settings); + var queryConstructor = new QueryConstructor(Settings); - return await IndexSearch.WindowsIndexSearchAsync(querySearchString, - queryConstructor.CreateQueryHelper().ConnectionString, + return await IndexSearch.WindowsIndexSearchAsync( + querySearchString, + queryConstructor.CreateQueryHelper(), queryConstructor.QueryForAllFilesAndFolders, - settings.IndexSearchExcludedSubdirectoryPaths, + Settings.IndexSearchExcludedSubdirectoryPaths, query, token).ConfigureAwait(false); } @@ -189,12 +191,13 @@ private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query qu private async Task> WindowsIndexTopLevelFolderSearchAsync(Query query, string path, CancellationToken token) { - var queryConstructor = new QueryConstructor(settings); + var queryConstructor = new QueryConstructor(Settings); - return await IndexSearch.WindowsIndexSearchAsync(path, - queryConstructor.CreateQueryHelper().ConnectionString, + return await IndexSearch.WindowsIndexSearchAsync( + path, + queryConstructor.CreateQueryHelper(), queryConstructor.QueryForTopLevelDirectorySearch, - settings.IndexSearchExcludedSubdirectoryPaths, + Settings.IndexSearchExcludedSubdirectoryPaths, query, token).ConfigureAwait(false); } @@ -203,10 +206,10 @@ private bool UseWindowsIndexForDirectorySearch(string locationPath) { var pathToDirectory = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath); - if (!settings.UseWindowsIndexForDirectorySearch) + if (!Settings.UseWindowsIndexForDirectorySearch) return false; - if (settings.IndexSearchExcludedSubdirectoryPaths + if (Settings.IndexSearchExcludedSubdirectoryPaths .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory) .StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))) return false; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs index cfb564924c0..010a19b583a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs @@ -5,9 +5,11 @@ using System.Collections.Generic; using System.Data.OleDb; using System.Linq; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; +using System.Windows; namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex { @@ -84,22 +86,36 @@ internal static async Task> ExecuteWindowsIndexSearchAsync(string i return results; } - internal async static Task> WindowsIndexSearchAsync(string searchString, string connectionString, - Func constructQuery, - List exclusionList, - Query query, - CancellationToken token) + internal async static Task> WindowsIndexSearchAsync( + string searchString, + CSearchQueryHelper queryHelper, + Func constructQuery, + List exclusionList, + Query query, + CancellationToken token) { var regexMatch = Regex.Match(searchString, reservedStringPattern); if (regexMatch.Success) return new List(); + + try + { + var constructedQuery = constructQuery(searchString); - var constructedQuery = constructQuery(searchString); - return RemoveResultsInExclusionList( - await ExecuteWindowsIndexSearchAsync(constructedQuery, connectionString, query, token).ConfigureAwait(false), + return RemoveResultsInExclusionList( + await ExecuteWindowsIndexSearchAsync(constructedQuery, queryHelper.ConnectionString, query, token).ConfigureAwait(false), exclusionList, token); + } + catch (COMException) + { + // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin + if (!SearchManager.Settings.WarnWindowsSearchServiceOff) + return new List(); + + return ResultForWindexSearchOff(query.RawQuery); + } } private static List RemoveResultsInExclusionList(List results, List exclusionList, CancellationToken token) @@ -137,9 +153,66 @@ private static List RemoveResultsInExclusionList(List results, L internal static bool PathIsIndexed(string path) { - var csm = new CSearchManager(); - var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager(); - return indexManager.IncludedInCrawlScope(path) > 0; + try + { + var csm = new CSearchManager(); + var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager(); + return indexManager.IncludedInCrawlScope(path) > 0; + } + catch(COMException) + { + // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin + return false; + } + } + + private static List ResultForWindexSearchOff(string rawQuery) + { + var api = SearchManager.Context.API; + + return new List + { + new Result + { + Title = api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"), + SubTitle = api.GetTranslation("plugin_explorer_windowsSearchServiceFix"), + Action = c => + { + SearchManager.Settings.WarnWindowsSearchServiceOff = false; + + var pluginsManagerPlugin= api.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == "9f8f9b14-2518-4907-b211-35ab6290dee7"); + + var actionKeywordCount = pluginsManagerPlugin.Metadata.ActionKeywords.Count; + + if (actionKeywordCount > 1) + LogException("PluginsManager's action keyword has increased to more than 1, this does not allow for determining the " + + "right action keyword. Explorer's code for managing Windows Search service not running exception needs to be updated", + new InvalidOperationException()); + + if (MessageBox.Show(string.Format(api.GetTranslation("plugin_explorer_alternative"), Environment.NewLine), + api.GetTranslation("plugin_explorer_alternative_title"), + MessageBoxButton.YesNo) == MessageBoxResult.Yes + && actionKeywordCount == 1) + { + api.ChangeQuery(string.Format("{0} install everything", pluginsManagerPlugin.Metadata.ActionKeywords[0])); + } + else + { + // Clears the warning message because same query string will not alter the displayed result list + api.ChangeQuery(string.Empty); + + api.ChangeQuery(rawQuery); + } + + var mainWindow = Application.Current.MainWindow; + mainWindow.Visibility = Visibility.Visible; + mainWindow.Focus(); + + return false; + }, + IcoPath = Constants.ExplorerIconImagePath + } + }; } private static void LogException(string message, Exception e) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 13f938dea1c..88656a40172 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,4 +1,4 @@ -using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; using Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption; using System; @@ -33,6 +33,8 @@ public class Settings public bool IndexOnlySearchKeywordEnabled { get; set; } + public bool WarnWindowsSearchServiceOff { get; set; } = true; + internal enum ActionKeyword { SearchActionKeyword, diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json index 5bd49949f48..59a31ec139c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json @@ -9,7 +9,7 @@ "Name": "Explorer", "Description": "Search and manage files and folders. Explorer utilises Windows Index Search", "Author": "Jeremy Wu", - "Version": "1.8.0", + "Version": "1.8.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll", diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs index 90ce19db44a..364216778bd 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs @@ -17,7 +17,8 @@ public ContextMenu(PluginInitContext context) public List LoadContextMenus(Result selectedResult) { - var pluginManifestInfo = selectedResult.ContextData as UserPlugin; + if(selectedResult.ContextData is not UserPlugin pluginManifestInfo) + return new List(); return new List { diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 1aa39469b11..995ac0fedfe 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -269,7 +269,13 @@ await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath) } return false; - } + }, + ContextData = + new UserPlugin + { + Website = x.PluginNewUserPlugin.Website, + UrlSourceCode = x.PluginNewUserPlugin.UrlSourceCode + } }); return Search(results, uninstallSearch); diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json b/Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json index 2555466860f..fa916a29d03 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.8.3", + "Version": "1.8.4", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll", diff --git a/README.md b/README.md index e9c7e33606f..e89558d5705 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,8 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be ### Installation -| [Windows 7 and up installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) | `WinGet install "Flow Launcher"` | -| -------------------------------------------------------------------------------------------- | -------------------------------- | +| [Windows 7 and up installer](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest) | [Portable](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest/download/Flow-Launcher-Portable.zip) | `WinGet install "Flow Launcher"` | +| --------------------------------- | --------------------------------- | --------------------------------- | 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. diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index 093f92768b4..b573b984b64 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -107,6 +107,13 @@ function Publish-Self-Contained ($p) { dotnet publish -c Release $csproj /p:PublishProfile=$profile } +function Publish-Portable ($outputLocation, $version) { + + & $outputLocation\Flow-Launcher-v$v.exe --silent | Out-Null + mkdir "$env:LocalAppData\FlowLauncher\app-$version\UserData" + Compress-Archive -Path $env:LocalAppData\FlowLauncher -DestinationPath $outputLocation\Flow-Launcher-Portable.zip +} + function Main { $p = Build-Path $v = Build-Version @@ -123,6 +130,8 @@ function Main { $o = "$p\Output\Packages" Validate-Directory $o Pack-Squirrel-Installer $p $v $o + + Publish-Portable $o $v } } diff --git a/appveyor.yml b/appveyor.yml index 9961a9111e8..191ee480332 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.8.0.{build}' +version: '1.8.1.{build}' init: - ps: | @@ -36,6 +36,8 @@ artifacts: name: Plugin nupkg - path: 'Output\Packages\Flow-Launcher-*.exe' name: Squirrel Installer +- path: Output\Packages\Flow-Launcher-Portable.zip + name: Portable Version - path: 'Output\Packages\FlowLauncher-*-full.nupkg' name: Squirrel nupkg - path: 'Output\Packages\RELEASES' @@ -47,13 +49,13 @@ deploy: api_key: secure: n80IeWR3pN81p0w4uXq4mO0TdTXoJSHHFL+yTB9YBJ0Wni2DjZGYwOFdaWzW4hRi on: - branch: master + APPVEYOR_REPO_TAG: true - provider: GitHub release: v$(flowVersion) auth_token: secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv - artifact: Squirrel Installer, Squirrel nupkg, Squirrel RELEASES + artifact: Squirrel Installer, Portable Version, Squirrel nupkg, Squirrel RELEASES draft: true force_update: true on: @@ -63,7 +65,19 @@ deploy: release: v$(flowVersion) auth_token: secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv - artifact: Squirrel Installer, Squirrel nupkg, Squirrel RELEASES + artifact: Squirrel Installer, Portable Version, Squirrel nupkg, Squirrel RELEASES force_update: true on: APPVEYOR_REPO_TAG: true + +environment: + winget_token: + secure: HKfVT2FYZITAG0qqMCePYhIem5a/gzvAgYDSlr6RlXfGmeBUOANUtgJ9X6fNroxN + +on_success: + - ps: | + if ($env:APPVEYOR_REPO_BRANCH -eq "master" -and $env:APPVEYOR_REPO_TAG -eq "true") + { + iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe + .\wingetcreate.exe update Flow-Launcher.Flow-Launcher -s true -u https://github.com/Flow-Launcher/Flow.Launcher/releases/download/v$env:flowVersion/Flow-Launcher-v$env:flowVersion.exe -v $env:flowVersion -t $env:winget_token + }