mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Implement displaying localized warning messages for duplicate hotkeys in HotkeyControlDialog, and implement the ability to overwrite them
This commit is contained in:
parent
737d29a0fb
commit
15d5510fae
5 changed files with 168 additions and 45 deletions
|
|
@ -2,7 +2,16 @@
|
|||
|
||||
namespace Flow.Launcher.Infrastructure.Hotkey;
|
||||
|
||||
/// <summary>
|
||||
/// Interface that you should implement in your settings class to be able to pass it to
|
||||
/// <c>Flow.Launcher.HotkeyControlDialog</c>. It allows the dialog to display the hotkeys that have already been
|
||||
/// registered, and optionally provide a way to unregister them.
|
||||
/// </summary>
|
||||
public interface IHotkeySettings
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of hotkeys that have already been registered. The dialog will display these hotkeys and provide a way to
|
||||
/// unregister them.
|
||||
/// </summary>
|
||||
public List<RegisteredHotkeyData> RegisteredHotkeys { get; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,16 +4,116 @@ namespace Flow.Launcher.Infrastructure.Hotkey;
|
|||
|
||||
#nullable enable
|
||||
|
||||
/// <summary>
|
||||
/// Represents a hotkey that has been registered. Used in <c>Flow.Launcher.HotkeyControlDialog</c> via
|
||||
/// <see cref="UserSettings"/> and <see cref="IHotkeySettings"/> to display errors if user tries to register a hotkey
|
||||
/// that has already been registered, and optionally provides a way to unregister the hotkey.
|
||||
/// </summary>
|
||||
public record RegisteredHotkeyData
|
||||
{
|
||||
/// <summary>
|
||||
/// <see cref="HotkeyModel"/> representation of this hotkey.
|
||||
/// </summary>
|
||||
public HotkeyModel Hotkey { get; }
|
||||
public string Description { get; }
|
||||
|
||||
/// <summary>
|
||||
/// String key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||
/// </summary>
|
||||
public string DescriptionResourceKey { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Array of values that will replace <c>{0}</c>, <c>{1}</c>, <c>{2}</c>, etc. in the localized string found via
|
||||
/// <see cref="DescriptionResourceKey"/>.
|
||||
/// </summary>
|
||||
public object?[] DescriptionFormatVariables { get; } = Array.Empty<object?>();
|
||||
|
||||
/// <summary>
|
||||
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that
|
||||
/// this hotkey can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||
/// </summary>
|
||||
public Action? RemoveHotkey { get; }
|
||||
|
||||
public RegisteredHotkeyData(string hotkey, string description, Action? removeHotkey = null)
|
||||
/// <summary>
|
||||
/// Creates an instance of <c>RegisteredHotkeyData</c>. Assumes that the key specified in
|
||||
/// <c>descriptionResourceKey</c> doesn't need any arguments for <c>string.Format</c>. If it does,
|
||||
/// use one of the other constructors.
|
||||
/// </summary>
|
||||
/// <param name="hotkey">
|
||||
/// The hotkey this class will represent.
|
||||
/// Example values: <c>F1</c>, <c>Ctrl+Shift+Enter</c>
|
||||
/// </param>
|
||||
/// <param name="descriptionResourceKey">
|
||||
/// The key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||
/// </param>
|
||||
/// <param name="removeHotkey">
|
||||
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that this hotkey
|
||||
/// can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||
/// </param>
|
||||
public RegisteredHotkeyData(string hotkey, string descriptionResourceKey, Action? removeHotkey = null)
|
||||
{
|
||||
Hotkey = new HotkeyModel(hotkey);
|
||||
Description = description;
|
||||
DescriptionResourceKey = descriptionResourceKey;
|
||||
RemoveHotkey = removeHotkey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <c>RegisteredHotkeyData</c>. Assumes that the key specified in
|
||||
/// <c>descriptionResourceKey</c> needs exactly one argument for <c>string.Format</c>.
|
||||
/// </summary>
|
||||
/// <param name="hotkey">
|
||||
/// The hotkey this class will represent.
|
||||
/// Example values: <c>F1</c>, <c>Ctrl+Shift+Enter</c>
|
||||
/// </param>
|
||||
/// <param name="descriptionResourceKey">
|
||||
/// The key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||
/// </param>
|
||||
/// <param name="descriptionFormatVariable">
|
||||
/// The value that will replace <c>{0}</c> in the localized string found via <c>description</c>.
|
||||
/// </param>
|
||||
/// <param name="removeHotkey">
|
||||
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that this hotkey
|
||||
/// can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||
/// </param>
|
||||
public RegisteredHotkeyData(
|
||||
string hotkey, string descriptionResourceKey, object? descriptionFormatVariable, Action? removeHotkey = null
|
||||
)
|
||||
{
|
||||
Hotkey = new HotkeyModel(hotkey);
|
||||
DescriptionResourceKey = descriptionResourceKey;
|
||||
DescriptionFormatVariables = new[] { descriptionFormatVariable };
|
||||
RemoveHotkey = removeHotkey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an instance of <c>RegisteredHotkeyData</c>. Assumes that the key specified in
|
||||
/// <paramref name="descriptionResourceKey"/> needs multiple arguments for <c>string.Format</c>.
|
||||
/// </summary>
|
||||
/// <param name="hotkey">
|
||||
/// The hotkey this class will represent.
|
||||
/// Example values: <c>F1</c>, <c>Ctrl+Shift+Enter</c>
|
||||
/// </param>
|
||||
/// <param name="descriptionResourceKey">
|
||||
/// The key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||
/// </param>
|
||||
/// <param name="descriptionFormatVariables">
|
||||
/// Array of values that will replace <c>{0}</c>, <c>{1}</c>, <c>{2}</c>, etc.
|
||||
/// in the localized string found via <c>description</c>.
|
||||
/// </param>
|
||||
/// <param name="removeHotkey">
|
||||
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that this hotkey
|
||||
/// can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||
/// </param>
|
||||
public RegisteredHotkeyData(
|
||||
string hotkey, string descriptionResourceKey, object?[] descriptionFormatVariables, Action? removeHotkey = null
|
||||
)
|
||||
{
|
||||
Hotkey = new HotkeyModel(hotkey);
|
||||
DescriptionResourceKey = descriptionResourceKey;
|
||||
DescriptionFormatVariables = descriptionFormatVariables;
|
||||
RemoveHotkey = removeHotkey;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -282,65 +282,69 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
{
|
||||
var list = new List<RegisteredHotkeyData>
|
||||
{
|
||||
new("Escape", "Escape"), // TODO
|
||||
new("F5", "ReloadPluginHotkey"), // TODO
|
||||
new("Alt+Home", "Select last result"), // TODO
|
||||
new("Alt+End", "Select last result"), // TODO
|
||||
new("Ctrl+R", "Requery"), // TODO
|
||||
new("Ctrl+H", "ToggleHistoryHotkey"), // TODO
|
||||
new("Ctrl+OemCloseBrackets", "QuickWidthHotkey"), // TODO
|
||||
new("Ctrl+OemOpenBrackets", "QuickWidthHotkey"), // TODO
|
||||
new("Ctrl+OemPlus", "QuickHeightHotkey"), // TODO
|
||||
new("Ctrl+OemMinus", "QuickHeightHotkey"), // TODO
|
||||
new("Ctrl+Shift+Enter", "HotkeyCtrlShiftEnterDesc"), // TODO
|
||||
new("Shift+Enter", "OpenContextMenuHotkey"), // TODO
|
||||
new("Enter", "HotkeyRunDesc"), // TODO
|
||||
new("Ctrl+Enter", "Open result"), // TODO
|
||||
new("Alt+Enter", "Open result"), // TODO
|
||||
new("Ctrl+F12", "ToggleGameModeHotkey"), // TODO
|
||||
new("Ctrl+Shift+C", "Copy alternative"), // TODO
|
||||
new("Up", "HotkeyLeftRightDesc"),
|
||||
new("Down", "HotkeyLeftRightDesc"),
|
||||
new("Left", "HotkeyUpDownDesc"),
|
||||
new("Right", "HotkeyUpDownDesc"),
|
||||
new("Escape", "HotkeyESCDesc"),
|
||||
new("F5", "ReloadPluginHotkey"),
|
||||
new("Alt+Home", "HotkeySelectFirstResult"),
|
||||
new("Alt+End", "HotkeySelectLastResult"),
|
||||
new("Ctrl+R", "HotkeyRequery"),
|
||||
new("Ctrl+H", "ToggleHistoryHotkey"),
|
||||
new("Ctrl+OemCloseBrackets", "QuickWidthHotkey"),
|
||||
new("Ctrl+OemOpenBrackets", "QuickWidthHotkey"),
|
||||
new("Ctrl+OemPlus", "QuickHeightHotkey"),
|
||||
new("Ctrl+OemMinus", "QuickHeightHotkey"),
|
||||
new("Ctrl+Shift+Enter", "HotkeyCtrlShiftEnterDesc"),
|
||||
new("Shift+Enter", "OpenContextMenuHotkey"),
|
||||
new("Enter", "HotkeyRunDesc"),
|
||||
new("Ctrl+Enter", "OpenContainFolderHotkey"),
|
||||
new("Alt+Enter", "HotkeyOpenResult"),
|
||||
new("Ctrl+F12", "ToggleGameModeHotkey"),
|
||||
new("Ctrl+Shift+C", "CopyFilePathHotkey"),
|
||||
|
||||
new($"{OpenResultModifiers}+D1", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D2", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D3", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D4", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D5", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D6", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D7", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D8", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D9", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D0", "Open Result"), // TODO
|
||||
new($"{OpenResultModifiers}+D1", "HotkeyOpenResultN", 1),
|
||||
new($"{OpenResultModifiers}+D2", "HotkeyOpenResultN", 2),
|
||||
new($"{OpenResultModifiers}+D3", "HotkeyOpenResultN", 3),
|
||||
new($"{OpenResultModifiers}+D4", "HotkeyOpenResultN", 4),
|
||||
new($"{OpenResultModifiers}+D5", "HotkeyOpenResultN", 5),
|
||||
new($"{OpenResultModifiers}+D6", "HotkeyOpenResultN", 6),
|
||||
new($"{OpenResultModifiers}+D7", "HotkeyOpenResultN", 7),
|
||||
new($"{OpenResultModifiers}+D8", "HotkeyOpenResultN", 8),
|
||||
new($"{OpenResultModifiers}+D9", "HotkeyOpenResultN", 9),
|
||||
new($"{OpenResultModifiers}+D0", "HotkeyOpenResultN", 10)
|
||||
};
|
||||
|
||||
if(!string.IsNullOrEmpty(Hotkey))
|
||||
list.Add(new(Hotkey, "Open main window", () => Hotkey = "")); // TODO
|
||||
list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = ""));
|
||||
if(!string.IsNullOrEmpty(PreviewHotkey))
|
||||
list.Add(new(PreviewHotkey, "Preview Hotkey", () => PreviewHotkey = "")); // TODO
|
||||
list.Add(new(PreviewHotkey, "previewHotkey", () => PreviewHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(AutoCompleteHotkey))
|
||||
list.Add(new(AutoCompleteHotkey, "AutoCompleteHotkey", () => AutoCompleteHotkey = "")); // TODO
|
||||
list.Add(new(AutoCompleteHotkey, "autoCompleteHotkey", () => AutoCompleteHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(AutoCompleteHotkey2))
|
||||
list.Add(new(AutoCompleteHotkey2, "AutoCompleteHotkey", () => AutoCompleteHotkey2 = "")); // TODO
|
||||
list.Add(new(AutoCompleteHotkey2, "autoCompleteHotkey", () => AutoCompleteHotkey2 = ""));
|
||||
if(!string.IsNullOrEmpty(SelectNextItemHotkey))
|
||||
list.Add(new(SelectNextItemHotkey, "SelectNextItemHotkey", () => SelectNextItemHotkey = "")); // TODO
|
||||
list.Add(new(SelectNextItemHotkey, "SelectNextItemHotkey", () => SelectNextItemHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(SelectNextItemHotkey2))
|
||||
list.Add(new(SelectNextItemHotkey2, "SelectNextItemHotkey", () => SelectNextItemHotkey2 = "")); // TODO
|
||||
list.Add(new(SelectNextItemHotkey2, "SelectNextItemHotkey", () => SelectNextItemHotkey2 = ""));
|
||||
if(!string.IsNullOrEmpty(SelectPrevItemHotkey))
|
||||
list.Add(new(SelectPrevItemHotkey, "SelectPrevItemHotkey", () => SelectPrevItemHotkey = "")); // TODO
|
||||
list.Add(new(SelectPrevItemHotkey, "SelectPrevItemHotkey", () => SelectPrevItemHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(SelectPrevItemHotkey2))
|
||||
list.Add(new(SelectPrevItemHotkey2, "SelectPrevItemHotkey", () => SelectPrevItemHotkey2 = "")); // TODO
|
||||
list.Add(new(SelectPrevItemHotkey2, "SelectPrevItemHotkey", () => SelectPrevItemHotkey2 = ""));
|
||||
if(!string.IsNullOrEmpty(SettingWindowHotkey))
|
||||
list.Add(new(SettingWindowHotkey, "SettingWindowHotkey", () => SettingWindowHotkey = "")); // TODO
|
||||
list.Add(new(SettingWindowHotkey, "SettingWindowHotkey", () => SettingWindowHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(OpenContextMenuHotkey))
|
||||
list.Add(new(OpenContextMenuHotkey, "OpenContextMenuHotkey", () => OpenContextMenuHotkey = "")); // TODO
|
||||
list.Add(new(OpenContextMenuHotkey, "OpenContextMenuHotkey", () => OpenContextMenuHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(SelectNextPageHotkey))
|
||||
list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = "")); // TODO
|
||||
list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(SelectPrevPageHotkey))
|
||||
list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = "")); // TODO
|
||||
list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = ""));
|
||||
|
||||
foreach (var customPluginHotkey in CustomPluginHotkeys)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(customPluginHotkey.Hotkey))
|
||||
list.Add(new(customPluginHotkey.Hotkey, "Custom plugin hotkey", () => customPluginHotkey.Hotkey = "")); // TODO
|
||||
list.Add(new(customPluginHotkey.Hotkey, "customQueryHotkey", () => customPluginHotkey.Hotkey = ""));
|
||||
}
|
||||
|
||||
return list;
|
||||
|
|
|
|||
|
|
@ -119,12 +119,16 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
|
||||
if (_hotkeySettings.RegisteredHotkeys.FirstOrDefault(v => v.Hotkey == hotkey) is { } registeredHotkeyData)
|
||||
{
|
||||
var description = string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation(registeredHotkeyData.DescriptionResourceKey),
|
||||
registeredHotkeyData.DescriptionFormatVariables
|
||||
);
|
||||
Alert.Visibility = Visibility.Visible;
|
||||
if (registeredHotkeyData.RemoveHotkey is not null)
|
||||
{
|
||||
tbMsg.Text = string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("hotkeyUnavailableEditable"),
|
||||
registeredHotkeyData.Description
|
||||
description
|
||||
);
|
||||
SaveBtn.IsEnabled = false;
|
||||
SaveBtn.Visibility = Visibility.Collapsed;
|
||||
|
|
@ -136,7 +140,7 @@ public partial class HotkeyControlDialog : ContentDialog
|
|||
{
|
||||
tbMsg.Text = string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("hotkeyUnavailableUneditable"),
|
||||
registeredHotkeyData.Description
|
||||
description
|
||||
);
|
||||
SaveBtn.IsEnabled = false;
|
||||
SaveBtn.Visibility = Visibility.Visible;
|
||||
|
|
|
|||
|
|
@ -398,6 +398,12 @@
|
|||
<system:String x:Key="HotkeyCtrlIDesc">Open Setting Window</system:String>
|
||||
<system:String x:Key="HotkeyF5Desc">Reload Plugin Data</system:String>
|
||||
|
||||
<system:String x:Key="HotkeySelectFirstResult">Select first result</system:String>
|
||||
<system:String x:Key="HotkeySelectLastResult">Select last result</system:String>
|
||||
<system:String x:Key="HotkeyRequery">Run current query again</system:String>
|
||||
<system:String x:Key="HotkeyOpenResult">Open result</system:String>
|
||||
<system:String x:Key="HotkeyOpenResultN">Open result #{0}</system:String>
|
||||
|
||||
<system:String x:Key="RecommendWeather">Weather</system:String>
|
||||
<system:String x:Key="RecommendWeatherDesc">Weather in Google Result</system:String>
|
||||
<system:String x:Key="RecommendShell">> ping 8.8.8.8</system:String>
|
||||
|
|
|
|||
Loading…
Reference in a new issue