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}" />
+
@@ -142,7 +145,7 @@
Minimum="0" />
@@ -151,7 +154,7 @@
+ Margin="0 0 20 0">
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs
index 36b5acc8acb..91864cb680c 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs
@@ -57,6 +57,16 @@ public bool HideUninstallers
}
}
+ public bool HideDuplicatedWindowsApp
+ {
+ get => _settings.HideDuplicatedWindowsApp;
+ set
+ {
+ Main.ResetCache();
+ _settings.HideDuplicatedWindowsApp = value;
+ }
+ }
+
public bool EnableRegistrySource
{
get => _settings.EnableRegistrySource;