Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Flow.Launcher.Infrastructure/UserSettings/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public string Theme
public bool UseAnimation { get; set; } = true;
public bool UseSound { get; set; } = true;
public double SoundVolume { get; set; } = 50;
public bool ShowBadges { get; set; } = false;
public bool ShowBadgesGlobalOnly { get; set; } = false;

public bool UseClock { get; set; } = true;
public bool UseDate { get; set; } = false;
Expand Down
158 changes: 97 additions & 61 deletions Flow.Launcher.Plugin/Result.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,19 @@ namespace Flow.Launcher.Plugin
/// </summary>
public class Result
{
/// <summary>
/// Maximum score. This can be useful when set one result to the top by default. This is the score for the results set to the topmost by users.
/// </summary>
public const int MaxScore = int.MaxValue;

private string _pluginDirectory;

private string _icoPath;

private string _copyText = string.Empty;

private string _badgeIcoPath;

/// <summary>
/// The title of the result. This is always required.
/// </summary>
Expand Down Expand Up @@ -60,7 +67,7 @@ public string CopyText
/// <remarks>GlyphInfo is prioritized if not null</remarks>
public string IcoPath
{
get { return _icoPath; }
get => _icoPath;
set
{
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
Expand All @@ -80,6 +87,33 @@ public string IcoPath
}
}

/// <summary>
/// The image to be displayed for the badge of the result.
/// </summary>
/// <value>Can be a local file path or a URL.</value>
/// <remarks>If null or empty, will use plugin icon</remarks>
public string BadgeIcoPath
{
get => _badgeIcoPath;
set
{
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
if (!string.IsNullOrEmpty(value)
&& !string.IsNullOrEmpty(PluginDirectory)
&& !Path.IsPathRooted(value)
&& !value.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
&& !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
&& !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
{
_badgeIcoPath = Path.Combine(PluginDirectory, value);
}
else
{
_badgeIcoPath = value;
}
}
}

/// <summary>
/// Determines if Icon has a border radius
/// </summary>
Expand All @@ -94,14 +128,18 @@ public string IcoPath
/// <summary>
/// Delegate to load an icon for this result.
/// </summary>
public IconDelegate Icon;
public IconDelegate Icon { get; set; }

/// <summary>
/// Delegate to load an icon for the badge of this result.
/// </summary>
public IconDelegate BadgeIcon { get; set; }

/// <summary>
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
/// </summary>
public GlyphInfo Glyph { get; init; }


/// <summary>
/// An action to take in the form of a function call when the result has been selected.
/// </summary>
Expand Down Expand Up @@ -143,59 +181,19 @@ public string IcoPath
/// </summary>
public string PluginDirectory
{
get { return _pluginDirectory; }
get => _pluginDirectory;
set
{
_pluginDirectory = value;

// When the Result object is returned from the query call, PluginDirectory is not provided until
// UpdatePluginMetadata call is made at PluginManager.cs L196. Once the PluginDirectory becomes available
// we need to update (only if not Uri path) the IcoPath with the full absolute path so the image can be loaded.
// we need to update (only if not Uri path) the IcoPath and BadgeIcoPath with the full absolute path so the image can be loaded.
IcoPath = _icoPath;
BadgeIcoPath = _badgeIcoPath;
}
}

/// <inheritdoc />
public override string ToString()
{
return Title + SubTitle + Score;
}

/// <summary>
/// Clones the current result
/// </summary>
public Result Clone()
{
return new Result
{
Title = Title,
SubTitle = SubTitle,
ActionKeywordAssigned = ActionKeywordAssigned,
CopyText = CopyText,
AutoCompleteText = AutoCompleteText,
IcoPath = IcoPath,
RoundedIcon = RoundedIcon,
Icon = Icon,
Glyph = Glyph,
Action = Action,
AsyncAction = AsyncAction,
Score = Score,
TitleHighlightData = TitleHighlightData,
OriginQuery = OriginQuery,
PluginDirectory = PluginDirectory,
ContextData = ContextData,
PluginID = PluginID,
TitleToolTip = TitleToolTip,
SubTitleToolTip = SubTitleToolTip,
PreviewPanel = PreviewPanel,
ProgressBar = ProgressBar,
ProgressBarColor = ProgressBarColor,
Preview = Preview,
AddSelectedCount = AddSelectedCount,
RecordKey = RecordKey
};
}

/// <summary>
/// Additional data associated with this result
/// </summary>
Expand Down Expand Up @@ -224,16 +222,6 @@ public Result Clone()
/// </summary>
public Lazy<UserControl> PreviewPanel { get; set; }

/// <summary>
/// Run this result, asynchronously
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public ValueTask<bool> ExecuteAsync(ActionContext context)
{
return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false);
}

/// <summary>
/// Progress bar display. Providing an int value between 0-100 will trigger the progress bar to be displayed on the result
/// </summary>
Expand All @@ -255,11 +243,6 @@ public ValueTask<bool> ExecuteAsync(ActionContext context)
/// </summary>
public bool AddSelectedCount { get; set; } = true;

/// <summary>
/// Maximum score. This can be useful when set one result to the top by default. This is the score for the results set to the topmost by users.
/// </summary>
public const int MaxScore = int.MaxValue;

/// <summary>
/// The key to identify the record. This is used when FL checks whether the result is the topmost record. Or FL calculates the hashcode of the result for user selected records.
/// This can be useful when your plugin will change the Title or SubTitle of the result dynamically.
Expand All @@ -268,6 +251,59 @@ public ValueTask<bool> ExecuteAsync(ActionContext context)
/// </summary>
public string RecordKey { get; set; } = null;

/// <summary>
/// Run this result, asynchronously
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public ValueTask<bool> ExecuteAsync(ActionContext context)
{
return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false);
}

