Skip to content

Commit 5e87156

Browse files
authored
Merge branch 'dev' into optimize
2 parents e9fb8c5 + 6c1f7fa commit 5e87156

File tree

32 files changed

+793
-209
lines changed

32 files changed

+793
-209
lines changed

Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@
7272
<PrivateAssets>all</PrivateAssets>
7373
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
7474
</PackageReference>
75-
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
75+
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.102" PrivateAssets="All" />
7676
<PackageReference Include="JetBrains.Annotations" Version="2025.2.2" />
77-
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.205">
77+
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.269">
7878
<PrivateAssets>all</PrivateAssets>
7979
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
8080
</PackageReference>

Flow.Launcher.Plugin/Result.cs

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
using System.Threading.Tasks;
55
using System.Windows.Controls;
66
using System.Windows.Media;
7+
using System.Text.Json.Serialization;
78

89
namespace Flow.Launcher.Plugin
910
{
1011
/// <summary>
11-
/// Describes a result of a <see cref="Query"/> executed by a plugin
12+
/// Describes a result of a <see cref="Query"/> executed by a plugin.
13+
/// This or its child classes is serializable.
1214
/// </summary>
1315
public class Result
1416
{
@@ -21,6 +23,8 @@ public class Result
2123

2224
private string _icoPath;
2325

26+
private string _icoPathAbsolute;
27+
2428
private string _copyText = string.Empty;
2529

2630
private string _badgeIcoPath;
@@ -64,15 +68,27 @@ public string CopyText
6468
public string AutoCompleteText { get; set; }
6569

6670
/// <summary>
67-
/// The image to be displayed for the result.
71+
/// Path or URI to the icon image for this result.
72+
/// Updates <see cref="IcoPathAbsolute"/> appropriately when set.
6873
/// </summary>
69-
/// <value>Can be a local file path or a URL.</value>
70-
/// <remarks>GlyphInfo is prioritized if not null</remarks>
74+
/// <remarks>
75+
/// Preferred usage: provide a path relative to the plugin directory (for example: "Images\icon.png").
76+
/// Because <see cref="IcoPath"/> is serialized, using relative paths keeps the icon reference portable
77+
/// when Flow is moved.
78+
///
79+
/// Accepted formats:
80+
/// - Relative file paths (resolved against <see cref="PluginDirectory"/> into <see cref="IcoPathAbsolute"/>)
81+
/// - Absolute file paths (left as-is)
82+
/// - HTTP/HTTPS URLs (left as-is)
83+
/// - Data URIs (left as-is)
84+
/// </remarks>
7185
public string IcoPath
7286
{
7387
get => _icoPath;
7488
set
7589
{
90+
_icoPath = value;
91+
7692
// As a standard this property will handle prepping and converting to absolute local path for icon image processing
7793
if (!string.IsNullOrEmpty(value)
7894
&& !string.IsNullOrEmpty(PluginDirectory)
@@ -81,15 +97,23 @@ public string IcoPath
8197
&& !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
8298
&& !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
8399
{
84-
_icoPath = Path.Combine(PluginDirectory, value);
100+
_icoPathAbsolute = Path.Combine(PluginDirectory, value);
85101
}
86102
else
87103
{
88-
_icoPath = value;
104+
_icoPathAbsolute = value;
89105
}
90106
}
91107
}
92108

109+
/// <summary>
110+
/// Absolute path or URI which is used to load and display the result icon for Flow.
111+
/// This is populated by the <see cref="IcoPath"/> setter.
112+
/// If a relative path was provided to <see cref="IcoPath"/>, this property will contain the resolved
113+
/// absolute local path after combining with <see cref="PluginDirectory"/>.
114+
/// </summary>
115+
public string IcoPathAbsolute => _icoPathAbsolute;
116+
93117
/// <summary>
94118
/// The image to be displayed for the badge of the result.
95119
/// </summary>
@@ -131,17 +155,34 @@ public string BadgeIcoPath
131155
/// <summary>
132156
/// Delegate to load an icon for this result.
133157
/// </summary>
158+
[JsonIgnore]
134159
public IconDelegate Icon = null;
135160

136161
/// <summary>
137162
/// Delegate to load an icon for the badge of this result.
138163
/// </summary>
164+
[JsonIgnore]
139165
public IconDelegate BadgeIcon = null;
140166

167+
private GlyphInfo _glyph;
168+
141169
/// <summary>
142170
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
143171
/// </summary>
144-
public GlyphInfo Glyph { get; init; }
172+
public GlyphInfo Glyph
173+
{
174+
get => _glyph;
175+
init => _glyph = value;
176+
}
177+
178+
/// <summary>
179+
/// Set the Glyph Icon after initialization
180+
/// </summary>
181+
/// <param name="glyph"></param>
182+
public void SetGlyph(GlyphInfo glyph)
183+
{
184+
_glyph = glyph;
185+
}
145186

146187
/// <summary>
147188
/// An action to take in the form of a function call when the result has been selected.
@@ -151,6 +192,7 @@ public string BadgeIcoPath
151192
/// Its result determines what happens to Flow Launcher's query form:
152193
/// when true, the form will be hidden; when false, it will stay in focus.
153194
/// </remarks>
195+
[JsonIgnore]
154196
public Func<ActionContext, bool> Action { get; set; }
155197

156198
/// <summary>
@@ -161,6 +203,7 @@ public string BadgeIcoPath
161203
/// Its result determines what happens to Flow Launcher's query form:
162204
/// when true, the form will be hidden; when false, it will stay in focus.
163205
/// </remarks>
206+
[JsonIgnore]
164207
public Func<ActionContext, ValueTask<bool>> AsyncAction { get; set; }
165208

166209
/// <summary>
@@ -203,11 +246,13 @@ public string PluginDirectory
203246
/// <example>
204247
/// As external information for ContextMenu
205248
/// </example>
249+
[JsonIgnore]
206250
public object ContextData { get; set; }
207251

208252
/// <summary>
209253
/// Plugin ID that generated this result
210254
/// </summary>
255+
[JsonInclude]
211256
public string PluginID { get; internal set; }
212257

213258
/// <summary>
@@ -223,6 +268,7 @@ public string PluginDirectory
223268
/// <summary>
224269
/// Customized Preview Panel
225270
/// </summary>
271+
[JsonIgnore]
226272
public Lazy<UserControl> PreviewPanel { get; set; }
227273

228274
/// <summary>
@@ -352,6 +398,7 @@ public record PreviewInfo
352398
/// <summary>
353399
/// Delegate to get the preview panel's image
354400
/// </summary>
401+
[JsonIgnore]
355402
public IconDelegate PreviewDelegate { get; set; } = null;
356403

357404
/// <summary>

Flow.Launcher.Plugin/packages.lock.json

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,23 @@
1616
},
1717
"Microsoft.SourceLink.GitHub": {
1818
"type": "Direct",
19-
"requested": "[8.0.0, )",
20-
"resolved": "8.0.0",
21-
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
19+
"requested": "[10.0.102, )",
20+
"resolved": "10.0.102",
21+
"contentHash": "Oxq3RCIJSdtpIU4hLqO7XaDe/Ra3HS9Wi8rJl838SAg6Zu1iQjerA0+xXWBgUFYbgknUGCLOU0T+lzMLkvY9Qg==",
2222
"dependencies": {
23-
"Microsoft.Build.Tasks.Git": "8.0.0",
24-
"Microsoft.SourceLink.Common": "8.0.0"
23+
"Microsoft.Build.Tasks.Git": "10.0.102",
24+
"Microsoft.SourceLink.Common": "10.0.102"
2525
}
2626
},
2727
"Microsoft.Windows.CsWin32": {
2828
"type": "Direct",
29-
"requested": "[0.3.205, )",
30-
"resolved": "0.3.205",
31-
"contentHash": "U5wGAnyKd7/I2YMd43nogm81VMtjiKzZ9dsLMVI4eAB7jtv5IEj0gprj0q/F3iRmAIaGv5omOf8iSYx2+nE6BQ==",
29+
"requested": "[0.3.269, )",
30+
"resolved": "0.3.269",
31+
"contentHash": "O4GVJ0ymxcoFRGS07VcoEClj7A9PIciHIjWDrPymzonhYlOfM7V0ZqGBUK19cUH3BPca9MfSOH0KLK/9JzQ8+Q==",
3232
"dependencies": {
3333
"Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha",
34-
"Microsoft.Windows.SDK.Win32Metadata": "61.0.15-preview",
35-
"Microsoft.Windows.WDK.Win32Metadata": "0.12.8-experimental"
34+
"Microsoft.Windows.SDK.Win32Metadata": "69.0.7-preview",
35+
"Microsoft.Windows.WDK.Win32Metadata": "0.13.25-experimental"
3636
}
3737
},
3838
"PropertyChanged.Fody": {
@@ -46,13 +46,13 @@
4646
},
4747
"Microsoft.Build.Tasks.Git": {
4848
"type": "Transitive",
49-
"resolved": "8.0.0",
50-
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
49+
"resolved": "10.0.102",
50+
"contentHash": "0i81LYX31U6UiXz4NOLbvc++u+/mVDmOt+PskrM/MygpDxkv9THKQyRUmavBpLK6iBV0abNWnn+CQgSRz//Pwg=="
5151
},
5252
"Microsoft.SourceLink.Common": {
5353
"type": "Transitive",
54-
"resolved": "8.0.0",
55-
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
54+
"resolved": "10.0.102",
55+
"contentHash": "Mk1IMb9q5tahC2NltxYXFkLBtuBvfBoCQ3pIxYQWfzbCE9o1OB9SsHe0hnNGo7lWgTA/ePbFAJLWu6nLL9K17A=="
5656
},
5757
"Microsoft.Windows.SDK.Win32Docs": {
5858
"type": "Transitive",
@@ -61,15 +61,15 @@
6161
},
6262
"Microsoft.Windows.SDK.Win32Metadata": {
6363
"type": "Transitive",
64-
"resolved": "61.0.15-preview",
65-
"contentHash": "cysex3dazKtCPALCluC2XX3f5Aedy9H2pw5jb+TW5uas2rkem1Z7FRnbUrg2vKx0pk0Qz+4EJNr37HdYTEcvEQ=="
64+
"resolved": "69.0.7-preview",
65+
"contentHash": "RJoNjQJVCIDNLPbvYuaygCFknTyAxOUE45of1voj0jjOgJa9MB2m1/G8L8F3IYc+2EFG5aqa/9y8PEx7Tk2tLQ=="
6666
},
6767
"Microsoft.Windows.WDK.Win32Metadata": {
6868
"type": "Transitive",
69-
"resolved": "0.12.8-experimental",
70-
"contentHash": "3n8R44/Z96Ly+ty4eYVJfESqbzvpw96lRLs3zOzyDmr1x1Kw7FNn5CyE416q+bZQV3e1HRuMUvyegMeRE/WedA==",
69+
"resolved": "0.13.25-experimental",
70+
"contentHash": "IM50tb/+UIwBr9FMr6ZKcZjCMW+Axo6NjGqKxgjUfyCY8dRnYUfrJEXxAaXoWtYP4X8EmASmC1Jtwh4XucseZg==",
7171
"dependencies": {
72-
"Microsoft.Windows.SDK.Win32Metadata": "61.0.15-preview"
72+
"Microsoft.Windows.SDK.Win32Metadata": "63.0.31-preview"
7373
}
7474
}
7575
}

Flow.Launcher.Test/Plugins/CalculatorTest.cs

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@ public class CalculatorPluginTest
1616
{
1717
DecimalSeparator = DecimalSeparator.UseSystemLocale,
1818
MaxDecimalPlaces = 10,
19-
ShowErrorMessage = false // Make sure we return the empty results when error occurs
19+
ShowErrorMessage = false, // Make sure we return the empty results when error occurs
20+
UseThousandsSeparator = true // Default value
2021
};
2122
private readonly Engine _engine = new(new Configuration
2223
{
2324
Scope = new Dictionary<string, object>
24-
{
25-
{ "e", Math.E }, // e is not contained in the default mages engine
26-
}
25+
{
26+
{ "e", Math.E }, // e is not contained in the default mages engine
27+
}
2728
});
2829

2930
public CalculatorPluginTest()
@@ -41,6 +42,44 @@ public CalculatorPluginTest()
4142
engineField.SetValue(null, _engine);
4243
}
4344

45+
[Test]
46+
public void ThousandsSeparatorTest_Enabled()
47+
{
48+
_settings.UseThousandsSeparator = true;
49+
50+
_settings.DecimalSeparator = DecimalSeparator.Dot;
51+
var result = GetCalculationResult("1000+234");
52+
// When thousands separator is enabled, the result should contain a separator
53+
// Since decimal separator is dot, thousands separator should be comma
54+
ClassicAssert.AreEqual("1,234", result);
55+
56+
_settings.DecimalSeparator = DecimalSeparator.Comma;
57+
var result2 = GetCalculationResult("1000+234");
58+
// When thousands separator is enabled, the result should contain a separator
59+
// Since decimal separator is comma, thousands separator should be dot
60+
ClassicAssert.AreEqual("1.234", result2);
61+
}
62+
63+
[Test]
64+
public void ThousandsSeparatorTest_Disabled()
65+
{
66+
_settings.UseThousandsSeparator = false;
67+
_settings.DecimalSeparator = DecimalSeparator.UseSystemLocale;
68+
69+
var result = GetCalculationResult("1000+234");
70+
ClassicAssert.AreEqual("1234", result);
71+
}
72+
73+
[Test]
74+
public void ThousandsSeparatorTest_LargeNumber()
75+
{
76+
_settings.UseThousandsSeparator = false;
77+
_settings.DecimalSeparator = DecimalSeparator.UseSystemLocale;
78+
79+
var result = GetCalculationResult("1000000+234567");
80+
ClassicAssert.AreEqual("1234567", result);
81+
}
82+
4483
// Basic operations
4584
[TestCase(@"1+1", "2")]
4685
[TestCase(@"2-1", "1")]
@@ -77,6 +116,9 @@ public CalculatorPluginTest()
77116
[TestCase(@"invalid_expression", "")]
78117
public void CalculatorTest(string expression, string result)
79118
{
119+
_settings.UseThousandsSeparator = false;
120+
_settings.DecimalSeparator = DecimalSeparator.Dot;
121+
80122
ClassicAssert.AreEqual(GetCalculationResult(expression), result);
81123
}
82124

Flow.Launcher/App.xaml.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
259259

260260
await PluginManager.InitializePluginsAsync(_mainVM);
261261

262+
// Refresh the history results after plugins are initialized so that we can parse the absolute icon paths
263+
_mainVM.RefreshLastOpenedHistoryResults();
264+
262265
// Refresh home page after plugins are initialized because users may open main window during plugin initialization
263266
// And home page is created without full plugin list
264267
if (_settings.ShowHomePage && _mainVM.QueryResultsSelected() && string.IsNullOrEmpty(_mainVM.QueryText))

Flow.Launcher/Flow.Launcher.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@
138138
<PrivateAssets>all</PrivateAssets>
139139
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
140140
</PackageReference>
141-
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.10.2.1" />
141+
<PackageReference Include="iNKORE.UI.WPF.Modern" Version="0.10.1" />
142142
<PackageReference Include="MdXaml" Version="1.27.0" />
143143
<PackageReference Include="MdXaml.AnimatedGif" Version="1.27.0" />
144144
<PackageReference Include="MdXaml.Html" Version="1.27.0" />

Flow.Launcher/Helper/ResultHelper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Flow.Launcher.Helper;
1111

1212
public static class ResultHelper
1313
{
14-
public static async Task<Result?> PopulateResultsAsync(LastOpenedHistoryItem item)
14+
public static async Task<Result?> PopulateResultsAsync(LastOpenedHistoryResult item)
1515
{
1616
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
1717
}
@@ -24,7 +24,7 @@ public static class ResultHelper
2424
if (query == null) return null;
2525
try
2626
{
27-
var freshResults = await plugin.Plugin.QueryAsync(query, CancellationToken.None);
27+
var freshResults = await PluginManager.QueryForPluginAsync(plugin, query, CancellationToken.None);
2828
// Try to match by record key first if it is valid, otherwise fall back to title + subtitle match
2929
if (string.IsNullOrEmpty(recordKey))
3030
{

0 commit comments

Comments
 (0)