diff --git a/.github/workflows/default_plugins.yml b/.github/workflows/default_plugins.yml index 83e830d75..381044c51 100644 --- a/.github/workflows/default_plugins.yml +++ b/.github/workflows/default_plugins.yml @@ -10,7 +10,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup .NET uses: actions/setup-dotnet@v5 with: diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 957f836bb..0659ae645 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -20,7 +20,7 @@ jobs: NUGET_CERT_REVOCATION_MODE: offline BUILD_NUMBER: ${{ github.run_number }} steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set Flow.Launcher.csproj version id: update uses: vers-one/dotnet-project-version-updater@v1.7 @@ -54,28 +54,28 @@ jobs: shell: powershell run: .\Scripts\post_build.ps1 - name: Upload Plugin Nupkg - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: Plugin nupkg path: | Output\Release\Flow.Launcher.Plugin.*.nupkg compression-level: 0 - name: Upload Setup - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: Flow Installer path: | Output\Packages\Flow-Launcher-*.exe compression-level: 0 - name: Upload Portable Version - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: Portable Version path: | Output\Packages\Flow-Launcher-Portable.zip compression-level: 0 - name: Upload Full Nupkg - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: Full nupkg path: | @@ -83,7 +83,7 @@ jobs: compression-level: 0 - name: Upload Release Information - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v6 with: name: RELEASES path: | diff --git a/.github/workflows/pr_assignee.yml b/.github/workflows/pr_assignee.yml index 5be603df6..33098672b 100644 --- a/.github/workflows/pr_assignee.yml +++ b/.github/workflows/pr_assignee.yml @@ -14,4 +14,4 @@ jobs: runs-on: ubuntu-latest steps: - name: Assign PR to creator - uses: toshimaru/auto-author-assign@v2.1.1 + uses: toshimaru/auto-author-assign@v3.0.1 diff --git a/.github/workflows/release_pr.yml b/.github/workflows/release_pr.yml index 58a877ba3..c7e9a90a6 100644 --- a/.github/workflows/release_pr.yml +++ b/.github/workflows/release_pr.yml @@ -11,7 +11,7 @@ jobs: update-pr: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - uses: actions/setup-python@v6 with: diff --git a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs index eab9a8c43..4fed10d25 100644 --- a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs +++ b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs @@ -26,9 +26,11 @@ namespace Flow.Launcher.Core.ExternalPlugins public static async Task UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default) { + bool lockAcquired = false; try { await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false); + lockAcquired = true; if (UserPlugins == null || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout) { @@ -54,13 +56,18 @@ namespace Flow.Launcher.Core.ExternalPlugins return true; } } + catch (OperationCanceledException) + { + // Ignored + } catch (Exception e) { PublicApi.Instance.LogException(ClassName, "Http request failed", e); } finally { - manifestUpdateLock.Release(); + // Only release the lock if it was acquired + if (lockAcquired) manifestUpdateLock.Release(); } return false; diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs index 148fd969e..470019143 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs @@ -100,11 +100,11 @@ namespace Flow.Launcher.Core.Plugin RPC = new JsonRpc(handler, new JsonRPCPublicAPI(Context.API)); - RPC.AddLocalRpcMethod("UpdateResults", new Action((rawQuery, response) => + RPC.AddLocalRpcMethod("UpdateResults", new Action((trimmedQuery, response) => { var results = ParseResults(response); ResultsUpdated?.Invoke(this, - new ResultUpdatedEventArgs { Query = new Query() { RawQuery = rawQuery }, Results = results }); + new ResultUpdatedEventArgs { Query = new Query() { TrimmedQuery = trimmedQuery }, Results = results }); })); RPC.SynchronizationContext = null; RPC.StartListening(); diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index d3a8003c1..54712942c 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -401,7 +401,7 @@ namespace Flow.Launcher.Core.Plugin { Title = Localize.pluginStillInitializing(metadata.Name), SubTitle = Localize.pluginStillInitializingSubtitle(), - AutoCompleteText = query.RawQuery, + AutoCompleteText = query.TrimmedQuery, IcoPath = metadata.IcoPath, PluginDirectory = metadata.PluginDirectory, ActionKeywordAssigned = query.ActionKeyword, @@ -443,7 +443,7 @@ namespace Flow.Launcher.Core.Plugin { Title = Localize.pluginFailedToRespond(metadata.Name), SubTitle = Localize.pluginFailedToRespondSubtitle(), - AutoCompleteText = query.RawQuery, + AutoCompleteText = query.TrimmedQuery, IcoPath = Constant.ErrorIcon, PluginDirectory = metadata.PluginDirectory, ActionKeywordAssigned = query.ActionKeyword, @@ -467,7 +467,7 @@ namespace Flow.Launcher.Core.Plugin { Title = Localize.pluginStillInitializing(metadata.Name), SubTitle = Localize.pluginStillInitializingSubtitle(), - AutoCompleteText = query.RawQuery, + AutoCompleteText = query.TrimmedQuery, IcoPath = metadata.IcoPath, PluginDirectory = metadata.PluginDirectory, ActionKeywordAssigned = query.ActionKeyword, diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs index 25a32a728..aac620cce 100644 --- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs +++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs @@ -6,15 +6,16 @@ namespace Flow.Launcher.Core.Plugin { public static class QueryBuilder { - public static Query Build(string text, Dictionary nonGlobalPlugins) + public static Query Build(string originalQuery, string trimmedQuery, Dictionary nonGlobalPlugins) { // home query - if (string.IsNullOrEmpty(text)) + if (string.IsNullOrEmpty(trimmedQuery)) { return new Query() { Search = string.Empty, - RawQuery = string.Empty, + OriginalQuery = string.Empty, + TrimmedQuery = string.Empty, SearchTerms = Array.Empty(), ActionKeyword = string.Empty, IsHomeQuery = true @@ -22,14 +23,13 @@ namespace Flow.Launcher.Core.Plugin } // replace multiple white spaces with one white space - var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries); + var terms = trimmedQuery.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries); if (terms.Length == 0) { // nothing was typed return null; } - var rawQuery = text; string actionKeyword, search; string possibleActionKeyword = terms[0]; string[] searchTerms; @@ -38,21 +38,22 @@ namespace Flow.Launcher.Core.Plugin { // use non global plugin for query actionKeyword = possibleActionKeyword; - search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty; + search = terms.Length > 1 ? trimmedQuery[(actionKeyword.Length + 1)..].TrimStart() : string.Empty; searchTerms = terms[1..]; } else { // non action keyword actionKeyword = string.Empty; - search = rawQuery.TrimStart(); + search = trimmedQuery.TrimStart(); searchTerms = terms; } return new Query() { Search = search, - RawQuery = rawQuery, + OriginalQuery = originalQuery, + TrimmedQuery = trimmedQuery, SearchTerms = searchTerms, ActionKeyword = actionKeyword, IsHomeQuery = false diff --git a/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs b/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs index 4a3e6474e..53df05bf2 100644 --- a/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs +++ b/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs @@ -496,6 +496,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump uint dwmsEventTime ) { + if (hwnd.IsNull) return; + await _foregroundChangeLock.WaitAsync(); try { @@ -647,6 +649,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump uint dwmsEventTime ) { + if (hwnd.IsNull) return; + // If the dialog window is moved, update the Dialog Jump window position var dialogWindowExist = false; lock (_dialogWindowLock) @@ -672,6 +676,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump uint dwmsEventTime ) { + if (hwnd.IsNull) return; + // If the dialog window is moved or resized, update the Dialog Jump window position if (_dragMoveTimer != null) { @@ -697,6 +703,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump uint dwmsEventTime ) { + if (hwnd.IsNull) return; + // If the dialog window is destroyed, set _dialogWindowHandle to null var dialogWindowExist = false; lock (_dialogWindowLock) @@ -728,6 +736,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump uint dwmsEventTime ) { + if (hwnd.IsNull) return; + // If the dialog window is hidden, set _dialogWindowHandle to null var dialogWindowExist = false; lock (_dialogWindowLock) @@ -759,6 +769,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump uint dwmsEventTime ) { + if (hwnd.IsNull) return; + // If the dialog window is ended, set _dialogWindowHandle to null var dialogWindowExist = false; lock (_dialogWindowLock) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index cd072f635..8c5633cfe 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -91,4 +91,6 @@ PBT_APMRESUMEAUTOMATIC PBT_APMRESUMESUSPEND PowerRegisterSuspendResumeNotification PowerUnregisterSuspendResumeNotification -DeviceNotifyCallbackRoutine \ No newline at end of file +DeviceNotifyCallbackRoutine + +MonitorFromWindow \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 1c0cc6872..7f55d8909 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -27,7 +27,7 @@ namespace Flow.Launcher.Infrastructure { switch (e.PropertyName) { - case nameof (Settings.ShouldUsePinyin): + case nameof(Settings.ShouldUsePinyin): if (_settings.ShouldUsePinyin) { Reload(); @@ -52,7 +52,7 @@ namespace Flow.Launcher.Infrastructure private void CreateDoublePinyinTableFromStream(Stream jsonStream) { - var table = JsonSerializer.Deserialize>>(jsonStream) ?? + var table = JsonSerializer.Deserialize>>(jsonStream) ?? throw new InvalidOperationException("Failed to deserialize double pinyin table: result is null"); var schemaKey = _settings.DoublePinyinSchema.ToString(); @@ -128,12 +128,12 @@ namespace Flow.Launcher.Infrastructure if (IsChineseCharacter(content[i])) { var translated = _settings.UseDoublePinyin ? ToDoublePinyin(resultList[i]) : resultList[i]; - - if (i > 0) + + if (i > 0 && content[i - 1] != ' ') { resultBuilder.Append(' '); } - + map.AddNewIndex(resultBuilder.Length, translated.Length); resultBuilder.Append(translated); previousIsChinese = true; @@ -144,11 +144,14 @@ namespace Flow.Launcher.Infrastructure if (previousIsChinese) { previousIsChinese = false; - resultBuilder.Append(' '); + if (content[i] != ' ') + { + resultBuilder.Append(' '); + } } - - map.AddNewIndex(resultBuilder.Length, resultList[i].Length); - resultBuilder.Append(resultList[i]); + + map.AddNewIndex(resultBuilder.Length, 1); + resultBuilder.Append(content[i]); } } @@ -156,7 +159,7 @@ namespace Flow.Launcher.Infrastructure var translation = resultBuilder.ToString(); var result = (translation, map); - + return _pinyinCache[content] = result; } @@ -185,8 +188,8 @@ namespace Flow.Launcher.Infrastructure private string ToDoublePinyin(string fullPinyin) { - return currentDoublePinyinTable.TryGetValue(fullPinyin, out var doublePinyinValue) - ? doublePinyinValue + return currentDoublePinyinTable.TryGetValue(fullPinyin, out var doublePinyinValue) + ? doublePinyinValue : fullPinyin; } } diff --git a/Flow.Launcher.Infrastructure/TranslationMapping.cs b/Flow.Launcher.Infrastructure/TranslationMapping.cs index b4c6764df..e70443077 100644 --- a/Flow.Launcher.Infrastructure/TranslationMapping.cs +++ b/Flow.Launcher.Infrastructure/TranslationMapping.cs @@ -21,7 +21,7 @@ namespace Flow.Launcher.Infrastructure public int MapToOriginalIndex(int translatedIndex) { var searchResult = _originalToTranslated.BinarySearch(translatedIndex); - return searchResult >= 0 ? searchResult : ~searchResult; + return searchResult >= 0 ? searchResult + 1 : ~searchResult; } public void EndConstruct() diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 6adefdb6a..7524d6c1a 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -481,6 +481,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings } public bool LeaveCmdOpen { get; set; } public bool HideWhenDeactivated { get; set; } = true; + public bool ShowTaskbarWhenInvoked { get; set; } = false; private bool _showAtTopmost = false; public bool ShowAtTopmost diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 8a41e12b4..635a43354 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -1016,5 +1016,32 @@ namespace Flow.Launcher.Infrastructure } #endregion + + #region Taskbar + + public static unsafe void ShowTaskbar() + { + // Find the taskbar window + var taskbarHwnd = PInvoke.FindWindowEx(HWND.Null, HWND.Null, "Shell_TrayWnd", null); + if (taskbarHwnd == HWND.Null) return; + + // Magic from https://github.com/Oliviaophia/SmartTaskbar + const uint TrayBarFlag = 0x05D1; + var mon = PInvoke.MonitorFromWindow(taskbarHwnd, Windows.Win32.Graphics.Gdi.MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST); + PInvoke.PostMessage(taskbarHwnd, TrayBarFlag, new WPARAM(1), new LPARAM((nint)mon.Value)); + } + + public static void HideTaskbar() + { + // Find the taskbar window + var taskbarHwnd = PInvoke.FindWindowEx(HWND.Null, HWND.Null, "Shell_TrayWnd", null); + if (taskbarHwnd == HWND.Null) return; + + // Magic from https://github.com/Oliviaophia/SmartTaskbar + const uint TrayBarFlag = 0x05D1; + PInvoke.PostMessage(taskbarHwnd, TrayBarFlag, new WPARAM(0), IntPtr.Zero); + } + + #endregion } } diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index f50614699..79e6f7d62 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System; +using System.Text.Json.Serialization; namespace Flow.Launcher.Plugin { @@ -8,11 +9,29 @@ namespace Flow.Launcher.Plugin public class Query { /// - /// Raw query, this includes action keyword if it has. - /// It has handled buildin custom query shortkeys and build-in shortcuts, and it trims the whitespace. - /// We didn't recommend use this property directly. You should always use Search property. + /// Original query, exactly how the user has typed into the search box. + /// We don't recommend using this property directly. You should always use Search property. /// - public string RawQuery { get; internal init; } + public string OriginalQuery { get; internal init; } + + /// + /// Raw query, this includes action keyword if it has. + /// It has handled built-in custom query hotkeys and built-in shortcuts, and it trims the whitespace. + /// We don't recommend using this property directly. You should always use Search property. + /// + [Obsolete("RawQuery is renamed to TrimmedQuery. This property will be removed. Update the code to use TrimmedQuery instead.")] + public string RawQuery { + get => TrimmedQuery; + internal init { TrimmedQuery = value; } + } + + /// + /// Original query but with trimmed whitespace. Includes action keyword. + /// It has handled built-in custom query hotkeys and build-in shortcuts. + /// If you need the exact original query from the search box, use OriginalQuery property instead. + /// We don't recommend using this property directly. You should always use Search property. + /// + public string TrimmedQuery { get; internal init; } /// /// Determines whether the query was forced to execute again. @@ -28,7 +47,7 @@ namespace Flow.Launcher.Plugin /// /// Search part of a query. - /// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as RawQuery. + /// This will not include action keyword if exclusive plugin gets it, otherwise it should be same as TrimmedQuery. /// Since we allow user to switch a exclusive plugin to generic plugin, /// so this property will always give you the "real" query part of the query /// @@ -103,6 +122,6 @@ namespace Flow.Launcher.Plugin } /// - public override string ToString() => RawQuery; + public override string ToString() => TrimmedQuery; } } diff --git a/Flow.Launcher.Test/QueryBuilderTest.cs b/Flow.Launcher.Test/QueryBuilderTest.cs index c8ac17748..0ede781f8 100644 --- a/Flow.Launcher.Test/QueryBuilderTest.cs +++ b/Flow.Launcher.Test/QueryBuilderTest.cs @@ -16,9 +16,9 @@ namespace Flow.Launcher.Test {">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List {">"}}}} }; - Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins); + Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins); - ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.RawQuery); + ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.TrimmedQuery); ClassicAssert.AreEqual("ping google.com -n 20 -6", q.Search, "Search should not start with the ActionKeyword."); ClassicAssert.AreEqual(">", q.ActionKeyword); @@ -39,10 +39,10 @@ namespace Flow.Launcher.Test {">", new PluginPair {Metadata = new PluginMetadata {ActionKeywords = new List {">"}, Disabled = true}}} }; - Query q = QueryBuilder.Build("> ping google.com -n 20 -6", nonGlobalPlugins); + Query q = QueryBuilder.Build("> ping google.com -n 20 -6", "> ping google.com -n 20 -6", nonGlobalPlugins); ClassicAssert.AreEqual("> ping google.com -n 20 -6", q.Search); - ClassicAssert.AreEqual(q.Search, q.RawQuery, "RawQuery should be equal to Search."); + ClassicAssert.AreEqual(q.Search, q.TrimmedQuery, "TrimmedQuery should be equal to Search."); ClassicAssert.AreEqual(6, q.SearchTerms.Length, "The length of SearchTerms should match."); ClassicAssert.AreNotEqual(">", q.ActionKeyword, "ActionKeyword should not match that of a disabled plugin."); ClassicAssert.AreEqual("ping google.com -n 20 -6", q.SecondToEndSearch, "SecondToEndSearch should be trimmed of multiple whitespace characters"); @@ -51,7 +51,7 @@ namespace Flow.Launcher.Test [Test] public void GenericPluginQueryTest() { - Query q = QueryBuilder.Build("file.txt file2 file3", new Dictionary()); + Query q = QueryBuilder.Build("file.txt file2 file3", "file.txt file2 file3", new Dictionary()); ClassicAssert.AreEqual("file.txt file2 file3", q.Search); ClassicAssert.AreEqual("", q.ActionKeyword); diff --git a/Flow.Launcher.Test/TranslationMappingTest.cs b/Flow.Launcher.Test/TranslationMappingTest.cs index bd3636f0a..a3c0026c0 100644 --- a/Flow.Launcher.Test/TranslationMappingTest.cs +++ b/Flow.Launcher.Test/TranslationMappingTest.cs @@ -22,19 +22,33 @@ namespace Flow.Launcher.Test ClassicAssert.AreEqual(10, GetOriginalToTranslatedAt(mapping, 1)); } - [TestCase(0, 0)] - [TestCase(2, 1)] - [TestCase(3, 1)] - [TestCase(5, 2)] - [TestCase(6, 2)] + + [TestCase(0, 0)] // "F" -> "F" + [TestCase(1, 1)] // "l" -> "l" + [TestCase(2, 2)] // "o" -> "o" + [TestCase(3, 3)] // "w" -> "w" + [TestCase(4, 4)] // " " -> " " + [TestCase(5, 5)] // "Y" (translated from "用") -> original index 5 + [TestCase(6, 5)] // "o" (translated from "用") -> original index 5 + [TestCase(7, 5)] // "n" (translated from "用") -> original index 5 + [TestCase(8, 5)] // "g" (translated from "用") -> original index 5 + [TestCase(10, 6)] // "H" (translated from "户") -> original index 6 + [TestCase(11, 6)] // "u" (translated from "户") -> original index 6 public void MapToOriginalIndex_ShouldReturnExpectedIndex(int translatedIndex, int expectedOriginalIndex) { var mapping = new TranslationMapping(); - // a测试 - // a Ce Shi - mapping.AddNewIndex(0, 1); - mapping.AddNewIndex(2, 2); - mapping.AddNewIndex(5, 3); + // Test case : + // 0123456 + // Flow 用户 + // 012345678901 + // Flow Yong Hu + mapping.AddNewIndex(0, 1); // F + mapping.AddNewIndex(1, 1); // l + mapping.AddNewIndex(2, 1); // o + mapping.AddNewIndex(3, 1); // w + mapping.AddNewIndex(4, 1); // ' ' + mapping.AddNewIndex(5, 4); // 用 -> Yong + mapping.AddNewIndex(10, 2); // 户 -> Hu var result = mapping.MapToOriginalIndex(translatedIndex); ClassicAssert.AreEqual(expectedOriginalIndex, result); diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 576bf6f2f..f3c614702 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -138,7 +138,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/Flow.Launcher/Helper/ErrorReporting.cs b/Flow.Launcher/Helper/ErrorReporting.cs index e201284cb..797f31482 100644 --- a/Flow.Launcher/Helper/ErrorReporting.cs +++ b/Flow.Launcher/Helper/ErrorReporting.cs @@ -16,6 +16,15 @@ public static class ErrorReporting var logger = LogManager.GetLogger(methodName); logger.Fatal(ExceptionFormatter.FormatExcpetion(e)); if (silent) return; + + // Workaround for issue https://github.com/Flow-Launcher/Flow.Launcher/issues/4016 + // The crash occurs in PresentationFramework.dll, not necessarily when the Runner UI is visible, originating from this line: + // https://github.com/dotnet/wpf/blob/3439f20fb8c685af6d9247e8fd2978cac42e74ac/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Shell/WindowChromeWorker.cs#L1005 + // Many bug reports because users see the "Error report UI" after the crash with System.Runtime.InteropServices.COMException 0xD0000701 or 0x80263001. + // However, displaying this "Error report UI" during WPF crashes, especially when DWM composition is changing, is not ideal; some users reported it hangs for up to a minute before the it appears. + // This change modifies the behavior to log the exception instead of showing the "Error report UI". + if (ExceptionHelper.IsRecoverableDwmCompositionException(e)) return; + var reportWindow = new ReportWindow(e); reportWindow.Show(); } diff --git a/Flow.Launcher/Helper/ExceptionHelper.cs b/Flow.Launcher/Helper/ExceptionHelper.cs new file mode 100644 index 000000000..5dd57f9bb --- /dev/null +++ b/Flow.Launcher/Helper/ExceptionHelper.cs @@ -0,0 +1,42 @@ +// This is a direct copy of the file at https://github.com/microsoft/PowerToys/blob/main/src/modules/launcher/PowerLauncher/Helper/ExceptionHelper.cs and adapted for flow. + +using System; +using System.Runtime.InteropServices; + +namespace Flow.Launcher.Helper; + +internal static class ExceptionHelper +{ + private const string PresentationFrameworkExceptionSource = "PresentationFramework"; + + private const int DWM_E_COMPOSITIONDISABLED = unchecked((int)0x80263001); + + // HRESULT for NT STATUS STATUS_MESSAGE_LOST (0xC0000701 | 0x10000000 == 0xD0000701) + private const int STATUS_MESSAGE_LOST_HR = unchecked((int)0xD0000701); + + /// + /// Returns true if the exception is a recoverable DWM composition exception. + /// + internal static bool IsRecoverableDwmCompositionException(Exception exception) + { + if (exception is not COMException comException) + { + return false; + } + + if (comException.HResult is DWM_E_COMPOSITIONDISABLED) + { + return true; + } + + if (comException.HResult is STATUS_MESSAGE_LOST_HR && comException.Source == PresentationFrameworkExceptionSource) + { + return true; + } + + // Check for common DWM composition changed patterns in the stack trace + var stackTrace = comException.StackTrace; + return !string.IsNullOrEmpty(stackTrace) && + stackTrace.Contains("DwmCompositionChanged", StringComparison.OrdinalIgnoreCase); + } +} diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs index bb1cddc6c..0a2826484 100644 --- a/Flow.Launcher/Helper/HotKeyMapper.cs +++ b/Flow.Launcher/Helper/HotKeyMapper.cs @@ -143,6 +143,8 @@ internal static class HotKeyMapper return; App.API.ShowMainWindow(); + // Make sure to go back to the query results page first since it can cause issues if current page is context menu + App.API.BackToQueryResults(); App.API.ChangeQuery(hotkey.ActionKeyword, true); }); } diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs index d0cf2dddc..82211242b 100644 --- a/Flow.Launcher/Helper/ResultHelper.cs +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -16,11 +16,11 @@ public static class ResultHelper return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey); } - public static async Task PopulateResultsAsync(string pluginId, string rawQuery, string title, string subTitle, string recordKey) + public static async Task PopulateResultsAsync(string pluginId, string trimmedQuery, string title, string subTitle, string recordKey) { var plugin = PluginManager.GetPluginForId(pluginId); if (plugin == null) return null; - var query = QueryBuilder.Build(rawQuery, PluginManager.GetNonGlobalPlugins()); + var query = QueryBuilder.Build(trimmedQuery, trimmedQuery, PluginManager.GetNonGlobalPlugins()); if (query == null) return null; try { diff --git a/Flow.Launcher/Languages/ar.xaml b/Flow.Launcher/Languages/ar.xaml index 7dcfcdb09..67f1f766e 100644 --- a/Flow.Launcher/Languages/ar.xaml +++ b/Flow.Launcher/Languages/ar.xaml @@ -64,6 +64,10 @@ إعادة تعيين الموقع Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info الإعدادات @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ الأيقونات لقد قمت بتفعيل Flow Launcher {0} مرات التحقق من التحديثات - كن راعيا + Become a Sponsor الإصدار الجديد {0} متاح، هل ترغب في إعادة تشغيل Flow Launcher لاستخدام التحديث فشل التحقق من التحديثات، يرجى التحقق من الاتصال وإعدادات البروكسي لـ api.github.com. diff --git a/Flow.Launcher/Languages/cs.xaml b/Flow.Launcher/Languages/cs.xaml index d08653a04..96cbe95e7 100644 --- a/Flow.Launcher/Languages/cs.xaml +++ b/Flow.Launcher/Languages/cs.xaml @@ -64,6 +64,10 @@ Obnovit pozici Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Nastavení @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Ikony Flow Launcher byl aktivován {0} krát Zkontrolovat Aktualizace - Staňte se sponzorem + Become a Sponsor Je k dispozici nová verze {0}, chcete Flow Launcher restartovat, aby se mohl aktualizovat? Hledání aktualizací se nezdařilo, zkontrolujte prosím své internetové připojení a nastavení proxy serveru k api.github.com. diff --git a/Flow.Launcher/Languages/da.xaml b/Flow.Launcher/Languages/da.xaml index 7ad686fe8..a1fc771d2 100644 --- a/Flow.Launcher/Languages/da.xaml +++ b/Flow.Launcher/Languages/da.xaml @@ -64,6 +64,10 @@ Position Reset Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Indstillinger @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Icons Du har aktiveret Flow Launcher {0} gange Tjek for opdateringer - Become A Sponsor + Become a Sponsor Ny version {0} er tilgængelig, genstart venligst Flow Launcher Check updates failed, please check your connection and proxy settings to api.github.com. diff --git a/Flow.Launcher/Languages/de.xaml b/Flow.Launcher/Languages/de.xaml index 064ac4038..2c083646f 100644 --- a/Flow.Launcher/Languages/de.xaml +++ b/Flow.Launcher/Languages/de.xaml @@ -64,6 +64,10 @@ Zurücksetzen der Position Position des Suchfensters zurücksetzen Zum Suchen hier tippen + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Einstellungen @@ -171,6 +175,10 @@ Ergebnisse der Homepage zeigen, wenn Abfragetext leer ist. Historie-Ergebnisse auf Homepage zeigen Maximal gezeigte Historie-Ergebnisse auf Homepage + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history Dies kann nur bearbeitet werden, wenn das Plug-in das Home-Feature unterstützt und die Homepage aktiviert ist. Suchfenster an vorderster zeigen Setzt die Einstellung 'Immer im Vordergrund' anderer Programme außer Kraft und zeigt Flow in der vordersten Position an. @@ -446,7 +454,7 @@ Icons Sie haben Flow Launcher {0} mal aktiviert Nach Updates suchen - Ein Sponsor werden + Become a Sponsor Neue Version {0} ist verfügbar. Möchten Sie Flow Launcher neu starten, um das Update zu verwenden? Überprüfung der Updates fehlgeschlagen. Bitte überprüfen Sie Ihre Verbindungs- und Proxy-Einstellungen zu api.github.com. diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 548441416..145e1883d 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -81,6 +81,8 @@ After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler Error setting launch on startup Hide Flow Launcher when focus is lost + Show taskbar when Flow Launcher is opened + Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars. Do not show new version notifications Search Window Location Remember Last Position @@ -449,7 +451,7 @@ Icons You have activated Flow Launcher {0} times Check for Updates - Become A Sponsor + Become a Sponsor New version {0} is available, would you like to restart Flow Launcher to use the update? Check updates failed, please check your connection and proxy settings to api.github.com. diff --git a/Flow.Launcher/Languages/es-419.xaml b/Flow.Launcher/Languages/es-419.xaml index 8554f3847..9f06c4436 100644 --- a/Flow.Launcher/Languages/es-419.xaml +++ b/Flow.Launcher/Languages/es-419.xaml @@ -64,6 +64,10 @@ Position Reset Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Ajustes @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Icons Has activado Flow Launcher {0} veces Buscar actualizaciones - Become A Sponsor + Become a Sponsor La nueva versión {0} está disponible, ¿desea reiniciar Flow Launcher para usar la actualización? Falló la comprobación de actualizaciones, compruebe su conexión y configuración de proxy a api.github.com. diff --git a/Flow.Launcher/Languages/es.xaml b/Flow.Launcher/Languages/es.xaml index be00fac94..f7a3fbb22 100644 --- a/Flow.Launcher/Languages/es.xaml +++ b/Flow.Launcher/Languages/es.xaml @@ -64,6 +64,10 @@ Restablecer posición Restablece la posición de la ventana de búsqueda Escribir aquí para buscar + {0}: Este complemento aún se está inicializando... + Seleccione este resultado para volver a realizar la consulta + {0}: ¡No se ha recibido respuesta! + Seleccione este resultado para más información Configuración @@ -171,6 +175,10 @@ Muestra los resultados de la página de inicio cuando el texto de la consulta está vacío. Mostrar historial de resultados en la página de inicio Número máximo de resultados del historial en la página de inicio + Estilo del historial + Elija el tipo de historial que desea mostrar en el historial y la página de inicio + Historial de consultas + Historial de últimas aperturas Esto solo se puede editar si el complemento soporta la función de Inicio y la Página de Inicio está activada. Mostrar ventana de búsqueda en primer plano Anula el ajuste «Siempre arriba» de otros programas y muestra Flow en primer plano. @@ -446,7 +454,7 @@ Iconos Ha activado Flow Launcher {0} veces Buscar actualizaciones - Hágase Patrocinador + Conviértase en Patrocinador La nueva versión {0} está disponible, ¿desea reiniciar Flow Launcher para actualizar? Ha fallado la comprobación de las actualizaciones, por favor, compruebe la configuración de su proxy y conexión a api.github.com. diff --git a/Flow.Launcher/Languages/fr.xaml b/Flow.Launcher/Languages/fr.xaml index b9ac0de4b..bdce6ddb9 100644 --- a/Flow.Launcher/Languages/fr.xaml +++ b/Flow.Launcher/Languages/fr.xaml @@ -64,6 +64,10 @@ Réinitialiser la position Réinitialiser la position de la fenêtre de recherche Tapez ici pour rechercher + {0}: Ce plugin est toujours en cours d'initialisation... + Sélectionner ce résultat pour la requête + {0}: Ne répond pas ! + Sélectionnez ce résultat pour plus d'informations Paramètres @@ -171,6 +175,10 @@ Afficher les résultats de la page d'accueil lorsque le texte de la requête est vide. Afficher les résultats de l'historique sur la page d'accueil Maximum de résultats de l'historique affichés sur la page d'accueil + Style d'historique + Choisissez le type d'historique à afficher dans l'historique et la page d'accueil + Historique des requêtes + Historique des dernières ouvertures Ceci ne peut être édité que si le plugin prend en charge la fonction Accueil et que la page d'accueil est activée. Afficher la fenêtre de recherche en premier plan Outrepasse le paramètre 'toujours en premier plan' des autres programmes et affiche Flow Launcher en première position. @@ -399,24 +407,24 @@ Pour les plugins pris en charge, des badges sont affichés afin de les distinguer plus facilement. Afficher les badges de résultats pour la requête globale uniquement Afficher les badges pour les résultats des requêtes globales uniquement - Dialog Jump + Saut de dialogue Entrez le raccourci pour naviguer rapidement dans la fenêtre de dialogue Ouvrir/Enregistrer sous, vers le chemin du gestionnaire de fichiers actuel. - Dialog Jump + Saut de dialogue Lorsque la fenêtre de dialogue Ouvrir/Enregistrer sous s'ouvre, accédez rapidement au chemin d'accès actuel du gestionnaire de fichiers. - Dialog Jump Automatically + Saut de dialogue automatique Lorsque la fenêtre de dialogue Ouvrir/Enregistrer sous est affichée, naviguez automatiquement vers le chemin du gestionnaire de fichiers actuel. (Expérimental) - Show Dialog Jump Window - Display Dialog Jump search window when the open/save dialog window is shown to quickly navigate to file/folder locations. - Dialog Jump Window Position - Select position for the Dialog Jump search window - Fixed under the Open/Save As dialog window. Displayed on open and stays until the window is closed - Default search window position. Displayed when triggered by search window hotkey - Dialog Jump Result Navigation Behaviour - Behaviour to navigate Open/Save As dialog window to the selected result path - Left click or Enter key + Afficher la fenêtre de saut de dialogue + Afficher la fenêtre de recherche de saut de dialogue lorsque la fenêtre de dialogue Ouvrir/Enregistrer sous est affichée pour naviguer rapidement vers les emplacements de fichier/dossier. + Position de la fenêtre de saut de dialogue + Sélectionnez la position pour la fenêtre de recherche de saut de dialogue + Fixé sous la fenêtre de dialogue Ouvrir/Enregistrer sous. Affiché à l'ouverture et reste jusqu'à ce que la fenêtre soit fermée. + Position de la fenêtre de recherche par défaut. Affiché lorsqu'il est déclenché par le raccourci clavier de la fenêtre de recherche + Comportement de navigation des résultats du saut de dialogue + Comportement pour naviguer dans la fenêtre de dialogue Ouvrir/Enregistrer sous vers le chemin de résultat sélectionné + Clic gauche ou touche Entrée Clique droit - Dialog Jump File Navigation Behaviour - Behaviour to navigate Open/Save As dialog window when the result is a file path + Comportement de navigation des résultats du saut de dialogue + Comportement pour naviguer dans la fenêtre de dialogue Ouvrir/Enregistrer sous lorsque le résultat est un chemin de fichier Remplir le chemin complet dans la zone de nom de fichier Remplir le chemin complet dans la zone de nom de fichier et ouvrir Remplir le répertoire dans la zone de chemin @@ -446,7 +454,7 @@ Icônes Vous avez utilisé Flow Launcher {0} fois Vérifier les mises à jour - Devenir un Sponsor + Devenez un sponsor Nouvelle version {0} disponible, souhaitez-vous redémarrer Flow Launcher pour l'installer ? Échec de la vérification de la mise à jour, vérifiez votre connexion et vos paramètres de configuration proxy pour pouvoir acceder à api.github.com. diff --git a/Flow.Launcher/Languages/he.xaml b/Flow.Launcher/Languages/he.xaml index ca69ddb50..39f02c702 100644 --- a/Flow.Launcher/Languages/he.xaml +++ b/Flow.Launcher/Languages/he.xaml @@ -64,6 +64,10 @@ איפוס מיקום אפס את מיקום חלון החיפוש הקלד כאן כדי לחפש + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info הגדרות @@ -170,6 +174,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history ניתן לערוך זאת רק אם התוסף תומך בתכונת הבית ודף הבית מופעל. Show Search Window at Foremost עוקף את הגדרת תמיד עליון של תוכנות אחרות, ומציג את Flow במיקום הגבוה ביותר. @@ -445,7 +453,7 @@ סמלים הפעלת את Flow Launcher {0} פעמים בדוק עדכונים - תן חסות + Become a Sponsor גרסה חדשה {0} זמינה, האם ברצונך להפעיל מחדש את Flow Launcher כדי להשתמש בעדכון? בדיקת העדכונים נכשלה, אנא בדוק את הגדרות החיבור ואת הגדרות ה-Proxy שלך לכתובת api.github.com. diff --git a/Flow.Launcher/Languages/it.xaml b/Flow.Launcher/Languages/it.xaml index 01062bed0..ffb716658 100644 --- a/Flow.Launcher/Languages/it.xaml +++ b/Flow.Launcher/Languages/it.xaml @@ -64,6 +64,10 @@ Ripristina Posizione Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Impostazioni @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Icone Hai usato Flow Launcher {0} volte Cerca aggiornamenti - Diventa un sostenitore + Become a Sponsor Una nuova versione {0} è disponibile, riavvia Flow Launcher per favore. Ricerca aggiornamenti fallita, per favore controlla la tua connessione e le eventuali impostazioni proxy per api.github.com. diff --git a/Flow.Launcher/Languages/ja.xaml b/Flow.Launcher/Languages/ja.xaml index 206791821..6ebe5271e 100644 --- a/Flow.Launcher/Languages/ja.xaml +++ b/Flow.Launcher/Languages/ja.xaml @@ -64,6 +64,10 @@ 位置のリセット 検索ウィンドウの位置をリセット ここに入力して検索 + {0}: このプラグインはまだ初期化中です… + この結果を選択して再検索する + {0}: 応答に失敗しました! + 詳細については、この結果を選択してください 設定 @@ -171,6 +175,10 @@ 検索文字列が空の場合、ホームページの結果を表示します。 クエリの履歴をホームページに表示 ホームページに表示される最大の履歴の数 + 履歴のスタイル + 履歴とホームページに表示する履歴の種類を選択します + クエリの履歴 + Last opened history これは、プラグインがホーム機能をサポートし、ホームページが有効な場合にのみ編集することができます。 検索ウィンドウを最前面に表示 他のプログラムの 'Always on Top' (最前面に表示)設定を上書きし、常に最前面のウィンドウで Flow を表示します。 diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml index 674cca7a7..503ff2f11 100644 --- a/Flow.Launcher/Languages/ko.xaml +++ b/Flow.Launcher/Languages/ko.xaml @@ -64,6 +64,10 @@ 창 위치 초기화 검색창 위치 초기화 검색어 입력 + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info 설정 @@ -162,6 +166,10 @@ 쿼리 입력창이 비어있을때, 홈페이지의 결과를 표시합니다. 히스토리를 홈페이지에 표시 홈페이지에 표시할 최대 히스토리 수 + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -437,7 +445,7 @@ 아이콘 Flow Launcher를 {0}번 실행했습니다. 업데이트 확인 - 후원하기 + Become a Sponsor 새 버전({0})이 있습니다. Flow Launcher를 재시작하세요. 업데이트 확인을 실패했습니다. api.github.com로의 연결 또는 프록시 설정을 확인해주세요. diff --git a/Flow.Launcher/Languages/nb.xaml b/Flow.Launcher/Languages/nb.xaml index 68e63e37e..8bd7f94a4 100644 --- a/Flow.Launcher/Languages/nb.xaml +++ b/Flow.Launcher/Languages/nb.xaml @@ -64,6 +64,10 @@ Tilbakestilling av posisjon Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Innstillinger @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Ikoner Du har aktivert Flow Launcher {0} ganger Se etter oppdateringer - Bli en sponsor + Become a Sponsor Ny versjon {0} er tilgjengelig, vil du starte Flow Launcher på nytt for å bruke oppdateringen? Sjekk oppdateringer mislyktes, vennligst sjekk tilkoblingen og proxy-innstillingene til api.github.com. diff --git a/Flow.Launcher/Languages/nl.xaml b/Flow.Launcher/Languages/nl.xaml index 69e2107bf..8b7b86329 100644 --- a/Flow.Launcher/Languages/nl.xaml +++ b/Flow.Launcher/Languages/nl.xaml @@ -64,6 +64,10 @@ Positie resetten Reset search window position Type om te zoeken + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Instellingen @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Pictogrammen U heeft Flow Launcher {0} keer opgestart Zoek naar Updates - Sponsor worden + Become a Sponsor Nieuwe versie {0} beschikbaar, start Flow Launcher opnieuw op Controleren op updates mislukt, controleer uw verbinding en proxy-instellingen voor api.github.com. diff --git a/Flow.Launcher/Languages/pl.xaml b/Flow.Launcher/Languages/pl.xaml index 5786f98ab..382626eb7 100644 --- a/Flow.Launcher/Languages/pl.xaml +++ b/Flow.Launcher/Languages/pl.xaml @@ -64,6 +64,10 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros Resetowanie pozycji Zresetuj pozycję okna wyszukiwania Wpisz tutaj, aby wyszukać + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Ustawienia @@ -170,6 +174,10 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros Wyświetl wyniki strony głównej, gdy pole wyszukiwania jest puste. Pokaż wyniki historii na stronie głównej Maksymalna liczba wyników historii wyświetlanych na stronie głównej + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history Można edytować tylko wtedy, gdy wtyczka obsługuje funkcję Strona główna i jest ona włączona. Wyświetl okno wyszukiwania na wierzchu Wyświetl okno wyszukiwania ponad innymi oknami @@ -445,7 +453,7 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros Ikony Uaktywniłeś Flow Launcher {0} razy Szukaj aktualizacji - Zostań sponsorem + Become a Sponsor Nowa wersja {0} jest dostępna, uruchom ponownie Flow Launcher Sprawdzenie aktualizacji nie powiodło się. Sprawdź swoje połączenie i ustawienia proxy dla api.github.com. diff --git a/Flow.Launcher/Languages/pt-br.xaml b/Flow.Launcher/Languages/pt-br.xaml index 6127e839b..15dcae2f4 100644 --- a/Flow.Launcher/Languages/pt-br.xaml +++ b/Flow.Launcher/Languages/pt-br.xaml @@ -64,6 +64,10 @@ Redefinição de Posição Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Configurações @@ -90,7 +94,7 @@ Posição Personalizada Idioma Estilo da Última Consulta - Mostrar/ocultar resultados anteriores quando o Lançador de Fluxos é reativado. + Mostrar/ocultar resultados anteriores quando o Flow Launcher for reativado. Preservar Última Consulta Selecionar última consulta Limpar última consulta @@ -138,7 +142,7 @@ Xiao Lang Sempre Pré-visualizar - Sempre abrir o painel de pré-visualização quando o Flow é ativado. Pressione {0} para ativar ou desativar a pré-visualização. + Sempre abrir o painel de pré-visualização quando o Flow for ativado. Pressione {0} para alternar a pré-visualização. O efeito de sombra não é permitido enquanto o tema atual tem o efeito de desfoque ativado Search Delay Adds a short delay while typing to reduce UI flicker and result load. Recommended if your typing speed is average. @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Ícones Você ativou o Flow Launcher {0} vezes Procurar atualizações - Torne-se um Sponsor + Become a Sponsor A nova versão {0} está disponível, por favor reinicie o Flow Launcher. Falha ao procurar atualizações, confira sua conexão e configuração de proxy para api.github.com. diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml index 2be609c99..b9bafc3a4 100644 --- a/Flow.Launcher/Languages/pt-pt.xaml +++ b/Flow.Launcher/Languages/pt-pt.xaml @@ -64,6 +64,10 @@ Repor posição Repor posição da janela de pesquisa Escreva aqui para pesquisar + {0}: Este plugin está a ser iniciado... + Selecione este resultado para pesquisar novamente + {0}: Falha na resposta! + Selecione este resultado para mais informação Definições @@ -170,6 +174,10 @@ Mostrar resultados da página inicial se o termo de pesquisa estiver vazio. Mostrar histórico na página inicial Máximo de resultados a mostrar na Página inicial + Estilo do histórico + Escolha o tipo de histórico a ser mostrado no Histórico e na Página inicial + Histórico de pesquisas + Último histórico aberto Esta opção apenas pode ser editada se o plugin tiver suporte a Página inicial e se estiver ativo. Janela de pesquisa à frente Sobrepõe a definição 'Sempre na frente' das outras aplicações e mostra Flow Launcher à frente de qualquer janela. @@ -412,13 +420,13 @@ Default search window position. Displayed when triggered by search window hotkey Dialog Jump Result Navigation Behaviour Behaviour to navigate Open/Save As dialog window to the selected result path - Left click or Enter key - Right click + Clique esquerdo ou tecla Enter + Clique direito Dialog Jump File Navigation Behaviour Behaviour to navigate Open/Save As dialog window when the result is a file path - Fill full path in file name box - Fill full path in file name box and open - Fill directory in path box + Preencher caminho total na caixa Nome do ficheiro + Preencher caminho total na caixa Nome do ficheiro e abrir + Preencher diretório na caixa Caminho Proxy HTTP @@ -445,7 +453,7 @@ Ícones Ativou o Flow Launcher {0} vezes Procurar atualizações - Tornar-se patrocinador + Torne-se um Patrocinador Está disponível a versão {0}. Gostaria de reiniciar Flow Launcher para atualizar a sua versão? Erro ao procurar atualizações. Verifique a sua ligação e as definições do proxy estabelecidas para api.github.com diff --git a/Flow.Launcher/Languages/ru.xaml b/Flow.Launcher/Languages/ru.xaml index df7c9d994..7bb5a8ff1 100644 --- a/Flow.Launcher/Languages/ru.xaml +++ b/Flow.Launcher/Languages/ru.xaml @@ -64,6 +64,10 @@ Сброс положения Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Настройки @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Значки Вы воспользовались Flow Launcher уже {0} раз Проверить наличие обновлений - Стать спонсором + Become a Sponsor Доступна новая версия {0}. Вы хотите перезапустить Flow Launcher, чтобы использовать обновление? Проверка обновлений не удалась, пожалуйста, проверьте настройки подключения и прокси-сервера к api.github.com. diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index a07613b13..881ccf340 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -65,6 +65,10 @@ Nevykonali sa žiadne zmeny. Resetovať pozíciu Resetovať pozíciu vyhľadávacieho okna Zadajte text na vyhľadávanie + {0}: Tento plugin sa stále inicializuje… + Vyberte tento výsledok na opätovné vyhľadávanie + {0}: Nepodarilo sa odpovedať! + Vyberte tento výsledok pre viac informácií Nastavenia @@ -169,10 +173,14 @@ Nevykonali sa žiadne zmeny. Nepodarilo sa zmeniť nastavenie kórejského IME Skontrolujte prístup do systémového registra alebo kontaktujte podporu. Domovská stránka - Zobraziť výsledky Domovskej stránky, keď je text dopytu prázdny. - Zobraziť výsledky histórie na Domovskej stránke - Maximálny počet zobrazených výsledkov histórie na Domovskej stránke - Úprava je možná len vtedy, ak plugin podporuje funkciu Domovská stránka a Domovská stránka je povolená. + Zobraziť výsledky domovskej stránky, keď je text dopytu prázdny. + Zobraziť výsledky histórie na domovskej stránke + Maximálny počet histórie výsledkov zobrazenej na domovskej stránke + Štýl histórie + Vyberte, ktorý typ histórie sa má zobraziť v histórii a na domovskej stránke + História dopytov + História naposledy otvorených + Úprava je možná len vtedy, ak plugin podporuje funkciu domovská stránka a zároveň je povolená. Zobraziť vyhľadávacie okno v popredí Prepíše nastavenie "Vždy na vrchu" ostatných programov a zobrazí navrchu Flow. Reštartovať po úprave pluginu cez Repozitár pluginov @@ -535,7 +543,7 @@ Nevykonali sa žiadne zmeny. Domovská stránka - Ak chcete zobrazovať výsledky pluginu, keď je dopyt prázdny, povoľte funkciu Domovská stránka. + Ak chcete zobrazovať výsledky pluginu, keď je dopyt prázdny, povoľte funkciu domovská stránka. Klávesová skratka vlastného vyhľadávania @@ -628,7 +636,7 @@ Ak pri zadávaní skratky pred ňu pridáte "@", bude sa zhodovať s Po aktualizácii pluginov reštartovať Flow Launcher - {0}: Aktualizované z v{1} na v{2} + {0}: Aktualizácia z v{1} na v{2} Nie je vybraný žiaden plugin diff --git a/Flow.Launcher/Languages/sr-Cyrl-RS.xaml b/Flow.Launcher/Languages/sr-Cyrl-RS.xaml index c9cd61886..d7d60e6a0 100644 --- a/Flow.Launcher/Languages/sr-Cyrl-RS.xaml +++ b/Flow.Launcher/Languages/sr-Cyrl-RS.xaml @@ -64,6 +64,10 @@ Position Reset Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Settings @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Icons You have activated Flow Launcher {0} times Check for Updates - Become A Sponsor + Become a Sponsor New version {0} is available, would you like to restart Flow Launcher to use the update? Check updates failed, please check your connection and proxy settings to api.github.com. diff --git a/Flow.Launcher/Languages/sr.xaml b/Flow.Launcher/Languages/sr.xaml index bfc41e5b8..7d1bcb9f3 100644 --- a/Flow.Launcher/Languages/sr.xaml +++ b/Flow.Launcher/Languages/sr.xaml @@ -64,6 +64,10 @@ Position Reset Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Podešavanja @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Icons Aktivirali ste Flow Launcher {0} puta Proveri ažuriranja - Become A Sponsor + Become a Sponsor Nove verzija {0} je dostupna, molim Vas ponovo pokrenite Flow Launcher. Neuspešna provera ažuriranja, molim Vas proverite vašu vezu i podešavanja za proksi prema api.github.com. diff --git a/Flow.Launcher/Languages/tr.xaml b/Flow.Launcher/Languages/tr.xaml index 2133bbb5a..67cdf9da4 100644 --- a/Flow.Launcher/Languages/tr.xaml +++ b/Flow.Launcher/Languages/tr.xaml @@ -64,6 +64,10 @@ Pencere Konumunu Sıfırla Arama penceresinin konumunu sıfırla Aramak için buraya yazın + {0}: Bu eklenti hala başlatılıyor... + Yeniden sorgulamak için bu sonucu seçin + {0}: Yanıt veremedi! + Daha fazla bilgi için bu sonucu seçin Ayarlar @@ -171,6 +175,10 @@ Sorgu metni boş olduğunda ana sayfa sonuçlarını gösterin. Geçmiş Sonuçlarını Ana Sayfada Göster Ana Sayfada Gösterilen Maksimum Geçmiş Sonuçları + Geçmiş Stili + Geçmiş ve Ana Sayfada gösterilecek geçmiş türünü seçin + Sorgu geçmişi + Son açılan geçmiş Bu sadece eklenti Ana Sayfa özelliğini destekliyorsa ve Ana Sayfa etkinleştirilmiş ise düzenlenebilir. Arama Penceresini En Üstte Göster Diğer programların 'Her Zaman Üstte' ayarını geçersiz kılar ve Flow’u en önde gösterir. @@ -446,7 +454,7 @@ Kullanılan Simgeler Şu ana kadar Flow Launcher'ı {0} kez aktifleştirdiniz. Güncellemeleri Kontrol Et - Sponsor Olun + Become a Sponsor Uygulamanın yeni sürümü ({0}) mevcut, Lütfen Flow Launcher'ı yeniden başlatın. Güncelleme kontrolü başarısız oldu. Lütfen bağlantınız ve vekil sunucu ayarlarınızın api.github.com adresine ulaşabilir olduğunu kontrol edin. diff --git a/Flow.Launcher/Languages/uk-UA.xaml b/Flow.Launcher/Languages/uk-UA.xaml index 53dcb8933..bec1f85e3 100644 --- a/Flow.Launcher/Languages/uk-UA.xaml +++ b/Flow.Launcher/Languages/uk-UA.xaml @@ -64,6 +64,10 @@ Скидання позиції Скинути положення вікна пошуку Напишіть тут, аби знайти + {0}: Цей плагін все ще ініціалізується... + Виберіть цей результат, щоб повторити запит + {0}: Не вдалося відповісти! + Виберіть цей результат, щоб отримати додаткову інформацію Налаштування @@ -171,6 +175,10 @@ Показувати результати на головній сторінці, коли текст запиту порожній. Показати результати історії на головній Максимальна кількість результатів історії, що показуються на головній + Стиль історії + Виберіть тип історії, який буде показуватися на сторінці «Історія» та «Головна». + Історія запитів + Остання відкрита історія Це можна редагувати тільки в тому випадку, якщо плагін підтримує функцію «Головна сторінка» і вона ввімкнена. Показувати вікно пошуку на передньому плані Перекриває налаштування «Завжди зверху» інших програм і виводить Flow на передній план. @@ -214,8 +222,8 @@ Версія Сайт Видалити - Search delay time: default - Search delay time: {0}ms + Час затримки пошуку: типово + Час затримки пошуку: {0} мс Не вдалося видалити налаштування плагіну Плагіни: {0} — Не вдалося видалити файли налаштувань плагінів, видаліть їх вручну. Не вдалося видалити кеш плагіну @@ -597,9 +605,9 @@ Вказаний файловий менеджер не знайдено. Перевірте налаштування вашого файлового менеджера в розділі Налаштування > Загальні. Помилка - An error occurred while opening the folder. + Під час відкриття теки сталася помилка. Під час відкриття URL-адреси в браузері сталася помилка. Перевірте налаштування типового веббраузера у розділі «Загальні» вікна налаштувань. - File or directory not found: {0} + Файл або каталог не знайдено: {0} Будь ласка, зачекайте... diff --git a/Flow.Launcher/Languages/vi.xaml b/Flow.Launcher/Languages/vi.xaml index 0618dc9a5..5809c7837 100644 --- a/Flow.Launcher/Languages/vi.xaml +++ b/Flow.Launcher/Languages/vi.xaml @@ -64,6 +64,10 @@ Đặt lại vị trí Cài lại vị trí cửa sổ tìm kiếm Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info Cài đặt @@ -171,6 +175,10 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. @@ -446,7 +454,7 @@ Biểu tượng Bạn đã kích hoạt Flow Launcher {0} lần Kiểm tra các bản cập nhật - Trở thành nhà tài trợ + Become a Sponsor Đã có phiên bản mới {0}, bạn có muốn khởi động lại Flow Launcher để sử dụng bản cập nhật không? Kiểm tra cập nhật không thành công. Vui lòng kiểm tra kết nối và cài đặt proxy của bạn tới api.github.com. diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml index a5a412439..7af54dc54 100644 --- a/Flow.Launcher/Languages/zh-cn.xaml +++ b/Flow.Launcher/Languages/zh-cn.xaml @@ -64,6 +64,10 @@ 重置位置 重置搜索窗口位置 在此处输入以搜索 + {0}:此插件仍在初始化... + 选择此结果以重试 + {0}:响应失败! + 选择此结果以获取更多信息 设置 @@ -123,7 +127,7 @@ 常规 使用拼音搜索 - 拼音是翻译中文的罗马化拼写的标准系统。请注意,启用此功能可以大大增加搜索时的内存使用量。 + 拼音是翻译中文的罗马化拼写的标准系统。请注意,启用此功能会大幅增加搜索时的内存使用量。 使用双拼 使用双拼而不是全拼进行搜索。 双拼方案 @@ -141,7 +145,7 @@ Flow 启动时总是打开预览面板。按 {0} 以切换预览。 当前主题已启用模糊效果,不允许启用阴影效果 延迟搜索 - 在输入时添加一个短时间延迟以减少UI闪烁和加载结果的负载。建议您的输入速度是平均的。 + 在输入时添加一个短时间延迟以减少UI闪烁和加载结果的负载。如果您的打字速度处于中等水平,建议启用此功能。 输入等待时间(毫秒),直到输入被认为完成。这只能在启用搜索延迟时进行编辑。 默认搜索延迟时间 在输入停止后显示结果之前等待时间。更高的数值等待更长时间(毫秒) @@ -171,6 +175,10 @@ 当查询文本为空时显示主页结果。 在主页中显示历史记录 在主页显示的最大历史结果数 + 历史样式 + 选择要在历史和主页中显示的历史类型 + 查询历史 + 最近打开历史 这只能在插件支持主页功能和主页启用时进行编辑。 将搜索窗口置于顶层 覆盖其他“总是在顶部”的程序窗口并在最顶层的位置显示 Flow Launcher 搜索窗口。 @@ -289,7 +297,7 @@ 项目高度 查询框字体 结果标题字体 - 结果字幕字体 + 结果副标题字体 重置 重置为推荐字体和大小设置。 导入主题尺寸 @@ -606,7 +614,7 @@ 检查新的更新 - 您已经拥有最新的 Flow Launcher 版本 + 您当前使用的 Flow Launcher 已是最新版本 检查到更新 更新中... diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml index 7c0fef077..ca7da7624 100644 --- a/Flow.Launcher/Languages/zh-tw.xaml +++ b/Flow.Launcher/Languages/zh-tw.xaml @@ -64,6 +64,10 @@ 重設位置 Reset search window position Type here to search + {0}: This plugin is still initializing... + Select this result to requery + {0}: Failed to respond! + Select this result for more info 設定 @@ -171,11 +175,15 @@ Show home page results when query text is empty. Show History Results in Home Page Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the History and Home Page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. - Restart after modifying plugin via Plugin Store - Restart Flow Launcher automatically after installing/uninstalling/updating plugin via Plugin Store + 在插件商店改動插件後重新啟動 + 在插件商店安裝/移除/更新插件後自動重新啟動Flow Launcher Show unknown source warning Show warning when installing plugins from unknown sources Auto update plugins @@ -446,7 +454,7 @@ 圖示 您已經啟動了 Flow Launcher {0} 次 檢查更新 - 成為贊助者 + Become a Sponsor 發現有新版本 {0}, 請重新啟動 Flow Launcher。 檢查更新失敗,請檢查你對 api.github.com 的連線和代理設定。 diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index dd47f9d4e..747975b2a 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -526,7 +526,7 @@ + Text="{Binding PreviewDescription}" /> diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 2b65737da..06b2dda9e 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -477,7 +477,7 @@ namespace Flow.Launcher && QueryTextBox.CaretIndex == QueryTextBox.Text.Length) { var queryWithoutActionKeyword = - QueryBuilder.Build(QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search; + QueryBuilder.Build(QueryTextBox.Text, QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search; if (FilesFolders.IsLocationPathString(queryWithoutActionKeyword)) { diff --git a/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs b/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs deleted file mode 100644 index 78985108c..000000000 --- a/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs +++ /dev/null @@ -1,253 +0,0 @@ -using iNKORE.UI.WPF.Modern.Controls; -using iNKORE.UI.WPF.Modern.Controls.Helpers; -using iNKORE.UI.WPF.Modern.Controls.Primitives; -using System; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; - -namespace Flow.Launcher.Resources.Controls -{ - // TODO: Use IsScrollAnimationEnabled property in future: https://github.com/iNKORE-NET/UI.WPF.Modern/pull/347 - public class CustomScrollViewerEx : ScrollViewer - { - private double LastVerticalLocation = 0; - private double LastHorizontalLocation = 0; - - public CustomScrollViewerEx() - { - Loaded += OnLoaded; - var valueSource = DependencyPropertyHelper.GetValueSource(this, AutoPanningMode.IsEnabledProperty).BaseValueSource; - if (valueSource == BaseValueSource.Default) - { - AutoPanningMode.SetIsEnabled(this, true); - } - } - - #region Orientation - - public static readonly DependencyProperty OrientationProperty = - DependencyProperty.Register( - nameof(Orientation), - typeof(Orientation), - typeof(CustomScrollViewerEx), - new PropertyMetadata(Orientation.Vertical)); - - public Orientation Orientation - { - get => (Orientation)GetValue(OrientationProperty); - set => SetValue(OrientationProperty, value); - } - - #endregion - - #region AutoHideScrollBars - - public static readonly DependencyProperty AutoHideScrollBarsProperty = - ScrollViewerHelper.AutoHideScrollBarsProperty - .AddOwner( - typeof(CustomScrollViewerEx), - new PropertyMetadata(true, OnAutoHideScrollBarsChanged)); - - public bool AutoHideScrollBars - { - get => (bool)GetValue(AutoHideScrollBarsProperty); - set => SetValue(AutoHideScrollBarsProperty, value); - } - - private static void OnAutoHideScrollBarsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is CustomScrollViewerEx sv) - { - sv.UpdateVisualState(); - } - } - - #endregion - - private void OnLoaded(object sender, RoutedEventArgs e) - { - LastVerticalLocation = VerticalOffset; - LastHorizontalLocation = HorizontalOffset; - UpdateVisualState(false); - } - - /// - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - - if (Style == null && ReadLocalValue(StyleProperty) == DependencyProperty.UnsetValue) - { - SetResourceReference(StyleProperty, typeof(ScrollViewer)); - } - } - - /// - protected override void OnMouseWheel(MouseWheelEventArgs e) - { - var Direction = GetDirection(); - ScrollViewerBehavior.SetIsAnimating(this, true); - - if (Direction == Orientation.Vertical) - { - if (ScrollableHeight > 0) - { - e.Handled = true; - } - - var WheelChange = e.Delta * (ViewportHeight / 1.5) / ActualHeight; - var newOffset = LastVerticalLocation - WheelChange; - - if (newOffset < 0) - { - newOffset = 0; - } - - if (newOffset > ScrollableHeight) - { - newOffset = ScrollableHeight; - } - - if (newOffset == LastVerticalLocation) - { - return; - } - - ScrollToVerticalOffset(LastVerticalLocation); - - ScrollToValue(newOffset, Direction); - LastVerticalLocation = newOffset; - } - else - { - if (ScrollableWidth > 0) - { - e.Handled = true; - } - - var WheelChange = e.Delta * (ViewportWidth / 1.5) / ActualWidth; - var newOffset = LastHorizontalLocation - WheelChange; - - if (newOffset < 0) - { - newOffset = 0; - } - - if (newOffset > ScrollableWidth) - { - newOffset = ScrollableWidth; - } - - if (newOffset == LastHorizontalLocation) - { - return; - } - - ScrollToHorizontalOffset(LastHorizontalLocation); - - ScrollToValue(newOffset, Direction); - LastHorizontalLocation = newOffset; - } - } - - /// - protected override void OnScrollChanged(ScrollChangedEventArgs e) - { - base.OnScrollChanged(e); - if (!ScrollViewerBehavior.GetIsAnimating(this)) - { - LastVerticalLocation = VerticalOffset; - LastHorizontalLocation = HorizontalOffset; - } - } - - private Orientation GetDirection() - { - var isShiftDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift); - - if (Orientation == Orientation.Horizontal) - { - return isShiftDown ? Orientation.Vertical : Orientation.Horizontal; - } - else - { - return isShiftDown ? Orientation.Horizontal : Orientation.Vertical; - } - } - - /// - /// Causes the to load a new view into the viewport using the specified offsets and zoom factor. - /// - /// A value between 0 and that specifies the distance the content should be scrolled horizontally. - /// A value between 0 and that specifies the distance the content should be scrolled vertically. - /// A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor. - /// if the view is changed; otherwise, . - public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor) - { - return ChangeView(horizontalOffset, verticalOffset, zoomFactor, false); - } - - /// - /// Causes the to load a new view into the viewport using the specified offsets and zoom factor, and optionally disables scrolling animation. - /// - /// A value between 0 and that specifies the distance the content should be scrolled horizontally. - /// A value between 0 and that specifies the distance the content should be scrolled vertically. - /// A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor. - /// to disable zoom/pan animations while changing the view; otherwise, . The default is false. - /// if the view is changed; otherwise, . - public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor, bool disableAnimation) - { - if (disableAnimation) - { - if (horizontalOffset.HasValue) - { - ScrollToHorizontalOffset(horizontalOffset.Value); - } - - if (verticalOffset.HasValue) - { - ScrollToVerticalOffset(verticalOffset.Value); - } - } - else - { - if (horizontalOffset.HasValue) - { - ScrollToHorizontalOffset(LastHorizontalLocation); - ScrollToValue(Math.Min(ScrollableWidth, horizontalOffset.Value), Orientation.Horizontal); - LastHorizontalLocation = horizontalOffset.Value; - } - - if (verticalOffset.HasValue) - { - ScrollToVerticalOffset(LastVerticalLocation); - ScrollToValue(Math.Min(ScrollableHeight, verticalOffset.Value), Orientation.Vertical); - LastVerticalLocation = verticalOffset.Value; - } - } - - return true; - } - - private void ScrollToValue(double value, Orientation Direction) - { - if (Direction == Orientation.Vertical) - { - ScrollToVerticalOffset(value); - } - else - { - ScrollToHorizontalOffset(value); - } - - ScrollViewerBehavior.SetIsAnimating(this, false); - } - - private void UpdateVisualState(bool useTransitions = true) - { - var stateName = AutoHideScrollBars ? "NoIndicator" : "MouseIndicator"; - VisualStateManager.GoToState(this, stateName, useTransitions); - } - } -} diff --git a/Flow.Launcher/ResultListBox.xaml.cs b/Flow.Launcher/ResultListBox.xaml.cs index ac51b195c..fcc73e9ce 100644 --- a/Flow.Launcher/ResultListBox.xaml.cs +++ b/Flow.Launcher/ResultListBox.xaml.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -9,7 +10,7 @@ namespace Flow.Launcher { public partial class ResultListBox { - protected object _lock = new object(); + protected Lock _lock = new(); private Point _lastpos; private ListBoxItem curItem = null; public ResultListBox() @@ -88,12 +89,11 @@ namespace Flow.Launcher } } - - private Point start; - private string path; - private string query; + private Point _start; + private string _path; + private string _trimmedQuery; // this method is called by the UI thread, which is single threaded, so we can be sloppy with locking - private bool isDragging; + private bool _isDragging; private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { @@ -104,53 +104,55 @@ namespace Flow.Launcher Result: { CopyText: { } copyText, - OriginQuery.RawQuery: { } rawQuery + OriginQuery.TrimmedQuery: { } trimmedQuery } } }) return; - path = copyText; - query = rawQuery; - start = e.GetPosition(null); - isDragging = true; + _path = copyText; + _trimmedQuery = trimmedQuery; + _start = e.GetPosition(null); + _isDragging = true; } + private void ResultList_MouseMove(object sender, MouseEventArgs e) { - if (e.LeftButton != MouseButtonState.Pressed || !isDragging) + if (e.LeftButton != MouseButtonState.Pressed || !_isDragging) { - start = default; - path = string.Empty; - query = string.Empty; - isDragging = false; + _start = default; + _path = string.Empty; + _trimmedQuery = string.Empty; + _isDragging = false; return; } - if (!File.Exists(path) && !Directory.Exists(path)) + if (!File.Exists(_path) && !Directory.Exists(_path)) return; Point mousePosition = e.GetPosition(null); - Vector diff = this.start - mousePosition; + Vector diff = _start - mousePosition; if (Math.Abs(diff.X) < SystemParameters.MinimumHorizontalDragDistance || Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance) return; - isDragging = false; + _isDragging = false; App.API.HideMainWindow(); var data = new DataObject(DataFormats.FileDrop, new[] { - path + _path }); // Reassigning query to a new variable because for some reason // after DragDrop.DoDragDrop call, 'query' loses its content, i.e. becomes empty string - var rawQuery = query; + var trimmedQuery = _trimmedQuery; var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy); if (effect == DragDropEffects.Move) - App.API.ChangeQuery(rawQuery, true); + App.API.ChangeQuery(trimmedQuery, true); } + private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result }) @@ -158,6 +160,7 @@ namespace Flow.Launcher RightClickResultCommand?.Execute(result.Result); } + private void ResultListBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e) { if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result }) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 720cb440b..b4c94cb35 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -72,6 +72,16 @@ OnContent="{DynamicResource enable}" /> + + + + record); + records.AddOrUpdate(result.OriginQuery.TrimmedQuery, record, (key, oldValue) => record); } } @@ -154,7 +154,7 @@ namespace Flow.Launcher.Storage // origin query is null when user select the context menu item directly of one item from query list // in this case, we do not need to check if the result is top most if (records.IsEmpty || result.OriginQuery == null || - !records.TryGetValue(result.OriginQuery.RawQuery, out var value)) + !records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value)) { return false; } @@ -168,7 +168,7 @@ namespace Flow.Launcher.Storage // origin query is null when user select the context menu item directly of one item from query list // in this case, we do not need to check if the result is top most if (records.IsEmpty || result.OriginQuery == null || - !records.TryGetValue(result.OriginQuery.RawQuery, out var value)) + !records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value)) { return -1; } @@ -194,7 +194,7 @@ namespace Flow.Launcher.Storage // origin query is null when user select the context menu item directly of one item from query list // in this case, we do not need to remove the record if (result.OriginQuery == null || - !records.TryGetValue(result.OriginQuery.RawQuery, out var value)) + !records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value)) { return; } @@ -204,12 +204,12 @@ namespace Flow.Launcher.Storage if (queue.IsEmpty) { // if the queue is empty, remove the queue from the dictionary - records.TryRemove(result.OriginQuery.RawQuery, out _); + records.TryRemove(result.OriginQuery.TrimmedQuery, out _); } else { // change the queue in the dictionary - records[result.OriginQuery.RawQuery] = queue; + records[result.OriginQuery.TrimmedQuery] = queue; } } @@ -229,19 +229,19 @@ namespace Flow.Launcher.Storage SubTitle = result.SubTitle, RecordKey = result.RecordKey }; - if (!records.TryGetValue(result.OriginQuery.RawQuery, out var value)) + if (!records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value)) { // create a new queue if it does not exist value = new ConcurrentQueue(); value.Enqueue(record); - records.TryAdd(result.OriginQuery.RawQuery, value); + records.TryAdd(result.OriginQuery.TrimmedQuery, value); } else { // add or update the record in the queue var queue = new ConcurrentQueue(value.Where(r => !r.Equals(result))); // make sure we don't have duplicates queue.Enqueue(record); - records[result.OriginQuery.RawQuery] = queue; + records[result.OriginQuery.TrimmedQuery] = queue; } } } diff --git a/Flow.Launcher/Themes/Base.xaml b/Flow.Launcher/Themes/Base.xaml index c5b45890b..c3831e68f 100644 --- a/Flow.Launcher/Themes/Base.xaml +++ b/Flow.Launcher/Themes/Base.xaml @@ -252,12 +252,14 @@ - - - - + - + diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 47183489f..e7b4023c2 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -36,9 +36,10 @@ namespace Flow.Launcher.ViewModel private static readonly string ClassName = nameof(MainViewModel); - private bool _isQueryRunning; private Query _lastQuery; private bool _previousIsHomeQuery; + private Query _progressQuery; // Used for QueryResultAsync + private Query _updateQuery; // Used for ResultsUpdated private string _queryTextBeforeLeaveResults; private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results @@ -64,6 +65,8 @@ namespace Flow.Launcher.ViewModel Priority = 0 // Priority is for calculating scores in UpdateResultView }; + private bool _taskbarShownByFlow = false; + #endregion #region Constructor @@ -283,7 +286,7 @@ namespace Flow.Launcher.ViewModel plugin.ResultsUpdated += (s, e) => { - if (e.Query.RawQuery != QueryText || e.Token.IsCancellationRequested) + if (_updateQuery == null || e.Query.OriginalQuery != _updateQuery.OriginalQuery || e.Token.IsCancellationRequested) { return; } @@ -442,7 +445,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private void Backspace(object index) { - var query = QueryBuilder.Build(QueryText.Trim(), PluginManager.GetNonGlobalPlugins()); + var query = QueryBuilder.Build(QueryText, QueryText.Trim(), PluginManager.GetNonGlobalPlugins()); // GetPreviousExistingDirectory does not require trailing '\', otherwise will return empty string var path = FilesFolders.GetPreviousExistingDirectory((_) => true, query.Search.TrimEnd('\\')); @@ -1382,7 +1385,7 @@ namespace Flow.Launcher.ViewModel return; } - App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and RawQuery <{query.RawQuery}>"); + App.API.LogDebug(ClassName, $"Start query with ActionKeyword <{query.ActionKeyword}> and TrimmedQuery <{query.TrimmedQuery}>"); var currentIsHomeQuery = query.IsHomeQuery; var currentIsDialogJump = _isDialogJump; @@ -1394,69 +1397,73 @@ namespace Flow.Launcher.ViewModel return; } - _updateSource?.Dispose(); - - var currentUpdateSource = new CancellationTokenSource(); - _updateSource = currentUpdateSource; - var currentCancellationToken = _updateSource.Token; - _updateToken = currentCancellationToken; - - ProgressBarVisibility = Visibility.Hidden; - _isQueryRunning = true; - - // Switch to ThreadPool thread - await TaskScheduler.Default; - - if (currentCancellationToken.IsCancellationRequested) return; - - // Update the query's IsReQuery property to true if this is a re-query - query.IsReQuery = isReQuery; - - ICollection plugins = Array.Empty(); - if (currentIsHomeQuery) + try { - if (Settings.ShowHomePage) - { - plugins = PluginManager.ValidPluginsForHomeQuery(); - } + _updateSource?.Dispose(); - PluginIconPath = null; - PluginIconSource = null; - SearchIconVisibility = Visibility.Visible; - } - else - { - plugins = PluginManager.ValidPluginsForQuery(query, currentIsDialogJump); + var currentUpdateSource = new CancellationTokenSource(); + _updateSource = currentUpdateSource; + var currentCancellationToken = _updateSource.Token; + _updateToken = currentCancellationToken; - if (plugins.Count == 1) - { - PluginIconPath = plugins.Single().Metadata.IcoPath; - PluginIconSource = await App.API.LoadImageAsync(PluginIconPath); - SearchIconVisibility = Visibility.Hidden; - } - else + ProgressBarVisibility = Visibility.Hidden; + + _progressQuery = query; + _updateQuery = query; + + // Switch to ThreadPool thread + await TaskScheduler.Default; + + if (currentCancellationToken.IsCancellationRequested) return; + + // Update the query's IsReQuery property to true if this is a re-query + query.IsReQuery = isReQuery; + + ICollection plugins = Array.Empty(); + if (currentIsHomeQuery) { + if (Settings.ShowHomePage) + { + plugins = PluginManager.ValidPluginsForHomeQuery(); + } + PluginIconPath = null; PluginIconSource = null; SearchIconVisibility = Visibility.Visible; } - } + else + { + plugins = PluginManager.ValidPluginsForQuery(query, currentIsDialogJump); - App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}"); + if (plugins.Count == 1) + { + PluginIconPath = plugins.Single().Metadata.IcoPath; + PluginIconSource = await App.API.LoadImageAsync(PluginIconPath); + SearchIconVisibility = Visibility.Hidden; + } + else + { + PluginIconPath = null; + PluginIconSource = null; + SearchIconVisibility = Visibility.Visible; + } + } - // Do not wait for performance improvement - /*if (string.IsNullOrEmpty(query.ActionKeyword)) - { - // Wait 15 millisecond for query change in global query - // if query changes, return so that it won't be calculated - await Task.Delay(15, currentCancellationToken); - if (currentCancellationToken.IsCancellationRequested) return; - }*/ + App.API.LogDebug(ClassName, $"Valid <{plugins.Count}> plugins: {string.Join(" ", plugins.Select(x => $"<{x.Metadata.Name}>"))}"); - _ = Task.Delay(200, currentCancellationToken).ContinueWith(_ => + // Do not wait for performance improvement + /*if (string.IsNullOrEmpty(query.ActionKeyword)) + { + // Wait 15 millisecond for query change in global query + // if query changes, return so that it won't be calculated + await Task.Delay(15, currentCancellationToken); + 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 (_isQueryRunning) + if (_progressQuery != null && _progressQuery.OriginalQuery == query.OriginalQuery) { ProgressBarVisibility = Visibility.Visible; } @@ -1465,58 +1472,65 @@ namespace Flow.Launcher.ViewModel TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default); - // plugins are ICollection, meaning LINQ will get the Count and preallocate Array + // plugins are ICollection, meaning LINQ will get the Count and preallocate Array - Task[] tasks; - if (currentIsHomeQuery) - { - if (ShouldClearExistingResultsForNonQuery(plugins)) + Task[] tasks; + if (currentIsHomeQuery) { - Results.Clear(); - App.API.LogDebug(ClassName, $"Existing results are cleared for non-query"); + if (ShouldClearExistingResultsForNonQuery(plugins)) + { + // there are no update tasks and so we can directly return + ClearResults(); + return; + } + + tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch + { + false => QueryTaskAsync(plugin, currentCancellationToken), + true => Task.CompletedTask + }).ToArray(); + + // Query history results for home page firstly so it will be put on top of the results + if (Settings.ShowHistoryResultsForHomePage) + { + QueryHistoryTask(currentCancellationToken); + } + } + else + { + tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch + { + false => QueryTaskAsync(plugin, currentCancellationToken), + true => Task.CompletedTask + }).ToArray(); } - tasks = plugins.Select(plugin => plugin.Metadata.HomeDisabled switch + try { - false => QueryTaskAsync(plugin, currentCancellationToken), - true => Task.CompletedTask - }).ToArray(); + // 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 + } - // Query history results for home page firstly so it will be put on top of the results - if (Settings.ShowHistoryResultsForHomePage) + if (currentCancellationToken.IsCancellationRequested) return; + + // this should happen once after all queries are done so progress bar should continue + // until the end of all querying + _progressQuery = null; + + if (!currentCancellationToken.IsCancellationRequested) { - QueryHistoryTask(currentCancellationToken); + // update to hidden if this is still the current query + ProgressBarVisibility = Visibility.Hidden; } } - else + finally { - tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch - { - false => QueryTaskAsync(plugin, currentCancellationToken), - true => Task.CompletedTask - }).ToArray(); - } - - try - { - // 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 - } - - if (currentCancellationToken.IsCancellationRequested) return; - - // this should happen once after all queries are done so progress bar should continue - // until the end of all querying - _isQueryRunning = false; - - if (!currentCancellationToken.IsCancellationRequested) - { - // update to hidden if this is still the current query - ProgressBarVisibility = Visibility.Hidden; + // this make sures progress query is null when this query is canceled + _progressQuery = null; } // Local function @@ -1616,7 +1630,7 @@ namespace Flow.Launcher.ViewModel { if (string.IsNullOrWhiteSpace(queryText)) { - return QueryBuilder.Build(string.Empty, PluginManager.GetNonGlobalPlugins()); + return QueryBuilder.Build(string.Empty, string.Empty, PluginManager.GetNonGlobalPlugins()); } var queryBuilder = new StringBuilder(queryText); @@ -1636,7 +1650,7 @@ namespace Flow.Launcher.ViewModel // Applying builtin shortcuts await BuildQueryAsync(builtInShortcuts, queryBuilder, queryBuilderTmp); - return QueryBuilder.Build(queryBuilder.ToString().Trim(), PluginManager.GetNonGlobalPlugins()); + return QueryBuilder.Build(queryText, queryBuilder.ToString().Trim(), PluginManager.GetNonGlobalPlugins()); } private async Task BuildQueryAsync(IEnumerable builtInShortcuts, @@ -2113,6 +2127,13 @@ namespace Flow.Launcher.ViewModel { Win32Helper.SwitchToEnglishKeyboardLayout(true); } + + // Show the taskbar if the setting is enabled + if (Settings.ShowTaskbarWhenInvoked && !_taskbarShownByFlow) + { + Win32Helper.ShowTaskbar(); + _taskbarShownByFlow = true; + } } public async void Hide(bool reset = true) @@ -2181,6 +2202,13 @@ namespace Flow.Launcher.ViewModel Win32Helper.RestorePreviousKeyboardLayout(); } + // Hide the taskbar if the setting is enabled + if (_taskbarShownByFlow) + { + Win32Helper.HideTaskbar(); + _taskbarShownByFlow = false; + } + // Delay for a while to make sure clock will not flicker await Task.Delay(50); diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 257758030..974b2e83b 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -288,6 +288,8 @@ namespace Flow.Launcher.ViewModel } } + public string PreviewDescription => Result.Preview?.Description ?? Result.SubTitle; + public Result Result { get; } public int ResultProgress { diff --git a/Flow.Launcher/packages.lock.json b/Flow.Launcher/packages.lock.json index b4b929d19..8c3a16e5e 100644 --- a/Flow.Launcher/packages.lock.json +++ b/Flow.Launcher/packages.lock.json @@ -28,9 +28,9 @@ }, "iNKORE.UI.WPF.Modern": { "type": "Direct", - "requested": "[0.10.1, )", - "resolved": "0.10.1", - "contentHash": "nRYmBosiL+42eUpLbHeqP7qJqtp5EpzuIMZTpvq4mFV33VB/JjkFg1y82gk50pjkXlAQWDvRyrfSAmPR5AM+3g==", + "requested": "[0.10.2.1, )", + "resolved": "0.10.2.1", + "contentHash": "nGwuuVul+TcLCTgPmaAZCc0fYFqUpCNZ8PiulVT3gZnsWt/AvxMZ0DSPpuyI/iRPc/NhFIg9lSIR7uaHWV0I/Q==", "dependencies": { "iNKORE.UI.WPF": "1.2.8" } @@ -1619,7 +1619,7 @@ "FSharp.Core": "[9.0.303, )", "Flow.Launcher.Infrastructure": "[1.0.0, )", "Flow.Launcher.Localization": "[0.0.6, )", - "Flow.Launcher.Plugin": "[5.0.0, )", + "Flow.Launcher.Plugin": "[5.1.0, )", "Meziantou.Framework.Win32.Jobs": "[3.4.5, )", "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", "SemanticVersioning": "[3.0.0, )", @@ -1634,7 +1634,7 @@ "BitFaster.Caching": "[2.5.4, )", "CommunityToolkit.Mvvm": "[8.4.0, )", "Flow.Launcher.Localization": "[0.0.6, )", - "Flow.Launcher.Plugin": "[5.0.0, )", + "Flow.Launcher.Plugin": "[5.1.0, )", "InputSimulator": "[1.0.4, )", "MemoryPack": "[1.21.4, )", "Microsoft.VisualStudio.Threading": "[17.14.15, )", 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 8f0dfb4f5..ed121375b 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -105,7 +105,7 @@ - + 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 d3ce290ab..f30b24e4f 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -64,7 +64,7 @@ - + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml index 234c613c6..44a126e61 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml @@ -2,7 +2,7 @@ 计算器 - 进行数学计算,包括十六进制值和高级函数,如“最小(1,2,3)”、“sqrt(123)”和“cos123”等。 + 进行数学计算,包括十六进制值和高级函数,如“min(1,2,3)”、“sqrt(123)”和“cos(123)”等。 请输入数字 表达错误或不完整(您是否忘记了一些括号?) 将结果复制到剪贴板 diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml index b56e4660f..0cf66c1cb 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml @@ -2,16 +2,16 @@ 計算機 - Perform mathematical calculations, including hex values and advanced functions such as 'min(1,2,3)', 'sqrt(123)' and 'cos(123)'. + 執行數學計算,包括十六進位數值以及進階函數,例如 'min(1,2,3)'、'sqrt(123)' 和 'cos(123)'。 不是一個數 (NaN) - Expression wrong or incomplete (Did you forget some parentheses?) + 表示式錯誤或不完整(你是否忘記了某些括號?) 複製此數至剪貼簿 小數點分隔符號 - The decimal separator to be used in the output. + 用於輸出的小數點分隔符。 使用系統區域設定 逗號 (,) 點 (.) 小數點後最大位數 - Copy failed, please try later - Show error message when calculation fails + 複製失敗,請稍後再試 + 計算失敗時顯示錯誤訊息 diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ar.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ar.xaml index 608fe88a1..1edc1f2aa 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ar.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ar.xaml @@ -56,6 +56,8 @@ بحث في محتوى الملفات: بحث مفهرس: وصول سريع: + Folder Search: + File Search: الكلمة المفتاحية الحالية للإجراء تم مفعّل diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/cs.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/cs.xaml index 2381d501b..3fd1b721a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/cs.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/cs.xaml @@ -56,6 +56,8 @@ Vyhledávání obsahu souborů: Vyhledávání v indexu: Rychlý přístup: + Folder Search: + File Search: Aktuální aktivační příkaz Hotovo Povoleno diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml index f5f13e5a3..59b1216e7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Færdig Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml index 8e352e614..3292568a6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml @@ -56,6 +56,8 @@ Suche nach Dateiinhalten: Index-Suche: Schnellzugriff: + Folder Search: + File Search: Aktuelles Aktions-Schlüsselwort Fertig Aktiviert diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index c40040df5..45c0d72ac 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -58,6 +58,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Done Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml index 7379571a7..dc8860bd7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Hecho Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml index b59ada7ea..860d64572 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml @@ -56,6 +56,8 @@ Búsqueda de contenido de archivo: Buscar índice: Acceso rápido: + Folder Search: + File Search: Palabra clave de acción actual Aceptar Activado diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml index b0b714154..5a91d3648 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml @@ -56,6 +56,8 @@ Recherche de contenu de fichier : Recherche dans l'index : Accès rapide : + Recherche de dossier : + Recherche de fichier : Mot-clé de l'action en cours Terminer Activé diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml index a84d7707d..a5d4c3829 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/he.xaml @@ -56,6 +56,8 @@ חיפוש תוכן קובץ: חיפוש אינדקס: גישה מהירה: + Folder Search: + File Search: מילת פעולה נוכחית בוצע מופעל diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml index a88ad2da1..ca774ce80 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml @@ -56,6 +56,8 @@ Ricerca Contenuto File: Ricerca in Indice: Accesso Rapido: + Folder Search: + File Search: Parola Chiave Corrente Conferma Abilitato diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml index 8a701ebc6..34b9095cd 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword 完了 Enabled @@ -70,9 +72,9 @@ Content Search Engine Directory Recursive Search Engine - Index Search Engine + インデックス検索エンジン Windowsのインデックスオプションを開く - Excluded File Types (comma seperated) + 除外されたファイルタイプ(カンマ区切りで入力) 例: exe,jpg,png 結果の最大表示件数 The maximum number of results requested from active search engine @@ -163,8 +165,8 @@ 作成日時 ↓ 更新日時 ↑ 更新日時 ↓ - Attributes ↑ - Attributes ↓ + 属性 ↑ + 属性 ↓ File List FileName ↑ File List FileName ↓ 実行回数 ↑ @@ -187,7 +189,7 @@ Everything サービスをインストールしています。お待ちください… Everything サービスを正常にインストールしました Everything サービスを自動的にインストールできませんでした。https://www.voidtools.com から手動でインストールしてください - Click here to start it + ここをクリックして開始 Everythingのインストールが見つかりませんでした。手動で場所を指定しますか?{0}{0}「いいえ」をクリックすると、Everythingが自動的にインストールされます。 Everything でのコンテンツ検索を有効にしますか? インデックスなしでは非常に遅くなることがあります(Everything v1.5以降でのみサポートされています) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml index e437926c8..0cbf40621 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml @@ -56,6 +56,8 @@ 파일 내용 검색: 색인 검색: 빠른 접근: + Folder Search: + File Search: 현재 액션 키워드 완료 diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml index b0672d3ad..9e96011b3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml @@ -56,6 +56,8 @@ Søk etter filinnhold: Indekssøk: Hurtigtilgang: + Folder Search: + File Search: Nåværende nøkkelord for handling Utført Aktivert diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml index 3de4ce5e5..796bd0a97 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Klaar Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml index 1a01e8b90..11c3b83b6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml @@ -56,6 +56,8 @@ Przeszukiwanie zawartości plików: Wyszukiwanie indeksowe: Szybki dostęp: + Folder Search: + File Search: Bieżące słowo kluczowe akcji Zapisz Aktywny diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml index 9a3a4ffeb..360342aed 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Finalizado Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml index 2d33768f9..82990de3c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml @@ -56,6 +56,8 @@ Pesquisa no conteúdo dos ficheiros: Pesquisa no índice: Acesso rápido: + Pesquisar pasta: + Pesquisar ficheiro: Palavra-chave atual OK Ativo diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml index cb28fcfd5..08d28d76f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Подтвердить Включено diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml index 1350969b6..1fc487585 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml @@ -56,6 +56,8 @@ Vyhľadávanie obsahu súborov: Vyhľadávanie v indexe: Rýchly prístup: + Vyhľadávanie priečinkov: + Vyhľadávanie súborov: Aktuálny aktivačný príkaz Hotovo Povolené diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr-Cyrl-RS.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr-Cyrl-RS.xaml index e7979f6dd..e9c2f6f84 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr-Cyrl-RS.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr-Cyrl-RS.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Done Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml index ef7e6a5c3..00bf880a6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: Quick Access: + Folder Search: + File Search: Current Action Keyword Gotovo Enabled diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml index 92461291b..38104d366 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml @@ -56,6 +56,8 @@ Dosya İçeriğini Ara: Dizin Araması: Hızlı Erişim: + Folder Search: + File Search: Geçerli Anahtar Kelime Tamam Etkin diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml index 60a08a82f..a6536afb4 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml @@ -22,7 +22,7 @@ Виникла помилка під час пошуку: {0} Не вдалося відкрити папку Не вдалося відкрити файл - This new action keyword is already assigned to another plugin, please choose a different one + Нова команда активації вже призначена іншому плагіну, виберіть іншу Видалити @@ -56,6 +56,8 @@ Пошук вмісту файлу: Індексний пошук: Швидкий доступ: + Пошук теки: + Пошук файлу: Поточне ключове слово дії Готово Увімкнено diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/vi.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/vi.xaml index 6416fc447..3b960522d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/vi.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/vi.xaml @@ -56,6 +56,8 @@ Tìm kiếm nội dung tệp: Tìm kiếm chỉ mục: Truy cập nhanh + Folder Search: + File Search: Từ hành động hiện tại Xong Đã bật diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml index bcef2b668..9758062b3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml @@ -56,6 +56,8 @@ 文件内容搜索: 索引搜索: 快速访问: + 目录搜索: + 文件搜索: 当前触发关键字 确认 已启用 diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml index d64cd7698..43e428093 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml @@ -56,6 +56,8 @@ File Content Search: Index Search: 快速存取: + Folder Search: + File Search: Current Action Keyword 已啟用 diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index fd62566d5..a4e959dd9 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -48,11 +48,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything public static async ValueTask IsEverythingRunningAsync(CancellationToken token = default) { - await _semaphore.WaitAsync(token); + try + { + await _semaphore.WaitAsync(token); + } + catch (OperationCanceledException) + { + return false; + } try { - EverythingApiDllImport.Everything_GetMajorVersion(); + _ = EverythingApiDllImport.Everything_GetMajorVersion(); var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError; return result; } @@ -77,8 +84,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything if (option.MaxCount < 0) throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0"); - await _semaphore.WaitAsync(token); - + try + { + await _semaphore.WaitAsync(token); + } + catch (OperationCanceledException) + { + yield break; + } try { @@ -120,8 +133,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME); } - - if (token.IsCancellationRequested) yield break; if (!EverythingApiDllImport.Everything_QueryW(true)) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs index f9d8963e6..9420e3d3a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs @@ -1,13 +1,14 @@ -using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo; -using Flow.Launcher.Plugin.Explorer.Search.Everything; -using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; -using Flow.Launcher.Plugin.SharedCommands; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Plugin.Explorer.Exceptions; +using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo; +using Flow.Launcher.Plugin.Explorer.Search.Everything; +using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; +using Flow.Launcher.Plugin.SharedCommands; +using static Flow.Launcher.Plugin.Explorer.Settings; using Path = System.IO.Path; namespace Flow.Launcher.Plugin.Explorer.Search @@ -18,6 +19,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search internal Settings Settings; + private readonly Dictionary _allowedTypesByActionKeyword = new() + { + { ActionKeyword.FileSearchActionKeyword, [ResultType.File] }, + { ActionKeyword.FolderSearchActionKeyword, [ResultType.Folder, ResultType.Volume] }, + { ActionKeyword.SearchActionKeyword, [ResultType.File, ResultType.Folder, ResultType.Volume] }, + }; + + public SearchManager(Settings settings, PluginInitContext context) { Context = context; @@ -44,51 +53,71 @@ namespace Flow.Launcher.Plugin.Explorer.Search } } + /// + /// Results for the different types of searches as follows: + /// 1. Search, only include results from: + /// - Files + /// - Folders + /// - Quick Access Links + /// - Path navigation + /// 2. File Content Search, only include results from: + /// - File contents from index search engines i.e. Windows Index, Everything (may not be available due its beta version) + /// 3. Path Search, only include results from: + /// - Path navigation + /// 4. Quick Access Links, only include results from: + /// - Full list of Quick Access Links if query is empty + /// - Matched Quick Access Links if query is not empty + /// - Quick Access Links that are matched on path, e.g. query "window" for results that contain 'window' in the path (even if not in the title), + /// i.e. result with path c:\windows\system32 + /// 5. Folder Search, only include results from: + /// - Folders + /// - Quick Access Links + /// 6. File Search, only include results from: + /// - Files + /// - Quick Access Links + /// internal async Task> SearchAsync(Query query, CancellationToken token) { var results = new HashSet(PathEqualityComparator.Instance); - // This allows the user to type the below action keywords and see/search the list of quick folder links - if (ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword) - || ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword) - || ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword) - || ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword) - || ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword)) - { - if (string.IsNullOrEmpty(query.Search) && ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword)) - return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks); + var keyword = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword; - var quickAccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks); - - results.UnionWith(quickAccessLinks); - } - else + // No action keyword matched - plugin should not handle this query, return empty results. + var activeActionKeywords = Settings.GetActiveActionKeywords(keyword); + if (activeActionKeywords.Count == 0) { - return new List(); + return [.. results]; } - IAsyncEnumerable searchResults; + var queryIsEmpty = string.IsNullOrEmpty(query.Search); + if (queryIsEmpty && activeActionKeywords.ContainsKey(ActionKeyword.QuickAccessActionKeyword)) + { + return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks); + } - bool isPathSearch = query.Search.IsLocationPathString() + if (queryIsEmpty) + { + return [.. results]; + } + + var isPathSearch = query.Search.IsLocationPathString() || EnvironmentVariables.IsEnvironmentVariableSearch(query.Search) || EnvironmentVariables.HasEnvironmentVar(query.Search); + IAsyncEnumerable searchResults; + string engineName; switch (isPathSearch) { case true - when ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword) - || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword): - + when CanUsePathSearchByActionKeywords(activeActionKeywords): results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false)); - - return results.ToList(); + return [.. results]; case false - when ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword): - // Intentionally require enabling of Everything's content search due to its slowness + when activeActionKeywords.ContainsKey(ActionKeyword.FileContentSearchActionKeyword): if (Settings.ContentIndexProvider is EverythingSearchManager && !Settings.EnableEverythingContentSearch) return EverythingContentSearchResult(query); @@ -96,29 +125,41 @@ namespace Flow.Launcher.Plugin.Explorer.Search engineName = Enum.GetName(Settings.ContentSearchEngine); break; - case false - when ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword) - || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword): + case true or false + when activeActionKeywords.ContainsKey(ActionKeyword.QuickAccessActionKeyword): + return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks); + + case false + when CanUseIndexSearchByActionKeywords(activeActionKeywords): searchResults = Settings.IndexProvider.SearchAsync(query.Search, token); engineName = Enum.GetName(Settings.IndexSearchEngine); break; default: - return results.ToList(); + return [.. results]; + } + + var actions = activeActionKeywords.Keys.ToList(); + //Merge Quick Access Link results for non-path searches. + results.UnionWith(GetQuickAccessResultsFilteredByActionKeyword(query, actions)); try { await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false)) - if (search.Type == ResultType.File && IsExcludedFile(search)) { + { + if (search.Type == ResultType.File && IsExcludedFile(search)) continue; - } else { - results.Add(ResultManager.CreateResult(query, search)); - } + + if (IsResultTypeFilteredByActionKeyword(search.Type, actions)) + continue; + + results.Add(ResultManager.CreateResult(query, search)); + } } catch (OperationCanceledException) { - return new List(); + return [.. results]; } catch (EngineNotAvailableException) { @@ -132,33 +173,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any( excludedPath => FilesFolders.PathContains(excludedPath.Path, r.SubTitle, allowEqual: true))); - return results.ToList(); - } - - private bool ActionKeywordMatch(Query query, Settings.ActionKeyword allowedActionKeyword) - { - var keyword = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword; - - return allowedActionKeyword switch - { - Settings.ActionKeyword.SearchActionKeyword => Settings.SearchActionKeywordEnabled && - keyword == Settings.SearchActionKeyword, - Settings.ActionKeyword.PathSearchActionKeyword => Settings.PathSearchKeywordEnabled && - keyword == Settings.PathSearchActionKeyword, - Settings.ActionKeyword.FileContentSearchActionKeyword => Settings.FileContentSearchKeywordEnabled && - keyword == Settings.FileContentSearchActionKeyword, - Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexSearchKeywordEnabled && - keyword == Settings.IndexSearchActionKeyword, - Settings.ActionKeyword.QuickAccessActionKeyword => Settings.QuickAccessKeywordEnabled && - keyword == Settings.QuickAccessActionKeyword, - _ => throw new ArgumentOutOfRangeException(nameof(allowedActionKeyword), allowedActionKeyword, "actionKeyword out of range") - }; + return [.. results]; } private List EverythingContentSearchResult(Query query) { - return new List() - { + return + [ new() { Title = Localize.flowlauncher_plugin_everything_enable_content_search(), @@ -167,11 +188,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search Action = c => { Settings.EnableEverythingContentSearch = true; - Context.API.ChangeQuery(query.RawQuery, true); + Context.API.ChangeQuery(query.TrimmedQuery, true); return false; } } - }; + ]; } private async Task> PathSearchAsync(Query query, CancellationToken token = default) @@ -192,7 +213,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search // Check that actual location exists, otherwise directory search will throw directory not found exception if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path).LocationExists()) - return results.ToList(); + return [.. results]; var useIndexSearch = Settings.IndexSearchEngine is Settings.IndexSearchEngineOption.WindowsIndex && UseWindowsIndexForDirectorySearch(path); @@ -204,7 +225,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search : ResultManager.CreateOpenCurrentFolderResult(retrievedDirectoryPath, query.ActionKeyword, useIndexSearch)); if (token.IsCancellationRequested) - return new List(); + return [.. results]; IAsyncEnumerable directoryResult; @@ -226,7 +247,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search } if (token.IsCancellationRequested) - return new List(); + return [.. results]; try { @@ -241,14 +262,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search } - return results.ToList(); + return [.. results]; } public bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword; public static bool UseIndexSearch(string path) { - if (Main.Settings.IndexSearchEngine is not Settings.IndexSearchEngineOption.WindowsIndex) + if (Main.Settings.IndexSearchEngine is not IndexSearchEngineOption.WindowsIndex) return false; // Check if the path is using windows index search @@ -270,10 +291,67 @@ namespace Flow.Launcher.Plugin.Explorer.Search private bool IsExcludedFile(SearchResult result) { - string[] excludedFileTypes = Settings.ExcludedFileTypes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + string[] excludedFileTypes = Settings.ExcludedFileTypes.Split([','], StringSplitOptions.RemoveEmptyEntries); string fileExtension = Path.GetExtension(result.FullPath).TrimStart('.'); return excludedFileTypes.Contains(fileExtension, StringComparer.OrdinalIgnoreCase); } + + private List GetQuickAccessResultsFilteredByActionKeyword(Query query, List actions) + { + if (!Settings.QuickAccessKeywordEnabled) + return []; + + var results = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks); + if (results.Count == 0) + return []; + + return results + .Where(r => r.ContextData is SearchResult result + && !IsResultTypeFilteredByActionKeyword(result.Type, actions)) + .ToList(); + } + private bool IsResultTypeFilteredByActionKeyword(ResultType type, List actions) + { + var actionsWithWhitelist = actions.Intersect(_allowedTypesByActionKeyword.Keys).ToList(); + if (actionsWithWhitelist.Count == 0) return false; + + // Check if ANY active keyword allows this type (union behavior) + foreach (var action in actionsWithWhitelist) + { + if (_allowedTypesByActionKeyword.TryGetValue(action, out var allowedTypes)) + { + if (allowedTypes.Contains(type)) + return false; + } + } + + return true; + } + + private bool CanUseIndexSearchByActionKeywords(Dictionary actions) + { + var keysToUseIndexSearch = new[] + { + ActionKeyword.FileSearchActionKeyword, ActionKeyword.FolderSearchActionKeyword, + ActionKeyword.IndexSearchActionKeyword, ActionKeyword.SearchActionKeyword + }; + + return keysToUseIndexSearch.Any(actions.ContainsKey); + } + + // Action keywords that supports patch search in results. + private bool CanUsePathSearchByActionKeywords(Dictionary actions) + { + var keysThatSupportPathSearch = new[] + { + ActionKeyword.PathSearchActionKeyword, + ActionKeyword.SearchActionKeyword, + }; + + return keysThatSupportPathSearch.Any(actions.ContainsKey); + + } + } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 8d62531cd..e65c03e9b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,12 +1,13 @@ -using Flow.Launcher.Plugin.Explorer.Search; -using Flow.Launcher.Plugin.Explorer.Search.Everything; -using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; -using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex; -using System; +using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Text.Json.Serialization; +using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search.Everything; using Flow.Launcher.Plugin.Explorer.Search.IProvider; +using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; +using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex; namespace Flow.Launcher.Plugin.Explorer { @@ -58,6 +59,15 @@ namespace Flow.Launcher.Plugin.Explorer public bool QuickAccessKeywordEnabled { get; set; } + + public string FolderSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign; + + public bool FolderSearchKeywordEnabled { get; set; } + + public string FileSearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign; + + public bool FileSearchKeywordEnabled { get; set; } + public bool WarnWindowsSearchServiceOff { get; set; } = true; public bool ShowFileSizeInPreviewPanel { get; set; } = true; @@ -160,7 +170,9 @@ namespace Flow.Launcher.Plugin.Explorer PathSearchActionKeyword, FileContentSearchActionKeyword, IndexSearchActionKeyword, - QuickAccessActionKeyword + QuickAccessActionKeyword, + FolderSearchActionKeyword, + FileSearchActionKeyword, } internal string GetActionKeyword(ActionKeyword actionKeyword) => actionKeyword switch @@ -170,6 +182,8 @@ namespace Flow.Launcher.Plugin.Explorer ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword, ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword, ActionKeyword.QuickAccessActionKeyword => QuickAccessActionKeyword, + ActionKeyword.FolderSearchActionKeyword => FolderSearchActionKeyword, + ActionKeyword.FileSearchActionKeyword => FileSearchActionKeyword, _ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyWord property not found") }; @@ -180,6 +194,8 @@ namespace Flow.Launcher.Plugin.Explorer ActionKeyword.FileContentSearchActionKeyword => FileContentSearchActionKeyword = keyword, ActionKeyword.IndexSearchActionKeyword => IndexSearchActionKeyword = keyword, ActionKeyword.QuickAccessActionKeyword => QuickAccessActionKeyword = keyword, + ActionKeyword.FolderSearchActionKeyword => FolderSearchActionKeyword = keyword, + ActionKeyword.FileSearchActionKeyword => FileSearchActionKeyword = keyword, _ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyWord property not found") }; @@ -190,6 +206,8 @@ namespace Flow.Launcher.Plugin.Explorer ActionKeyword.IndexSearchActionKeyword => IndexSearchKeywordEnabled, ActionKeyword.FileContentSearchActionKeyword => FileContentSearchKeywordEnabled, ActionKeyword.QuickAccessActionKeyword => QuickAccessKeywordEnabled, + ActionKeyword.FolderSearchActionKeyword => FolderSearchKeywordEnabled, + ActionKeyword.FileSearchActionKeyword => FileSearchKeywordEnabled, _ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined") }; @@ -200,7 +218,27 @@ namespace Flow.Launcher.Plugin.Explorer ActionKeyword.IndexSearchActionKeyword => IndexSearchKeywordEnabled = enable, ActionKeyword.FileContentSearchActionKeyword => FileContentSearchKeywordEnabled = enable, ActionKeyword.QuickAccessActionKeyword => QuickAccessKeywordEnabled = enable, + ActionKeyword.FolderSearchActionKeyword => FolderSearchKeywordEnabled = enable, + ActionKeyword.FileSearchActionKeyword => FileSearchKeywordEnabled = enable, _ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined") }; + + // Returns a dictionary because some ActionKeywords may use wildcards (*), + // which means multiple ActionKeywords can be considered active at the same time. + // Using a dictionary ensures O(1) lookup time when checking which actions + // are enabled. + internal Dictionary GetActiveActionKeywords(string actionKeywordStr) + { + var result = new Dictionary(); + if (string.IsNullOrEmpty(actionKeywordStr)) return null; + foreach (var action in Enum.GetValues()) + { + var keywordStr = GetActionKeyword(action); + if (string.IsNullOrEmpty(keywordStr)) continue; + var isEnabled = GetActionKeywordEnabled(action); + if (keywordStr == actionKeywordStr && isEnabled) result.Add(action, keywordStr); + } + return result; + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index 2d46c6307..956c84db2 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -279,7 +279,11 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels new(Settings.ActionKeyword.IndexSearchActionKeyword, "plugin_explorer_actionkeywordview_indexsearch"), new(Settings.ActionKeyword.QuickAccessActionKeyword, - "plugin_explorer_actionkeywordview_quickaccess") + "plugin_explorer_actionkeywordview_quickaccess"), + new(Settings.ActionKeyword.FolderSearchActionKeyword, + "plugin_explorer_actionkeywordview_foldersearch"), + new(Settings.ActionKeyword.FileSearchActionKeyword, + "plugin_explorer_actionkeywordview_filesearch") }; } diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml index ddd24d0ed..c13048133 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml @@ -31,7 +31,7 @@ Please check if you can connect to github.com. This error means you may not be able to install or update plugins. Update all plugins Would you like to update all plugins? - Would you like to update {0} plugins?{1}Flow Launcher will restart after updating all plugins. + 你要更新{0}個插件?{1}Flow Launcher會在更新所有插件後重新啟動。 Would you like to update {0} plugins? {0} plugins successfully updated. Restarting Flow, please wait... Plugin {0} successfully updated. Restarting Flow, please wait... @@ -66,5 +66,5 @@ Install from unknown source warning - Restart Flow Launcher automatically after installing/uninstalling/updating plugin via Plugins Manager + 以插件管理員安裝/移除/更新插件後自動重新啟動Flow Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml index a8ff4ecbc..2653b69da 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml @@ -82,7 +82,7 @@ 程式 在 Flow Launcher 中搜尋程式 - Invalid Path + 無效的路徑 Customized Explorer Args diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 0258a10d2..9c84747d2 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -31,6 +31,8 @@ namespace Flow.Launcher.Plugin.Program internal static PluginInitContext Context { get; private set; } + private static readonly Lock _lastIndexTimeLock = new(); + private static readonly List emptyResults = []; private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 }; @@ -82,8 +84,45 @@ namespace Flow.Launcher.Plugin.Program { var resultList = await Task.Run(async () => { - await _win32sLock.WaitAsync(token); - await _uwpsLock.WaitAsync(token); + // Preparing win32 programs + List win32s; + bool win32LockAcquired = false; + try + { + await _win32sLock.WaitAsync(token); + win32LockAcquired = true; + win32s = [.. _win32s]; + } + catch (OperationCanceledException) + { + return emptyResults; + } + finally + { + // Only release the lock if it was acquired + if (win32LockAcquired) _win32sLock.Release(); + } + + // Preparing UWP programs + List uwps; + bool uwpsLockAcquired = false; + try + { + await _uwpsLock.WaitAsync(token); + uwpsLockAcquired = true; + uwps = [.. _uwps]; + } + catch (OperationCanceledException) + { + return emptyResults; + } + finally + { + // Only release the lock if it was acquired + if (uwpsLockAcquired) _uwpsLock.Release(); + } + + // Start querying programs try { // Collect all UWP Windows app directories @@ -94,8 +133,8 @@ namespace Flow.Launcher.Plugin.Program .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray() : null; - return _win32s.Cast() - .Concat(_uwps) + return win32s.Cast() + .Concat(uwps) .AsParallel() .WithCancellation(token) .Where(HideUninstallersFilter) @@ -109,11 +148,6 @@ namespace Flow.Launcher.Plugin.Program { return emptyResults; } - finally - { - _uwpsLock.Release(); - _win32sLock.Release(); - } }, token); resultList = resultList.Count != 0 ? resultList : emptyResults; @@ -275,7 +309,12 @@ namespace Flow.Launcher.Plugin.Program var cacheEmpty = _win32sCount == 0 || _uwpsCount == 0; - if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now) + bool needReindex; + lock (_lastIndexTimeLock) + { + needReindex = _settings.LastIndexTime.AddHours(30) < DateTime.Now; + } + if (cacheEmpty || needReindex) { _ = Task.Run(async () => { @@ -295,7 +334,7 @@ namespace Flow.Launcher.Plugin.Program } } - public static async Task IndexWin32ProgramsAsync() + public static async Task IndexWin32ProgramsAsync(bool resetCache) { await _win32sLock.WaitAsync(); try @@ -306,9 +345,15 @@ namespace Flow.Launcher.Plugin.Program { _win32s.Add(win32); } - ResetCache(); + if (resetCache) + { + ResetCache(); + } await Context.API.SaveCacheBinaryStorageAsync>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath); - _settings.LastIndexTime = DateTime.Now; + lock (_lastIndexTimeLock) + { + _settings.LastIndexTime = DateTime.Now; + } } catch (Exception e) { @@ -320,7 +365,7 @@ namespace Flow.Launcher.Plugin.Program } } - public static async Task IndexUwpProgramsAsync() + public static async Task IndexUwpProgramsAsync(bool resetCache) { await _uwpsLock.WaitAsync(); try @@ -331,9 +376,15 @@ namespace Flow.Launcher.Plugin.Program { _uwps.Add(uwp); } - ResetCache(); + if (resetCache) + { + ResetCache(); + } await Context.API.SaveCacheBinaryStorageAsync>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath); - _settings.LastIndexTime = DateTime.Now; + lock (_lastIndexTimeLock) + { + _settings.LastIndexTime = DateTime.Now; + } } catch (Exception e) { @@ -349,12 +400,12 @@ namespace Flow.Launcher.Plugin.Program { var win32Task = Task.Run(async () => { - await Context.API.StopwatchLogInfoAsync(ClassName, "Win32Program index cost", IndexWin32ProgramsAsync); + await Context.API.StopwatchLogInfoAsync(ClassName, "Win32Program index cost", () => IndexWin32ProgramsAsync(resetCache: true)); }); var uwpTask = Task.Run(async () => { - await Context.API.StopwatchLogInfoAsync(ClassName, "UWPProgram index cost", IndexUwpProgramsAsync); + await Context.API.StopwatchLogInfoAsync(ClassName, "UWPProgram index cost", () => IndexUwpProgramsAsync(resetCache: true)); }); await Task.WhenAll(win32Task, uwpTask).ConfigureAwait(false); @@ -362,9 +413,21 @@ namespace Flow.Launcher.Plugin.Program internal static void ResetCache() { - var oldCache = cache; - cache = new MemoryCache(cacheOptions); - oldCache.Dispose(); + var newCache = new MemoryCache(cacheOptions); + + // Atomically swap and get the previous cache instance, avoids double-dispose/lost-assignment race + // where each caller receives a distinct prior instance to dispose. + var oldCache = Interlocked.Exchange(ref cache, newCache); + + // Dispose the previous instance (if any)- each caller gets a unique prior instance from above + try + { + oldCache?.Dispose(); + } + catch (Exception e) + { + Context.API.LogException(ClassName, "Failed to dispose old program cache", e); + } } public Control CreateSettingPanel() @@ -397,12 +460,26 @@ namespace Flow.Launcher.Plugin.Program Title = Context.API.GetTranslation("flowlauncher_plugin_program_disable_program"), Action = c => { - _ = DisableProgramAsync(program); - Context.API.ShowMsg( - Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"), - Context.API.GetTranslation( - "flowlauncher_plugin_program_disable_dlgtitle_success_message")); - Context.API.ReQuery(); + _ = Task.Run(async () => + { + try + { + var disabled = await DisableProgramAsync(program); + if (disabled) + { + ResetCache(); + Context.API.ShowMsg( + Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"), + Context.API.GetTranslation( + "flowlauncher_plugin_program_disable_dlgtitle_success_message")); + } + Context.API.ReQuery(); + } + catch (Exception e) + { + Context.API.LogException(ClassName, "Failed to disable program", e); + } + }); return false; }, IcoPath = "Images/disable.png", @@ -413,52 +490,50 @@ namespace Flow.Launcher.Plugin.Program return menuOptions; } - private static async Task DisableProgramAsync(IProgram programToDelete) + private static async Task DisableProgramAsync(IProgram programToDelete) { if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)) - return; + { + return false; + } await _uwpsLock.WaitAsync(); - var reindexUwps = true; try { - reindexUwps = _uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier); - var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier); - program.Enabled = false; - _settings.DisabledProgramSources.Add(new ProgramSource(program)); + var program = _uwps.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier); + if (program != null) + { + program.Enabled = false; + _settings.DisabledProgramSources.Add(new ProgramSource(program)); + // Reindex UWP programs + _ = Task.Run(() => IndexUwpProgramsAsync(resetCache: false)); + return true; + } } finally { _uwpsLock.Release(); } - // Reindex UWP programs - if (reindexUwps) - { - _ = Task.Run(IndexUwpProgramsAsync); - return; - } - await _win32sLock.WaitAsync(); - var reindexWin32s = true; try { - reindexWin32s = _win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier); - var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier); - program.Enabled = false; - _settings.DisabledProgramSources.Add(new ProgramSource(program)); + var program = _win32s.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier); + if (program != null) + { + program.Enabled = false; + _settings.DisabledProgramSources.Add(new ProgramSource(program)); + // Reindex Win32 programs + _ = Task.Run(() => IndexWin32ProgramsAsync(resetCache: false)); + return true; + } } finally { _win32sLock.Release(); } - // Reindex Win32 programs - if (reindexWin32s) - { - _ = Task.Run(IndexWin32ProgramsAsync); - return; - } + return false; } public static void StartProcess(Func runProcess, ProcessStartInfo info) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs index 9a8326e9a..8e3362285 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWPPackage.cs @@ -290,7 +290,7 @@ namespace Flow.Launcher.Plugin.Program.Programs } private static readonly Channel PackageChangeChannel = Channel.CreateBounded(1); - private static PackageCatalog? catalog; + private static PackageCatalog catalog; public static async Task WatchPackageChangeAsync() { @@ -317,7 +317,7 @@ namespace Flow.Launcher.Plugin.Program.Programs { await Task.Delay(3000).ConfigureAwait(false); PackageChangeChannel.Reader.TryRead(out _); - await Task.Run(Main.IndexUwpProgramsAsync); + await Main.IndexUwpProgramsAsync(resetCache: true).ConfigureAwait(false); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs index 7aca8f3b6..6c7ff1dc1 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs @@ -796,7 +796,7 @@ namespace Flow.Launcher.Plugin.Program.Programs { } - await Task.Run(Main.IndexWin32ProgramsAsync); + await Main.IndexWin32ProgramsAsync(resetCache: true).ConfigureAwait(false); } } diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml index 02eb35336..3fa06dabc 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml @@ -13,7 +13,7 @@ 此指令已執行了 {0} 次 執行指令 以系統管理員身分執行 - Copy the command + 複製命令 Only show number of most used commands: Command not found: {0} Error running the command: {0} diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml index 8b5f3c94b..8f19cdcb3 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml +++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml @@ -77,8 +77,8 @@ Надає команди, пов'язані з системою, наприклад, вимкнення, блокування, налаштування тощо. - This theme supports two (light/dark) modes and Blur Transparent Background - This theme supports two (light/dark) modes - This theme supports Blur Transparent Background + Ця тема підтримує два режими (світлий / темний) та розмитий прозорий фон + Ця тема підтримує два (світлий / темний) режими + Ця тема підтримує розмитий прозорий фон diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml index 18ac48fd0..bd705490c 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml +++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml @@ -44,7 +44,7 @@ Open recycle bin 索引選項 Hibernate computer - Save all Flow Launcher settings + 儲存所有Flow Lanuncher設定 Refreshes plugin data with new content Open Flow Launcher's log location Check for new Flow Launcher update diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/es.xaml index 5d402f293..e84a02a30 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/es.xaml @@ -10,13 +10,13 @@ Elegir Aplicación(*.exe)|*.exe|Todos los archivos|*.* - Use custom instead of Flow's default web browser - Browser path + Utilizar un navegador web personalizado en lugar del predeterminado de Flow + Ruta del navegador Nueva pestaña Nueva ventana - Private mode + Modo privado - Prefer https over http + Priorizar https frente a http diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/ja.xaml index f643a1081..b51c79899 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Languages/ja.xaml +++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/ja.xaml @@ -10,13 +10,13 @@ 選択 Application(*.exe)|*.exe|All files|*.* - Use custom instead of Flow's default web browser - Browser path + FlowのデフォルトのWebブラウザの代わりにカスタムを使用する + ブラウザーのパス - New tab - New window + 新しいタブ + 新しいウインドウ - Private mode + プライベートモード - Prefer https over http + httpよりもhttpsを優先 diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/tr.xaml index 2ce323d08..0318b4301 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Languages/tr.xaml +++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/tr.xaml @@ -10,13 +10,13 @@ Seç Programlar (*.exe)|*.exe|Tüm Dosyalar|*.* - Use custom instead of Flow's default web browser - Browser path + Flow'un varsayılan web tarayıcısı yerine özel tarayıcıyı kullanın + Tarayıcı yolu Yeni sekme Yeni pencere - Private mode + Gizli mod - Prefer https over http + http yerine https'yi tercih et diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/uk-UA.xaml index f7ccd7cc1..a3cf6e02d 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Languages/uk-UA.xaml +++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/uk-UA.xaml @@ -10,13 +10,13 @@ Обрати Application(*.exe)|*.exe|Усі файли|*.* - Use custom instead of Flow's default web browser - Browser path + Використовувати власний веббраузер замість стандартного браузера Flow + Шлях до браузера Нова вкладка Нове вікно - Private mode + Приватний режим - Prefer https over http + Віддавати перевагу HTTPS над HTTP diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml index 7daee625b..41a6325b3 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml @@ -45,7 +45,7 @@ Por favor, introduzca una URL La palabra clave de acción ya está en uso, por favor, introduzca una diferente Correcto - Failed to update search source. The item may have been removed. + No se ha podido actualizar la fuente de búsqueda. Es posible que el elemento haya sido eliminado. Sugerencia: No es necesario colocar imágenes personalizadas en esta carpeta, al actualizar Flow se perderán. Flow copiará automáticamente cualquier imagen externa a esta carpeta en la ubicación de imágenes personalizada de WebSearch. Búsquedas Web diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml index 3ad1461e6..51aa07bab 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml @@ -46,7 +46,7 @@ https://www.netflix.com/search?q={q} URLを入力してください キーワードはすでに存在します。違うキーワードを入力してください 成功しました - Failed to update search source. The item may have been removed. + 検索ソースの更新に失敗しました。項目が削除されている可能性があります。 Hint: You do not need to place custom images in this directory, if Flow's version is updated they will be lost. Flow will automatically copy any images outside of this directory across to WebSearch's custom image location. Web検索 diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml index 8c2dd2104..e706b7bf7 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml @@ -45,7 +45,7 @@ Lütfen bir URL giriniz Anahtar kelime zaten mevcut. Lütfen yeni bir tane seçiniz. Başarılı - Failed to update search source. The item may have been removed. + Arama kaynağı güncellenemedi. Öge kaldırılmış olabilir. İpucu: Bu dizine özel resimler yerleştirmenize gerek yoktur, Flow'un sürümü güncellenirse bunlar kaybolacaktır. Flow, bu dizinin dışındaki tüm görüntüleri otomatik olarak WebSearch'ün özel görüntü konumuna kopyalayacaktır. Web Araması diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml index 3fe7068d1..2163c29be 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml @@ -45,7 +45,7 @@ Будь ласка, введіть URL-адресу Ключове слово дії вже існує, будь ласка, введіть інше Успішно - Failed to update search source. The item may have been removed. + Не вдалося оновити джерело пошуку. Елемент, можливо, було видалено. Підказка: Вам не потрібно розміщувати власні зображення в цьому каталозі, якщо версія Flow оновиться, вони будуть втрачені. Flow автоматично копіює всі зображення з цього каталогу до спеціального каталогу WebSearch. Вебпошук diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.ja-JP.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.ja-JP.resx index 3a2f991a1..ec98231ae 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.ja-JP.resx +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.ja-JP.resx @@ -150,7 +150,7 @@ Area Control Panel (legacy settings) - アクティブ化 + アクティベーション Area UpdateAndSecurity @@ -1206,7 +1206,7 @@ Windows の設定を検索するためのプラグイン - Windows Settings + Windows の設定 電源とスリープ @@ -1836,19 +1836,19 @@ Check firewall status - Send or receive a file + ファイルを送受信する - Add or remove user accounts + ユーザーアカウントの追加または削除 Edit the system environment variables - Manage BitLocker + BitLocker の管理 - Auto-hide the taskbar + タスクバーを自動的に隠す Change sound card settings @@ -1947,10 +1947,10 @@ View recommended actions to keep Windows running smoothly - Change cursor blink rate + カーソルの点滅速度を変更する - Add or remove programs + プログラムの追加と削除 Create a password reset disk @@ -2070,7 +2070,7 @@ Change temporary Internet file settings - Connect to the Internet + インターネットに接続 Find and fix audio playback problems @@ -2079,7 +2079,7 @@ Change the mouse pointer display or speed - Back up your recovery key + リカバリーキーのバックアップ Save backup copies of your files with File History @@ -2094,31 +2094,31 @@ Change how your mouse works - Show how much RAM is on this computer + このコンピュータにあるRAMの量を表示する - Edit power plan + 電源プランを編集 - Adjust system volume + システム音量の調整 - Defragment and optimise your drives + ドライブのデフラグと最適化 Set up ODBC data sources (32-bit) - Change Font Settings + フォント設定を変更 - Magnify portions of the screen using Magnifier + 拡大鏡を使って画面の一部を拡大する Change the file type associated with a file extension - View event logs + イベントログを表示 Manage Windows Credentials @@ -2127,7 +2127,7 @@ Set up a microphone - Change how the mouse pointer looks + マウスポインタの見た目を変更する Change power-saving settings @@ -2152,7 +2152,7 @@ Manage Work Folders - Encrypt your offline files + オフラインファイルを暗号化 Train the computer to recognise your voice @@ -2161,7 +2161,7 @@ Advanced printer setup - Change default printer + 既定のプリンタを変更する Edit environment variables for your account @@ -2188,19 +2188,19 @@ Private Character Editor - Record steps to reproduce a problem + 問題を再現するためのステップを記録 - Adjust the appearance and performance of Windows + Windowsの外観とパフォーマンスを調整する - Settings for Microsoft IME (Japanese) + 日本語用 Microsoft IME の設定 Invite someone to connect to your PC and help you, or offer to help someone else - Run programs made for previous versions of Windows + 以前のバージョンの Windows 用に作られたプログラムを実行 Choose the order of how your screen rotates @@ -2212,10 +2212,10 @@ Set flicks to perform certain tasks - Change account type + アカウントタイプの変更 - Change screen saver + スクリーンセーバーを変更 Change User Account Control settings @@ -2224,37 +2224,37 @@ Turn on easy access keys - Identify and repair network problems + ネットワークの問題を特定して修復する Find and fix networking and connection problems - Play CDs or other media automatically + CD やその他のメディアを自動的に再生 View basic information about your computer - Choose how you open links + リンクを開く方法の選択 Allow Remote Assistance invitations to be sent from this computer - Task Manager + タスクマネージャー Turn flicks on or off - Add a language + 言語を追加 View network status and tasks - Turn Magnifier on or off + 拡大鏡のオン/オフ See the name of this computer @@ -2269,10 +2269,10 @@ Manage disk space used by your offline files - Turn High Contrast on or off + ハイコントラストのオン/オフ - Change the way time is displayed + 時間の表示方法を変更する Change how web pages are displayed in tabs @@ -2284,22 +2284,22 @@ Manage audio devices - Change security settings + セキュリティ設定を変更 Check security status - Delete cookies or temporary files + Cookie や一時ファイルを削除 - Specify which hand you write with + どの手で書くかを指定する Change touch input settings - How to change the size of virtual memory + 仮想メモリのサイズを変更する方法 Hear text read aloud with Narrator @@ -2353,13 +2353,13 @@ Manage Storage Spaces - Show or hide file extensions + 拡張子の表示/非表示 - Allow an app through Windows Firewall + Windowsファイアウォールでアプリを許可する - Change system sounds + システムのサウンドを変更 ClearTypeテキストを調整 @@ -2380,7 +2380,7 @@ Internet Explorer の検索プロバイダを変更する - Join a domain + ドメインに参加 端末を追加 @@ -2398,7 +2398,7 @@ プログラムのアンインストール - Create and format hard disk partitions + ハードディスクのパーティション作成とフォーマット 日付、時刻、数の書式を変更 @@ -2410,7 +2410,7 @@ Manage network passwords - Change input methods + 入力方法を変更 Manage advanced sharing settings @@ -2428,13 +2428,13 @@ Manage Web Credentials - Change the time zone + タイムゾーンの変更 音声認識を開始 - View installed updates + インストール済みのアップデートを表示 What's happened to the Quick Launch toolbar? @@ -2452,7 +2452,7 @@ Change the way measurements are displayed - Press key combinations one at a time + キーの組み合わせを同時に押してください Restore data, files or computer from backup (Windows 7) @@ -2467,7 +2467,7 @@ ペンまたはタッチ入力の画面をキャリブレーション - Manage user certificates + ユーザー証明書の管理 タスクのスケジュール diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.sk-SK.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.sk-SK.resx index 5b4dea6a9..2d242d5b1 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.sk-SK.resx +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.sk-SK.resx @@ -1377,7 +1377,7 @@ Area SurfaceHub - Domov + Nastavenia dovmoskej stránky Area Home, Overview-page for all areas of settings diff --git a/README.md b/README.md index 49331decf..e7595fff5 100644 --- a/README.md +++ b/README.md @@ -246,9 +246,9 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea -### [Clipboard History](https://github.com/liberize/Flow.Launcher.Plugin.ClipboardHistory) +### [Clipboard+](https://github.com/Jack251970/Flow.Launcher.Plugin.ClipboardPlus) - + ### [Home Assistant Commander](https://github.com/Garulf/HA-Commander) @@ -348,8 +348,8 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea - - + +

@@ -362,6 +362,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea + diff --git a/appveyor.yml b/appveyor.yml index b015c19ab..03542e8d2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0.2.{build}' +version: '2.0.3.{build}' # Do not build on tags because we create a release on merge to master. Otherwise will upload artifacts twice changing the hash, as well as triggering duplicate GitHub release action & NuGet deployments. skip_tags: true