using System;
using System.Runtime;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Media;
namespace Flow.Launcher.Plugin
{
///
/// Describes a result of a executed by a plugin
///
public class Result
{
private string _pluginDirectory;
private string _icoPath;
private string _copyText = string.Empty;
///
/// The title of the result. This is always required.
///
public string Title { get; set; }
///
/// Provides additional details for the result. This is optional
///
public string SubTitle { get; set; } = string.Empty;
///
/// This holds the action keyword that triggered the result.
/// If result is triggered by global keyword: *, this should be empty.
///
public string ActionKeywordAssigned { get; set; }
///
/// This holds the text which can be provided by plugin to be copied to the
/// user's clipboard when Ctrl + C is pressed on a result. If the text is a file/directory path
/// flow will copy the actual file/folder instead of just the path text.
///
public string CopyText
{
get => string.IsNullOrEmpty(_copyText) ? SubTitle : _copyText;
set => _copyText = value;
}
///
/// This holds the text which can be provided by plugin to help Flow autocomplete text
/// for user on the plugin result. If autocomplete action for example is tab, pressing tab will have
/// the default constructed autocomplete text (result's Title), or the text provided here if not empty.
///
/// When a value is not set, the will be used.
public string AutoCompleteText { get; set; }
///
/// The image to be displayed for the result.
///
/// Can be a local file path or a URL.
/// GlyphInfo is prioritized if not null
public string IcoPath
{
get { return _icoPath; }
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))
{
_icoPath = Path.Combine(PluginDirectory, value);
}
else
{
_icoPath = value;
}
}
}
///
/// Determines if Icon has a border radius
///
public bool RoundedIcon { get; set; } = false;
///
/// Delegate function that produces an
///
///
public delegate ImageSource IconDelegate();
///
/// Delegate to load an icon for this result.
///
public IconDelegate Icon;
///
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
///
public GlyphInfo Glyph { get; init; }
///
/// An action to take in the form of a function call when the result has been selected.
///
///
/// The function is invoked with an as the only parameter.
/// Its result determines what happens to Flow Launcher's query form:
/// when true, the form will be hidden; when false, it will stay in focus.
///
public Func Action { get; set; }
///
/// An async action to take in the form of a function call when the result has been selected.
///
///
/// The function is invoked with an as the only parameter and awaited.
/// Its result determines what happens to Flow Launcher's query form:
/// when true, the form will be hidden; when false, it will stay in focus.
///
public Func> AsyncAction { get; set; }
///
/// Priority of the current result
///
/// default: 0
public int Score { get; set; }
///
/// A list of indexes for the characters to be highlighted in Title
///
public IList TitleHighlightData { get; set; }
///
/// Query information associated with the result
///
internal Query OriginQuery { get; set; }
///
/// Plugin directory
///
public string PluginDirectory
{
get { return _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.
IcoPath = _icoPath;
}
}
///
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
///
///
/// As external information for ContextMenu
///
public object ContextData { get; set; }
///
/// Plugin ID that generated this result
///
public string PluginID { get; internal set; }
///
/// Show message as ToolTip on result Title hover over
///
public string TitleToolTip { get; set; }
///
/// Show message as ToolTip on result SubTitle hover over
///
public string SubTitleToolTip { get; set; }
///
/// Customized Preview Panel
///
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
///
public int? ProgressBar { get; set; }
///
/// Optionally set the color of the progress bar
///
/// #26a0da (blue)
public string ProgressBarColor { get; set; } = "#26a0da";
///
/// Contains data used to populate the preview section of this result.
///
public PreviewInfo Preview { get; set; } = PreviewInfo.Default;
///
/// Determines if the user selection count should be added to the score. This can be useful when set to false to allow the result sequence order to be the same everytime instead of changing based on selection.
///
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.
/// If the plugin does not specific this, FL just uses Title and SubTitle to identify this result.
///
public string RecordKey { get; set; } = string.Empty;
///
/// Info of the preview section of a
///
public record PreviewInfo
{
///
/// Full image used for preview panel
///
public string PreviewImagePath { get; set; } = null;
///
/// Determines if the preview image should occupy the full width of the preview panel.
///
public bool IsMedia { get; set; } = false;
///
/// Result description text that is shown at the bottom of the preview panel.
///
///
/// When a value is not set, the will be used.
///
public string Description { get; set; } = null;
///
/// Delegate to get the preview panel's image
///
public IconDelegate PreviewDelegate { get; set; } = null;
///
/// File path of the result. For third-party programs providing external preview.
///
public string FilePath { get; set; } = null;
///
/// Default instance of
///
public static PreviewInfo Default { get; } = new()
{
PreviewImagePath = null,
Description = null,
IsMedia = false,
PreviewDelegate = null,
FilePath = null,
};
}
}
}