implement plugin badge

This commit is contained in:
Hongtao Zhang 2024-05-25 00:59:55 -05:00
parent cffbd9a157
commit 00af78d5e3
2 changed files with 130 additions and 69 deletions

View file

@ -74,12 +74,15 @@
VerticalAlignment="Center"
Style="{DynamicResource ItemHotkeyStyle}">
<TextBlock.Visibility>
<Binding Converter="{StaticResource ResourceKey=OpenResultHotkeyVisibilityConverter}" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}" />
<Binding
Converter="{StaticResource ResourceKey=OpenResultHotkeyVisibilityConverter}"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}" />
</TextBlock.Visibility>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}+{1}">
<Binding Path="OpenResultModifiers" />
<Binding Converter="{StaticResource ResourceKey=OrdinalConverter}" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}" />
<Binding Converter="{StaticResource ResourceKey=OrdinalConverter}"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
@ -96,53 +99,84 @@
Grid.Column="0"
Style="{DynamicResource BulletStyle}" />
<Border
Grid.Column="1"
Margin="9,0,0,0"
BorderBrush="Transparent"
BorderThickness="1">
<Grid Grid.Column="1"
Margin="9,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="6*" />
<RowDefinition Height="4*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*" />
<ColumnDefinition Width="4*" />
</Grid.ColumnDefinitions>
<Border
Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="2"
Grid.ColumnSpan="2"
Margin="9,0,0,0"
BorderBrush="Transparent"
BorderThickness="1"
Grid.ZIndex="0">
<Image
x:Name="ImageIcon"
Margin="0,0,0,0"
HorizontalAlignment="Center"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="Fant"
Source="{Binding Image, TargetNullValue={x:Null}}"
Stretch="Uniform"
Style="{DynamicResource ImageIconStyle}"
Visibility="{Binding ShowIcon}">
<Image.Clip>
<EllipseGeometry
Center="{Binding ElementName=ImageIcon, Path=ActualWidth, Converter={StaticResource DiameterToCenterPointConverter}}">
<EllipseGeometry.RadiusX>
<MultiBinding Converter="{StaticResource IconRadiusConverter}">
<Binding ElementName="ImageIcon" Path="ActualWidth" />
<Binding Path="Result.RoundedIcon" />
</MultiBinding>
</EllipseGeometry.RadiusX>
<EllipseGeometry.RadiusY>
<MultiBinding Converter="{StaticResource IconRadiusConverter}">
<Binding ElementName="ImageIcon" Path="ActualWidth" />
<Binding Path="Result.RoundedIcon" />
</MultiBinding>
</EllipseGeometry.RadiusY>
</EllipseGeometry>
</Image.Clip>
</Image>
</Border>
<Border
Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="2"
Grid.ColumnSpan="2"
Margin="9,0,0,0"
BorderBrush="Transparent"
BorderThickness="0"
Grid.ZIndex="0">
<TextBlock
x:Name="GlyphIcon"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{Binding Glyph.FontFamily}"
Style="{DynamicResource ItemGlyph}"
Text="{Binding Glyph.Glyph}"
Visibility="{Binding ShowGlyph}" />
</Border>
<Image
x:Name="ImageIcon"
Margin="0,0,0,0"
HorizontalAlignment="Center"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="Fant"
Source="{Binding Image, TargetNullValue={x:Null}}"
Stretch="Uniform"
Style="{DynamicResource ImageIconStyle}"
Visibility="{Binding ShowIcon}">
<Image.Clip>
<EllipseGeometry Center="{Binding ElementName=ImageIcon, Path=ActualWidth, Converter={StaticResource DiameterToCenterPointConverter}}">
<EllipseGeometry.RadiusX>
<MultiBinding Converter="{StaticResource IconRadiusConverter}">
<Binding ElementName="ImageIcon" Path="ActualWidth" />
<Binding Path="Result.RoundedIcon" />
</MultiBinding>
</EllipseGeometry.RadiusX>
<EllipseGeometry.RadiusY>
<MultiBinding Converter="{StaticResource IconRadiusConverter}">
<Binding ElementName="ImageIcon" Path="ActualWidth" />
<Binding Path="Result.RoundedIcon" />
</MultiBinding>
</EllipseGeometry.RadiusY>
</EllipseGeometry>
</Image.Clip>
</Image>
</Border>
<Border
Grid.Column="1"
Margin="9,0,0,0"
BorderBrush="Transparent"
BorderThickness="0">
<TextBlock
x:Name="GlyphIcon"
Grid.Row="1"
Grid.Column="1"
Grid.ZIndex="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{Binding Glyph.FontFamily}"
Style="{DynamicResource ItemGlyph}"
Text="{Binding Glyph.Glyph}"
Visibility="{Binding ShowGlyph}" />
</Border>
RenderOptions.BitmapScalingMode="Fant"
Source="{Binding PluginIcon}">
</Image>
</Grid>
</Grid>
<Grid
@ -204,7 +238,9 @@
</Button>
<!-- a result item height is 52 including margin -->
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Value="True">
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"
Value="True">
<Setter TargetName="Bullet" Property="Style" Value="{DynamicResource ItemBulletSelectedStyle}" />
<Setter TargetName="Title" Property="Style" Value="{DynamicResource ItemTitleSelectedStyle}" />
<Setter TargetName="SubTitle" Property="Style" Value="{DynamicResource ItemSubTitleSelectedStyle}" />
@ -243,8 +279,10 @@
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource ItemSelectedBackgroundColor}" />
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource ItemSelectedBackgroundColor}" />
<Setter TargetName="Bd" Property="Background"
Value="{DynamicResource ItemSelectedBackgroundColor}" />
<Setter TargetName="Bd" Property="BorderBrush"
Value="{DynamicResource ItemSelectedBackgroundColor}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>

