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)) { _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 bool Equals(object obj) { var r = obj as Result; var equality = string.Equals(r?.Title, Title) && string.Equals(r?.SubTitle, SubTitle) && string.Equals(r?.AutoCompleteText, AutoCompleteText) && string.Equals(r?.CopyText, CopyText) && string.Equals(r?.IcoPath, IcoPath) && TitleHighlightData == r.TitleHighlightData; return equality; } /// public override int GetHashCode() { return HashCode.Combine(Title, SubTitle, AutoCompleteText, CopyText, 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, }; } /// /// 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; /// /// Info of the preview section of a /// public record PreviewInfo { /// /// Full image used for preview panel /// public string PreviewImagePath { get; set; } /// /// Determines if the preview image should occupy the full width of the preview panel. /// public bool IsMedia { get; set; } /// /// 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; } /// /// Delegate to get the preview panel's image /// public IconDelegate PreviewDelegate { get; set; } /// /// Default instance of /// public static PreviewInfo Default { get; } = new() { PreviewImagePath = null, Description = null, IsMedia = false, PreviewDelegate = null, }; } } }