diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 75f208c9ed1..b8f1408e7cb 100644 --- a/Flow.Launcher.Infrastructure/Logger/Log.cs +++ b/Flow.Launcher.Infrastructure/Logger/Log.cs @@ -1,4 +1,4 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.CompilerServices; using NLog; diff --git a/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs b/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs new file mode 100644 index 00000000000..71020369a60 --- /dev/null +++ b/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs @@ -0,0 +1,65 @@ +using System; +using System.Text.Json.Serialization; + +namespace Flow.Launcher.Infrastructure.UserSettings +{ + public abstract class ShortcutBaseModel + { + public string Key { get; set; } + + [JsonIgnore] + public Func Expand { get; set; } = () => { return ""; }; + + public override bool Equals(object obj) + { + return obj is ShortcutBaseModel other && + Key == other.Key; + } + + public override int GetHashCode() + { + return Key.GetHashCode(); + } + } + + public class CustomShortcutModel : ShortcutBaseModel + { + public string Value { get; set; } + + [JsonConstructorAttribute] + public CustomShortcutModel(string key, string value) + { + Key = key; + Value = value; + Expand = () => { return Value; }; + } + + public void Deconstruct(out string key, out string value) + { + key = Key; + value = Value; + } + + public static implicit operator (string Key, string Value)(CustomShortcutModel shortcut) + { + return (shortcut.Key, shortcut.Value); + } + + public static implicit operator CustomShortcutModel((string Key, string Value) shortcut) + { + return new CustomShortcutModel(shortcut.Key, shortcut.Value); + } + } + + public class BuiltinShortcutModel : ShortcutBaseModel + { + public string Description { get; set; } + + public BuiltinShortcutModel(string key, string description, Func expand) + { + Key = key; + Description = description; + Expand = expand ?? (() => { return ""; }); + } + } +} diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 27afff5b64a..7ead7459f55 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -3,6 +3,7 @@ using System.Collections.ObjectModel; using System.Drawing; using System.Text.Json.Serialization; +using System.Windows; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; using Flow.Launcher; @@ -129,8 +130,7 @@ public CustomBrowserViewModel CustomBrowser PrivateArg = "-private", EnablePrivate = false, Editable = false - } - , + }, new() { Name = "MS Edge", @@ -186,6 +186,13 @@ public string QuerySearchPrecisionString public ObservableCollection CustomPluginHotkeys { get; set; } = new ObservableCollection(); + public ObservableCollection CustomShortcuts { get; set; } = new ObservableCollection(); + + [JsonIgnore] + public ObservableCollection BuiltinShortcuts { get; set; } = new ObservableCollection() { + new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText) + }; + public bool DontPromptUpdateMsg { get; set; } public bool EnableUpdateLog { get; set; } diff --git a/Flow.Launcher/Converters/TranslationConverter.cs b/Flow.Launcher/Converters/TranslationConverter.cs new file mode 100644 index 00000000000..e1e8a58e368 --- /dev/null +++ b/Flow.Launcher/Converters/TranslationConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Globalization; +using System.Windows.Data; +using Flow.Launcher.Core.Resource; + +namespace Flow.Launcher.Converters +{ + public class TranlationConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var key = value.ToString(); + if (String.IsNullOrEmpty(key)) + return key; + return InternationalizationManager.Instance.GetTranslation(key); + } + + public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException(); + } +} diff --git a/Flow.Launcher/CustomShortcutSetting.xaml b/Flow.Launcher/CustomShortcutSetting.xaml new file mode 100644 index 00000000000..78b392f3e52 --- /dev/null +++ b/Flow.Launcher/CustomShortcutSetting.xaml @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Flow.Launcher/CustomShortcutSetting.xaml.cs b/Flow.Launcher/CustomShortcutSetting.xaml.cs new file mode 100644 index 00000000000..097d6a53b8a --- /dev/null +++ b/Flow.Launcher/CustomShortcutSetting.xaml.cs @@ -0,0 +1,73 @@ +using Flow.Launcher.Core.Resource; +using Flow.Launcher.ViewModel; +using System; +using System.Windows; +using System.Windows.Input; + +namespace Flow.Launcher +{ + public partial class CustomShortcutSetting : Window + { + private SettingWindowViewModel viewModel; + public string Key { get; set; } = String.Empty; + public string Value { get; set; } = String.Empty; + private string originalKey { get; init; } = null; + private string originalValue { get; init; } = null; + private bool update { get; init; } = false; + + public CustomShortcutSetting(SettingWindowViewModel vm) + { + viewModel = vm; + InitializeComponent(); + } + + public CustomShortcutSetting(string key, string value, SettingWindowViewModel vm) + { + viewModel = vm; + Key = key; + Value = value; + originalKey = key; + originalValue = value; + update = true; + InitializeComponent(); + } + + private void BtnCancel_OnClick(object sender, RoutedEventArgs e) + { + DialogResult = false; + Close(); + } + + private void BtnAdd_OnClick(object sender, RoutedEventArgs e) + { + if (String.IsNullOrEmpty(Key) || String.IsNullOrEmpty(Value)) + { + MessageBox.Show(InternationalizationManager.Instance.GetTranslation("emptyShortcut")); + return; + } + // Check if key is modified or adding a new one + if (((update && originalKey != Key) || !update) + && viewModel.ShortcutExists(Key)) + { + MessageBox.Show(InternationalizationManager.Instance.GetTranslation("duplicateShortcut")); + return; + } + DialogResult = !update || originalKey != Key || originalValue != Value; + Close(); + } + + private void cmdEsc_OnPress(object sender, ExecutedRoutedEventArgs e) + { + DialogResult = false; + Close(); + } + + private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e) + { + App.API.ChangeQuery(tbExpand.Text); + Application.Current.MainWindow.Show(); + Application.Current.MainWindow.Opacity = 1; + Application.Current.MainWindow.Focus(); + } + } +} diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 0eff97f4aae..2e3922d06d7 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -144,12 +144,18 @@ Show Hotkey Show result selection hotkey with results. Custom Query Hotkey + Custom Query Shortcut Query + Shortcut + Expanded + Description Delete Edit Add Please select an item Are you sure you want to delete {0} plugin hotkey? + Are you sure you want to delete shortcut: {0} with expansion {1}? + Get text from clipboard. Query window shadow effect Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited. Window Width Size @@ -241,6 +247,12 @@ Invalid plugin hotkey Update + + Custom Query Shortcut + Enter a shortcut that automatically expands to the specified query. + Shortcut already exists, please enter a new Shortcut or edit the existing one. + Shortcut and/or its expansion is empty. + Hotkey Unavailable diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 808531765b9..3c0905aa725 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -41,6 +41,7 @@ + @@ -2345,9 +2346,17 @@ + + + + + + + +