From 97d7eab1a7ef74791c300b4bae6c52321bb185a8 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Wed, 4 Feb 2026 22:46:23 +0000
Subject: [PATCH 01/24] Bump Microsoft.Windows.CsWin32 from 0.3.205 to 0.3.269
---
updated-dependencies:
- dependency-name: Microsoft.Windows.CsWin32
dependency-version: 0.3.269
dependency-type: direct:production
update-type: version-update:semver-patch
- dependency-name: Microsoft.Windows.CsWin32
dependency-version: 0.3.269
dependency-type: direct:production
update-type: version-update:semver-patch
- dependency-name: Microsoft.Windows.CsWin32
dependency-version: 0.3.269
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
.../Flow.Launcher.Plugin.csproj | 2 +-
Flow.Launcher.Plugin/packages.lock.json | 20 +++++++++----------
.../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +-
.../Flow.Launcher.Plugin.Sys.csproj | 2 +-
4 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
index 103a72113..b5ba36f98 100644
--- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
+++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
@@ -74,7 +74,7 @@
-
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Flow.Launcher.Plugin/packages.lock.json b/Flow.Launcher.Plugin/packages.lock.json
index 3240b3981..662192b4a 100644
--- a/Flow.Launcher.Plugin/packages.lock.json
+++ b/Flow.Launcher.Plugin/packages.lock.json
@@ -26,13 +26,13 @@
},
"Microsoft.Windows.CsWin32": {
"type": "Direct",
- "requested": "[0.3.205, )",
- "resolved": "0.3.205",
- "contentHash": "U5wGAnyKd7/I2YMd43nogm81VMtjiKzZ9dsLMVI4eAB7jtv5IEj0gprj0q/F3iRmAIaGv5omOf8iSYx2+nE6BQ==",
+ "requested": "[0.3.269, )",
+ "resolved": "0.3.269",
+ "contentHash": "O4GVJ0ymxcoFRGS07VcoEClj7A9PIciHIjWDrPymzonhYlOfM7V0ZqGBUK19cUH3BPca9MfSOH0KLK/9JzQ8+Q==",
"dependencies": {
"Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha",
- "Microsoft.Windows.SDK.Win32Metadata": "61.0.15-preview",
- "Microsoft.Windows.WDK.Win32Metadata": "0.12.8-experimental"
+ "Microsoft.Windows.SDK.Win32Metadata": "69.0.7-preview",
+ "Microsoft.Windows.WDK.Win32Metadata": "0.13.25-experimental"
}
},
"PropertyChanged.Fody": {
@@ -61,15 +61,15 @@
},
"Microsoft.Windows.SDK.Win32Metadata": {
"type": "Transitive",
- "resolved": "61.0.15-preview",
- "contentHash": "cysex3dazKtCPALCluC2XX3f5Aedy9H2pw5jb+TW5uas2rkem1Z7FRnbUrg2vKx0pk0Qz+4EJNr37HdYTEcvEQ=="
+ "resolved": "69.0.7-preview",
+ "contentHash": "RJoNjQJVCIDNLPbvYuaygCFknTyAxOUE45of1voj0jjOgJa9MB2m1/G8L8F3IYc+2EFG5aqa/9y8PEx7Tk2tLQ=="
},
"Microsoft.Windows.WDK.Win32Metadata": {
"type": "Transitive",
- "resolved": "0.12.8-experimental",
- "contentHash": "3n8R44/Z96Ly+ty4eYVJfESqbzvpw96lRLs3zOzyDmr1x1Kw7FNn5CyE416q+bZQV3e1HRuMUvyegMeRE/WedA==",
+ "resolved": "0.13.25-experimental",
+ "contentHash": "IM50tb/+UIwBr9FMr6ZKcZjCMW+Axo6NjGqKxgjUfyCY8dRnYUfrJEXxAaXoWtYP4X8EmASmC1Jtwh4XucseZg==",
"dependencies": {
- "Microsoft.Windows.SDK.Win32Metadata": "61.0.15-preview"
+ "Microsoft.Windows.SDK.Win32Metadata": "63.0.31-preview"
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
index 39586771f..ec8a32b95 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
@@ -54,7 +54,7 @@
-
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
index 4cf09baab..1ef6dc495 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
@@ -60,7 +60,7 @@
-
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
From d4f472a64ea30cf5567484af621f148df8f31d97 Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Thu, 5 Feb 2026 20:28:37 +0800
Subject: [PATCH 02/24] Update AdjustTokenPrivileges PInvoke usage
Refactored the AdjustTokenPrivileges call to use null for the previous state and an out variable for the return length, improving compatibility with the PInvoke signature and aligning with recommended usage.
---
Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index 57b9749f7..e0da6cbe1 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -175,7 +175,7 @@ namespace Flow.Launcher.Plugin.Sys
Privileges = new() { e0 = new LUID_AND_ATTRIBUTES { Luid = luid, Attributes = TOKEN_PRIVILEGES_ATTRIBUTES.SE_PRIVILEGE_ENABLED } }
};
- if (!PInvoke.AdjustTokenPrivileges(tokenHandle, false, &privileges, 0, null, null))
+ if (!PInvoke.AdjustTokenPrivileges(tokenHandle, false, &privileges, null, out var _))
{
return false;
}
From 0717933459f3999c60c7eb910058340ef8dda1e4 Mon Sep 17 00:00:00 2001
From: Jack Ye
Date: Sun, 8 Feb 2026 09:49:12 +0800
Subject: [PATCH 03/24] Fix progress query management and thread safety (#4135)
---
Flow.Launcher/ViewModel/MainViewModel.cs | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index ba170feb0..333ac3652 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
@@ -37,7 +38,7 @@ namespace Flow.Launcher.ViewModel
private Query _lastQuery;
private bool _previousIsHomeQuery;
- private Query _progressQuery; // Used for QueryResultAsync
+ private readonly ConcurrentDictionary _progressQueryDict = new(); // 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
@@ -1415,6 +1416,9 @@ namespace Flow.Launcher.ViewModel
return;
}
+ // Create a Guid for this update session so that we can filter out in progress checking
+ var updateGuid = Guid.NewGuid();
+
try
{
_updateSource?.Dispose();
@@ -1426,7 +1430,7 @@ namespace Flow.Launcher.ViewModel
ProgressBarVisibility = Visibility.Hidden;
- _progressQuery = query;
+ _progressQueryDict.TryAdd(updateGuid, query);
_updateQuery = query;
// Switch to ThreadPool thread
@@ -1481,7 +1485,8 @@ namespace Flow.Launcher.ViewModel
_ = 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 (_progressQuery != null && _progressQuery.OriginalQuery == query.OriginalQuery)
+ if (_progressQueryDict.TryGetValue(updateGuid, out var progressQuery) &&
+ progressQuery.OriginalQuery == query.OriginalQuery)
{
ProgressBarVisibility = Visibility.Visible;
}
@@ -1537,7 +1542,7 @@ namespace Flow.Launcher.ViewModel
// this should happen once after all queries are done so progress bar should continue
// until the end of all querying
- _progressQuery = null;
+ _progressQueryDict.Remove(updateGuid, out _);
if (!currentCancellationToken.IsCancellationRequested)
{
@@ -1547,8 +1552,8 @@ namespace Flow.Launcher.ViewModel
}
finally
{
- // this make sures progress query is null when this query is canceled
- _progressQuery = null;
+ // this ensures the query is removed from the progress tracking dictionary when this query is canceled or completes
+ _progressQueryDict.Remove(updateGuid, out _);
}
// Local function
From 0f829d0b911d449b16ccaa11c0537e6920614d23 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 10 Feb 2026 01:07:13 +0000
Subject: [PATCH 04/24] Bump SkiaSharp from 3.119.1 to 3.119.2
---
updated-dependencies:
- dependency-name: SkiaSharp
dependency-version: 3.119.2
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
.../Flow.Launcher.Plugin.BrowserBookmark.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 3e78ac1a3..cb86f719e 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -107,7 +107,7 @@
-
+
From 498913e71d12ce694426ac0d1020f97d330adbfb Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 10 Feb 2026 22:45:10 +0000
Subject: [PATCH 05/24] Bump Microsoft.Data.Sqlite from 10.0.2 to 10.0.3
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
dependency-version: 10.0.3
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
.../Flow.Launcher.Plugin.BrowserBookmark.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 cb86f719e..9fd6ff5d8 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -105,7 +105,7 @@
-
+
From 60ef8e648c7b7f43f7cf713fc1a508fb79bb0378 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue, 10 Feb 2026 22:45:26 +0000
Subject: [PATCH 06/24] Bump Microsoft.SourceLink.GitHub from 10.0.102 to
10.0.103
---
updated-dependencies:
- dependency-name: Microsoft.SourceLink.GitHub
dependency-version: 10.0.103
dependency-type: direct:production
update-type: version-update:semver-patch
...
Signed-off-by: dependabot[bot]
---
.../Flow.Launcher.Plugin.csproj | 2 +-
Flow.Launcher.Plugin/packages.lock.json | 18 +++++++++---------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
index b5ba36f98..ee77d7f75 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/packages.lock.json b/Flow.Launcher.Plugin/packages.lock.json
index 662192b4a..7565ec3f4 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": "[10.0.102, )",
- "resolved": "10.0.102",
- "contentHash": "Oxq3RCIJSdtpIU4hLqO7XaDe/Ra3HS9Wi8rJl838SAg6Zu1iQjerA0+xXWBgUFYbgknUGCLOU0T+lzMLkvY9Qg==",
+ "requested": "[10.0.103, )",
+ "resolved": "10.0.103",
+ "contentHash": "qZk7r40ftpZY+/sO019sgWAWfNqC2CLSspDdAxNYCJU/bCi/8jVwvOMjzb/d5gjCRNzQ4OCYgBfhdpQyVwLTyw==",
"dependencies": {
- "Microsoft.Build.Tasks.Git": "10.0.102",
- "Microsoft.SourceLink.Common": "10.0.102"
+ "Microsoft.Build.Tasks.Git": "10.0.103",
+ "Microsoft.SourceLink.Common": "10.0.103"
}
},
"Microsoft.Windows.CsWin32": {
@@ -46,13 +46,13 @@
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
- "resolved": "10.0.102",
- "contentHash": "0i81LYX31U6UiXz4NOLbvc++u+/mVDmOt+PskrM/MygpDxkv9THKQyRUmavBpLK6iBV0abNWnn+CQgSRz//Pwg=="
+ "resolved": "10.0.103",
+ "contentHash": "QoiCMcPuxC6eqRQmrmF9zBY96ejIznXtve/lJJbonGD9I5Aygf2AUCOWslGiCEtBbfWRSuUnepBjuuVOdAl5ag=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
- "resolved": "10.0.102",
- "contentHash": "Mk1IMb9q5tahC2NltxYXFkLBtuBvfBoCQ3pIxYQWfzbCE9o1OB9SsHe0hnNGo7lWgTA/ePbFAJLWu6nLL9K17A=="
+ "resolved": "10.0.103",
+ "contentHash": "cMtGW5/r0ck72Jg2QwZcNTX59z+iB/B1kW84VMa/eX8L19DhHIuIcQjfK0pgLLBxd60Jl0Bj9GUolcM0MnJnZA=="
},
"Microsoft.Windows.SDK.Win32Docs": {
"type": "Transitive",
From cb52fa6ab734683e99a3f3d327036b484ea954f7 Mon Sep 17 00:00:00 2001
From: umutKaracelebi
Date: Thu, 19 Feb 2026 21:29:39 +0300
Subject: [PATCH 07/24] Fix typo: 'can be change' -> 'can be changed' in Drag &
Drop section
---
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e7595fff5..d8f5bb030 100644
--- a/README.md
+++ b/README.md
@@ -135,7 +135,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
- Drag a file/folder to File Explorer, or even Discord.
-- Copy/move behavior can be change via Ctrl or Shift, and the operation is displayed on the mouse cursor.
+- Copy/move behavior can be changed via Ctrl or Shift, and the operation is displayed on the mouse cursor.
### Priority
From 9c3dfcd09f782ae0fe0c0a6fabd36bc0d597cf42 Mon Sep 17 00:00:00 2001
From: umutKaracelebi
Date: Thu, 19 Feb 2026 21:50:29 +0300
Subject: [PATCH 08/24] README Polish: fixed grammar, consistency, and phrasing
---
README.md | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index d8f5bb030..c2aae3b83 100644
--- a/README.md
+++ b/README.md
@@ -79,7 +79,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
-- Support search using environment variable paths.
+- Supports search using environment variable paths.
### Web Searches & URLs
@@ -141,7 +141,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
-- Prioritise the order of each plugin's results.
+- Prioritize the order of each plugin's results.
### Preview Panel
@@ -327,7 +327,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
| Check For Update | Check for new Flow Launcher update |
| Open Log Location | Open Flow Launcher's log location |
| Index Option | Open Windows Search Index window |
-| Flow Launcher Tips | Visit Flow Launcher's documentation for more help and how to use tips |
+| Flow Launcher Tips | Visit Flow Launcher's documentation for more help and usage tips |
| Flow Launcher UserData Folder | Open the location where Flow Launcher's settings are stored |
| Toggle Game Mode | Toggle Game Mode |
| Set Flow Launcher Theme | Set the Flow Launcher Theme |
@@ -397,9 +397,9 @@ Our UI library is using [iNKORE.UI.WPF.Modern](https://github.com/iNKORE-NET/UI.
-### New changes
+### New Changes
-All changes to flow are captured via pull requests. Some new changes will have been merged but still pending release, this means while a change may not exist in the current release, it may very well have been accepted and merged into the dev branch and available as a pre-release download. It is therefore a good idea to search through the open and closed pull requests before you start to make changes to ensure the change you intend to make is not already done.
+All changes to Flow are captured via pull requests. Some new changes may have been merged but are still pending release. This means that while a change may not exist in the current release, it may have been accepted and merged into the dev branch and is available as a pre-release download. It is therefore a good idea to search through the open and closed pull requests before you start to make changes to ensure the change you intend to make is not already done.
Each of the pull requests will be marked with a milestone indicating the planned release version for the change.
From 2b50c4faae3154b3e651cd41343a13700ff15bef Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Fri, 20 Feb 2026 12:22:44 +0800
Subject: [PATCH 09/24] README Polish: fixed Flow
---
README.md | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index c2aae3b83..2dbeb8b42 100644
--- a/README.md
+++ b/README.md
@@ -19,9 +19,9 @@
A quick file search and app launcher for Windows with community-made plugins.
-Dedicated to making your work flow more seamless. Search everything from applications, files, bookmarks, YouTube, Twitter and more. Flow will continue to evolve, designed to be open and built with the community at heart.
+Dedicated to making your workflow more seamless. Search everything from applications, files, bookmarks, YouTube, Twitter and more. Flow will continue to evolve, designed to be open and built with the community at heart.
-
Remember to star it, flow will love you more :)
+
Remember to star it, Flow will love you more :)
@@ -228,7 +228,7 @@ Or download the [early access version](https://github.com/Flow-Launcher/Prerelea
## 📦 Plugins
- Support wide range of plugins. Visit [here](https://www.flowlauncher.com/plugins/) for our plugin portfolio.
-- Publish your own plugin to flow! Create plugins in:
+- Publish your own plugin to Flow! Create plugins in:
@@ -407,7 +407,7 @@ Each of the pull requests will be marked with a milestone indicating the planned
Contributions are very welcome, in addition to the main project (C#) there are also [documentation](https://github.com/Flow-Launcher/docs) (md), [website](https://github.com/Flow-Launcher/flow-launcher.github.io) (html/css) and [others](https://github.com/Flow-Launcher) that can be contributed to. If you are unsure of a change you want to make, let us know in the [Discussions](https://github.com/Flow-Launcher/Flow.Launcher/discussions/categories/ideas), otherwise feel free to submit a pull request.
-You will find the main goals of flow placed under the [Projects board](https://github.com/orgs/Flow-Launcher/projects/4), so feel free to contribute on that. If you would like to make small incremental changes, feel free to do so as well.
+You will find the main goals of Flow placed under the [Projects board](https://github.com/orgs/Flow-Launcher/projects/4), so feel free to contribute on that. If you would like to make small incremental changes, feel free to do so as well.
Get in touch if you would like to join the Flow-Launcher Team and help build this great tool.
From 12fc597b56553f4720d71e83d9dae4e5da1e32a9 Mon Sep 17 00:00:00 2001
From: DB P
Date: Fri, 20 Feb 2026 17:06:31 +0900
Subject: [PATCH 10/24] Add Checkbox for Skip Confirm
---
Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml | 3 +++
Plugins/Flow.Launcher.Plugin.Sys/Settings.cs | 9 +++++++++
.../Flow.Launcher.Plugin.Sys/SettingsViewModel.cs | 2 ++
Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml | 13 ++++++++++---
4 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
index 9e9a2f93d..33b936ead 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/en.xaml
@@ -3,6 +3,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs b/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs
index 96a545e74..dc6bf9b4e 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs
@@ -124,4 +124,13 @@ public class Settings : BaseModel
[JsonIgnore]
public Command SelectedCommand { get; set; }
+ private bool _skipPowerActionConfirmation;
+ public bool SkipPowerActionConfirmation
+ {
+ get => _skipPowerActionConfirmation;
+ set
+ {
+ _skipPowerActionConfirmation = value;
+ }
+ }
}
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs
index bda8c6c04..b02561a01 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs
@@ -4,4 +4,6 @@
{
public Settings Settings { get; } = settings;
}
+
+
}
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml b/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml
index 7908bd1e3..fda3128f5 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml
@@ -12,13 +12,20 @@
+
-
+
+
+
From 2d7d025682544c941e04ab74fcb7c3e40cf5e199 Mon Sep 17 00:00:00 2001
From: DB P
Date: Fri, 20 Feb 2026 17:18:21 +0900
Subject: [PATCH 11/24] Add Skip logic in command
---
Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 74 +++++++++++++-----------
1 file changed, 41 insertions(+), 33 deletions(-)
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index e0da6cbe1..bd4360a41 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -193,7 +193,7 @@ namespace Flow.Launcher.Plugin.Sys
}
}
- private static List Commands(Query query)
+ private List Commands(Query query)
{
var results = new List();
var recycleBinFolder = "shell:RecycleBinFolder";
@@ -206,22 +206,23 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\shutdown.png",
Action = c =>
{
- var result = Context.API.ShowMsgBox(
- Localize.flowlauncher_plugin_sys_dlgtext_shutdown_computer(),
- Localize.flowlauncher_plugin_sys_shutdown_computer(),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
+ MessageBoxResult result = _settings.SkipPowerActionConfirmation
+ ? MessageBoxResult.Yes
+ : Context.API.ShowMsgBox(
+ Localize.flowlauncher_plugin_sys_dlgtext_shutdown_computer(),
+ Localize.flowlauncher_plugin_sys_shutdown_computer(),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
+
if (result == MessageBoxResult.Yes)
{
- // Save settings before shutdown to avoid data loss
Context.API.SaveAppAllSettings();
-
if (EnableShutdownPrivilege())
PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_SHUTDOWN | EXIT_WINDOWS_FLAGS.EWX_POWEROFF, REASON);
else
Process.Start("shutdown", "/s /t 0");
}
return true;
- }
+ }
},
new Result
{
@@ -230,21 +231,22 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\restart.png",
Action = c =>
{
- var result = Context.API.ShowMsgBox(
- Localize.flowlauncher_plugin_sys_dlgtext_restart_computer(),
- Localize.flowlauncher_plugin_sys_restart_computer(),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
- if (result == MessageBoxResult.Yes)
- {
- // Save settings before restart to avoid data loss
- Context.API.SaveAppAllSettings();
+ MessageBoxResult result = _settings.SkipPowerActionConfirmation
+ ? MessageBoxResult.Yes
+ : Context.API.ShowMsgBox(
+ Localize.flowlauncher_plugin_sys_dlgtext_restart_computer(),
+ Localize.flowlauncher_plugin_sys_restart_computer(),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
- if (EnableShutdownPrivilege())
- PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, REASON);
- else
- Process.Start("shutdown", "/r /t 0");
- }
- return true;
+ if (result == MessageBoxResult.Yes)
+ {
+ Context.API.SaveAppAllSettings();
+ if (EnableShutdownPrivilege())
+ PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, REASON);
+ else
+ Process.Start("shutdown", "/r /t 0");
+ }
+ return true;
}
},
new Result
@@ -254,10 +256,13 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\restart_advanced.png",
Action = c =>
{
- var result = Context.API.ShowMsgBox(
- Localize.flowlauncher_plugin_sys_dlgtext_restart_computer_advanced(),
- Localize.flowlauncher_plugin_sys_restart_computer(),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
+ var result = _settings.SkipPowerActionConfirmation
+ ? MessageBoxResult.Yes
+ : Context.API.ShowMsgBox(
+ Localize.flowlauncher_plugin_sys_dlgtext_restart_computer_advanced(),
+ Localize.flowlauncher_plugin_sys_restart_computer(),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
+
if (result == MessageBoxResult.Yes)
{
// Save settings before advanced restart to avoid data loss
@@ -278,13 +283,16 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\logoff.png",
Action = c =>
{
- var result = Context.API.ShowMsgBox(
- Localize.flowlauncher_plugin_sys_dlgtext_logoff_computer(),
- Localize.flowlauncher_plugin_sys_log_off(),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
- if (result == MessageBoxResult.Yes)
- PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, REASON);
- return true;
+ MessageBoxResult result = _settings.SkipPowerActionConfirmation
+ ? MessageBoxResult.Yes
+ : Context.API.ShowMsgBox(
+ Localize.flowlauncher_plugin_sys_dlgtext_logoff_computer(),
+ Localize.flowlauncher_plugin_sys_log_off(),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
+
+ if (result == MessageBoxResult.Yes)
+ PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, REASON);
+ return true;
}
},
new Result
From cecd90e6750a7633c82c5928dabfe05c3dce2355 Mon Sep 17 00:00:00 2001
From: DB P
Date: Fri, 20 Feb 2026 17:34:37 +0900
Subject: [PATCH 12/24] Refactor: Improve power action logic and property
setter - Add braces for better readability in shutdown/reboot logic
(Main.cs). - Prevent redundant OnPropertyChanged calls in
_skipPowerActionConfirmation setter (Settings.cs).
---
Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 20 ++++++++++----------
Plugins/Flow.Launcher.Plugin.Sys/Settings.cs | 5 +++++
2 files changed, 15 insertions(+), 10 deletions(-)
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index bd4360a41..72b02052d 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -222,7 +222,7 @@ namespace Flow.Launcher.Plugin.Sys
Process.Start("shutdown", "/s /t 0");
}
return true;
- }
+ }
},
new Result
{
@@ -238,15 +238,15 @@ namespace Flow.Launcher.Plugin.Sys
Localize.flowlauncher_plugin_sys_restart_computer(),
MessageBoxButton.YesNo, MessageBoxImage.Warning);
- if (result == MessageBoxResult.Yes)
- {
- Context.API.SaveAppAllSettings();
- if (EnableShutdownPrivilege())
- PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, REASON);
- else
- Process.Start("shutdown", "/r /t 0");
- }
- return true;
+ if (result == MessageBoxResult.Yes)
+ {
+ Context.API.SaveAppAllSettings();
+ if (EnableShutdownPrivilege())
+ PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_REBOOT, REASON);
+ else
+ Process.Start("shutdown", "/r /t 0");
+ }
+ return true;
}
},
new Result
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs b/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs
index dc6bf9b4e..c24c51961 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Settings.cs
@@ -130,7 +130,12 @@ public class Settings : BaseModel
get => _skipPowerActionConfirmation;
set
{
+ if (_skipPowerActionConfirmation == value)
+ {
+ return;
+ }
_skipPowerActionConfirmation = value;
+ OnPropertyChanged();
}
}
}
From 7e9a6268915a69dd5a1e2d831e3ed5f8fa917066 Mon Sep 17 00:00:00 2001
From: DB P
Date: Fri, 20 Feb 2026 17:40:27 +0900
Subject: [PATCH 13/24] style: fix indentation and tab spacing
---
Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index 72b02052d..3ec09a17b 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -232,11 +232,11 @@ namespace Flow.Launcher.Plugin.Sys
Action = c =>
{
MessageBoxResult result = _settings.SkipPowerActionConfirmation
- ? MessageBoxResult.Yes
- : Context.API.ShowMsgBox(
- Localize.flowlauncher_plugin_sys_dlgtext_restart_computer(),
- Localize.flowlauncher_plugin_sys_restart_computer(),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
+ ? MessageBoxResult.Yes
+ : Context.API.ShowMsgBox(
+ Localize.flowlauncher_plugin_sys_dlgtext_restart_computer(),
+ Localize.flowlauncher_plugin_sys_restart_computer(),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
if (result == MessageBoxResult.Yes)
{
From a99b8399fea67f6c38dcb3fb27f8a5288c4c1b49 Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Sat, 21 Feb 2026 14:51:20 +0800
Subject: [PATCH 14/24] Improve code quality
---
Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 22 +++++++++----------
.../SettingsViewModel.cs | 2 --
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
index 3ec09a17b..78effb6d2 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs
@@ -206,7 +206,7 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\shutdown.png",
Action = c =>
{
- MessageBoxResult result = _settings.SkipPowerActionConfirmation
+ var result = _settings.SkipPowerActionConfirmation
? MessageBoxResult.Yes
: Context.API.ShowMsgBox(
Localize.flowlauncher_plugin_sys_dlgtext_shutdown_computer(),
@@ -231,7 +231,7 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\restart.png",
Action = c =>
{
- MessageBoxResult result = _settings.SkipPowerActionConfirmation
+ var result = _settings.SkipPowerActionConfirmation
? MessageBoxResult.Yes
: Context.API.ShowMsgBox(
Localize.flowlauncher_plugin_sys_dlgtext_restart_computer(),
@@ -283,16 +283,16 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\logoff.png",
Action = c =>
{
- MessageBoxResult result = _settings.SkipPowerActionConfirmation
- ? MessageBoxResult.Yes
- : Context.API.ShowMsgBox(
- Localize.flowlauncher_plugin_sys_dlgtext_logoff_computer(),
- Localize.flowlauncher_plugin_sys_log_off(),
- MessageBoxButton.YesNo, MessageBoxImage.Warning);
+ var result = _settings.SkipPowerActionConfirmation
+ ? MessageBoxResult.Yes
+ : Context.API.ShowMsgBox(
+ Localize.flowlauncher_plugin_sys_dlgtext_logoff_computer(),
+ Localize.flowlauncher_plugin_sys_log_off(),
+ MessageBoxButton.YesNo, MessageBoxImage.Warning);
- if (result == MessageBoxResult.Yes)
- PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, REASON);
- return true;
+ if (result == MessageBoxResult.Yes)
+ PInvoke.ExitWindowsEx(EXIT_WINDOWS_FLAGS.EWX_LOGOFF, REASON);
+ return true;
}
},
new Result
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs
index b02561a01..bda8c6c04 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/SettingsViewModel.cs
@@ -4,6 +4,4 @@
{
public Settings Settings { get; } = settings;
}
-
-
}
From 918eb0f4a9f98dfb41004fbdd1234e381f7d70cb Mon Sep 17 00:00:00 2001
From: Jeremy Wu
Date: Sat, 21 Feb 2026 21:51:21 +1100
Subject: [PATCH 15/24] New Crowdin updates (#4181)
---
Flow.Launcher/Languages/ar.xaml | 2 +
Flow.Launcher/Languages/cs.xaml | 2 +
Flow.Launcher/Languages/da.xaml | 2 +
Flow.Launcher/Languages/de.xaml | 2 +
Flow.Launcher/Languages/es-419.xaml | 2 +
Flow.Launcher/Languages/es.xaml | 2 +
Flow.Launcher/Languages/fr.xaml | 2 +
Flow.Launcher/Languages/he.xaml | 6 +-
Flow.Launcher/Languages/it.xaml | 16 +-
Flow.Launcher/Languages/ja.xaml | 4 +-
Flow.Launcher/Languages/ko.xaml | 2 +
Flow.Launcher/Languages/nb.xaml | 2 +
Flow.Launcher/Languages/nl.xaml | 2 +
Flow.Launcher/Languages/pl.xaml | 2 +
Flow.Launcher/Languages/pt-br.xaml | 2 +
Flow.Launcher/Languages/pt-pt.xaml | 2 +
Flow.Launcher/Languages/ru.xaml | 2 +
Flow.Launcher/Languages/sk.xaml | 2 +
Flow.Launcher/Languages/sr-Cyrl-RS.xaml | 2 +
Flow.Launcher/Languages/sr.xaml | 2 +
Flow.Launcher/Languages/tr.xaml | 4 +-
Flow.Launcher/Languages/uk-UA.xaml | 2 +
Flow.Launcher/Languages/vi.xaml | 2 +
Flow.Launcher/Languages/zh-cn.xaml | 4 +-
Flow.Launcher/Languages/zh-tw.xaml | 258 +++++++++---------
.../Languages/zh-tw.xaml | 4 +-
.../Languages/ar.xaml | 1 +
.../Languages/cs.xaml | 1 +
.../Languages/da.xaml | 1 +
.../Languages/de.xaml | 1 +
.../Languages/es-419.xaml | 1 +
.../Languages/es.xaml | 1 +
.../Languages/fr.xaml | 1 +
.../Languages/he.xaml | 1 +
.../Languages/it.xaml | 1 +
.../Languages/ja.xaml | 1 +
.../Languages/ko.xaml | 1 +
.../Languages/nb.xaml | 1 +
.../Languages/nl.xaml | 1 +
.../Languages/pl.xaml | 1 +
.../Languages/pt-br.xaml | 1 +
.../Languages/pt-pt.xaml | 1 +
.../Languages/ru.xaml | 1 +
.../Languages/sk.xaml | 1 +
.../Languages/sr-Cyrl-RS.xaml | 1 +
.../Languages/sr.xaml | 1 +
.../Languages/tr.xaml | 1 +
.../Languages/uk-UA.xaml | 1 +
.../Languages/vi.xaml | 1 +
.../Languages/zh-cn.xaml | 1 +
.../Languages/zh-tw.xaml | 1 +
.../Languages/es.xaml | 4 +-
.../Languages/tr.xaml | 4 +-
.../Languages/zh-tw.xaml | 50 ++--
.../Languages/zh-tw.xaml | 2 +-
.../Languages/zh-tw.xaml | 28 +-
.../Languages/zh-tw.xaml | 14 +-
.../Languages/zh-tw.xaml | 26 +-
.../Languages/zh-tw.xaml | 4 +-
.../Languages/ar.xaml | 3 +
.../Languages/cs.xaml | 3 +
.../Languages/da.xaml | 3 +
.../Languages/de.xaml | 3 +
.../Languages/es-419.xaml | 3 +
.../Languages/es.xaml | 3 +
.../Languages/fr.xaml | 3 +
.../Languages/he.xaml | 3 +
.../Languages/it.xaml | 3 +
.../Languages/ja.xaml | 3 +
.../Languages/ko.xaml | 3 +
.../Languages/nb.xaml | 3 +
.../Languages/nl.xaml | 3 +
.../Languages/pl.xaml | 3 +
.../Languages/pt-br.xaml | 3 +
.../Languages/pt-pt.xaml | 3 +
.../Languages/ru.xaml | 3 +
.../Languages/sk.xaml | 3 +
.../Languages/sr-Cyrl-RS.xaml | 3 +
.../Languages/sr.xaml | 3 +
.../Languages/tr.xaml | 3 +
.../Languages/uk-UA.xaml | 3 +
.../Languages/vi.xaml | 3 +
.../Languages/zh-cn.xaml | 3 +
.../Languages/zh-tw.xaml | 27 +-
.../Languages/zh-tw.xaml | 8 +-
.../Languages/ar.xaml | 1 +
.../Languages/cs.xaml | 1 +
.../Languages/da.xaml | 1 +
.../Languages/de.xaml | 1 +
.../Languages/es-419.xaml | 1 +
.../Languages/es.xaml | 1 +
.../Languages/fr.xaml | 1 +
.../Languages/he.xaml | 1 +
.../Languages/it.xaml | 1 +
.../Languages/ja.xaml | 1 +
.../Languages/ko.xaml | 1 +
.../Languages/nb.xaml | 1 +
.../Languages/nl.xaml | 1 +
.../Languages/pl.xaml | 1 +
.../Languages/pt-br.xaml | 1 +
.../Languages/pt-pt.xaml | 1 +
.../Languages/ru.xaml | 1 +
.../Languages/sk.xaml | 1 +
.../Languages/sr-Cyrl-RS.xaml | 1 +
.../Languages/sr.xaml | 1 +
.../Languages/tr.xaml | 1 +
.../Languages/uk-UA.xaml | 1 +
.../Languages/vi.xaml | 1 +
.../Languages/zh-cn.xaml | 1 +
.../Languages/zh-tw.xaml | 5 +-
.../Properties/Resources.zh-TW.resx | 2 +-
111 files changed, 402 insertions(+), 227 deletions(-)
diff --git a/Flow.Launcher/Languages/ar.xaml b/Flow.Launcher/Languages/ar.xaml
index 67f1f766e..b1c9ca426 100644
--- a/Flow.Launcher/Languages/ar.xaml
+++ b/Flow.Launcher/Languages/ar.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Schedulerخطأ في إعداد التشغيل عند بدء التشغيلإخفاء Flow Launcher عند فقدان التركيز
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.عدم عرض إشعارات الإصدار الجديدSearch Window Locationتذكر آخر موقع
diff --git a/Flow.Launcher/Languages/cs.xaml b/Flow.Launcher/Languages/cs.xaml
index 96cbe95e7..b55026e28 100644
--- a/Flow.Launcher/Languages/cs.xaml
+++ b/Flow.Launcher/Languages/cs.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerPři nastavování spouštění došlo k chyběSkrýt Flow Launcher při vykliknutí
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Nezobrazovat oznámení o nové verziSearch Window LocationZapamatovat poslední pozici
diff --git a/Flow.Launcher/Languages/da.xaml b/Flow.Launcher/Languages/da.xaml
index a1fc771d2..7d4094c84 100644
--- a/Flow.Launcher/Languages/da.xaml
+++ b/Flow.Launcher/Languages/da.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerError setting launch on startupSkjul Flow Launcher ved mistet fokus
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Vis ikke notifikationer om nye versionerSearch Window LocationRemember Last Position
diff --git a/Flow.Launcher/Languages/de.xaml b/Flow.Launcher/Languages/de.xaml
index 2c083646f..32f8d5d2b 100644
--- a/Flow.Launcher/Languages/de.xaml
+++ b/Flow.Launcher/Languages/de.xaml
@@ -79,6 +79,8 @@
Nach der Deinstallation müssen Sie diese Aufgabe (Flow.Launcher Startup) via Task-Scheduler manuell entfernenFehler bei Einstellungsstart beim StartFlow Launcher ausblenden, wenn Fokus verloren geht
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Versionsbenachrichtigungen nicht zeigenOrt des SuchfenstersLetzte Position merken
diff --git a/Flow.Launcher/Languages/es-419.xaml b/Flow.Launcher/Languages/es-419.xaml
index 9f06c4436..40e8cb978 100644
--- a/Flow.Launcher/Languages/es-419.xaml
+++ b/Flow.Launcher/Languages/es-419.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerError setting launch on startupOcultar Flow Launcher cuando se pierde el enfoque
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.No mostrar notificaciones de nuevas versionesSearch Window LocationRemember Last Position
diff --git a/Flow.Launcher/Languages/es.xaml b/Flow.Launcher/Languages/es.xaml
index f7a3fbb22..049b33858 100644
--- a/Flow.Launcher/Languages/es.xaml
+++ b/Flow.Launcher/Languages/es.xaml
@@ -79,6 +79,8 @@
Después de la desinstalación, es necesario eliminar manualmente la tarea (Flow.Launcher Startup) mediante el Programador de TareasError de configuración de arranque al iniciarOcultar Flow Launcher cuando se pierde el foco
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.No mostrar notificaciones de nuevas versionesUbicación de la ventana de búsquedaRecordar última ubicación
diff --git a/Flow.Launcher/Languages/fr.xaml b/Flow.Launcher/Languages/fr.xaml
index bdce6ddb9..d60d53a1c 100644
--- a/Flow.Launcher/Languages/fr.xaml
+++ b/Flow.Launcher/Languages/fr.xaml
@@ -79,6 +79,8 @@
Après une désinstallation, vous devez supprimer manuellement cette tâche (Flow.Launcher Startup) via le planificateur de tâchesErreur lors de la configuration du lancement au démarrageCacher Flow Launcher lors de la perte de focus
+ Afficher la barre des tâches lorsque Flow Launcher est ouvert
+ Afficher temporairement la barre des tâches lorsque Flow Launcher est ouvert, utile pour les barres de tâches auto-masquées.Ne pas afficher le message de mise à jour pour les nouvelles versionsEmplacement de la fenêtre de rechercheSe souvenir de la dernière position
diff --git a/Flow.Launcher/Languages/he.xaml b/Flow.Launcher/Languages/he.xaml
index 39f02c702..926d94886 100644
--- a/Flow.Launcher/Languages/he.xaml
+++ b/Flow.Launcher/Languages/he.xaml
@@ -8,9 +8,9 @@
אנא בחר את קובץ ההפעלה {0}
- Your selected {0} executable is invalid.
+ קובץ ההפעלה {0} שבחרת אינו חוקי.
{2}{2}
- Click yes if you would like select the {0} executable again. Click no if you would like to download {1}
+ לחץ על כן אם ברצונך, בחר את {0} ההפעלה הקודמת. לחץ על לא אם ברצונך להוריד את {1}
לא ניתן להגדיר נתיב הפעלה {0}, אנא נסה שוב בהגדרות Flow (גלול עד למטה).נכשל בהפעלת תוספים
@@ -79,6 +79,8 @@
לאחר הסרת ההתקנה, עליך להסיר ידנית משימה זו (Flow.Launcher Startup) דרך מתזמן המשימותשגיאה בהגדרת ההפעלה בעת הפעלת windowsהסתר את Flow Launcher כאשר הוא אינו החלון הפעיל
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.אל תציג התראות על גרסה חדשהמיקום חלון חיפושזכור את המיקום האחרון
diff --git a/Flow.Launcher/Languages/it.xaml b/Flow.Launcher/Languages/it.xaml
index ffb716658..92afa5436 100644
--- a/Flow.Launcher/Languages/it.xaml
+++ b/Flow.Launcher/Languages/it.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerErrore nell'impostazione del lancio all'avvioNascondi Flow Launcher quando perde il focus
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Non mostrare le notifiche per una nuova versioneSearch Window LocationRicorda L'Ultima Posizione
@@ -147,8 +149,8 @@
Search DelayAdds a short delay while typing to reduce UI flicker and result load. Recommended if your typing speed is average.Enter the wait time (in ms) until input is considered complete. This can only be edited if Search Delay is enabled.
- Default Search Delay Time
- Wait time before showing results after typing stops. Higher values wait longer. (ms)
+ Tempo predefinito ritardo ricerca
+ Tempo di attesa prima di mostrare i risultati dopo l'interruzione della digitazione. Valori più alti attendono più a lungo. (ms)Information for Korean IME user
The Korean input method used in Windows 11 may cause some issues in Flow Launcher.
@@ -265,11 +267,11 @@
Plugin update{0} di {1} {2}{2}Vuoi aggiornare questo plugin?Download del plugin
- Automatically restart after installing/uninstalling/updating plugins in plugin store
- Zip file does not have a valid plugin.json configuration
+ Riavvia automaticamente dopo l'installazione/disinstallazione/aggiornamento dei plugin nel Plugin Store
+ Il file zip non contiene una configurazione plugin.json validaInstallazione da una fonte sconosciutaThis plugin is from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning in general section of setting window)
- Zip files
+ File zipPlease select zip fileInstall plugin from local pathNessun aggiornamento disponibile
@@ -469,7 +471,7 @@
Cancella i logSei sicuro di voler cancellare tutti i log?Cache Folder
- Clear Caches
+ Cancella cacheAre you sure you want to delete all caches?Failed to clear part of folders and files. Please see log file for more informationWizard
@@ -636,7 +638,7 @@ Se si aggiunge un prefisso '@' mentre si inserisce una scorciatoia, corrisponde
Restart Flow Launcher after updating plugins{0}: Update from v{1} to v{2}
- No plugin selected
+ Nessun plugin selezionatoSalta
diff --git a/Flow.Launcher/Languages/ja.xaml b/Flow.Launcher/Languages/ja.xaml
index 6ebe5271e..39b23f269 100644
--- a/Flow.Launcher/Languages/ja.xaml
+++ b/Flow.Launcher/Languages/ja.xaml
@@ -79,6 +79,8 @@
アンインストール後は、「タスク スケジューラ」からこのタスク(Flow.Launcher Startup)を手動で削除する必要があります。スタートアップ時に起動の設定失敗フォーカスを失った時にFlow Launcherを隠す
+ Flow Launcher を開いたときにタスクバーを表示する
+ Flow Launcher を開いたときに一時的にタスクバーを表示します。タスクバーの自動非表示を設定している場合に便利です。最新版が入手可能であっても、アップグレードメッセージを表示しない検索ウィンドウの位置最後の表示位置を記憶する
@@ -169,7 +171,7 @@
開く前の韓国語IMEを使用You can change the Previous Korean IME settings directly from here
- Failed to change Korean IME setting
+ 韓国語IME設定の変更に失敗しましたシステムのレジストリへのアクセスが可能か確認するか、サポートにお問い合わせください。ホームページ検索文字列が空の場合、ホームページの結果を表示します。
diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml
index 503ff2f11..22f3bb011 100644
--- a/Flow.Launcher/Languages/ko.xaml
+++ b/Flow.Launcher/Languages/ko.xaml
@@ -79,6 +79,8 @@
Flow Launcher를 제거한 후에는 작업 스케줄러에서 이 작업(Flow.Launcher Startup)을 수동으로 삭제해야 합니다Error setting launch on startup포커스 잃으면 Flow Launcher 숨김
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.새 버전 알림 끄기검색 창 위치마지막 위치 기억
diff --git a/Flow.Launcher/Languages/nb.xaml b/Flow.Launcher/Languages/nb.xaml
index 8bd7f94a4..1ef057125 100644
--- a/Flow.Launcher/Languages/nb.xaml
+++ b/Flow.Launcher/Languages/nb.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerFeil ved å sette kjør ved oppstartSkjul Flow Launcher når fokus forsvinner
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Ikke vis varsler om nye versjonerSearch Window LocationHusk siste posisjon
diff --git a/Flow.Launcher/Languages/nl.xaml b/Flow.Launcher/Languages/nl.xaml
index 8b7b86329..412781b55 100644
--- a/Flow.Launcher/Languages/nl.xaml
+++ b/Flow.Launcher/Languages/nl.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerFout bij het instellen van uitvoeren bij opstartenVerberg Flow Launcher als focus verloren is
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Laat geen nieuwe versie notificaties zienSearch Window LocationLaatste Positie Onthouden
diff --git a/Flow.Launcher/Languages/pl.xaml b/Flow.Launcher/Languages/pl.xaml
index 382626eb7..efc2ade55 100644
--- a/Flow.Launcher/Languages/pl.xaml
+++ b/Flow.Launcher/Languages/pl.xaml
@@ -79,6 +79,8 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros
Po odinstalowaniu musisz ręcznie usunąć to zadanie (Flow.Launcher Startup) za pomocą Harmonogramu zadańBłąd uruchamiania ustawień przy starcieUkryj okno Flow Launcher kiedy przestanie ono być aktywne
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Nie pokazuj powiadomienia o nowej wersjiPozycja okna wyszukiwaniaZapamiętaj Ostatnią Pozycję
diff --git a/Flow.Launcher/Languages/pt-br.xaml b/Flow.Launcher/Languages/pt-br.xaml
index 15dcae2f4..a7cf5ac68 100644
--- a/Flow.Launcher/Languages/pt-br.xaml
+++ b/Flow.Launcher/Languages/pt-br.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerErro ao ativar início com o sistemaEsconder Flow Launcher quando foco for perdido
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Não mostrar notificações de novas versõesSearch Window LocationLembrar Última Posição
diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml
index b9bafc3a4..a2b58b1a0 100644
--- a/Flow.Launcher/Languages/pt-pt.xaml
+++ b/Flow.Launcher/Languages/pt-pt.xaml
@@ -79,6 +79,8 @@
Se desinstalar a aplicação, tem que remover manualmente a tarefa (Flow.Launcher Startup) no agendamento de tarefasErro ao definir para iniciar ao arrancarOcultar Flow Launcher ao perder o foco
+ Mostrar barra de tarefas ao abrir Flow Launcher
+ Mostrar, temporariamente, a barra de tarefas ao abrir Flow launcher. Útil para barra de tarefas oculta automaticamente.Não notificar acerca de novas versõesPosição da janela de pesquisaMemorizar última posição
diff --git a/Flow.Launcher/Languages/ru.xaml b/Flow.Launcher/Languages/ru.xaml
index 7bb5a8ff1..544816684 100644
--- a/Flow.Launcher/Languages/ru.xaml
+++ b/Flow.Launcher/Languages/ru.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerОшибка настройки запуска при запускеСкрывать Flow Launcher, если потерян фокуc
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Не отображать сообщение об обновлении, когда доступна новая версияSearch Window LocationЗапомнить последнее положение
diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml
index 881ccf340..c47b47ae1 100644
--- a/Flow.Launcher/Languages/sk.xaml
+++ b/Flow.Launcher/Languages/sk.xaml
@@ -80,6 +80,8 @@ Nevykonali sa žiadne zmeny.Po odinštalovaní musíte úlohu manuálne odstrániť (Flow.Launcher Startup) cez Plánovač úlohChybné nastavenie spustenia pri spusteníSchovať Flow Launcher po strate fokusu
+ Zobraziť panel úloh, keď je Flow Launcher otvorený
+ Dočasne zobraziť panel úloh pri otvorení Flow Launchera, užitočné pri automatickom skrývaní panela úloh.Nezobrazovať upozornenia na novú verziuPoloha vyhľadávacieho oknaZapamätať si poslednú pozíciu
diff --git a/Flow.Launcher/Languages/sr-Cyrl-RS.xaml b/Flow.Launcher/Languages/sr-Cyrl-RS.xaml
index d7d60e6a0..824b48dbf 100644
--- a/Flow.Launcher/Languages/sr-Cyrl-RS.xaml
+++ b/Flow.Launcher/Languages/sr-Cyrl-RS.xaml
@@ -79,6 +79,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/sr.xaml b/Flow.Launcher/Languages/sr.xaml
index 7d1bcb9f3..3ee982819 100644
--- a/Flow.Launcher/Languages/sr.xaml
+++ b/Flow.Launcher/Languages/sr.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerError setting launch on startupSakri Flow Launcher kada se izgubi fokus
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Ne prikazuj obaveštenje o novoj verzijiSearch Window LocationRemember Last Position
diff --git a/Flow.Launcher/Languages/tr.xaml b/Flow.Launcher/Languages/tr.xaml
index 67cdf9da4..023eb2aa6 100644
--- a/Flow.Launcher/Languages/tr.xaml
+++ b/Flow.Launcher/Languages/tr.xaml
@@ -79,6 +79,8 @@
Kaldırma işleminden sonra, bu görevi (Flow.Launcher Startup) Görev Zamanlayıcı üzerinden elle kaldırmanız gerekmektedirSistemle başlatma ayarı başarısız olduOdak Pencereden Ayrıldığında Gizle
+ Flow Launcher açıldığında görev çubuğunu göster
+ Flow Launcher açıldığında geçici olarak görev çubuğunu gösterir, otomatik gizlenen görev çubukları için kullanışlıdır.Güncelleme bildirimlerini göstermePencere KonumuSon Konumu Hatırla
@@ -454,7 +456,7 @@
Kullanılan SimgelerŞu ana kadar Flow Launcher'ı {0} kez aktifleştirdiniz.Güncellemeleri Kontrol Et
- Become a Sponsor
+ Sponsor OlunUygulamanı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 bec1f85e3..0da6c7a47 100644
--- a/Flow.Launcher/Languages/uk-UA.xaml
+++ b/Flow.Launcher/Languages/uk-UA.xaml
@@ -79,6 +79,8 @@
Після видалення, вам необхідно вручну видалити це завдання (Flow.Launcher Startup) через планувальник завданьПомилка запуску налаштування під час запускуСховати Flow Launcher, якщо втрачено фокус
+ Показувати панель завдань, коли Flow Launcher відкрито
+ Тимчасово показувати панель завдань при відкритті Flow Launcher, корисно для автоматично прихованих панелей завдань.Не повідомляти про доступні нові версіїРозташування вікна пошукуПам'ятати останню позицію
diff --git a/Flow.Launcher/Languages/vi.xaml b/Flow.Launcher/Languages/vi.xaml
index 5809c7837..463c11d0b 100644
--- a/Flow.Launcher/Languages/vi.xaml
+++ b/Flow.Launcher/Languages/vi.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerKhông lưu được tính năng tự khởi động khi khởi động hệ thốngẨn Flow Launcher khi mất tiêu điểm
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Không hiển thị thông báo khi có phiên bản mớiSearch Window LocationGhi nhớ vị trí cuối cùng
diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml
index 7af54dc54..089ba2dd1 100644
--- a/Flow.Launcher/Languages/zh-cn.xaml
+++ b/Flow.Launcher/Languages/zh-cn.xaml
@@ -2,7 +2,7 @@
- Flow 检测到您已安装 {0} 个插件,需要 {1} 才能运行。是否要下载 {1}?
+ Flow 检测到您已安装 {0} 插件,需要 {1} 才能运行。是否要下载 {1}?
{2}{2}
如果已安装,请单击“否”,系统将提示您选择包含 {1} 可执行文件的文件夹
@@ -79,6 +79,8 @@
卸载后,您需要通过任务计划程序手动移除此任务 (Flow.Launcher Startup)设置开机自启时出错失去焦点时自动隐藏 Flow Launcher
+ 打开 Flow 时显示任务栏
+ 打开 Flow 时临时显示任务栏,用于自动隐藏任务栏不显示新版本提示搜索窗口位置记住上次的位置
diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml
index ca7da7624..7aacc2190 100644
--- a/Flow.Launcher/Languages/zh-tw.xaml
+++ b/Flow.Launcher/Languages/zh-tw.xaml
@@ -2,43 +2,43 @@
- Flow detected you have installed {0} plugins, which will require {1} to run. Would you like to download {1}?
+ Flow 檢測到你已安裝 {0} 個插件,需要 {1} 才能運行。是否要下載 {1}?
{2}{2}
- Click no if it's already installed, and you will be prompted to select the folder that contains the {1} executable
+ 如果已安裝,請點擊“否”,系統將提示你選擇包含 {1} 個程式的資料夾
- Please select the {0} executable
+ 請選擇 {0} 可執行檔
- Your selected {0} executable is invalid.
+ 您所選擇的 {0} 可執行檔無效。
{2}{2}
- Click yes if you would like select the {0} executable again. Click no if you would like to download {1}
+ 若要重新選取 {0} 可執行檔,請按「是」。若要下載 {1},請按「否」。
- Unable to set {0} executable path, please try from Flow's settings (scroll down to the bottom).
- Fail to Init Plugins
- Plugins: {0} - fail to load and would be disabled, please contact plugin creator for help
+ 無法設定 {0} 可執行檔路徑,請從 Flow 的設定中嘗試(向下捲動至最底部)。
+ 初始化外掛失敗
+ 外掛:{0} — 載入失敗,將被停用,請聯絡外掛開發者以取得協助
- Flow Launcher needs to restart to finish disabling portable mode, after the restart your portable data profile will be deleted and roaming data profile kept
- Flow Launcher needs to restart to finish enabling portable mode, after the restart your roaming data profile will be deleted and portable data profile kept
- Flow Launcher has detected you enabled portable mode, would you like to move it to a different location?
- Flow Launcher has detected you disabled portable mode, the relevant shortcuts and uninstaller entry have been created
- Flow Launcher detected your user data exists both in {0} and {1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.
+ Flow Launcher 需要重新啟動以完成停用可攜式模式,重新啟動後您的可攜式資料設定檔將被刪除,漫遊資料設定檔會保留
+ Flow Launcher 需要重新啟動以完成啟用可攜式模式,重新啟動後您的漫遊資料設定檔將被刪除,而可攜式資料設定檔則會保留
+ Flow Launcher 偵測到您已啟用可攜式模式,是否要將它移到其他位置?
+ Flow Launcher 偵測到您已停用可攜模式,相關的捷徑與解除安裝程式項目已建立
+ Flow Launcher 偵測到您的使用者資料同時存在於 {0} 與 {1}。{2}{2}請刪除 {1} 以繼續。尚未發生任何變更。
- The following plugin has errored and cannot be loaded:
- The following plugins have errored and cannot be loaded:
- Please refer to the logs for more information
+ 下列外掛發生錯誤,無法載入:
+ 下列外掛發生錯誤,無法載入:
+ 請參閱日誌以獲得更多資訊
- Please try again
- Unable to parse Http Proxy
+ 請再試一次
+ 無法解析 Http 代理
- Failed to install TypeScript environment. Please try again later
- Failed to install Python environment. Please try again later.
+ 無法安裝 TypeScript 環境。請稍後再試一次
+ 安裝 Python 環境失敗。請稍後再試。
- Failed to register hotkey "{0}". The hotkey may be in use by another program. Change to a different hotkey, or exit another program.
- Failed to unregister hotkey "{0}". Please try again or see log for details
+ 註冊熱鍵「{0}」失敗。此熱鍵可能已被其他程式使用。請更改為不同的熱鍵,或關閉其他程式。
+ 無法取消註冊熱鍵「{0}」。請再試一次或查看日誌以取得詳細資訊Flow Launcher啟動命令 {0} 失敗無效的 Flow Launcher 外掛格式
@@ -54,7 +54,7 @@
複製剪下貼上
- Undo
+ 還原全選檔案資料夾
@@ -62,12 +62,12 @@
遊戲模式暫停使用快捷鍵。重設位置
- Reset search window position
- Type here to search
- {0}: This plugin is still initializing...
- Select this result to requery
- {0}: Failed to respond!
- Select this result for more info
+ 重設搜尋視窗位置
+ 在此輸入以搜尋
+ 「{0}:此外掛程式仍在初始化……」……
+ 選擇此結果以重新查詢
+ 「{0}:未能回應!」!
+ 選取此結果以取得更多資訊設定
@@ -75,22 +75,24 @@
便攜模式將所有設定和使用者資料存儲在一個資料夾中(當與可移動磁碟或雲服務一起使用時很有用)。開機時啟動
- Use logon task instead of startup entry for faster startup experience
- After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler
- Error setting launch on startup
+ 使用登入工作取代啟動項目,以加快啟動體驗
+ 解除安裝後,您需要透過工作排程程式手動移除此工作(Flow.Launcher Startup)
+ 設定開機啟動時發生錯誤失去焦點時自動隱藏 Flow Launcher
+ 當 Flow Launcher 開啟時顯示工作列
+ 當開啟 Flow Launcher 時暫時顯示工作列,對自動隱藏的工作列很有用。不顯示新版本提示
- Search Window Location
+ 搜尋視窗位置記住最後位置
- Monitor with Mouse Cursor
- Monitor with Focused Window
- Primary Monitor
- Custom Monitor
+ 帶有滑鼠游標的顯示器
+ 以焦點視窗進行監視
+ 主顯示器
+ 自訂搜尋視窗位置搜尋視窗在螢幕上的位置
- Center
- Center Top
- Left Top
- Right Top
+ 置中
+ 頂部置中
+ 左側置中
+ 右側置中自訂搜尋視窗位置語言最後查詢樣式
@@ -98,10 +100,10 @@
保留上一個查詢選擇上一個查詢清空上次搜尋關鍵字
- Preserve Last Action Keyword
- Select Last Action Keyword
+ 保留上次操作的關鍵字
+ 選擇最後操作的關鍵字最大結果顯示個數
- You can also quickly adjust this by using CTRL+Plus and CTRL+Minus.
+ 您也可以使用「CTRL+加號」和「CTRL+減號」快速調整此設定。全螢幕模式下忽略快捷鍵全螢幕模式下停用快捷鍵(推薦用於遊戲時)。預設檔案管理器
@@ -109,28 +111,28 @@
預設瀏覽器設定新增分頁、視窗和無痕模式。Python 位置
- Node.js Path
- Please select the Node.js executable
+ Node.js的路徑
+ 請選擇Node.js的可執行檔請選擇 pythonw.exe一律以英文模式開始輸入啟動 Flow 時暫時將輸入法切換為英文模式。自動更新
- Automatically check and update the app when available
+ 在可用時自動檢查並更新應用程式選擇啟動時不顯示主視窗
- Flow Launcher search window is hidden in the tray after starting up.
+ 啟動後,Flow Launcher搜尋視窗會隱藏在系統匣中。隱藏任務欄圖示當圖示從系統列隱藏時,可以透過在搜尋視窗上按右鍵來開啟設定選單。查詢搜尋精確度更改結果所需的最低匹配分數。
- None
- Low
- Regular
+ 無
+ 低
+ 一般拼音搜尋
- Pinyin is the standard system of romanized spelling for translating Chinese. Please note, enabling this can significantly increase memory usage during search.
- Use Double Pinyin
- Use Double Pinyin instead of Full Pinyin to search.
- Double Pinyin Schema
+ 拼音是中文翻譯的標準羅馬化拼字系統。請注意,啟用此功能可能會顯著增加搜尋時的記憶體使用量。
+ 啟用雙拼模式
+ 請使用雙拼以搜尋,而不是全拼搜尋。
+ 雙拼結構Xiao HeZi Ran MaWei Ruan
@@ -143,12 +145,12 @@
一律預覽當 Flow 啟動時,一律開啟預覽面板。按下 {0} 可切換預覽。
- Shadow effect is not allowed while current theme has blur effect enabled
- Search Delay
- Adds a short delay while typing to reduce UI flicker and result load. Recommended if your typing speed is average.
- Enter the wait time (in ms) until input is considered complete. This can only be edited if Search Delay is enabled.
- Default Search Delay Time
- Wait time before showing results after typing stops. Higher values wait longer. (ms)
+ 當目前主題啟用模糊效果時,將不允許使用陰影效果
+ 延遲搜尋
+ 在輸入時增加短暫延遲,以減少介面閃爍和結果載入時間。建議打字速度中等的使用者使用。
+ 輸入等待時間(以毫秒為單位),直到認為輸入完成為止。僅當啟用“搜尋延遲”時才能編輯此設定。
+ 預設搜尋延遲時間
+ 輸入停止後顯示結果前的等待時間。數值越高,等待時間越長。 (以毫秒為單位)Information for Korean IME user
The Korean input method used in Windows 11 may cause some issues in Flow Launcher.
@@ -164,17 +166,17 @@
- Open Language and Region System Settings
- Opens the Korean IME setting location. Go to Korean > Language Options > Keyboard - Microsoft IME > Compatibility
+ 開啟語言和區域設定
+ 開啟韓語輸入法設定。前往“韓語”>“語言選項”>“鍵盤 - Microsoft 輸入法”>“相容性”。開啟
- Use Previous Korean IME
- You can change the Previous Korean IME settings directly from here
- Failed to change Korean IME setting
- Please check your system registry access or contact support.
- Home Page
- Show home page results when query text is empty.
- Show History Results in Home Page
- Maximum History Results Shown in Home Page
+ 使用舊版韓語輸入法
+ 您可以直接從這裡更改先前的韓語輸入法設定
+ 更改韓語輸入法設定失敗
+ 請檢查您的系統註冊表存取權限或尋求協助。
+ 首頁
+ 當查詢文字為空時,顯示首頁結果。
+ 在首頁顯示歷史記錄
+ 首頁顯示最多歷史搜尋結果History StyleChoose the type of history to show in the History and Home PageQuery history
@@ -209,8 +211,8 @@
Advanced Settings:已啟用優先
- Search Delay
- Home Page
+ 延遲搜尋
+ 首頁目前優先新增優先優先
@@ -263,21 +265,21 @@
Plugin uninstall{0} by {1} {2}{2}Would you like to uninstall this plugin?Plugin update
- {0} by {1} {2}{2}Would you like to update this plugin?
+ 您想更新{0} (由 {1} {2}{2} 製作)嗎?正在下載擴充功能
- Automatically restart after installing/uninstalling/updating plugins in plugin store
- Zip file does not have a valid plugin.json configuration
- Installing from an unknown source
- This plugin is from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning in general section of setting window)
- Zip files
- Please select zip file
- Install plugin from local path
+ 在外掛商店安裝/卸載/更新插件後自動重啟
+ 壓縮檔中沒有有效的plugin.json配置
+ 從未知來源安裝
+ 您正在安裝來自未知來源的插件,它可能有潛在風險!{0}{0} 請確保您了解此插件的來源並確認其安全性。{0}{0} 是否繼續? {0}{0}(您可以在設定中關閉此警告)
+ 壓縮檔
+ 請選擇一個壓縮檔
+ 從本地路徑安裝外掛無可用更新所有插件均為最新版本
- Plugin updates available
- Update plugins
- Check plugin updates
- Plugins are successfully updated. Please restart Flow.
+ 有外掛更新可用
+ 更新外掛程式
+ 檢查外掛更新
+ 插件已成功更新。請重新啟動Flow。主題
@@ -288,21 +290,21 @@
檔案總管搜尋檔案、資料夾和檔案內容網路搜尋
- Search the web with different search engine support
+ 使用不同的搜尋引擎搜尋網絡程式以系統管理員或其他使用者啟用應用程式ProcessKiller
- Terminate unwanted processes
- Search Bar Height
- Item Height
+ 終止不需要的進程
+ 搜尋列高度
+ 項目高度查詢框字體
- Result Title Font
- Result Subtitle Font
- Reset
- Reset to the recommended font and size settings.
- Import Theme Size
- If a size value intended by the theme designer is available, it will be retrieved and applied.
- Customize
+ 結果標題字體
+ 結果副標題字體
+ 重設
+ 恢復預設字體與文字大小設定。
+ 匯入主題大小
+ 如果主題設計者預設的尺寸值存在,則會擷取並套用該尺寸值。
+ 個人化視窗模式透明度找不到主題 {0} ,將回到預設主題
@@ -315,49 +317,49 @@
暗色系音效搜尋窗口打開時播放音效
- Sound Effect Volume
- Adjust the volume of the sound effect
- Windows Media Player is unavailable and is required for Flow's volume adjustment. Please check your installation if you need to adjust volume.
+ 音效音量
+ 調整音效音量
+ Windows Media Player不可用,而Flow的音量調整功能需要它。如果您需要調整音量,請檢查您的安裝情況。動畫使用介面動畫
- Animation Speed
- The speed of the UI animation
- Slow
- Medium
- Fast
- Custom
+ 動畫速度
+ UI動畫速度
+ 慢速
+ 中等
+ 快速
+ 自訂時鐘日期
- Backdrop Type
- The backdrop effect is not applied in the preview.
- Backdrop supported starting from Windows 11 build 22000 and above
- None
- Acrylic
- Mica
- Mica Alt
- This theme supports two (light/dark) modes.
- This theme supports Blur Transparent Background.
- Show placeholder
- Display placeholder when query is empty
- Placeholder text
- Change placeholder text. Input empty will use: {0}
- Fixed Window Size
- The window size is not adjustable by dragging.
- Since Always Preview is on, maximum results shown may not take effect because preview panel requires a certain minimum height
+ 背景類型
+ 預覽中未套用背景效果。
+ 從 Windows 11 版本 22000 及更高版本開始支援背景功能
+ 無
+ 壓克力
+ 雲母
+ 雲母(替代樣式)
+ 此主題支援兩種(淺色/深色)模式。
+ 此主題支援模糊透明背景。
+ 顯示佔位符
+ 當查詢為空時顯示佔位符
+ 佔位符文字
+ 更改佔位符文字。輸入為空將使用{0}
+ 固定視窗大小
+ 視窗大小無法透過拖曳進行調整。
+ 由於「始終預覽」已啟用,因此可能無法顯示最大效果,因為預覽面板需要一定的最小高度快捷鍵快捷鍵
- Open Flow Launcher
+ 開啟Flow Launcher執行縮寫以顯示 / 隱藏 Flow Launcher。
- Toggle Preview
+ 切換預覽Enter shortcut to show/hide preview in search window.Hotkey PresetsList of currently registered hotkeys開放結果修飾符
- Select a modifier key to open selected result via keyboard.
+ 選擇一個修飾鍵以透過鍵盤開啟已選擇的結果。顯示快捷鍵
- Show result selection hotkey with results.
+ 利用結果來顯示選擇的快捷鍵結果。Auto CompleteRuns autocomplete for the selected items.Select Next Item
@@ -541,7 +543,7 @@
Input the search delay time in ms you like to use for the plugin. Input empty if you don't want to specify any, and the plugin will use default search delay time.
- Home Page
+ 首頁Enable the plugin home page state if you like to show the plugin results when query is empty.
@@ -655,12 +657,12 @@ If you add an '@' prefix while inputting a shortcut, it matches any position in
返回 / 快捷選單
- Item Navigation
+ 物件導覽打開選單開啟檔案位置Run as Admin / Open Folder in Default File Manager查詢歷史
- Back to Result in Context Menu
+ 返回右鍵選單中的結果自動完成開啟/運行選擇項目開啟視窗設定
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml
index e8bc6bcb6..5d2dd561a 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml
@@ -6,7 +6,7 @@
搜尋你的瀏覽器書籤
- Failed to set url in clipboard
+ 設定剪貼簿網址失敗書籤資料
@@ -28,6 +28,6 @@
瀏覽器引擎如果你沒有使用 Chrome、Firefox 或 Edge,或者使用它們的便攜版,你需要新增書籤資料位置並選擇正確的瀏覽器引擎,才能讓這個擴充功能正常運作。例如:Brave 瀏覽器的引擎是 Chromium;而它的預設書籤資料位置是「%LOCALAPPDATA%\BraveSoftware\Brave-Browser\UserData」。對於 Firefox 瀏覽器引擎,書籤資料位置是包含 places.sqlite 檔案的 userdata 資料夾。
- Load favicons (can be time consuming during startup)
+ 載入網站圖示(啟動時可能比較耗時)
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml
index 324c91972..8387d0ed4 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ar.xaml
@@ -12,6 +12,7 @@
فاصلة (,)نقطة (.)أقصى عدد من المنازل العشرية
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml
index 844c2dc30..aa60e9331 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/cs.xaml
@@ -12,6 +12,7 @@
Čárka (,)Tečka (.)Desetinná místa
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml
index 405a39e92..8c125e3f0 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/da.xaml
@@ -12,6 +12,7 @@
Comma (,)Dot (.)Max. decimal places
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml
index 4dc634db2..749e1a325 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/de.xaml
@@ -12,6 +12,7 @@
Komma (,)Punkt (.)Max. Dezimalstellen
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml
index 12b4fdb0a..b59072b5f 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es-419.xaml
@@ -12,6 +12,7 @@
Coma (,)Punto (.)Número máximo de decimales
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml
index eeb8923ba..2fc2732e4 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/es.xaml
@@ -12,6 +12,7 @@
Coma (,)Punto (.)Número máximo de decimales
+ Show thousands separator in resultsHa fallado la copia, inténtelo más tardeMostrar mensaje de error cuando falle el cálculo
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml
index 3219e517a..fb952429c 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/fr.xaml
@@ -12,6 +12,7 @@
Virgule (,)Point (.)Décimales max.
+ Afficher le séparateur de milliers dans les résultatsÉchec de la copie, réessayer plus tardAfficher le message d'erreur lorsque le calcul échoue
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml
index 7ee027743..2c30e7c71 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/he.xaml
@@ -12,6 +12,7 @@
פסיק (,)נקודה (.)מספר מקסימלי של מקומות עשרוניים
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml
index a0e61ff32..a8a0a1e2d 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/it.xaml
@@ -12,6 +12,7 @@
Virgola (,)Punto (.)Max. cifre decimali
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml
index 5c251d241..d55355139 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ja.xaml
@@ -12,6 +12,7 @@
コンマ(,)ドット (.)小数点以下の最大桁数
+ Show thousands separator in resultsコピーに失敗しました。後でやり直してください計算に失敗したときにエラーメッセージを表示
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml
index a595f4839..9f95c0105 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ko.xaml
@@ -12,6 +12,7 @@
쉼표 (,)마침표 (.)최대 소수점 아래 자릿 수
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml
index 9b6b1f808..b008b14a6 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nb.xaml
@@ -12,6 +12,7 @@
Komma (,)Prikk (.)Maks. desimaler
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml
index 405a39e92..8c125e3f0 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/nl.xaml
@@ -12,6 +12,7 @@
Comma (,)Dot (.)Max. decimal places
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml
index 03f50ca23..131da0eb5 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pl.xaml
@@ -12,6 +12,7 @@
Przecinek (,)Kropka (.)Maks. liczba miejsc po przecinku
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml
index 9afc3b784..6f3ab9540 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-br.xaml
@@ -12,6 +12,7 @@
Vírgula (,)Ponto (.)Max. decimal places
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml
index 1201e2555..a0c1a6fe9 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/pt-pt.xaml
@@ -12,6 +12,7 @@
Vírgula (,)Ponto (.)Número máximo de casas decimais
+ Mostrar separador dos milhares no resultadoFalha ao copiar. Por favor tente mais tarde.Mostrar mensagem de erro se o cálculo falhar
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml
index 7b40770cd..0097d54f0 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/ru.xaml
@@ -12,6 +12,7 @@
Запятая (,)Точка (.)Макс. число знаков после запятой
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml
index f398ab3e2..1ba75e4bb 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml
@@ -12,6 +12,7 @@
Čiarka (,)Bodka (.)Desatinné miesta
+ Zobraziť vo výsledkoch oddeľovač tisícovKopírovanie zlyhalo, skúste to neskôrZobraziť chybovú správu, keď výpočet zlyhá
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr-Cyrl-RS.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr-Cyrl-RS.xaml
index 405a39e92..8c125e3f0 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr-Cyrl-RS.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr-Cyrl-RS.xaml
@@ -12,6 +12,7 @@
Comma (,)Dot (.)Max. decimal places
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml
index 405a39e92..8c125e3f0 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/sr.xaml
@@ -12,6 +12,7 @@
Comma (,)Dot (.)Max. decimal places
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml
index aec5bec43..16fd93d9f 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/tr.xaml
@@ -12,6 +12,7 @@
Virgül (,)Nokta (.)Maks. ondalık basamak
+ Sonuçlarda binlik ayırıcıyı gösterKopyalama başarısız oldu, lütfen daha sonra deneyinHesaplama başarısız olduğunda hata mesajı göster
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml
index c2af4bbe3..c02fa6d46 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/uk-UA.xaml
@@ -12,6 +12,7 @@
Кома (,)Крапка (.)Макс. кількість знаків після коми
+ Show thousands separator in resultsКопіювання не вдалося, спробуйте пізнішеПоказувати повідомлення про помилку, якщо обчислення не вдалося
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml
index 6efbda3e4..96d6549d6 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/vi.xaml
@@ -12,6 +12,7 @@
Dấu phẩy (,)dấu chấm (.)Tối đa. chữ số thập phân
+ Show thousands separator in resultsCopy failed, please try laterShow error message when calculation fails
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml
index 44a126e61..c0b8372e8 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-cn.xaml
@@ -12,6 +12,7 @@
逗号(,)点(.)小数点后最大位数
+ 在结果中显示千分隔符复制失败,请稍后再试计算错误时显示错误消息
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml
index 0cf66c1cb..19cb2f525 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Languages/zh-tw.xaml
@@ -12,6 +12,7 @@
逗號 (,)點 (.)小數點後最大位數
+ 在結果中顯示千位分隔符複製失敗,請稍後再試計算失敗時顯示錯誤訊息
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml
index 860d64572..e623ac9c5 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml
@@ -56,8 +56,8 @@
Búsqueda de contenido de archivo:Buscar índice:Acceso rápido:
- Folder Search:
- File Search:
+ Buscar carpeta:
+ Buscar archivo:Palabra clave de acción actualAceptarActivado
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml
index 38104d366..f485c9f56 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml
@@ -56,8 +56,8 @@
Dosya İçeriğini Ara:Dizin Araması:Hızlı Erişim:
- Folder Search:
- File Search:
+ Klasör Araması:
+ Dosya Araması:Geçerli Anahtar KelimeTamamEtkin
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml
index 43e428093..11b5bb2fa 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml
@@ -2,7 +2,7 @@
- Please make a selection first
+ 請先選擇一或多個選項Please select a folder path.Please choose a different name or folder path.Are you sure you want to delete this quick access link?
@@ -13,12 +13,12 @@
Are you sure you want to permanently delete this file/folder?成功刪除已成功刪除 {0}
- Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword
- Quick Access can not be set to the global action keyword when enabled. Please choose a specific action keyword
- The required service for Windows Index Search does not appear to be running
- To fix this, start the Windows Search service. Select here to remove this warning
- The warning message has been switched off. As an alternative for searching files and folders, would you like to install Everything plugin?{0}{0}Select 'Yes' to install Everything plugin, or 'No' to return
- Explorer Alternative
+ 設定全局操作關鍵字可能會導致搜尋結果過多。請選擇一個特定的操作關鍵字
+ 啟用「快速存取」後,無法將其設定為全域操作關鍵字。請選擇一個特定的操作關鍵字
+ Windows 索引搜尋所需的服務似乎未運作
+ 若要解決此問題,請啟動 Windows 搜尋服務。選擇此處可移除此警告
+ 警告訊息已關閉。要使用 Everything 外掛程式搜尋檔案和資料夾,您是否願意安裝該外掛程式? {0}{0}選擇「是」安裝 Everything 插件,或選擇「否」返回
+ 瀏覽器替代方案Error occurred during search: {0}Could not open folderCould not open file
@@ -29,7 +29,7 @@
編輯新增General Setting
- Customise Action Keywords
+ 更改觸發關鍵字Customise Quick Access快速訪問連結Everything Setting
@@ -45,7 +45,7 @@
Launch Hidden編輯器路Shell Path
- Index Search Excluded Paths
+ 搜尋索引排除路徑使用程式所在目錄作為工作目錄Display more information like size and age in tooltipsHit Enter to open folder in Default File Manager
@@ -53,15 +53,15 @@
索引選項搜尋:路徑搜尋:
- File Content Search:
- Index Search:
+ 檔案內容搜尋:
+ 索引搜尋:快速存取:Folder Search:File Search:
- Current Action Keyword
+ 目前觸發關鍵字確已啟用
- When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ 停用此選項後,Flow 將不會執行此搜尋選項,並會還原為「*」以釋放操作關鍵字EverythingWindows IndexDirect Enumeration
@@ -107,26 +107,26 @@
檔案資料夾刪除所選內容
- Run as different user
- Run the selected using a different user account
+ 以另一個使用者的身分執行
+ 使用其他帳戶運行所選的程式開啟檔案位置Open the location that contains current item在編輯器中開啟:Failed to open file at {0} with Editor {1} at {2}Open With Shell:Failed to open folder {0} with Shell {1} at {2}
- Exclude current and sub-directories from Index Search
- Excluded from Index Search
- Open Windows Indexing Options
- Manage indexed files and folders
- Failed to open Windows Indexing Options
- Add to Quick Access
+ 從索引搜尋中排除目前目錄及其子目錄
+ 已從索引搜尋中排除
+ 開啟Windows搜尋索引功能的設定
+ 管理索引的檔案和資料夾
+ 無法開啟Windows索引服務的設定
+ 加入快速存取Add current item to Quick Access添加成功
- Successfully added to Quick Access
- Successfully Removed
- Successfully removed from Quick Access
- Add to Quick Access so it can be opened with Explorer's Search Activation action keyword
+ 已成功添加到快速存取
+ 成功移除
+ 成功從快速存取中移除
+ 添加到快速存取,以便可以使用檔案總管的搜尋啟動操作關鍵字打開它從快速訪問中移除從快速訪問中移除Remove current item from Quick Access
diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/zh-tw.xaml
index 0c6477a34..4a03db22f 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Languages/zh-tw.xaml
@@ -1,7 +1,7 @@
- Activate {0} plugin action keyword
+ 啟動 {0} 外掛程式操作關鍵字套件關鍵字提示提供套件關鍵字搜尋提示
diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml
index c13048133..449614e96 100644
--- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/zh-tw.xaml
@@ -5,9 +5,9 @@
正在下載擴充功能下載完成錯誤:無法下載擴充功能
- {0} by {1} {2}{3}Would you like to uninstall this plugin? After the uninstallation Flow will automatically restart.
+ {0}(來自 {1} {2} {3})您想解除安裝此外掛程式嗎?卸載後,Flow 將自動重新啟動。{0} by {1} {2}{2}Would you like to uninstall this plugin?
- {0} by {1} {2}{3}Would you like to install this plugin? After the installation Flow will automatically restart.
+ {0}(來自 {1} {2} {3})您想安裝此外掛程式嗎?安裝後,Flow 將自動重新啟動。{0} by {1} {2}{2}Would you like to install this plugin?安裝擴充功能Installing Plugin
@@ -16,27 +16,27 @@
Keep plugin settingsDo you want to keep the settings of the plugin for the next usage?外掛安裝成功。正在重啟 Flow,請稍後...
- Unable to find the plugin.json metadata file from the extracted zip file.
- Error: A plugin which has the same or greater version with {0} already exists.
+ 無法從解壓縮後的zip檔案中找到plugin.json檔案。
+ 錯誤:已經安裝版本高於 {0} 的外掛程式。安裝擴充功能時發生錯誤嘗試安裝 {0} 時發生錯誤Error uninstalling plugin無可用更新所有插件均為最新版本
- {0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart.
+ {0}(來自 {1} {2} {3})您想更新此外掛程式嗎?更新後,Flow 將自動重新啟動。{0} by {1} {2}{2}Would you like to update this plugin?擴充功能更新已安裝此擴充功能
- Plugin Manifest Download Failed
- Please check if you can connect to github.com. This error means you may not be able to install or update plugins.
+ 外掛程式清單下載失敗
+ 請檢查您是否可以連接到github.com。此錯誤表示您可能無法安裝或更新外掛程式。Update all pluginsWould you like to update 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...
- Installing from an unknown source
- You are installing this plugin from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning via settings)
+ 從未知來源安裝
+ 您正在安裝來自未知來源的插件,它可能有潛在風險!{0}{0}請確保您了解此插件的來源並確認其安全性。{0}{0}是否繼續? {0}{0}(您可以在設定中關閉此警告)Plugin {0} successfully installed. Please restart Flow.Plugin {0} successfully uninstalled. Please restart Flow.
@@ -59,12 +59,12 @@
查看擴充功能的網站查看原始碼查看擴充功能的原始碼
- Suggest an enhancement or submit an issue
- Suggest an enhancement or submit an issue to the plugin developer
- Go to Flow's plugins repository
- Visit the PluginsManifest repository to see community-made plugin submissions
+ 提出改進建議或提交問題
+ 向作者提出改進建議或提交問題
+ 前往 Flow 的線上外掛清單
+ 造訪PluginsManifest儲存庫,查看社群提交的插件
- Install from unknown source warning
+ 安裝未知來源警告以插件管理員安裝/移除/更新插件後自動重新啟動Flow Launcher
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/zh-tw.xaml
index 0a7176d2c..086ffc080 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/zh-tw.xaml
@@ -1,14 +1,14 @@
- Process Killer
- Kill running processes from Flow Launcher
+ 進程結束器
+ 使用Flow Launcher終止正在執行的進程
- kill all instances of "{0}"
- kill {0} processes
- kill all instances
+ 刪除{0}的所有實例
+ 終止 {0} 個進程
+ 終止所有實例
- Show title for processes with visible windows
- Put processes with visible windows on the top
+ 顯示具有可見視窗的進程的標題
+ 將可見的進程置於最上方
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml
index 2653b69da..df2714022 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/zh-tw.xaml
@@ -14,7 +14,7 @@
已啟用Disabled路徑
- All Programs
+ 所有程式File Type重新建立索引正在建立索引
@@ -23,16 +23,16 @@
UWP AppsWhen enabled, Flow will load UWP ApplicationsStart Menu
- When enabled, Flow will load programs from the start menu
+ 啟用後,Flow將從開始功能表載入程式Registry
- When enabled, Flow will load programs from the registry
+ 啟用後,Flow將從註冊表載入程式PATHWhen enabled, Flow will load programs from the PATH environment variable
- Hide app path
- For executable files such as UWP or lnk, hide the file path from being visible
+ 隱藏程式路徑
+ 對於UWP或lnk等可執行文件,隱藏檔案路徑Hide uninstallersHides programs with common uninstaller names, such as unins000.exe
- Search in Program Description
+ 在程式說明中搜尋Flow will search program's descriptionHide duplicated appsHide duplicated Win32 programs that are already in the UWP list
@@ -45,7 +45,7 @@
最大搜尋深度(-1是無限的):請先選擇一項
- Are you sure you want to delete the selected program sources?
+ 您確定要刪除選定的程式來源嗎?Please select program sources that are not added by youPlease select program sources that are added by youAnother program source with the same location already exists.
@@ -73,7 +73,7 @@
Insert protocols of .url files you want to index. Protocols should be separated by ';', and should end with "://". (ex>ftp://;mailto://)
- Run As Different User
+ 以另一個使用者的身分執行以系統管理員身分執行開啟檔案位置Hide
@@ -84,16 +84,16 @@
無效的路徑
- Customized Explorer
- Args
+ 自訂檔案管理器
+ 參數You can customize the explorer used for opening the container folder by inputing the Environmental Variable of the explorer you want to use. It will be useful to use CMD to test whether the Environmental Variable is available.
- Enter the customized args you want to add for your customized explorer. %s for parent directory, %f for full path (which only works for win32). Check the explorer's website for details.
+ 輸入您要為自訂資源管理器新增的自訂參數。 %s 表示父目錄,%f 表示完整路徑(僅適用於 Win32)。請造訪資源管理器的網站以了解詳情。成Error
- Successfully disabled this program from displaying in your query
- This app is not intended to be run as administrator
+ 已經禁止此程式顯示在您的搜尋結果中
+ 此應用程式不應以管理員身分執行Unable to run {0}
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml
index 3fa06dabc..0d2872d2d 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/zh-tw.xaml
@@ -7,14 +7,14 @@
執行後不關閉命令提示字元視窗一律以系統管理員身分執行Use Windows Terminal
- Run as different user
+ 以另一個使用者的身分執行命令提示字元Allows to execute system commands from Flow Launcher此指令已執行了 {0} 次執行指令以系統管理員身分執行複製命令
- 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/ar.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ar.xaml
index b28bd4d9b..10f36502d 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ar.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ar.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
اسم البرنامجوصف
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/cs.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/cs.xaml
index a88f113e3..cf16ff8ed 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/cs.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/cs.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
JménoPopis
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/da.xaml
index 944d5c679..8ac0d48c1 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/da.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/da.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/de.xaml
index 8ef862199..1987257a2 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/de.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameBeschreibung
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es-419.xaml
index 7587fab43..004718b49 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es-419.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es-419.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml
index 55d3f457a..0a97e1c17 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NombreDescripción
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/fr.xaml
index 6b46ca9dd..48c8fc405 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/fr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/fr.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NomDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml
index 6bd87b60c..5e8df297a 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/he.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
שםתיאור
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/it.xaml
index 5212a8ce6..8c16cfab5 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/it.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/it.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NomeDescrizione
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ja.xaml
index a62c09300..0d60abd65 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ja.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ja.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
名前説明
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml
index b0c74748d..9df9868c3 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
Name설명
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/nb.xaml
index 9c5ea839e..bf4fd46ba 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/nb.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/nb.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NavnBeskrivelse
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/nl.xaml
index 9e1c18a30..1f5b9421f 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/nl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/nl.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameBeschrijving
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/pl.xaml
index 5aa8e054c..271647107 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/pl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/pl.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NazwaOpis
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-br.xaml
index 95639b82f..6c5b08249 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-br.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-br.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NomeDescrição
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-pt.xaml
index a3a1411dc..433011195 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-pt.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/pt-pt.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NomeDescrição
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ru.xaml
index cd5cc111b..3d50ac4e0 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ru.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ru.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/sk.xaml
index 0a9ce9bbd..e5aafbf10 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/sk.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/sk.xaml
@@ -1,6 +1,9 @@
+
+ Preskočiť potvrdenie pri vypínaní, reštartovaní alebo odhlasovaní
+
NázovPopis
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr-Cyrl-RS.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr-Cyrl-RS.xaml
index 58bb224cc..4a8a704d7 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr-Cyrl-RS.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr-Cyrl-RS.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr.xaml
index 4ca394f25..5f570b7fe 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/sr.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
NameDescription
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/tr.xaml
index 49fee5a9f..79676e2fb 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/tr.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
AdAçıklama
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml
index 8f19cdcb3..ff65ac8ac 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/uk-UA.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
НазваОпис
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/vi.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/vi.xaml
index ecbcfb66c..58c4ed7e3 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/vi.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/vi.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
TênMô Tả
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-cn.xaml
index 170bbbd39..c485cce4a 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-cn.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-cn.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
名称描述
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml
index bd705490c..de4af6f2d 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/zh-tw.xaml
@@ -1,6 +1,9 @@
+
+ Skip confirmation when Shutting down, Restarting, or Logging off
+
名稱描述
@@ -33,7 +36,7 @@
電腦關機電腦重新啟動
- Restart the computer with Advanced Boot Options for Safe and Debugging modes, as well as other options
+ 使用進階啟動選項重新啟動裝置,進入安全模式、偵錯模式以及其他模式登出鎖定電腦退出Flow Launcher
@@ -43,23 +46,23 @@
清空資源回收桶Open recycle bin索引選項
- Hibernate computer
+ 休眠儲存所有Flow Lanuncher設定
- Refreshes plugin data with new content
- Open Flow Launcher's log location
- Check for new Flow Launcher update
- Visit Flow Launcher's documentation for more help and how to use tips
- Open the location where Flow Launcher's settings are stored
+ 使用新內容更新插件資料
+ 開啟Flow Launcher的日誌位置
+ 檢查Flow Launcher的更新
+ 請檢閱Flow Launcher的說明文件以取得更多協助和使用技巧
+ 開啟Flow Launcher設定檔的路徑Toggle Game ModeQuickly change the Flow Launcher theme成
- All Flow Launcher settings saved
- Reloaded all applicable plugin data
- Are you sure you want to shut the computer down?
- Are you sure you want to restart the computer?
- Are you sure you want to restart the computer with Advanced Boot Options?
+ Flow Launcher的所有設定已儲存
+ 已重新載入所有適用的插件資料
+ 你是否確定要關機?
+ 你是否確定要重啟?
+ 你是否確定要將裝置重啟至進階啟動選項?Are you sure you want to log off?ErrorFailed to empty the recycle bin. This might happen if:{0}- Some items are currently in use{0}- Some items can't be deleted due to permissions{0}Please close any applications that might be using these files and try again.
diff --git a/Plugins/Flow.Launcher.Plugin.Url/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Url/Languages/zh-tw.xaml
index af0a3b175..224d5fe1f 100644
--- a/Plugins/Flow.Launcher.Plugin.Url/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Url/Languages/zh-tw.xaml
@@ -10,13 +10,13 @@
選擇應用程式(*.exe)|*.exe|檔案|*.*
- Use custom instead of Flow's default web browser
- Browser path
+ 使用自訂瀏覽器而非Flow的預設瀏覽器
+ 瀏覽器路徑新增分頁新增視窗
- Private mode
+ 隱私模式
- Prefer https over http
+ 偏好https而非http
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml
index dda561f00..730f688f9 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ar.xaml
@@ -19,6 +19,7 @@
الرابطبحثUse Search Query Autocomplete
+ Max Suggestionsبيانات الإكمال التلقائي من:يرجى اختيار بحث على الويبهل أنت متأكد أنك تريد حذف {0}؟
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml
index 960e63c81..ae5dfd1cc 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/cs.xaml
@@ -19,6 +19,7 @@
URLHledatUse Search Query Autocomplete
+ Max SuggestionsAutomatické doplnění údajů z:Vyberte webové vyhledáváníOpravdu chcete odstranit {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml
index 90f20bcc4..693f8443b 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml
@@ -19,6 +19,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/de.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml
index ed9f35454..7d66efbc4 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml
@@ -19,6 +19,7 @@
URLSucheAutovervollständigung von Suchanfragen verwenden
+ Max SuggestionsAutovervollständigung der Daten aus:Bitte wählen Sie eine Websuche ausSind Sie sicher, dass Sie {0} löschen wollen?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml
index 232ead8d5..3be59e2d1 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml
@@ -19,6 +19,7 @@
URLBuscarUse Search Query Autocomplete
+ Max SuggestionsAutocompletar datos de:Por favor, seleccione una búsqueda¿Seguro que desea eliminar {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml
index 41a6325b3..c2c5e50c2 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml
@@ -19,6 +19,7 @@
URLBusca enUsar autocompletado en consultas de búsqueda
+ Max SuggestionsAutocompletar datos desde:Por favor, seleccione una búsqueda web¿Está seguro de que desea eliminar {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml
index f185a4b50..4318827c8 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml
@@ -19,6 +19,7 @@
URLRechercher surUtiliser la fonction d'auto-complétion des requêtes de recherche
+ Suggestions max.Saisir automatiquement les données à partir de :Veuillez sélectionner une recherche webÊtes-vous sûr de vouloir supprimer {0} ?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml
index e19ba1438..67fa53b5d 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/he.xaml
@@ -19,6 +19,7 @@
כתובת URLחיפוהשתמש בהשלמה אוטומטית לשאילתת חיפוש
+ Max Suggestionsהשלמה אוטומטית מתוך:בחר שירות חיפוש אינטרנטיהאם אתה בטוח שברצונך למחוק את {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml
index f6a44354e..a91a650f7 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml
@@ -19,6 +19,7 @@
URLCercaUse Search Query Autocomplete
+ Max SuggestionsAutocompleta i dati da:Seleziona una ricerca webSei sicuro di voler eliminare {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml
index 51aa07bab..89b465154 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml
@@ -19,6 +19,7 @@
URL検索検索クエリのサジェストを有効にする
+ Max Suggestionsサジェストデータの情報源:web検索を選択してください{0} を削除してもよろしいですか?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml
index df46aee90..b1871f922 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml
@@ -19,6 +19,7 @@
URL검색Use Search Query Autocomplete
+ Max Suggestions자동완성 데이터 출처:웹 검색을 선택하세요Are you sure you want to delete {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml
index d648efcdf..758c2bfea 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml
@@ -19,6 +19,7 @@
NettadresseSøkUse Search Query Autocomplete
+ Max SuggestionsAutofullfør data fra:Vennligst velg et websøkEr du sikker på at du ønsker å slette {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml
index 820004fd7..e4b60d329 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml
@@ -19,6 +19,7 @@
URLSearchUse Search Query Autocomplete
+ Max aantal suggestiesAutocomplete Data from:Please select a web searchAre you sure you want to delete {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml
index 1b562a8c2..77573f984 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml
@@ -19,6 +19,7 @@
Adres URLSzukajUżyj autouzupełniania zapytań wyszukiwania
+ Max SuggestionsAutouzupełnianie danych z:Musisz wybrać coś z listyCzy jesteś pewien że chcesz usunąć {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml
index 6a6704b95..a701a8ec6 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml
@@ -19,6 +19,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/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml
index 21c0ff7cd..808043a2b 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml
@@ -19,6 +19,7 @@
URLPesquisarUtilizar conclusão automática para as consultas
+ Máximo de sugestõesPreencher dados a partir de:Selecione uma pesquisa webTem a certeza de que deseja eliminar {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml
index 4435ba9c9..9a88a2d0c 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml
@@ -19,6 +19,7 @@
URLПоискUse Search Query Autocomplete
+ Max SuggestionsAutocomplete Data from:Please select a web searchВы уверены, что хотите удалить {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml
index 698283c23..a1becbabf 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml
@@ -19,6 +19,7 @@
Adresa URLHľadaťPoužiť automatické dokončovanie výrazov vyhľadávania
+ Maximum návrhovAutomatické dokončovanie údajov z:Vyberte webové vyhľadávanieNaozaj chcete odstrániť {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr-Cyrl-RS.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr-Cyrl-RS.xaml
index 98a65928b..9a8baaa09 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr-Cyrl-RS.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr-Cyrl-RS.xaml
@@ -19,6 +19,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/sr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml
index 205d8edcc..09f971117 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml
@@ -19,6 +19,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/tr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml
index e706b7bf7..6d36fff80 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml
@@ -19,6 +19,7 @@
URLAra:Arama Sorgusu Otomatik Doldurmayı Kullan
+ Maksimum ÖnerilerOtomatik Doldurma Verileri:Lütfen bir web araması seçin{0} bağlantısını silmek istediğinize emin misiniz?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml
index 2163c29be..a9121ee99 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml
@@ -19,6 +19,7 @@
URLПошукВикористовувати автозаповнення пошукового запиту
+ Максимум пропозиційАвтозаповнення даних з:Будь ласка, виберіть пошуковий запит в ІнтернетіВи впевнені, що хочете видалити {0}?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml
index 1da790eee..d86a98b12 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/vi.xaml
@@ -19,6 +19,7 @@
Địa chỉ URLTìm kiếmUse Search Query Autocomplete
+ Max SuggestionsTự động hoàn thành dữ liệu từ:Vui lòng chọn tìm kiếm trên webBạn có chắc chắn muốn xóa {0} không?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml
index 230c587c3..7178358e1 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml
@@ -19,6 +19,7 @@
打开链接搜索使用搜索查询自动补全
+ 最大建议数自动补全数据:请选择一项您确定要删除 {0} 吗?
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml
index 9bb37f2ec..22fcab5bb 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml
@@ -2,7 +2,7 @@
搜尋來源設定
- Open search in:
+ 在以下位置開啟搜尋:新增視窗新索引標籤設定瀏覽器路徑:
@@ -19,6 +19,7 @@
網址搜尋Use Search Query Autocomplete
+ Max Suggestions從以下位置自動填入資料:請選擇一項你確認要刪除{0}嗎
@@ -46,7 +47,7 @@
觸發關鍵字已經存在,請選擇一個新的關鍵字操作成功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.
+ 提示:您無需將自訂圖片放置在此目錄中,如果 Flow 版本更新,這些圖片將會遺失。 Flow 會自動將此目錄以外的所有圖片複製到 WebSearch 的自訂圖片位置。網頁搜尋提供網頁搜尋功能
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.zh-TW.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.zh-TW.resx
index ac04a16bf..52223652f 100644
--- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.zh-TW.resx
+++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.zh-TW.resx
@@ -1639,7 +1639,7 @@
視窗框線
- Windows Anytime Upgrade
+ Windows 隨時升級Area Control Panel (legacy settings)
From 118d6e2a73b6ae5cb87c8c198a7d103b32e29e3b Mon Sep 17 00:00:00 2001
From: Jack Ye
Date: Sat, 21 Feb 2026 19:34:53 +0800
Subject: [PATCH 16/24] Fix incomplete plugin directory deletion on uninstall
(#4250)
---
Flow.Launcher.Core/Plugin/PluginConfig.cs | 14 ++-
Flow.Launcher.Core/Plugin/PluginManager.cs | 12 ++
.../SharedCommands/FilesFolders.cs | 113 ++++++++++++++++++
Flow.Launcher.Test/FilesFoldersTest.cs | 85 +++++++++++++
4 files changed, 223 insertions(+), 1 deletion(-)
diff --git a/Flow.Launcher.Core/Plugin/PluginConfig.cs b/Flow.Launcher.Core/Plugin/PluginConfig.cs
index 4bf12faff..db6813deb 100644
--- a/Flow.Launcher.Core/Plugin/PluginConfig.cs
+++ b/Flow.Launcher.Core/Plugin/PluginConfig.cs
@@ -6,6 +6,7 @@ using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin;
using System.Text.Json;
using Flow.Launcher.Infrastructure.UserSettings;
+using Flow.Launcher.Plugin.SharedCommands;
namespace Flow.Launcher.Core.Plugin
{
@@ -30,7 +31,18 @@ namespace Flow.Launcher.Core.Plugin
{
try
{
- Directory.Delete(directory, true);
+ var fullyDeleted = FilesFolders.TryDeleteDirectoryRobust(directory, maxRetries: 3, retryDelayMs: 200);
+ if (!fullyDeleted)
+ {
+ PublicApi.Instance.LogWarn(ClassName, $"Directory <{directory}> was not fully deleted.");
+
+ // Directory was not fully deleted, recreate the marker file so deletion will be retried on next startup
+ var markerFilePath = Path.Combine(directory, DataLocation.PluginDeleteFile);
+ if (!File.Exists(markerFilePath))
+ {
+ File.WriteAllText(markerFilePath, string.Empty);
+ }
+ }
}
catch (Exception e)
{
diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs
index 54712942c..b808e2a7f 100644
--- a/Flow.Launcher.Core/Plugin/PluginManager.cs
+++ b/Flow.Launcher.Core/Plugin/PluginManager.cs
@@ -931,6 +931,18 @@ namespace Flow.Launcher.Core.Plugin
FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => PublicApi.Instance.ShowMsgBox(s));
+ // Check if marker file exists and delete it
+ try
+ {
+ var markerFilePath = Path.Combine(newPluginPath, DataLocation.PluginDeleteFile);
+ if (File.Exists(markerFilePath))
+ File.Delete(markerFilePath);
+ }
+ catch (Exception e)
+ {
+ PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin marker file in {newPluginPath}", e);
+ }
+
try
{
if (Directory.Exists(tempFolderPluginPath))
diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
index 3af57f00d..cd1ddf983 100644
--- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
+++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
@@ -130,6 +130,119 @@ namespace Flow.Launcher.Plugin.SharedCommands
}
}
+ ///
+ /// Attempts to delete a directory robustly with retry logic for locked files.
+ /// This method tries to delete files individually with retries, then removes empty directories.
+ /// Returns true if the directory was completely deleted, false if some files/folders remain.
+ ///
+ /// The directory path to delete
+ /// Maximum number of retry attempts for locked files (default: 3)
+ /// Delay in milliseconds between retries (default: 100ms)
+ /// True if directory was fully deleted, false if some items remain
+ public static bool TryDeleteDirectoryRobust(string path, int maxRetries = 3, int retryDelayMs = 100)
+ {
+ if (!Directory.Exists(path))
+ return true;
+
+ bool fullyDeleted = true;
+
+ try
+ {
+ // First, try to delete all files in the directory tree
+ var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
+ foreach (var file in files)
+ {
+ bool fileDeleted = false;
+ for (int attempt = 0; attempt <= maxRetries; attempt++)
+ {
+ try
+ {
+ // Remove read-only attribute if present
+ var fileInfo = new FileInfo(file);
+ if (fileInfo.Exists && fileInfo.IsReadOnly)
+ {
+ fileInfo.IsReadOnly = false;
+ }
+
+ File.Delete(file);
+ fileDeleted = true;
+ break;
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // File is in use or access denied, wait and retry
+ if (attempt < maxRetries)
+ {
+ System.Threading.Thread.Sleep(retryDelayMs);
+ }
+ }
+ catch (IOException)
+ {
+ // File is in use, wait and retry
+ if (attempt < maxRetries)
+ {
+ System.Threading.Thread.Sleep(retryDelayMs);
+ }
+ }
+ catch
+ {
+ // Other exceptions, don't retry
+ break;
+ }
+ }
+
+ if (!fileDeleted)
+ {
+ fullyDeleted = false;
+ }
+ }
+
+ // Then, try to delete all empty directories (from deepest to shallowest)
+ var directories = Directory.GetDirectories(path, "*", SearchOption.AllDirectories)
+ .OrderByDescending(d => d.Length) // Delete deeper directories first
+ .ToArray();
+
+ foreach (var directory in directories)
+ {
+ try
+ {
+ if (Directory.Exists(directory) && !Directory.EnumerateFileSystemEntries(directory).Any())
+ {
+ Directory.Delete(directory, false);
+ }
+ }
+ catch
+ {
+ // If we can't delete an empty directory, mark as not fully deleted
+ fullyDeleted = false;
+ }
+ }
+
+ // Finally, try to delete the root directory itself
+ try
+ {
+ if (Directory.Exists(path) && !Directory.EnumerateFileSystemEntries(path).Any())
+ {
+ Directory.Delete(path, false);
+ }
+ else if (Directory.Exists(path))
+ {
+ fullyDeleted = false;
+ }
+ }
+ catch
+ {
+ fullyDeleted = false;
+ }
+ }
+ catch
+ {
+ fullyDeleted = false;
+ }
+
+ return fullyDeleted;
+ }
+
///
/// Checks if a directory exists
///
diff --git a/Flow.Launcher.Test/FilesFoldersTest.cs b/Flow.Launcher.Test/FilesFoldersTest.cs
index 2621fc2da..a63b59c39 100644
--- a/Flow.Launcher.Test/FilesFoldersTest.cs
+++ b/Flow.Launcher.Test/FilesFoldersTest.cs
@@ -1,6 +1,7 @@
using Flow.Launcher.Plugin.SharedCommands;
using NUnit.Framework;
using NUnit.Framework.Legacy;
+using System.IO;
namespace Flow.Launcher.Test
{
@@ -50,5 +51,89 @@ namespace Flow.Launcher.Test
{
ClassicAssert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, allowEqual: expectedResult));
}
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryDoesNotExist_ReturnsTrue()
+ {
+ // Arrange
+ string nonExistentPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(nonExistentPath);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryIsEmpty_DeletesSuccessfully()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryHasFiles_DeletesSuccessfully()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+ File.WriteAllText(Path.Combine(tempDir, "test.txt"), "test content");
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryHasNestedStructure_DeletesSuccessfully()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+ string subDir1 = Path.Combine(tempDir, "SubDir1");
+ string subDir2 = Path.Combine(tempDir, "SubDir2");
+ Directory.CreateDirectory(subDir1);
+ Directory.CreateDirectory(subDir2);
+ File.WriteAllText(Path.Combine(subDir1, "file1.txt"), "content1");
+ File.WriteAllText(Path.Combine(subDir2, "file2.txt"), "content2");
+ File.WriteAllText(Path.Combine(tempDir, "root.txt"), "root content");
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenFileIsReadOnly_RemovesAttributeAndDeletes()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+ string filePath = Path.Combine(tempDir, "readonly.txt");
+ File.WriteAllText(filePath, "readonly content");
+ File.SetAttributes(filePath, FileAttributes.ReadOnly);
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
}
}
From cb604926577c2e572b93a073fdd70273b3d9a035 Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Sun, 22 Feb 2026 12:38:17 +0800
Subject: [PATCH 17/24] Downgrade iNKORE.UI.WPF.Modern to 0.10.1
The package reference for iNKORE.UI.WPF.Modern in Flow.Launcher.Plugin.WebSearch.csproj was changed from version 0.10.2.1 to 0.10.1.
---
.../Flow.Launcher.Plugin.WebSearch.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
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 3b3add106..3c9d849c6 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
@@ -51,7 +51,7 @@
-
+
From c04da3ab8308271cf73c86ca0fbe6b23c1dcf0fe Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Sun, 22 Feb 2026 21:13:38 +0800
Subject: [PATCH 18/24] Add RISC-V 64-bit runtime support to project config
Included linux-musl-riscv64 and linux-riscv64 in both OutputPath and PublishDir of Flow.Launcher.Plugin.BrowserBookmark.csproj to ensure runtime files for RISC-V 64-bit architectures are available during build and publish.
---
.../Flow.Launcher.Plugin.BrowserBookmark.csproj | 4 ++++
1 file changed, 4 insertions(+)
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 9fd6ff5d8..dae14092a 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -51,6 +51,8 @@
$(OutputPath)runtimes\linux-s390x;
$(OutputPath)runtimes\linux-x64;
$(OutputPath)runtimes\linux-x86;
+ $(OutputPath)runtimes\linux-musl-riscv64;
+ $(OutputPath)runtimes\linux-riscv64;
$(OutputPath)runtimes\maccatalyst-arm64;
$(OutputPath)runtimes\maccatalyst-x64;
$(OutputPath)runtimes\osx;
@@ -74,6 +76,8 @@
$(PublishDir)runtimes\linux-s390x;
$(PublishDir)runtimes\linux-x64;
$(PublishDir)runtimes\linux-x86;
+ $(PublishDir)runtimes\linux-musl-riscv64;
+ $(PublishDir)runtimes\linux-riscv64;
$(PublishDir)runtimes\maccatalyst-arm64;
$(PublishDir)runtimes\maccatalyst-x64;
$(PublishDir)runtimes\osx;
From c46a52d1caf7016978c051435e5b635f7a87f11c Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Sun, 22 Feb 2026 21:22:17 +0800
Subject: [PATCH 19/24] Remove SkiaSharp .pdb files after build and publish
Added MSBuild targets to delete unnecessary SkiaSharp .pdb files from output and publish directories after build and publish steps, reducing artifact size.
---
.../Flow.Launcher.Plugin.BrowserBookmark.csproj | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
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 dae14092a..9e57690d8 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -87,6 +87,20 @@
$(PublishDir)runtimes\win-arm64;"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
PreserveNewest
@@ -114,4 +128,4 @@
-
+
\ No newline at end of file
From d511872c0094878918b33b75bd636b779b80bb1a Mon Sep 17 00:00:00 2001
From: Jack Ye
Date: Sun, 22 Feb 2026 21:29:01 +0800
Subject: [PATCH 20/24] Ensure runtimes folder
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
.../Flow.Launcher.Plugin.BrowserBookmark.csproj | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
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 9e57690d8..dc5299fb7 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -90,13 +90,13 @@
-
+
-
+
From 9e66f717746b98d6a97f659159773c4c128e6479 Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Mon, 23 Feb 2026 16:36:08 +0800
Subject: [PATCH 21/24] Revert version bump of SkiaSharp package
---
.../Flow.Launcher.Plugin.BrowserBookmark.csproj | 16 +---------------
1 file changed, 1 insertion(+), 15 deletions(-)
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 dc5299fb7..aff73ea77 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
@@ -87,20 +87,6 @@
$(PublishDir)runtimes\win-arm64;"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
PreserveNewest
@@ -125,7 +111,7 @@
-
+
\ No newline at end of file
From 72269db8e6d7b66a0a4b2c25e89dd3285832691e Mon Sep 17 00:00:00 2001
From: Jack251970 <1160210343@qq.com>
Date: Tue, 24 Feb 2026 00:07:36 +0800
Subject: [PATCH 22/24] Enable TwoWay binding for MaxSuggestions NumberBox
Changed NumberBox binding for Settings.MaxSuggestions from OneWay to TwoWay, allowing user input in the UI to update the underlying setting. This ensures changes made by users are saved back to the settings model.
---
Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
index e4f3485cd..2c0841253 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
@@ -164,7 +164,7 @@
SpinButtonPlacementMode="Compact"
ValidationMode="InvalidInputOverwritten"
ValueChanged="NumberBox_ValueChanged"
- Value="{Binding Settings.MaxSuggestions, Mode=OneWay}" />
+ Value="{Binding Settings.MaxSuggestions, Mode=TwoWay}" />
Date: Tue, 24 Feb 2026 18:17:22 +0800
Subject: [PATCH 23/24] Fix process priority for logon startup task set to
BelowNormal by default (#4283)
---
Flow.Launcher/Helper/AutoStartup.cs | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs
index 34700c610..1f057f839 100644
--- a/Flow.Launcher/Helper/AutoStartup.cs
+++ b/Flow.Launcher/Helper/AutoStartup.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using Flow.Launcher.Infrastructure;
@@ -64,7 +65,9 @@ public class AutoStartup
if (task.Definition.Actions.FirstOrDefault() is Microsoft.Win32.TaskScheduler.Action taskAction)
{
var action = taskAction.ToString().Trim();
- if (!action.Equals(Constant.ExecutablePath, StringComparison.OrdinalIgnoreCase))
+ var needsRecreation = !action.Equals(Constant.ExecutablePath, StringComparison.OrdinalIgnoreCase)
+ || task.Definition.Settings.Priority != ProcessPriorityClass.Normal;
+ if (needsRecreation)
{
UnscheduleLogonTask();
ScheduleLogonTask();
@@ -184,6 +187,7 @@ public class AutoStartup
td.Settings.StopIfGoingOnBatteries = false;
td.Settings.DisallowStartIfOnBatteries = false;
td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
+ td.Settings.Priority = ProcessPriorityClass.Normal;
try
{
From cd9825380d2686d83083b36e40a25699da038dfe Mon Sep 17 00:00:00 2001
From: Jeremy Wu
Date: Tue, 24 Feb 2026 22:52:23 +1100
Subject: [PATCH 24/24] Release 2.1.0 | Plugin 5.2.0 (#4276)
---
.github/workflows/default_plugins.yml | 2 +-
.github/workflows/dotnet.yml | 12 +-
.github/workflows/pr_assignee.yml | 2 +-
.github/workflows/release_pr.yml | 2 +-
Flow.Launcher.Core/Configuration/Portable.cs | 29 +-
.../ExternalPlugins/CommunityPluginSource.cs | 23 +-
.../Environments/AbstractPluginEnvironment.cs | 23 +-
.../Environments/PythonEnvironment.cs | 2 +-
.../Environments/TypeScriptEnvironment.cs | 2 +-
.../Environments/TypeScriptV2Environment.cs | 2 +-
.../ExternalPlugins/PluginsManifest.cs | 11 +-
Flow.Launcher.Core/Flow.Launcher.Core.csproj | 15 +-
.../Plugin/IResultUpdateRegister.cs | 12 +
.../Plugin/JsonRPCPluginSettings.cs | 2 +-
Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs | 4 +-
Flow.Launcher.Core/Plugin/PluginConfig.cs | 33 +-
Flow.Launcher.Core/Plugin/PluginInstaller.cs | 164 +-
Flow.Launcher.Core/Plugin/PluginManager.cs | 593 ++-
Flow.Launcher.Core/Plugin/PluginsLoader.cs | 99 +-
Flow.Launcher.Core/Plugin/QueryBuilder.cs | 17 +-
.../Resource/Internationalization.cs | 37 +-
.../Resource/LocalizedDescriptionAttribute.cs | 30 -
Flow.Launcher.Core/Resource/Theme.cs | 18 +-
Flow.Launcher.Core/Updater.cs | 25 +-
Flow.Launcher.Core/packages.lock.json | 15 +-
.../DialogJump/DialogJump.cs | 86 +-
.../FileExplorerHelper.cs | 75 +-
.../Flow.Launcher.Infrastructure.csproj | 14 +
Flow.Launcher.Infrastructure/Http/Http.cs | 8 +-
.../Image/ThumbnailReader.cs | 84 +-
Flow.Launcher.Infrastructure/Logger/Log.cs | 38 +-
.../NativeMethods.txt | 4 +-
.../PinyinAlphabet.cs | 27 +-
.../TranslationMapping.cs | 2 +-
.../UserSettings/CustomBrowserViewModel.cs | 7 +-
.../UserSettings/CustomExplorerViewModel.cs | 7 +-
.../UserSettings/CustomShortcutModel.cs | 8 +-
.../UserSettings/Settings.cs | 3 +-
Flow.Launcher.Infrastructure/Win32Helper.cs | 27 +
.../packages.lock.json | 12 +
.../Flow.Launcher.Plugin.csproj | 12 +-
Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 14 +-
Flow.Launcher.Plugin/Query.cs | 33 +-
.../SharedCommands/FilesFolders.cs | 113 +
Flow.Launcher.Plugin/packages.lock.json | 38 +-
Flow.Launcher.Test/FilesFoldersTest.cs | 85 +
Flow.Launcher.Test/Plugins/CalculatorTest.cs | 50 +-
Flow.Launcher.Test/QueryBuilderTest.cs | 10 +-
Flow.Launcher.Test/TranslationMappingTest.cs | 34 +-
Flow.Launcher/ActionKeywords.xaml.cs | 4 +-
Flow.Launcher/App.xaml | 18 +-
Flow.Launcher/App.xaml.cs | 61 +-
.../BoolToIMEConversionModeConverter.cs | 4 +-
.../Converters/CornerRadiusFilterConverter.cs | 91 +
.../Converters/PlacementRectangleConverter.cs | 32 +
.../Converters/SharedSizeGroupConverter.cs | 19 +
.../Converters/StringToKeyBindingConverter.cs | 2 +-
.../CustomQueryHotkeySetting.xaml.cs | 2 +-
Flow.Launcher/CustomShortcutSetting.xaml.cs | 4 +-
Flow.Launcher/Flow.Launcher.csproj | 52 +-
Flow.Launcher/Helper/AutoStartup.cs | 6 +-
Flow.Launcher/Helper/BorderHelper.cs | 33 +
Flow.Launcher/Helper/HotKeyMapper.cs | 14 +-
Flow.Launcher/HotkeyControl.xaml.cs | 4 +-
Flow.Launcher/HotkeyControlDialog.xaml | 2 +-
Flow.Launcher/HotkeyControlDialog.xaml.cs | 18 +-
Flow.Launcher/Languages/ar.xaml | 2 +
Flow.Launcher/Languages/cs.xaml | 2 +
Flow.Launcher/Languages/da.xaml | 2 +
Flow.Launcher/Languages/de.xaml | 2 +
Flow.Launcher/Languages/en.xaml | 15 +-
Flow.Launcher/Languages/es-419.xaml | 2 +
Flow.Launcher/Languages/es.xaml | 2 +
Flow.Launcher/Languages/fr.xaml | 2 +
Flow.Launcher/Languages/he.xaml | 6 +-
Flow.Launcher/Languages/it.xaml | 16 +-
Flow.Launcher/Languages/ja.xaml | 14 +-
Flow.Launcher/Languages/ko.xaml | 2 +
Flow.Launcher/Languages/nb.xaml | 2 +
Flow.Launcher/Languages/nl.xaml | 2 +
Flow.Launcher/Languages/pl.xaml | 2 +
Flow.Launcher/Languages/pt-br.xaml | 2 +
Flow.Launcher/Languages/pt-pt.xaml | 12 +-
Flow.Launcher/Languages/ru.xaml | 2 +
Flow.Launcher/Languages/sk.xaml | 4 +-
Flow.Launcher/Languages/sr-Cyrl-RS.xaml | 2 +
Flow.Launcher/Languages/sr.xaml | 2 +
Flow.Launcher/Languages/tr.xaml | 4 +-
Flow.Launcher/Languages/uk-UA.xaml | 2 +
Flow.Launcher/Languages/vi.xaml | 2 +
Flow.Launcher/Languages/zh-cn.xaml | 4 +-
Flow.Launcher/Languages/zh-tw.xaml | 258 +-
Flow.Launcher/MainWindow.xaml | 4 +-
Flow.Launcher/MainWindow.xaml.cs | 39 +-
Flow.Launcher/PluginUpdateWindow.xaml | 5 +-
Flow.Launcher/PluginUpdateWindow.xaml.cs | 9 +-
Flow.Launcher/PublicAPIInstance.cs | 40 +-
Flow.Launcher/ReleaseNotesWindow.xaml | 24 +-
Flow.Launcher/ReleaseNotesWindow.xaml.cs | 17 +-
Flow.Launcher/ReportWindow.xaml.cs | 6 +-
Flow.Launcher/Resources/Controls/Card.xaml | 139 -
Flow.Launcher/Resources/Controls/Card.xaml.cs | 67 -
.../Resources/Controls/CardGroup.xaml | 32 -
.../Resources/Controls/CardGroup.xaml.cs | 47 -
.../Controls/CardGroupCardStyleSelector.cs | 21 -
.../Controls/CustomScrollViewerEx.cs | 253 ++
Flow.Launcher/Resources/Controls/ExCard.xaml | 312 --
.../Resources/Controls/ExCard.xaml.cs | 57 -
.../Resources/Controls/HyperLink.xaml | 14 -
.../Resources/Controls/HyperLink.xaml.cs | 39 -
Flow.Launcher/Resources/Controls/InfoBar.xaml | 81 -
.../Resources/Controls/InfoBar.xaml.cs | 222 -
.../Controls/InstalledPluginDisplay.xaml | 4 +-
.../Controls/InstalledPluginDisplay.xaml.cs | 2 +-
.../Resources/CustomControlTemplate.xaml | 3811 +++--------------
Flow.Launcher/Resources/Dark.xaml | 1549 +------
Flow.Launcher/Resources/Light.xaml | 1552 +------
.../Resources/Pages/WelcomePage1.xaml | 11 +-
.../Resources/Pages/WelcomePage2.xaml | 17 +-
.../Resources/Pages/WelcomePage3.xaml | 153 +-
.../Resources/Pages/WelcomePage4.xaml | 9 +-
.../Resources/Pages/WelcomePage5.xaml | 13 +-
.../Resources/Pages/WelcomePage5.xaml.cs | 2 +-
.../Resources/SettingWindowStyle.xaml | 435 +-
Flow.Launcher/ResultListBox.xaml | 1 +
Flow.Launcher/ResultListBox.xaml.cs | 47 +-
Flow.Launcher/SelectBrowserWindow.xaml | 2 +-
Flow.Launcher/SelectFileManagerWindow.xaml | 6 +-
Flow.Launcher/SelectFileManagerWindow.xaml.cs | 6 -
.../ViewModels/SettingsPaneAboutViewModel.cs | 27 +-
.../SettingsPaneGeneralViewModel.cs | 15 +-
.../ViewModels/SettingsPaneHotkeyViewModel.cs | 24 +-
.../SettingsPanePluginStoreViewModel.cs | 6 +-
.../SettingsPanePluginsViewModel.cs | 9 +-
.../ViewModels/SettingsPaneThemeViewModel.cs | 33 +-
.../SettingPages/Views/SettingsPaneAbout.xaml | 180 +-
.../Views/SettingsPaneAbout.xaml.cs | 6 -
.../Views/SettingsPaneGeneral.xaml | 733 ++--
.../Views/SettingsPaneHotkey.xaml | 736 ++--
.../Views/SettingsPanePluginStore.xaml | 102 +-
.../Views/SettingsPanePlugins.xaml | 55 +-
.../SettingPages/Views/SettingsPaneProxy.xaml | 77 +-
.../SettingPages/Views/SettingsPaneTheme.xaml | 666 +--
Flow.Launcher/SettingWindow.xaml | 5 +-
Flow.Launcher/SettingWindow.xaml.cs | 9 +-
Flow.Launcher/Storage/QueryHistory.cs | 2 +-
Flow.Launcher/Storage/TopMostRecord.cs | 22 +-
Flow.Launcher/Themes/Base.xaml | 23 +-
Flow.Launcher/Themes/BlurWhite.xaml | 2 +-
Flow.Launcher/Themes/Circle System.xaml | 2 +-
Flow.Launcher/Themes/Cyan Dark.xaml | 12 +-
Flow.Launcher/Themes/Dracula.xaml | 6 +-
Flow.Launcher/Themes/Gray.xaml | 8 +-
Flow.Launcher/Themes/Sublime.xaml | 6 +-
Flow.Launcher/Themes/Win10System.xaml | 2 +-
Flow.Launcher/Themes/Win11Light.xaml | 2 +-
Flow.Launcher/ViewModel/MainViewModel.cs | 331 +-
Flow.Launcher/ViewModel/PluginViewModel.cs | 70 +-
Flow.Launcher/ViewModel/ResultViewModel.cs | 2 +
.../ViewModel/SelectBrowserViewModel.cs | 2 +-
.../ViewModel/SelectFileManagerViewModel.cs | 7 +-
Flow.Launcher/WelcomeWindow.xaml | 7 +-
Flow.Launcher/WelcomeWindow.xaml.cs | 2 +-
Flow.Launcher/packages.lock.json | 36 +-
...low.Launcher.Plugin.BrowserBookmark.csproj | 6 +-
.../Languages/zh-tw.xaml | 4 +-
.../Flow.Launcher.Plugin.Calculator.csproj | 4 +-
.../Languages/ar.xaml | 1 +
.../Languages/cs.xaml | 1 +
.../Languages/da.xaml | 1 +
.../Languages/de.xaml | 1 +
.../Languages/en.xaml | 1 +
.../Languages/es-419.xaml | 1 +
.../Languages/es.xaml | 1 +
.../Languages/fr.xaml | 1 +
.../Languages/he.xaml | 1 +
.../Languages/it.xaml | 1 +
.../Languages/ja.xaml | 1 +
.../Languages/ko.xaml | 1 +
.../Languages/nb.xaml | 1 +
.../Languages/nl.xaml | 1 +
.../Languages/pl.xaml | 1 +
.../Languages/pt-br.xaml | 1 +
.../Languages/pt-pt.xaml | 1 +
.../Languages/ru.xaml | 1 +
.../Languages/sk.xaml | 1 +
.../Languages/sr-Cyrl-RS.xaml | 1 +
.../Languages/sr.xaml | 1 +
.../Languages/tr.xaml | 1 +
.../Languages/uk-UA.xaml | 1 +
.../Languages/vi.xaml | 1 +
.../Languages/zh-cn.xaml | 1 +
.../Languages/zh-tw.xaml | 1 +
.../Flow.Launcher.Plugin.Calculator/Main.cs | 2 +-
.../Settings.cs | 2 +
.../Views/CalculatorSettings.xaml | 11 +
.../Languages/ar.xaml | 2 +
.../Languages/cs.xaml | 2 +
.../Languages/da.xaml | 2 +
.../Languages/de.xaml | 2 +
.../Languages/en.xaml | 2 +
.../Languages/es-419.xaml | 2 +
.../Languages/es.xaml | 2 +
.../Languages/fr.xaml | 2 +
.../Languages/he.xaml | 2 +
.../Languages/it.xaml | 2 +
.../Languages/ja.xaml | 2 +
.../Languages/ko.xaml | 2 +
.../Languages/nb.xaml | 2 +
.../Languages/nl.xaml | 2 +
.../Languages/pl.xaml | 2 +
.../Languages/pt-br.xaml | 2 +
.../Languages/pt-pt.xaml | 2 +
.../Languages/ru.xaml | 2 +
.../Languages/sk.xaml | 2 +
.../Languages/sr-Cyrl-RS.xaml | 2 +
.../Languages/sr.xaml | 2 +
.../Languages/tr.xaml | 2 +
.../Languages/uk-UA.xaml | 2 +
.../Languages/vi.xaml | 2 +
.../Languages/zh-cn.xaml | 2 +
.../Languages/zh-tw.xaml | 52 +-
.../Search/SearchManager.cs | 221 +-
.../Flow.Launcher.Plugin.Explorer/Settings.cs | 50 +-
.../ViewModels/SettingsViewModel.cs | 8 +-
.../Views/ExplorerSettings.xaml | 15 +-
.../Languages/zh-tw.xaml | 2 +-
.../Languages/zh-tw.xaml | 28 +-
.../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +-
.../Languages/zh-tw.xaml | 14 +-
.../Languages/zh-tw.xaml | 26 +-
Plugins/Flow.Launcher.Plugin.Program/Main.cs | 110 +-
.../NativeMethods.txt | 5 +-
.../ProgramSuffixes.xaml | 2 +-
.../Programs/ShellLocalization.cs | 57 +-
.../Programs/UWPPackage.cs | 4 +-
.../Programs/Win32.cs | 2 +-
.../Languages/zh-tw.xaml | 4 +-
.../Flow.Launcher.Plugin.Sys.csproj | 2 +-
.../Languages/ar.xaml | 3 +
.../Languages/cs.xaml | 3 +
.../Languages/da.xaml | 3 +
.../Languages/de.xaml | 3 +
.../Languages/en.xaml | 3 +
.../Languages/es-419.xaml | 3 +
.../Languages/es.xaml | 3 +
.../Languages/fr.xaml | 3 +
.../Languages/he.xaml | 3 +
.../Languages/it.xaml | 3 +
.../Languages/ja.xaml | 3 +
.../Languages/ko.xaml | 3 +
.../Languages/nb.xaml | 3 +
.../Languages/nl.xaml | 3 +
.../Languages/pl.xaml | 3 +
.../Languages/pt-br.xaml | 3 +
.../Languages/pt-pt.xaml | 3 +
.../Languages/ru.xaml | 3 +
.../Languages/sk.xaml | 3 +
.../Languages/sr-Cyrl-RS.xaml | 3 +
.../Languages/sr.xaml | 3 +
.../Languages/tr.xaml | 3 +
.../Languages/uk-UA.xaml | 3 +
.../Languages/vi.xaml | 3 +
.../Languages/zh-cn.xaml | 3 +
.../Languages/zh-tw.xaml | 27 +-
Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 52 +-
Plugins/Flow.Launcher.Plugin.Sys/Settings.cs | 14 +
.../Flow.Launcher.Plugin.Sys/SysSettings.xaml | 13 +-
.../Converters/BoolToVisibilityConverter.cs | 23 +
.../Converters/InverseBoolConverter.cs | 25 +
.../Languages/en.xaml | 22 +-
.../Languages/zh-tw.xaml | 8 +-
Plugins/Flow.Launcher.Plugin.Url/Main.cs | 63 +-
Plugins/Flow.Launcher.Plugin.Url/Settings.cs | 50 +-
.../SettingsControl.xaml | 126 +
.../SettingsControl.xaml.cs | 27 +
.../Flow.Launcher.Plugin.WebSearch.csproj | 4 +
.../Languages/ar.xaml | 1 +
.../Languages/cs.xaml | 1 +
.../Languages/da.xaml | 1 +
.../Languages/de.xaml | 1 +
.../Languages/en.xaml | 1 +
.../Languages/es-419.xaml | 1 +
.../Languages/es.xaml | 1 +
.../Languages/fr.xaml | 1 +
.../Languages/he.xaml | 1 +
.../Languages/it.xaml | 1 +
.../Languages/ja.xaml | 1 +
.../Languages/ko.xaml | 1 +
.../Languages/nb.xaml | 1 +
.../Languages/nl.xaml | 1 +
.../Languages/pl.xaml | 1 +
.../Languages/pt-br.xaml | 1 +
.../Languages/pt-pt.xaml | 1 +
.../Languages/ru.xaml | 1 +
.../Languages/sk.xaml | 1 +
.../Languages/sr-Cyrl-RS.xaml | 1 +
.../Languages/sr.xaml | 1 +
.../Languages/tr.xaml | 1 +
.../Languages/uk-UA.xaml | 1 +
.../Languages/vi.xaml | 1 +
.../Languages/zh-cn.xaml | 1 +
.../Languages/zh-tw.xaml | 5 +-
.../Flow.Launcher.Plugin.WebSearch/Main.cs | 5 +-
.../Settings.cs | 17 +
.../SettingsControl.xaml | 96 +-
.../SettingsControl.xaml.cs | 114 +-
.../Properties/Resources.zh-TW.resx | 2 +-
README.md | 41 +-
appveyor.yml | 2 +-
310 files changed, 5920 insertions(+), 10598 deletions(-)
create mode 100644 Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs
delete mode 100644 Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs
create mode 100644 Flow.Launcher/Converters/CornerRadiusFilterConverter.cs
create mode 100644 Flow.Launcher/Converters/PlacementRectangleConverter.cs
create mode 100644 Flow.Launcher/Converters/SharedSizeGroupConverter.cs
create mode 100644 Flow.Launcher/Helper/BorderHelper.cs
delete mode 100644 Flow.Launcher/Resources/Controls/Card.xaml
delete mode 100644 Flow.Launcher/Resources/Controls/Card.xaml.cs
delete mode 100644 Flow.Launcher/Resources/Controls/CardGroup.xaml
delete mode 100644 Flow.Launcher/Resources/Controls/CardGroup.xaml.cs
delete mode 100644 Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs
create mode 100644 Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs
delete mode 100644 Flow.Launcher/Resources/Controls/ExCard.xaml
delete mode 100644 Flow.Launcher/Resources/Controls/ExCard.xaml.cs
delete mode 100644 Flow.Launcher/Resources/Controls/HyperLink.xaml
delete mode 100644 Flow.Launcher/Resources/Controls/HyperLink.xaml.cs
delete mode 100644 Flow.Launcher/Resources/Controls/InfoBar.xaml
delete mode 100644 Flow.Launcher/Resources/Controls/InfoBar.xaml.cs
create mode 100644 Plugins/Flow.Launcher.Plugin.Url/Converters/BoolToVisibilityConverter.cs
create mode 100644 Plugins/Flow.Launcher.Plugin.Url/Converters/InverseBoolConverter.cs
create mode 100644 Plugins/Flow.Launcher.Plugin.Url/SettingsControl.xaml
create mode 100644 Plugins/Flow.Launcher.Plugin.Url/SettingsControl.xaml.cs
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/Configuration/Portable.cs b/Flow.Launcher.Core/Configuration/Portable.cs
index bc6f073c3..9c23db537 100644
--- a/Flow.Launcher.Core/Configuration/Portable.cs
+++ b/Flow.Launcher.Core/Configuration/Portable.cs
@@ -3,10 +3,8 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
-using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
using Microsoft.Win32;
using Squirrel;
@@ -17,8 +15,6 @@ namespace Flow.Launcher.Core.Configuration
{
private static readonly string ClassName = nameof(Portable);
- private readonly IPublicAPI API = Ioc.Default.GetRequiredService();
-
///
/// As at Squirrel.Windows version 1.5.2, UpdateManager needs to be disposed after finish
///
@@ -45,13 +41,13 @@ namespace Flow.Launcher.Core.Configuration
#endif
IndicateDeletion(DataLocation.PortableDataPath);
- API.ShowMsgBox(API.GetTranslation("restartToDisablePortableMode"));
+ PublicApi.Instance.ShowMsgBox(Localize.restartToDisablePortableMode());
UpdateManager.RestartApp(Constant.ApplicationFileName);
}
catch (Exception e)
{
- API.LogException(ClassName, "Error occurred while disabling portable mode", e);
+ PublicApi.Instance.LogException(ClassName, "Error occurred while disabling portable mode", e);
}
}
@@ -68,13 +64,13 @@ namespace Flow.Launcher.Core.Configuration
#endif
IndicateDeletion(DataLocation.RoamingDataPath);
- API.ShowMsgBox(API.GetTranslation("restartToEnablePortableMode"));
+ PublicApi.Instance.ShowMsgBox(Localize.restartToEnablePortableMode());
UpdateManager.RestartApp(Constant.ApplicationFileName);
}
catch (Exception e)
{
- API.LogException(ClassName, "Error occurred while enabling portable mode", e);
+ PublicApi.Instance.LogException(ClassName, "Error occurred while enabling portable mode", e);
}
}
@@ -94,13 +90,13 @@ namespace Flow.Launcher.Core.Configuration
public void MoveUserDataFolder(string fromLocation, string toLocation)
{
- FilesFolders.CopyAll(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
+ FilesFolders.CopyAll(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
VerifyUserDataAfterMove(fromLocation, toLocation);
}
public void VerifyUserDataAfterMove(string fromLocation, string toLocation)
{
- FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => API.ShowMsgBox(s));
+ FilesFolders.VerifyBothFolderFilesEqual(fromLocation, toLocation, (s) => PublicApi.Instance.ShowMsgBox(s));
}
public void CreateShortcuts()
@@ -150,12 +146,12 @@ namespace Flow.Launcher.Core.Configuration
// delete it and prompt the user to pick the portable data location
if (File.Exists(roamingDataDeleteFilePath))
{
- FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => API.ShowMsgBox(s));
+ FilesFolders.RemoveFolderIfExists(roamingDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));
- if (API.ShowMsgBox(API.GetTranslation("moveToDifferentLocation"),
+ if (PublicApi.Instance.ShowMsgBox(Localize.moveToDifferentLocation(),
string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
- FilesFolders.OpenPath(Constant.RootDirectory, (s) => API.ShowMsgBox(s));
+ FilesFolders.OpenPath(Constant.RootDirectory, (s) => PublicApi.Instance.ShowMsgBox(s));
Environment.Exit(0);
}
@@ -164,9 +160,9 @@ namespace Flow.Launcher.Core.Configuration
// delete it and notify the user about it.
else if (File.Exists(portableDataDeleteFilePath))
{
- FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => API.ShowMsgBox(s));
+ FilesFolders.RemoveFolderIfExists(portableDataDir, (s) => PublicApi.Instance.ShowMsgBox(s));
- API.ShowMsgBox(API.GetTranslation("shortcutsUninstallerCreated"));
+ PublicApi.Instance.ShowMsgBox(Localize.shortcutsUninstallerCreated());
}
}
@@ -177,8 +173,7 @@ namespace Flow.Launcher.Core.Configuration
if (roamingLocationExists && portableLocationExists)
{
- API.ShowMsgBox(string.Format(API.GetTranslation("userDataDuplicated"),
- DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
+ PublicApi.Instance.ShowMsgBox(Localize.userDataDuplicated(DataLocation.PortableDataPath, DataLocation.RoamingDataPath, Environment.NewLine));
return false;
}
diff --git a/Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs b/Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs
index 841099dd1..7c0290b2a 100644
--- a/Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/CommunityPluginSource.cs
@@ -8,7 +8,6 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure.Http;
using Flow.Launcher.Plugin;
@@ -18,13 +17,9 @@ namespace Flow.Launcher.Core.ExternalPlugins
{
private static readonly string ClassName = nameof(CommunityPluginSource);
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
private string latestEtag = "";
- private List plugins = new();
+ private List plugins = [];
private static readonly JsonSerializerOptions PluginStoreItemSerializationOption = new()
{
@@ -41,7 +36,7 @@ namespace Flow.Launcher.Core.ExternalPlugins
///
public async Task> FetchAsync(CancellationToken token)
{
- API.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
+ PublicApi.Instance.LogInfo(ClassName, $"Loading plugins from {ManifestFileUrl}");
var request = new HttpRequestMessage(HttpMethod.Get, ManifestFileUrl);
@@ -59,40 +54,40 @@ namespace Flow.Launcher.Core.ExternalPlugins
.ConfigureAwait(false);
latestEtag = response.Headers.ETag?.Tag;
- API.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
+ PublicApi.Instance.LogInfo(ClassName, $"Loaded {plugins.Count} plugins from {ManifestFileUrl}");
return plugins;
}
else if (response.StatusCode == HttpStatusCode.NotModified)
{
- API.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
+ PublicApi.Instance.LogInfo(ClassName, $"Resource {ManifestFileUrl} has not been modified.");
return plugins;
}
else
{
- API.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
+ PublicApi.Instance.LogWarn(ClassName, $"Failed to load resource {ManifestFileUrl} with response {response.StatusCode}");
return null;
}
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
- API.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
+ PublicApi.Instance.LogDebug(ClassName, $"Fetching from {ManifestFileUrl} was cancelled by caller.");
return null;
}
catch (TaskCanceledException)
{
// Likely an HttpClient timeout or external cancellation not requested by our token
- API.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
+ PublicApi.Instance.LogWarn(ClassName, $"Fetching from {ManifestFileUrl} timed out.");
return null;
}
catch (Exception e)
{
if (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException)
{
- API.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
+ PublicApi.Instance.LogException(ClassName, $"Check your connection and proxy settings to {ManifestFileUrl}.", e);
}
else
{
- API.LogException(ClassName, "Error Occurred", e);
+ PublicApi.Instance.LogException(ClassName, "Error Occurred", e);
}
return null;
}
diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs
index 14796a87a..1a324a993 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs
@@ -4,7 +4,6 @@ using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
@@ -15,7 +14,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
{
private static readonly string ClassName = nameof(AbstractPluginEnvironment);
- protected readonly IPublicAPI API = Ioc.Default.GetRequiredService();
+ protected readonly IPublicAPI API = PublicApi.Instance;
internal abstract string Language { get; }
@@ -58,15 +57,10 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
}
- var noRuntimeMessage = string.Format(
- API.GetTranslation("runtimePluginInstalledChooseRuntimePrompt"),
- Language,
- EnvName,
- Environment.NewLine
- );
+ var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
if (API.ShowMsgBox(noRuntimeMessage, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
{
- var msg = string.Format(API.GetTranslation("runtimePluginChooseRuntimeExecutable"), EnvName);
+ var msg = Localize.runtimePluginChooseRuntimeExecutable(EnvName);
var selectedFile = GetFileFromDialog(msg, FileDialogFilter);
@@ -77,12 +71,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
// Nothing selected because user pressed cancel from the file dialog window
else
{
- var forceDownloadMessage = string.Format(
- API.GetTranslation("runtimeExecutableInvalidChooseDownload"),
- Language,
- EnvName,
- Environment.NewLine
- );
+ var forceDownloadMessage = Localize.runtimeExecutableInvalidChooseDownload(Language, EnvName, Environment.NewLine);
// Let users select valid path or choose to download
while (string.IsNullOrEmpty(selectedFile))
@@ -120,7 +109,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
}
else
{
- API.ShowMsgBox(string.Format(API.GetTranslation("runtimePluginUnableToSetExecutablePath"), Language));
+ API.ShowMsgBox(Localize.runtimePluginUnableToSetExecutablePath(Language));
API.LogError(ClassName,
$"Not able to successfully set {EnvName} path, setting's plugin executable path variable is still an empty string.",
$"{Language}Environment");
@@ -248,7 +237,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
private static string GetUpdatedEnvironmentPath(string filePath)
{
var index = filePath.IndexOf(DataLocation.PluginEnvironments);
-
+
// get the substring after "Environments" because we can not determine it dynamically
var executablePathSubstring = filePath[(index + DataLocation.PluginEnvironments.Length)..];
return $"{DataLocation.PluginEnvironmentsPath}{executablePathSubstring}";
diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs
index 89286dfb0..76c775fb4 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/PythonEnvironment.cs
@@ -51,7 +51,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
}
catch (System.Exception e)
{
- API.ShowMsgError(API.GetTranslation("failToInstallPythonEnv"));
+ API.ShowMsgError(Localize.failToInstallPythonEnv());
API.LogException(ClassName, "Failed to install Python environment", e);
}
});
diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs
index 724ae20f4..d8244cbf3 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptEnvironment.cs
@@ -46,7 +46,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
}
catch (System.Exception e)
{
- API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
+ API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
API.LogException(ClassName, "Failed to install TypeScript environment", e);
}
});
diff --git a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs
index 6a32664a1..e2de53e39 100644
--- a/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/Environments/TypeScriptV2Environment.cs
@@ -46,7 +46,7 @@ namespace Flow.Launcher.Core.ExternalPlugins.Environments
}
catch (System.Exception e)
{
- API.ShowMsgError(API.GetTranslation("failToInstallTypeScriptEnv"));
+ API.ShowMsgError(Localize.failToInstallTypeScriptEnv());
API.LogException(ClassName, "Failed to install TypeScript environment", e);
}
});
diff --git a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
index 7d3d78ef0..4fed10d25 100644
--- a/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
+++ b/Flow.Launcher.Core/ExternalPlugins/PluginsManifest.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Plugin;
using Flow.Launcher.Infrastructure;
@@ -23,10 +22,6 @@ namespace Flow.Launcher.Core.ExternalPlugins
private static DateTime lastFetchedAt = DateTime.MinValue;
private static readonly TimeSpan fetchTimeout = TimeSpan.FromMinutes(2);
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
public static List UserPlugins { get; private set; }
public static async Task UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
@@ -67,7 +62,7 @@ namespace Flow.Launcher.Core.ExternalPlugins
}
catch (Exception e)
{
- API.LogException(ClassName, "Http request failed", e);
+ PublicApi.Instance.LogException(ClassName, "Http request failed", e);
}
finally
{
@@ -90,12 +85,12 @@ namespace Flow.Launcher.Core.ExternalPlugins
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
+ PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
+ "Plugin excluded from manifest", e);
return false;
}
- API.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
+ PublicApi.Instance.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
+ $"but current version is {Constant.Version}. Plugin excluded from manifest.");
return false;
diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj
index 540eabbf0..7bf90ea51 100644
--- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj
+++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj
@@ -1,4 +1,4 @@
-
+net9.0-windows
@@ -34,6 +34,7 @@
prompt4false
+ $(NoWarn);FLSG0007
@@ -55,6 +56,7 @@
+
@@ -63,6 +65,17 @@
+
+
+ true
+
+
+
+
+
+ Languages\en.xaml
+
+
diff --git a/Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs b/Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs
new file mode 100644
index 000000000..1da04bf01
--- /dev/null
+++ b/Flow.Launcher.Core/Plugin/IResultUpdateRegister.cs
@@ -0,0 +1,12 @@
+using Flow.Launcher.Plugin;
+
+namespace Flow.Launcher.Core.Plugin;
+
+public interface IResultUpdateRegister
+{
+ ///
+ /// Register a plugin to receive results updated event.
+ ///
+ ///
+ void RegisterResultsUpdatedEvent(PluginPair pair);
+}
diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs
index 9212dada6..abefd47bc 100644
--- a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs
+++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs
@@ -285,7 +285,7 @@ namespace Flow.Launcher.Core.Plugin
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Center,
Margin = SettingPanelItemLeftMargin,
- Content = API.GetTranslation("select")
+ Content = Localize.select()
};
Btn.Click += (_, _) =>
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/PluginConfig.cs b/Flow.Launcher.Core/Plugin/PluginConfig.cs
index 4313a51af..db6813deb 100644
--- a/Flow.Launcher.Core/Plugin/PluginConfig.cs
+++ b/Flow.Launcher.Core/Plugin/PluginConfig.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
@@ -6,7 +6,7 @@ using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin;
using System.Text.Json;
using Flow.Launcher.Infrastructure.UserSettings;
-using CommunityToolkit.Mvvm.DependencyInjection;
+using Flow.Launcher.Plugin.SharedCommands;
namespace Flow.Launcher.Core.Plugin
{
@@ -14,10 +14,6 @@ namespace Flow.Launcher.Core.Plugin
{
private static readonly string ClassName = nameof(PluginConfig);
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
///
/// Parse plugin metadata in the given directories
///
@@ -35,11 +31,22 @@ namespace Flow.Launcher.Core.Plugin
{
try
{
- Directory.Delete(directory, true);
+ var fullyDeleted = FilesFolders.TryDeleteDirectoryRobust(directory, maxRetries: 3, retryDelayMs: 200);
+ if (!fullyDeleted)
+ {
+ PublicApi.Instance.LogWarn(ClassName, $"Directory <{directory}> was not fully deleted.");
+
+ // Directory was not fully deleted, recreate the marker file so deletion will be retried on next startup
+ var markerFilePath = Path.Combine(directory, DataLocation.PluginDeleteFile);
+ if (!File.Exists(markerFilePath))
+ {
+ File.WriteAllText(markerFilePath, string.Empty);
+ }
+ }
}
catch (Exception e)
{
- API.LogException(ClassName, $"Can't delete <{directory}>", e);
+ PublicApi.Instance.LogException(ClassName, $"Can't delete <{directory}>", e);
}
}
else
@@ -56,7 +63,7 @@ namespace Flow.Launcher.Core.Plugin
duplicateList
.ForEach(
- x => API.LogWarn(ClassName,
+ x => PublicApi.Instance.LogWarn(ClassName,
string.Format("Duplicate plugin name: {0}, id: {1}, version: {2} " +
"not loaded due to version not the highest of the duplicates",
x.Name, x.ID, x.Version),
@@ -108,7 +115,7 @@ namespace Flow.Launcher.Core.Plugin
string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName);
if (!File.Exists(configPath))
{
- API.LogError(ClassName, $"Didn't find config file <{configPath}>");
+ PublicApi.Instance.LogError(ClassName, $"Didn't find config file <{configPath}>");
return null;
}
@@ -124,19 +131,19 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Invalid json for config <{configPath}>", e);
+ PublicApi.Instance.LogException(ClassName, $"Invalid json for config <{configPath}>", e);
return null;
}
if (!AllowedLanguage.IsAllowed(metadata.Language))
{
- API.LogError(ClassName, $"Invalid language <{metadata.Language}> for config <{configPath}>");
+ PublicApi.Instance.LogError(ClassName, $"Invalid language <{metadata.Language}> for config <{configPath}>");
return null;
}
if (!File.Exists(metadata.ExecuteFilePath))
{
- API.LogError(ClassName, $"Execute file path didn't exist <{metadata.ExecuteFilePath}> for conifg <{configPath}");
+ PublicApi.Instance.LogError(ClassName, $"Execute file path didn't exist <{metadata.ExecuteFilePath}> for conifg <{configPath}");
return null;
}
diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs
index d01b34ab6..6027b712e 100644
--- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs
+++ b/Flow.Launcher.Core/Plugin/PluginInstaller.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
@@ -22,10 +22,6 @@ public static class PluginInstaller
private static readonly Settings Settings = Ioc.Default.GetRequiredService();
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
///
/// Installs a plugin and restarts the application if required by settings. Prompts user for confirmation and handles download if needed.
///
@@ -33,18 +29,16 @@ public static class PluginInstaller
/// A Task representing the asynchronous install operation.
public static async Task InstallPluginAndCheckRestartAsync(UserPlugin newPlugin)
{
- if (API.PluginModified(newPlugin.ID))
+ if (PublicApi.Instance.PluginModified(newPlugin.ID))
{
- API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), newPlugin.Name),
- API.GetTranslation("pluginModifiedAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(newPlugin.Name),
+ Localize.pluginModifiedAlreadyMessage());
return;
}
- if (API.ShowMsgBox(
- string.Format(
- API.GetTranslation("InstallPromptSubtitle"),
- newPlugin.Name, newPlugin.Author, Environment.NewLine),
- API.GetTranslation("InstallPromptTitle"),
+ if (PublicApi.Instance.ShowMsgBox(
+ Localize.InstallPromptSubtitle(newPlugin.Name, newPlugin.Author, Environment.NewLine),
+ Localize.InstallPromptTitle(),
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
try
@@ -61,7 +55,7 @@ public static class PluginInstaller
if (!newPlugin.IsFromLocalInstallPath)
{
await DownloadFileAsync(
- $"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
+ $"{Localize.DownloadingPlugin()} {newPlugin.Name}",
newPlugin.UrlDownload, filePath, cts);
}
else
@@ -80,7 +74,7 @@ public static class PluginInstaller
throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath);
}
- if (!API.InstallPlugin(newPlugin, filePath))
+ if (!PublicApi.Instance.InstallPlugin(newPlugin, filePath))
{
return;
}
@@ -92,23 +86,20 @@ public static class PluginInstaller
}
catch (Exception e)
{
- API.LogException(ClassName, "Failed to install plugin", e);
- API.ShowMsgError(API.GetTranslation("ErrorInstallingPlugin"));
+ PublicApi.Instance.LogException(ClassName, "Failed to install plugin", e);
+ PublicApi.Instance.ShowMsgError(Localize.ErrorInstallingPlugin());
return; // do not restart on failure
}
if (Settings.AutoRestartAfterChanging)
{
- API.RestartApp();
+ PublicApi.Instance.RestartApp();
}
else
{
- API.ShowMsg(
- API.GetTranslation("installbtn"),
- string.Format(
- API.GetTranslation(
- "InstallSuccessNoRestart"),
- newPlugin.Name));
+ PublicApi.Instance.ShowMsg(
+ Localize.installbtn(),
+ Localize.InstallSuccessNoRestart(newPlugin.Name));
}
}
@@ -133,24 +124,23 @@ public static class PluginInstaller
}
catch (Exception e)
{
- API.LogException(ClassName, "Failed to validate zip file", e);
- API.ShowMsgError(API.GetTranslation("ZipFileNotHavePluginJson"));
+ PublicApi.Instance.LogException(ClassName, "Failed to validate zip file", e);
+ PublicApi.Instance.ShowMsgError(Localize.ZipFileNotHavePluginJson());
return;
}
- if (API.PluginModified(plugin.ID))
+ if (PublicApi.Instance.PluginModified(plugin.ID))
{
- API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), plugin.Name),
- API.GetTranslation("pluginModifiedAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(plugin.Name),
+ Localize.pluginModifiedAlreadyMessage());
return;
}
if (Settings.ShowUnknownSourceWarning)
{
if (!InstallSourceKnown(plugin.Website)
- && API.ShowMsgBox(string.Format(
- API.GetTranslation("InstallFromUnknownSourceSubtitle"), Environment.NewLine),
- API.GetTranslation("InstallFromUnknownSourceTitle"),
+ && PublicApi.Instance.ShowMsgBox(Localize.InstallFromUnknownSourceSubtitle(Environment.NewLine),
+ Localize.InstallFromUnknownSourceTitle(),
MessageBoxButton.YesNo) == MessageBoxResult.No)
return;
}
@@ -165,51 +155,46 @@ public static class PluginInstaller
/// A Task representing the asynchronous uninstall operation.
public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin)
{
- if (API.PluginModified(oldPlugin.ID))
+ if (PublicApi.Instance.PluginModified(oldPlugin.ID))
{
- API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), oldPlugin.Name),
- API.GetTranslation("pluginModifiedAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(oldPlugin.Name),
+ Localize.pluginModifiedAlreadyMessage());
return;
}
- if (API.ShowMsgBox(
- string.Format(
- API.GetTranslation("UninstallPromptSubtitle"),
- oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
- API.GetTranslation("UninstallPromptTitle"),
+ if (PublicApi.Instance.ShowMsgBox(
+ Localize.UninstallPromptSubtitle(oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
+ Localize.UninstallPromptTitle(),
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
- var removePluginSettings = API.ShowMsgBox(
- API.GetTranslation("KeepPluginSettingsSubtitle"),
- API.GetTranslation("KeepPluginSettingsTitle"),
+ var removePluginSettings = PublicApi.Instance.ShowMsgBox(
+ Localize.KeepPluginSettingsSubtitle(),
+ Localize.KeepPluginSettingsTitle(),
button: MessageBoxButton.YesNo) == MessageBoxResult.No;
try
{
- if (!await API.UninstallPluginAsync(oldPlugin, removePluginSettings))
+ if (!await PublicApi.Instance.UninstallPluginAsync(oldPlugin, removePluginSettings))
{
return;
}
}
catch (Exception e)
{
- API.LogException(ClassName, "Failed to uninstall plugin", e);
- API.ShowMsgError(API.GetTranslation("ErrorUninstallingPlugin"));
+ PublicApi.Instance.LogException(ClassName, "Failed to uninstall plugin", e);
+ PublicApi.Instance.ShowMsgError(Localize.ErrorUninstallingPlugin());
return; // don not restart on failure
}
if (Settings.AutoRestartAfterChanging)
{
- API.RestartApp();
+ PublicApi.Instance.RestartApp();
}
else
{
- API.ShowMsg(
- API.GetTranslation("uninstallbtn"),
- string.Format(
- API.GetTranslation(
- "UninstallSuccessNoRestart"),
- oldPlugin.Name));
+ PublicApi.Instance.ShowMsg(
+ Localize.uninstallbtn(),
+ Localize.UninstallSuccessNoRestart(oldPlugin.Name));
}
}
@@ -221,11 +206,9 @@ public static class PluginInstaller
/// A Task representing the asynchronous update operation.
public static async Task UpdatePluginAndCheckRestartAsync(UserPlugin newPlugin, PluginMetadata oldPlugin)
{
- if (API.ShowMsgBox(
- string.Format(
- API.GetTranslation("UpdatePromptSubtitle"),
- oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
- API.GetTranslation("UpdatePromptTitle"),
+ if (PublicApi.Instance.ShowMsgBox(
+ Localize.UpdatePromptSubtitle(oldPlugin.Name, oldPlugin.Author, Environment.NewLine),
+ Localize.UpdatePromptTitle(),
button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return;
try
@@ -237,7 +220,7 @@ public static class PluginInstaller
if (!newPlugin.IsFromLocalInstallPath)
{
await DownloadFileAsync(
- $"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}",
+ $"{Localize.DownloadingPlugin()} {newPlugin.Name}",
newPlugin.UrlDownload, filePath, cts);
}
else
@@ -251,30 +234,27 @@ public static class PluginInstaller
return;
}
- if (!await API.UpdatePluginAsync(oldPlugin, newPlugin, filePath))
+ if (!await PublicApi.Instance.UpdatePluginAsync(oldPlugin, newPlugin, filePath))
{
return;
}
}
catch (Exception e)
{
- API.LogException(ClassName, "Failed to update plugin", e);
- API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
+ PublicApi.Instance.LogException(ClassName, "Failed to update plugin", e);
+ PublicApi.Instance.ShowMsgError(Localize.ErrorUpdatingPlugin());
return; // do not restart on failure
}
if (Settings.AutoRestartAfterChanging)
{
- API.RestartApp();
+ PublicApi.Instance.RestartApp();
}
else
{
- API.ShowMsg(
- API.GetTranslation("updatebtn"),
- string.Format(
- API.GetTranslation(
- "UpdateSuccessNoRestart"),
- newPlugin.Name));
+ PublicApi.Instance.ShowMsg(
+ Localize.updatebtn(),
+ Localize.UpdateSuccessNoRestart(newPlugin.Name));
}
}
@@ -289,17 +269,17 @@ public static class PluginInstaller
public static async Task CheckForPluginUpdatesAsync(Action> updateAllPlugins, bool silentUpdate = true, bool usePrimaryUrlOnly = false, CancellationToken token = default)
{
// Update the plugin manifest
- await API.UpdatePluginManifestAsync(usePrimaryUrlOnly, token);
+ await PublicApi.Instance.UpdatePluginManifestAsync(usePrimaryUrlOnly, token);
// Get all plugins that can be updated
var resultsForUpdate = (
- from existingPlugin in API.GetAllPlugins()
- join pluginUpdateSource in API.GetPluginManifest()
+ from existingPlugin in PublicApi.Instance.GetAllPlugins()
+ join pluginUpdateSource in PublicApi.Instance.GetPluginManifest()
on existingPlugin.Metadata.ID equals pluginUpdateSource.ID
where string.Compare(existingPlugin.Metadata.Version, pluginUpdateSource.Version,
StringComparison.InvariantCulture) <
0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest)
- && !API.PluginModified(existingPlugin.Metadata.ID)
+ && !PublicApi.Instance.PluginModified(existingPlugin.Metadata.ID)
select
new PluginUpdateInfo()
{
@@ -314,25 +294,25 @@ public static class PluginInstaller
}).ToList();
// No updates
- if (!resultsForUpdate.Any())
+ if (resultsForUpdate.Count == 0)
{
if (!silentUpdate)
{
- API.ShowMsg(API.GetTranslation("updateNoResultTitle"), API.GetTranslation("updateNoResultSubtitle"));
+ PublicApi.Instance.ShowMsg(Localize.updateNoResultTitle(), Localize.updateNoResultSubtitle());
}
return;
}
// If all plugins are modified, just return
- if (resultsForUpdate.All(x => API.PluginModified(x.ID)))
+ if (resultsForUpdate.All(x => PublicApi.Instance.PluginModified(x.ID)))
{
return;
}
// Show message box with button to update all plugins
- API.ShowMsgWithButton(
- API.GetTranslation("updateAllPluginsTitle"),
- API.GetTranslation("updateAllPluginsButtonContent"),
+ PublicApi.Instance.ShowMsgWithButton(
+ Localize.updateAllPluginsTitle(),
+ Localize.updateAllPluginsButtonContent(),
() =>
{
updateAllPlugins(resultsForUpdate);
@@ -357,7 +337,7 @@ public static class PluginInstaller
using var cts = new CancellationTokenSource();
await DownloadFileAsync(
- $"{API.GetTranslation("DownloadingPlugin")} {plugin.PluginNewUserPlugin.Name}",
+ $"{Localize.DownloadingPlugin()} {plugin.PluginNewUserPlugin.Name}",
plugin.PluginNewUserPlugin.UrlDownload, downloadToFilePath, cts);
// check if user cancelled download before installing plugin
@@ -366,7 +346,7 @@ public static class PluginInstaller
return;
}
- if (!await API.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath))
+ if (!await PublicApi.Instance.UpdatePluginAsync(plugin.PluginExistingMetadata, plugin.PluginNewUserPlugin, downloadToFilePath))
{
return;
}
@@ -375,8 +355,8 @@ public static class PluginInstaller
}
catch (Exception e)
{
- API.LogException(ClassName, "Failed to update plugin", e);
- API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin"));
+ PublicApi.Instance.LogException(ClassName, "Failed to update plugin", e);
+ PublicApi.Instance.ShowMsgError(Localize.ErrorUpdatingPlugin());
}
}));
@@ -384,13 +364,13 @@ public static class PluginInstaller
if (restart)
{
- API.RestartApp();
+ PublicApi.Instance.RestartApp();
}
else
{
- API.ShowMsg(
- API.GetTranslation("updatebtn"),
- API.GetTranslation("PluginsUpdateSuccessNoRestart"));
+ PublicApi.Instance.ShowMsg(
+ Localize.updatebtn(),
+ Localize.PluginsUpdateSuccessNoRestart());
}
}
@@ -412,7 +392,7 @@ public static class PluginInstaller
if (showProgress)
{
var exceptionHappened = false;
- await API.ShowProgressBoxAsync(progressBoxTitle,
+ await PublicApi.Instance.ShowProgressBoxAsync(progressBoxTitle,
async (reportProgress) =>
{
if (reportProgress == null)
@@ -424,18 +404,18 @@ public static class PluginInstaller
}
else
{
- await API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
+ await PublicApi.Instance.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false);
}
}, cts.Cancel);
// if exception happened while downloading and user does not cancel downloading,
// we need to redownload the plugin
if (exceptionHappened && (!cts.IsCancellationRequested))
- await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
+ await PublicApi.Instance.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
}
else
{
- await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
+ await PublicApi.Instance.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false);
}
}
@@ -462,7 +442,7 @@ public static class PluginInstaller
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri) || uri.Host != acceptedHost)
return false;
- return API.GetAllPlugins().Any(x =>
+ return PublicApi.Instance.GetAllPlugins().Any(x =>
!string.IsNullOrEmpty(x.Metadata.Website) &&
x.Metadata.Website.StartsWith(constructedUrlPart)
);
diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs
index 7bdfc8009..b808e2a7f 100644
--- a/Flow.Launcher.Core/Plugin/PluginManager.cs
+++ b/Flow.Launcher.Core/Plugin/PluginManager.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
@@ -6,8 +6,8 @@ using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core.ExternalPlugins;
+using Flow.Launcher.Core.Resource;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.DialogJump;
using Flow.Launcher.Infrastructure.UserSettings;
@@ -25,48 +25,36 @@ namespace Flow.Launcher.Core.Plugin
{
private static readonly string ClassName = nameof(PluginManager);
- public static List AllPlugins { get; private set; }
- public static readonly HashSet GlobalPlugins = new();
- public static readonly Dictionary NonGlobalPlugins = new();
-
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
+ private static readonly ConcurrentDictionary _allLoadedPlugins = [];
+ private static readonly ConcurrentDictionary _allInitializedPlugins = [];
+ private static readonly ConcurrentDictionary _initFailedPlugins = [];
+ private static readonly ConcurrentDictionary _globalPlugins = [];
+ private static readonly ConcurrentDictionary _nonGlobalPlugins = [];
private static PluginsSettings Settings;
- private static readonly ConcurrentBag ModifiedPlugins = new();
+ private static readonly ConcurrentBag ModifiedPlugins = [];
- private static IEnumerable _contextMenuPlugins;
- private static IEnumerable _homePlugins;
- private static IEnumerable _resultUpdatePlugin;
- private static IEnumerable _translationPlugins;
-
- private static readonly List _dialogJumpExplorerPlugins = new();
- private static readonly List _dialogJumpDialogPlugins = new();
+ private static readonly ConcurrentBag _contextMenuPlugins = [];
+ private static readonly ConcurrentBag _homePlugins = [];
+ private static readonly ConcurrentBag _translationPlugins = [];
+ private static readonly ConcurrentBag _externalPreviewPlugins = [];
///
/// Directories that will hold Flow Launcher plugin directory
///
public static readonly string[] Directories =
- {
+ [
Constant.PreinstalledDirectory, DataLocation.PluginsDirectory
- };
+ ];
- private static void DeletePythonBinding()
- {
- const string binding = "flowlauncher.py";
- foreach (var subDirectory in Directory.GetDirectories(DataLocation.PluginsDirectory))
- {
- File.Delete(Path.Combine(subDirectory, binding));
- }
- }
+ #region Save & Dispose & Reload Plugin
///
/// Save json and ISavable
///
public static void Save()
{
- foreach (var pluginPair in AllPlugins)
+ foreach (var pluginPair in GetAllInitializedPlugins(includeFailed: false))
{
var savable = pluginPair.Plugin as ISavable;
try
@@ -75,17 +63,18 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to save plugin {pluginPair.Metadata.Name}", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed to save plugin {pluginPair.Metadata.Name}", e);
}
}
- API.SavePluginSettings();
- API.SavePluginCaches();
+ PublicApi.Instance.SavePluginSettings();
+ PublicApi.Instance.SavePluginCaches();
}
public static async ValueTask DisposePluginsAsync()
{
- foreach (var pluginPair in AllPlugins)
+ // Still call dispose for all plugins even if initialization failed, so that we can clean up resources
+ foreach (var pluginPair in GetAllInitializedPlugins(includeFailed: true))
{
await DisposePluginAsync(pluginPair);
}
@@ -107,55 +96,59 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to dispose plugin {pluginPair.Metadata.Name}", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed to dispose plugin {pluginPair.Metadata.Name}", e);
}
}
public static async Task ReloadDataAsync()
{
- await Task.WhenAll(AllPlugins.Select(plugin => plugin.Plugin switch
+ await Task.WhenAll([.. GetAllInitializedPlugins(includeFailed: false).Select(plugin => plugin.Plugin switch
{
IReloadable p => Task.Run(p.ReloadData),
IAsyncReloadable p => p.ReloadDataAsync(),
_ => Task.CompletedTask,
- }).ToArray());
+ })]);
}
+ #endregion
+
+ #region External Preview
+
public static async Task OpenExternalPreviewAsync(string path, bool sendFailToast = true)
{
- await Task.WhenAll(AllPlugins.Select(plugin => plugin.Plugin switch
+ await Task.WhenAll([.. GetAllInitializedPlugins(includeFailed: false).Select(plugin => plugin.Plugin switch
{
IAsyncExternalPreview p => p.OpenPreviewAsync(path, sendFailToast),
_ => Task.CompletedTask,
- }).ToArray());
+ })]);
}
public static async Task CloseExternalPreviewAsync()
{
- await Task.WhenAll(AllPlugins.Select(plugin => plugin.Plugin switch
+ await Task.WhenAll([.. GetAllInitializedPlugins(includeFailed: false).Select(plugin => plugin.Plugin switch
{
IAsyncExternalPreview p => p.ClosePreviewAsync(),
_ => Task.CompletedTask,
- }).ToArray());
+ })]);
}
public static async Task SwitchExternalPreviewAsync(string path, bool sendFailToast = true)
{
- await Task.WhenAll(AllPlugins.Select(plugin => plugin.Plugin switch
+ await Task.WhenAll([.. GetAllInitializedPlugins(includeFailed: false).Select(plugin => plugin.Plugin switch
{
IAsyncExternalPreview p => p.SwitchPreviewAsync(path, sendFailToast),
_ => Task.CompletedTask,
- }).ToArray());
+ })]);
}
public static bool UseExternalPreview()
{
- return GetPluginsForInterface().Any(x => !x.Metadata.Disabled);
+ return GetExternalPreviewPlugins().Any(x => !x.Metadata.Disabled);
}
public static bool AllowAlwaysPreview()
{
- var plugin = GetPluginsForInterface().FirstOrDefault(x => !x.Metadata.Disabled);
+ var plugin = GetExternalPreviewPlugins().FirstOrDefault(x => !x.Metadata.Disabled);
if (plugin is null)
return false;
@@ -163,6 +156,15 @@ namespace Flow.Launcher.Core.Plugin
return ((IAsyncExternalPreview)plugin.Plugin).AllowAlwaysPreview();
}
+ private static IList GetExternalPreviewPlugins()
+ {
+ return [.. _externalPreviewPlugins.Where(p => !PluginModified(p.Metadata.ID))];
+ }
+
+ #endregion
+
+ #region Constructor
+
static PluginManager()
{
// validate user directory
@@ -171,9 +173,28 @@ namespace Flow.Launcher.Core.Plugin
DeletePythonBinding();
}
+ private static void DeletePythonBinding()
+ {
+ const string binding = "flowlauncher.py";
+ foreach (var subDirectory in Directory.GetDirectories(DataLocation.PluginsDirectory))
+ {
+ try
+ {
+ File.Delete(Path.Combine(subDirectory, binding));
+ }
+ catch (Exception e)
+ {
+ PublicApi.Instance.LogDebug(ClassName, $"Failed to delete {binding} in {subDirectory}: {e.Message}");
+ }
+ }
+ }
+
+ #endregion
+
+ #region Load & Initialize Plugins
+
///
- /// because InitializePlugins needs API, so LoadPlugins needs to be called first
- /// todo happlebao The API should be removed
+ /// Load plugins from the directories specified in Directories.
///
///
public static void LoadPlugins(PluginsSettings settings)
@@ -181,33 +202,22 @@ namespace Flow.Launcher.Core.Plugin
var metadatas = PluginConfig.Parse(Directories);
Settings = settings;
Settings.UpdatePluginSettings(metadatas);
- AllPlugins = PluginsLoader.Plugins(metadatas, Settings);
+
+ // Load plugins
+ var allLoadedPlugins = PluginsLoader.Plugins(metadatas, Settings);
+ foreach (var plugin in allLoadedPlugins)
+ {
+ if (plugin != null)
+ {
+ if (!_allLoadedPlugins.TryAdd(plugin.Metadata.ID, plugin))
+ {
+ PublicApi.Instance.LogError(ClassName, $"Plugin with ID {plugin.Metadata.ID} already loaded");
+ }
+ }
+ }
+
// Since dotnet plugins need to get assembly name first, we should update plugin directory after loading plugins
UpdatePluginDirectory(metadatas);
-
- // Initialize plugin enumerable after all plugins are initialized
- _contextMenuPlugins = GetPluginsForInterface();
- _homePlugins = GetPluginsForInterface();
- _resultUpdatePlugin = GetPluginsForInterface();
- _translationPlugins = GetPluginsForInterface();
-
- // Initialize Dialog Jump plugin pairs
- foreach (var pair in GetPluginsForInterface())
- {
- _dialogJumpExplorerPlugins.Add(new DialogJumpExplorerPair
- {
- Plugin = (IDialogJumpExplorer)pair.Plugin,
- Metadata = pair.Metadata
- });
- }
- foreach (var pair in GetPluginsForInterface())
- {
- _dialogJumpDialogPlugins.Add(new DialogJumpDialogPair
- {
- Plugin = (IDialogJumpDialog)pair.Plugin,
- Metadata = pair.Metadata
- });
- }
}
private static void UpdatePluginDirectory(List metadatas)
@@ -218,7 +228,7 @@ namespace Flow.Launcher.Core.Plugin
{
if (string.IsNullOrEmpty(metadata.AssemblyName))
{
- API.LogWarn(ClassName, $"AssemblyName is empty for plugin with metadata: {metadata.Name}");
+ PublicApi.Instance.LogWarn(ClassName, $"AssemblyName is empty for plugin with metadata: {metadata.Name}");
continue; // Skip if AssemblyName is not set, which can happen for erroneous plugins
}
metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.AssemblyName);
@@ -228,7 +238,7 @@ namespace Flow.Launcher.Core.Plugin
{
if (string.IsNullOrEmpty(metadata.Name))
{
- API.LogWarn(ClassName, $"Name is empty for plugin with metadata: {metadata.Name}");
+ PublicApi.Instance.LogWarn(ClassName, $"Name is empty for plugin with metadata: {metadata.Name}");
continue; // Skip if Name is not set, which can happen for erroneous plugins
}
metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.Name);
@@ -238,106 +248,146 @@ namespace Flow.Launcher.Core.Plugin
}
///
- /// Call initialize for all plugins
+ /// Initialize all plugins asynchronously.
///
+ /// The register to register results updated event for each plugin.
/// return the list of failed to init plugins or null for none
- public static async Task InitializePluginsAsync()
+ public static async Task InitializePluginsAsync(IResultUpdateRegister register)
{
- var failedPlugins = new ConcurrentQueue();
-
- var InitTasks = AllPlugins.Select(pair => Task.Run(async delegate
+ var initTasks = _allLoadedPlugins.Select(x => Task.Run(async () =>
{
+ var pair = x.Value;
+
+ // Register plugin action keywords so that plugins can be queried in results
+ RegisterPluginActionKeywords(pair);
+
try
{
- var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Init method time cost for <{pair.Metadata.Name}>",
- () => pair.Plugin.InitAsync(new PluginInitContext(pair.Metadata, API)));
+ var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Init method time cost for <{pair.Metadata.Name}>",
+ () => pair.Plugin.InitAsync(new PluginInitContext(pair.Metadata, PublicApi.Instance)));
pair.Metadata.InitTime += milliseconds;
- API.LogInfo(ClassName,
+ PublicApi.Instance.LogInfo(ClassName,
$"Total init cost for <{pair.Metadata.Name}> is <{pair.Metadata.InitTime}ms>");
}
catch (Exception e)
{
- API.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e);
+ PublicApi.Instance.LogException(ClassName, $"Fail to Init plugin: {pair.Metadata.Name}", e);
if (pair.Metadata.Disabled && pair.Metadata.HomeDisabled)
{
// If this plugin is already disabled, do not show error message again
// Or else it will be shown every time
- API.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error");
+ PublicApi.Instance.LogDebug(ClassName, $"Skipped init for <{pair.Metadata.Name}> due to error");
}
else
{
pair.Metadata.Disabled = true;
pair.Metadata.HomeDisabled = true;
- failedPlugins.Enqueue(pair);
- API.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed");
+ PublicApi.Instance.LogDebug(ClassName, $"Disable plugin <{pair.Metadata.Name}> because init failed");
}
+
+ // Even if the plugin cannot be initialized, we still need to add it in all plugin list so that
+ // we can remove the plugin from Plugin or Store page or Plugin Manager plugin.
+ _allInitializedPlugins.TryAdd(pair.Metadata.ID, pair);
+ _initFailedPlugins.TryAdd(pair.Metadata.ID, pair);
+ return;
}
+
+ // Register ResultsUpdated event so that plugin query can use results updated interface
+ register.RegisterResultsUpdatedEvent(pair);
+
+ // Update plugin metadata translation after the plugin is initialized with IPublicAPI instance
+ Internationalization.UpdatePluginMetadataTranslation(pair);
+
+ // Add plugin to Dialog Jump plugin list after the plugin is initialized
+ DialogJump.InitializeDialogJumpPlugin(pair);
+
+ // Add plugin to lists after the plugin is initialized
+ AddPluginToLists(pair);
}));
- await Task.WhenAll(InitTasks);
+ await Task.WhenAll(initTasks);
- foreach (var plugin in AllPlugins)
+ if (!_initFailedPlugins.IsEmpty)
{
- // set distinct on each plugin's action keywords helps only firing global(*) and action keywords once where a plugin
- // has multiple global and action keywords because we will only add them here once.
- foreach (var actionKeyword in plugin.Metadata.ActionKeywords.Distinct())
- {
- switch (actionKeyword)
- {
- case Query.GlobalPluginWildcardSign:
- GlobalPlugins.Add(plugin);
- break;
- default:
- NonGlobalPlugins[actionKeyword] = plugin;
- break;
- }
- }
- }
-
- if (failedPlugins.Any())
- {
- var failed = string.Join(",", failedPlugins.Select(x => x.Metadata.Name));
- API.ShowMsg(
- API.GetTranslation("failedToInitializePluginsTitle"),
- string.Format(
- API.GetTranslation("failedToInitializePluginsMessage"),
- failed
- ),
+ var failed = string.Join(",", _initFailedPlugins.Values.Select(x => x.Metadata.Name));
+ PublicApi.Instance.ShowMsg(
+ Localize.failedToInitializePluginsTitle(),
+ Localize.failedToInitializePluginsMessage(failed),
"",
false
);
}
}
+ private static void RegisterPluginActionKeywords(PluginPair pair)
+ {
+ // set distinct on each plugin's action keywords helps only firing global(*) and action keywords once where a plugin
+ // has multiple global and action keywords because we will only add them here once.
+ foreach (var actionKeyword in pair.Metadata.ActionKeywords.Distinct())
+ {
+ switch (actionKeyword)
+ {
+ case Query.GlobalPluginWildcardSign:
+ _globalPlugins.TryAdd(pair.Metadata.ID, pair);
+ break;
+ default:
+ _nonGlobalPlugins.TryAdd(actionKeyword, pair);
+ break;
+ }
+ }
+ }
+
+ private static void AddPluginToLists(PluginPair pair)
+ {
+ if (pair.Plugin is IContextMenu)
+ {
+ _contextMenuPlugins.Add(pair);
+ }
+ if (pair.Plugin is IAsyncHomeQuery)
+ {
+ _homePlugins.Add(pair);
+ }
+ if (pair.Plugin is IPluginI18n)
+ {
+ _translationPlugins.Add(pair);
+ }
+ if (pair.Plugin is IAsyncExternalPreview)
+ {
+ _externalPreviewPlugins.Add(pair);
+ }
+ _allInitializedPlugins.TryAdd(pair.Metadata.ID, pair);
+ }
+
+ #endregion
+
+ #region Validate & Query Plugins
+
public static ICollection ValidPluginsForQuery(Query query, bool dialogJump)
{
if (query is null)
return Array.Empty();
- if (!NonGlobalPlugins.TryGetValue(query.ActionKeyword, out var plugin))
+ if (!_nonGlobalPlugins.TryGetValue(query.ActionKeyword, out var plugin))
{
if (dialogJump)
- return GlobalPlugins.Where(p => p.Plugin is IAsyncDialogJump && !PluginModified(p.Metadata.ID)).ToList();
+ return [.. GetGlobalPlugins().Where(p => p.Plugin is IAsyncDialogJump && !PluginModified(p.Metadata.ID))];
else
- return GlobalPlugins.Where(p => !PluginModified(p.Metadata.ID)).ToList();
+ return [.. GetGlobalPlugins().Where(p => !PluginModified(p.Metadata.ID))];
}
if (dialogJump && plugin.Plugin is not IAsyncDialogJump)
return Array.Empty();
- if (API.PluginModified(plugin.Metadata.ID))
+ if (PluginModified(plugin.Metadata.ID))
return Array.Empty();
- return new List
- {
- plugin
- };
+ return [plugin];
}
public static ICollection ValidPluginsForHomeQuery()
{
- return _homePlugins.Where(p => !PluginModified(p.Metadata.ID)).ToList();
+ return [.. _homePlugins.Where(p => !PluginModified(p.Metadata.ID))];
}
public static async Task> QueryForPluginAsync(PluginPair pair, Query query, CancellationToken token)
@@ -345,9 +395,31 @@ namespace Flow.Launcher.Core.Plugin
var results = new List();
var metadata = pair.Metadata;
+ if (IsPluginInitializing(metadata))
+ {
+ Result r = new()
+ {
+ Title = Localize.pluginStillInitializing(metadata.Name),
+ SubTitle = Localize.pluginStillInitializingSubtitle(),
+ AutoCompleteText = query.TrimmedQuery,
+ IcoPath = metadata.IcoPath,
+ PluginDirectory = metadata.PluginDirectory,
+ ActionKeywordAssigned = query.ActionKeyword,
+ PluginID = metadata.ID,
+ OriginQuery = query,
+ Action = _ =>
+ {
+ PublicApi.Instance.ReQuery();
+ return false;
+ }
+ };
+ results.Add(r);
+ return results;
+ }
+
try
{
- var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
+ var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
async () => results = await pair.Plugin.QueryAsync(query, token).ConfigureAwait(false));
token.ThrowIfCancellationRequested();
@@ -369,15 +441,15 @@ namespace Flow.Launcher.Core.Plugin
{
Result r = new()
{
- Title = $"{metadata.Name}: Failed to respond!",
- SubTitle = "Select this result for more info",
+ Title = Localize.pluginFailedToRespond(metadata.Name),
+ SubTitle = Localize.pluginFailedToRespondSubtitle(),
+ AutoCompleteText = query.TrimmedQuery,
IcoPath = Constant.ErrorIcon,
PluginDirectory = metadata.PluginDirectory,
ActionKeywordAssigned = query.ActionKeyword,
PluginID = metadata.ID,
OriginQuery = query,
- Action = _ => { throw new FlowPluginException(metadata, e);},
- Score = -100
+ Action = _ => { throw new FlowPluginException(metadata, e);}
};
results.Add(r);
}
@@ -389,9 +461,31 @@ namespace Flow.Launcher.Core.Plugin
var results = new List();
var metadata = pair.Metadata;
+ if (IsPluginInitializing(metadata))
+ {
+ Result r = new()
+ {
+ Title = Localize.pluginStillInitializing(metadata.Name),
+ SubTitle = Localize.pluginStillInitializingSubtitle(),
+ AutoCompleteText = query.TrimmedQuery,
+ IcoPath = metadata.IcoPath,
+ PluginDirectory = metadata.PluginDirectory,
+ ActionKeywordAssigned = query.ActionKeyword,
+ PluginID = metadata.ID,
+ OriginQuery = query,
+ Action = _ =>
+ {
+ PublicApi.Instance.ReQuery();
+ return false;
+ }
+ };
+ results.Add(r);
+ return results;
+ }
+
try
{
- var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
+ var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
async () => results = await ((IAsyncHomeQuery)pair.Plugin).HomeQueryAsync(token).ConfigureAwait(false));
token.ThrowIfCancellationRequested();
@@ -408,7 +502,7 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed to query home for plugin: {metadata.Name}", e);
return null;
}
return results;
@@ -419,9 +513,15 @@ namespace Flow.Launcher.Core.Plugin
var results = new List();
var metadata = pair.Metadata;
+ if (IsPluginInitializing(metadata))
+ {
+ // null will be fine since the results will only be added into queue if the token hasn't been cancelled
+ return null;
+ }
+
try
{
- var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
+ var milliseconds = await PublicApi.Instance.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
async () => results = await ((IAsyncDialogJump)pair.Plugin).QueryDialogJumpAsync(query, token).ConfigureAwait(false));
token.ThrowIfCancellationRequested();
@@ -438,12 +538,58 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to query Dialog Jump for plugin: {metadata.Name}", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed to query Dialog Jump for plugin: {metadata.Name}", e);
return null;
}
return results;
}
+ private static bool IsPluginInitializing(PluginMetadata metadata)
+ {
+ return !_allInitializedPlugins.ContainsKey(metadata.ID);
+ }
+
+ #endregion
+
+ #region Get Plugin List
+
+ public static List GetAllLoadedPlugins()
+ {
+ return [.. _allLoadedPlugins.Values];
+ }
+
+ public static List GetAllInitializedPlugins(bool includeFailed)
+ {
+ if (includeFailed)
+ {
+ return [.. _allInitializedPlugins.Values];
+ }
+ else
+ {
+ return [.. _allInitializedPlugins.Values
+ .Where(p => !_initFailedPlugins.ContainsKey(p.Metadata.ID))];
+ }
+ }
+
+ private static List GetGlobalPlugins()
+ {
+ return [.. _globalPlugins.Values];
+ }
+
+ public static Dictionary GetNonGlobalPlugins()
+ {
+ return _nonGlobalPlugins.ToDictionary();
+ }
+
+ public static List GetTranslationPlugins()
+ {
+ return [.. _translationPlugins.Where(p => !PluginModified(p.Metadata.ID))];
+ }
+
+ #endregion
+
+ #region Update Metadata & Get Plugin
+
public static void UpdatePluginMetadata(IReadOnlyList results, PluginMetadata metadata, Query query)
{
foreach (var r in results)
@@ -462,28 +608,19 @@ namespace Flow.Launcher.Core.Plugin
///
/// get specified plugin, return null if not found
///
+ ///
+ /// Plugin may not be initialized, so do not use its plugin model to execute any commands
+ ///
///
///
public static PluginPair GetPluginForId(string id)
{
- return AllPlugins.FirstOrDefault(o => o.Metadata.ID == id);
+ return GetAllLoadedPlugins().FirstOrDefault(o => o.Metadata.ID == id);
}
- private static IEnumerable GetPluginsForInterface() where T : IFeatures
- {
- // Handle scenario where this is called before all plugins are instantiated, e.g. language change on startup
- return AllPlugins?.Where(p => p.Plugin is T) ?? Array.Empty();
- }
+ #endregion
- public static IList GetResultUpdatePlugin()
- {
- return _resultUpdatePlugin.Where(p => !PluginModified(p.Metadata.ID)).ToList();
- }
-
- public static IList GetTranslationPlugins()
- {
- return _translationPlugins.Where(p => !PluginModified(p.Metadata.ID)).ToList();
- }
+ #region Get Context Menus
public static List GetContextMenusForPlugin(Result result)
{
@@ -505,7 +642,7 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName,
+ PublicApi.Instance.LogException(ClassName,
$"Can't load context menus for plugin <{pluginPair.Metadata.Name}>",
e);
}
@@ -514,27 +651,82 @@ namespace Flow.Launcher.Core.Plugin
return results;
}
+ #endregion
+
+ #region Check Home Plugin
+
public static bool IsHomePlugin(string id)
{
return _homePlugins.Where(p => !PluginModified(p.Metadata.ID)).Any(p => p.Metadata.ID == id);
}
- public static IList GetDialogJumpExplorers()
+ #endregion
+
+ #region Check Initializing & Init Failed
+
+ public static bool IsInitializingOrInitFailed(string id)
{
- return _dialogJumpExplorerPlugins.Where(p => !PluginModified(p.Metadata.ID)).ToList();
+ // Id does not exist in loaded plugins
+ if (!_allLoadedPlugins.ContainsKey(id)) return false;
+
+ // Plugin initialized already
+ if (_allInitializedPlugins.ContainsKey(id))
+ {
+ // Check if the plugin initialization failed
+ return _initFailedPlugins.ContainsKey(id);
+ }
+ // Plugin is still initializing
+ else
+ {
+ return true;
+ }
}
- public static IList GetDialogJumpDialogs()
+ public static bool IsInitializing(string id)
{
- return _dialogJumpDialogPlugins.Where(p => !PluginModified(p.Metadata.ID)).ToList();
+ // Id does not exist in loaded plugins
+ if (!_allLoadedPlugins.ContainsKey(id)) return false;
+
+ // Plugin initialized already
+ if (_allInitializedPlugins.ContainsKey(id))
+ {
+ return false;
+ }
+ // Plugin is still initializing
+ else
+ {
+ return true;
+ }
}
+ public static bool IsInitializationFailed(string id)
+ {
+ // Id does not exist in loaded plugins
+ if (!_allLoadedPlugins.ContainsKey(id)) return false;
+
+ // Plugin initialized already
+ if (_allInitializedPlugins.ContainsKey(id))
+ {
+ // Check if the plugin initialization failed
+ return _initFailedPlugins.ContainsKey(id);
+ }
+ // Plugin is still initializing
+ else
+ {
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region Plugin Action Keyword
+
public static bool ActionKeywordRegistered(string actionKeyword)
{
// this method is only checking for action keywords (defined as not '*') registration
// hence the actionKeyword != Query.GlobalPluginWildcardSign logic
return actionKeyword != Query.GlobalPluginWildcardSign
- && NonGlobalPlugins.ContainsKey(actionKeyword);
+ && _nonGlobalPlugins.ContainsKey(actionKeyword);
}
///
@@ -546,11 +738,11 @@ namespace Flow.Launcher.Core.Plugin
var plugin = GetPluginForId(id);
if (newActionKeyword == Query.GlobalPluginWildcardSign)
{
- GlobalPlugins.Add(plugin);
+ _globalPlugins.TryAdd(id, plugin);
}
else
{
- NonGlobalPlugins[newActionKeyword] = plugin;
+ _nonGlobalPlugins.AddOrUpdate(newActionKeyword, plugin, (key, oldValue) => plugin);
}
// Update action keywords and action keyword in plugin metadata
@@ -577,11 +769,13 @@ namespace Flow.Launcher.Core.Plugin
plugin.Metadata.ActionKeywords
.Count(x => x == Query.GlobalPluginWildcardSign) == 1)
{
- GlobalPlugins.Remove(plugin);
+ _globalPlugins.TryRemove(id, out _);
}
if (oldActionkeyword != Query.GlobalPluginWildcardSign)
- NonGlobalPlugins.Remove(oldActionkeyword);
+ {
+ _nonGlobalPlugins.TryRemove(oldActionkeyword, out _);
+ }
// Update action keywords and action keyword in plugin metadata
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
@@ -595,6 +789,12 @@ namespace Flow.Launcher.Core.Plugin
}
}
+ #endregion
+
+ #region Plugin Install & Uninstall & Update
+
+ #region Private Functions
+
private static string GetContainingFolderPathAfterUnzip(string unzippedParentFolderPath)
{
var unzippedFolderCount = Directory.GetDirectories(unzippedParentFolderPath).Length;
@@ -620,12 +820,15 @@ namespace Flow.Launcher.Core.Plugin
if (!Version.TryParse(newMetadata.Version, out var newVersion))
return true; // If version is not valid, we assume it is lesser than any existing version
- return AllPlugins.Any(x => x.Metadata.ID == newMetadata.ID
- && Version.TryParse(x.Metadata.Version, out var version)
- && newVersion <= version);
+ // Get all plugins even if initialization failed so that we can check if the plugin with the same ID exists
+ return GetAllInitializedPlugins(includeFailed: true).Any(x => x.Metadata.ID == newMetadata.ID
+ && Version.TryParse(x.Metadata.Version, out var version)
+ && newVersion <= version);
}
- #region Public functions
+ #endregion
+
+ #region Public Functions
public static bool PluginModified(string id)
{
@@ -636,8 +839,8 @@ namespace Flow.Launcher.Core.Plugin
{
if (PluginModified(existingVersion.ID))
{
- API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), existingVersion.Name),
- API.GetTranslation("pluginModifiedAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(existingVersion.Name),
+ Localize.pluginModifiedAlreadyMessage());
return false;
}
@@ -663,14 +866,14 @@ namespace Flow.Launcher.Core.Plugin
#endregion
- #region Internal functions
+ #region Internal Functions
internal static bool InstallPlugin(UserPlugin plugin, string zipFilePath, bool checkModified)
{
if (checkModified && PluginModified(plugin.ID))
{
- API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), plugin.Name),
- API.GetTranslation("pluginModifiedAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(plugin.Name),
+ Localize.pluginModifiedAlreadyMessage());
return false;
}
@@ -689,15 +892,15 @@ namespace Flow.Launcher.Core.Plugin
if (string.IsNullOrEmpty(metadataJsonFilePath) || string.IsNullOrEmpty(pluginFolderPath))
{
- API.ShowMsgError(string.Format(API.GetTranslation("failedToInstallPluginTitle"), plugin.Name),
- string.Format(API.GetTranslation("fileNotFoundMessage"), pluginFolderPath));
+ PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name),
+ Localize.fileNotFoundMessage(pluginFolderPath));
return false;
}
if (SameOrLesserPluginVersionExists(metadataJsonFilePath))
{
- API.ShowMsgError(string.Format(API.GetTranslation("failedToInstallPluginTitle"), plugin.Name),
- API.GetTranslation("pluginExistAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name),
+ Localize.pluginExistAlreadyMessage());
return false;
}
@@ -726,7 +929,19 @@ namespace Flow.Launcher.Core.Plugin
var newPluginPath = Path.Combine(installDirectory, folderName);
- FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => API.ShowMsgBox(s));
+ FilesFolders.CopyAll(pluginFolderPath, newPluginPath, (s) => PublicApi.Instance.ShowMsgBox(s));
+
+ // Check if marker file exists and delete it
+ try
+ {
+ var markerFilePath = Path.Combine(newPluginPath, DataLocation.PluginDeleteFile);
+ if (File.Exists(markerFilePath))
+ File.Delete(markerFilePath);
+ }
+ catch (Exception e)
+ {
+ PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin marker file in {newPluginPath}", e);
+ }
try
{
@@ -735,7 +950,7 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to delete temp folder {tempFolderPluginPath}", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed to delete temp folder {tempFolderPluginPath}", e);
}
if (checkModified)
@@ -750,8 +965,8 @@ namespace Flow.Launcher.Core.Plugin
{
if (checkModified && PluginModified(plugin.ID))
{
- API.ShowMsgError(string.Format(API.GetTranslation("pluginModifiedAlreadyTitle"), plugin.Name),
- API.GetTranslation("pluginModifiedAlreadyMessage"));
+ PublicApi.Instance.ShowMsgError(Localize.pluginModifiedAlreadyTitle(plugin.Name),
+ Localize.pluginModifiedAlreadyMessage());
return false;
}
@@ -760,7 +975,7 @@ namespace Flow.Launcher.Core.Plugin
// If we want to remove plugin from AllPlugins,
// we need to dispose them so that they can release file handles
// which can help FL to delete the plugin settings & cache folders successfully
- var pluginPairs = AllPlugins.FindAll(p => p.Metadata.ID == plugin.ID);
+ var pluginPairs = GetAllInitializedPlugins(includeFailed: true).Where(p => p.Metadata.ID == plugin.ID).ToList();
foreach (var pluginPair in pluginPairs)
{
await DisposePluginAsync(pluginPair);
@@ -770,7 +985,7 @@ namespace Flow.Launcher.Core.Plugin
if (removePluginSettings)
{
// For dotnet plugins, we need to remove their PluginJsonStorage and PluginBinaryStorage instances
- if (AllowedLanguage.IsDotNet(plugin.Language) && API is IRemovable removable)
+ if (AllowedLanguage.IsDotNet(plugin.Language) && PublicApi.Instance is IRemovable removable)
{
removable.RemovePluginSettings(plugin.AssemblyName);
removable.RemovePluginCaches(plugin.PluginCacheDirectoryPath);
@@ -784,9 +999,9 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to delete plugin settings folder for {plugin.Name}", e);
- API.ShowMsgError(API.GetTranslation("failedToRemovePluginSettingsTitle"),
- string.Format(API.GetTranslation("failedToRemovePluginSettingsMessage"), plugin.Name));
+ PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin settings folder for {plugin.Name}", e);
+ PublicApi.Instance.ShowMsgError(Localize.failedToRemovePluginSettingsTitle(),
+ Localize.failedToRemovePluginSettingsMessage(plugin.Name));
}
}
@@ -800,17 +1015,27 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to delete plugin cache folder for {plugin.Name}", e);
- API.ShowMsgError(API.GetTranslation("failedToRemovePluginCacheTitle"),
- string.Format(API.GetTranslation("failedToRemovePluginCacheMessage"), plugin.Name));
+ PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin cache folder for {plugin.Name}", e);
+ PublicApi.Instance.ShowMsgError(Localize.failedToRemovePluginCacheTitle(),
+ Localize.failedToRemovePluginCacheMessage(plugin.Name));
}
Settings.RemovePluginSettings(plugin.ID);
- AllPlugins.RemoveAll(p => p.Metadata.ID == plugin.ID);
- GlobalPlugins.RemoveWhere(p => p.Metadata.ID == plugin.ID);
- var keysToRemove = NonGlobalPlugins.Where(p => p.Value.Metadata.ID == plugin.ID).Select(p => p.Key).ToList();
+ {
+ _allLoadedPlugins.TryRemove(plugin.ID, out var _);
+ }
+ {
+ _allInitializedPlugins.TryRemove(plugin.ID, out var _);
+ }
+ {
+ _initFailedPlugins.TryRemove(plugin.ID, out var _);
+ }
+ {
+ _globalPlugins.TryRemove(plugin.ID, out var _);
+ }
+ var keysToRemove = _nonGlobalPlugins.Where(p => p.Value.Metadata.ID == plugin.ID).Select(p => p.Key).ToList();
foreach (var key in keysToRemove)
{
- NonGlobalPlugins.Remove(key);
+ _nonGlobalPlugins.TryRemove(key, out var _);
}
}
@@ -826,5 +1051,7 @@ namespace Flow.Launcher.Core.Plugin
}
#endregion
+
+ #endregion
}
}
diff --git a/Flow.Launcher.Core/Plugin/PluginsLoader.cs b/Flow.Launcher.Core/Plugin/PluginsLoader.cs
index e9e5ee367..119dd83ba 100644
--- a/Flow.Launcher.Core/Plugin/PluginsLoader.cs
+++ b/Flow.Launcher.Core/Plugin/PluginsLoader.cs
@@ -2,9 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
-using System.Threading.Tasks;
-using System.Windows;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core.ExternalPlugins.Environments;
#pragma warning disable IDE0005
using Flow.Launcher.Infrastructure.Logger;
@@ -18,10 +15,6 @@ namespace Flow.Launcher.Core.Plugin
{
private static readonly string ClassName = nameof(PluginsLoader);
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
public static List Plugins(List metadatas, PluginsSettings settings)
{
var dotnetPlugins = DotNetPlugins(metadatas);
@@ -55,7 +48,7 @@ namespace Flow.Launcher.Core.Plugin
return plugins;
}
- private static IEnumerable DotNetPlugins(List source)
+ private static List DotNetPlugins(List source)
{
var erroredPlugins = new List();
@@ -64,56 +57,58 @@ namespace Flow.Launcher.Core.Plugin
foreach (var metadata in metadatas)
{
- var milliseconds = API.StopwatchLogDebug(ClassName, $"Constructor init cost for {metadata.Name}", () =>
+ var milliseconds = PublicApi.Instance.StopwatchLogDebug(ClassName, $"Constructor init cost for {metadata.Name}", () =>
+ {
+ Assembly assembly = null;
+ IAsyncPlugin plugin = null;
+
+ try
{
- Assembly assembly = null;
- IAsyncPlugin plugin = null;
+ var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
+ assembly = assemblyLoader.LoadAssemblyAndDependencies();
- try
- {
- var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
- assembly = assemblyLoader.LoadAssemblyAndDependencies();
+ var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly,
+ typeof(IAsyncPlugin));
- var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly,
- typeof(IAsyncPlugin));
+ plugin = Activator.CreateInstance(type) as IAsyncPlugin;
- plugin = Activator.CreateInstance(type) as IAsyncPlugin;
-
- metadata.AssemblyName = assembly.GetName().Name;
- }
+ metadata.AssemblyName = assembly.GetName().Name;
+ }
#if DEBUG
- catch (Exception)
- {
- throw;
- }
+ catch (Exception)
+ {
+ throw;
+ }
#else
- catch (Exception e) when (assembly == null)
- {
- Log.Exception(ClassName, $"Couldn't load assembly for the plugin: {metadata.Name}", e);
- }
- catch (InvalidOperationException e)
- {
- Log.Exception(ClassName, $"Can't find the required IPlugin interface for the plugin: <{metadata.Name}>", e);
- }
- catch (ReflectionTypeLoadException e)
- {
- Log.Exception(ClassName, $"The GetTypes method was unable to load assembly types for the plugin: <{metadata.Name}>", e);
- }
- catch (Exception e)
- {
- Log.Exception(ClassName, $"The following plugin has errored and can not be loaded: <{metadata.Name}>", e);
- }
+ catch (Exception e) when (assembly == null)
+ {
+ PublicApi.Instance.LogException(ClassName, $"Couldn't load assembly for the plugin: {metadata.Name}", e);
+ }
+ catch (InvalidOperationException e)
+ {
+ PublicApi.Instance.LogException(ClassName, $"Can't find the required IPlugin interface for the plugin: <{metadata.Name}>", e);
+ }
+ catch (ReflectionTypeLoadException e)
+ {
+ PublicApi.Instance.LogException(ClassName, $"The GetTypes method was unable to load assembly types for the plugin: <{metadata.Name}>", e);
+ }
+ catch (Exception e)
+ {
+ PublicApi.Instance.LogException(ClassName, $"The following plugin has errored and can not be loaded: <{metadata.Name}>", e);
+ }
#endif
- if (plugin == null)
- {
- erroredPlugins.Add(metadata.Name);
- return;
- }
+ if (plugin == null)
+ {
+ erroredPlugins.Add(metadata.Name);
+ return;
+ }
+
+ plugins.Add(new PluginPair { Plugin = plugin, Metadata = metadata });
+ });
- plugins.Add(new PluginPair { Plugin = plugin, Metadata = metadata });
- });
metadata.InitTime += milliseconds;
+ PublicApi.Instance.LogDebug(ClassName, $"Constructor cost for <{metadata.Name}> is <{metadata.InitTime}ms>");
}
if (erroredPlugins.Count > 0)
@@ -121,12 +116,12 @@ namespace Flow.Launcher.Core.Plugin
var errorPluginString = string.Join(Environment.NewLine, erroredPlugins);
var errorMessage = erroredPlugins.Count > 1 ?
- API.GetTranslation("pluginsHaveErrored") :
- API.GetTranslation("pluginHasErrored");
+ Localize.pluginsHaveErrored():
+ Localize.pluginHasErrored();
- API.ShowMsgError($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
+ PublicApi.Instance.ShowMsgError($"{errorMessage}{Environment.NewLine}{Environment.NewLine}" +
$"{errorPluginString}{Environment.NewLine}{Environment.NewLine}" +
- API.GetTranslation("referToLogs"));
+ Localize.referToLogs());
}
return plugins;
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.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs
index 983f8b234..7505dca62 100644
--- a/Flow.Launcher.Core/Resource/Internationalization.cs
+++ b/Flow.Launcher.Core/Resource/Internationalization.cs
@@ -6,7 +6,6 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
@@ -18,10 +17,6 @@ namespace Flow.Launcher.Core.Resource
{
private static readonly string ClassName = nameof(Internationalization);
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
private const string Folder = "Languages";
private const string DefaultLanguageCode = "en";
private const string DefaultFile = "en.xaml";
@@ -104,7 +99,7 @@ namespace Flow.Launcher.Core.Resource
var directory = Path.Combine(Constant.ProgramDirectory, Folder);
if (!Directory.Exists(directory))
{
- API.LogError(ClassName, $"Flow Launcher language directory can't be found <{directory}>");
+ PublicApi.Instance.LogError(ClassName, $"Flow Launcher language directory can't be found <{directory}>");
return;
}
@@ -175,7 +170,7 @@ namespace Flow.Launcher.Core.Resource
FirstOrDefault(o => o.LanguageCode.Equals(languageCode, StringComparison.OrdinalIgnoreCase));
if (language == null)
{
- API.LogError(ClassName, $"Language code can't be found <{languageCode}>");
+ PublicApi.Instance.LogError(ClassName, $"Language code can't be found <{languageCode}>");
return AvailableLanguages.English;
}
else
@@ -208,7 +203,7 @@ namespace Flow.Launcher.Core.Resource
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed to change language to <{language.LanguageCode}>", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed to change language to <{language.LanguageCode}>", e);
}
finally
{
@@ -254,7 +249,7 @@ namespace Flow.Launcher.Core.Resource
// "Do you want to search with pinyin?"
string text = languageToSet == AvailableLanguages.Chinese ? "是否启用拼音搜索?" : "是否啓用拼音搜索?";
- if (API.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
+ if (PublicApi.Instance.ShowMsgBox(text, string.Empty, MessageBoxButton.YesNo) == MessageBoxResult.No)
return false;
return true;
@@ -311,7 +306,7 @@ namespace Flow.Launcher.Core.Resource
}
else
{
- API.LogError(ClassName, $"Language path can't be found <{path}>");
+ PublicApi.Instance.LogError(ClassName, $"Language path can't be found <{path}>");
var english = Path.Combine(folder, DefaultFile);
if (File.Exists(english))
{
@@ -319,7 +314,7 @@ namespace Flow.Launcher.Core.Resource
}
else
{
- API.LogError(ClassName, $"Default English Language path can't be found <{path}>");
+ PublicApi.Instance.LogError(ClassName, $"Default English Language path can't be found <{path}>");
return string.Empty;
}
}
@@ -354,7 +349,7 @@ namespace Flow.Launcher.Core.Resource
}
else
{
- API.LogError(ClassName, $"No Translation for key {key}");
+ PublicApi.Instance.LogError(ClassName, $"No Translation for key {key}");
return $"No Translation for key {key}";
}
}
@@ -377,11 +372,27 @@ namespace Flow.Launcher.Core.Resource
}
catch (Exception e)
{
- API.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e);
+ PublicApi.Instance.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e);
}
}
}
+ public static void UpdatePluginMetadataTranslation(PluginPair p)
+ {
+ // Update plugin metadata name & description
+ if (p.Plugin is not IPluginI18n pluginI18N) return;
+ try
+ {
+ p.Metadata.Name = pluginI18N.GetTranslatedPluginTitle();
+ p.Metadata.Description = pluginI18N.GetTranslatedPluginDescription();
+ pluginI18N.OnCultureInfoChanged(CultureInfo.CurrentCulture);
+ }
+ catch (Exception e)
+ {
+ PublicApi.Instance.LogException(ClassName, $"Failed for <{p.Metadata.Name}>", e);
+ }
+ }
+
#endregion
#region IDisposable
diff --git a/Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs b/Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs
deleted file mode 100644
index 3e1a19a76..000000000
--- a/Flow.Launcher.Core/Resource/LocalizedDescriptionAttribute.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using System.ComponentModel;
-using CommunityToolkit.Mvvm.DependencyInjection;
-using Flow.Launcher.Plugin;
-
-namespace Flow.Launcher.Core.Resource
-{
- public class LocalizedDescriptionAttribute : DescriptionAttribute
- {
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
- private readonly string _resourceKey;
-
- public LocalizedDescriptionAttribute(string resourceKey)
- {
- _resourceKey = resourceKey;
- }
-
- public override string Description
- {
- get
- {
- string description = API.GetTranslation(_resourceKey);
- return string.IsNullOrWhiteSpace(description) ?
- string.Format("[[{0}]]", _resourceKey) : description;
- }
- }
- }
-}
diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs
index a6e8dc6bf..c3bb6190f 100644
--- a/Flow.Launcher.Core/Resource/Theme.cs
+++ b/Flow.Launcher.Core/Resource/Theme.cs
@@ -444,17 +444,27 @@ namespace Flow.Launcher.Core.Resource
_api.LogError(ClassName, $"Theme <{theme}> path can't be found");
if (theme != Constant.DefaultTheme)
{
- _api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_path_not_exists"), theme));
+ _api.ShowMsgBox(Localize.theme_load_failure_path_not_exists(theme));
ChangeTheme(Constant.DefaultTheme);
}
return false;
}
- catch (XamlParseException)
+ catch (XamlParseException e)
{
- _api.LogError(ClassName, $"Theme <{theme}> fail to parse");
+ _api.LogException(ClassName, $"Theme <{theme}> fail to parse xaml", e);
if (theme != Constant.DefaultTheme)
{
- _api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_parse_error"), theme));
+ _api.ShowMsgBox(Localize.theme_load_failure_parse_error(theme));
+ ChangeTheme(Constant.DefaultTheme);
+ }
+ return false;
+ }
+ catch (Exception e)
+ {
+ _api.LogException(ClassName, $"Theme <{theme}> fail to load", e);
+ if (theme != Constant.DefaultTheme)
+ {
+ _api.ShowMsgBox(Localize.theme_load_failure_parse_error(theme));
ChangeTheme(Constant.DefaultTheme);
}
return false;
diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs
index 45275696c..1f138e843 100644
--- a/Flow.Launcher.Core/Updater.cs
+++ b/Flow.Launcher.Core/Updater.cs
@@ -41,8 +41,8 @@ namespace Flow.Launcher.Core
try
{
if (!silentUpdate)
- _api.ShowMsg(_api.GetTranslation("pleaseWait"),
- _api.GetTranslation("update_flowlauncher_update_check"));
+ _api.ShowMsg(Localize.pleaseWait(),
+ Localize.update_flowlauncher_update_check());
using var updateManager = await GitHubUpdateManagerAsync(GitHubRepository).ConfigureAwait(false);
@@ -58,13 +58,13 @@ namespace Flow.Launcher.Core
if (newReleaseVersion <= currentVersion)
{
if (!silentUpdate)
- _api.ShowMsgBox(_api.GetTranslation("update_flowlauncher_already_on_latest"));
+ _api.ShowMsgBox(Localize.update_flowlauncher_already_on_latest());
return;
}
if (!silentUpdate)
- _api.ShowMsg(_api.GetTranslation("update_flowlauncher_update_found"),
- _api.GetTranslation("update_flowlauncher_updating"));
+ _api.ShowMsg(Localize.update_flowlauncher_update_found(),
+ Localize.update_flowlauncher_updating());
await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply).ConfigureAwait(false);
@@ -77,10 +77,7 @@ namespace Flow.Launcher.Core
FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination, (s) => _api.ShowMsgBox(s));
if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination,
(s) => _api.ShowMsgBox(s)))
- _api.ShowMsgBox(string.Format(
- _api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"),
- DataLocation.PortableDataPath,
- targetDestination));
+ _api.ShowMsgBox(Localize.update_flowlauncher_fail_moving_portable_user_profile_data(DataLocation.PortableDataPath, targetDestination));
}
else
{
@@ -91,7 +88,7 @@ namespace Flow.Launcher.Core
_api.LogInfo(ClassName, $"Update success:{newVersionTips}");
- if (_api.ShowMsgBox(newVersionTips, _api.GetTranslation("update_flowlauncher_new_update"),
+ if (_api.ShowMsgBox(newVersionTips, Localize.update_flowlauncher_new_update(),
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
UpdateManager.RestartApp(Constant.ApplicationFileName);
@@ -111,8 +108,8 @@ namespace Flow.Launcher.Core
}
if (!silentUpdate)
- _api.ShowMsgError(_api.GetTranslation("update_flowlauncher_fail"),
- _api.GetTranslation("update_flowlauncher_check_connection"));
+ _api.ShowMsgError(Localize.update_flowlauncher_fail(),
+ Localize.update_flowlauncher_check_connection());
}
finally
{
@@ -150,9 +147,9 @@ namespace Flow.Launcher.Core
return manager;
}
- private string NewVersionTips(string version)
+ private static string NewVersionTips(string version)
{
- var tips = string.Format(_api.GetTranslation("newVersionTips"), version);
+ var tips = Localize.newVersionTips(version);
return tips;
}
diff --git a/Flow.Launcher.Core/packages.lock.json b/Flow.Launcher.Core/packages.lock.json
index b499a5860..ba97f57f3 100644
--- a/Flow.Launcher.Core/packages.lock.json
+++ b/Flow.Launcher.Core/packages.lock.json
@@ -11,6 +11,12 @@
"YamlDotNet": "9.1.0"
}
},
+ "Flow.Launcher.Localization": {
+ "type": "Direct",
+ "requested": "[0.0.6, )",
+ "resolved": "0.0.6",
+ "contentHash": "WNI/TLGPDr3XdOW8gaALN0Uyz9h+bzqOaNZev2nHEuA3HW9o7XuqaM6C0PqNi96mNgxiypwWpVazBNzaylJ2Aw=="
+ },
"FSharp.Core": {
"type": "Direct",
"requested": "[9.0.303, )",
@@ -84,6 +90,11 @@
"resolved": "1.1.0",
"contentHash": "j/zGAQ9hLbl7JDpeO40DaXvyyNxwQNDwnJEN7eCexn5F9Kid+VKya/Er0rfIv5Zod/32XarkqFP/V6WFHS/UpQ=="
},
+ "ini-parser": {
+ "type": "Transitive",
+ "resolved": "2.5.2",
+ "contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
+ },
"InputSimulator": {
"type": "Transitive",
"resolved": "1.0.4",
@@ -1161,6 +1172,7 @@
"Ben.Demystifier": "[0.4.1, )",
"BitFaster.Caching": "[2.5.4, )",
"CommunityToolkit.Mvvm": "[8.4.0, )",
+ "Flow.Launcher.Localization": "[0.0.6, )",
"Flow.Launcher.Plugin": "[5.0.0, )",
"InputSimulator": "[1.0.4, )",
"MemoryPack": "[1.21.4, )",
@@ -1170,7 +1182,8 @@
"NLog.OutputDebugString": "[6.0.4, )",
"SharpVectors.Wpf": "[1.8.5, )",
"System.Drawing.Common": "[7.0.0, )",
- "ToolGood.Words.Pinyin": "[3.1.0.3, )"
+ "ToolGood.Words.Pinyin": "[3.1.0.3, )",
+ "ini-parser": "[2.5.2, )"
}
},
"flow.launcher.plugin": {
diff --git a/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs b/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
index aa2c641ca..53df05bf2 100644
--- a/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
+++ b/Flow.Launcher.Infrastructure/DialogJump/DialogJump.cs
@@ -13,6 +13,7 @@ using NHotkey;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Accessibility;
+using System.Collections.Concurrent;
namespace Flow.Launcher.Infrastructure.DialogJump
{
@@ -58,21 +59,17 @@ namespace Flow.Launcher.Infrastructure.DialogJump
private static readonly Settings _settings = Ioc.Default.GetRequiredService();
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
private static HWND _mainWindowHandle = HWND.Null;
- private static readonly Dictionary _dialogJumpExplorers = new();
+ private static readonly ConcurrentDictionary _dialogJumpExplorers = new();
private static DialogJumpExplorerPair _lastExplorer = null;
- private static readonly object _lastExplorerLock = new();
+ private static readonly Lock _lastExplorerLock = new();
- private static readonly Dictionary _dialogJumpDialogs = new();
+ private static readonly ConcurrentDictionary _dialogJumpDialogs = new();
private static IDialogJumpDialogWindow _dialogWindow = null;
- private static readonly object _dialogWindowLock = new();
+ private static readonly Lock _dialogWindowLock = new();
private static HWINEVENTHOOK _foregroundChangeHook = HWINEVENTHOOK.Null;
private static HWINEVENTHOOK _locationChangeHook = HWINEVENTHOOK.Null;
@@ -89,8 +86,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
private static DispatcherTimer _dragMoveTimer = null;
// A list of all file dialog windows that are auto switched already
- private static readonly List _autoSwitchedDialogs = new();
- private static readonly object _autoSwitchedDialogsLock = new();
+ private static readonly List _autoSwitchedDialogs = [];
+ private static readonly Lock _autoSwitchedDialogsLock = new();
private static HWINEVENTHOOK _moveSizeHook = HWINEVENTHOOK.Null;
private static readonly WINEVENTPROC _moveProc = MoveSizeCallBack;
@@ -105,22 +102,13 @@ namespace Flow.Launcher.Infrastructure.DialogJump
#region Initialize & Setup
- public static void InitializeDialogJump(IList dialogJumpExplorers,
- IList dialogJumpDialogs)
+ public static void InitializeDialogJump()
{
if (_initialized) return;
- // Initialize Dialog Jump explorers & dialogs
- _dialogJumpExplorers.Add(WindowsDialogJumpExplorer, null);
- foreach (var explorer in dialogJumpExplorers)
- {
- _dialogJumpExplorers.Add(explorer, null);
- }
- _dialogJumpDialogs.Add(WindowsDialogJumpDialog, null);
- foreach (var dialog in dialogJumpDialogs)
- {
- _dialogJumpDialogs.Add(dialog, null);
- }
+ // Initialize preinstalled Dialog Jump explorers & dialogs
+ _dialogJumpExplorers.TryAdd(WindowsDialogJumpExplorer, null);
+ _dialogJumpDialogs.TryAdd(WindowsDialogJumpDialog, null);
// Initialize main window handle
_mainWindowHandle = Win32Helper.GetMainWindowHandle();
@@ -135,6 +123,29 @@ namespace Flow.Launcher.Infrastructure.DialogJump
_initialized = true;
}
+ public static void InitializeDialogJumpPlugin(PluginPair pair)
+ {
+ // Add Dialog Jump explorers & dialogs
+ if (pair.Plugin is IDialogJumpExplorer explorer)
+ {
+ var dialogJumpExplorer = new DialogJumpExplorerPair
+ {
+ Plugin = explorer,
+ Metadata = pair.Metadata
+ };
+ _dialogJumpExplorers.TryAdd(dialogJumpExplorer, null);
+ }
+ if (pair.Plugin is IDialogJumpDialog dialog)
+ {
+ var dialogJumpDialog = new DialogJumpDialogPair
+ {
+ Plugin = dialog,
+ Metadata = pair.Metadata
+ };
+ _dialogJumpDialogs.TryAdd(dialogJumpDialog, null);
+ }
+ }
+
public static void SetupDialogJump(bool enabled)
{
if (enabled == _enabled) return;
@@ -315,7 +326,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
{
foreach (var explorer in _dialogJumpExplorers.Keys)
{
- if (API.PluginModified(explorer.Metadata.ID) || // Plugin is modified
+ if (PublicApi.Instance.PluginModified(explorer.Metadata.ID) || // Plugin is modified
explorer.Metadata.Disabled) continue; // Plugin is disabled
var explorerWindow = explorer.Plugin.CheckExplorerWindow(hWnd);
@@ -485,6 +496,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
uint dwmsEventTime
)
{
+ if (hwnd.IsNull) return;
+
await _foregroundChangeLock.WaitAsync();
try
{
@@ -493,7 +506,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
var dialogWindowChanged = false;
foreach (var dialog in _dialogJumpDialogs.Keys)
{
- if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
+ if (PublicApi.Instance.PluginModified(dialog.Metadata.ID) || // Plugin is modified
dialog.Metadata.Disabled) continue; // Plugin is disabled
IDialogJumpDialogWindow dialogWindow;
@@ -596,7 +609,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
{
foreach (var explorer in _dialogJumpExplorers.Keys)
{
- if (API.PluginModified(explorer.Metadata.ID) || // Plugin is modified
+ if (PublicApi.Instance.PluginModified(explorer.Metadata.ID) || // Plugin is modified
explorer.Metadata.Disabled) continue; // Plugin is disabled
var explorerWindow = explorer.Plugin.CheckExplorerWindow(hwnd);
@@ -636,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)
@@ -661,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)
{
@@ -686,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)
@@ -717,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)
@@ -748,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)
@@ -887,7 +910,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
// Then check all dialog windows
foreach (var dialog in _dialogJumpDialogs.Keys)
{
- if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
+ if (PublicApi.Instance.PluginModified(dialog.Metadata.ID) || // Plugin is modified
dialog.Metadata.Disabled) continue; // Plugin is disabled
var dialogWindow = _dialogJumpDialogs[dialog];
@@ -900,7 +923,7 @@ namespace Flow.Launcher.Infrastructure.DialogJump
// Finally search for the dialog window again
foreach (var dialog in _dialogJumpDialogs.Keys)
{
- if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
+ if (PublicApi.Instance.PluginModified(dialog.Metadata.ID) || // Plugin is modified
dialog.Metadata.Disabled) continue; // Plugin is disabled
IDialogJumpDialogWindow dialogWindow;
@@ -1083,11 +1106,8 @@ namespace Flow.Launcher.Infrastructure.DialogJump
_navigationLock.Dispose();
// Stop drag move timer
- if (_dragMoveTimer != null)
- {
- _dragMoveTimer.Stop();
- _dragMoveTimer = null;
- }
+ _dragMoveTimer?.Stop();
+ _dragMoveTimer = null;
}
#endregion
diff --git a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs
index 1085cc833..6e2d86849 100644
--- a/Flow.Launcher.Infrastructure/FileExplorerHelper.cs
+++ b/Flow.Launcher.Infrastructure/FileExplorerHelper.cs
@@ -1,8 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using Windows.Win32;
namespace Flow.Launcher.Infrastructure
{
@@ -13,9 +9,10 @@ namespace Flow.Launcher.Infrastructure
///
public static string GetActiveExplorerPath()
{
- var explorerWindow = GetActiveExplorer();
- string locationUrl = explorerWindow?.LocationURL;
- return !string.IsNullOrEmpty(locationUrl) ? GetDirectoryPath(new Uri(locationUrl).LocalPath) : null;
+ var explorerPath = DialogJump.DialogJump.GetActiveExplorerPath();
+ return !string.IsNullOrEmpty(explorerPath) ?
+ GetDirectoryPath(new Uri(explorerPath).LocalPath) :
+ null;
}
///
@@ -23,74 +20,12 @@ namespace Flow.Launcher.Infrastructure
///
private static string GetDirectoryPath(string path)
{
- if (!path.EndsWith("\\"))
+ if (!path.EndsWith('\\'))
{
return path + "\\";
}
return path;
}
-
- ///
- /// Gets the file explorer that is currently in the foreground
- ///
- private static dynamic GetActiveExplorer()
- {
- Type type = Type.GetTypeFromProgID("Shell.Application");
- if (type == null) return null;
- dynamic shell = Activator.CreateInstance(type);
- if (shell == null)
- {
- return null;
- }
-
- var explorerWindows = new List();
- var openWindows = shell.Windows();
- for (int i = 0; i < openWindows.Count; i++)
- {
- var window = openWindows.Item(i);
- if (window == null) continue;
-
- // find the desired window and make sure that it is indeed a file explorer
- // we don't want the Internet Explorer or the classic control panel
- // ToLower() is needed, because Windows can report the path as "C:\\Windows\\Explorer.EXE"
- if (Path.GetFileName((string)window.FullName)?.ToLower() == "explorer.exe")
- {
- explorerWindows.Add(window);
- }
- }
-
- if (explorerWindows.Count == 0) return null;
-
- var zOrders = GetZOrder(explorerWindows);
-
- return explorerWindows.Zip(zOrders).MinBy(x => x.Second).First;
- }
-
- ///
- /// Gets the z-order for one or more windows atomically with respect to each other. In Windows, smaller z-order is higher. If the window is not top level, the z order is returned as -1.
- ///
- private static IEnumerable GetZOrder(List hWnds)
- {
- var z = new int[hWnds.Count];
- for (var i = 0; i < hWnds.Count; i++) z[i] = -1;
-
- var index = 0;
- var numRemaining = hWnds.Count;
- PInvoke.EnumWindows((wnd, _) =>
- {
- var searchIndex = hWnds.FindIndex(x => new IntPtr(x.HWND) == wnd);
- if (searchIndex != -1)
- {
- z[searchIndex] = index;
- numRemaining--;
- if (numRemaining == 0) return false;
- }
- index++;
- return true;
- }, IntPtr.Zero);
-
- return z;
- }
}
}
diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
index 5b4eaf893..4cde3f6e0 100644
--- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
+++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
@@ -34,6 +34,7 @@
prompt4false
+ $(NoWarn);FLSG0007
@@ -56,10 +57,12 @@
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -80,4 +83,15 @@
+
+ true
+
+
+
+
+
+ Languages\en.xaml
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher.Infrastructure/Http/Http.cs b/Flow.Launcher.Infrastructure/Http/Http.cs
index 8afab419b..f8c111f36 100644
--- a/Flow.Launcher.Infrastructure/Http/Http.cs
+++ b/Flow.Launcher.Infrastructure/Http/Http.cs
@@ -4,10 +4,8 @@ using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
-using Flow.Launcher.Plugin;
using JetBrains.Annotations;
namespace Flow.Launcher.Infrastructure.Http
@@ -20,10 +18,6 @@ namespace Flow.Launcher.Infrastructure.Http
private static readonly HttpClient client = new();
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
static Http()
{
// need to be added so it would work on a win10 machine
@@ -82,7 +76,7 @@ namespace Flow.Launcher.Infrastructure.Http
}
catch (UriFormatException e)
{
- API.ShowMsgError(API.GetTranslation("pleaseTryAgain"), API.GetTranslation("parseProxyFailed"));
+ PublicApi.Instance.ShowMsgError(Localize.pleaseTryAgain(), Localize.parseProxyFailed());
Log.Exception(ClassName, "Unable to parse Uri", e);
}
}
diff --git a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs
index 4ce0df026..86f757eb8 100644
--- a/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs
+++ b/Flow.Launcher.Infrastructure/Image/ThumbnailReader.cs
@@ -1,13 +1,14 @@
using System;
-using System.Runtime.InteropServices;
using System.IO;
+using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
+using IniParser;
using Windows.Win32;
using Windows.Win32.Foundation;
-using Windows.Win32.UI.Shell;
using Windows.Win32.Graphics.Gdi;
+using Windows.Win32.UI.Shell;
namespace Flow.Launcher.Infrastructure.Image
{
@@ -35,9 +36,32 @@ namespace Flow.Launcher.Infrastructure.Image
private static readonly HRESULT S_PATHNOTFOUND = (HRESULT)0x8004B205;
+ private const string UrlExtension = ".url";
+
+ ///
+ /// Obtains a BitmapSource thumbnail for the specified file.
+ ///
+ ///
+ /// If the file is a Windows URL shortcut (".url"), the method attempts to resolve the shortcut's icon and use that for the thumbnail; otherwise it requests a thumbnail for the file path. The native HBITMAP used to create the BitmapSource is always released to avoid native memory leaks.
+ ///
+ /// Path to the file (can be a regular file or a ".url" shortcut).
+ /// Requested thumbnail width in pixels.
+ /// Requested thumbnail height in pixels.
+ /// Thumbnail extraction options (flags) controlling fallback and caching behavior.
+ /// A BitmapSource representing the requested thumbnail.
public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
{
- HBITMAP hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
+ HBITMAP hBitmap;
+
+ var extension = Path.GetExtension(fileName);
+ if (string.Equals(extension, UrlExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ hBitmap = GetHBitmapForUrlFile(fileName, width, height, options);
+ }
+ else
+ {
+ hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
+ }
try
{
@@ -50,6 +74,21 @@ namespace Flow.Launcher.Infrastructure.Image
}
}
+ ///
+ /// Obtains a native HBITMAP for the specified file at the requested size using the Windows Shell image factory.
+ ///
+ ///
+ /// If is and thumbnail extraction fails
+ /// due to extraction errors or a missing path, the method falls back to requesting an icon ().
+ /// The returned HBITMAP is a raw GDI handle; the caller is responsible for releasing it (e.g., via DeleteObject) to avoid native memory leaks.
+ ///
+ /// Path to the file to thumbnail.
+ /// Requested thumbnail width in pixels.
+ /// Requested thumbnail height in pixels.
+ /// Thumbnail request flags that control behavior (e.g., ThumbnailOnly, IconOnly).
+ /// An HBITMAP handle containing the image. Caller must free the handle when finished.
+ /// If creating the shell item fails (HRESULT returned by SHCreateItemFromParsingName).
+ /// If the shell item does not expose IShellItemImageFactory or if an unexpected error occurs while obtaining the image.
private static unsafe HBITMAP GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
{
var retCode = PInvoke.SHCreateItemFromParsingName(
@@ -108,5 +147,44 @@ namespace Flow.Launcher.Infrastructure.Image
return hBitmap;
}
+
+ ///
+ /// Obtains an HBITMAP for a Windows .url shortcut by resolving its IconFile entry and delegating to GetHBitmap.
+ ///
+ ///
+ /// The method parses the .url file as an INI, looks in the "InternetShortcut" section for the "IconFile" entry,
+ /// and requests a bitmap for that icon path. If no IconFile is present or any error occurs while reading or
+ /// resolving the icon, it falls back to requesting a thumbnail for the .url file itself.
+ ///
+ /// Path to the .url shortcut file.
+ /// Requested thumbnail width (pixels).
+ /// Requested thumbnail height (pixels).
+ /// ThumbnailOptions flags controlling extraction behavior.
+ /// An HBITMAP containing the requested image; callers are responsible for freeing the native handle.
+ private static unsafe HBITMAP GetHBitmapForUrlFile(string fileName, int width, int height, ThumbnailOptions options)
+ {
+ HBITMAP hBitmap;
+
+ try
+ {
+ var parser = new FileIniDataParser();
+ var data = parser.ReadFile(fileName);
+ var urlSection = data["InternetShortcut"];
+
+ var iconPath = urlSection?["IconFile"];
+ if (!File.Exists(iconPath))
+ {
+ // If the IconFile is missing, throw exception to fallback to the default icon
+ throw new FileNotFoundException("Icon file not specified in Internet shortcut (.url) file.");
+ }
+ hBitmap = GetHBitmap(Path.GetFullPath(iconPath), width, height, options);
+ }
+ catch
+ {
+ hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
+ }
+
+ return hBitmap;
+ }
}
}
diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs
index 09eb98f46..2a5b826a9 100644
--- a/Flow.Launcher.Infrastructure/Logger/Log.cs
+++ b/Flow.Launcher.Infrastructure/Logger/Log.cs
@@ -34,7 +34,7 @@ namespace Flow.Launcher.Infrastructure.Logger
var fileTarget = new FileTarget
{
- FileName = CurrentLogDirectory.Replace(@"\", "/") + "/${shortdate}.txt",
+ FileName = CurrentLogDirectory.Replace(@"\", "/") + "/Flow.Launcher.${date:format=yyyy-MM-dd}.log",
Layout = layout
};
@@ -65,26 +65,22 @@ namespace Flow.Launcher.Infrastructure.Logger
public static void SetLogLevel(LOGLEVEL level)
{
- switch (level)
+ var rule = LogManager.Configuration.FindRuleByName("file");
+
+ var nlogLevel = level switch
{
- case LOGLEVEL.DEBUG:
- UseDebugLogLevel();
- break;
- default:
- UseInfoLogLevel();
- break;
- }
- Info(nameof(Logger), $"Using log level: {level}.");
- }
+ LOGLEVEL.NONE => LogLevel.Off,
+ LOGLEVEL.ERROR => LogLevel.Error,
+ LOGLEVEL.DEBUG => LogLevel.Debug,
+ _ => LogLevel.Info
+ };
- private static void UseDebugLogLevel()
- {
- LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Debug, LogLevel.Fatal);
- }
+ rule.SetLoggingLevels(nlogLevel, LogLevel.Fatal);
- private static void UseInfoLogLevel()
- {
- LogManager.Configuration.FindRuleByName("file").SetLoggingLevels(LogLevel.Info, LogLevel.Fatal);
+ LogManager.ReconfigExistingLoggers();
+
+ // We can't log Info when level is set to Error or None, so we use Debug
+ Debug(nameof(Logger), $"Using log level: {level}.");
}
private static void LogFaultyFormat(string message)
@@ -169,7 +165,9 @@ namespace Flow.Launcher.Infrastructure.Logger
public enum LOGLEVEL
{
- DEBUG,
- INFO
+ NONE,
+ ERROR,
+ INFO,
+ DEBUG
}
}
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/CustomBrowserViewModel.cs b/Flow.Launcher.Infrastructure/UserSettings/CustomBrowserViewModel.cs
index 9c795f952..009b27666 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/CustomBrowserViewModel.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/CustomBrowserViewModel.cs
@@ -1,18 +1,13 @@
using System.Text.Json.Serialization;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Infrastructure.UserSettings
{
public class CustomBrowserViewModel : BaseModel
{
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
public string Name { get; set; }
[JsonIgnore]
- public string DisplayName => Name == "Default" ? API.GetTranslation("defaultBrowser_default") : Name;
+ public string DisplayName => Name == "Default" ? Localize.defaultBrowser_default() : Name;
public string Path { get; set; }
public string PrivateArg { get; set; }
public bool EnablePrivate { get; set; }
diff --git a/Flow.Launcher.Infrastructure/UserSettings/CustomExplorerViewModel.cs b/Flow.Launcher.Infrastructure/UserSettings/CustomExplorerViewModel.cs
index 2af0bb0e5..ae406f4c5 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/CustomExplorerViewModel.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/CustomExplorerViewModel.cs
@@ -1,18 +1,13 @@
using System.Text.Json.Serialization;
-using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Infrastructure.UserSettings
{
public class CustomExplorerViewModel : BaseModel
{
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
-
public string Name { get; set; }
[JsonIgnore]
- public string DisplayName => Name == "Explorer" ? API.GetTranslation("fileManagerExplorer") : Name;
+ public string DisplayName => Name == "Explorer" ? Localize.fileManagerExplorer() : Name;
public string Path { get; set; }
public string FileArgument { get; set; } = "\"%d\"";
public string DirectoryArgument { get; set; } = "\"%d\"";
diff --git a/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs b/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs
index 2603d4675..a2e95b668 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs
@@ -1,8 +1,6 @@
using System;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
-using CommunityToolkit.Mvvm.DependencyInjection;
-using Flow.Launcher.Plugin;
namespace Flow.Launcher.Infrastructure.UserSettings
{
@@ -55,11 +53,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
{
public string Description { get; set; }
- public string LocalizedDescription => API.GetTranslation(Description);
-
- // We should not initialize API in static constructor because it will create another API instance
- private static IPublicAPI api = null;
- private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService();
+ public string LocalizedDescription => PublicApi.Instance.GetTranslation(Description);
public BaseBuiltinShortcutModel(string key, string description)
{
diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index d49cd276a..37ff59a08 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
using System.Windows;
@@ -480,6 +480,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.Infrastructure/packages.lock.json b/Flow.Launcher.Infrastructure/packages.lock.json
index 47c94d5f6..db77f9d93 100644
--- a/Flow.Launcher.Infrastructure/packages.lock.json
+++ b/Flow.Launcher.Infrastructure/packages.lock.json
@@ -23,12 +23,24 @@
"resolved": "8.4.0",
"contentHash": "tqVU8yc/ADO9oiTRyTnwhFN68hCwvkliMierptWOudIAvWY1mWCh5VFh+guwHJmpMwfg0J0rY+yyd5Oy7ty9Uw=="
},
+ "Flow.Launcher.Localization": {
+ "type": "Direct",
+ "requested": "[0.0.6, )",
+ "resolved": "0.0.6",
+ "contentHash": "WNI/TLGPDr3XdOW8gaALN0Uyz9h+bzqOaNZev2nHEuA3HW9o7XuqaM6C0PqNi96mNgxiypwWpVazBNzaylJ2Aw=="
+ },
"Fody": {
"type": "Direct",
"requested": "[6.9.3, )",
"resolved": "6.9.3",
"contentHash": "1CUGgFdyECDKgi5HaUBhdv6k+VG9Iy4OCforGfHyar3xQXAJypZkzymgKtWj/4SPd6nSG0Qi7NH71qHrDSZLaA=="
},
+ "ini-parser": {
+ "type": "Direct",
+ "requested": "[2.5.2, )",
+ "resolved": "2.5.2",
+ "contentHash": "hp3gKmC/14+6eKLgv7Jd1Z7OV86lO+tNfOXr/stQbwmRhdQuXVSvrRAuAe7G5+lwhkov0XkqZ8/bn1PYWMx6eg=="
+ },
"InputSimulator": {
"type": "Direct",
"requested": "[1.0.4, )",
diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
index 649d59ad7..378d4306a 100644
--- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
+++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
@@ -15,10 +15,10 @@
- 5.1.0
- 5.1.0
- 5.1.0
- 5.1.0
+ 5.2.0
+ 5.2.0
+ 5.2.0
+ 5.2.0Flow.Launcher.PluginFlow-LauncherMIT
@@ -72,9 +72,9 @@
allruntime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
index dd44647b4..93844159f 100644
--- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
@@ -173,9 +173,21 @@ namespace Flow.Launcher.Plugin
///
/// Get all loaded plugins
///
+ ///
+ /// Will also return any plugins not fully initialized yet
+ ///
///
List GetAllPlugins();
+ ///
+ /// Get all initialized plugins
+ ///
+ ///
+ /// Whether to include plugins that failed to initialize
+ ///
+ ///
+ List GetAllInitializedPlugins(bool includeFailed);
+
///
/// Registers a callback function for global keyboard events.
///
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/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
index 3af57f00d..cd1ddf983 100644
--- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
+++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
@@ -130,6 +130,119 @@ namespace Flow.Launcher.Plugin.SharedCommands
}
}
+ ///
+ /// Attempts to delete a directory robustly with retry logic for locked files.
+ /// This method tries to delete files individually with retries, then removes empty directories.
+ /// Returns true if the directory was completely deleted, false if some files/folders remain.
+ ///
+ /// The directory path to delete
+ /// Maximum number of retry attempts for locked files (default: 3)
+ /// Delay in milliseconds between retries (default: 100ms)
+ /// True if directory was fully deleted, false if some items remain
+ public static bool TryDeleteDirectoryRobust(string path, int maxRetries = 3, int retryDelayMs = 100)
+ {
+ if (!Directory.Exists(path))
+ return true;
+
+ bool fullyDeleted = true;
+
+ try
+ {
+ // First, try to delete all files in the directory tree
+ var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
+ foreach (var file in files)
+ {
+ bool fileDeleted = false;
+ for (int attempt = 0; attempt <= maxRetries; attempt++)
+ {
+ try
+ {
+ // Remove read-only attribute if present
+ var fileInfo = new FileInfo(file);
+ if (fileInfo.Exists && fileInfo.IsReadOnly)
+ {
+ fileInfo.IsReadOnly = false;
+ }
+
+ File.Delete(file);
+ fileDeleted = true;
+ break;
+ }
+ catch (UnauthorizedAccessException)
+ {
+ // File is in use or access denied, wait and retry
+ if (attempt < maxRetries)
+ {
+ System.Threading.Thread.Sleep(retryDelayMs);
+ }
+ }
+ catch (IOException)
+ {
+ // File is in use, wait and retry
+ if (attempt < maxRetries)
+ {
+ System.Threading.Thread.Sleep(retryDelayMs);
+ }
+ }
+ catch
+ {
+ // Other exceptions, don't retry
+ break;
+ }
+ }
+
+ if (!fileDeleted)
+ {
+ fullyDeleted = false;
+ }
+ }
+
+ // Then, try to delete all empty directories (from deepest to shallowest)
+ var directories = Directory.GetDirectories(path, "*", SearchOption.AllDirectories)
+ .OrderByDescending(d => d.Length) // Delete deeper directories first
+ .ToArray();
+
+ foreach (var directory in directories)
+ {
+ try
+ {
+ if (Directory.Exists(directory) && !Directory.EnumerateFileSystemEntries(directory).Any())
+ {
+ Directory.Delete(directory, false);
+ }
+ }
+ catch
+ {
+ // If we can't delete an empty directory, mark as not fully deleted
+ fullyDeleted = false;
+ }
+ }
+
+ // Finally, try to delete the root directory itself
+ try
+ {
+ if (Directory.Exists(path) && !Directory.EnumerateFileSystemEntries(path).Any())
+ {
+ Directory.Delete(path, false);
+ }
+ else if (Directory.Exists(path))
+ {
+ fullyDeleted = false;
+ }
+ }
+ catch
+ {
+ fullyDeleted = false;
+ }
+ }
+ catch
+ {
+ fullyDeleted = false;
+ }
+
+ return fullyDeleted;
+ }
+
///
/// Checks if a directory exists
///
diff --git a/Flow.Launcher.Plugin/packages.lock.json b/Flow.Launcher.Plugin/packages.lock.json
index 70f71f20d..7565ec3f4 100644
--- a/Flow.Launcher.Plugin/packages.lock.json
+++ b/Flow.Launcher.Plugin/packages.lock.json
@@ -16,23 +16,23 @@
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
- "requested": "[8.0.0, )",
- "resolved": "8.0.0",
- "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "requested": "[10.0.103, )",
+ "resolved": "10.0.103",
+ "contentHash": "qZk7r40ftpZY+/sO019sgWAWfNqC2CLSspDdAxNYCJU/bCi/8jVwvOMjzb/d5gjCRNzQ4OCYgBfhdpQyVwLTyw==",
"dependencies": {
- "Microsoft.Build.Tasks.Git": "8.0.0",
- "Microsoft.SourceLink.Common": "8.0.0"
+ "Microsoft.Build.Tasks.Git": "10.0.103",
+ "Microsoft.SourceLink.Common": "10.0.103"
}
},
"Microsoft.Windows.CsWin32": {
"type": "Direct",
- "requested": "[0.3.205, )",
- "resolved": "0.3.205",
- "contentHash": "U5wGAnyKd7/I2YMd43nogm81VMtjiKzZ9dsLMVI4eAB7jtv5IEj0gprj0q/F3iRmAIaGv5omOf8iSYx2+nE6BQ==",
+ "requested": "[0.3.269, )",
+ "resolved": "0.3.269",
+ "contentHash": "O4GVJ0ymxcoFRGS07VcoEClj7A9PIciHIjWDrPymzonhYlOfM7V0ZqGBUK19cUH3BPca9MfSOH0KLK/9JzQ8+Q==",
"dependencies": {
"Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha",
- "Microsoft.Windows.SDK.Win32Metadata": "61.0.15-preview",
- "Microsoft.Windows.WDK.Win32Metadata": "0.12.8-experimental"
+ "Microsoft.Windows.SDK.Win32Metadata": "69.0.7-preview",
+ "Microsoft.Windows.WDK.Win32Metadata": "0.13.25-experimental"
}
},
"PropertyChanged.Fody": {
@@ -46,13 +46,13 @@
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ "resolved": "10.0.103",
+ "contentHash": "QoiCMcPuxC6eqRQmrmF9zBY96ejIznXtve/lJJbonGD9I5Aygf2AUCOWslGiCEtBbfWRSuUnepBjuuVOdAl5ag=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
- "resolved": "8.0.0",
- "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ "resolved": "10.0.103",
+ "contentHash": "cMtGW5/r0ck72Jg2QwZcNTX59z+iB/B1kW84VMa/eX8L19DhHIuIcQjfK0pgLLBxd60Jl0Bj9GUolcM0MnJnZA=="
},
"Microsoft.Windows.SDK.Win32Docs": {
"type": "Transitive",
@@ -61,15 +61,15 @@
},
"Microsoft.Windows.SDK.Win32Metadata": {
"type": "Transitive",
- "resolved": "61.0.15-preview",
- "contentHash": "cysex3dazKtCPALCluC2XX3f5Aedy9H2pw5jb+TW5uas2rkem1Z7FRnbUrg2vKx0pk0Qz+4EJNr37HdYTEcvEQ=="
+ "resolved": "69.0.7-preview",
+ "contentHash": "RJoNjQJVCIDNLPbvYuaygCFknTyAxOUE45of1voj0jjOgJa9MB2m1/G8L8F3IYc+2EFG5aqa/9y8PEx7Tk2tLQ=="
},
"Microsoft.Windows.WDK.Win32Metadata": {
"type": "Transitive",
- "resolved": "0.12.8-experimental",
- "contentHash": "3n8R44/Z96Ly+ty4eYVJfESqbzvpw96lRLs3zOzyDmr1x1Kw7FNn5CyE416q+bZQV3e1HRuMUvyegMeRE/WedA==",
+ "resolved": "0.13.25-experimental",
+ "contentHash": "IM50tb/+UIwBr9FMr6ZKcZjCMW+Axo6NjGqKxgjUfyCY8dRnYUfrJEXxAaXoWtYP4X8EmASmC1Jtwh4XucseZg==",
"dependencies": {
- "Microsoft.Windows.SDK.Win32Metadata": "61.0.15-preview"
+ "Microsoft.Windows.SDK.Win32Metadata": "63.0.31-preview"
}
}
}
diff --git a/Flow.Launcher.Test/FilesFoldersTest.cs b/Flow.Launcher.Test/FilesFoldersTest.cs
index 2621fc2da..a63b59c39 100644
--- a/Flow.Launcher.Test/FilesFoldersTest.cs
+++ b/Flow.Launcher.Test/FilesFoldersTest.cs
@@ -1,6 +1,7 @@
using Flow.Launcher.Plugin.SharedCommands;
using NUnit.Framework;
using NUnit.Framework.Legacy;
+using System.IO;
namespace Flow.Launcher.Test
{
@@ -50,5 +51,89 @@ namespace Flow.Launcher.Test
{
ClassicAssert.AreEqual(expectedResult, FilesFolders.PathContains(parentPath, path, allowEqual: expectedResult));
}
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryDoesNotExist_ReturnsTrue()
+ {
+ // Arrange
+ string nonExistentPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(nonExistentPath);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryIsEmpty_DeletesSuccessfully()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryHasFiles_DeletesSuccessfully()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+ File.WriteAllText(Path.Combine(tempDir, "test.txt"), "test content");
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenDirectoryHasNestedStructure_DeletesSuccessfully()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+ string subDir1 = Path.Combine(tempDir, "SubDir1");
+ string subDir2 = Path.Combine(tempDir, "SubDir2");
+ Directory.CreateDirectory(subDir1);
+ Directory.CreateDirectory(subDir2);
+ File.WriteAllText(Path.Combine(subDir1, "file1.txt"), "content1");
+ File.WriteAllText(Path.Combine(subDir2, "file2.txt"), "content2");
+ File.WriteAllText(Path.Combine(tempDir, "root.txt"), "root content");
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
+
+ [Test]
+ public void TryDeleteDirectoryRobust_WhenFileIsReadOnly_RemovesAttributeAndDeletes()
+ {
+ // Arrange
+ string tempDir = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
+ Directory.CreateDirectory(tempDir);
+ string filePath = Path.Combine(tempDir, "readonly.txt");
+ File.WriteAllText(filePath, "readonly content");
+ File.SetAttributes(filePath, FileAttributes.ReadOnly);
+
+ // Act
+ bool result = FilesFolders.TryDeleteDirectoryRobust(tempDir);
+
+ // Assert
+ ClassicAssert.IsTrue(result);
+ ClassicAssert.IsFalse(Directory.Exists(tempDir));
+ }
}
}
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/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs
index 8e05686c9..a94b265fc 100644
--- a/Flow.Launcher/ActionKeywords.xaml.cs
+++ b/Flow.Launcher/ActionKeywords.xaml.cs
@@ -47,7 +47,7 @@ namespace Flow.Launcher
if (addedActionKeywords.Any(App.API.ActionKeywordAssigned))
{
- App.API.ShowMsgBox(App.API.GetTranslation("newActionKeywordsHasBeenAssigned"));
+ App.API.ShowMsgBox(Localize.newActionKeywordsHasBeenAssigned());
return;
}
@@ -63,7 +63,7 @@ namespace Flow.Launcher
if (sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords))
{
// User just changes the sequence of action keywords
- App.API.ShowMsgBox(App.API.GetTranslation("newActionKeywordsSameAsOld"));
+ App.API.ShowMsgBox(Localize.newActionKeywordsSameAsOld());
}
else
{
diff --git a/Flow.Launcher/App.xaml b/Flow.Launcher/App.xaml
index 565bbe3c7..e922cd558 100644
--- a/Flow.Launcher/App.xaml
+++ b/Flow.Launcher/App.xaml
@@ -2,7 +2,8 @@
x:Class="Flow.Launcher.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:sys="clr-namespace:System;assembly=mscorlib"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
ShutdownMode="OnMainWindowClose"
Startup="OnStartup">
@@ -10,17 +11,17 @@
-
+
-
+
-
+
@@ -33,6 +34,15 @@
+
+
+ 2
+ 0
+ 0
+ 40
+ 0
+ 36
+
\ No newline at end of file
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index 8ec11e5ff..b45bbc549 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -22,6 +22,7 @@ using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.SettingPages.ViewModels;
using Flow.Launcher.ViewModel;
+using iNKORE.UI.WPF.Modern.Common;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.VisualStudio.Threading;
@@ -56,6 +57,9 @@ namespace Flow.Launcher
public App()
{
+ // Do not use bitmap cache since it can cause WPF second window freezing issue
+ ShadowAssist.UseBitmapCache = false;
+
// Initialize settings
_settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled();
@@ -183,12 +187,14 @@ namespace Flow.Launcher
// So set to OnExplicitShutdown to prevent the application from shutting down before main window is created
Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;
+ // Setup log level before any logging is done
Log.SetLogLevel(_settings.LogLevel);
// Update dynamic resources base on settings
Current.Resources["SettingWindowFont"] = new FontFamily(_settings.SettingWindowFont);
Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(_settings.SettingWindowFont);
+ // Initialize notification system before any notification api is called
Notification.Install();
// Enable Win32 dark mode if the system is in dark mode before creating all windows
@@ -197,6 +203,7 @@ namespace Flow.Launcher
// Initialize language before portable clean up since it needs translations
await _internationalization.InitializeLanguageAsync();
+ // Clean up after portability update
Ioc.Default.GetRequiredService().PreStartCleanUpAfterPortabilityUpdate();
API.LogInfo(ClassName, "Begin Flow Launcher startup ----------------------------------------------------");
@@ -206,32 +213,25 @@ namespace Flow.Launcher
RegisterDispatcherUnhandledException();
RegisterTaskSchedulerUnhandledException();
- var imageLoadertask = ImageLoader.InitializeAsync();
-
- AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings);
-
- PluginManager.LoadPlugins(_settings.PluginSettings);
-
- // Register ResultsUpdated event after all plugins are loaded
- Ioc.Default.GetRequiredService().RegisterResultsUpdatedEvent();
+ var imageLoaderTask = ImageLoader.InitializeAsync();
Http.Proxy = _settings.Proxy;
// Initialize plugin manifest before initializing plugins so that they can use the manifest instantly
await API.UpdatePluginManifestAsync();
- await PluginManager.InitializePluginsAsync();
-
- // Update plugin titles after plugins are initialized with their api instances
- Internationalization.UpdatePluginMetadataTranslations();
-
- await imageLoadertask;
+ await imageLoaderTask;
_mainWindow = new MainWindow();
Current.MainWindow = _mainWindow;
Current.MainWindow.Title = Constant.FlowLauncher;
+ // Initialize Dialog Jump before hotkey mapper since hotkey mapper will register its hotkey
+ // Initialize Dialog Jump after main window is created so that it can access main window handle
+ DialogJump.InitializeDialogJump();
+ DialogJump.SetupDialogJump(_settings.EnableDialogJump);
+
// Initialize hotkey mapper instantly after main window is created because
// it will steal focus from main window which causes window hide
HotKeyMapper.Initialize();
@@ -239,19 +239,40 @@ namespace Flow.Launcher
// Initialize theme for main window
Ioc.Default.GetRequiredService().ChangeTheme();
- DialogJump.InitializeDialogJump(PluginManager.GetDialogJumpExplorers(), PluginManager.GetDialogJumpDialogs());
- DialogJump.SetupDialogJump(_settings.EnableDialogJump);
-
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
RegisterExitEvents();
AutoStartup();
AutoUpdates();
- AutoPluginUpdates();
API.SaveAppAllSettings();
- API.LogInfo(ClassName, "End Flow Launcher startup ----------------------------------------------------");
+ API.LogInfo(ClassName, "End Flow Launcher startup ------------------------------------------------------");
+
+ _ = API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
+ {
+ API.LogInfo(ClassName, "Begin plugin initialization ----------------------------------------------------");
+
+ AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings);
+
+ PluginManager.LoadPlugins(_settings.PluginSettings);
+
+ await PluginManager.InitializePluginsAsync(_mainVM);
+
+ // 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))
+ {
+ _mainVM.QueryResults();
+ }
+
+ AutoPluginUpdates();
+
+ // Save all settings since we possibly update the plugin environment paths
+ API.SaveAppAllSettings();
+
+ API.LogInfo(ClassName, "End plugin initialization ------------------------------------------------------");
+ });
});
}
@@ -276,7 +297,7 @@ namespace Flow.Launcher
// but if it fails (permissions, etc) then don't keep retrying
// this also gives the user a visual indication in the Settings widget
_settings.StartFlowLauncherOnSystemStartup = false;
- API.ShowMsgError(API.GetTranslation("setAutoStartFailed"), e.Message);
+ API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
}
}
}
diff --git a/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs b/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs
index 41e879913..82da6d936 100644
--- a/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs
+++ b/Flow.Launcher/Converters/BoolToIMEConversionModeConverter.cs
@@ -5,7 +5,7 @@ using System.Windows.Input;
namespace Flow.Launcher.Converters;
-internal class BoolToIMEConversionModeConverter : IValueConverter
+public class BoolToIMEConversionModeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
@@ -22,7 +22,7 @@ internal class BoolToIMEConversionModeConverter : IValueConverter
}
}
-internal class BoolToIMEStateConverter : IValueConverter
+public class BoolToIMEStateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
diff --git a/Flow.Launcher/Converters/CornerRadiusFilterConverter.cs b/Flow.Launcher/Converters/CornerRadiusFilterConverter.cs
new file mode 100644
index 000000000..fd43cafac
--- /dev/null
+++ b/Flow.Launcher/Converters/CornerRadiusFilterConverter.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Flow.Launcher.Converters;
+
+public class CornerRadiusFilterConverter : DependencyObject, IValueConverter
+{
+ public CornerRadiusFilterKind Filter { get; set; }
+
+ public double Scale { get; set; } = 1.0;
+
+ public static CornerRadius Convert(CornerRadius radius, CornerRadiusFilterKind filterKind)
+ {
+ CornerRadius result = radius;
+
+ switch (filterKind)
+ {
+ case CornerRadiusFilterKind.Top:
+ result.BottomLeft = 0;
+ result.BottomRight = 0;
+ break;
+ case CornerRadiusFilterKind.Right:
+ result.TopLeft = 0;
+ result.BottomLeft = 0;
+ break;
+ case CornerRadiusFilterKind.Bottom:
+ result.TopLeft = 0;
+ result.TopRight = 0;
+ break;
+ case CornerRadiusFilterKind.Left:
+ result.TopRight = 0;
+ result.BottomRight = 0;
+ break;
+ }
+
+ return result;
+ }
+
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ var cornerRadius = (CornerRadius)value;
+
+ var scale = Scale;
+ if (!double.IsNaN(scale))
+ {
+ cornerRadius.TopLeft *= scale;
+ cornerRadius.TopRight *= scale;
+ cornerRadius.BottomRight *= scale;
+ cornerRadius.BottomLeft *= scale;
+ }
+
+ var filterType = Filter;
+ if (filterType == CornerRadiusFilterKind.TopLeftValue ||
+ filterType == CornerRadiusFilterKind.BottomRightValue)
+ {
+ return GetDoubleValue(cornerRadius, filterType);
+ }
+
+ return Convert(cornerRadius, filterType);
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+
+ private static double GetDoubleValue(CornerRadius radius, CornerRadiusFilterKind filterKind)
+ {
+ switch (filterKind)
+ {
+ case CornerRadiusFilterKind.TopLeftValue:
+ return radius.TopLeft;
+ case CornerRadiusFilterKind.BottomRightValue:
+ return radius.BottomRight;
+ }
+ return 0;
+ }
+}
+
+public enum CornerRadiusFilterKind
+{
+ None,
+ Top,
+ Right,
+ Bottom,
+ Left,
+ TopLeftValue,
+ BottomRightValue
+}
diff --git a/Flow.Launcher/Converters/PlacementRectangleConverter.cs b/Flow.Launcher/Converters/PlacementRectangleConverter.cs
new file mode 100644
index 000000000..130d04e16
--- /dev/null
+++ b/Flow.Launcher/Converters/PlacementRectangleConverter.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Flow.Launcher.Converters;
+
+public class PlacementRectangleConverter : IMultiValueConverter
+{
+ public Thickness Margin { get; set; }
+
+ public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+ {
+ if (values.Length == 2 &&
+ values[0] is double width &&
+ values[1] is double height)
+ {
+ var margin = Margin;
+ var topLeft = new Point(margin.Left, margin.Top);
+ var bottomRight = new Point(width - margin.Right, height - margin.Bottom);
+ var rect = new Rect(topLeft, bottomRight);
+ return rect;
+ }
+
+ return Rect.Empty;
+ }
+
+ public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/Flow.Launcher/Converters/SharedSizeGroupConverter.cs b/Flow.Launcher/Converters/SharedSizeGroupConverter.cs
new file mode 100644
index 000000000..594787027
--- /dev/null
+++ b/Flow.Launcher/Converters/SharedSizeGroupConverter.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace Flow.Launcher.Converters;
+
+public class SharedSizeGroupConverter : IValueConverter
+{
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return (Visibility)value != Visibility.Collapsed ? (string)parameter : null;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
diff --git a/Flow.Launcher/Converters/StringToKeyBindingConverter.cs b/Flow.Launcher/Converters/StringToKeyBindingConverter.cs
index 21bf584e7..b7bca41c5 100644
--- a/Flow.Launcher/Converters/StringToKeyBindingConverter.cs
+++ b/Flow.Launcher/Converters/StringToKeyBindingConverter.cs
@@ -5,7 +5,7 @@ using System.Windows.Input;
namespace Flow.Launcher.Converters;
-class StringToKeyBindingConverter : IValueConverter
+public class StringToKeyBindingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
diff --git a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs
index 2ee08bf85..3bba2c5b8 100644
--- a/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs
+++ b/Flow.Launcher/CustomQueryHotkeySetting.xaml.cs
@@ -41,7 +41,7 @@ namespace Flow.Launcher
if (string.IsNullOrEmpty(Hotkey) && string.IsNullOrEmpty(ActionKeyword))
{
- App.API.ShowMsgBox(App.API.GetTranslation("emptyPluginHotkey"));
+ App.API.ShowMsgBox(Localize.emptyPluginHotkey());
return;
}
diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs
index f4644a267..317d059a1 100644
--- a/Flow.Launcher/CustomShortcutSetting.xaml.cs
+++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs
@@ -40,14 +40,14 @@ namespace Flow.Launcher
{
if (string.IsNullOrEmpty(Key) || string.IsNullOrEmpty(Value))
{
- App.API.ShowMsgBox(App.API.GetTranslation("emptyShortcut"));
+ App.API.ShowMsgBox(Localize.emptyShortcut());
return;
}
// Check if key is modified or adding a new one
if (((update && originalKey != Key) || !update) && _hotkeyVm.DoesShortcutExist(Key))
{
- App.API.ShowMsgBox(App.API.GetTranslation("duplicateShortcut"));
+ App.API.ShowMsgBox(Localize.duplicateShortcut());
return;
}
diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj
index a99d4d8c2..8c7670426 100644
--- a/Flow.Launcher/Flow.Launcher.csproj
+++ b/Flow.Launcher/Flow.Launcher.csproj
@@ -37,14 +37,53 @@
prompt4false
+ $(NoWarn);FLSG0007
-
+
-
+
@@ -94,10 +133,12 @@
+ allruntime; build; native; contentfiles; analyzers; buildtransitive
+
@@ -106,9 +147,6 @@
-
-
- all
@@ -123,6 +161,10 @@
+
+ true
+
+
Always
diff --git a/Flow.Launcher/Helper/AutoStartup.cs b/Flow.Launcher/Helper/AutoStartup.cs
index 34700c610..1f057f839 100644
--- a/Flow.Launcher/Helper/AutoStartup.cs
+++ b/Flow.Launcher/Helper/AutoStartup.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using Flow.Launcher.Infrastructure;
@@ -64,7 +65,9 @@ public class AutoStartup
if (task.Definition.Actions.FirstOrDefault() is Microsoft.Win32.TaskScheduler.Action taskAction)
{
var action = taskAction.ToString().Trim();
- if (!action.Equals(Constant.ExecutablePath, StringComparison.OrdinalIgnoreCase))
+ var needsRecreation = !action.Equals(Constant.ExecutablePath, StringComparison.OrdinalIgnoreCase)
+ || task.Definition.Settings.Priority != ProcessPriorityClass.Normal;
+ if (needsRecreation)
{
UnscheduleLogonTask();
ScheduleLogonTask();
@@ -184,6 +187,7 @@ public class AutoStartup
td.Settings.StopIfGoingOnBatteries = false;
td.Settings.DisallowStartIfOnBatteries = false;
td.Settings.ExecutionTimeLimit = TimeSpan.Zero;
+ td.Settings.Priority = ProcessPriorityClass.Normal;
try
{
diff --git a/Flow.Launcher/Helper/BorderHelper.cs b/Flow.Launcher/Helper/BorderHelper.cs
new file mode 100644
index 000000000..0f2a78e7d
--- /dev/null
+++ b/Flow.Launcher/Helper/BorderHelper.cs
@@ -0,0 +1,33 @@
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Flow.Launcher.Helper;
+
+public static class BorderHelper
+{
+ #region Child
+
+ public static readonly DependencyProperty ChildProperty =
+ DependencyProperty.RegisterAttached(
+ "Child",
+ typeof(UIElement),
+ typeof(BorderHelper),
+ new PropertyMetadata(default(UIElement), OnChildChanged));
+
+ public static UIElement GetChild(Border border)
+ {
+ return (UIElement)border.GetValue(ChildProperty);
+ }
+
+ public static void SetChild(Border border, UIElement value)
+ {
+ border.SetValue(ChildProperty, value);
+ }
+
+ private static void OnChildChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ ((Border)d).Child = (UIElement)e.NewValue;
+ }
+
+ #endregion
+}
diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs
index 86a68475e..0a2826484 100644
--- a/Flow.Launcher/Helper/HotKeyMapper.cs
+++ b/Flow.Launcher/Helper/HotKeyMapper.cs
@@ -61,8 +61,8 @@ internal static class HotKeyMapper
string.Format("|HotkeyMapper.SetWithChefKeys|Error registering hotkey: {0} \nStackTrace:{1}",
e.Message,
e.StackTrace));
- string errorMsg = string.Format(App.API.GetTranslation("registerHotkeyFailed"), hotkeyStr);
- string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
+ string errorMsg = Localize.registerHotkeyFailed(hotkeyStr);
+ string errorMsgTitle = Localize.MessageBoxTitle();
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
}
}
@@ -87,8 +87,8 @@ internal static class HotKeyMapper
e.Message,
e.StackTrace,
hotkeyStr));
- string errorMsg = string.Format(App.API.GetTranslation("registerHotkeyFailed"), hotkeyStr);
- string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
+ string errorMsg = Localize.registerHotkeyFailed(hotkeyStr);
+ string errorMsgTitle = Localize.MessageBoxTitle();
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
}
}
@@ -112,8 +112,8 @@ internal static class HotKeyMapper
string.Format("|HotkeyMapper.RemoveHotkey|Error removing hotkey: {0} \nStackTrace:{1}",
e.Message,
e.StackTrace));
- string errorMsg = string.Format(App.API.GetTranslation("unregisterHotkeyFailed"), hotkeyStr);
- string errorMsgTitle = App.API.GetTranslation("MessageBoxTitle");
+ string errorMsg = Localize.unregisterHotkeyFailed(hotkeyStr);
+ string errorMsgTitle = Localize.MessageBoxTitle();
App.API.ShowMsgBox(errorMsg, errorMsgTitle);
}
}
@@ -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/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs
index 89bfde349..b920b53a7 100644
--- a/Flow.Launcher/HotkeyControl.xaml.cs
+++ b/Flow.Launcher/HotkeyControl.xaml.cs
@@ -1,4 +1,4 @@
-using System.Collections.ObjectModel;
+using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
@@ -234,7 +234,7 @@ namespace Flow.Launcher
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
- public string EmptyHotkey => App.API.GetTranslation("none");
+ public string EmptyHotkey => Localize.none();
public ObservableCollection KeysToDisplay { get; set; } = new();
diff --git a/Flow.Launcher/HotkeyControlDialog.xaml b/Flow.Launcher/HotkeyControlDialog.xaml
index d416f1bdc..9fdfda865 100644
--- a/Flow.Launcher/HotkeyControlDialog.xaml
+++ b/Flow.Launcher/HotkeyControlDialog.xaml
@@ -2,7 +2,7 @@
x:Class="Flow.Launcher.HotkeyControlDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Background="{DynamicResource PopuBGColor}"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="0 1 0 0"
diff --git a/Flow.Launcher/HotkeyControlDialog.xaml.cs b/Flow.Launcher/HotkeyControlDialog.xaml.cs
index c7af8c5b8..e1fc86f95 100644
--- a/Flow.Launcher/HotkeyControlDialog.xaml.cs
+++ b/Flow.Launcher/HotkeyControlDialog.xaml.cs
@@ -9,7 +9,7 @@ using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
-using ModernWpf.Controls;
+using iNKORE.UI.WPF.Modern.Controls;
namespace Flow.Launcher;
@@ -33,7 +33,7 @@ public partial class HotkeyControlDialog : ContentDialog
public EResultType ResultType { get; private set; } = EResultType.Cancel;
public string ResultValue { get; private set; } = string.Empty;
- public static string EmptyHotkey => App.API.GetTranslation("none");
+ public static string EmptyHotkey => Localize.none();
private static bool isOpenFlowHotkey;
@@ -41,7 +41,7 @@ public partial class HotkeyControlDialog : ContentDialog
{
WindowTitle = windowTitle switch
{
- "" or null => App.API.GetTranslation("hotkeyRegTitle"),
+ "" or null => Localize.hotkeyRegTitle(),
_ => windowTitle
};
DefaultHotkey = defaultHotkey;
@@ -146,10 +146,7 @@ public partial class HotkeyControlDialog : ContentDialog
Alert.Visibility = Visibility.Visible;
if (registeredHotkeyData.RemoveHotkey is not null)
{
- tbMsg.Text = string.Format(
- App.API.GetTranslation("hotkeyUnavailableEditable"),
- description
- );
+ tbMsg.Text = Localize.hotkeyUnavailableEditable(description);
SaveBtn.IsEnabled = false;
SaveBtn.Visibility = Visibility.Collapsed;
OverwriteBtn.IsEnabled = true;
@@ -158,10 +155,7 @@ public partial class HotkeyControlDialog : ContentDialog
}
else
{
- tbMsg.Text = string.Format(
- App.API.GetTranslation("hotkeyUnavailableUneditable"),
- description
- );
+ tbMsg.Text = Localize.hotkeyUnavailableUneditable(description);
SaveBtn.IsEnabled = false;
SaveBtn.Visibility = Visibility.Visible;
OverwriteBtn.IsEnabled = false;
@@ -175,7 +169,7 @@ public partial class HotkeyControlDialog : ContentDialog
if (!CheckHotkeyAvailability(hotkey.Value, true))
{
- tbMsg.Text = App.API.GetTranslation("hotkeyUnavailable");
+ tbMsg.Text = Localize.hotkeyUnavailable();
Alert.Visibility = Visibility.Visible;
SaveBtn.IsEnabled = false;
SaveBtn.Visibility = Visibility.Visible;
diff --git a/Flow.Launcher/Languages/ar.xaml b/Flow.Launcher/Languages/ar.xaml
index 67f1f766e..b1c9ca426 100644
--- a/Flow.Launcher/Languages/ar.xaml
+++ b/Flow.Launcher/Languages/ar.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Schedulerخطأ في إعداد التشغيل عند بدء التشغيلإخفاء Flow Launcher عند فقدان التركيز
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.عدم عرض إشعارات الإصدار الجديدSearch Window Locationتذكر آخر موقع
diff --git a/Flow.Launcher/Languages/cs.xaml b/Flow.Launcher/Languages/cs.xaml
index 96cbe95e7..b55026e28 100644
--- a/Flow.Launcher/Languages/cs.xaml
+++ b/Flow.Launcher/Languages/cs.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerPři nastavování spouštění došlo k chyběSkrýt Flow Launcher při vykliknutí
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Nezobrazovat oznámení o nové verziSearch Window LocationZapamatovat poslední pozici
diff --git a/Flow.Launcher/Languages/da.xaml b/Flow.Launcher/Languages/da.xaml
index a1fc771d2..7d4094c84 100644
--- a/Flow.Launcher/Languages/da.xaml
+++ b/Flow.Launcher/Languages/da.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerError setting launch on startupSkjul Flow Launcher ved mistet fokus
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Vis ikke notifikationer om nye versionerSearch Window LocationRemember Last Position
diff --git a/Flow.Launcher/Languages/de.xaml b/Flow.Launcher/Languages/de.xaml
index 2c083646f..32f8d5d2b 100644
--- a/Flow.Launcher/Languages/de.xaml
+++ b/Flow.Launcher/Languages/de.xaml
@@ -79,6 +79,8 @@
Nach der Deinstallation müssen Sie diese Aufgabe (Flow.Launcher Startup) via Task-Scheduler manuell entfernenFehler bei Einstellungsstart beim StartFlow Launcher ausblenden, wenn Fokus verloren geht
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Versionsbenachrichtigungen nicht zeigenOrt des SuchfenstersLetzte Position merken
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index 22d93f1bd..451a21ad7 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -66,6 +66,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
@@ -77,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
@@ -209,6 +215,8 @@
VersionWebsiteUninstall
+ Search delay time: default
+ Search delay time: {0}msFail to remove plugin settingsPlugins: {0} - Fail to remove plugin settings files, please remove them manuallyFail to remove plugin cache
@@ -219,6 +227,7 @@
Fail to uninstall {0}Unable to find plugin.json from the extracted zip file, or this path {0} does not existA plugin with the same ID and version already exists, or the version is greater than this downloaded plugin
+ Error creating setting panel for plugin {0}:{1}{2}Plugin Store
@@ -462,8 +471,10 @@
Open FolderAdvancedLog Level
- Debug
+ Silent
+ ErrorInfo
+ DebugSetting Window Font
@@ -585,7 +596,7 @@
The specified file manager could not be found. Please check the Custom File Manager setting under Settings > General.
Error
- An error occurred while opening the folder. {0}
+ An error occurred while opening the folder.An error occurred while opening the URL in the browser. Please check your Default Web Browser configuration in the General section of the settings windowFile or directory not found: {0}
diff --git a/Flow.Launcher/Languages/es-419.xaml b/Flow.Launcher/Languages/es-419.xaml
index 9f06c4436..40e8cb978 100644
--- a/Flow.Launcher/Languages/es-419.xaml
+++ b/Flow.Launcher/Languages/es-419.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerError setting launch on startupOcultar Flow Launcher cuando se pierde el enfoque
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.No mostrar notificaciones de nuevas versionesSearch Window LocationRemember Last Position
diff --git a/Flow.Launcher/Languages/es.xaml b/Flow.Launcher/Languages/es.xaml
index f7a3fbb22..049b33858 100644
--- a/Flow.Launcher/Languages/es.xaml
+++ b/Flow.Launcher/Languages/es.xaml
@@ -79,6 +79,8 @@
Después de la desinstalación, es necesario eliminar manualmente la tarea (Flow.Launcher Startup) mediante el Programador de TareasError de configuración de arranque al iniciarOcultar Flow Launcher cuando se pierde el foco
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.No mostrar notificaciones de nuevas versionesUbicación de la ventana de búsquedaRecordar última ubicación
diff --git a/Flow.Launcher/Languages/fr.xaml b/Flow.Launcher/Languages/fr.xaml
index bdce6ddb9..d60d53a1c 100644
--- a/Flow.Launcher/Languages/fr.xaml
+++ b/Flow.Launcher/Languages/fr.xaml
@@ -79,6 +79,8 @@
Après une désinstallation, vous devez supprimer manuellement cette tâche (Flow.Launcher Startup) via le planificateur de tâchesErreur lors de la configuration du lancement au démarrageCacher Flow Launcher lors de la perte de focus
+ Afficher la barre des tâches lorsque Flow Launcher est ouvert
+ Afficher temporairement la barre des tâches lorsque Flow Launcher est ouvert, utile pour les barres de tâches auto-masquées.Ne pas afficher le message de mise à jour pour les nouvelles versionsEmplacement de la fenêtre de rechercheSe souvenir de la dernière position
diff --git a/Flow.Launcher/Languages/he.xaml b/Flow.Launcher/Languages/he.xaml
index 39f02c702..926d94886 100644
--- a/Flow.Launcher/Languages/he.xaml
+++ b/Flow.Launcher/Languages/he.xaml
@@ -8,9 +8,9 @@
אנא בחר את קובץ ההפעלה {0}
- Your selected {0} executable is invalid.
+ קובץ ההפעלה {0} שבחרת אינו חוקי.
{2}{2}
- Click yes if you would like select the {0} executable again. Click no if you would like to download {1}
+ לחץ על כן אם ברצונך, בחר את {0} ההפעלה הקודמת. לחץ על לא אם ברצונך להוריד את {1}
לא ניתן להגדיר נתיב הפעלה {0}, אנא נסה שוב בהגדרות Flow (גלול עד למטה).נכשל בהפעלת תוספים
@@ -79,6 +79,8 @@
לאחר הסרת ההתקנה, עליך להסיר ידנית משימה זו (Flow.Launcher Startup) דרך מתזמן המשימותשגיאה בהגדרת ההפעלה בעת הפעלת windowsהסתר את Flow Launcher כאשר הוא אינו החלון הפעיל
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.אל תציג התראות על גרסה חדשהמיקום חלון חיפושזכור את המיקום האחרון
diff --git a/Flow.Launcher/Languages/it.xaml b/Flow.Launcher/Languages/it.xaml
index ffb716658..92afa5436 100644
--- a/Flow.Launcher/Languages/it.xaml
+++ b/Flow.Launcher/Languages/it.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerErrore nell'impostazione del lancio all'avvioNascondi Flow Launcher quando perde il focus
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Non mostrare le notifiche per una nuova versioneSearch Window LocationRicorda L'Ultima Posizione
@@ -147,8 +149,8 @@
Search DelayAdds a short delay while typing to reduce UI flicker and result load. Recommended if your typing speed is average.Enter the wait time (in ms) until input is considered complete. This can only be edited if Search Delay is enabled.
- Default Search Delay Time
- Wait time before showing results after typing stops. Higher values wait longer. (ms)
+ Tempo predefinito ritardo ricerca
+ Tempo di attesa prima di mostrare i risultati dopo l'interruzione della digitazione. Valori più alti attendono più a lungo. (ms)Information for Korean IME user
The Korean input method used in Windows 11 may cause some issues in Flow Launcher.
@@ -265,11 +267,11 @@
Plugin update{0} di {1} {2}{2}Vuoi aggiornare questo plugin?Download del plugin
- Automatically restart after installing/uninstalling/updating plugins in plugin store
- Zip file does not have a valid plugin.json configuration
+ Riavvia automaticamente dopo l'installazione/disinstallazione/aggiornamento dei plugin nel Plugin Store
+ Il file zip non contiene una configurazione plugin.json validaInstallazione da una fonte sconosciutaThis plugin is from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning in general section of setting window)
- Zip files
+ File zipPlease select zip fileInstall plugin from local pathNessun aggiornamento disponibile
@@ -469,7 +471,7 @@
Cancella i logSei sicuro di voler cancellare tutti i log?Cache Folder
- Clear Caches
+ Cancella cacheAre you sure you want to delete all caches?Failed to clear part of folders and files. Please see log file for more informationWizard
@@ -636,7 +638,7 @@ Se si aggiunge un prefisso '@' mentre si inserisce una scorciatoia, corrisponde
Restart Flow Launcher after updating plugins{0}: Update from v{1} to v{2}
- No plugin selected
+ Nessun plugin selezionatoSalta
diff --git a/Flow.Launcher/Languages/ja.xaml b/Flow.Launcher/Languages/ja.xaml
index 51ec99ddd..39b23f269 100644
--- a/Flow.Launcher/Languages/ja.xaml
+++ b/Flow.Launcher/Languages/ja.xaml
@@ -64,10 +64,10 @@
位置のリセット検索ウィンドウの位置をリセットここに入力して検索
- {0}: This plugin is still initializing...
- Select this result to requery
- {0}: Failed to respond!
- Select this result for more info
+ {0}: このプラグインはまだ初期化中です…
+ この結果を選択して再検索する
+ {0}: 応答に失敗しました!
+ 詳細については、この結果を選択してください設定
@@ -79,6 +79,8 @@
アンインストール後は、「タスク スケジューラ」からこのタスク(Flow.Launcher Startup)を手動で削除する必要があります。スタートアップ時に起動の設定失敗フォーカスを失った時にFlow Launcherを隠す
+ Flow Launcher を開いたときにタスクバーを表示する
+ Flow Launcher を開いたときに一時的にタスクバーを表示します。タスクバーの自動非表示を設定している場合に便利です。最新版が入手可能であっても、アップグレードメッセージを表示しない検索ウィンドウの位置最後の表示位置を記憶する
@@ -169,7 +171,7 @@
開く前の韓国語IMEを使用You can change the Previous Korean IME settings directly from here
- Failed to change Korean IME setting
+ 韓国語IME設定の変更に失敗しましたシステムのレジストリへのアクセスが可能か確認するか、サポートにお問い合わせください。ホームページ検索文字列が空の場合、ホームページの結果を表示します。
@@ -454,7 +456,7 @@
アイコンあなたはFlow Launcherを {0} 回利用しましたアップデートを確認する
- Become a Sponsor
+ スポンサーになる新しいバージョン {0} が利用可能です。Flow Launcherを再起動してください。アップデートの確認に失敗しました、api.github.com への接続とプロキシ設定を確認してください。
diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml
index 503ff2f11..22f3bb011 100644
--- a/Flow.Launcher/Languages/ko.xaml
+++ b/Flow.Launcher/Languages/ko.xaml
@@ -79,6 +79,8 @@
Flow Launcher를 제거한 후에는 작업 스케줄러에서 이 작업(Flow.Launcher Startup)을 수동으로 삭제해야 합니다Error setting launch on startup포커스 잃으면 Flow Launcher 숨김
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.새 버전 알림 끄기검색 창 위치마지막 위치 기억
diff --git a/Flow.Launcher/Languages/nb.xaml b/Flow.Launcher/Languages/nb.xaml
index 8bd7f94a4..1ef057125 100644
--- a/Flow.Launcher/Languages/nb.xaml
+++ b/Flow.Launcher/Languages/nb.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerFeil ved å sette kjør ved oppstartSkjul Flow Launcher når fokus forsvinner
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Ikke vis varsler om nye versjonerSearch Window LocationHusk siste posisjon
diff --git a/Flow.Launcher/Languages/nl.xaml b/Flow.Launcher/Languages/nl.xaml
index 8b7b86329..412781b55 100644
--- a/Flow.Launcher/Languages/nl.xaml
+++ b/Flow.Launcher/Languages/nl.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerFout bij het instellen van uitvoeren bij opstartenVerberg Flow Launcher als focus verloren is
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Laat geen nieuwe versie notificaties zienSearch Window LocationLaatste Positie Onthouden
diff --git a/Flow.Launcher/Languages/pl.xaml b/Flow.Launcher/Languages/pl.xaml
index 382626eb7..efc2ade55 100644
--- a/Flow.Launcher/Languages/pl.xaml
+++ b/Flow.Launcher/Languages/pl.xaml
@@ -79,6 +79,8 @@ Kliknij "nie", jeśli jest już zainstalowany. Zostaniesz wtedy popros
Po odinstalowaniu musisz ręcznie usunąć to zadanie (Flow.Launcher Startup) za pomocą Harmonogramu zadańBłąd uruchamiania ustawień przy starcieUkryj okno Flow Launcher kiedy przestanie ono być aktywne
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Nie pokazuj powiadomienia o nowej wersjiPozycja okna wyszukiwaniaZapamiętaj Ostatnią Pozycję
diff --git a/Flow.Launcher/Languages/pt-br.xaml b/Flow.Launcher/Languages/pt-br.xaml
index 15dcae2f4..a7cf5ac68 100644
--- a/Flow.Launcher/Languages/pt-br.xaml
+++ b/Flow.Launcher/Languages/pt-br.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerErro ao ativar início com o sistemaEsconder Flow Launcher quando foco for perdido
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Não mostrar notificações de novas versõesSearch Window LocationLembrar Última Posição
diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml
index 3746ada13..a2b58b1a0 100644
--- a/Flow.Launcher/Languages/pt-pt.xaml
+++ b/Flow.Launcher/Languages/pt-pt.xaml
@@ -79,6 +79,8 @@
Se desinstalar a aplicação, tem que remover manualmente a tarefa (Flow.Launcher Startup) no agendamento de tarefasErro ao definir para iniciar ao arrancarOcultar Flow Launcher ao perder o foco
+ Mostrar barra de tarefas ao abrir Flow Launcher
+ Mostrar, temporariamente, a barra de tarefas ao abrir Flow launcher. Útil para barra de tarefas oculta automaticamente.Não notificar acerca de novas versõesPosição da janela de pesquisaMemorizar última posição
@@ -420,13 +422,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
diff --git a/Flow.Launcher/Languages/ru.xaml b/Flow.Launcher/Languages/ru.xaml
index 7bb5a8ff1..544816684 100644
--- a/Flow.Launcher/Languages/ru.xaml
+++ b/Flow.Launcher/Languages/ru.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerОшибка настройки запуска при запускеСкрывать Flow Launcher, если потерян фокуc
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Не отображать сообщение об обновлении, когда доступна новая версияSearch Window LocationЗапомнить последнее положение
diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml
index e76061a3b..c47b47ae1 100644
--- a/Flow.Launcher/Languages/sk.xaml
+++ b/Flow.Launcher/Languages/sk.xaml
@@ -80,6 +80,8 @@ Nevykonali sa žiadne zmeny.Po odinštalovaní musíte úlohu manuálne odstrániť (Flow.Launcher Startup) cez Plánovač úlohChybné nastavenie spustenia pri spusteníSchovať Flow Launcher po strate fokusu
+ Zobraziť panel úloh, keď je Flow Launcher otvorený
+ Dočasne zobraziť panel úloh pri otvorení Flow Launchera, užitočné pri automatickom skrývaní panela úloh.Nezobrazovať upozornenia na novú verziuPoloha vyhľadávacieho oknaZapamätať si poslednú pozíciu
@@ -636,7 +638,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 d7d60e6a0..824b48dbf 100644
--- a/Flow.Launcher/Languages/sr-Cyrl-RS.xaml
+++ b/Flow.Launcher/Languages/sr-Cyrl-RS.xaml
@@ -79,6 +79,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/sr.xaml b/Flow.Launcher/Languages/sr.xaml
index 7d1bcb9f3..3ee982819 100644
--- a/Flow.Launcher/Languages/sr.xaml
+++ b/Flow.Launcher/Languages/sr.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerError setting launch on startupSakri Flow Launcher kada se izgubi fokus
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Ne prikazuj obaveštenje o novoj verzijiSearch Window LocationRemember Last Position
diff --git a/Flow.Launcher/Languages/tr.xaml b/Flow.Launcher/Languages/tr.xaml
index 67cdf9da4..023eb2aa6 100644
--- a/Flow.Launcher/Languages/tr.xaml
+++ b/Flow.Launcher/Languages/tr.xaml
@@ -79,6 +79,8 @@
Kaldırma işleminden sonra, bu görevi (Flow.Launcher Startup) Görev Zamanlayıcı üzerinden elle kaldırmanız gerekmektedirSistemle başlatma ayarı başarısız olduOdak Pencereden Ayrıldığında Gizle
+ Flow Launcher açıldığında görev çubuğunu göster
+ Flow Launcher açıldığında geçici olarak görev çubuğunu gösterir, otomatik gizlenen görev çubukları için kullanışlıdır.Güncelleme bildirimlerini göstermePencere KonumuSon Konumu Hatırla
@@ -454,7 +456,7 @@
Kullanılan SimgelerŞu ana kadar Flow Launcher'ı {0} kez aktifleştirdiniz.Güncellemeleri Kontrol Et
- Become a Sponsor
+ Sponsor OlunUygulamanı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 bec1f85e3..0da6c7a47 100644
--- a/Flow.Launcher/Languages/uk-UA.xaml
+++ b/Flow.Launcher/Languages/uk-UA.xaml
@@ -79,6 +79,8 @@
Після видалення, вам необхідно вручну видалити це завдання (Flow.Launcher Startup) через планувальник завданьПомилка запуску налаштування під час запускуСховати Flow Launcher, якщо втрачено фокус
+ Показувати панель завдань, коли Flow Launcher відкрито
+ Тимчасово показувати панель завдань при відкритті Flow Launcher, корисно для автоматично прихованих панелей завдань.Не повідомляти про доступні нові версіїРозташування вікна пошукуПам'ятати останню позицію
diff --git a/Flow.Launcher/Languages/vi.xaml b/Flow.Launcher/Languages/vi.xaml
index 5809c7837..463c11d0b 100644
--- a/Flow.Launcher/Languages/vi.xaml
+++ b/Flow.Launcher/Languages/vi.xaml
@@ -79,6 +79,8 @@
After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task SchedulerKhông lưu được tính năng tự khởi động khi khởi động hệ thốngẨn Flow Launcher khi mất tiêu điểm
+ Show taskbar when Flow Launcher is opened
+ Temporarily show the taskbar when Flow Launcher is opened, useful for auto-hidden taskbars.Không hiển thị thông báo khi có phiên bản mớiSearch Window LocationGhi nhớ vị trí cuối cùng
diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml
index 7af54dc54..089ba2dd1 100644
--- a/Flow.Launcher/Languages/zh-cn.xaml
+++ b/Flow.Launcher/Languages/zh-cn.xaml
@@ -2,7 +2,7 @@
- Flow 检测到您已安装 {0} 个插件,需要 {1} 才能运行。是否要下载 {1}?
+ Flow 检测到您已安装 {0} 插件,需要 {1} 才能运行。是否要下载 {1}?
{2}{2}
如果已安装,请单击“否”,系统将提示您选择包含 {1} 可执行文件的文件夹
@@ -79,6 +79,8 @@
卸载后,您需要通过任务计划程序手动移除此任务 (Flow.Launcher Startup)设置开机自启时出错失去焦点时自动隐藏 Flow Launcher
+ 打开 Flow 时显示任务栏
+ 打开 Flow 时临时显示任务栏,用于自动隐藏任务栏不显示新版本提示搜索窗口位置记住上次的位置
diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml
index ca7da7624..7aacc2190 100644
--- a/Flow.Launcher/Languages/zh-tw.xaml
+++ b/Flow.Launcher/Languages/zh-tw.xaml
@@ -2,43 +2,43 @@
- Flow detected you have installed {0} plugins, which will require {1} to run. Would you like to download {1}?
+ Flow 檢測到你已安裝 {0} 個插件,需要 {1} 才能運行。是否要下載 {1}?
{2}{2}
- Click no if it's already installed, and you will be prompted to select the folder that contains the {1} executable
+ 如果已安裝,請點擊“否”,系統將提示你選擇包含 {1} 個程式的資料夾
- Please select the {0} executable
+ 請選擇 {0} 可執行檔
- Your selected {0} executable is invalid.
+ 您所選擇的 {0} 可執行檔無效。
{2}{2}
- Click yes if you would like select the {0} executable again. Click no if you would like to download {1}
+ 若要重新選取 {0} 可執行檔,請按「是」。若要下載 {1},請按「否」。
- Unable to set {0} executable path, please try from Flow's settings (scroll down to the bottom).
- Fail to Init Plugins
- Plugins: {0} - fail to load and would be disabled, please contact plugin creator for help
+ 無法設定 {0} 可執行檔路徑,請從 Flow 的設定中嘗試(向下捲動至最底部)。
+ 初始化外掛失敗
+ 外掛:{0} — 載入失敗,將被停用,請聯絡外掛開發者以取得協助
- Flow Launcher needs to restart to finish disabling portable mode, after the restart your portable data profile will be deleted and roaming data profile kept
- Flow Launcher needs to restart to finish enabling portable mode, after the restart your roaming data profile will be deleted and portable data profile kept
- Flow Launcher has detected you enabled portable mode, would you like to move it to a different location?
- Flow Launcher has detected you disabled portable mode, the relevant shortcuts and uninstaller entry have been created
- Flow Launcher detected your user data exists both in {0} and {1}. {2}{2}Please delete {1} in order to proceed. No changes have occurred.
+ Flow Launcher 需要重新啟動以完成停用可攜式模式,重新啟動後您的可攜式資料設定檔將被刪除,漫遊資料設定檔會保留
+ Flow Launcher 需要重新啟動以完成啟用可攜式模式,重新啟動後您的漫遊資料設定檔將被刪除,而可攜式資料設定檔則會保留
+ Flow Launcher 偵測到您已啟用可攜式模式,是否要將它移到其他位置?
+ Flow Launcher 偵測到您已停用可攜模式,相關的捷徑與解除安裝程式項目已建立
+ Flow Launcher 偵測到您的使用者資料同時存在於 {0} 與 {1}。{2}{2}請刪除 {1} 以繼續。尚未發生任何變更。
- The following plugin has errored and cannot be loaded:
- The following plugins have errored and cannot be loaded:
- Please refer to the logs for more information
+ 下列外掛發生錯誤,無法載入:
+ 下列外掛發生錯誤,無法載入:
+ 請參閱日誌以獲得更多資訊
- Please try again
- Unable to parse Http Proxy
+ 請再試一次
+ 無法解析 Http 代理
- Failed to install TypeScript environment. Please try again later
- Failed to install Python environment. Please try again later.
+ 無法安裝 TypeScript 環境。請稍後再試一次
+ 安裝 Python 環境失敗。請稍後再試。
- Failed to register hotkey "{0}". The hotkey may be in use by another program. Change to a different hotkey, or exit another program.
- Failed to unregister hotkey "{0}". Please try again or see log for details
+ 註冊熱鍵「{0}」失敗。此熱鍵可能已被其他程式使用。請更改為不同的熱鍵,或關閉其他程式。
+ 無法取消註冊熱鍵「{0}」。請再試一次或查看日誌以取得詳細資訊Flow Launcher啟動命令 {0} 失敗無效的 Flow Launcher 外掛格式
@@ -54,7 +54,7 @@
複製剪下貼上
- Undo
+ 還原全選檔案資料夾
@@ -62,12 +62,12 @@
遊戲模式暫停使用快捷鍵。重設位置
- Reset search window position
- Type here to search
- {0}: This plugin is still initializing...
- Select this result to requery
- {0}: Failed to respond!
- Select this result for more info
+ 重設搜尋視窗位置
+ 在此輸入以搜尋
+ 「{0}:此外掛程式仍在初始化……」……
+ 選擇此結果以重新查詢
+ 「{0}:未能回應!」!
+ 選取此結果以取得更多資訊設定
@@ -75,22 +75,24 @@
便攜模式將所有設定和使用者資料存儲在一個資料夾中(當與可移動磁碟或雲服務一起使用時很有用)。開機時啟動
- Use logon task instead of startup entry for faster startup experience
- After uninstallation, you need to manually remove this task (Flow.Launcher Startup) via Task Scheduler
- Error setting launch on startup
+ 使用登入工作取代啟動項目,以加快啟動體驗
+ 解除安裝後,您需要透過工作排程程式手動移除此工作(Flow.Launcher Startup)
+ 設定開機啟動時發生錯誤失去焦點時自動隱藏 Flow Launcher
+ 當 Flow Launcher 開啟時顯示工作列
+ 當開啟 Flow Launcher 時暫時顯示工作列,對自動隱藏的工作列很有用。不顯示新版本提示
- Search Window Location
+ 搜尋視窗位置記住最後位置
- Monitor with Mouse Cursor
- Monitor with Focused Window
- Primary Monitor
- Custom Monitor
+ 帶有滑鼠游標的顯示器
+ 以焦點視窗進行監視
+ 主顯示器
+ 自訂搜尋視窗位置搜尋視窗在螢幕上的位置
- Center
- Center Top
- Left Top
- Right Top
+ 置中
+ 頂部置中
+ 左側置中
+ 右側置中自訂搜尋視窗位置語言最後查詢樣式
@@ -98,10 +100,10 @@
保留上一個查詢選擇上一個查詢清空上次搜尋關鍵字
- Preserve Last Action Keyword
- Select Last Action Keyword
+ 保留上次操作的關鍵字
+ 選擇最後操作的關鍵字最大結果顯示個數
- You can also quickly adjust this by using CTRL+Plus and CTRL+Minus.
+ 您也可以使用「CTRL+加號」和「CTRL+減號」快速調整此設定。全螢幕模式下忽略快捷鍵全螢幕模式下停用快捷鍵(推薦用於遊戲時)。預設檔案管理器
@@ -109,28 +111,28 @@
預設瀏覽器設定新增分頁、視窗和無痕模式。Python 位置
- Node.js Path
- Please select the Node.js executable
+ Node.js的路徑
+ 請選擇Node.js的可執行檔請選擇 pythonw.exe一律以英文模式開始輸入啟動 Flow 時暫時將輸入法切換為英文模式。自動更新
- Automatically check and update the app when available
+ 在可用時自動檢查並更新應用程式選擇啟動時不顯示主視窗
- Flow Launcher search window is hidden in the tray after starting up.
+ 啟動後,Flow Launcher搜尋視窗會隱藏在系統匣中。隱藏任務欄圖示當圖示從系統列隱藏時,可以透過在搜尋視窗上按右鍵來開啟設定選單。查詢搜尋精確度更改結果所需的最低匹配分數。
- None
- Low
- Regular
+ 無
+ 低
+ 一般拼音搜尋
- Pinyin is the standard system of romanized spelling for translating Chinese. Please note, enabling this can significantly increase memory usage during search.
- Use Double Pinyin
- Use Double Pinyin instead of Full Pinyin to search.
- Double Pinyin Schema
+ 拼音是中文翻譯的標準羅馬化拼字系統。請注意,啟用此功能可能會顯著增加搜尋時的記憶體使用量。
+ 啟用雙拼模式
+ 請使用雙拼以搜尋,而不是全拼搜尋。
+ 雙拼結構Xiao HeZi Ran MaWei Ruan
@@ -143,12 +145,12 @@
一律預覽當 Flow 啟動時,一律開啟預覽面板。按下 {0} 可切換預覽。
- Shadow effect is not allowed while current theme has blur effect enabled
- Search Delay
- Adds a short delay while typing to reduce UI flicker and result load. Recommended if your typing speed is average.
- Enter the wait time (in ms) until input is considered complete. This can only be edited if Search Delay is enabled.
- Default Search Delay Time
- Wait time before showing results after typing stops. Higher values wait longer. (ms)
+ 當目前主題啟用模糊效果時,將不允許使用陰影效果
+ 延遲搜尋
+ 在輸入時增加短暫延遲,以減少介面閃爍和結果載入時間。建議打字速度中等的使用者使用。
+ 輸入等待時間(以毫秒為單位),直到認為輸入完成為止。僅當啟用“搜尋延遲”時才能編輯此設定。
+ 預設搜尋延遲時間
+ 輸入停止後顯示結果前的等待時間。數值越高,等待時間越長。 (以毫秒為單位)Information for Korean IME user
The Korean input method used in Windows 11 may cause some issues in Flow Launcher.
@@ -164,17 +166,17 @@
- Open Language and Region System Settings
- Opens the Korean IME setting location. Go to Korean > Language Options > Keyboard - Microsoft IME > Compatibility
+ 開啟語言和區域設定
+ 開啟韓語輸入法設定。前往“韓語”>“語言選項”>“鍵盤 - Microsoft 輸入法”>“相容性”。開啟
- Use Previous Korean IME
- You can change the Previous Korean IME settings directly from here
- Failed to change Korean IME setting
- Please check your system registry access or contact support.
- Home Page
- Show home page results when query text is empty.
- Show History Results in Home Page
- Maximum History Results Shown in Home Page
+ 使用舊版韓語輸入法
+ 您可以直接從這裡更改先前的韓語輸入法設定
+ 更改韓語輸入法設定失敗
+ 請檢查您的系統註冊表存取權限或尋求協助。
+ 首頁
+ 當查詢文字為空時,顯示首頁結果。
+ 在首頁顯示歷史記錄
+ 首頁顯示最多歷史搜尋結果History StyleChoose the type of history to show in the History and Home PageQuery history
@@ -209,8 +211,8 @@
Advanced Settings:已啟用優先
- Search Delay
- Home Page
+ 延遲搜尋
+ 首頁目前優先新增優先優先
@@ -263,21 +265,21 @@
Plugin uninstall{0} by {1} {2}{2}Would you like to uninstall this plugin?Plugin update
- {0} by {1} {2}{2}Would you like to update this plugin?
+ 您想更新{0} (由 {1} {2}{2} 製作)嗎?正在下載擴充功能
- Automatically restart after installing/uninstalling/updating plugins in plugin store
- Zip file does not have a valid plugin.json configuration
- Installing from an unknown source
- This plugin is from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning in general section of setting window)
- Zip files
- Please select zip file
- Install plugin from local path
+ 在外掛商店安裝/卸載/更新插件後自動重啟
+ 壓縮檔中沒有有效的plugin.json配置
+ 從未知來源安裝
+ 您正在安裝來自未知來源的插件,它可能有潛在風險!{0}{0} 請確保您了解此插件的來源並確認其安全性。{0}{0} 是否繼續? {0}{0}(您可以在設定中關閉此警告)
+ 壓縮檔
+ 請選擇一個壓縮檔
+ 從本地路徑安裝外掛無可用更新所有插件均為最新版本
- Plugin updates available
- Update plugins
- Check plugin updates
- Plugins are successfully updated. Please restart Flow.
+ 有外掛更新可用
+ 更新外掛程式
+ 檢查外掛更新
+ 插件已成功更新。請重新啟動Flow。主題
@@ -288,21 +290,21 @@
檔案總管搜尋檔案、資料夾和檔案內容網路搜尋
- Search the web with different search engine support
+ 使用不同的搜尋引擎搜尋網絡程式以系統管理員或其他使用者啟用應用程式ProcessKiller
- Terminate unwanted processes
- Search Bar Height
- Item Height
+ 終止不需要的進程
+ 搜尋列高度
+ 項目高度查詢框字體
- Result Title Font
- Result Subtitle Font
- Reset
- Reset to the recommended font and size settings.
- Import Theme Size
- If a size value intended by the theme designer is available, it will be retrieved and applied.
- Customize
+ 結果標題字體
+ 結果副標題字體
+ 重設
+ 恢復預設字體與文字大小設定。
+ 匯入主題大小
+ 如果主題設計者預設的尺寸值存在,則會擷取並套用該尺寸值。
+ 個人化視窗模式透明度找不到主題 {0} ,將回到預設主題
@@ -315,49 +317,49 @@
暗色系音效搜尋窗口打開時播放音效
- Sound Effect Volume
- Adjust the volume of the sound effect
- Windows Media Player is unavailable and is required for Flow's volume adjustment. Please check your installation if you need to adjust volume.
+ 音效音量
+ 調整音效音量
+ Windows Media Player不可用,而Flow的音量調整功能需要它。如果您需要調整音量,請檢查您的安裝情況。動畫使用介面動畫
- Animation Speed
- The speed of the UI animation
- Slow
- Medium
- Fast
- Custom
+ 動畫速度
+ UI動畫速度
+ 慢速
+ 中等
+ 快速
+ 自訂時鐘日期
- Backdrop Type
- The backdrop effect is not applied in the preview.
- Backdrop supported starting from Windows 11 build 22000 and above
- None
- Acrylic
- Mica
- Mica Alt
- This theme supports two (light/dark) modes.
- This theme supports Blur Transparent Background.
- Show placeholder
- Display placeholder when query is empty
- Placeholder text
- Change placeholder text. Input empty will use: {0}
- Fixed Window Size
- The window size is not adjustable by dragging.
- Since Always Preview is on, maximum results shown may not take effect because preview panel requires a certain minimum height
+ 背景類型
+ 預覽中未套用背景效果。
+ 從 Windows 11 版本 22000 及更高版本開始支援背景功能
+ 無
+ 壓克力
+ 雲母
+ 雲母(替代樣式)
+ 此主題支援兩種(淺色/深色)模式。
+ 此主題支援模糊透明背景。
+ 顯示佔位符
+ 當查詢為空時顯示佔位符
+ 佔位符文字
+ 更改佔位符文字。輸入為空將使用{0}
+ 固定視窗大小
+ 視窗大小無法透過拖曳進行調整。
+ 由於「始終預覽」已啟用,因此可能無法顯示最大效果,因為預覽面板需要一定的最小高度快捷鍵快捷鍵
- Open Flow Launcher
+ 開啟Flow Launcher執行縮寫以顯示 / 隱藏 Flow Launcher。
- Toggle Preview
+ 切換預覽Enter shortcut to show/hide preview in search window.Hotkey PresetsList of currently registered hotkeys開放結果修飾符
- Select a modifier key to open selected result via keyboard.
+ 選擇一個修飾鍵以透過鍵盤開啟已選擇的結果。顯示快捷鍵
- Show result selection hotkey with results.
+ 利用結果來顯示選擇的快捷鍵結果。Auto CompleteRuns autocomplete for the selected items.Select Next Item
@@ -541,7 +543,7 @@
Input the search delay time in ms you like to use for the plugin. Input empty if you don't want to specify any, and the plugin will use default search delay time.
- Home Page
+ 首頁Enable the plugin home page state if you like to show the plugin results when query is empty.
@@ -655,12 +657,12 @@ If you add an '@' prefix while inputting a shortcut, it matches any position in
返回 / 快捷選單
- Item Navigation
+ 物件導覽打開選單開啟檔案位置Run as Admin / Open Folder in Default File Manager查詢歷史
- Back to Result in Context Menu
+ 返回右鍵選單中的結果自動完成開啟/運行選擇項目開啟視窗設定
diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml
index 132ec8389..747975b2a 100644
--- a/Flow.Launcher/MainWindow.xaml
+++ b/Flow.Launcher/MainWindow.xaml
@@ -6,7 +6,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
Name="FlowMainWindow"
Title="Flow Launcher"
@@ -526,7 +526,7 @@
+ Text="{Binding PreviewDescription}" />
diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs
index 7f31de22d..942cccbe9 100644
--- a/Flow.Launcher/MainWindow.xaml.cs
+++ b/Flow.Launcher/MainWindow.xaml.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.ComponentModel;
using System.Linq;
using System.Media;
@@ -25,7 +25,8 @@ using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.ViewModel;
-using ModernWpf.Controls;
+using iNKORE.UI.WPF.Modern;
+using iNKORE.UI.WPF.Modern.Controls;
using DataObject = System.Windows.DataObject;
using Key = System.Windows.Input.Key;
using MouseButtons = System.Windows.Forms.MouseButtons;
@@ -148,8 +149,8 @@ namespace Flow.Launcher
_settings.ReleaseNotesVersion = Constant.Version;
// Show release note popup with button
App.API.ShowMsgWithButton(
- string.Format(App.API.GetTranslation("appUpdateTitle"), Constant.Version),
- App.API.GetTranslation("appUpdateButtonContent"),
+ Localize.appUpdateTitle(Constant.Version),
+ Localize.appUpdateButtonContent(),
() =>
{
Application.Current.Dispatcher.Invoke(() =>
@@ -191,11 +192,11 @@ namespace Flow.Launcher
// Initialize color scheme
if (_settings.ColorScheme == Constant.Light)
{
- ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Light;
+ ThemeManager.Current.ApplicationTheme = ApplicationTheme.Light;
}
else if (_settings.ColorScheme == Constant.Dark)
{
- ModernWpf.ThemeManager.Current.ApplicationTheme = ModernWpf.ApplicationTheme.Dark;
+ ThemeManager.Current.ApplicationTheme = ApplicationTheme.Dark;
}
// Initialize position
@@ -475,7 +476,7 @@ namespace Flow.Launcher
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
{
var queryWithoutActionKeyword =
- QueryBuilder.Build(QueryTextBox.Text.Trim(), PluginManager.NonGlobalPlugins)?.Search;
+ QueryBuilder.Build(QueryTextBox.Text, QueryTextBox.Text.Trim(), PluginManager.GetNonGlobalPlugins())?.Search;
if (FilesFolders.IsLocationPathString(queryWithoutActionKeyword))
{
@@ -793,12 +794,12 @@ namespace Flow.Launcher
private void UpdateNotifyIconText()
{
var menu = _contextMenu;
- ((MenuItem)menu.Items[0]).Header = App.API.GetTranslation("iconTrayOpen") +
+ ((MenuItem)menu.Items[0]).Header = Localize.iconTrayOpen() +
" (" + _settings.Hotkey + ")";
- ((MenuItem)menu.Items[1]).Header = App.API.GetTranslation("GameMode");
- ((MenuItem)menu.Items[2]).Header = App.API.GetTranslation("PositionReset");
- ((MenuItem)menu.Items[3]).Header = App.API.GetTranslation("iconTraySettings");
- ((MenuItem)menu.Items[4]).Header = App.API.GetTranslation("iconTrayExit");
+ ((MenuItem)menu.Items[1]).Header = Localize.GameMode();
+ ((MenuItem)menu.Items[2]).Header = Localize.PositionReset();
+ ((MenuItem)menu.Items[3]).Header = Localize.iconTraySettings();
+ ((MenuItem)menu.Items[4]).Header = Localize.iconTrayExit();
}
private void InitializeContextMenu()
@@ -808,31 +809,31 @@ namespace Flow.Launcher
var openIcon = new FontIcon { Glyph = "\ue71e" };
var open = new MenuItem
{
- Header = App.API.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")",
+ Header = Localize.iconTrayOpen() + " (" + _settings.Hotkey + ")",
Icon = openIcon
};
var gamemodeIcon = new FontIcon { Glyph = "\ue7fc" };
var gamemode = new MenuItem
{
- Header = App.API.GetTranslation("GameMode"),
+ Header = Localize.GameMode(),
Icon = gamemodeIcon
};
var positionresetIcon = new FontIcon { Glyph = "\ue73f" };
var positionreset = new MenuItem
{
- Header = App.API.GetTranslation("PositionReset"),
+ Header = Localize.PositionReset(),
Icon = positionresetIcon
};
var settingsIcon = new FontIcon { Glyph = "\ue713" };
var settings = new MenuItem
{
- Header = App.API.GetTranslation("iconTraySettings"),
+ Header = Localize.iconTraySettings(),
Icon = settingsIcon
};
var exitIcon = new FontIcon { Glyph = "\ue7e8" };
var exit = new MenuItem
{
- Header = App.API.GetTranslation("iconTrayExit"),
+ Header = Localize.iconTrayExit(),
Icon = exitIcon
};
@@ -842,8 +843,8 @@ namespace Flow.Launcher
settings.Click += (o, e) => App.API.OpenSettingDialog();
exit.Click += (o, e) => Close();
- gamemode.ToolTip = App.API.GetTranslation("GameModeToolTip");
- positionreset.ToolTip = App.API.GetTranslation("PositionResetToolTip");
+ gamemode.ToolTip = Localize.GameModeToolTip();
+ positionreset.ToolTip = Localize.PositionResetToolTip();
_contextMenu.Items.Add(open);
_contextMenu.Items.Add(gamemode);
diff --git a/Flow.Launcher/PluginUpdateWindow.xaml b/Flow.Launcher/PluginUpdateWindow.xaml
index 04cd1f7bc..a4bb06431 100644
--- a/Flow.Launcher/PluginUpdateWindow.xaml
+++ b/Flow.Launcher/PluginUpdateWindow.xaml
@@ -4,6 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Title="{DynamicResource updateAllPluginsButtonContent}"
Width="530"
Background="{DynamicResource PopuBGColor}"
@@ -66,13 +67,13 @@
Text="{DynamicResource updateAllPluginsButtonContent}"
TextAlignment="Left" />
-
-
+
Internationalization.GetTranslation(key);
- public List GetAllPlugins() => PluginManager.AllPlugins.ToList();
+ public List GetAllPlugins() => PluginManager.GetAllLoadedPlugins();
+
+ public List GetAllInitializedPlugins(bool includeFailed) =>
+ PluginManager.GetAllInitializedPlugins(includeFailed);
public MatchResult FuzzySearch(string query, string stringToCompare) =>
StringMatcher.FuzzySearch(query, stringToCompare);
@@ -393,18 +395,18 @@ namespace Flow.Launcher
}
catch (Win32Exception ex) when (ex.NativeErrorCode == 2)
{
- LogError(ClassName, "File Manager not found");
+ LogException(ClassName, "File Manager not found", ex);
ShowMsgError(
- GetTranslation("fileManagerNotFoundTitle"),
- string.Format(GetTranslation("fileManagerNotFound"), ex.Message)
+ Localize.fileManagerNotFoundTitle(),
+ Localize.fileManagerNotFound()
);
}
catch (Exception ex)
{
LogException(ClassName, "Failed to open folder", ex);
ShowMsgError(
- GetTranslation("errorTitle"),
- string.Format(GetTranslation("folderOpenError"), ex.Message)
+ Localize.errorTitle(),
+ Localize.folderOpenError()
);
}
}
@@ -413,7 +415,7 @@ namespace Flow.Launcher
{
if (uri.IsFile && !FilesFolders.FileOrLocationExists(uri.LocalPath))
{
- ShowMsgError(GetTranslation("errorTitle"), string.Format(GetTranslation("fileNotFoundError"), uri.LocalPath));
+ ShowMsgError(Localize.errorTitle(), Localize.fileNotFoundError(uri.LocalPath));
return;
}
@@ -439,8 +441,8 @@ namespace Flow.Launcher
var tabOrWindow = browserInfo.OpenInTab ? "tab" : "window";
LogException(ClassName, $"Failed to open URL in browser {tabOrWindow}: {path}, {inPrivate ?? browserInfo.EnablePrivate}, {browserInfo.PrivateArg}", e);
ShowMsgError(
- GetTranslation("errorTitle"),
- GetTranslation("browserOpenError")
+ Localize.errorTitle(),
+ Localize.browserOpenError()
);
}
}
@@ -457,7 +459,7 @@ namespace Flow.Launcher
catch (Exception e)
{
LogException(ClassName, $"Failed to open: {uri.AbsoluteUri}", e);
- ShowMsgError(GetTranslation("errorTitle"), e.Message);
+ ShowMsgError(Localize.errorTitle(), e.Message);
}
}
}
diff --git a/Flow.Launcher/ReleaseNotesWindow.xaml b/Flow.Launcher/ReleaseNotesWindow.xaml
index f0bdbadda..6072f40f1 100644
--- a/Flow.Launcher/ReleaseNotesWindow.xaml
+++ b/Flow.Launcher/ReleaseNotesWindow.xaml
@@ -7,7 +7,7 @@
xmlns:local="clr-namespace:Flow.Launcher"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:mdxam="clr-namespace:MdXaml;assembly=MdXaml"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
Title="{DynamicResource releaseNotes}"
Width="940"
@@ -16,6 +16,7 @@
MinHeight="600"
Background="{DynamicResource PopuBGColor}"
Closed="Window_Closed"
+ DataContext="{Binding RelativeSource={RelativeSource Self}}"
Foreground="{DynamicResource PopupTextColor}"
Loaded="Window_Loaded"
ResizeMode="CanResize"
@@ -44,7 +45,7 @@
-
+
@@ -161,18 +162,23 @@
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="5"
- Margin="18 0 18 0">
-
+ Margin="6 0 18 0">
+
-
+ Height="500"
+ Margin="15 0 0 0"
+ Padding="0 0 15 0"
+ HorizontalAlignment="Stretch">
@@ -193,11 +199,11 @@
VerticalScrollBarVisibility="Disabled"
Visibility="Collapsed" />
-
+
-
+
Properties.Settings.Default.GithubRepo + "/releases";
public ReleaseNotesWindow()
{
InitializeComponent();
- SeeMore.Uri = ReleaseNotes;
- ModernWpf.ThemeManager.Current.ActualApplicationThemeChanged += ThemeManager_ActualApplicationThemeChanged;
+ ThemeManager.Current.ActualApplicationThemeChanged += ThemeManager_ActualApplicationThemeChanged;
}
#region Window Events
- private void ThemeManager_ActualApplicationThemeChanged(ModernWpf.ThemeManager sender, object args)
+ private void ThemeManager_ActualApplicationThemeChanged(ThemeManager sender, object args)
{
Application.Current.Dispatcher.Invoke(() =>
{
- if (ModernWpf.ThemeManager.Current.ActualApplicationTheme == ModernWpf.ApplicationTheme.Light)
+ if (ThemeManager.Current.ActualApplicationTheme == ApplicationTheme.Light)
{
MarkdownViewer.MarkdownStyle = (Style)Application.Current.Resources["DocumentStyleGithubLikeLight"];
MarkdownViewer.Foreground = Brushes.Black;
@@ -58,7 +58,7 @@ namespace Flow.Launcher
private void Window_Closed(object sender, EventArgs e)
{
- ModernWpf.ThemeManager.Current.ActualApplicationThemeChanged -= ThemeManager_ActualApplicationThemeChanged;
+ ThemeManager.Current.ActualApplicationThemeChanged -= ThemeManager_ActualApplicationThemeChanged;
}
#endregion
@@ -132,8 +132,8 @@ namespace Flow.Launcher
RefreshButton.Visibility = Visibility.Visible;
MarkdownViewer.Visibility = Visibility.Collapsed;
App.API.ShowMsgError(
- App.API.GetTranslation("checkNetworkConnectionTitle"),
- App.API.GetTranslation("checkNetworkConnectionSubTitle"));
+ Localize.checkNetworkConnectionTitle(),
+ Localize.checkNetworkConnectionSubTitle());
}
else
{
@@ -147,7 +147,6 @@ namespace Flow.Launcher
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
MarkdownScrollViewer.Height = e.NewSize.Height;
- MarkdownScrollViewer.Width = e.NewSize.Width;
}
private void MarkdownViewer_MouseWheel(object sender, MouseWheelEventArgs e)
diff --git a/Flow.Launcher/ReportWindow.xaml.cs b/Flow.Launcher/ReportWindow.xaml.cs
index ae0767934..bb0ce0073 100644
--- a/Flow.Launcher/ReportWindow.xaml.cs
+++ b/Flow.Launcher/ReportWindow.xaml.cs
@@ -48,10 +48,10 @@ namespace Flow.Launcher
_ => Constant.IssuesUrl
};
- var paragraph = Hyperlink(App.API.GetTranslation("reportWindow_please_open_issue"), websiteUrl);
- paragraph.Inlines.Add(string.Format(App.API.GetTranslation("reportWindow_upload_log"), log.FullName));
+ var paragraph = Hyperlink(Localize.reportWindow_please_open_issue(), websiteUrl);
+ paragraph.Inlines.Add(Localize.reportWindow_upload_log(log.FullName));
paragraph.Inlines.Add("\n");
- paragraph.Inlines.Add(App.API.GetTranslation("reportWindow_copy_below"));
+ paragraph.Inlines.Add(Localize.reportWindow_copy_below());
ErrorTextbox.Document.Blocks.Add(paragraph);
StringBuilder content = new StringBuilder();
diff --git a/Flow.Launcher/Resources/Controls/Card.xaml b/Flow.Launcher/Resources/Controls/Card.xaml
deleted file mode 100644
index e3c5f8194..000000000
--- a/Flow.Launcher/Resources/Controls/Card.xaml
+++ /dev/null
@@ -1,139 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Flow.Launcher/Resources/Controls/Card.xaml.cs b/Flow.Launcher/Resources/Controls/Card.xaml.cs
deleted file mode 100644
index 6a70dded2..000000000
--- a/Flow.Launcher/Resources/Controls/Card.xaml.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using System.Windows;
-using UserControl = System.Windows.Controls.UserControl;
-
-namespace Flow.Launcher.Resources.Controls
-{
- public partial class Card : UserControl
- {
- public enum CardType
- {
- Default,
- Inside,
- InsideFit,
- First,
- Middle,
- Last
- }
-
- public Card()
- {
- InitializeComponent();
- }
-
- public string Title
- {
- get { return (string)GetValue(TitleProperty); }
- set { SetValue(TitleProperty, value); }
- }
- public static readonly DependencyProperty TitleProperty =
- DependencyProperty.Register(nameof(Title), typeof(string), typeof(Card), new PropertyMetadata(string.Empty));
-
- public string Sub
- {
- get { return (string)GetValue(SubProperty); }
- set { SetValue(SubProperty, value); }
- }
- public static readonly DependencyProperty SubProperty =
- DependencyProperty.Register(nameof(Sub), typeof(string), typeof(Card), new PropertyMetadata(string.Empty));
-
- public string Icon
- {
- get { return (string)GetValue(IconProperty); }
- set { SetValue(IconProperty, value); }
- }
- public static readonly DependencyProperty IconProperty =
- DependencyProperty.Register(nameof(Icon), typeof(string), typeof(Card), new PropertyMetadata(string.Empty));
-
- ///
- /// Gets or sets additional content for the UserControl
- ///
- public object AdditionalContent
- {
- get { return (object)GetValue(AdditionalContentProperty); }
- set { SetValue(AdditionalContentProperty, value); }
- }
- public static readonly DependencyProperty AdditionalContentProperty =
- DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(Card),
- new PropertyMetadata(null));
- public CardType Type
- {
- get { return (CardType)GetValue(TypeProperty); }
- set { SetValue(TypeProperty, value); }
- }
- public static readonly DependencyProperty TypeProperty =
- DependencyProperty.Register(nameof(Type), typeof(CardType), typeof(Card),
- new PropertyMetadata(CardType.Default));
- }
-}
diff --git a/Flow.Launcher/Resources/Controls/CardGroup.xaml b/Flow.Launcher/Resources/Controls/CardGroup.xaml
deleted file mode 100644
index f48bf4b6c..000000000
--- a/Flow.Launcher/Resources/Controls/CardGroup.xaml
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Flow.Launcher/Resources/Controls/CardGroup.xaml.cs b/Flow.Launcher/Resources/Controls/CardGroup.xaml.cs
deleted file mode 100644
index b9588275c..000000000
--- a/Flow.Launcher/Resources/Controls/CardGroup.xaml.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Windows;
-using System.Windows.Controls;
-
-namespace Flow.Launcher.Resources.Controls;
-
-public partial class CardGroup : UserControl
-{
- public enum CardGroupPosition
- {
- NotInGroup,
- First,
- Middle,
- Last
- }
-
- public new ObservableCollection Content
- {
- get { return (ObservableCollection)GetValue(ContentProperty); }
- set { SetValue(ContentProperty, value); }
- }
-
- public static new readonly DependencyProperty ContentProperty =
- DependencyProperty.Register(nameof(Content), typeof(ObservableCollection), typeof(CardGroup));
-
- public static readonly DependencyProperty PositionProperty = DependencyProperty.RegisterAttached(
- "Position", typeof(CardGroupPosition), typeof(CardGroup),
- new FrameworkPropertyMetadata(CardGroupPosition.NotInGroup, FrameworkPropertyMetadataOptions.AffectsRender)
- );
-
- public static void SetPosition(UIElement element, CardGroupPosition value)
- {
- element.SetValue(PositionProperty, value);
- }
-
- public static CardGroupPosition GetPosition(UIElement element)
- {
- return (CardGroupPosition)element.GetValue(PositionProperty);
- }
-
- public CardGroup()
- {
- InitializeComponent();
- Content = new ObservableCollection();
- }
-}
diff --git a/Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs b/Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs
deleted file mode 100644
index 605934e80..000000000
--- a/Flow.Launcher/Resources/Controls/CardGroupCardStyleSelector.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Windows;
-using System.Windows.Controls;
-
-namespace Flow.Launcher.Resources.Controls;
-
-public class CardGroupCardStyleSelector : StyleSelector
-{
- public Style FirstStyle { get; set; }
- public Style MiddleStyle { get; set; }
- public Style LastStyle { get; set; }
-
- public override Style SelectStyle(object item, DependencyObject container)
- {
- var itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
- var index = itemsControl.ItemContainerGenerator.IndexFromContainer(container);
-
- if (index == 0) return FirstStyle;
- if (index == itemsControl.Items.Count - 1) return LastStyle;
- return MiddleStyle;
- }
-}
diff --git a/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs b/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs
new file mode 100644
index 000000000..78985108c
--- /dev/null
+++ b/Flow.Launcher/Resources/Controls/CustomScrollViewerEx.cs
@@ -0,0 +1,253 @@
+using iNKORE.UI.WPF.Modern.Controls;
+using iNKORE.UI.WPF.Modern.Controls.Helpers;
+using iNKORE.UI.WPF.Modern.Controls.Primitives;
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace Flow.Launcher.Resources.Controls
+{
+ // TODO: Use IsScrollAnimationEnabled property in future: https://github.com/iNKORE-NET/UI.WPF.Modern/pull/347
+ public class CustomScrollViewerEx : ScrollViewer
+ {
+ private double LastVerticalLocation = 0;
+ private double LastHorizontalLocation = 0;
+
+ public CustomScrollViewerEx()
+ {
+ Loaded += OnLoaded;
+ var valueSource = DependencyPropertyHelper.GetValueSource(this, AutoPanningMode.IsEnabledProperty).BaseValueSource;
+ if (valueSource == BaseValueSource.Default)
+ {
+ AutoPanningMode.SetIsEnabled(this, true);
+ }
+ }
+
+ #region Orientation
+
+ public static readonly DependencyProperty OrientationProperty =
+ DependencyProperty.Register(
+ nameof(Orientation),
+ typeof(Orientation),
+ typeof(CustomScrollViewerEx),
+ new PropertyMetadata(Orientation.Vertical));
+
+ public Orientation Orientation
+ {
+ get => (Orientation)GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
+ }
+
+ #endregion
+
+ #region AutoHideScrollBars
+
+ public static readonly DependencyProperty AutoHideScrollBarsProperty =
+ ScrollViewerHelper.AutoHideScrollBarsProperty
+ .AddOwner(
+ typeof(CustomScrollViewerEx),
+ new PropertyMetadata(true, OnAutoHideScrollBarsChanged));
+
+ public bool AutoHideScrollBars
+ {
+ get => (bool)GetValue(AutoHideScrollBarsProperty);
+ set => SetValue(AutoHideScrollBarsProperty, value);
+ }
+
+ private static void OnAutoHideScrollBarsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is CustomScrollViewerEx sv)
+ {
+ sv.UpdateVisualState();
+ }
+ }
+
+ #endregion
+
+ private void OnLoaded(object sender, RoutedEventArgs e)
+ {
+ LastVerticalLocation = VerticalOffset;
+ LastHorizontalLocation = HorizontalOffset;
+ UpdateVisualState(false);
+ }
+
+ ///
+ protected override void OnInitialized(EventArgs e)
+ {
+ base.OnInitialized(e);
+
+ if (Style == null && ReadLocalValue(StyleProperty) == DependencyProperty.UnsetValue)
+ {
+ SetResourceReference(StyleProperty, typeof(ScrollViewer));
+ }
+ }
+
+ ///
+ protected override void OnMouseWheel(MouseWheelEventArgs e)
+ {
+ var Direction = GetDirection();
+ ScrollViewerBehavior.SetIsAnimating(this, true);
+
+ if (Direction == Orientation.Vertical)
+ {
+ if (ScrollableHeight > 0)
+ {
+ e.Handled = true;
+ }
+
+ var WheelChange = e.Delta * (ViewportHeight / 1.5) / ActualHeight;
+ var newOffset = LastVerticalLocation - WheelChange;
+
+ if (newOffset < 0)
+ {
+ newOffset = 0;
+ }
+
+ if (newOffset > ScrollableHeight)
+ {
+ newOffset = ScrollableHeight;
+ }
+
+ if (newOffset == LastVerticalLocation)
+ {
+ return;
+ }
+
+ ScrollToVerticalOffset(LastVerticalLocation);
+
+ ScrollToValue(newOffset, Direction);
+ LastVerticalLocation = newOffset;
+ }
+ else
+ {
+ if (ScrollableWidth > 0)
+ {
+ e.Handled = true;
+ }
+
+ var WheelChange = e.Delta * (ViewportWidth / 1.5) / ActualWidth;
+ var newOffset = LastHorizontalLocation - WheelChange;
+
+ if (newOffset < 0)
+ {
+ newOffset = 0;
+ }
+
+ if (newOffset > ScrollableWidth)
+ {
+ newOffset = ScrollableWidth;
+ }
+
+ if (newOffset == LastHorizontalLocation)
+ {
+ return;
+ }
+
+ ScrollToHorizontalOffset(LastHorizontalLocation);
+
+ ScrollToValue(newOffset, Direction);
+ LastHorizontalLocation = newOffset;
+ }
+ }
+
+ ///
+ protected override void OnScrollChanged(ScrollChangedEventArgs e)
+ {
+ base.OnScrollChanged(e);
+ if (!ScrollViewerBehavior.GetIsAnimating(this))
+ {
+ LastVerticalLocation = VerticalOffset;
+ LastHorizontalLocation = HorizontalOffset;
+ }
+ }
+
+ private Orientation GetDirection()
+ {
+ var isShiftDown = Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift);
+
+ if (Orientation == Orientation.Horizontal)
+ {
+ return isShiftDown ? Orientation.Vertical : Orientation.Horizontal;
+ }
+ else
+ {
+ return isShiftDown ? Orientation.Horizontal : Orientation.Vertical;
+ }
+ }
+
+ ///
+ /// Causes the to load a new view into the viewport using the specified offsets and zoom factor.
+ ///
+ /// A value between 0 and that specifies the distance the content should be scrolled horizontally.
+ /// A value between 0 and that specifies the distance the content should be scrolled vertically.
+ /// A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor.
+ /// if the view is changed; otherwise, .
+ public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor)
+ {
+ return ChangeView(horizontalOffset, verticalOffset, zoomFactor, false);
+ }
+
+ ///
+ /// Causes the to load a new view into the viewport using the specified offsets and zoom factor, and optionally disables scrolling animation.
+ ///
+ /// A value between 0 and that specifies the distance the content should be scrolled horizontally.
+ /// A value between 0 and that specifies the distance the content should be scrolled vertically.
+ /// A value between MinZoomFactor and MaxZoomFactor that specifies the required target ZoomFactor.
+ /// to disable zoom/pan animations while changing the view; otherwise, . The default is false.
+ /// if the view is changed; otherwise, .
+ public bool ChangeView(double? horizontalOffset, double? verticalOffset, float? zoomFactor, bool disableAnimation)
+ {
+ if (disableAnimation)
+ {
+ if (horizontalOffset.HasValue)
+ {
+ ScrollToHorizontalOffset(horizontalOffset.Value);
+ }
+
+ if (verticalOffset.HasValue)
+ {
+ ScrollToVerticalOffset(verticalOffset.Value);
+ }
+ }
+ else
+ {
+ if (horizontalOffset.HasValue)
+ {
+ ScrollToHorizontalOffset(LastHorizontalLocation);
+ ScrollToValue(Math.Min(ScrollableWidth, horizontalOffset.Value), Orientation.Horizontal);
+ LastHorizontalLocation = horizontalOffset.Value;
+ }
+
+ if (verticalOffset.HasValue)
+ {
+ ScrollToVerticalOffset(LastVerticalLocation);
+ ScrollToValue(Math.Min(ScrollableHeight, verticalOffset.Value), Orientation.Vertical);
+ LastVerticalLocation = verticalOffset.Value;
+ }
+ }
+
+ return true;
+ }
+
+ private void ScrollToValue(double value, Orientation Direction)
+ {
+ if (Direction == Orientation.Vertical)
+ {
+ ScrollToVerticalOffset(value);
+ }
+ else
+ {
+ ScrollToHorizontalOffset(value);
+ }
+
+ ScrollViewerBehavior.SetIsAnimating(this, false);
+ }
+
+ private void UpdateVisualState(bool useTransitions = true)
+ {
+ var stateName = AutoHideScrollBars ? "NoIndicator" : "MouseIndicator";
+ VisualStateManager.GoToState(this, stateName, useTransitions);
+ }
+ }
+}
diff --git a/Flow.Launcher/Resources/Controls/ExCard.xaml b/Flow.Launcher/Resources/Controls/ExCard.xaml
deleted file mode 100644
index a70c0f4ea..000000000
--- a/Flow.Launcher/Resources/Controls/ExCard.xaml
+++ /dev/null
@@ -1,312 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Flow.Launcher/Resources/Controls/ExCard.xaml.cs b/Flow.Launcher/Resources/Controls/ExCard.xaml.cs
deleted file mode 100644
index f149951f0..000000000
--- a/Flow.Launcher/Resources/Controls/ExCard.xaml.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System.Windows;
-using System.Windows.Controls;
-
-namespace Flow.Launcher.Resources.Controls
-{
- public partial class ExCard : UserControl
- {
- public ExCard()
- {
- InitializeComponent();
- }
- public string Title
- {
- get { return (string)GetValue(TitleProperty); }
- set { SetValue(TitleProperty, value); }
- }
- public static readonly DependencyProperty TitleProperty =
- DependencyProperty.Register(nameof(Title), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty));
-
- public string Sub
- {
- get { return (string)GetValue(SubProperty); }
- set { SetValue(SubProperty, value); }
- }
- public static readonly DependencyProperty SubProperty =
- DependencyProperty.Register(nameof(Sub), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty));
-
- public string Icon
- {
- get { return (string)GetValue(IconProperty); }
- set { SetValue(IconProperty, value); }
- }
- public static readonly DependencyProperty IconProperty =
- DependencyProperty.Register(nameof(Icon), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty));
-
- ///
- /// Gets or sets additional content for the UserControl
- ///
- public object AdditionalContent
- {
- get { return (object)GetValue(AdditionalContentProperty); }
- set { SetValue(AdditionalContentProperty, value); }
- }
- public static readonly DependencyProperty AdditionalContentProperty =
- DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(ExCard),
- new PropertyMetadata(null));
-
- public object SideContent
- {
- get { return (object)GetValue(SideContentProperty); }
- set { SetValue(SideContentProperty, value); }
- }
- public static readonly DependencyProperty SideContentProperty =
- DependencyProperty.Register(nameof(SideContent), typeof(object), typeof(ExCard),
- new PropertyMetadata(null));
- }
-}
diff --git a/Flow.Launcher/Resources/Controls/HyperLink.xaml b/Flow.Launcher/Resources/Controls/HyperLink.xaml
deleted file mode 100644
index 9ea550afd..000000000
--- a/Flow.Launcher/Resources/Controls/HyperLink.xaml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
diff --git a/Flow.Launcher/Resources/Controls/HyperLink.xaml.cs b/Flow.Launcher/Resources/Controls/HyperLink.xaml.cs
deleted file mode 100644
index 855cccdbd..000000000
--- a/Flow.Launcher/Resources/Controls/HyperLink.xaml.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Navigation;
-
-namespace Flow.Launcher.Resources.Controls;
-
-public partial class HyperLink : UserControl
-{
- public static readonly DependencyProperty UriProperty = DependencyProperty.Register(
- nameof(Uri), typeof(string), typeof(HyperLink), new PropertyMetadata(default(string))
- );
-
- public string Uri
- {
- get => (string)GetValue(UriProperty);
- set => SetValue(UriProperty, value);
- }
-
- public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
- nameof(Text), typeof(string), typeof(HyperLink), new PropertyMetadata(default(string))
- );
-
- public string Text
- {
- get => (string)GetValue(TextProperty);
- set => SetValue(TextProperty, value);
- }
-
- public HyperLink()
- {
- InitializeComponent();
- }
-
- private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
- {
- App.API.OpenUrl(e.Uri);
- e.Handled = true;
- }
-}
diff --git a/Flow.Launcher/Resources/Controls/InfoBar.xaml b/Flow.Launcher/Resources/Controls/InfoBar.xaml
deleted file mode 100644
index 2ddcbdd0c..000000000
--- a/Flow.Launcher/Resources/Controls/InfoBar.xaml
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Flow.Launcher/Resources/Controls/InfoBar.xaml.cs b/Flow.Launcher/Resources/Controls/InfoBar.xaml.cs
deleted file mode 100644
index ebf763e22..000000000
--- a/Flow.Launcher/Resources/Controls/InfoBar.xaml.cs
+++ /dev/null
@@ -1,222 +0,0 @@
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Media;
-
-namespace Flow.Launcher.Resources.Controls
-{
- public partial class InfoBar : UserControl
- {
- public InfoBar()
- {
- InitializeComponent();
- Loaded += InfoBar_Loaded;
- }
-
- private void InfoBar_Loaded(object sender, RoutedEventArgs e)
- {
- UpdateStyle();
- UpdateTitleVisibility();
- UpdateMessageVisibility();
- UpdateOrientation();
- UpdateIconAlignmentAndMargin();
- UpdateIconVisibility();
- UpdateCloseButtonVisibility();
- }
-
- public static readonly DependencyProperty TypeProperty =
- DependencyProperty.Register(nameof(Type), typeof(InfoBarType), typeof(InfoBar), new PropertyMetadata(InfoBarType.Info, OnTypeChanged));
-
- public InfoBarType Type
- {
- get => (InfoBarType)GetValue(TypeProperty);
- set => SetValue(TypeProperty, value);
- }
-
- private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- if (d is InfoBar infoBar)
- {
- infoBar.UpdateStyle();
- }
- }
-
- public static readonly DependencyProperty MessageProperty =
- DependencyProperty.Register(nameof(Message), typeof(string), typeof(InfoBar), new PropertyMetadata(string.Empty, OnMessageChanged));
-
- public string Message
- {
- get => (string)GetValue(MessageProperty);
- set
- {
- SetValue(MessageProperty, value);
- }
- }
-
- private static void OnMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- if (d is InfoBar infoBar)
- {
- infoBar.UpdateMessageVisibility();
- }
- }
-
- private void UpdateMessageVisibility()
- {
- PART_Message.Visibility = string.IsNullOrEmpty(Message) ? Visibility.Collapsed : Visibility.Visible;
- }
-
- public static readonly DependencyProperty TitleProperty =
- DependencyProperty.Register(nameof(Title), typeof(string), typeof(InfoBar), new PropertyMetadata(string.Empty, OnTitleChanged));
-
- public string Title
- {
- get => (string)GetValue(TitleProperty);
- set
- {
- SetValue(TitleProperty, value);
- UpdateTitleVisibility(); // Visibility update when change Title
- }
- }
-
- private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- if (d is InfoBar infoBar)
- {
- infoBar.UpdateTitleVisibility();
- }
- }
-
- private void UpdateTitleVisibility()
- {
- PART_Title.Visibility = string.IsNullOrEmpty(Title) ? Visibility.Collapsed : Visibility.Visible;
- }
-
- public static readonly DependencyProperty IsIconVisibleProperty =
- DependencyProperty.Register(nameof(IsIconVisible), typeof(bool), typeof(InfoBar), new PropertyMetadata(true, OnIsIconVisibleChanged));
-
- public bool IsIconVisible
- {
- get => (bool)GetValue(IsIconVisibleProperty);
- set => SetValue(IsIconVisibleProperty, value);
- }
-
- public static readonly DependencyProperty LengthProperty =
- DependencyProperty.Register(nameof(Length), typeof(InfoBarLength), typeof(InfoBar), new PropertyMetadata(InfoBarLength.Short, OnLengthChanged));
-
- public InfoBarLength Length
- {
- get { return (InfoBarLength)GetValue(LengthProperty); }
- set { SetValue(LengthProperty, value); }
- }
-
- private static void OnLengthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- if (d is InfoBar infoBar)
- {
- infoBar.UpdateOrientation();
- infoBar.UpdateIconAlignmentAndMargin();
- }
- }
-
- private void UpdateOrientation()
- {
- PART_StackPanel.Orientation = Length == InfoBarLength.Long ? Orientation.Vertical : Orientation.Horizontal;
- }
-
- private void UpdateIconAlignmentAndMargin()
- {
- if (Length == InfoBarLength.Short)
- {
- PART_IconBorder.VerticalAlignment = VerticalAlignment.Center;
- PART_IconBorder.Margin = new Thickness(0, 0, 12, 0);
- }
- else
- {
- PART_IconBorder.VerticalAlignment = VerticalAlignment.Top;
- PART_IconBorder.Margin = new Thickness(0, 2, 12, 0);
- }
- }
-
- public static readonly DependencyProperty ClosableProperty =
- DependencyProperty.Register(nameof(Closable), typeof(bool), typeof(InfoBar), new PropertyMetadata(true, OnClosableChanged));
-
- public bool Closable
- {
- get => (bool)GetValue(ClosableProperty);
- set => SetValue(ClosableProperty, value);
- }
-
- private void PART_CloseButton_Click(object sender, RoutedEventArgs e)
- {
- Visibility = Visibility.Collapsed;
- }
-
- private void UpdateStyle()
- {
- switch (Type)
- {
- case InfoBarType.Info:
- PART_Border.Background = (Brush)FindResource("InfoBarInfoBG");
- PART_IconBorder.Background = (Brush)FindResource("InfoBarInfoIcon");
- PART_Icon.Glyph = "\xF13F";
- break;
- case InfoBarType.Success:
- PART_Border.Background = (Brush)FindResource("InfoBarSuccessBG");
- PART_IconBorder.Background = (Brush)FindResource("InfoBarSuccessIcon");
- PART_Icon.Glyph = "\xF13E";
- break;
- case InfoBarType.Warning:
- PART_Border.Background = (Brush)FindResource("InfoBarWarningBG");
- PART_IconBorder.Background = (Brush)FindResource("InfoBarWarningIcon");
- PART_Icon.Glyph = "\xF13C";
- break;
- case InfoBarType.Error:
- PART_Border.Background = (Brush)FindResource("InfoBarErrorBG");
- PART_IconBorder.Background = (Brush)FindResource("InfoBarErrorIcon");
- PART_Icon.Glyph = "\xF13D";
- break;
- default:
- PART_Border.Background = (Brush)FindResource("InfoBarInfoBG");
- PART_IconBorder.Background = (Brush)FindResource("InfoBarInfoIcon");
- PART_Icon.Glyph = "\xF13F";
- break;
- }
- }
-
- private static void OnIsIconVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var infoBar = (InfoBar)d;
- infoBar.UpdateIconVisibility();
- }
-
- private static void OnClosableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var infoBar = (InfoBar)d;
- infoBar.UpdateCloseButtonVisibility();
- }
-
- private void UpdateIconVisibility()
- {
- PART_IconBorder.Visibility = IsIconVisible ? Visibility.Visible : Visibility.Collapsed;
- }
-
- private void UpdateCloseButtonVisibility()
- {
- PART_CloseButton.Visibility = Closable ? Visibility.Visible : Visibility.Collapsed;
- }
- }
-
- public enum InfoBarType
- {
- Info,
- Success,
- Warning,
- Error
- }
-
- public enum InfoBarLength
- {
- Short,
- Long
- }
-}
diff --git a/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml b/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml
index 0842a64f3..eb0906c4c 100644
--- a/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml
+++ b/Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml
@@ -6,7 +6,7 @@
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:viewModel="clr-namespace:Flow.Launcher.ViewModel"
d:DataContext="{d:DesignInstance viewModel:PluginViewModel}"
d:DesignHeight="300"
@@ -66,6 +66,7 @@
Text="{DynamicResource priority}"
ToolTip="{DynamicResource priorityToolTip}" />
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern">
Segoe UI
@@ -26,6 +29,7 @@
{DynamicResource SettingWindowFont}
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+ 0,0,0,4
+ 10
+ 10
-
+ 12
+ 12
-
-
-
+ 154
-
-
-
-
-
-
-
-
-
-
- 0,0,0,4
- 12,6,0,6
- 11,5,32,6
- 32
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0,0,0,4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 8,5,8,6
-
-
-
-
-
-
-
-
-
0:0:0.0330:0:0.3670.1,0.9 0.2,1.0
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 40
- 4,4,4,4
- 1
- 1
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- F1 M 17.939453 5.439453 L 7.5 15.888672 L 2.060547 10.439453 L 2.939453 9.560547 L 7.5 14.111328 L 17.060547 4.560547 Z
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- M 5.029297 19.091797 L 14.111328 10 L 5.029297 0.908203 L 5.908203 0.029297 L 15.888672 10 L 5.908203 19.970703 Z
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
48
@@ -4104,134 +2153,6 @@
-
-
-
-
-
-
-
-
-
-
-
+
-
+
@@ -5138,7 +2576,7 @@
-
+
@@ -5163,10 +2601,8 @@
-
+
+
@@ -5249,13 +2685,13 @@
-
-
+
-
+
-
+
@@ -5489,14 +2925,12 @@
-
-
-
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Resources/Dark.xaml b/Flow.Launcher/Resources/Dark.xaml
index 3fd66d623..51d1e2b27 100644
--- a/Flow.Launcher/Resources/Dark.xaml
+++ b/Flow.Launcher/Resources/Dark.xaml
@@ -1,9 +1,9 @@
@@ -55,14 +55,12 @@
-
-
-
-
+
+
@@ -76,8 +74,6 @@
- #272727
-
#202020#2b2b2b#1d1d1d
@@ -107,29 +103,22 @@
#f5f5f5#464646#ffffff
-
- #272727
+
+
-
+
+
-
-
-
-
-
-
+
@@ -150,1522 +139,4 @@
0,0,0,01,1,1,1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1,1,1,1
- 0,0,0,0
- 1,1,1,1
- 1,1,1,1
-
-
-
-
-
-
-
- 1,1,1,1
- 0,0,0,1
-
-
- 4,4,4,4
- 4,4,4,4
-
-
-
-
-
-
-
-
- #FF000000
- #33000000
- #99000000
- #CC000000
- #66000000
- #FFFFFFFF
- #33FFFFFF
- #99FFFFFF
- #CCFFFFFF
- #66FFFFFF
- #45FFFFFF
- #FFF2F2F2
- #FF000000
- #33000000
- #66000000
- #CC000000
- #FF333333
- #FF858585
- #FF767676
- #FF171717
- #FF1F1F1F
- #FF323232
- #FF2B2B2B
- #FFFFFFFF
- #FF767676
- #19FFFFFF
- #33FFFFFF
- #FFF000
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 24
- 48
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 374
- 0
- 1
- 0,2,0,2
- -1,0,-1,0
- 12,11,0,13
-
-
-
- 12
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 64
- 1
- 1
- 0
- 0,4,0,4
- Normal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 11,5,11,7
- 11,11,11,13
- 11,11,11,13
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 160
- 240
- 480
- 198
-
-
-
-
-
-
-
- 1
- 0,0,0,1
- 0,1,0,0
- 0
- 0
- 0
-
-
- 1
- 1,1,1,0
- 1,0,1,1
-
-
-
- 320
- 548
- 184
- 756
- 130
- 202
- 32
- 32
- 56
- 1
- 0,0,4,0
- 0,0,0,0
- 0,0,0,0
- 0,0,0,0
- 0,24,0,0
- 0,0,0,12
- 24,18,24,24
-
-
-
-
-
-
- 0.6
- 0.8
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0,0,0,4
- 1
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- 758
- 456
- 40
- 96
- 240
- 1
- 0
- 12,11,12,12
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- 44
- 44
- 20
- 20
-
-
-
-
-
-
- -40.5
- 0.55
- 0.80
- 0.80
- 0.50
- 0.95
- 10.0
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
- 1
- 32
- 1
- 0,0
- 24,0,0,0
- 11,9,11,10
- 11,4,11,7
- 28,0,0,0
- 56,0,0,0
- 12,4,12,4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
- 0
-
-
-
-
-
-
-
- 0.8
- 1.0
- 0
- 2
-
-
- 24
- 40
- 14
- -25
- 12,0,12,0
- 12,0,12,0
- 0
- 0,6,0,0
- 12,14,0,13
- 350
- Bold
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0.6
- 4
- 0
- #33FFFFFF
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4
- 2
- 0
- 0,0,0,4
- Normal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
- 320
- 48
- 0,0,1,0
- 1,0,0,0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 80
- 1
- 1
- 0,0,0,4
- 0,0,20,0
- 20,0,0,0
- Normal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 12
- 1
- 8,5,8,7
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
- 64
- 1
- 2
- 0,9.5,0,9.5
- 0,0,-2,0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- False
-
-
-
-
-
\ No newline at end of file
diff --git a/Flow.Launcher/Resources/Light.xaml b/Flow.Launcher/Resources/Light.xaml
index 112815ed0..f196db299 100644
--- a/Flow.Launcher/Resources/Light.xaml
+++ b/Flow.Launcher/Resources/Light.xaml
@@ -1,9 +1,9 @@
@@ -51,12 +51,12 @@
-
+
@@ -71,8 +71,6 @@
- #f6f6f6
-
#f3f3f3#ffffff#e5e5e5
@@ -99,32 +97,22 @@
#f5f5f5#878787#1b1b1b
-
- #f6f6f6
-
-
+
+
-
+
-
-
-
-
-
-
+
@@ -145,1526 +133,4 @@
1,1,1,10,0,0,0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1,1,1,0
- 0,0,0,2
- 1,1,1,0
- 1,1,1,1
-
-
-
-
-
-
-
- 1,1,1,1
- 0,0,0,1
-
-
-
- 4,4,4,4
- 4,4,4,4
-
-
-
-
-
-
-
-
-
- #FFFFFFFF
- #33FFFFFF
- #99FFFFFF
- #CCFFFFFF
- #66FFFFFF
- #FF000000
- #33000000
- #99000000
- #CC000000
- #66000000
-
- #3E000000
- #FF171717
- #FF000000
- #33000000
- #66000000
- #CC000000
- #FFCCCCCC
- #FF7A7A7A
- #FFCCCCCC
- #FFF2F2F2
- #FFE6E6E6
- #FFE6E6E6
- #FFF2F2F2
- #FFFFFFFF
- #FF767676
- #19000000
- #33000000
- #C50500
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 24
- 48
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 374
- 0
- 1
- 0,2,0,2
- -1,0,-1,0
- 10,11,0,13
-
-
-
- 12
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 64
- 1
- 1
- 0
- 0,4,0,4
- Normal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 11,5,11,7
- 11,11,11,13
- 11,11,11,13
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 160
- 240
- 480
- 198
-
-
-
-
-
-
-
- 1
- 0,0,0,1
- 0,1,0,0
- 0
- 0
- 0
-
-
- 1
- 1,1,1,0
- 1,0,1,1
-
-
-
- 320
- 548
- 184
- 756
- 130
- 202
- 32
- 32
- 56
- 1
- 0,0,4,0
- 0,0,0,0
- 0,0,0,0
- 0,0,0,0
- 0,24,0,0
- 0,0,0,12
- 24,18,24,24
-
-
-
-
-
-
- 0.4
- 0.6
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0,0,0,4
- 1
- 0
- 0
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
- 758
- 456
- 40
- 96
- 240
- 1
- 0
- 12,11,12,12
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
- 44
- 44
- 20
- 20
-
-
-
-
-
-
- -40.5
- 0.55
- 0.80
- 0.80
- 0.50
- 0.95
- 10.0
- 4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
- 1
- 32
- 1
- 0,0
- 24,0,0,0
- 11,9,11,10
- 11,4,11,7
- 28,0,0,0
- 56,0,0,0
- 12,4,12,4
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
- 0
-
-
-
-
-
-
-
- 0.8
- 1.0
- 0
- 2
-
-
- 24
- 40
- 14
- -25
- 12,0,12,0
- 12,0,12,0
- 0
- 0,6,0,0
- 12,14,0,13
- 350
- Bold
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0.6
- 4
- 0
- #29C50500
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4
- 2
- 0
- 0,0,0,4
- Normal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
- 320
- 48
- 0,0,1,0
- 1,0,0,0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 80
- 1
- 1
- 0,0,0,4
- 0,0,20,0
- 20,0,0,0
- Normal
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 0
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 12
- 1
- 8,5,8,7
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 1
-
- 64
- 1
- 2
- 0,9.5,0,9.5
- 0,0,-2,0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- False
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/Flow.Launcher/Resources/Pages/WelcomePage1.xaml b/Flow.Launcher/Resources/Pages/WelcomePage1.xaml
index ea651d4ee..4b25f8cc4 100644
--- a/Flow.Launcher/Resources/Pages/WelcomePage1.xaml
+++ b/Flow.Launcher/Resources/Pages/WelcomePage1.xaml
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Title="WelcomePage1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d">
@@ -99,11 +99,11 @@
-
+
-
+
@@ -156,7 +156,8 @@
+ Text="{DynamicResource Welcome_Page1_Title}"
+ TextWrapping="WrapWithOverflow" />
-
+
diff --git a/Flow.Launcher/Resources/Pages/WelcomePage2.xaml b/Flow.Launcher/Resources/Pages/WelcomePage2.xaml
index cf0dff9ab..34fe1cdfc 100644
--- a/Flow.Launcher/Resources/Pages/WelcomePage2.xaml
+++ b/Flow.Launcher/Resources/Pages/WelcomePage2.xaml
@@ -7,7 +7,7 @@
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Title="WelcomePage2"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
mc:Ignorable="d">
@@ -34,11 +34,11 @@
-
+
-
+
@@ -89,12 +89,13 @@
-
-
+
+
+ Text="{DynamicResource Welcome_Page2_Title}"
+ TextWrapping="WrapWithOverflow" />
-
+
-
+
diff --git a/Flow.Launcher/Resources/Pages/WelcomePage3.xaml b/Flow.Launcher/Resources/Pages/WelcomePage3.xaml
index 0c1dcfea0..17396e680 100644
--- a/Flow.Launcher/Resources/Pages/WelcomePage3.xaml
+++ b/Flow.Launcher/Resources/Pages/WelcomePage3.xaml
@@ -4,9 +4,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Title="WelcomePage3"
VerticalAlignment="Stretch"
mc:Ignorable="d">
@@ -40,75 +41,97 @@
FontSize="20"
FontWeight="SemiBold"
Text="{DynamicResource Welcome_Page3_Title}" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/Flow.Launcher/Resources/Pages/WelcomePage4.xaml b/Flow.Launcher/Resources/Pages/WelcomePage4.xaml
index c319d7c6e..1ed09e4c2 100644
--- a/Flow.Launcher/Resources/Pages/WelcomePage4.xaml
+++ b/Flow.Launcher/Resources/Pages/WelcomePage4.xaml
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Title="WelcomePage4"
d:DesignHeight="450"
d:DesignWidth="800"
@@ -54,7 +54,7 @@
-
+
@@ -93,7 +93,8 @@
+ Text="{DynamicResource Welcome_Page4_Title}"
+ TextWrapping="WrapWithOverflow" />
-
+
diff --git a/Flow.Launcher/Resources/Pages/WelcomePage5.xaml b/Flow.Launcher/Resources/Pages/WelcomePage5.xaml
index 997f724b9..0ead07000 100644
--- a/Flow.Launcher/Resources/Pages/WelcomePage5.xaml
+++ b/Flow.Launcher/Resources/Pages/WelcomePage5.xaml
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
Title="WelcomePage5"
d:DesignHeight="450"
@@ -49,11 +49,11 @@
-
+
-
+
@@ -79,12 +79,13 @@
-
+
+ Text="{DynamicResource Welcome_Page5_Title}"
+ TextWrapping="WrapWithOverflow" />
-
+
diff --git a/Flow.Launcher/Resources/Pages/WelcomePage5.xaml.cs b/Flow.Launcher/Resources/Pages/WelcomePage5.xaml.cs
index 10cd18821..5e3ab6815 100644
--- a/Flow.Launcher/Resources/Pages/WelcomePage5.xaml.cs
+++ b/Flow.Launcher/Resources/Pages/WelcomePage5.xaml.cs
@@ -59,7 +59,7 @@ namespace Flow.Launcher.Resources.Pages
}
catch (Exception e)
{
- App.API.ShowMsgError(App.API.GetTranslation("setAutoStartFailed"), e.Message);
+ App.API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
}
}
diff --git a/Flow.Launcher/Resources/SettingWindowStyle.xaml b/Flow.Launcher/Resources/SettingWindowStyle.xaml
index 3ebd22c74..fc4a93224 100644
--- a/Flow.Launcher/Resources/SettingWindowStyle.xaml
+++ b/Flow.Launcher/Resources/SettingWindowStyle.xaml
@@ -2,39 +2,17 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
- xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core">
+ xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
+ xmlns:wpftk="clr-namespace:WpfToolkit.Controls;assembly=VirtualizingWrapPanel">
F1 M512,512z M0,0z M448,256C448,150,362,64,256,64L256,448C362,448,448,362,448,256z M0,256A256,256,0,1,1,512,256A256,256,0,1,1,0,256z
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml
index e469bb63b..e815c8735 100644
--- a/Flow.Launcher/ResultListBox.xaml
+++ b/Flow.Launcher/ResultListBox.xaml
@@ -25,6 +25,7 @@
SelectionChanged="OnSelectionChanged"
SelectionMode="Single"
Style="{DynamicResource BaseListboxStyle}"
+ VirtualizingPanel.ScrollUnit="Item"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
Visibility="{Binding Visibility}"
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/SelectBrowserWindow.xaml b/Flow.Launcher/SelectBrowserWindow.xaml
index 67c22b07d..8af33206c 100644
--- a/Flow.Launcher/SelectBrowserWindow.xaml
+++ b/Flow.Launcher/SelectBrowserWindow.xaml
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Flow.Launcher"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
Title="{DynamicResource defaultBrowserTitle}"
Width="550"
diff --git a/Flow.Launcher/SelectFileManagerWindow.xaml b/Flow.Launcher/SelectFileManagerWindow.xaml
index cd4bec424..b81b1b0f4 100644
--- a/Flow.Launcher/SelectFileManagerWindow.xaml
+++ b/Flow.Launcher/SelectFileManagerWindow.xaml
@@ -5,7 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Flow.Launcher"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
Title="{DynamicResource fileManagerWindow}"
Width="600"
@@ -75,9 +75,9 @@
-
+
-
+
file.Length);
- return $"{App.API.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})";
+ return $"{Localize.clearlogfolder()} ({BytesToReadableString(size)})";
}
}
@@ -34,7 +34,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
get
{
var size = GetCacheFiles().Sum(file => file.Length);
- return $"{App.API.GetTranslation("clearcachefolder")} ({BytesToReadableString(size)})";
+ return $"{Localize.clearcachefolder()} ({BytesToReadableString(size)})";
}
}
@@ -51,10 +51,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
_ => Constant.Version
};
- public string ActivatedTimes => string.Format(
- App.API.GetTranslation("about_activate_times"),
- _settings.ActivateTimes
- );
+ public string ActivatedTimes => Localize.about_activate_times(_settings.ActivateTimes);
public class LogLevelData : DropdownDataGeneric { }
@@ -98,8 +95,8 @@ public partial class SettingsPaneAboutViewModel : BaseModel
private void AskClearLogFolderConfirmation()
{
var confirmResult = App.API.ShowMsgBox(
- App.API.GetTranslation("clearlogfolderMessage"),
- App.API.GetTranslation("clearlogfolder"),
+ Localize.clearlogfolderMessage(),
+ Localize.clearlogfolder(),
MessageBoxButton.YesNo
);
@@ -107,7 +104,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
{
if (!ClearLogFolder())
{
- App.API.ShowMsgBox(App.API.GetTranslation("clearfolderfailMessage"));
+ App.API.ShowMsgBox(Localize.clearfolderfailMessage());
}
}
}
@@ -116,8 +113,8 @@ public partial class SettingsPaneAboutViewModel : BaseModel
private void AskClearCacheFolderConfirmation()
{
var confirmResult = App.API.ShowMsgBox(
- App.API.GetTranslation("clearcachefolderMessage"),
- App.API.GetTranslation("clearcachefolder"),
+ Localize.clearcachefolderMessage(),
+ Localize.clearcachefolder(),
MessageBoxButton.YesNo
);
@@ -125,7 +122,7 @@ public partial class SettingsPaneAboutViewModel : BaseModel
{
if (!ClearCacheFolder())
{
- App.API.ShowMsgBox(App.API.GetTranslation("clearfolderfailMessage"));
+ App.API.ShowMsgBox(Localize.clearfolderfailMessage());
}
}
}
@@ -327,4 +324,10 @@ public partial class SettingsPaneAboutViewModel : BaseModel
var releaseNotesWindow = new ReleaseNotesWindow();
releaseNotesWindow.Show();
}
+
+ [RelayCommand]
+ private void OpenSponsorPage()
+ {
+ App.API.OpenUrl(SponsorPage);
+ }
}
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
index 885330b8c..6641ac689 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
@@ -65,7 +65,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
}
catch (Exception e)
{
- App.API.ShowMsgError(App.API.GetTranslation("setAutoStartFailed"), e.Message);
+ App.API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
}
}
}
@@ -92,7 +92,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
}
catch (Exception e)
{
- App.API.ShowMsgError(App.API.GetTranslation("setAutoStartFailed"), e.Message);
+ App.API.ShowMsgError(Localize.setAutoStartFailed(), e.Message);
}
}
}
@@ -257,7 +257,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
else
{
// Since this is rarely seen text, language support is not provided.
- App.API.ShowMsgError(App.API.GetTranslation("KoreanImeSettingChangeFailTitle"), App.API.GetTranslation("KoreanImeSettingChangeFailSubTitle"));
+ App.API.ShowMsgError(Localize.KoreanImeSettingChangeFailTitle(), Localize.KoreanImeSettingChangeFailSubTitle());
}
}
}
@@ -325,10 +325,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
public List Languages => _translater.LoadAvailableLanguages();
- public string AlwaysPreviewToolTip => string.Format(
- App.API.GetTranslation("AlwaysPreviewToolTip"),
- Settings.PreviewHotkey
- );
+ public string AlwaysPreviewToolTip => Localize.AlwaysPreviewToolTip(Settings.PreviewHotkey);
private static string GetFileFromDialog(string title, string filter = "")
{
@@ -372,7 +369,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
private void SelectPython()
{
var selectedFile = GetFileFromDialog(
- App.API.GetTranslation("selectPythonExecutable"),
+ Localize.selectPythonExecutable(),
"Python|pythonw.exe"
);
@@ -384,7 +381,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
private void SelectNode()
{
var selectedFile = GetFileFromDialog(
- App.API.GetTranslation("selectNodeExecutable"),
+ Localize.selectNodeExecutable(),
"node|*.exe"
);
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs
index 8b0718ed4..2ec69e81a 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs
@@ -50,15 +50,13 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
var item = SelectedCustomPluginHotkey;
if (item is null)
{
- App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
+ App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
return;
}
var result = App.API.ShowMsgBox(
- string.Format(
- App.API.GetTranslation("deleteCustomHotkeyWarning"), item.Hotkey
- ),
- App.API.GetTranslation("delete"),
+ Localize.deleteCustomHotkeyWarning(item.Hotkey),
+ Localize.delete(),
MessageBoxButton.YesNo
);
@@ -75,7 +73,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
var item = SelectedCustomPluginHotkey;
if (item is null)
{
- App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
+ App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
return;
}
@@ -83,7 +81,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey);
if (settingItem == null)
{
- App.API.ShowMsgBox(App.API.GetTranslation("invalidPluginHotkey"));
+ App.API.ShowMsgBox(Localize.invalidPluginHotkey());
return;
}
@@ -117,15 +115,13 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
var item = SelectedCustomShortcut;
if (item is null)
{
- App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
+ App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
return;
}
var result = App.API.ShowMsgBox(
- string.Format(
- App.API.GetTranslation("deleteCustomShortcutWarning"), item.Key, item.Value
- ),
- App.API.GetTranslation("delete"),
+ Localize.deleteCustomShortcutWarning(item.Key, item.Value),
+ Localize.delete(),
MessageBoxButton.YesNo
);
@@ -141,7 +137,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
var item = SelectedCustomShortcut;
if (item is null)
{
- App.API.ShowMsgBox(App.API.GetTranslation("pleaseSelectAnItem"));
+ App.API.ShowMsgBox(Localize.pleaseSelectAnItem());
return;
}
@@ -149,7 +145,7 @@ public partial class SettingsPaneHotkeyViewModel : BaseModel
o.Key == item.Key && o.Value == item.Value);
if (settingItem == null)
{
- App.API.ShowMsgBox(App.API.GetTranslation("invalidShortcut"));
+ App.API.ShowMsgBox(Localize.invalidShortcut());
return;
}
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs
index f133b7d2b..d67695a75 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@@ -103,8 +103,8 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
private async Task InstallPluginAsync()
{
var file = GetFileFromDialog(
- App.API.GetTranslation("SelectZipFile"),
- $"{App.API.GetTranslation("ZipFiles")} (*.zip)|*.zip");
+ Localize.SelectZipFile(),
+ $"{Localize.ZipFiles()} (*.zip)|*.zip");
if (!string.IsNullOrEmpty(file))
await PluginInstaller.InstallPluginAndCheckRestartAsync(file);
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
index 3e1294bc2..2d418ee7e 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginsViewModel.cs
@@ -8,7 +8,7 @@ using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
-using ModernWpf.Controls;
+using iNKORE.UI.WPF.Modern.Controls;
#nullable enable
@@ -114,8 +114,11 @@ public partial class SettingsPanePluginsViewModel : BaseModel
}
}
- private IList? _pluginViewModels;
- public IList PluginViewModels => _pluginViewModels ??= PluginManager.AllPlugins
+ private List? _pluginViewModels;
+ // Get all plugins: Initializing & Initialized & Init failed plugins
+ // Include init failed ones so that we can uninstall them
+ // Include initializing ones so that we can change related settings like action keywords, etc.
+ public List PluginViewModels => _pluginViewModels ??= App.API.GetAllPlugins()
.OrderBy(plugin => plugin.Metadata.Disabled)
.ThenBy(plugin => plugin.Metadata.Name)
.Select(plugin => new PluginViewModel
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs
index 98dac499f..f69774e8e 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneThemeViewModel.cs
@@ -14,8 +14,7 @@ using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.ViewModel;
-using ModernWpf;
-using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;
+using iNKORE.UI.WPF.Modern;
namespace Flow.Launcher.SettingPages.ViewModels;
@@ -26,7 +25,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
private readonly Theme _theme;
private readonly string DefaultFont = Win32Helper.GetSystemDefaultFont();
- public string BackdropSubText => !Win32Helper.IsBackdropSupported() ? App.API.GetTranslation("BackdropTypeDisabledToolTip") : "";
+ public string BackdropSubText => !Win32Helper.IsBackdropSupported() ? Localize.BackdropTypeDisabledToolTip(): "";
public static string LinkHowToCreateTheme => @"https://www.flowlauncher.com/theme-builder/";
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
@@ -41,7 +40,11 @@ public partial class SettingsPaneThemeViewModel : BaseModel
set
{
_selectedTheme = value;
- App.API.SetCurrentTheme(value);
+ if (!App.API.SetCurrentTheme(value))
+ {
+ // Revert selection if failed to set theme
+ OnPropertyChanged();
+ }
// Update UI state
OnPropertyChanged(nameof(BackdropType));
@@ -127,12 +130,12 @@ public partial class SettingsPaneThemeViewModel : BaseModel
get => Settings.ColorScheme;
set
{
- ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme = value switch
+ ThemeManager.Current.ApplicationTheme = value switch
{
Constant.Light => ApplicationTheme.Light,
Constant.Dark => ApplicationTheme.Dark,
Constant.System => null,
- _ => ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme
+ _ => ThemeManager.Current.ApplicationTheme
};
Settings.ColorScheme = value;
_ = _theme.RefreshFrameAsync();
@@ -272,7 +275,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
public string PlaceholderTextTip
{
- get => string.Format(App.API.GetTranslation("PlaceholderTextTip"), App.API.GetTranslation("queryTextBoxPlaceholder"));
+ get => Localize.PlaceholderTextTip(Localize.queryTextBoxPlaceholder());
}
public string PlaceholderText
@@ -447,8 +450,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
{
new()
{
- Title = App.API.GetTranslation("SampleTitleExplorer"),
- SubTitle = App.API.GetTranslation("SampleSubTitleExplorer"),
+ Title = Localize.SampleTitleExplorer(),
+ SubTitle = Localize.SampleSubTitleExplorer(),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png"
@@ -456,8 +459,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
},
new()
{
- Title = App.API.GetTranslation("SampleTitleWebSearch"),
- SubTitle = App.API.GetTranslation("SampleSubTitleWebSearch"),
+ Title = Localize.SampleTitleWebSearch(),
+ SubTitle = Localize.SampleSubTitleWebSearch(),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png"
@@ -465,8 +468,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
},
new()
{
- Title = App.API.GetTranslation("SampleTitleProgram"),
- SubTitle = App.API.GetTranslation("SampleSubTitleProgram"),
+ Title = Localize.SampleTitleProgram(),
+ SubTitle = Localize.SampleSubTitleProgram(),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.Program\Images\program.png"
@@ -474,8 +477,8 @@ public partial class SettingsPaneThemeViewModel : BaseModel
},
new()
{
- Title = App.API.GetTranslation("SampleTitleProcessKiller"),
- SubTitle = App.API.GetTranslation("SampleSubTitleProcessKiller"),
+ Title = Localize.SampleTitleProcessKiller(),
+ SubTitle = Localize.SampleSubTitleProcessKiller(),
IcoPath = Path.Combine(
Constant.ProgramDirectory,
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png"
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml
index 5710138c0..4801caa36 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml
@@ -4,9 +4,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
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:settingsVm="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
Title="About"
d:DataContext="{d:DesignInstance Type=settingsVm:SettingsPaneAboutViewModel}"
d:DesignHeight="450"
@@ -17,9 +18,7 @@
-
@@ -31,80 +30,80 @@
Text="{DynamicResource about}"
TextAlignment="left" />
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
+
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml.cs b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml.cs
index 47532b243..07aaace14 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml.cs
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml.cs
@@ -28,10 +28,4 @@ public partial class SettingsPaneAbout
}
base.OnNavigatedTo(e);
}
-
- private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
- {
- App.API.OpenUrl(e.Uri.AbsoluteUri);
- e.Handled = true;
- }
}
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
index 07cc7b6a7..4ab0ef330 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
@@ -6,9 +6,10 @@
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ext="clr-namespace:Flow.Launcher.Resources.MarkupExtensions"
+ xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:settingsViewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
Title="General"
d:DataContext="{d:DesignInstance settingsViewModels:SettingsPaneGeneralViewModel}"
@@ -18,9 +19,7 @@
-
@@ -33,272 +32,303 @@
Text="{DynamicResource general}"
TextAlignment="left" />
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
+
+
+
-
+
-
+
-
-
+ Description="{DynamicResource showAtTopmostToolTip}"
+ Header="{DynamicResource showAtTopmost}">
+
+
+
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+ Text="x" />
+
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Description="{DynamicResource ignoreHotkeysOnFullscreenToolTip}"
+ Header="{DynamicResource ignoreHotkeysOnFullscreen}">
+
+
+
+
-
+
-
+ Description="{Binding AlwaysPreviewToolTip}"
+ Header="{DynamicResource AlwaysPreview}">
+
+
+
+
-
+
-
+ Description="{DynamicResource autoUpdatesTooltip}"
+ Header="{DynamicResource autoUpdates}">
+
+
+
+
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Description="{DynamicResource querySearchPrecisionToolTip}"
+ Header="{DynamicResource querySearchPrecision}">
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+ Description="{DynamicResource searchDelayToolTip}"
+ Header="{DynamicResource searchDelay}">
+
+
+
-
+
+
+
+
+
+
+
+
+
+ Description="{DynamicResource homePageToolTip}"
+ Header="{DynamicResource homePage}">
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+ Description="{DynamicResource defaultFileManagerToolTip}"
+ Header="{DynamicResource defaultFileManager}">
+
+
+
+
-
+
+
+
+
+
+
-
-
+
-
+
-
+
-
+
-
+
-
+ Description="{DynamicResource typingStartEnTooltip}"
+ Header="{DynamicResource typingStartEn}">
+
+
+
+
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
+ IsEqualToBool=True}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
-
+
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml
index d82d6baa0..e8b445cee 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml
@@ -5,8 +5,9 @@
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
+ xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
Title="Hotkey"
@@ -14,7 +15,7 @@
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
-
-
+
+
+
+
+
-
+
+
+
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+ Description="{DynamicResource openResultModifiersToolTip}"
+ Header="{DynamicResource openResultModifiers}">
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+ Description="{DynamicResource hotkeyPresetsToolTip}"
+ Header="{DynamicResource hotkeyPresets}">
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
+ Description="{DynamicResource autoCompleteHotkeyToolTip}"
+ Header="{DynamicResource autoCompleteHotkey}">
+
+
+
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Style="{StaticResource SettingSeparatorStyle}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+ BorderThickness="1"
+ Style="{StaticResource SettingSeparatorStyle}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Style="{StaticResource SettingSeparatorStyle}" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
+
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml b/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml
index c73369fcd..aa027e19e 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml
@@ -3,9 +3,10 @@
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:sys="clr-namespace:System;assembly=mscorlib"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
xmlns:wpftk="clr-namespace:WpfToolkit.Controls;assembly=VirtualizingWrapPanel"
Title="PluginStore"
@@ -51,21 +52,22 @@
Grid.Column="1"
Margin="5 24 0 0">
-
+ Orientation="Horizontal"
+ Spacing="8">
-
+
@@ -94,14 +96,12 @@
@@ -112,48 +112,19 @@
Height="34"
Margin="0 0 26 0"
HorizontalAlignment="Right"
+ VerticalContentAlignment="Center"
+ ui:ControlHelper.PlaceholderText="{DynamicResource searchplugin}"
ContextMenu="{StaticResource TextBoxContextMenu}"
DockPanel.Dock="Right"
FontSize="14"
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
- TextAlignment="Left"
ToolTip="{DynamicResource searchpluginToolTip}"
ToolTipService.InitialShowDelay="200"
- ToolTipService.Placement="Top">
-
-
-
-
-
-
+ ToolTipService.Placement="Top" />
+
-
-
+ VirtualizingPanel.ScrollUnit="Pixel"
+ VirtualizingPanel.VirtualizationMode="Recycling">
+
-
-
+
+
+
-
-
-
+ ToolTipService.Placement="Top" />
+
-
-
+
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
-
+
-
+
-
+
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml
index 796a08fdc..20b8dfb9c 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml
@@ -6,8 +6,9 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ext="clr-namespace:Flow.Launcher.Resources.MarkupExtensions"
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
+ xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
Title="Theme"
@@ -23,9 +24,8 @@
-
@@ -89,10 +89,8 @@
-
+
+
-
+
@@ -396,310 +394,323 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ Header="{DynamicResource theme}">
+
+
+
-
-
-
-
+
-
+ Data="{DynamicResource circle_half_stroke_solid}"
+ ToolTip="{DynamicResource TypeIsDarkToolTip}"
+ ToolTipService.InitialShowDelay="0"
+ Visibility="{Binding SelectedTheme.IsDark, Converter={StaticResource BoolToVisibilityConverter}}" />
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Content="{DynamicResource browserMoreThemes}"
+ NavigateUri="{Binding LinkThemeGallery}" />
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Severity="Warning" />
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+ Description="{DynamicResource ShowPlaceholderTip}"
+ Header="{DynamicResource ShowPlaceholder}">
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+ Description="{DynamicResource AnimationTip}"
+ Header="{DynamicResource Animation}">
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ Description="{DynamicResource SoundEffectTip}"
+ Header="{DynamicResource SoundEffect}">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ Description="{DynamicResource useGlyphUIEffect}"
+ Header="{DynamicResource useGlyphUI}">
+
+
+
+
-
+
-
-
-
-
-
-
-
-
+ Description="{DynamicResource showBadgesToolTip}"
+ Header="{DynamicResource showBadges}">
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
-
+
-
+
+
+
+
+
-
+
-
+ Content="{DynamicResource howToCreateTheme}"
+ NavigateUri="{Binding LinkHowToCreateTheme}" />
-
+
diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml
index da128266c..9bc3d496e 100644
--- a/Flow.Launcher/SettingWindow.xaml
+++ b/Flow.Launcher/SettingWindow.xaml
@@ -4,7 +4,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
Title="{DynamicResource flowlauncher_settings}"
Width="{Binding SettingWindowWidth, Mode=TwoWay}"
@@ -266,8 +266,5 @@
-
-
-
diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs
index 0e3e69996..a318592a6 100644
--- a/Flow.Launcher/SettingWindow.xaml.cs
+++ b/Flow.Launcher/SettingWindow.xaml.cs
@@ -3,14 +3,13 @@ using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
-using System.Windows.Interop;
using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.SettingPages.Views;
using Flow.Launcher.ViewModel;
-using ModernWpf.Controls;
+using iNKORE.UI.WPF.Modern.Controls;
namespace Flow.Launcher;
@@ -43,12 +42,6 @@ public partial class SettingWindow
{
RefreshMaximizeRestoreButton();
- // Fix (workaround) for the window freezes after lock screen (Win+L) or sleep
- // https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf
- HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
- HwndTarget hwndTarget = hwndSource.CompositionTarget;
- hwndTarget.RenderMode = RenderMode.SoftwareOnly; // Must use software only render mode here
-
UpdatePositionAndState();
_viewModel.PropertyChanged += ViewModel_PropertyChanged;
diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs
index a5383b179..339f7b91e 100644
--- a/Flow.Launcher/Storage/QueryHistory.cs
+++ b/Flow.Launcher/Storage/QueryHistory.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
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/Themes/Base.xaml b/Flow.Launcher/Themes/Base.xaml
index a5ded7e59..c5b45890b 100644
--- a/Flow.Launcher/Themes/Base.xaml
+++ b/Flow.Launcher/Themes/Base.xaml
@@ -1,7 +1,9 @@
00
@@ -46,20 +48,20 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
-
-
+
-
-
+
+
@@ -250,9 +252,12 @@
-
-
-
-
+
-
+
diff --git a/Flow.Launcher/Themes/BlurWhite.xaml b/Flow.Launcher/Themes/BlurWhite.xaml
index 25cbfe9c9..43cd8f4b5 100644
--- a/Flow.Launcher/Themes/BlurWhite.xaml
+++ b/Flow.Launcher/Themes/BlurWhite.xaml
@@ -15,7 +15,7 @@
#BFFAFAFA#BFFAFAFA0 0 0 8
-
+
-
+
@@ -169,7 +169,7 @@
x:Key="ClockPanel"
BasedOn="{StaticResource ClockPanel}"
TargetType="{x:Type StackPanel}">
-
+
-
+
@@ -149,7 +149,7 @@
x:Key="ClockPanel"
BasedOn="{StaticResource ClockPanel}"
TargetType="{x:Type StackPanel}">
-
+
-
+