Implement {clipboard} feature and the setting panel

This commit is contained in:
Hongtao Zhang 2022-06-04 00:30:33 -05:00
parent c0a61c0b40
commit d60ba015e0
9 changed files with 327 additions and 24 deletions

View file

@ -204,9 +204,9 @@ namespace Flow.Launcher.Infrastructure.UserSettings
// This needs to be loaded last by staying at the bottom
public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
internal ObservableCollection<KeyValuePair<string, string>> ShortCuts { get; set; } = new()
internal ObservableCollection<ShortCutModel> ShortCuts { get; set; } = new()
{
new("spp", "sp play")
("spp", "sp play")
};
}
@ -223,4 +223,44 @@ namespace Flow.Launcher.Infrastructure.UserSettings
Light,
Dark
}
public struct ShortCutModel
{
public string Key { get; set; }
public string Value { get; set; }
public ShortCutModel(string key, string value)
{
Key = key;
Value = value;
}
public override bool Equals(object obj)
{
return obj is ShortCutModel other &&
Key == other.Key &&
Value == other.Value;
}
public override int GetHashCode()
{
return HashCode.Combine(Key, Value);
}
public void Deconstruct(out string key, out string value)
{
key = Key;
value = Value;
}
public static implicit operator (string Key, string Value)(ShortCutModel value)
{
return (value.Key, value.Value);
}
public static implicit operator ShortCutModel((string Key, string Value) value)
{
return new ShortCutModel(value.Key, value.Value);
}
}
}

View file

@ -0,0 +1,148 @@
<Window
x:Class="Flow.Launcher.CustomShortcutSetting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
Title="{DynamicResource customeQueryHotkeyTitle}"
Width="530"
Background="{DynamicResource PopuBGColor}"
Foreground="{DynamicResource PopupTextColor}"
Icon="Images\app.png"
ResizeMode="NoResize"
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
</WindowChrome.WindowChrome>
<Window.InputBindings>
<KeyBinding Key="Escape" Command="Close" />
</Window.InputBindings>
<Window.CommandBindings>
<CommandBinding Command="Close" Executed="cmdEsc_OnPress" />
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="4"
Click="BtnCancel_OnClick"
Style="{StaticResource TitleBarCloseButtonStyle}">
<Path
Width="46"
Height="32"
Data="M 18,11 27,20 M 18,20 27,11"
Stroke="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
StrokeThickness="1">
<Path.Style>
<Style TargetType="Path">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Value="False">
<Setter Property="Opacity" Value="0.5" />
</DataTrigger>
</Style.Triggers>
</Style>
</Path.Style>
</Path>
</Button>
</Grid>
</StackPanel>
<StackPanel Margin="26,0,26,0">
<StackPanel Grid.Row="0" Margin="0,0,0,12">
<TextBlock
Grid.Column="0"
Margin="0,0,0,0"
FontFamily="Segoe UI"
FontSize="20"
FontWeight="SemiBold"
Text="{DynamicResource customeQueryHotkeyTitle}"
TextAlignment="Left" />
</StackPanel>
<StackPanel>
<TextBlock
FontSize="14"
Text="{DynamicResource customeQueryHotkeyTips}"
TextAlignment="Left"
TextWrapping="WrapWithOverflow" />
</StackPanel>
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
<Grid Width="470">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="14"
Text="{DynamicResource customShortcut}" />
<TextBox
Grid.Row="0"
Grid.Column="1"
Margin="10"
Text="{Binding Key}"
/>
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="14"
Text="{DynamicResource customShortcutExpansion}" />
<TextBox
Grid.Row="1"
Grid.Column="1"
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Text="{Binding Value}"/>
</Grid>
</StackPanel>
</StackPanel>
</StackPanel>
<Border
Grid.Row="1"
Margin="0,14,0,0"
Background="{DynamicResource PopupButtonAreaBGColor}"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="0,1,0,0">
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Button
x:Name="btnCancel"
MinWidth="140"
Margin="10,0,5,0"
Click="BtnCancel_OnClick"
Content="{DynamicResource cancel}" />
<Button
x:Name="btnAdd"
MinWidth="140"
Margin="5,0,10,0"
Click="btnAdd_OnClick"
Style="{StaticResource AccentButtonStyle}">
<TextBlock x:Name="lblAdd" Text="{DynamicResource done}" />
</Button>
</StackPanel>
</Border>
</Grid>
</Window>

