Skip to content

Commit 588ef4b

Browse files
authored
Merge pull request #930 from Flow-Launcher/Shortcut
Custom Query Shortcut + built-in variables
2 parents 49b9e97 + 9ccdf59 commit 588ef4b

File tree

11 files changed

+599
-20
lines changed

11 files changed

+599
-20
lines changed

Flow.Launcher.Infrastructure/Logger/Log.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System.Diagnostics;
1+
using System.Diagnostics;
22
using System.IO;
33
using System.Runtime.CompilerServices;
44
using NLog;
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
using System;
2+
using System.Text.Json.Serialization;
3+
4+
namespace Flow.Launcher.Infrastructure.UserSettings
5+
{
6+
public abstract class ShortcutBaseModel
7+
{
8+
public string Key { get; set; }
9+
10+
[JsonIgnore]
11+
public Func<string> Expand { get; set; } = () => { return ""; };
12+
13+
public override bool Equals(object obj)
14+
{
15+
return obj is ShortcutBaseModel other &&
16+
Key == other.Key;
17+
}
18+
19+
public override int GetHashCode()
20+
{
21+
return Key.GetHashCode();
22+
}
23+
}
24+
25+
public class CustomShortcutModel : ShortcutBaseModel
26+
{
27+
public string Value { get; set; }
28+
29+
[JsonConstructorAttribute]
30+
public CustomShortcutModel(string key, string value)
31+
{
32+
Key = key;
33+
Value = value;
34+
Expand = () => { return Value; };
35+
}
36+
37+
public void Deconstruct(out string key, out string value)
38+
{
39+
key = Key;
40+
value = Value;
41+
}
42+
43+
public static implicit operator (string Key, string Value)(CustomShortcutModel shortcut)
44+
{
45+
return (shortcut.Key, shortcut.Value);
46+
}
47+
48+
public static implicit operator CustomShortcutModel((string Key, string Value) shortcut)
49+
{
50+
return new CustomShortcutModel(shortcut.Key, shortcut.Value);
51+
}
52+
}
53+
54+
public class BuiltinShortcutModel : ShortcutBaseModel
55+
{
56+
public string Description { get; set; }
57+
58+
public BuiltinShortcutModel(string key, string description, Func<string> expand)
59+
{
60+
Key = key;
61+
Description = description;
62+
Expand = expand ?? (() => { return ""; });
63+
}
64+
}
65+
}

