diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml index 7ed711e172e..790c9d2c621 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml @@ -36,6 +36,8 @@ Hides programs with common uninstaller names, such as unins000.exe Search in Program Description Flow will search program's description + Hide duplicated apps + Hide duplicated Win32 programs that are already in the UWP list Suffixes Max Depth diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 6ba7047f23e..65af0b56c35 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -72,6 +72,8 @@ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, I private const string ExeUninstallerSuffix = ".exe"; private const string InkUninstallerSuffix = ".lnk"; + private static readonly string WindowsAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WindowsApps"); + static Main() { } @@ -90,11 +92,20 @@ public async Task> QueryAsync(Query query, CancellationToken token) { try { + // Collect all UWP Windows app directories + var uwpsDirectories = _settings.HideDuplicatedWindowsApp ? _uwps + .Where(uwp => !string.IsNullOrEmpty(uwp.Location)) // Exclude invalid paths + .Where(uwp => uwp.Location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) // Keep system apps + .Select(uwp => uwp.Location.TrimEnd('\\')) // Remove trailing slash + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToArray() : null; + return _win32s.Cast() .Concat(_uwps) .AsParallel() .WithCancellation(token) .Where(HideUninstallersFilter) + .Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories)) .Where(p => p.Enabled) .Select(p => p.Result(query.Search, Context.API)) .Where(r => r?.Score > 0) @@ -152,6 +163,23 @@ private bool HideUninstallersFilter(IProgram program) return true; } + private static bool HideDuplicatedWindowsAppFilter(IProgram program, string[] uwpsDirectories) + { + if (uwpsDirectories == null || uwpsDirectories.Length == 0) return true; + if (program is UWPApp) return true; + + var location = program.Location.TrimEnd('\\'); // Ensure trailing slash + if (string.IsNullOrEmpty(location)) + return true; // Keep if location is invalid + + if (!location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) + return true; // Keep if not a Windows app + + // Check if the any Win32 executable directory contains UWP Windows app location matches + return !uwpsDirectories.Any(uwpDirectory => + location.StartsWith(uwpDirectory, 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 fb24f64d7d6..b2aad63b325 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs @@ -121,6 +121,7 @@ private void RemoveRedundantSuffixes() public bool EnableRegistrySource { get; set; } = true; public bool EnablePathSource { get; set; } = false; public bool EnableUWP { get; set; } = true; + public bool HideDuplicatedWindowsApp { get; set; } = false; internal const char SuffixSeparator = ';'; } diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml index e5ca6967e73..973ac9f60af 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml @@ -8,7 +8,7 @@ DataContext="{Binding RelativeSource={RelativeSource Self}}" mc:Ignorable="d"> - + @@ -18,40 +18,40 @@ + ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}" + Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}" /> @@ -67,21 +67,20 @@ BorderBrush="{DynamicResource Color03B}" BorderThickness="1" /> @@ -91,11 +90,15 @@ IsChecked="{Binding HideUninstallers}" ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" /> +