View file

@ -9,6 +9,7 @@ using Flow.Launcher.Plugin;
using System.IO;
using System.Drawing.Text;
using System.Collections.Generic;
using Flow.Launcher.Core.Plugin;
namespace Flow.Launcher.ViewModel
{
@ -25,6 +26,7 @@ namespace Flow.Launcher.ViewModel
{
return;
}
Result = result;
if (Result.Glyph is { FontFamily: not null } glyph)
@ -41,19 +43,14 @@ namespace Flow.Launcher.ViewModel
if (fonts.ContainsKey(fontFamilyPath))
{
Glyph = glyph with
{
FontFamily = fonts[fontFamilyPath]
};
Glyph = glyph with { FontFamily = fonts[fontFamilyPath] };
}
else
{
fontCollection.AddFontFile(fontFamilyPath);
fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}";
Glyph = glyph with
{
FontFamily = fonts[fontFamilyPath]
};
fonts[fontFamilyPath] =
$"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}";
Glyph = glyph with { FontFamily = fonts[fontFamilyPath] };
}
}
else
@ -61,7 +58,6 @@ namespace Flow.Launcher.ViewModel
Glyph = glyph;
}
}
}
private Settings Settings { get; }
@ -71,7 +67,8 @@ namespace Flow.Launcher.ViewModel
public Visibility ShowDefaultPreview => Result.PreviewPanel == null ? Visibility.Visible : Visibility.Collapsed;
public Visibility ShowCustomizedPreview => Result.PreviewPanel == null ? Visibility.Collapsed : Visibility.Visible;
public Visibility ShowCustomizedPreview =>
Result.PreviewPanel == null ? Visibility.Collapsed : Visibility.Visible;
public Visibility ShowIcon
{
@ -114,9 +111,9 @@ namespace Flow.Launcher.ViewModel
{
return IconXY / 2;
}
return IconXY;
}
}
public Visibility ShowGlyph
@ -136,7 +133,8 @@ namespace Flow.Launcher.ViewModel
private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPath) || Result.Icon is not null;
private bool PreviewImageAvailable => !string.IsNullOrEmpty(Result.Preview.PreviewImagePath) || Result.Preview.PreviewDelegate != null;
private bool PreviewImageAvailable => !string.IsNullOrEmpty(Result.Preview.PreviewImagePath) ||
Result.Preview.PreviewDelegate != null;
public string OpenResultModifiers => Settings.OpenResultModifiers;
@ -148,19 +146,42 @@ namespace Flow.Launcher.ViewModel
? Result.SubTitle
: Result.SubTitleToolTip;
private volatile bool ImageLoaded;
private volatile bool PreviewImageLoaded;
private volatile bool imageLoaded;
private volatile bool pluginIconLoaded;
private volatile bool previewImageLoaded;
private ImageSource image = ImageLoader.LoadingImage;
private ImageSource previewImage = ImageLoader.LoadingImage;
private ImageSource pluginIcon = ImageLoader.LoadingImage;
public ImageSource PluginIcon
{
get
{
if (!pluginIconLoaded)
{
pluginIconLoaded = true;
_ = LoadPluginIconAsync();
}
return pluginIcon;
}
private set => pluginIcon = value;
}
private async Task LoadPluginIconAsync()
{
PluginIcon = await ImageLoader.LoadAsync(PluginManager.GetPluginForId(Result.PluginID).Metadata.IcoPath)
.ConfigureAwait(false);
}
public ImageSource Image
{
get
{
if (!ImageLoaded)
if (!imageLoaded)
{
ImageLoaded = true;
imageLoaded = true;
_ = LoadImageAsync();
}
@ -182,7 +203,8 @@ namespace Flow.Launcher.ViewModel
public GlyphInfo Glyph { get; set; }
private async Task<ImageSource> LoadImageInternalAsync(string imagePath, Result.IconDelegate icon, bool loadFullImage)
private async Task<ImageSource> LoadImageInternalAsync(string imagePath, Result.IconDelegate icon,
bool loadFullImage)
{
if (string.IsNullOrEmpty(imagePath) && icon != null)
{
@ -236,15 +258,16 @@ namespace Flow.Launcher.ViewModel
{
if (ShowDefaultPreview == Visibility.Visible)
{
if (!PreviewImageLoaded && ShowPreviewImage == Visibility.Visible)
if (!previewImageLoaded && ShowPreviewImage == Visibility.Visible)
{
PreviewImageLoaded = true;
previewImageLoaded = true;
_ = LoadPreviewImageAsync();
}
}
}
public Result Result { get; }
public int ResultProgress
{
get