Flow.Launcher.Infrastructure/UserSettings/Settings.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Collections.ObjectModel;
44
using System.Drawing;
55
using System.Text.Json.Serialization;
6+
using System.Windows;
67
using Flow.Launcher.Plugin;
78
using Flow.Launcher.Plugin.SharedModels;
89
using Flow.Launcher;
@@ -129,8 +130,7 @@ public CustomBrowserViewModel CustomBrowser
129130
PrivateArg = "-private",
130131
EnablePrivate = false,
131132
Editable = false
132-
}
133-
,
133+
},
134134
new()
135135
{
136136
Name = "MS Edge",
@@ -186,6 +186,13 @@ public string QuerySearchPrecisionString
186186

187187
public ObservableCollection<CustomPluginHotkey> CustomPluginHotkeys { get; set; } = new ObservableCollection<CustomPluginHotkey>();
188188

189+
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();
190+
191+
[JsonIgnore]
192+
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new ObservableCollection<BuiltinShortcutModel>() {
193+
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText)
194+
};
195+
189196
public bool DontPromptUpdateMsg { get; set; }
190197
public bool EnableUpdateLog { get; set; }
191198

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Globalization;
3+
using System.Windows.Data;
4+
using Flow.Launcher.Core.Resource;
5+
6+
namespace Flow.Launcher.Converters
7+
{
8+
public class TranlationConverter : IValueConverter
9+
{
10+
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
11+
{
12+
var key = value.ToString();
13+
if (String.IsNullOrEmpty(key))
14+
return key;
15+
return InternationalizationManager.Instance.GetTranslation(key);
16+
}
17+
18+
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
19+
}
20+
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<Window
2+
x:Class="Flow.Launcher.CustomShortcutSetting"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
6+
Title="{DynamicResource customeQueryShortcutTitle}"
7+
Width="530"
8+
Background="{DynamicResource PopuBGColor}"
9+
Foreground="{DynamicResource PopupTextColor}"
10+
Icon="Images\app.png"
11+
ResizeMode="NoResize"
12+
SizeToContent="Height"
13+
WindowStartupLocation="CenterScreen"
14+
DataContext="{Binding RelativeSource={RelativeSource Self}}">
15+
<WindowChrome.WindowChrome>
16+
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
17+
</WindowChrome.WindowChrome>
18+
<Window.InputBindings>
19+
<KeyBinding Key="Escape" Command="Close" />
20+
</Window.InputBindings>
21+
<Window.CommandBindings>
22+
<CommandBinding Command="Close" Executed="cmdEsc_OnPress" />
23+
</Window.CommandBindings>
24+
<Grid>
25+
<Grid.RowDefinitions>
26+
<RowDefinition />
27+
<RowDefinition Height="80" />
28+
</Grid.RowDefinitions>
29+
<StackPanel Grid.Row="0">
30+
<StackPanel>
31+
<Grid>
32+
<Grid.ColumnDefinitions>
33+
<ColumnDefinition Width="Auto" />
34+
<ColumnDefinition Width="*" />
35+
<ColumnDefinition Width="Auto" />
36+
<ColumnDefinition Width="Auto" />
37+
<ColumnDefinition Width="Auto" />
38+
</Grid.ColumnDefinitions>
39+
<Button
40+
Grid.Column="4"
41+
Click="BtnCancel_OnClick"
42+
Style="{StaticResource TitleBarCloseButtonStyle}">
43+
<Path
44+
Width="46"
45+
Height="32"
46+
Data="M 18,11 27,20 M 18,20 27,11"
47+
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
48+
StrokeThickness="1">
49+
<Path.Style>
50+
<Style TargetType="Path">
51+
<Style.Triggers>
52+
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
53+
<Setter Property="Opacity" Value="0.5" />
54+
</DataTrigger>
55+
</Style.Triggers>
56+
</Style>
57+
</Path.Style>
58+
</Path>
59+
</Button>
60+
</Grid>
61+
</StackPanel>
62+
<StackPanel Margin="26,0,26,0">
63+
<StackPanel Grid.Row="0" Margin="0,0,0,12">
64+
<TextBlock
65+
Grid.Column="0"
66+
Margin="0,0,0,0"
67+
FontFamily="Segoe UI"
68+
FontSize="20"
69+
FontWeight="SemiBold"
70+
Text="{DynamicResource customQueryShortcut}"
71+
TextAlignment="Left" />
72+
</StackPanel>
73+
<StackPanel>
74+
<TextBlock
75+
FontSize="14"
76+
Text="{DynamicResource customeQueryShortcutTips}"
77+
TextAlignment="Left"
78+
TextWrapping="WrapWithOverflow" />
79+
</StackPanel>
80+
81+
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
82+
<Grid Width="470">
83+
<Grid.RowDefinitions>
84+
<RowDefinition />
85+
<RowDefinition />
86+
</Grid.RowDefinitions>
87+
<Grid.ColumnDefinitions>
88+
<ColumnDefinition Width="Auto" />
89+
<ColumnDefinition Width="*" />
90+
</Grid.ColumnDefinitions>
91+
<TextBlock
92+
Grid.Row="0"
93+
Grid.Column="0"
94+
Margin="10"
95+
HorizontalAlignment="Left"
96+
VerticalAlignment="Center"
97+
FontSize="14"
98+
Text="{DynamicResource customShortcut}" />
99+
<TextBox
100+
Grid.Row="0"
101+
Grid.Column="1"
102+
Margin="10"
103+
Text="{Binding Key}"
104+
/>
105+
<TextBlock
106+
Grid.Row="1"
107+
Grid.Column="0"
108+
Margin="10"
109+
HorizontalAlignment="Left"
110+
VerticalAlignment="Center"
111+
FontSize="14"
112+
Text="{DynamicResource customShortcutExpansion}" />
113+
114+
<DockPanel
115+
Grid.Row="1"
116+
Grid.Column="1"
117+
LastChildFill="True">
118+
<Button
119+
x:Name="btnTestShortcut"
120+
Margin="0,0,10,0"
121+
Padding="10,5,10,5"
122+
Click="BtnTestShortcut_OnClick"
123+
Content="{DynamicResource preview}"
124+
DockPanel.Dock="Right" />
125+
<TextBox
126+
x:Name="tbExpand"
127+
Margin="10"
128+
HorizontalAlignment="Stretch"
129+
Text="{Binding Value}"
130+
VerticalAlignment="Center" />
131+
</DockPanel>
132+
</Grid>
133+
</StackPanel>
134+
</StackPanel>
135+
</StackPanel>
136+
<Border
137+
Grid.Row="1"
138+
Margin="0,14,0,0"
139+
Background="{DynamicResource PopupButtonAreaBGColor}"
140+
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
141+
BorderThickness="0,1,0,0">
142+
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
143+
<Button
144+
x:Name="btnCancel"
145+
MinWidth="140"
146+
Margin="10,0,5,0"
147+
Click="BtnCancel_OnClick"
148+
Content="{DynamicResource cancel}" />
149+
<Button
150+
x:Name="btnAdd"
151+
MinWidth="140"
152+
Margin="5,0,10,0"
153+
Click="BtnAdd_OnClick"
154+
Style="{StaticResource AccentButtonStyle}">
155+
<TextBlock x:Name="lblAdd" Text="{DynamicResource done}" />
156+
</Button>
157+
</StackPanel>
158+
</Border>
159+
</Grid>
160+
</Window>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using Flow.Launcher.Core.Resource;
2+
using Flow.Launcher.ViewModel;
3+
using System;
4+
using System.Windows;
5+
using System.Windows.Input;
6+
7+
namespace Flow.Launcher
8+
{
9+
public partial class CustomShortcutSetting : Window
10+
{
11+
private SettingWindowViewModel viewModel;
12+
public string Key { get; set; } = String.Empty;
13+
public string Value { get; set; } = String.Empty;
14+
private string originalKey { get; init; } = null;
15+
private string originalValue { get; init; } = null;
16+
private bool update { get; init; } = false;
17+
18+
public CustomShortcutSetting(SettingWindowViewModel vm)
19+
{
20+
viewModel = vm;
21+
InitializeComponent();
22+
}
23+
24+
public CustomShortcutSetting(string key, string value, SettingWindowViewModel vm)
25+
{
26+
viewModel = vm;
27+
Key = key;
28+
Value = value;
29+
originalKey = key;
30+
originalValue = value;
31+
update = true;
32+
InitializeComponent();
33+
}
34+
35+
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
36+
{
37+
DialogResult = false;
38+
Close();
39+
}
40+
41+
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
42+
{
43+
if (String.IsNullOrEmpty(Key) || String.IsNullOrEmpty(Value))
44+
{
45+
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("emptyShortcut"));
46+
return;
47+
}
48+
// Check if key is modified or adding a new one
49+
if (((update && originalKey != Key) || !update)
50+
&& viewModel.ShortcutExists(Key))
51+
{
52+
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("duplicateShortcut"));
53+
return;
54+
}
55+
DialogResult = !update || originalKey != Key || originalValue != Value;
56+
Close();
57+
}
58+
59+
private void cmdEsc_OnPress(object sender, ExecutedRoutedEventArgs e)
60+
{
61+
DialogResult = false;
62+
Close();
63+
}
64+
65+
private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e)
66+
{
67+
App.API.ChangeQuery(tbExpand.Text);
68+
Application.Current.MainWindow.Show();
69+
Application.Current.MainWindow.Opacity = 1;
70+
Application.Current.MainWindow.Focus();
71+
}
72+
}
73+
}

