mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #3259 from Jack251970/remove_duplicated_programs
Support removing duplicated programs
This commit is contained in:
commit
e028ed399f
5 changed files with 69 additions and 25 deletions
|
|
@ -36,6 +36,8 @@
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_hideuninstallers_tooltip">Hides programs with common uninstaller names, such as unins000.exe</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_hideuninstallers_tooltip">Hides programs with common uninstaller names, such as unins000.exe</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_description_tooltip">Flow will search program's description</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_description_tooltip">Flow will search program's description</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_enable_hideduplicatedwindowsapp">Hide duplicated apps</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_enable_hideduplicatedwindowsapp_tooltip">Hide duplicated Win32 programs that are already in the UWP list</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_header">Suffixes</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_header">Suffixes</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_max_depth_header">Max Depth</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_max_depth_header">Max Depth</system:String>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
private const string ExeUninstallerSuffix = ".exe";
|
private const string ExeUninstallerSuffix = ".exe";
|
||||||
private const string InkUninstallerSuffix = ".lnk";
|
private const string InkUninstallerSuffix = ".lnk";
|
||||||
|
|
||||||
|
private static readonly string WindowsAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WindowsApps");
|
||||||
|
|
||||||
static Main()
|
static Main()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -90,11 +92,20 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
try
|
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<IProgram>()
|
return _win32s.Cast<IProgram>()
|
||||||
.Concat(_uwps)
|
.Concat(_uwps)
|
||||||
.AsParallel()
|
.AsParallel()
|
||||||
.WithCancellation(token)
|
.WithCancellation(token)
|
||||||
.Where(HideUninstallersFilter)
|
.Where(HideUninstallersFilter)
|
||||||
|
.Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories))
|
||||||
.Where(p => p.Enabled)
|
.Where(p => p.Enabled)
|
||||||
.Select(p => p.Result(query.Search, Context.API))
|
.Select(p => p.Result(query.Search, Context.API))
|
||||||
.Where(r => r?.Score > 0)
|
.Where(r => r?.Score > 0)
|
||||||
|
|
@ -152,6 +163,23 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
return true;
|
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)
|
public async Task InitAsync(PluginInitContext context)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
public bool EnableRegistrySource { get; set; } = true;
|
public bool EnableRegistrySource { get; set; } = true;
|
||||||
public bool EnablePathSource { get; set; } = false;
|
public bool EnablePathSource { get; set; } = false;
|
||||||
public bool EnableUWP { get; set; } = true;
|
public bool EnableUWP { get; set; } = true;
|
||||||
|
public bool HideDuplicatedWindowsApp { get; set; } = false;
|
||||||
|
|
||||||
internal const char SuffixSeparator = ';';
|
internal const char SuffixSeparator = ';';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
|
@ -18,40 +18,40 @@
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Margin="70,10,0,8"
|
Margin="70 10 0 8"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
LastChildFill="True">
|
LastChildFill="True">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="0,5,10,0"
|
Margin="0 5 10 0"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="0,0,14,0"
|
Margin="0 0 14 0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="UWPEnabled"
|
Name="UWPEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_uwp}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_uwp}"
|
||||||
IsChecked="{Binding EnableUWP}"
|
IsChecked="{Binding EnableUWP}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}"
|
||||||
|
Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="StartMenuEnabled"
|
Name="StartMenuEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
||||||
IsChecked="{Binding EnableStartMenuSource}"
|
IsChecked="{Binding EnableStartMenuSource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="RegistryEnabled"
|
Name="RegistryEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
||||||
IsChecked="{Binding EnableRegistrySource}"
|
IsChecked="{Binding EnableRegistrySource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="PATHEnabled"
|
Name="PATHEnabled"
|
||||||
Margin="12,0,12,0"
|
Margin="12 0 12 0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
||||||
IsChecked="{Binding EnablePATHSource}"
|
IsChecked="{Binding EnablePATHSource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
||||||
|
|
@ -67,21 +67,20 @@
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
BorderThickness="1" />
|
BorderThickness="1" />
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Margin="70,10,0,8"
|
Margin="70 10 0 8"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
LastChildFill="True">
|
LastChildFill="True">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="0,5,10,0"
|
Margin="0 5 10 0"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="0,0,14,0"
|
Margin="0 0 14 0"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="HideLnkEnabled"
|
Margin="12 0 12 0"
|
||||||
Margin="12,0,12,0"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
||||||
IsChecked="{Binding HideAppsPath}"
|
IsChecked="{Binding HideAppsPath}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
||||||
|
|
@ -91,11 +90,15 @@
|
||||||
IsChecked="{Binding HideUninstallers}"
|
IsChecked="{Binding HideUninstallers}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="DescriptionEnabled"
|
Margin="12 0 12 0"
|
||||||
Margin="12,0,12,0"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
||||||
IsChecked="{Binding EnableDescription}"
|
IsChecked="{Binding EnableDescription}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
||||||
|
<CheckBox
|
||||||
|
Margin="12 0 12 0"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp}"
|
||||||
|
IsChecked="{Binding HideDuplicatedWindowsApp}"
|
||||||
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp_tooltip}" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Separator
|
<Separator
|
||||||
|
|
@ -103,28 +106,28 @@
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
BorderThickness="1" />
|
BorderThickness="1" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Margin="60,0,0,2"
|
Margin="60 0 0 2"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnLoadAllProgramSource"
|
x:Name="btnLoadAllProgramSource"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="10,10,5,10"
|
Margin="10 10 5 10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="btnLoadAllProgramSource_OnClick"
|
Click="btnLoadAllProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_all_programs}" />
|
Content="{DynamicResource flowlauncher_plugin_program_all_programs}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnProgramSuffixes"
|
x:Name="btnProgramSuffixes"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="5,10,5,10"
|
Margin="5 10 5 10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="BtnProgramSuffixes_OnClick"
|
Click="BtnProgramSuffixes_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_suffixes}" />
|
Content="{DynamicResource flowlauncher_plugin_program_suffixes}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnReindex"
|
x:Name="btnReindex"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="5,10,5,10"
|
Margin="5 10 5 10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="btnReindex_Click"
|
Click="btnReindex_Click"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_reindex}" />
|
Content="{DynamicResource flowlauncher_plugin_program_reindex}" />
|
||||||
|
|
@ -142,7 +145,7 @@
|
||||||
Minimum="0" />
|
Minimum="0" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Height="20"
|
Height="20"
|
||||||
Margin="10,0,0,0"
|
Margin="10 0 0 0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
@ -151,7 +154,7 @@
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="programSourceView"
|
x:Name="programSourceView"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="70,0,20,0"
|
Margin="70 0 20 0"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
|
@ -203,7 +206,7 @@
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.RowSpan="1"
|
Grid.RowSpan="1"
|
||||||
Margin="0,0,20,0">
|
Margin="0 0 20 0">
|
||||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnProgramSourceStatus"
|
x:Name="btnProgramSourceStatus"
|
||||||
|
|
@ -220,7 +223,7 @@
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAddProgramSource"
|
x:Name="btnAddProgramSource"
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
Margin="10,10,0,10"
|
Margin="10 10 0 10"
|
||||||
Click="btnAddProgramSource_OnClick"
|
Click="btnAddProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_add}" />
|
Content="{DynamicResource flowlauncher_plugin_program_add}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,16 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool HideDuplicatedWindowsApp
|
||||||
|
{
|
||||||
|
get => _settings.HideDuplicatedWindowsApp;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Main.ResetCache();
|
||||||
|
_settings.HideDuplicatedWindowsApp = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnableRegistrySource
|
public bool EnableRegistrySource
|
||||||
{
|
{
|
||||||
get => _settings.EnableRegistrySource;
|
get => _settings.EnableRegistrySource;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue