44using System . Threading . Tasks ;
55using System . Windows . Controls ;
66using System . Windows . Media ;
7+ using System . Text . Json . Serialization ;
78
89namespace 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>
0 commit comments