Flow.Launcher/Languages/en.xaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,12 +144,18 @@
144144
<system:String x:Key="showOpenResultHotkey">Show Hotkey</system:String>
145145
<system:String x:Key="showOpenResultHotkeyToolTip">Show result selection hotkey with results.</system:String>
146146
<system:String x:Key="customQueryHotkey">Custom Query Hotkey</system:String>
147+
<system:String x:Key="customQueryShortcut">Custom Query Shortcut</system:String>
147148
<system:String x:Key="customQuery">Query</system:String>
149+
<system:String x:Key="customShortcut">Shortcut</system:String>
150+
<system:String x:Key="customShortcutExpansion">Expanded</system:String>
151+
<system:String x:Key="builtinShortcutDescription">Description</system:String>
148152
<system:String x:Key="delete">Delete</system:String>
149153
<system:String x:Key="edit">Edit</system:String>
150154
<system:String x:Key="add">Add</system:String>
151155
<system:String x:Key="pleaseSelectAnItem">Please select an item</system:String>
152156
<system:String x:Key="deleteCustomHotkeyWarning">Are you sure you want to delete {0} plugin hotkey?</system:String>
157+
<system:String x:Key="deleteCustomShortcutWarning">Are you sure you want to delete shortcut: {0} with expansion {1}?</system:String>
158+
<system:String x:Key="shortcut_clipboard_description">Get text from clipboard.</system:String>
153159
<system:String x:Key="queryWindowShadowEffect">Query window shadow effect</system:String>
154160
<system:String x:Key="shadowEffectCPUUsage">Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited.</system:String>
155161
<system:String x:Key="windowWidthSize">Window Width Size</system:String>
@@ -241,6 +247,12 @@
241247
<system:String x:Key="invalidPluginHotkey">Invalid plugin hotkey</system:String>
242248
<system:String x:Key="update">Update</system:String>
243249

250+
<!-- Custom Query Shortcut Dialog -->
251+
<system:String x:Key="customeQueryShortcutTitle">Custom Query Shortcut</system:String>
252+
<system:String x:Key="customeQueryShortcutTips">Enter a shortcut that automatically expands to the specified query.</system:String>
253+
<system:String x:Key="duplicateShortcut">Shortcut already exists, please enter a new Shortcut or edit the existing one.</system:String>
254+
<system:String x:Key="emptyShortcut">Shortcut and/or its expansion is empty.</system:String>
255+
244256
<!-- Hotkey Control -->
245257
<system:String x:Key="hotkeyUnavailable">Hotkey Unavailable</system:String>
246258

0 commit comments

Comments
 (0)