Merge pull request #3494 from Flow-Launcher/plugin_filters

Support filtering dotnet, python, node.js, executable plugins
This commit is contained in:
Jack Ye 2025-04-29 20:20:33 +08:00 committed by GitHub
commit b36562af6d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 225 additions and 70 deletions

View file

@ -65,7 +65,42 @@ namespace Flow.Launcher.Plugin
public static bool IsDotNet(string language)
{
return language.Equals(CSharp, StringComparison.OrdinalIgnoreCase)
|| language.Equals(FSharp, StringComparison.OrdinalIgnoreCase);
|| language.Equals(FSharp, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Determines if this language is a Python language
/// </summary>
/// <param name="language"></param>
/// <returns></returns>
public static bool IsPython(string language)
{
return language.Equals(Python, StringComparison.OrdinalIgnoreCase)
|| language.Equals(PythonV2, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Determines if this language is a Node.js language
/// </summary>
/// <param name="language"></param>
/// <returns></returns>
public static bool IsNodeJs(string language)
{
return language.Equals(TypeScript, StringComparison.OrdinalIgnoreCase)
|| language.Equals(TypeScriptV2, StringComparison.OrdinalIgnoreCase)
|| language.Equals(JavaScript, StringComparison.OrdinalIgnoreCase)
|| language.Equals(JavaScriptV2, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Determines if this language is a executable language
/// </summary>
/// <param name="language"></param>
/// <returns></returns>
public static bool IsExecutable(string language)
{
return language.Equals(Executable, StringComparison.OrdinalIgnoreCase)
|| language.Equals(ExecutableV2, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
@ -76,15 +111,9 @@ namespace Flow.Launcher.Plugin
public static bool IsAllowed(string language)
{
return IsDotNet(language)
|| language.Equals(Python, StringComparison.OrdinalIgnoreCase)
|| language.Equals(PythonV2, StringComparison.OrdinalIgnoreCase)
|| language.Equals(Executable, StringComparison.OrdinalIgnoreCase)
|| language.Equals(TypeScript, StringComparison.OrdinalIgnoreCase)
|| language.Equals(JavaScript, StringComparison.OrdinalIgnoreCase)
|| language.Equals(ExecutableV2, StringComparison.OrdinalIgnoreCase)
|| language.Equals(TypeScriptV2, StringComparison.OrdinalIgnoreCase)
|| language.Equals(JavaScriptV2, StringComparison.OrdinalIgnoreCase);
;
|| IsPython(language)
|| IsNodeJs(language)
|| IsExecutable(language);
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -9,7 +9,75 @@ namespace Flow.Launcher.SettingPages.ViewModels;
public partial class SettingsPanePluginStoreViewModel : BaseModel
{
public string FilterText { get; set; } = string.Empty;
private string filterText = string.Empty;
public string FilterText
{
get => filterText;
set
{
if (filterText != value)
{
filterText = value;
OnPropertyChanged();
}
}
}
private bool showDotNet = true;
public bool ShowDotNet
{
get => showDotNet;
set
{
if (showDotNet != value)
{
showDotNet = value;
OnPropertyChanged();
}
}
}
private bool showPython = true;
public bool ShowPython
{
get => showPython;
set
{
if (showPython != value)
{
showPython = value;
OnPropertyChanged();
}
}
}
private bool showNodeJs = true;
public bool ShowNodeJs
{
get => showNodeJs;
set
{
if (showNodeJs != value)
{
showNodeJs = value;
OnPropertyChanged();
}
}
}
private bool showExecutable = true;
public bool ShowExecutable
{
get => showExecutable;
set
{
if (showExecutable != value)
{
showExecutable = value;
OnPropertyChanged();
}
}
}
public IList<PluginStoreItemViewModel> ExternalPlugins =>
App.API.GetPluginManifest()?.Select(p => new PluginStoreItemViewModel(p))
@ -30,8 +98,29 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel
public bool SatisfiesFilter(PluginStoreItemViewModel plugin)
{
// Check plugin language
var pluginShown = false;
if (AllowedLanguage.IsDotNet(plugin.Language))
{
pluginShown = ShowDotNet;
}
else if (AllowedLanguage.IsPython(plugin.Language))
{
pluginShown = ShowPython;
}
else if (AllowedLanguage.IsNodeJs(plugin.Language))
{
pluginShown = ShowNodeJs;
}
else if (AllowedLanguage.IsExecutable(plugin.Language))
{
pluginShown = ShowExecutable;
}
if (!pluginShown) return false;
// Check plugin name & description
return string.IsNullOrEmpty(FilterText) ||
App.API.FuzzySearch(FilterText, plugin.Name).IsSearchPrecisionScoreMet() ||
App.API.FuzzySearch(FilterText, plugin.Description).IsSearchPrecisionScoreMet();
App.API.FuzzySearch(FilterText, plugin.Name).IsSearchPrecisionScoreMet() ||
App.API.FuzzySearch(FilterText, plugin.Description).IsSearchPrecisionScoreMet();
}
}

View file

@ -27,8 +27,8 @@
</ui:Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="72" />
@ -51,60 +51,93 @@
Grid.Column="1"
Margin="5 24 0 0">
<TextBox
Name="PluginStoreFilterTextbox"
Width="150"
Height="34"
Margin="0 0 26 0"
HorizontalAlignment="Right"
ContextMenu="{StaticResource TextBoxContextMenu}"
DockPanel.Dock="Right"
FontSize="14"
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
TextAlignment="Left"
ToolTip="{DynamicResource searchpluginToolTip}"
ToolTipService.InitialShowDelay="200"
ToolTipService.Placement="Top">
<TextBox.Style>
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
<Style.Resources>
<VisualBrush
x:Key="CueBannerBrush"
AlignmentX="Left"
AlignmentY="Center"
Stretch="None">
<VisualBrush.Visual>
<Label
Padding="10 0 0 0"
Content="{DynamicResource searchplugin}"
Foreground="{DynamicResource CustomContextDisabled}" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="{DynamicResource Color02B}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button
Height="34"
Margin="0 5 10 5"
Padding="12 4"
<StackPanel
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding RefreshExternalPluginsCommand}"
Content="{DynamicResource refresh}"
DockPanel.Dock="Right"
FontSize="13" />
Orientation="Horizontal">
<Button
Height="34"
Margin="0 5 10 5"
Padding="12 4"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding RefreshExternalPluginsCommand}"
Content="{DynamicResource refresh}"
FontSize="13" />
<Button Height="34" Margin="0 0 10 0">
<ui:FontIcon FontSize="14" Glyph="&#xe71c;" />
<ui:FlyoutService.Flyout>
<ui:MenuFlyout x:Name="FilterFlyout" Placement="Bottom">
<MenuItem
Header=".Net"
IsCheckable="True"
IsChecked="{Binding ShowDotNet, Mode=TwoWay}"
StaysOpenOnClick="True" />
<MenuItem
Header="Python"
IsCheckable="True"
IsChecked="{Binding ShowPython, Mode=TwoWay}"
StaysOpenOnClick="True" />
<MenuItem
Header="Node.js"
IsCheckable="True"
IsChecked="{Binding ShowNodeJs, Mode=TwoWay}"
StaysOpenOnClick="True" />
<MenuItem
Header="Exe"
IsCheckable="True"
IsChecked="{Binding ShowExecutable, Mode=TwoWay}"
StaysOpenOnClick="True" />
</ui:MenuFlyout>
</ui:FlyoutService.Flyout>
</Button>
<TextBox
Name="PluginStoreFilterTextbox"
Width="150"
Height="34"
Margin="0 0 26 0"
HorizontalAlignment="Right"
ContextMenu="{StaticResource TextBoxContextMenu}"
DockPanel.Dock="Right"
FontSize="14"
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
TextAlignment="Left"
ToolTip="{DynamicResource searchpluginToolTip}"
ToolTipService.InitialShowDelay="200"
ToolTipService.Placement="Top">
<TextBox.Style>
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
<Style.Resources>
<VisualBrush
x:Key="CueBannerBrush"
AlignmentX="Left"
AlignmentY="Center"
Stretch="None">
<VisualBrush.Visual>
<Label
Padding="10 0 0 0"
Content="{DynamicResource searchplugin}"
Foreground="{DynamicResource CustomContextDisabled}" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="{DynamicResource Color02B}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</DockPanel>
<ListView
x:Name="StoreListBox"
@ -343,9 +376,7 @@
Text="{Binding Description, Mode=OneWay}"
TextTrimming="WordEllipsis"
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</Button>
</DataTemplate>

View file

@ -26,9 +26,15 @@ public partial class SettingsPanePluginStore
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(SettingsPanePluginStoreViewModel.FilterText))
switch (e.PropertyName)
{
((CollectionViewSource)FindResource("PluginStoreCollectionView")).View.Refresh();
case nameof(SettingsPanePluginStoreViewModel.FilterText):
case nameof(SettingsPanePluginStoreViewModel.ShowDotNet):
case nameof(SettingsPanePluginStoreViewModel.ShowPython):
case nameof(SettingsPanePluginStoreViewModel.ShowNodeJs):
case nameof(SettingsPanePluginStoreViewModel.ShowExecutable):
((CollectionViewSource)FindResource("PluginStoreCollectionView")).View.Refresh();
break;
}
}