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 416c75a9d..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@v5
+ 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@v5
+ 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@v5
+ 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@v5
+ 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@v5
+ 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 e45ac5e6b..67bb851e8 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/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
index 649d59ad7..103a72113 100644
--- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
+++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
@@ -72,7 +72,7 @@
allruntime; build; native; contentfiles; analyzers; buildtransitive
-
+ all
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.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs
index 2c9b8d4fd..9404d1107 100644
--- a/Flow.Launcher.Plugin/Result.cs
+++ b/Flow.Launcher.Plugin/Result.cs
@@ -4,11 +4,13 @@ using System.IO;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
+using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin
{
///
- /// Describes a result of a executed by a plugin
+ /// Describes a result of a executed by a plugin.
+ /// This or its child classes is serializable.
///
public class Result
{
@@ -21,6 +23,8 @@ namespace Flow.Launcher.Plugin
private string _icoPath;
+ private string _icoPathAbsolute;
+
private string _copyText = string.Empty;
private string _badgeIcoPath;
@@ -64,15 +68,27 @@ namespace Flow.Launcher.Plugin
public string AutoCompleteText { get; set; }
///
- /// The image to be displayed for the result.
+ /// Path or URI to the icon image for this result.
+ /// Updates appropriately when set.
///
- /// Can be a local file path or a URL.
- /// GlyphInfo is prioritized if not null
+ ///
+ /// Preferred usage: provide a path relative to the plugin directory (for example: "Images\icon.png").
+ /// Because is serialized, using relative paths keeps the icon reference portable
+ /// when Flow is moved.
+ ///
+ /// Accepted formats:
+ /// - Relative file paths (resolved against into )
+ /// - Absolute file paths (left as-is)
+ /// - HTTP/HTTPS URLs (left as-is)
+ /// - Data URIs (left as-is)
+ ///
public string IcoPath
{
get => _icoPath;
set
{
+ _icoPath = value;
+
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
if (!string.IsNullOrEmpty(value)
&& !string.IsNullOrEmpty(PluginDirectory)
@@ -81,15 +97,23 @@ namespace Flow.Launcher.Plugin
&& !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
&& !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
{
- _icoPath = Path.Combine(PluginDirectory, value);
+ _icoPathAbsolute = Path.Combine(PluginDirectory, value);
}
else
{
- _icoPath = value;
+ _icoPathAbsolute = value;
}
}
}
+ ///
+ /// Absolute path or URI which is used to load and display the result icon for Flow.
+ /// This is populated by the setter.
+ /// If a relative path was provided to , this property will contain the resolved
+ /// absolute local path after combining with .
+ ///
+ public string IcoPathAbsolute => _icoPathAbsolute;
+
///
/// The image to be displayed for the badge of the result.
///
@@ -131,17 +155,34 @@ namespace Flow.Launcher.Plugin
///
/// Delegate to load an icon for this result.
///
+ [JsonIgnore]
public IconDelegate Icon = null;
///
/// Delegate to load an icon for the badge of this result.
///
+ [JsonIgnore]
public IconDelegate BadgeIcon = null;
+ private GlyphInfo _glyph;
+
///
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
///
- public GlyphInfo Glyph { get; init; }
+ public GlyphInfo Glyph
+ {
+ get => _glyph;
+ init => _glyph = value;
+ }
+
+ ///
+ /// Set the Glyph Icon after initialization
+ ///
+ ///
+ public void SetGlyph(GlyphInfo glyph)
+ {
+ _glyph = glyph;
+ }
///
/// An action to take in the form of a function call when the result has been selected.
@@ -151,6 +192,7 @@ namespace Flow.Launcher.Plugin
/// Its result determines what happens to Flow Launcher's query form:
/// when true, the form will be hidden; when false, it will stay in focus.
///
+ [JsonIgnore]
public Func Action { get; set; }
///
@@ -161,6 +203,7 @@ namespace Flow.Launcher.Plugin
/// Its result determines what happens to Flow Launcher's query form:
/// when true, the form will be hidden; when false, it will stay in focus.
///
+ [JsonIgnore]
public Func> AsyncAction { get; set; }
///
@@ -203,11 +246,13 @@ namespace Flow.Launcher.Plugin
///
/// As external information for ContextMenu
///
+ [JsonIgnore]
public object ContextData { get; set; }
///
/// Plugin ID that generated this result
///
+ [JsonInclude]
public string PluginID { get; internal set; }
///
@@ -223,6 +268,7 @@ namespace Flow.Launcher.Plugin
///
/// Customized Preview Panel
///
+ [JsonIgnore]
public Lazy PreviewPanel { get; set; }
///
@@ -352,6 +398,7 @@ namespace Flow.Launcher.Plugin
///
/// Delegate to get the preview panel's image
///
+ [JsonIgnore]
public IconDelegate PreviewDelegate { get; set; } = null;
///
diff --git a/Flow.Launcher.Plugin/packages.lock.json b/Flow.Launcher.Plugin/packages.lock.json
index 70f71f20d..3240b3981 100644
--- a/Flow.Launcher.Plugin/packages.lock.json
+++ b/Flow.Launcher.Plugin/packages.lock.json
@@ -16,12 +16,12 @@
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "requested": "[10.0.102, )",
+ "resolved": "10.0.102",
+ "contentHash": "Oxq3RCIJSdtpIU4hLqO7XaDe/Ra3HS9Wi8rJl838SAg6Zu1iQjerA0+xXWBgUFYbgknUGCLOU0T+lzMLkvY9Qg==",
"dependencies": {
- "Microsoft.Build.Tasks.Git": "8.0.0",
- "Microsoft.SourceLink.Common": "8.0.0"
+ "Microsoft.Build.Tasks.Git": "10.0.102",
+ "Microsoft.SourceLink.Common": "10.0.102"
}
},
"Microsoft.Windows.CsWin32": {
@@ -46,13 +46,13 @@
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ "resolved": "10.0.102",
+ "contentHash": "0i81LYX31U6UiXz4NOLbvc++u+/mVDmOt+PskrM/MygpDxkv9THKQyRUmavBpLK6iBV0abNWnn+CQgSRz//Pwg=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ "resolved": "10.0.102",
+ "contentHash": "Mk1IMb9q5tahC2NltxYXFkLBtuBvfBoCQ3pIxYQWfzbCE9o1OB9SsHe0hnNGo7lWgTA/ePbFAJLWu6nLL9K17A=="
},
"Microsoft.Windows.SDK.Win32Docs": {
"type": "Transitive",
diff --git a/Flow.Launcher.Test/Plugins/CalculatorTest.cs b/Flow.Launcher.Test/Plugins/CalculatorTest.cs
index b075813db..4e40d3645 100644
--- a/Flow.Launcher.Test/Plugins/CalculatorTest.cs
+++ b/Flow.Launcher.Test/Plugins/CalculatorTest.cs
@@ -16,14 +16,15 @@ namespace Flow.Launcher.Test.Plugins
{
DecimalSeparator = DecimalSeparator.UseSystemLocale,
MaxDecimalPlaces = 10,
- ShowErrorMessage = false // Make sure we return the empty results when error occurs
+ ShowErrorMessage = false, // Make sure we return the empty results when error occurs
+ UseThousandsSeparator = true // Default value
};
private readonly Engine _engine = new(new Configuration
{
Scope = new Dictionary
- {
- { "e", Math.E }, // e is not contained in the default mages engine
- }
+ {
+ { "e", Math.E }, // e is not contained in the default mages engine
+ }
});
public CalculatorPluginTest()
@@ -41,6 +42,44 @@ namespace Flow.Launcher.Test.Plugins
engineField.SetValue(null, _engine);
}
+ [Test]
+ public void ThousandsSeparatorTest_Enabled()
+ {
+ _settings.UseThousandsSeparator = true;
+
+ _settings.DecimalSeparator = DecimalSeparator.Dot;
+ var result = GetCalculationResult("1000+234");
+ // When thousands separator is enabled, the result should contain a separator
+ // Since decimal separator is dot, thousands separator should be comma
+ ClassicAssert.AreEqual("1,234", result);
+
+ _settings.DecimalSeparator = DecimalSeparator.Comma;
+ var result2 = GetCalculationResult("1000+234");
+ // When thousands separator is enabled, the result should contain a separator
+ // Since decimal separator is comma, thousands separator should be dot
+ ClassicAssert.AreEqual("1.234", result2);
+ }
+
+ [Test]
+ public void ThousandsSeparatorTest_Disabled()
+ {
+ _settings.UseThousandsSeparator = false;
+ _settings.DecimalSeparator = DecimalSeparator.UseSystemLocale;
+
+ var result = GetCalculationResult("1000+234");
+ ClassicAssert.AreEqual("1234", result);
+ }
+
+ [Test]
+ public void ThousandsSeparatorTest_LargeNumber()
+ {
+ _settings.UseThousandsSeparator = false;
+ _settings.DecimalSeparator = DecimalSeparator.UseSystemLocale;
+
+ var result = GetCalculationResult("1000000+234567");
+ ClassicAssert.AreEqual("1234567", result);
+ }
+
// Basic operations
[TestCase(@"1+1", "2")]
[TestCase(@"2-1", "1")]
@@ -77,6 +116,9 @@ namespace Flow.Launcher.Test.Plugins
[TestCase(@"invalid_expression", "")]
public void CalculatorTest(string expression, string result)
{
+ _settings.UseThousandsSeparator = false;
+ _settings.DecimalSeparator = DecimalSeparator.Dot;
+
ClassicAssert.AreEqual(GetCalculationResult(expression), result);
}
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/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index b45bbc549..da11380b8 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -259,6 +259,9 @@ namespace Flow.Launcher
await PluginManager.InitializePluginsAsync(_mainVM);
+ // Refresh the history results after plugins are initialized so that we can parse the absolute icon paths
+ _mainVM.RefreshLastOpenedHistoryResults();
+
// Refresh home page after plugins are initialized because users may open main window during plugin initialization
// And home page is created without full plugin list
if (_settings.ShowHomePage && _mainVM.QueryResultsSelected() && string.IsNullOrEmpty(_mainVM.QueryText))
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 5f9a69f28..017651fdf 100644
--- a/Flow.Launcher/Helper/ResultHelper.cs
+++ b/Flow.Launcher/Helper/ResultHelper.cs
@@ -11,20 +11,20 @@ namespace Flow.Launcher.Helper;
public static class ResultHelper
{
- public static async Task PopulateResultsAsync(LastOpenedHistoryItem item)
+ public static async Task PopulateResultsAsync(LastOpenedHistoryResult item)
{
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
{
- var freshResults = await plugin.Plugin.QueryAsync(query, CancellationToken.None);
+ var freshResults = await PluginManager.QueryForPluginAsync(plugin, query, CancellationToken.None);
// Try to match by record key first if it is valid, otherwise fall back to title + subtitle match
if (string.IsNullOrEmpty(recordKey))
{
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 positionType 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 PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides 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 poziciReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoNastavení
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IkonyFlow Launcher byl aktivován {0} krátZkontrolovat Aktualizace
- Staňte se sponzorem
+ Become a SponsorJe 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 ResetReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoIndstillinger
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IconsDu har aktiveret Flow Launcher {0} gangeTjek for opdateringer
- Become A Sponsor
+ Become a SponsorNy version {0} er tilgængelig, genstart venligst Flow LauncherCheck 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 PositionPosition des Suchfensters zurücksetzenZum Suchen hier tippen
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoEinstellungen
@@ -171,6 +175,10 @@
Ergebnisse der Homepage zeigen, wenn Abfragetext leer ist.Historie-Ergebnisse auf Homepage zeigenMaximal gezeigte Historie-Ergebnisse auf Homepage
+ History Style
+ Choose the type of history to show in the History and Home Page
+ Query history
+ Last opened historyDies kann nur bearbeitet werden, wenn das Plug-in das Home-Feature unterstützt und die Homepage aktiviert ist.Suchfenster an vorderster zeigenSetzt die Einstellung 'Immer im Vordergrund' anderer Programme außer Kraft und zeigt Flow in der vordersten Position an.
@@ -446,7 +454,7 @@
IconsSie haben Flow Launcher {0} mal aktiviertNach Updates suchen
- Ein Sponsor werden
+ Become a SponsorNeue 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 a1ea6aac2..db91faa27 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 SchedulerError setting launch on startupHide 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 notificationsSearch Window LocationRemember Last Position
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 ResetReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoAjustes
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IconsHas activado Flow Launcher {0} vecesBuscar actualizaciones
- Become A Sponsor
+ Become a SponsorLa 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ónRestablece la posición de la ventana de búsquedaEscribir 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ónConfiguració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 inicioNú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 aperturasEsto 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 planoAnula el ajuste «Siempre arriba» de otros programas y muestra Flow en primer plano.
@@ -446,7 +454,7 @@
IconosHa activado Flow Launcher {0} vecesBuscar actualizaciones
- Hágase Patrocinador
+ Conviértase en PatrocinadorLa 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 positionRéinitialiser la position de la fenêtre de rechercheTapez 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'informationsParamè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'accueilMaximum 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 ouverturesCeci 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 planOutrepasse 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 uniquementAfficher les badges pour les résultats des requêtes globales uniquement
- Dialog Jump
+ Saut de dialogueEntrez 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 dialogueLorsque 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 automatiqueLorsque 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éeClique 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 fichierRemplir le chemin complet dans la zone de nom de fichierRemplir le chemin complet dans la zone de nom de fichier et ouvrirRemplir le répertoire dans la zone de chemin
@@ -446,7 +454,7 @@
IcônesVous avez utilisé Flow Launcher {0} foisVérifier les mises à jour
- Devenir un Sponsor
+ Devenez un sponsorNouvelle 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 PageMaximum 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 PosizioneReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoImpostazioni
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IconeHai usato Flow Launcher {0} volteCerca aggiornamenti
- Diventa un sostenitore
+ Become a SponsorUna 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides 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 posisjonReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoInnstillinger
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IkonerDu har aktivert Flow Launcher {0} gangerSe etter oppdateringer
- Bli en sponsor
+ Become a SponsorNy 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 resettenReset search window positionType om te zoeken
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoInstellingen
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
PictogrammenU heeft Flow Launcher {0} keer opgestartZoek naar Updates
- Sponsor worden
+ Become a SponsorNieuwe versie {0} beschikbaar, start Flow Launcher opnieuw opControleren 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 pozycjiZresetuj pozycję okna wyszukiwaniaWpisz tutaj, aby wyszukać
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoUstawienia
@@ -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łównejMaksymalna 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 historyMożna edytować tylko wtedy, gdy wtyczka obsługuje funkcję Strona główna i jest ona włączona.Wyświetl okno wyszukiwania na wierzchuWyświetl okno wyszukiwania ponad innymi oknami
@@ -445,7 +453,7 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros
IkonyUaktywniłeś Flow Launcher {0} razySzukaj aktualizacji
- Zostań sponsorem
+ Become a SponsorNowa wersja {0} jest dostępna, uruchom ponownie Flow LauncherSprawdzenie 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çãoReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoConfigurações
@@ -90,7 +94,7 @@
Posição PersonalizadaIdiomaEstilo 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 ConsultaSelecionar última consultaLimpar última consulta
@@ -138,7 +142,7 @@
Xiao LangSempre 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 ativadoSearch DelayAdds 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 PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
ÍconesVocê ativou o Flow Launcher {0} vezesProcurar atualizações
- Torne-se um Sponsor
+ Become a SponsorA 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çãoRepor posição da janela de pesquisaEscreva 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çãoDefinições
@@ -170,6 +174,10 @@
Mostrar resultados da página inicial se o termo de pesquisa estiver vazio.Mostrar histórico na página inicialMá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 abertoEsta opção apenas pode ser editada se o plugin tiver suporte a Página inicial e se estiver ativo.Janela de pesquisa à frenteSobrepõ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 hotkeyDialog Jump Result Navigation BehaviourBehaviour 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 direitoDialog Jump File Navigation BehaviourBehaviour 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 CaminhoProxy HTTP
@@ -445,7 +453,7 @@
ÍconesAtivou o Flow Launcher {0} vezesProcurar atualizações
- Tornar-se patrocinador
+ Torne-se um PatrocinadorEstá 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 positionType 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 PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides 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íciuResetovať pozíciu vyhľadávacieho oknaZadajte 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 IMESkontrolujte 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 ResetReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoSettings
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IconsYou have activated Flow Launcher {0} timesCheck for Updates
- Become A Sponsor
+ Become a SponsorNew 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 ResetReset search window positionType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoPodešavanja
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
IconsAktivirali ste Flow Launcher {0} putaProveri ažuriranja
- Become A Sponsor
+ Become a SponsorNove 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ırlaArama penceresinin konumunu sıfırlaAramak 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çinAyarlar
@@ -171,6 +175,10 @@
Sorgu metni boş olduğunda ana sayfa sonuçlarını gösterin.Geçmiş Sonuçlarını Ana Sayfada GösterAna 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österDiğ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 SponsorUygulamanı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ếmType here to search
+ {0}: This plugin is still initializing...
+ Select this result to requery
+ {0}: Failed to respond!
+ Select this result for more infoCài đặt
@@ -171,6 +175,10 @@
Show home page results when query text is empty.Show History Results in Home PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides other programs' 'Always on Top' setting and displays Flow in the foremost position.
@@ -446,7 +454,7 @@
Biểu tượngBạn đã kích hoạt Flow Launcher {0} lầnKiể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 positionType 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 PageMaximum 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 historyThis can only be edited if plugin supports Home feature and Home Page is enabled.Show Search Window at ForemostOverrides 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 LauncherShow unknown source warningShow warning when installing plugins from unknown sourcesAuto 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/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 ec9179463..7049b5304 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
@@ -72,6 +72,16 @@
OnContent="{DynamicResource enable}" />
+
+
+
+
+ Source="{Binding IcoPathAbsolute, IsAsync=True}" />
+/// A serializable result used to record the last opened history for reopening results.
+/// Inherits common result fields from and adds the original query and execution time.
+///
+public class LastOpenedHistoryResult : Result
+{
+ ///
+ /// The query string from Query.TrimmedQuery property, it is stored as a string instead of the entire Query class .
+ /// This is used so results can be reopened or re-run using the serialized query string.
+ ///
+ public string Query { get; set; } = string.Empty;
+
+ ///
+ /// The local date and time when this result was executed/opened.
+ ///
+ public DateTime ExecutedDateTime { get; set; }
+
+ ///
+ /// Initializes a new instance of .
+ ///
+ public LastOpenedHistoryResult()
+ {
+ }
+
+ ///
+ /// Creates a from an existing .
+ /// Copies required fields and sets up default reopening actions.
+ ///
+ /// The original result to create history from.
+ public LastOpenedHistoryResult(Result result)
+ {
+ Title = result.Title;
+ SubTitle = result.SubTitle;
+ PluginID = result.PluginID;
+ Query = result.OriginQuery.TrimmedQuery;
+ OriginQuery = result.OriginQuery;
+ RecordKey = result.RecordKey;
+ IcoPath = result.IcoPath;
+ PluginDirectory = result.PluginDirectory;
+ Glyph = result.Glyph;
+ ExecutedDateTime = DateTime.Now;
+ // Used for Query History style reopening
+ Action = _ =>
+ {
+ App.API.BackToQueryResults();
+ App.API.ChangeQuery(result.OriginQuery.TrimmedQuery);
+ return false;
+ };
+ // Used for Last Opened History style reopening, currently need to be assigned at MainViewModel.cs
+ AsyncAction = null;
+ }
+
+ ///
+ /// Selectively creates a deep copy of the required properties for
+ /// based on the style of history- Last Opened or Query.
+ /// This copy should be independent of original and full isolated.
+ ///
+ /// A new containing the same required data.
+ public LastOpenedHistoryResult DeepCopyForHistoryStyle(bool isHistoryStyleLastOpened)
+ {
+ // queryValue and glyphValue are captured to ensure they are correctly referenced in the Action delegate.
+ var queryValue = Query;
+ var glyphValue = Glyph;
+
+ var title = string.Empty;
+ var showBadge = false;
+ var badgeIcoPath = string.Empty;
+ var icoPath = string.Empty;
+ var glyph = null as GlyphInfo;
+
+ if (isHistoryStyleLastOpened)
+ {
+ title = Title;
+ icoPath = IcoPath;
+ glyph = glyphValue != null
+ ? new GlyphInfo(glyphValue.FontFamily, glyphValue.Glyph)
+ : null;
+ showBadge = true;
+ badgeIcoPath = Constant.HistoryIcon;
+ }
+ else
+ {
+ title = Localize.executeQuery(Query);
+ icoPath = Constant.HistoryIcon;
+ glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C");
+ showBadge = false;
+ }
+
+ return new LastOpenedHistoryResult
+ {
+ Title = title,
+ // Subtitle has datetime which can cause duplicates when saving.
+ SubTitle = Localize.lastExecuteTime(ExecutedDateTime),
+ // Empty PluginID so the source of last opened history results won't be updated, this copy is meant to be temporary.
+ PluginID = string.Empty,
+ Query = Query,
+ OriginQuery = new Query { TrimmedQuery = Query },
+ RecordKey = RecordKey,
+ IcoPath = icoPath,
+ ShowBadge = showBadge,
+ BadgeIcoPath = badgeIcoPath,
+ PluginDirectory = PluginDirectory,
+ // Used for Query History style reopening
+ Action = _ =>
+ {
+ App.API.BackToQueryResults();
+ App.API.ChangeQuery(queryValue);
+ return false;
+ },
+ // Used for Last Opened History style reopening, currently need to be assigned at MainViewModel.cs
+ AsyncAction = null,
+ Glyph = glyph,
+ ExecutedDateTime = ExecutedDateTime
+ // Note: Other properties are left as default — copy if needed.
+ };
+ }
+
+ ///
+ /// Determines whether the specified is equivalent to this history result.
+ /// Comparison uses when available; otherwise falls back to title/subtitle/plugin id and query.
+ ///
+ /// The result to compare to.
+ /// true if the results are considered equal; otherwise false.
+ public bool Equals(Result r)
+ {
+ if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey))
+ {
+ return Title == r.Title
+ && SubTitle == r.SubTitle
+ && PluginID == r.PluginID
+ && Query == r.OriginQuery.TrimmedQuery;
+ }
+ else
+ {
+ return RecordKey == r.RecordKey
+ && PluginID == r.PluginID
+ && Query == r.OriginQuery.TrimmedQuery;
+ }
+ }
+}
diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs
index 8284f7eea..7bf948399 100644
--- a/Flow.Launcher/Storage/QueryHistory.cs
+++ b/Flow.Launcher/Storage/QueryHistory.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
+using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Storage
@@ -14,28 +15,50 @@ namespace Flow.Launcher.Storage
#pragma warning restore CS0618 // Type or member is obsolete
[JsonInclude]
- public List LastOpenedHistoryItems { get; private set; } = [];
+ public List LastOpenedHistoryItems { get; private set; } = [];
private readonly int _maxHistory = 300;
+ ///
+ /// Migrate legacy history data (stored in ) into the new
+ /// format and append them to
+ /// .
+ ///
+ [Obsolete("For backwards compatibility. Remove after release v2.3.0")]
public void PopulateHistoryFromLegacyHistory()
{
if (Items.Count == 0) return;
// Migrate old history items to new LastOpenedHistoryItems
foreach (var item in Items)
{
- LastOpenedHistoryItems.Add(new LastOpenedHistoryItem
+ LastOpenedHistoryItems.Add(new LastOpenedHistoryResult
{
+ Title = Localize.executeQuery(item.Query),
+ OriginQuery = new Query { TrimmedQuery = item.Query },
Query = item.Query,
+ Action = _ =>
+ {
+ App.API.BackToQueryResults();
+ App.API.ChangeQuery(item.Query);
+ return false;
+ },
ExecutedDateTime = item.ExecutedDateTime
});
}
Items.Clear();
}
+ ///
+ /// Records a result into the last-opened history list ().
+ /// This will also update the IcoPath if existing history item has one that is different.
+ ///
+ /// The result to add to history. Must have a non-empty ..
public void Add(Result result)
{
- if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return;
+ if (string.IsNullOrEmpty(result.OriginQuery.TrimmedQuery)) return;
+ // History results triggered from homepage do not contain PluginID,
+ // these are intentionally not saved otherwise cause duplicates due to subtitle
+ // containing datetime string.
if (string.IsNullOrEmpty(result.PluginID)) return;
// Maintain the max history limit
@@ -44,23 +67,53 @@ namespace Flow.Launcher.Storage
LastOpenedHistoryItems.RemoveAt(0);
}
- // If the last item is the same as the current result, just update the timestamp
- if (LastOpenedHistoryItems.Count > 0 &&
- LastOpenedHistoryItems.Last().Equals(result))
+ // If the last item is the same as the current result, just update the timestamp and the icon path
+ if (LastOpenedHistoryItems.Count > 0 &&
+ TryGetLastOpenedHistoryResult(result, out var existingHistoryItem))
{
- LastOpenedHistoryItems.Last().ExecutedDateTime = DateTime.Now;
+ existingHistoryItem.ExecutedDateTime = DateTime.Now;
+
+ if (existingHistoryItem.IcoPath != result.IcoPath)
+ existingHistoryItem.IcoPath = result.IcoPath;
+
+ if (existingHistoryItem.Glyph?.Glyph != result.Glyph?.Glyph
+ || existingHistoryItem.Glyph?.FontFamily != result.Glyph?.FontFamily)
+ existingHistoryItem.SetGlyph(result.Glyph);
}
else
{
- LastOpenedHistoryItems.Add(new LastOpenedHistoryItem
- {
- Title = result.Title,
- SubTitle = result.SubTitle,
- PluginID = result.PluginID,
- Query = result.OriginQuery.RawQuery,
- RecordKey = result.RecordKey,
- ExecutedDateTime = DateTime.Now
- });
+ LastOpenedHistoryItems.Add(new LastOpenedHistoryResult(result));
+ }
+ }
+
+ ///
+ /// Attempts to find an existing in
+ /// that is considered equal to the supplied .
+ ///
+ private bool TryGetLastOpenedHistoryResult(Result result, out LastOpenedHistoryResult historyItem)
+ {
+ historyItem = LastOpenedHistoryItems.FirstOrDefault(x => x.Equals(result));
+ return historyItem is not null;
+ }
+
+ ///
+ /// Flow uses IcoPathAbsolute property to display result the icons. This refreshes the IcoPathAbsolute
+ /// property using current plugin metadata by updating the PluginDirectory property, which in turn also
+ /// updates IcoPath. This keeps the saved icon paths of results updated correctly if flow is moved around.
+ ///
+ /// Call this after plugins are loaded/initialized.
+ public void UpdateIcoPathAbsolute()
+ {
+ if (LastOpenedHistoryItems.Count == 0) return;
+
+ foreach (var item in LastOpenedHistoryItems)
+ {
+ if (string.IsNullOrEmpty(item.PluginID)) continue;
+
+ var pluginPair = PluginManager.GetPluginForId(item.PluginID);
+ if (pluginPair == null) continue;
+
+ item.PluginDirectory = pluginPair.Metadata.PluginDirectory;
}
}
}
diff --git a/Flow.Launcher/Storage/TopMostRecord.cs b/Flow.Launcher/Storage/TopMostRecord.cs
index 7fc9dcaaa..9708eab97 100644
--- a/Flow.Launcher/Storage/TopMostRecord.cs
+++ b/Flow.Launcher/Storage/TopMostRecord.cs
@@ -113,7 +113,7 @@ namespace Flow.Launcher.Storage
internal bool IsTopMost(Result result)
{
- if (records.IsEmpty || !records.TryGetValue(result.OriginQuery.RawQuery, out var value))
+ if (records.IsEmpty || !records.TryGetValue(result.OriginQuery.TrimmedQuery, out var value))
{
return false;
}
@@ -124,7 +124,7 @@ namespace Flow.Launcher.Storage
internal void Remove(Result result)
{
- records.Remove(result.OriginQuery.RawQuery, out _);
+ records.Remove(result.OriginQuery.TrimmedQuery, out _);
}
internal void AddOrUpdate(Result result)
@@ -136,7 +136,7 @@ namespace Flow.Launcher.Storage
SubTitle = result.SubTitle,
RecordKey = result.RecordKey
};
- records.AddOrUpdate(result.OriginQuery.RawQuery, record, (key, oldValue) => 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/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index 0c0c317ed..6fa4b7e90 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -35,17 +35,18 @@ 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
private readonly FlowLauncherJsonStorage _historyItemsStorage;
- private readonly FlowLauncherJsonStorage _userSelectedRecordStorage;
- private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord;
private readonly History _history;
private int lastHistoryIndex = 1;
+ private readonly FlowLauncherJsonStorage _userSelectedRecordStorage;
+ private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord;
private readonly UserSelectedRecord _userSelectedRecord;
private CancellationTokenSource _updateSource; // Used to cancel old query flows
@@ -63,6 +64,8 @@ namespace Flow.Launcher.ViewModel
Priority = 0 // Priority is for calculating scores in UpdateResultView
};
+ private bool _taskbarShownByFlow = false;
+
#endregion
#region Constructor
@@ -149,11 +152,10 @@ namespace Flow.Launcher.ViewModel
};
_historyItemsStorage = new FlowLauncherJsonStorage();
- _userSelectedRecordStorage = new FlowLauncherJsonStorage();
- _topMostRecord = new FlowLauncherJsonStorageTopMostRecord();
_history = _historyItemsStorage.Load();
- _history.PopulateHistoryFromLegacyHistory();
+ _userSelectedRecordStorage = new FlowLauncherJsonStorage();
_userSelectedRecord = _userSelectedRecordStorage.Load();
+ _topMostRecord = new FlowLauncherJsonStorageTopMostRecord();
ContextMenu = new ResultsViewModel(Settings, this)
{
@@ -283,7 +285,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;
}
@@ -352,11 +354,17 @@ namespace Flow.Launcher.ViewModel
if (QueryResultsSelected())
{
SelectedResults = History;
- History.SelectedIndex = _history.LastOpenedHistoryItems.Count - 1;
+ if (History.Results.Count > 0)
+ {
+ SelectedResults.SelectedIndex = 0;
+ SelectedResults.SelectedItem = History.Results[0];
+ }
}
else
{
SelectedResults = Results;
+ PreviewSelectedItem = Results.SelectedItem;
+ _ = UpdatePreviewAsync();
}
}
@@ -428,7 +436,8 @@ namespace Flow.Launcher.ViewModel
{
// When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing
// i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing
- if (SelectedResults.SelectedItem != null)
+ if (SelectedResults.SelectedItem?.Result != null &&
+ !string.IsNullOrEmpty(SelectedResults.SelectedItem.Result.PluginID)) // Do not show context menu for history results
{
SelectedResults = ContextMenu;
}
@@ -436,13 +445,15 @@ namespace Flow.Launcher.ViewModel
else
{
SelectedResults = Results;
+ PreviewSelectedItem = Results.SelectedItem;
+ _ = UpdatePreviewAsync();
}
}
[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('\\'));
@@ -641,6 +652,8 @@ namespace Flow.Launcher.ViewModel
if (!QueryResultsSelected())
{
SelectedResults = Results;
+ PreviewSelectedItem = Results.SelectedItem;
+ _ = UpdatePreviewAsync();
}
else
{
@@ -1251,22 +1264,12 @@ namespace Flow.Launcher.ViewModel
var selected = Results.SelectedItem?.Result;
- if (selected != null) // SelectedItem returns null if selection is empty.
+ if (selected != null && // SelectedItem returns null if selection is empty.
+ !string.IsNullOrEmpty(selected.PluginID)) // SelectedItem must have a valid PluginID, history results do not.
{
- List results;
- if (selected.PluginID == null) // SelectedItem from history in home page.
- {
- results = new()
- {
- ContextMenuTopMost(selected)
- };
- }
- else
- {
- results = PluginManager.GetContextMenusForPlugin(selected);
- results.Add(ContextMenuTopMost(selected));
- results.Add(ContextMenuPluginInfo(selected));
- }
+ List results = PluginManager.GetContextMenusForPlugin(selected);
+ results.Add(ContextMenuTopMost(selected));
+ results.Add(ContextMenuPluginInfo(selected));
if (!string.IsNullOrEmpty(query))
{
@@ -1317,68 +1320,77 @@ namespace Flow.Launcher.ViewModel
}
}
- private List GetHistoryItems(IEnumerable historyItems)
+ private List GetHistoryItems(IEnumerable historyItems, int? maxResult = null)
{
var results = new List();
- if (Settings.HistoryStyle == HistoryStyle.Query)
- {
- foreach (var h in historyItems)
- {
- var result = new Result
- {
- Title = Localize.executeQuery(h.Query),
- SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
- IcoPath = Constant.HistoryIcon,
- OriginQuery = new Query { RawQuery = h.Query },
- Action = _ =>
- {
- App.API.BackToQueryResults();
- App.API.ChangeQuery(h.Query);
- return false;
- },
- Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C")
- };
- results.Add(result);
- }
- }
- else
- {
- foreach (var h in historyItems)
- {
- var result = new Result
- {
- Title = string.IsNullOrEmpty(h.Title) ? // Old migrated history items have no title
- Localize.executeQuery(h.Query) :
- h.Title,
- SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
- IcoPath = Constant.HistoryIcon,
- OriginQuery = new Query { RawQuery = h.Query },
- AsyncAction = async c =>
- {
- var reflectResult = await ResultHelper.PopulateResultsAsync(h);
- if (reflectResult != null)
- {
- // Record the user selected record for result ranking
- _userSelectedRecord.Add(reflectResult);
- // Since some actions may need to hide the Flow window to execute
- // So let us populate the results of them
- return await reflectResult.ExecuteAsync(c);
- }
+ // Order by executed time descending: Latest -> Oldest
+ historyItems = historyItems.OrderByDescending(x => x.ExecutedDateTime);
- // If we cannot get the result, fallback to re-query
- App.API.BackToQueryResults();
- App.API.ChangeQuery(h.Query);
- return false;
- },
- Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C")
- };
- results.Add(result);
- }
+ if (Settings.HistoryStyle == HistoryStyle.LastOpened)
+ {
+ // Items saved to disk are differentiated by Query also, but LastOpened style only cares about unique results
+ historyItems = historyItems
+ .GroupBy(r => new { r.Title, r.SubTitle, r.PluginID, r.RecordKey })
+ .Select(g => g.First());
}
+
+ // Max history results to return for display
+ if (maxResult.HasValue)
+ {
+ historyItems = historyItems.Take(maxResult.Value);
+ }
+
+ foreach (var item in historyItems)
+ {
+ var copiedItem = item.DeepCopyForHistoryStyle(Settings.HistoryStyle == HistoryStyle.LastOpened);
+
+ if (Settings.HistoryStyle == HistoryStyle.LastOpened)
+ {
+ copiedItem.AsyncAction = async c =>
+ {
+ // Use original history item to reflect correct result because properties like subtitle have been modified in copiedItem
+ var reflectResult = await ResultHelper.PopulateResultsAsync(item);
+ if (reflectResult != null)
+ {
+ // Since some actions may need to hide the Flow window to execute
+ // So let us populate the results of them
+ return await reflectResult.ExecuteAsync(c);
+ }
+
+ // If we cannot get the result, fallback to re-query
+ App.API.BackToQueryResults();
+ App.API.ChangeQuery(copiedItem.Query);
+ return false;
+ };
+ }
+
+ results.Add(copiedItem);
+ }
+
return results;
}
+ ///
+ /// Refreshes the last-opened history storage by migrating legacy entries and
+ /// updating stored icon paths to their resolved (absolute) locations.
+ ///
+ ///
+ /// Calls to refresh absolute icon
+ /// paths on the migrated/saved history entries by updating each item's
+ /// PluginDirectory (which in turn resolves IcoPathAbsolute).
+ ///
+ /// Important:
+ /// - Plugins must be initialized (their metadata and PluginDirectory set)
+ /// before calling this method; otherwise icon resolution cannot be performed.
+ ///
+ internal void RefreshLastOpenedHistoryResults()
+ {
+ _history.PopulateHistoryFromLegacyHistory();
+
+ _history.UpdateIcoPathAbsolute();
+ }
+
private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true)
{
_updateSource?.Cancel();
@@ -1393,7 +1405,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;
@@ -1405,69 +1417,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;
}
@@ -1476,58 +1492,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
@@ -1605,10 +1628,8 @@ namespace Flow.Launcher.ViewModel
void QueryHistoryTask(CancellationToken token)
{
- // Select last history results and revert its order to make sure last history results are on top
- var historyItems = _history.LastOpenedHistoryItems.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse();
-
- var results = GetHistoryItems(historyItems);
+ // Select last history results
+ var results = GetHistoryItems(_history.LastOpenedHistoryItems, Settings.MaxHistoryResultsToShowForHomePage);
if (token.IsCancellationRequested) return;
@@ -1627,7 +1648,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);
@@ -1647,7 +1668,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,
@@ -2125,6 +2146,12 @@ 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)
@@ -2193,6 +2220,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 d4382fb7f..077acfce7 100644
--- a/Flow.Launcher/ViewModel/ResultViewModel.cs
+++ b/Flow.Launcher/ViewModel/ResultViewModel.cs
@@ -141,7 +141,7 @@ namespace Flow.Launcher.ViewModel
private bool GlyphAvailable => Glyph is not null;
- private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPath) || Result.Icon is not null;
+ private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPathAbsolute) || Result.Icon is not null;
private bool BadgeIconAvailable => !string.IsNullOrEmpty(Result.BadgeIcoPath) || Result.BadgeIcon is not null;
@@ -236,7 +236,7 @@ namespace Flow.Launcher.ViewModel
private async Task LoadImageAsync()
{
- var imagePath = Result.IcoPath;
+ var imagePath = Result.IcoPathAbsolute;
var iconDelegate = Result.Icon;
if (ImageLoader.TryGetValue(imagePath, false, out var img))
{
@@ -266,7 +266,7 @@ namespace Flow.Launcher.ViewModel
private async Task LoadPreviewImageAsync()
{
- var imagePath = Result.Preview.PreviewImagePath ?? Result.IcoPath;
+ var imagePath = Result.Preview.PreviewImagePath ?? Result.IcoPathAbsolute;
var iconDelegate = Result.Preview.PreviewDelegate ?? Result.Icon;
if (ImageLoader.TryGetValue(imagePath, true, out var img))
{
@@ -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/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
index 8f0dfb4f5..3e78ac1a3 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -105,8 +105,8 @@
-
-
+
+
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/en.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml
index b12972b1b..5f9a3ca5a 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml
@@ -14,6 +14,7 @@
Comma (,)Dot (.)Max. decimal places
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
\ 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.Calculator/Main.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
index a20a1ad5d..1b9a38e18 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
@@ -363,7 +363,7 @@ namespace Flow.Launcher.Plugin.Calculator
string integerPart = parts[0];
string fractionalPart = parts.Length > 1 ? parts[1] : string.Empty;
- if (integerPart.Length > 3)
+ if (_settings.UseThousandsSeparator && integerPart.Length > 3)
{
integerPart = ThousandGroupRegex.Replace(integerPart, groupSeparator);
}
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Settings.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Settings.cs
index 1544dc41f..69cd17ed2 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Settings.cs
@@ -7,4 +7,6 @@ public class Settings
public int MaxDecimalPlaces { get; set; } = 10;
public bool ShowErrorMessage { get; set; } = false;
+
+ public bool UseThousandsSeparator { get; set; } = true;
}
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml
index 9e7549b2d..82f8eec60 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml
@@ -16,6 +16,7 @@
+
@@ -66,6 +67,16 @@
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
+ Content="{DynamicResource flowlauncher_plugin_calculator_use_thousands_separator}"
+ IsChecked="{Binding Settings.UseThousandsSeparator, Mode=TwoWay}" />
+
+
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říkazHotovoPovoleno
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 KeywordFærdigEnabled
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üsselwortFertigAktiviert
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 KeywordDoneEnabled
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 KeywordHechoEnabled
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 actualAceptarActivado
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 coursTerminerActivé
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 CorrenteConfermaAbilitato
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 EngineDirectory 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 handlingUtførtAktivert
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 KeywordKlaarEnabled
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 akcjiZapiszAktywny
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 KeywordFinalizadoEnabled
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 atualOKAtivo
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íkazHotovoPovolené
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 KeywordDoneEnabled
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 KeywordGotovoEnabled
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 KelimeTamamEtkin
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ạiXongĐã 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 d7b069082..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,48 +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))
+ var keyword = query.ActionKeyword.Length == 0 ? Query.GlobalPluginWildcardSign : query.ActionKeyword;
+
+ // No action keyword matched - plugin should not handle this query, return empty results.
+ var activeActionKeywords = Settings.GetActiveActionKeywords(keyword);
+ if (activeActionKeywords.Count == 0)
{
- if (string.IsNullOrEmpty(query.Search) && ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword))
- return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
- }
- else
- {
- // No action keyword matched- plugin should not handle this query, return empty results.
- 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);
@@ -93,37 +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;
-
- case true or false
- when ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword):
- return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
-
default:
- return results.ToList();
+ return [.. results];
+
}
- // Merge Quick Access Link results for non-path searches.
- results.UnionWith(QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks));
+ 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)
{
@@ -137,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(),
@@ -172,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)
@@ -197,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);
@@ -209,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;
@@ -231,7 +247,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
}
if (token.IsCancellationRequested)
- return new List();
+ return [.. results];
try
{
@@ -246,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
@@ -275,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..30c2c7f14 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")
};
}
@@ -528,7 +532,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
[RelayCommand]
private void OpenShellPath()
{
- var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
+ var path = PromptUserSelectPath(ResultType.File, Settings.ShellPath != null ? Path.GetDirectoryName(Settings.ShellPath) : null);
if (path is null)
return;
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 pluginsWould 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 ExplorerArgs
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/NativeMethods.txt b/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
index ecd547dff..a8fe178c7 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
+++ b/Plugins/Flow.Launcher.Plugin.Program/NativeMethods.txt
@@ -7,4 +7,7 @@ S_OK
SLGP_FLAGS
WIN32_FIND_DATAW
SLR_FLAGS
-IShellLinkW
\ No newline at end of file
+IShellItem
+SHCreateItemFromParsingName
+IShellLinkW
+CoTaskMemFree
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs
index 5c2f6f976..815b74b96 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLocalization.cs
@@ -3,7 +3,6 @@ using System.IO;
using System.Runtime.InteropServices;
using Windows.Win32;
using Windows.Win32.Foundation;
-using Windows.Win32.System.LibraryLoader;
namespace Flow.Launcher.Plugin.Program.Programs
{
@@ -21,46 +20,28 @@ namespace Flow.Launcher.Plugin.Program.Programs
/// The localized name as string or .
public static unsafe string GetLocalizedName(string path)
{
- const int capacity = 1024;
- Span buffer = new char[capacity];
-
- // If there is no resource to localize a file name the method returns a non zero value.
- fixed (char* bufferPtr = buffer)
+ int retCode = PInvoke.SHCreateItemFromParsingName(path, null, typeof(Windows.Win32.UI.Shell.IShellItem).GUID, out object shellItemObj);
+ if (retCode != 0 || shellItemObj is not Windows.Win32.UI.Shell.IShellItem shellItem)
{
- int id;
- fixed (char* pathPtr = path)
- {
- var result = PInvoke.SHGetLocalizedName(new PCWSTR(pathPtr), bufferPtr, capacity, &id);
-
- if (result != HRESULT.S_OK)
- {
- return string.Empty;
- }
-
- var resourcePathStr = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
- fixed (char* resourcePathPtr = resourcePathStr)
- {
- _ = PInvoke.ExpandEnvironmentStrings(new PCWSTR(resourcePathPtr), bufferPtr, capacity);
- using var handle = PInvoke.LoadLibraryEx(resourcePathStr,
- LOAD_LIBRARY_FLAGS.DONT_RESOLVE_DLL_REFERENCES | LOAD_LIBRARY_FLAGS.LOAD_LIBRARY_AS_DATAFILE);
- if (handle.IsInvalid)
- {
- return string.Empty;
- }
-
- // not sure about the behavior of Pinvoke.LoadString, so we clear the buffer before using it (so it must be a null-terminated string)
- buffer.Clear();
-
- if (PInvoke.LoadString(handle, (uint)id, buffer, capacity) != 0)
- {
- var lString = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(bufferPtr).ToString();
- return lString;
- }
- }
- }
+ return string.Empty;
}
- return string.Empty;
+ try
+ {
+ PWSTR displayName;
+ shellItem.GetDisplayName(Windows.Win32.UI.Shell.SIGDN.SIGDN_NORMALDISPLAY, &displayName);
+ string filename = displayName.ToString();
+ PInvoke.CoTaskMemFree(displayName);
+ return filename;
+ }
+ catch
+ {
+ return string.Empty;
+ }
+ finally
+ {
+ Marshal.ReleaseComObject(shellItem);
+ }
}
///
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 contentOpen Flow Launcher's log locationCheck 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 @@
ElegirAplicació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 navegadorNueva pestañaNueva 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ı yoluYeni sekmeYeni 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/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
index 42176376b..3b3add106 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
@@ -50,6 +50,10 @@
+
+
+
+
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
index 5d65e4462..2b2b06fae 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
@@ -21,6 +21,7 @@
URLSearchUse Search Query Autocomplete
+ Max SuggestionsAutocomplete Data from:Please select a web searchAre you sure you want to delete {0}?
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 URLLa palabra clave de acción ya está en uso, por favor, introduzca una diferenteCorrecto
- 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 girinizAnahtar 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.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
index b9b8a0b19..299e27499 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -91,6 +91,7 @@ namespace Flow.Launcher.Plugin.WebSearch
if (token.IsCancellationRequested)
return null;
+
}
return results;
@@ -126,7 +127,7 @@ namespace Flow.Launcher.Plugin.WebSearch
token.ThrowIfCancellationRequested();
- var resultsFromSuggestion = suggestions?.Select(o => new Result
+ var resultsFromSuggestion = suggestions?.Take(_settings.MaxSuggestions).Select(o => new Result
{
Title = o,
SubTitle = subtitle,
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs
index 0c0ac4b84..31540ad92 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Settings.cs
@@ -205,6 +205,23 @@ namespace Flow.Launcher.Plugin.WebSearch
}
}
+ private int maxSuggestions = 1;
+ public int MaxSuggestions
+ {
+ get => maxSuggestions;
+ set
+ {
+ if (value > 0 && value <= 1000)
+ {
+ if (maxSuggestions != value)
+ {
+ maxSuggestions = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+ }
+
[JsonIgnore]
public SuggestionSource[] Suggestions { get; set; } = {
new Google(),
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
index 152558e81..e4f3485cd 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
@@ -3,7 +3,9 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vm="clr-namespace:Flow.Launcher.Plugin.WebSearch"
d:DataContext="{d:DesignInstance vm:SettingsViewModel}"
d:DesignHeight="300"
@@ -45,17 +47,17 @@
x:Name="SearchSourcesListView"
Grid.Row="0"
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
+ AllowDrop="True"
BorderBrush="DarkGray"
BorderThickness="1"
+ Drop="ListView_Drop"
GridViewColumnHeader.Click="SortByColumn"
ItemsSource="{Binding Settings.SearchSources}"
MouseDoubleClick="MouseDoubleClickItem"
- SelectedItem="{Binding Settings.SelectedSearchSource}"
- SizeChanged="ListView_SizeChanged"
PreviewMouseLeftButtonDown="ListView_PreviewMouseLeftButtonDown"
PreviewMouseMove="ListView_PreviewMouseMove"
- AllowDrop="True"
- Drop="ListView_Drop"
+ SelectedItem="{Binding Settings.SelectedSearchSource}"
+ SizeChanged="ListView_SizeChanged"
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
@@ -146,31 +148,43 @@
-
-
-
+
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs
index 6dc766fff..1c1dd3116 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml.cs
@@ -240,5 +240,15 @@ namespace Flow.Launcher.Plugin.WebSearch
}
return null;
}
+
+ // This is used for NumberBox to force its value to be 1 when the user clears the value
+ private void NumberBox_ValueChanged(iNKORE.UI.WPF.Modern.Controls.NumberBox sender, iNKORE.UI.WPF.Modern.Controls.NumberBoxValueChangedEventArgs args)
+ {
+ if (double.IsNaN(args.NewValue))
+ {
+ sender.Value = 1;
+ _settings.MaxSuggestions = (int)sender.Value;
+ }
+ }
}
}
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ánkyArea 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