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;