diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs index 2e4befdc2..7e520175e 100644 --- a/Flow.Launcher.Plugin/Result.cs +++ b/Flow.Launcher.Plugin/Result.cs @@ -12,12 +12,19 @@ namespace Flow.Launcher.Plugin /// public class Result { + /// + /// 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. + /// + public const int MaxScore = int.MaxValue; + private string _pluginDirectory; private string _icoPath; private string _copyText = string.Empty; + private string _badgePath; + /// /// The title of the result. This is always required. /// @@ -80,6 +87,33 @@ namespace Flow.Launcher.Plugin } } + /// + /// The image to be displayed for the badge of the result. + /// + /// Can be a local file path or a URL. + /// If null or empty, will use plugin icon + public string BadgePath + { + get => _badgePath; + 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)) + { + _badgePath = Path.Combine(PluginDirectory, value); + } + else + { + _badgePath = value; + } + } + } + /// /// Determines if Icon has a border radius /// @@ -94,7 +128,12 @@ namespace Flow.Launcher.Plugin /// /// Delegate to load an icon for this result. /// - public IconDelegate Icon; + public IconDelegate Icon { get; set; } + + /// + /// Delegate to load an icon for the badge of this result. + /// + public IconDelegate BadgeIcon { get; set; } /// /// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons) @@ -154,47 +193,6 @@ namespace Flow.Launcher.Plugin } } - /// - public override string ToString() - { - return Title + SubTitle + Score; - } - - /// - /// Clones the current result - /// - 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 - }; - } - /// /// Additional data associated with this result /// @@ -223,16 +221,6 @@ namespace Flow.Launcher.Plugin /// public Lazy PreviewPanel { get; set; } - /// - /// Run this result, asynchronously - /// - /// - /// - public ValueTask ExecuteAsync(ActionContext context) - { - return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false); - } - /// /// Progress bar display. Providing an int value between 0-100 will trigger the progress bar to be displayed on the result /// @@ -254,11 +242,6 @@ namespace Flow.Launcher.Plugin /// public bool AddSelectedCount { get; set; } = true; - /// - /// 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. - /// - public const int MaxScore = int.MaxValue; - /// /// 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. @@ -267,6 +250,59 @@ namespace Flow.Launcher.Plugin /// public string RecordKey { get; set; } = null; + /// + /// Run this result, asynchronously + /// + /// + /// + public ValueTask ExecuteAsync(ActionContext context) + { + return AsyncAction?.Invoke(context) ?? ValueTask.FromResult(Action?.Invoke(context) ?? false); + } + + /// + public override string ToString() + { + return Title + SubTitle + Score; + } + + /// + /// Clones the current result + /// + public Result Clone() + { + return new Result + { + Title = Title, + SubTitle = SubTitle, + ActionKeywordAssigned = ActionKeywordAssigned, + CopyText = CopyText, + AutoCompleteText = AutoCompleteText, + IcoPath = IcoPath, + BadgePath = BadgePath, + 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 + }; + } + /// /// Info of the preview section of a /// diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 4a6c1d639..38efca72b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1268,8 +1268,7 @@ namespace Flow.Launcher.ViewModel // Task.Yield will force it to run in ThreadPool await Task.Yield(); - IReadOnlyList results = - await PluginManager.QueryForPluginAsync(plugin, query, token); + var results = await PluginManager.QueryForPluginAsync(plugin, query, token); if (token.IsCancellationRequested) return; @@ -1285,6 +1284,14 @@ namespace Flow.Launcher.ViewModel resultsCopy = DeepCloneResults(results, token); } + foreach (var result in results) + { + if (string.IsNullOrEmpty(result.BadgePath)) + { + result.BadgePath = plugin.Metadata.IcoPath; + } + } + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query, token, reSelect))) {