Skip to content

Commit 9b5d22a

Browse files
authored
Merge pull request #3438 from onesounds/250410-PluginBadge2
Result Badge
2 parents 9414710 + 03d7dcc commit 9b5d22a

File tree

11 files changed

+327
-122
lines changed

11 files changed

+327
-122
lines changed

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ public string Theme
101101
public bool UseAnimation { get; set; } = true;
102102
public bool UseSound { get; set; } = true;
103103
public double SoundVolume { get; set; } = 50;
104+
public bool ShowBadges { get; set; } = false;
105+
public bool ShowBadgesGlobalOnly { get; set; } = false;
104106

105107
public bool UseClock { get; set; } = true;
106108
public bool UseDate { get; set; } = false;

Flow.Launcher.Plugin/Result.cs

Lines changed: 104 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,19 @@ namespace Flow.Launcher.Plugin
1212
/// </summary>
1313
public class Result
1414
{
15+
/// <summary>
16+
/// 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.
17+
/// </summary>
18+
public const int MaxScore = int.MaxValue;
19+
1520
private string _pluginDirectory;
1621

1722
private string _icoPath;
1823

1924
private string _copyText = string.Empty;
2025

26+
private string _badgeIcoPath;
27+
2128
/// <summary>
2229
/// The title of the result. This is always required.
2330
/// </summary>
@@ -60,7 +67,7 @@ public string CopyText
6067
/// <remarks>GlyphInfo is prioritized if not null</remarks>
6168
public string IcoPath
6269
{
63-
get { return _icoPath; }
70+
get => _icoPath;
6471
set
6572
{
6673
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
@@ -80,6 +87,33 @@ public string IcoPath
8087
}
8188
}
8289

90+
/// <summary>
91+
/// The image to be displayed for the badge of the result.
92+
/// </summary>
93+
/// <value>Can be a local file path or a URL.</value>
94+
/// <remarks>If null or empty, will use plugin icon</remarks>
95+
public string BadgeIcoPath
96+
{
97+
get => _badgeIcoPath;
98+
set
99+
{
100+
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
101+
if (!string.IsNullOrEmpty(value)
102+
&& !string.IsNullOrEmpty(PluginDirectory)
103+
&& !Path.IsPathRooted(value)
104+
&& !value.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
105+
&& !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
106+
&& !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
107+
{
108+
_badgeIcoPath = Path.Combine(PluginDirectory, value);
109+
}
110+
else
111+
{
112+
_badgeIcoPath = value;
113+
}
114+
}
115+
}
116+
83117
/// <summary>
84118
/// Determines if Icon has a border radius
85119
/// </summary>
@@ -94,14 +128,18 @@ public string IcoPath
94128
/// <summary>
95129
/// Delegate to load an icon for this result.
96130
/// </summary>
97-
public IconDelegate Icon;
131+
public IconDelegate Icon { get; set; }
132+
133+
/// <summary>
134+
/// Delegate to load an icon for the badge of this result.
135+
/// </summary>
136+
public IconDelegate BadgeIcon { get; set; }
98137

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

104-
105143
/// <summary>
106144
/// An action to take in the form of a function call when the result has been selected.
107145
/// </summary>
@@ -143,59 +181,19 @@ public string IcoPath
143181
/// </summary>
144182
public string PluginDirectory
145183
{
146-
get { return _pluginDirectory; }
184+
get => _pluginDirectory;
147185
set
148186
{
149187
_pluginDirectory = value;
150188

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

158-
/// <inheritdoc />
159-
public override string ToString()
160-
{
161-
return Title + SubTitle + Score;
162-
}
163-
164-
/// <summary>
165-
/// Clones the current result
166-
/// </summary>
167-
public Result Clone()
168-
{
169-
return new Result
170-
{
171-
Title = Title,
172-
SubTitle = SubTitle,
173-
ActionKeywordAssigned = ActionKeywordAssigned,
174-
CopyText = CopyText,
175-
AutoCompleteText = AutoCompleteText,
176-
IcoPath = IcoPath,
177-
RoundedIcon = RoundedIcon,
178-
Icon = Icon,
179-
Glyph = Glyph,
180-
Action = Action,
181-
AsyncAction = AsyncAction,
182-
Score = Score,
183-
TitleHighlightData = TitleHighlightData,
184-
OriginQuery = OriginQuery,
185-
PluginDirectory = PluginDirectory,
186-
ContextData = ContextData,
187-
PluginID = PluginID,
188-
TitleToolTip = TitleToolTip,
189-
SubTitleToolTip = SubTitleToolTip,
190-
PreviewPanel = PreviewPanel,
191-
ProgressBar = ProgressBar,
192-
ProgressBarColor = ProgressBarColor,
193-
Preview = Preview,
194-
AddSelectedCount = AddSelectedCount,
195-
RecordKey = RecordKey
196-
};
197-
}
198-
199197
/// <summary>
200198
/// Additional data associated with this result
201199
/// </summary>
@@ -224,16 +222,6 @@ public Result Clone()
224222
/// </summary>
225223
public Lazy<UserControl> PreviewPanel { get; set; }
226224

227-
/// <summary>
228-
/// Run this result, asynchronously
229-
/// </summary>
230-
/// <param name="context"></param>
231-
/// <returns></returns>
232-
public ValueTask<bool> ExecuteAsync(ActionContext context)
233-
{
234-
return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false);
235-
}
236-
237225
/// <summary>
238226
/// Progress bar display. Providing an int value between 0-100 will trigger the progress bar to be displayed on the result
239227
/// </summary>
@@ -255,11 +243,6 @@ public ValueTask<bool> ExecuteAsync(ActionContext context)
255243
/// </summary>
256244
public bool AddSelectedCount { get; set; } = true;
257245

258-
/// <summary>
259-
/// 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.
260-
/// </summary>
261-
public const int MaxScore = int.MaxValue;
262-
263246
/// <summary>
264247
/// 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.
265248
/// This can be useful when your plugin will change the Title or SubTitle of the result dynamically.
@@ -268,6 +251,66 @@ public ValueTask<bool> ExecuteAsync(ActionContext context)
268251
/// </summary>
269252
public string RecordKey { get; set; } = null;
270253

254+
/// <summary>
255+
/// Determines if the badge icon should be shown.
256+
/// If users want to show the result badges and here you set this to true, the results will show the badge icon.
257+
/// </summary>
258+
public bool ShowBadge { get; set; } = false;
259+
260+
/// <summary>
261+
/// Run this result, asynchronously
262+
/// </summary>
263+
/// <param name="context"></param>
264+
/// <returns></returns>
265+
public ValueTask<bool> ExecuteAsync(ActionContext context)
266+
{
267+
return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false);
268+
}
269+
270+
/// <inheritdoc />
271+
public override string ToString()
272+
{
273+
return Title + SubTitle + Score;
274+
}
275+
276+
/// <summary>
277+
/// Clones the current result
278+
/// </summary>
279+
public Result Clone()
280+
{
281+
return new Result
282+
{
283+
Title = Title,
284+
SubTitle = SubTitle,
285+
ActionKeywordAssigned = ActionKeywordAssigned,
286+
CopyText = CopyText,
287+
AutoCompleteText = AutoCompleteText,
288+
IcoPath = IcoPath,
289+
BadgeIcoPath = BadgeIcoPath,
290+
RoundedIcon = RoundedIcon,
291+
Icon = Icon,
292+
BadgeIcon = BadgeIcon,
293+
Glyph = Glyph,
294+
Action = Action,
295+
AsyncAction = AsyncAction,
296+
Score = Score,
297+
TitleHighlightData = TitleHighlightData,
298+
OriginQuery = OriginQuery,
299+
PluginDirectory = PluginDirectory,
300+
ContextData = ContextData,
301+
PluginID = PluginID,
302+
TitleToolTip = TitleToolTip,
303+
SubTitleToolTip = SubTitleToolTip,
304+
PreviewPanel = PreviewPanel,
305+
ProgressBar = ProgressBar,
306+
ProgressBarColor = ProgressBarColor,
307+
Preview = Preview,
308+
AddSelectedCount = AddSelectedCount,
309+
RecordKey = RecordKey,
310+
ShowBadge = ShowBadge,
311+
};
312+
}
313+
271314
/// <summary>
272315
/// Info of the preview section of a <see cref="Result"/>
273316
/// </summary>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows.Data;
4+
5+
namespace Flow.Launcher.Converters;
6+
7+
public class BadgePositionConverter : IValueConverter
8+
{
9+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10+
{
11+
if (value is double actualWidth && parameter is string param)
12+
{
13+
double offset = actualWidth / 2 - 8;
14+
15+
if (param == "1") // X-Offset
16+
{
17+
return offset + 2;
18+
}
19+
else if (param == "2") // Y-Offset
20+
{
21+
return offset + 2;
22+
}
23+
}
24+
25+
return 0.0;
26+
}
27+
28+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
29+
{
30+
throw new NotSupportedException();
31+
}
32+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Windows.Data;
2+
using System;
3+
using System.Globalization;
4+
using System.Windows;
5+
6+
namespace Flow.Launcher.Converters;
7+
8+
public class SizeRatioConverter : IValueConverter
9+
{
10+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
11+
{
12+
if (value is double size && parameter is string ratioString)
13+
{
14+
if (double.TryParse(ratioString, NumberStyles.Any, CultureInfo.InvariantCulture, out double ratio))
15+
{
16+
return size * ratio;
17+
}
18+
}
19+
20+
return 0.0;
21+
}
22+
23+
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
24+
{
25+
throw new NotSupportedException();
26+
}
27+
}

Flow.Launcher/Languages/en.xaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,10 @@
298298
<system:String x:Key="useGlyphUI">Use Segoe Fluent Icons</system:String>
299299
<system:String x:Key="useGlyphUIEffect">Use Segoe Fluent Icons for query results where supported</system:String>
300300
<system:String x:Key="flowlauncherPressHotkey">Press Key</system:String>
301+
<system:String x:Key="showBadges">Show Result Badges</system:String>
302+
<system:String x:Key="showBadgesToolTip">Show badges for query results where supported</system:String>
303+
<system:String x:Key="showBadgesGlobalOnly">Show Result Badges for Global Query Only</system:String>
304+
<system:String x:Key="showBadgesGlobalOnlyToolTip">Show badges for global query results only</system:String>
301305

302306
<!-- Setting Proxy -->
303307
<system:String x:Key="proxy">HTTP Proxy</system:String>

0 commit comments

Comments
 (0)