diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs
index 46c72624a..5a6633525 100644
--- a/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs
+++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginV2.cs
@@ -139,11 +139,20 @@ namespace Flow.Launcher.Core.Plugin
return Task.CompletedTask;
}
- public virtual ValueTask DisposeAsync()
+ public virtual async ValueTask DisposeAsync()
{
- RPC?.Dispose();
- ErrorStream?.Dispose();
- return ValueTask.CompletedTask;
+ try
+ {
+ await RPC.InvokeAsync("close");
+ }
+ catch (RemoteMethodNotFoundException e)
+ {
+ }
+ finally
+ {
+ RPC?.Dispose();
+ ErrorStream?.Dispose();
+ }
}
}
}
diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index aeb492162..6528f626c 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -188,32 +188,16 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public bool AlwaysPreview { get; set; } = false;
public bool AlwaysStartEn { get; set; } = false;
+ private SearchPrecisionScore _querySearchPrecision = SearchPrecisionScore.Regular;
[JsonInclude, JsonConverter(typeof(JsonStringEnumConverter))]
- public SearchPrecisionScore QuerySearchPrecision { get; private set; } = SearchPrecisionScore.Regular;
-
- [JsonIgnore]
- public string QuerySearchPrecisionString
+ public SearchPrecisionScore QuerySearchPrecision
{
- get { return QuerySearchPrecision.ToString(); }
+ get => _querySearchPrecision;
set
{
- try
- {
- var precisionScore = (SearchPrecisionScore)Enum
- .Parse(typeof(SearchPrecisionScore), value);
-
- QuerySearchPrecision = precisionScore;
- StringMatcher.Instance.UserSettingSearchPrecision = precisionScore;
- }
- catch (ArgumentException e)
- {
- Logger.Log.Exception(nameof(Settings), "Failed to load QuerySearchPrecisionString value from Settings file", e);
-
- QuerySearchPrecision = SearchPrecisionScore.Regular;
- StringMatcher.Instance.UserSettingSearchPrecision = SearchPrecisionScore.Regular;
-
- throw;
- }
+ _querySearchPrecision = value;
+ if (StringMatcher.Instance != null)
+ StringMatcher.Instance.UserSettingSearchPrecision = value;
}
}
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index 68401898f..28b516757 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -79,6 +79,9 @@
When the icon is hidden from the tray, the Settings menu can be opened by right-clicking on the search window.
Query Search Precision
Changes minimum match score required for results.
+ None
+ Low
+ Regular
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
Always Preview
diff --git a/Flow.Launcher/Languages/ru.xaml b/Flow.Launcher/Languages/ru.xaml
index 08da85991..739252da7 100644
--- a/Flow.Launcher/Languages/ru.xaml
+++ b/Flow.Launcher/Languages/ru.xaml
@@ -1,5 +1,8 @@
-
-
+
+
Не удалось зарегистрировать сочетание клавиш "{0}". Возможно, оно используется другой программой. Измените сочетание клавиш или закройте другую программу.
Flow Launcher
@@ -75,6 +78,9 @@
Когда значок скрыт в трее, меню настройки можно открыть, щёлкнув правой кнопкой мыши на окне поиска.
Точность поиска запросов
Изменение минимального количества совпадений при поиске, необходимого для получения результатов.
+ Нет
+ Низкая
+ Обычная
Поиск с использованием пиньинь
Позволяет использовать пиньинь для поиска. Пиньинь - это стандартная система латинизированной орфографии для перевода китайского языка.
Всегда предпросмотр
diff --git a/Flow.Launcher/SettingPages/ViewModels/DropdownDataGeneric.cs b/Flow.Launcher/SettingPages/ViewModels/DropdownDataGeneric.cs
index 025c73f85..15a814436 100644
--- a/Flow.Launcher/SettingPages/ViewModels/DropdownDataGeneric.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/DropdownDataGeneric.cs
@@ -8,7 +8,8 @@ namespace Flow.Launcher.SettingPages.ViewModels;
public class DropdownDataGeneric : BaseModel where TValue : Enum
{
public string Display { get; set; }
- public TValue Value { get; set; }
+ public TValue Value { get; private init; }
+ private string LocalizationKey { get; init; }
public static List GetValues
(string keyPrefix) where TR : DropdownDataGeneric, new()
{
@@ -19,9 +20,17 @@ public class DropdownDataGeneric : BaseModel where TValue : Enum
{
var key = keyPrefix + value;
var display = InternationalizationManager.Instance.GetTranslation(key);
- data.Add(new TR { Display = display, Value = value });
+ data.Add(new TR { Display = display, Value = value, LocalizationKey = key });
}
return data;
}
+
+ public static void UpdateLabels(List
options) where TR : DropdownDataGeneric
+ {
+ foreach (var item in options)
+ {
+ item.Display = InternationalizationManager.Instance.GetTranslation(item.LocalizationKey);
+ }
+ }
}
diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
index 7afb2d995..99aafc8e6 100644
--- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
+++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs
@@ -24,13 +24,13 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
Settings = settings;
_updater = updater;
_portable = portable;
- UpdateLastQueryModeDisplay();
+ UpdateEnumDropdownLocalizations();
}
- public class SearchWindowScreen : DropdownDataGeneric { }
- public class SearchWindowAlign : DropdownDataGeneric { }
- // todo a better name?
- public class LastQueryMode : DropdownDataGeneric { }
+ public class SearchWindowScreenData : DropdownDataGeneric { }
+ public class SearchWindowAlignData : DropdownDataGeneric { }
+ public class SearchPrecisionData : DropdownDataGeneric { }
+ public class LastQueryModeData : DropdownDataGeneric { }
public bool StartFlowLauncherOnSystemStartup
{
@@ -55,11 +55,14 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
}
- public List SearchWindowScreens =>
- DropdownDataGeneric.GetValues("SearchWindowScreen");
+ public List SearchWindowScreens { get; } =
+ DropdownDataGeneric.GetValues("SearchWindowScreen");
- public List SearchWindowAligns =>
- DropdownDataGeneric.GetValues("SearchWindowAlign");
+ public List SearchWindowAligns { get; } =
+ DropdownDataGeneric.GetValues("SearchWindowAlign");
+
+ public List SearchPrecisionScores { get; } =
+ DropdownDataGeneric.GetValues("SearchPrecision");
public List ScreenNumbers
{
@@ -98,29 +101,15 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
}
}
- private List _lastQueryModes = new();
+ public List LastQueryModes { get; } =
+ DropdownDataGeneric.GetValues("LastQuery");
- public List LastQueryModes
+ private void UpdateEnumDropdownLocalizations()
{
- get
- {
- if (_lastQueryModes.Count == 0)
- {
- _lastQueryModes =
- DropdownDataGeneric
- .GetValues("LastQuery");
- }
-
- return _lastQueryModes;
- }
- }
-
- private void UpdateLastQueryModeDisplay()
- {
- foreach (var item in LastQueryModes)
- {
- item.Display = InternationalizationManager.Instance.GetTranslation($"LastQuery{item.Value}");
- }
+ DropdownDataGeneric.UpdateLabels(SearchWindowScreens);
+ DropdownDataGeneric.UpdateLabels(SearchWindowAligns);
+ DropdownDataGeneric.UpdateLabels(SearchPrecisionScores);
+ DropdownDataGeneric.UpdateLabels(LastQueryModes);
}
public string Language
@@ -133,7 +122,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
if (InternationalizationManager.Instance.PromptShouldUsePinyin(value))
ShouldUsePinyin = true;
- UpdateLastQueryModeDisplay();
+ UpdateEnumDropdownLocalizations();
}
}
@@ -143,12 +132,6 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
set => Settings.ShouldUsePinyin = value;
}
- public List QuerySearchPrecisionStrings => Enum
- .GetValues(typeof(SearchPrecisionScore))
- .Cast()
- .Select(v => v.ToString())
- .ToList();
-
public List Languages => InternationalizationManager.Instance.LoadAvailableLanguages();
public string AlwaysPreviewToolTip => string.Format(
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
index c2b23a295..6b301e33a 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
@@ -30,19 +30,31 @@
TextAlignment="left" />
-
+
-
+
-
+
-
+
@@ -111,7 +123,10 @@
Title="{DynamicResource ignoreHotkeysOnFullscreen}"
Icon=""
Sub="{DynamicResource ignoreHotkeysOnFullscreenToolTip}">
-
+
-
+
-
+
-
+
+ DisplayMemberPath="Display"
+ ItemsSource="{Binding SearchPrecisionScores}"
+ SelectedValue="{Binding Settings.QuerySearchPrecision}"
+ SelectedValuePath="Value" />
@@ -211,14 +238,21 @@
Margin="0 30 0 0"
Icon=""
Sub="{DynamicResource typingStartEnTooltip}">
-
+
-
+
-
-
+
+
diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneProxy.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneProxy.xaml
index 63a43a8fb..768abbf97 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneProxy.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneProxy.xaml
@@ -33,7 +33,10 @@
-
+
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
index d7e87b50b..25ceac3bb 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
@@ -32,6 +32,8 @@
When 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
+ Hide uninstallers
+ Hides programs with common uninstaller names, such as unins000.exe
Search in Program Description
Flow will search program's description
Suffixes
@@ -92,4 +94,4 @@
This app is not intended to be run as administrator
Unable to run {0}
-
\ No newline at end of file
+
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs
index e0a7f23de..8bf1830e3 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs
@@ -11,6 +11,7 @@ using Flow.Launcher.Plugin.Program.Programs;
using Flow.Launcher.Plugin.Program.Views;
using Flow.Launcher.Plugin.Program.Views.Models;
using Microsoft.Extensions.Caching.Memory;
+using Path = System.IO.Path;
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
namespace Flow.Launcher.Plugin.Program
@@ -33,6 +34,17 @@ namespace Flow.Launcher.Plugin.Program
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
private static MemoryCache cache = new(cacheOptions);
+ private static readonly string[] commonUninstallerNames =
+ {
+ "uninst.exe",
+ "unins000.exe",
+ "uninst000.exe",
+ "uninstall.exe"
+ };
+ // For cases when the uninstaller is named like "Uninstall Program Name.exe"
+ private const string CommonUninstallerPrefix = "uninstall";
+ private const string CommonUninstallerSuffix = ".exe";
+
static Main()
{
}
@@ -52,6 +64,7 @@ namespace Flow.Launcher.Plugin.Program
.Concat(_uwps)
.AsParallel()
.WithCancellation(token)
+ .Where(HideUninstallersFilter)
.Where(p => p.Enabled)
.Select(p => p.Result(query.Search, Context.API))
.Where(r => r?.Score > 0)
@@ -68,6 +81,16 @@ namespace Flow.Launcher.Plugin.Program
return result;
}
+ private bool HideUninstallersFilter(IProgram program)
+ {
+ if (!_settings.HideUninstallers) return true;
+ if (program is not Win32 win32) return true;
+ var fileName = Path.GetFileName(win32.ExecutablePath);
+ return !commonUninstallerNames.Contains(fileName, StringComparer.OrdinalIgnoreCase) &&
+ !(fileName.StartsWith(CommonUninstallerPrefix, StringComparison.OrdinalIgnoreCase) &&
+ fileName.EndsWith(CommonUninstallerSuffix, StringComparison.OrdinalIgnoreCase));
+ }
+
public async Task InitAsync(PluginInitContext context)
{
Context = context;
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
index ca203f803..fb24f64d7 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
@@ -102,7 +102,7 @@ namespace Flow.Launcher.Plugin.Program
// CustomSuffixes no longer contains custom suffixes
// users has tweaked the settings
// or this function has been executed once
- if (UseCustomSuffixes == true || ProgramSuffixes == null)
+ if (UseCustomSuffixes == true || ProgramSuffixes == null)
return;
var suffixes = ProgramSuffixes.ToList();
foreach(var item in BuiltinSuffixesStatus)
@@ -117,6 +117,7 @@ namespace Flow.Launcher.Plugin.Program
public bool EnableStartMenuSource { get; set; } = true;
public bool EnableDescription { get; set; } = false;
public bool HideAppsPath { get; set; } = true;
+ public bool HideUninstallers { get; set; } = false;
public bool EnableRegistrySource { get; set; } = true;
public bool EnablePathSource { get; set; } = false;
public bool EnableUWP { get; set; } = true;
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
index fa97de4f2..e5ca6967e 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
@@ -85,6 +85,11 @@
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
IsChecked="{Binding HideAppsPath}"
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
+
ProgramSettingDisplayList { get; set; }
public bool EnableDescription
@@ -47,6 +47,16 @@ namespace Flow.Launcher.Plugin.Program.Views
}
}
+ public bool HideUninstallers
+ {
+ get => _settings.HideUninstallers;
+ set
+ {
+ Main.ResetCache();
+ _settings.HideUninstallers = value;
+ }
+ }
+
public bool EnableRegistrySource
{
get => _settings.EnableRegistrySource;