/// <inheritdoc />
public override string ToString()
{
return Title + SubTitle + Score;
}

/// <summary>
/// Clones the current result
/// </summary>
public Result Clone()
{
return new Result
{
Title = Title,
SubTitle = SubTitle,
ActionKeywordAssigned = ActionKeywordAssigned,
CopyText = CopyText,
AutoCompleteText = AutoCompleteText,
IcoPath = IcoPath,
BadgeIcoPath = BadgeIcoPath,
RoundedIcon = RoundedIcon,
Icon = Icon,
BadgeIcon = BadgeIcon,
Glyph = Glyph,
Action = Action,
AsyncAction = AsyncAction,
Score = Score,
TitleHighlightData = TitleHighlightData,
OriginQuery = OriginQuery,
PluginDirectory = PluginDirectory,
ContextData = ContextData,
PluginID = PluginID,
TitleToolTip = TitleToolTip,
SubTitleToolTip = SubTitleToolTip,
PreviewPanel = PreviewPanel,
ProgressBar = ProgressBar,
ProgressBarColor = ProgressBarColor,
Preview = Preview,
AddSelectedCount = AddSelectedCount,
RecordKey = RecordKey
};
}

/// <summary>
/// Info of the preview section of a <see cref="Result"/>
/// </summary>
Expand Down
4 changes: 4 additions & 0 deletions Flow.Launcher/Languages/en.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,10 @@
<system:String x:Key="useGlyphUI">Use Segoe Fluent Icons</system:String>
<system:String x:Key="useGlyphUIEffect">Use Segoe Fluent Icons for query results where supported</system:String>
<system:String x:Key="flowlauncherPressHotkey">Press Key</system:String>
<system:String x:Key="showBadges">Show Result Badges</system:String>
<system:String x:Key="showBadgesToolTip">Show badges for query results where supported</system:String>
<system:String x:Key="showBadgesGlobalOnly">Show Result Badges for Global Query Only</system:String>
<system:String x:Key="showBadgesGlobalOnlyToolTip">Show badges for global query results only</system:String>

<!-- Setting Proxy -->
<system:String x:Key="proxy">HTTP Proxy</system:String>
Expand Down
88 changes: 44 additions & 44 deletions Flow.Launcher/ResultListBox.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -90,60 +90,60 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Border
x:Name="Bullet"
Grid.Column="0"
Style="{DynamicResource BulletStyle}" />

<Border
Grid.Column="1"
Margin="9 0 0 0"
BorderBrush="Transparent"
BorderThickness="1">
<Image
x:Name="ImageIcon"
Margin="0 0 0 0"
HorizontalAlignment="Center"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="Fant"
Source="{Binding Image, TargetNullValue={x:Null}}"
Stretch="Uniform"
StretchDirection="DownOnly"
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"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="{Binding Glyph.FontFamily}"
Style="{DynamicResource ItemGlyph}"
Text="{Binding Glyph.Glyph}"
Visibility="{Binding ShowGlyph}" />
<Grid>
<Image
x:Name="ImageIcon"
IsHitTestVisible="False"
RenderOptions.BitmapScalingMode="Fant"
Source="{Binding Image, TargetNullValue={x:Null}}"
Stretch="Uniform"
StretchDirection="DownOnly"
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>

<TextBlock
x:Name="GlyphIcon"
FontFamily="{Binding Glyph.FontFamily}"
Style="{DynamicResource ItemGlyph}"
Text="{Binding Glyph.Glyph}"
Visibility="{Binding ShowGlyph}" />

<Image
x:Name="BadgeIcon"
Width="{Binding ElementName=ImageIcon, Path=ActualWidth}"
Height="{Binding ElementName=ImageIcon, Path=ActualHeight}"
RenderOptions.BitmapScalingMode="HighQuality"
Source="{Binding BadgeImage, TargetNullValue={x:Null}}"
Visibility="{Binding ShowBadge}" />
</Grid>
</Border>

</Grid>

<Grid
Expand Down
Loading
Loading