Add plugin hotkey model

This commit is contained in:
Jack251970 2025-06-25 20:24:50 +08:00
parent f991d91b8f
commit 94f3746ddc
5 changed files with 271 additions and 0 deletions

View file

@ -26,6 +26,7 @@ namespace Flow.Launcher.Core.Plugin
private static IEnumerable<PluginPair> _contextMenuPlugins;
private static IEnumerable<PluginPair> _homePlugins;
private static IEnumerable<PluginPair> _hotkeyPlugins;
public static List<PluginPair> AllPlugins { get; private set; }
public static readonly HashSet<PluginPair> GlobalPlugins = new();
@ -250,6 +251,8 @@ namespace Flow.Launcher.Core.Plugin
_contextMenuPlugins = GetPluginsForInterface<IContextMenu>();
_homePlugins = GetPluginsForInterface<IAsyncHomeQuery>();
_hotkeyPlugins = GetPluginsForInterface<IPluginHotkey>();
Settings.UpdatePluginHotkeyInfo(GetPluginHotkeyInfo());
foreach (var plugin in AllPlugins)
{
@ -442,6 +445,18 @@ namespace Flow.Launcher.Core.Plugin
return _homePlugins.Any(p => p.Metadata.ID == id);
}
public static Dictionary<PluginPair, List<BasePluginHotkey>> GetPluginHotkeyInfo()
{
var hotkeyPluginInfos = new Dictionary<PluginPair, List<BasePluginHotkey>>();
foreach (var plugin in _hotkeyPlugins)
{
var hotkeys = ((IPluginHotkey)plugin.Plugin).GetPuginHotkeys();
hotkeyPluginInfos.Add(plugin, hotkeys);
}
return hotkeyPluginInfos;
}
public static bool ActionKeywordRegistered(string actionKeyword)
{
// this method is only checking for action keywords (defined as not '*') registration

View file

@ -89,6 +89,110 @@ namespace Flow.Launcher.Infrastructure.UserSettings
}
}
/// <summary>
/// Update plugin hotkey information in metadata and plugin setting.
/// </summary>
/// <param name="hotkeyPluginInfo"></param>
public void UpdatePluginHotkeyInfo(Dictionary<PluginPair, List<BasePluginHotkey>> hotkeyPluginInfo)
{
foreach (var info in hotkeyPluginInfo)
{
var pluginPair = info.Key;
var hotkeyInfo = info.Value;
var metadata = pluginPair.Metadata;
if (Plugins.TryGetValue(pluginPair.Metadata.ID, out var plugin))
{
if (plugin.pluginHotkeys == null || plugin.pluginHotkeys.Count == 0)
{
// If plugin hotkeys does not exist, create a new one and initialize with default values
plugin.pluginHotkeys = new List<PluginHotkey>();
foreach (var hotkey in hotkeyInfo)
{
plugin.pluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = hotkey.DefaultHotkey // use default value
});
metadata.PluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = hotkey.DefaultHotkey // use default value
});
}
}
else
{
// If plugin hotkeys exist, update the existing hotkeys with the new values
foreach (var hotkey in hotkeyInfo)
{
var existingHotkey = plugin.pluginHotkeys.Find(h => h.Id == hotkey.Id);
if (existingHotkey != null)
{
// Update existing hotkey
existingHotkey.DefaultHotkey = hotkey.DefaultHotkey; // hotkey info provides default values
metadata.PluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = existingHotkey.Hotkey // use settings value
});
}
else
{
// Add new hotkey if it does not exist
plugin.pluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = hotkey.DefaultHotkey // use default value
});
metadata.PluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = hotkey.DefaultHotkey // use default value
});
}
}
}
}
else
{
// If settings does not exist, create a new one
Plugins[metadata.ID] = new Plugin
{
ID = metadata.ID,
Name = metadata.Name,
Version = metadata.Version,
DefaultActionKeywords = metadata.ActionKeywords, // metadata provides default values
ActionKeywords = metadata.ActionKeywords, // use default value
Disabled = metadata.Disabled,
HomeDisabled = metadata.HomeDisabled,
Priority = metadata.Priority,
DefaultSearchDelayTime = metadata.SearchDelayTime, // metadata provides default values
SearchDelayTime = metadata.SearchDelayTime, // use default value
};
foreach (var hotkey in hotkeyInfo)
{
Plugins[metadata.ID].pluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = hotkey.DefaultHotkey // use default value
});
metadata.PluginHotkeys.Add(new PluginHotkey
{
Id = hotkey.Id,
DefaultHotkey = hotkey.DefaultHotkey, // hotkey info provides default values
Hotkey = hotkey.DefaultHotkey // use default value
});
}
}
}
}
public Plugin GetPluginSettings(string id)
{
if (Plugins.TryGetValue(id, out var plugin))
@ -126,6 +230,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public int? SearchDelayTime { get; set; }
public List<PluginHotkey> pluginHotkeys { get; set; } = new List<PluginHotkey>();
/// <summary>
/// Used only to save the state of the plugin in settings
/// </summary>

View file

@ -0,0 +1,16 @@
using System.Collections.Generic;
namespace Flow.Launcher.Plugin
{
/// <summary>
/// Represent plugins that support global hotkey or search window hotkey.
/// </summary>
public interface IPluginHotkey : IFeatures
{
/// <summary>
/// Get the list of plugin hotkeys which will be registered in the settings page.
/// </summary>
/// <returns></returns>
List<BasePluginHotkey> GetPuginHotkeys();
}
}

View file

@ -0,0 +1,129 @@
using System;
namespace Flow.Launcher.Plugin;
/// <summary>
/// Represents a base plugin hotkey model.
/// </summary>
/// <remarks>
/// Do not use this class directly. Use <see cref="GlobalPluginHotkey"/> or <see cref="SearchWindowPluginHotkey"/> instead.
/// </remarks>
public class BasePluginHotkey
{
/// <summary>
/// Initializes a new instance of the <see cref="BasePluginHotkey"/> class with the specified hotkey type.
/// </summary>
/// <param name="type"></param>
public BasePluginHotkey(HotkeyType type)
{
HotkeyType = type;
}
/// <summary>
/// The unique identifier for the hotkey, which is used to identify and rank the hotkey in the settings page.
/// </summary>
public int Id { get; set; } = 0;
/// <summary>
/// The name of the hotkey, which will be displayed in the settings page.
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// The description of the hotkey, which will be displayed in the settings page.
/// </summary>
public string Description { get; set; } = string.Empty;
/// <summary>
/// The glyph information for the hotkey, which will be displayed in the settings page.
/// </summary>
public GlyphInfo Glyph { get; set; }
/// <summary>
/// The default hotkey that will be used if the user does not set a custom hotkey.
/// </summary>
public string DefaultHotkey { get; set; } = string.Empty;
/// <summary>
/// The type of the hotkey, which can be either global or search window specific.
/// </summary>
public HotkeyType HotkeyType { get; } = HotkeyType.Global;
/// <summary>
/// Indicates whether the hotkey is editable by the user in the settings page.
/// </summary>
public bool Editable { get; set; } = false;
}
/// <summary>
/// Represent a global plugin hotkey model.
/// </summary>
public class GlobalPluginHotkey : BasePluginHotkey
{
/// <summary>
/// Initializes a new instance of the <see cref="GlobalPluginHotkey"/> class.
/// </summary>
public GlobalPluginHotkey() : base(HotkeyType.Global)
{
}
/// <summary>
/// An action that will be executed when the hotkey is triggered.
/// </summary>
public Action Action { get; set; } = null;
}
/// <summary>
/// Represents a plugin hotkey that is specific to the search window.
/// </summary>
public class SearchWindowPluginHotkey : BasePluginHotkey
{
/// <summary>
/// Initializes a new instance of the <see cref="SearchWindowPluginHotkey"/> class.
/// </summary>
public SearchWindowPluginHotkey() : base(HotkeyType.SearchWindow)
{
}
/// <summary>
/// An action that will be executed when the hotkey is triggered.
/// </summary>
public Func<Result, bool> Action { get; set; } = null;
}
/// <summary>
/// Represents the type of hotkey for a plugin.
/// </summary>
public enum HotkeyType
{
/// <summary>
/// A hotkey that will be trigged globally, regardless of the active window.
/// </summary>
Global,
/// <summary>
/// A hotkey that will be triggered only when the search window is active.
/// </summary>
SearchWindow
}
/// <summary>
/// Represents a plugin hotkey model which is used to store the hotkey information for a plugin.
/// </summary>
public class PluginHotkey
{
/// <summary>
/// The unique identifier for the hotkey.
/// </summary>
public int Id { get; set; } = 0;
/// <summary>
/// The default hotkey that will be used if the user does not set a custom hotkey.
/// </summary>
public string DefaultHotkey { get; set; } = string.Empty;
/// <summary>
/// The current hotkey that the user has set for the plugin.
/// </summary>
public string Hotkey { get; set; } = string.Empty;
}

View file

@ -152,6 +152,11 @@ namespace Flow.Launcher.Plugin
/// </summary>
public string PluginCacheDirectoryPath { get; internal set; }
/// <summary>
/// List of registered plugin hotkeys.
/// </summary>
public List<PluginHotkey> PluginHotkeys { get; set; } = new List<PluginHotkey>();
/// <summary>
/// Convert <see cref="PluginMetadata"/> to string.
/// </summary>