View file

@ -0,0 +1,52 @@
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.UserSettings;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Controls;
using System.Collections.Generic;
namespace Flow.Launcher
{
public partial class CustomShortcutSetting : Window
{
private SettingWindow _settingWidow;
private bool update;
private CustomPluginHotkey updateCustomHotkey;
private Settings _settings;
public string Key { get; set; }
public string Value { get; set; }
public ShortCutModel ShortCut => (Key, Value);
public CustomShortcutSetting()
{
InitializeComponent();
}
public CustomShortcutSetting((string, string) shortcut)
{
(Key, Value) = shortcut;
InitializeComponent();
}
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void btnAdd_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
private void cmdEsc_OnPress(object sender, ExecutedRoutedEventArgs e)
{
DialogResult = false;
Close();
}
}
}

View file

@ -12,6 +12,7 @@
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View file

@ -115,6 +115,8 @@
<system:String x:Key="showOpenResultHotkeyToolTip">Show result selection hotkey with results.</system:String>
<system:String x:Key="customQueryHotkey">Custom Query Hotkey</system:String>
<system:String x:Key="customQuery">Query</system:String>
<system:String x:Key="customShortcut">Shortcut</system:String>
<system:String x:Key="customShortcutExpansion">Expanded</system:String>
<system:String x:Key="delete">Delete</system:String>
<system:String x:Key="edit">Edit</system:String>
<system:String x:Key="add">Add</system:String>

View file

@ -2159,7 +2159,7 @@
<Button
MinWidth="100"
Margin="10"
Click="OnnEditCustomHotkeyClick"
Click="OnEditCustomHotkeyClick"
Content="{DynamicResource edit}" />
<Button
MinWidth="100"
@ -2183,7 +2183,8 @@
BorderBrush="DarkGray"
BorderThickness="1"
ItemsSource="{Binding ShortCuts}"
SelectedItem="{Binding SelectedCustomPluginHotkey}"
SelectedItem="{Binding SelectedCustomShortcut}"
SelectedIndex="{Binding SelectCustomShortcutIndex}"
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
<ListView.View>
<GridView>
@ -2212,17 +2213,17 @@
<Button
MinWidth="100"
Margin="10"
Click="OnDeleteCustomHotkeyClick"
Click="OnDeleteCustomShortCutClick"
Content="{DynamicResource delete}" />
<Button
MinWidth="100"
Margin="10"
Click="OnnEditCustomHotkeyClick"
Click="OnEditCustomShortCutClick"
Content="{DynamicResource edit}" />
<Button
MinWidth="100"
Margin="10,10,0,10"
Click="OnAddCustomeHotkeyClick"
Click="OnAddCustomeShortCutClick"
Content="{DynamicResource add}" />
</StackPanel>
</StackPanel>

View file

