diff --git a/Flow.Launcher.Infrastructure/Logger/Log.cs b/Flow.Launcher.Infrastructure/Logger/Log.cs index 75f208c9e..b8f1408e7 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 000000000..71020369a --- /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 27afff5b6..7ead7459f 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; 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 @@ namespace Flow.Launcher.Infrastructure.UserSettings PrivateArg = "-private", EnablePrivate = false, Editable = false - } - , + }, new() { Name = "MS Edge", @@ -186,6 +186,13 @@ namespace Flow.Launcher.Infrastructure.UserSettings 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 000000000..e1e8a58e3 --- /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 000000000..78b392f3e --- /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 000000000..097d6a53b --- /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/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 813a44527..1e7f70b0a 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -98,6 +98,7 @@ + @@ -120,7 +121,7 @@ - + diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 0eff97f4a..2e3922d06 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/Resources/Dark.xaml b/Flow.Launcher/Resources/Dark.xaml index 445e07c63..674e04deb 100644 --- a/Flow.Launcher/Resources/Dark.xaml +++ b/Flow.Launcher/Resources/Dark.xaml @@ -69,6 +69,8 @@ + #272727 + #202020 #2b2b2b #1d1d1d diff --git a/Flow.Launcher/Resources/Light.xaml b/Flow.Launcher/Resources/Light.xaml index cee8b63cd..8b04196dd 100644 --- a/Flow.Launcher/Resources/Light.xaml +++ b/Flow.Launcher/Resources/Light.xaml @@ -62,6 +62,8 @@ + #f6f6f6 + #f3f3f3 #ffffff #e5e5e5 diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 61815fce6..07a33024d 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -11,6 +11,7 @@ xmlns:ui="http://schemas.modernwpf.com/2019" xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure" xmlns:vm="clr-namespace:Flow.Launcher.ViewModel" + xmlns:wpftk="clr-namespace:WpfToolkit.Controls;assembly=VirtualizingWrapPanel" Title="{DynamicResource flowlauncher_settings}" Width="{Binding SettingWindowWidth, Mode=TwoWay}" Height="{Binding SettingWindowHeight, Mode=TwoWay}" @@ -41,12 +42,31 @@ + + + + + + + + - + - + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + @@ -1763,7 +1684,9 @@ + ScrollViewer.CanContentScroll="True" + VirtualizingStackPanel.IsVirtualizing="True" + VirtualizingStackPanel.ScrollUnit="Pixel"> @@ -2339,16 +2262,26 @@ + ScrollViewer.CanContentScroll="True" + VirtualizingStackPanel.IsVirtualizing="True" + VirtualizingStackPanel.ScrollUnit="Pixel"> + + + + + + + +