@ -175,7 +175,7 @@ namespace Flow.Launcher
}
}
private void OnnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
private void OnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
{
var item = viewModel.SelectedCustomPluginHotkey;
if (item != null)
@ -307,7 +307,7 @@ namespace Flow.Launcher
private void OnExternalPluginInstallClick(object sender, RoutedEventArgs e)
{
if(sender is Button { DataContext: UserPlugin plugin })
if (sender is Button { DataContext: UserPlugin plugin })
{
var pluginsManagerPlugin = PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7");
var actionKeyword = pluginsManagerPlugin.Metadata.ActionKeywords.Count == 0 ? "" : pluginsManagerPlugin.Metadata.ActionKeywords[0];
@ -326,7 +326,7 @@ namespace Flow.Launcher
textBox.MoveFocus(tRequest);
}
private void ColorSchemeSelectedIndexChanged(object sender, EventArgs e)
private void ColorSchemeSelectedIndexChanged(object sender, EventArgs e)
=> ThemeManager.Current.ApplicationTheme = settings.ColorScheme switch
{
Constant.Light => ApplicationTheme.Light,
@ -370,5 +370,49 @@ namespace Flow.Launcher
RefreshMaximizeRestoreButton();
}
private void OnDeleteCustomShortCutClick(object sender, RoutedEventArgs e)
{
var item = viewModel.SelectedCustomShortcut;
if (item == null)
{
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
return;
}
string deleteWarning =
string.Format(InternationalizationManager.Instance.GetTranslation("deleteCustomHotkeyWarning"),
item.Value.Key);
if (
MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"),
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
settings.ShortCuts.Remove(item.Value);
}
}
private void OnEditCustomShortCutClick(object sender, RoutedEventArgs e)
{
var item = viewModel.SelectedCustomShortcut;
if (item != null)
{
var shortcutSettingWindow = new CustomShortcutSetting(item.Value);
if (shortcutSettingWindow.ShowDialog() == true)
{
settings.ShortCuts[viewModel.SelectCustomShortcutIndex.Value] = shortcutSettingWindow.ShortCut;
}
}
else
{
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
}
}
private void OnAddCustomeShortCutClick(object sender, RoutedEventArgs e)
{
var shortcutSettingWindow = new CustomShortcutSetting();
if (shortcutSettingWindow.ShowDialog() == true)
{
settings.ShortCuts.Add(shortcutSettingWindow.ShortCut);
}
}
}
}

View file

@ -554,17 +554,8 @@ namespace Flow.Launcher.ViewModel
return;
}
StringBuilder queryBuilder = new(QueryText);
var query = ConstructQuery(QueryText, _settings.ShortCuts);
foreach (var (key, value) in _settings.ShortCuts)
{
if (queryBuilder.Equals(key))
{
queryBuilder.Replace(key, value);
}
queryBuilder.Replace('@' + key, value);
}
_updateSource?.Dispose();
@ -582,7 +573,6 @@ namespace Flow.Launcher.ViewModel
if (currentCancellationToken.IsCancellationRequested)
return;
var query = QueryBuilder.Build(queryBuilder.ToString().Trim(), PluginManager.NonGlobalPlugins);
// handle the exclusiveness of plugin using action keyword
RemoveOldQueryResults(query);
@ -672,6 +662,26 @@ namespace Flow.Launcher.ViewModel
}
}
private static Query ConstructQuery(string queryText, IEnumerable<ShortCutModel> shortcuts)
{
StringBuilder queryBuilder = new(queryText);
foreach (var (key, value) in shortcuts)
{
if (queryBuilder.Equals(key))
{
queryBuilder.Replace(key, value);
}
queryBuilder.Replace('@' + key, value);
}
queryBuilder.Replace("{clipboard}", Clipboard.GetText());
var query = QueryBuilder.Build(queryBuilder.ToString().Trim(), PluginManager.NonGlobalPlugins);
return query;
}
private void RemoveOldQueryResults(Query query)
{
if (_lastQuery.ActionKeyword != query.ActionKeyword)

View file

@ -120,7 +120,8 @@ namespace Flow.Launcher.ViewModel
var display = _translater.GetTranslation(key);
var m = new LastQueryMode
{
Display = display, Value = e,
Display = display,
Value = e,
};
modes.Add(m);
}
@ -179,7 +180,7 @@ namespace Flow.Launcher.ViewModel
public List<Language> Languages => _translater.LoadAvailableLanguages();
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);
public ObservableCollection<KeyValuePair<string, string>> ShortCuts => Settings.ShortCuts;
public ObservableCollection<ShortCutModel> ShortCuts => Settings.ShortCuts;
public string TestProxy()
{
@ -345,7 +346,8 @@ namespace Flow.Launcher.ViewModel
var display = _translater.GetTranslation(key);
var m = new ColorScheme
{
Display = display, Value = e,
Display = display,
Value = e,
};
modes.Add(m);
}
@ -539,6 +541,9 @@ namespace Flow.Launcher.ViewModel
public CustomPluginHotkey SelectedCustomPluginHotkey { get; set; }
public ShortCutModel? SelectedCustomShortcut { get; set; }
public int? SelectCustomShortcutIndex { get; set; }
#endregion
#region about