mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'FixMemoryLeak' of https://github.com/onesounds/Flow.Launcher into FixMemoryLeak
This commit is contained in:
commit
03c9a1aab4
23 changed files with 777 additions and 56 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
|
||||||
|
|
@ -202,7 +202,11 @@ namespace Flow.Launcher.Infrastructure
|
||||||
if (allQuerySubstringsMatched)
|
if (allQuerySubstringsMatched)
|
||||||
{
|
{
|
||||||
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
|
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
|
||||||
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1,
|
|
||||||
|
// firstMatchIndex - nearestSpaceIndex - 1 is to set the firstIndex as the index of the first matched char
|
||||||
|
// preceded by a space e.g. 'world' matching 'hello world' firstIndex would be 0 not 6
|
||||||
|
// giving more weight than 'we or donald' by allowing the distance calculation to treat the starting position at after the space.
|
||||||
|
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, spaceIndices,
|
||||||
lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
|
||||||
|
|
||||||
var resultList = indexList.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList();
|
var resultList = indexList.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList();
|
||||||
|
|
@ -296,7 +300,7 @@ namespace Flow.Launcher.Infrastructure
|
||||||
return currentQuerySubstringIndex >= querySubstringsLength;
|
return currentQuerySubstringIndex >= querySubstringsLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen,
|
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, List<int> spaceIndices, int matchLen,
|
||||||
bool allSubstringsContainedInCompareString)
|
bool allSubstringsContainedInCompareString)
|
||||||
{
|
{
|
||||||
// A match found near the beginning of a string is scored more than a match found near the end
|
// A match found near the beginning of a string is scored more than a match found near the end
|
||||||
|
|
@ -304,6 +308,14 @@ namespace Flow.Launcher.Infrastructure
|
||||||
// while the score is lower if they are more spread out
|
// while the score is lower if they are more spread out
|
||||||
var score = 100 * (query.Length + 1) / ((1 + firstIndex) + (matchLen + 1));
|
var score = 100 * (query.Length + 1) / ((1 + firstIndex) + (matchLen + 1));
|
||||||
|
|
||||||
|
// Give more weight to a match that is closer to the start of the string.
|
||||||
|
// if the first matched char is immediately before space and all strings are contained in the compare string e.g. 'world' matching 'hello world'
|
||||||
|
// and 'world hello', because both have 'world' immediately preceded by space, their firstIndex will be 0 when distance is calculated,
|
||||||
|
// to prevent them scoring the same, we adjust the score by deducting the number of spaces it has from the start of the string, so 'world hello'
|
||||||
|
// will score slightly higher than 'hello world' because 'hello world' has one additional space.
|
||||||
|
if (firstIndex == 0 && allSubstringsContainedInCompareString)
|
||||||
|
score -= spaceIndices.Count;
|
||||||
|
|
||||||
// A match with less characters assigning more weights
|
// A match with less characters assigning more weights
|
||||||
if (stringToCompare.Length - query.Length < 5)
|
if (stringToCompare.Length - query.Length < 5)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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<string> 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<string> expand)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Description = description;
|
||||||
|
Expand = expand ?? (() => { return ""; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Windows;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
using Flow.Launcher;
|
using Flow.Launcher;
|
||||||
|
|
@ -129,8 +130,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
PrivateArg = "-private",
|
PrivateArg = "-private",
|
||||||
EnablePrivate = false,
|
EnablePrivate = false,
|
||||||
Editable = false
|
Editable = false
|
||||||
}
|
},
|
||||||
,
|
|
||||||
new()
|
new()
|
||||||
{
|
{
|
||||||
Name = "MS Edge",
|
Name = "MS Edge",
|
||||||
|
|
@ -186,6 +186,13 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
|
|
||||||
public ObservableCollection<CustomPluginHotkey> CustomPluginHotkeys { get; set; } = new ObservableCollection<CustomPluginHotkey>();
|
public ObservableCollection<CustomPluginHotkey> CustomPluginHotkeys { get; set; } = new ObservableCollection<CustomPluginHotkey>();
|
||||||
|
|
||||||
|
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new ObservableCollection<BuiltinShortcutModel>() {
|
||||||
|
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText)
|
||||||
|
};
|
||||||
|
|
||||||
public bool DontPromptUpdateMsg { get; set; }
|
public bool DontPromptUpdateMsg { get; set; }
|
||||||
public bool EnableUpdateLog { get; set; }
|
public bool EnableUpdateLog { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,11 @@ namespace Flow.Launcher.Plugin
|
||||||
/// user's clipboard when Ctrl + C is pressed on a result. If the text is a file/directory path
|
/// user's clipboard when Ctrl + C is pressed on a result. If the text is a file/directory path
|
||||||
/// flow will copy the actual file/folder instead of just the path text.
|
/// flow will copy the actual file/folder instead of just the path text.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CopyText { get; set; } = string.Empty;
|
public string CopyText
|
||||||
|
{
|
||||||
|
get => string.IsNullOrEmpty(_copyText) ? SubTitle : _copyText;
|
||||||
|
set => _copyText = value;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This holds the text which can be provided by plugin to help Flow autocomplete text
|
/// This holds the text which can be provided by plugin to help Flow autocomplete text
|
||||||
|
|
@ -81,6 +85,7 @@ namespace Flow.Launcher.Plugin
|
||||||
/// Delegate to Get Image Source
|
/// Delegate to Get Image Source
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IconDelegate Icon;
|
public IconDelegate Icon;
|
||||||
|
private string _copyText = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
|
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
|
||||||
|
|
|
||||||
|
|
@ -129,14 +129,20 @@ namespace Flow.Launcher.Test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These are standard match scenarios
|
||||||
|
/// The intention of this test is provide a bench mark for how much the score has increased from a change.
|
||||||
|
/// Usually the increase in scoring should not be drastic, increase of less than 10 is acceptable.
|
||||||
|
/// </summary>
|
||||||
[TestCase(Chrome, Chrome, 157)]
|
[TestCase(Chrome, Chrome, 157)]
|
||||||
[TestCase(Chrome, LastIsChrome, 147)]
|
[TestCase(Chrome, LastIsChrome, 145)]
|
||||||
[TestCase("chro", HelpCureHopeRaiseOnMindEntityChrome, 50)]
|
[TestCase("chro", HelpCureHopeRaiseOnMindEntityChrome, 50)]
|
||||||
[TestCase("chr", HelpCureHopeRaiseOnMindEntityChrome, 30)]
|
[TestCase("chr", HelpCureHopeRaiseOnMindEntityChrome, 30)]
|
||||||
[TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 21)]
|
[TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 21)]
|
||||||
[TestCase(Chrome, CandyCrushSagaFromKing, 0)]
|
[TestCase(Chrome, CandyCrushSagaFromKing, 0)]
|
||||||
[TestCase("sql", MicrosoftSqlServerManagementStudio, 110)]
|
[TestCase("sql", MicrosoftSqlServerManagementStudio, 109)]
|
||||||
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 121)] //double spacing intended
|
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 120)] //double spacing intended
|
||||||
public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring(
|
public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring(
|
||||||
string queryString, string compareString, int expectedScore)
|
string queryString, string compareString, int expectedScore)
|
||||||
{
|
{
|
||||||
|
|
@ -275,7 +281,40 @@ namespace Flow.Launcher.Test
|
||||||
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
||||||
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
||||||
$"Should be greater than{Environment.NewLine}" +
|
$"Should be greater than{Environment.NewLine}" +
|
||||||
$"CompareString2: \"{compareString2}\", Score: {compareString1Result.Score}{Environment.NewLine}");
|
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase("red", "red colour", "metro red")]
|
||||||
|
[TestCase("red", "this red colour", "this colour red")]
|
||||||
|
[TestCase("red", "this red colour", "this colour is very red")]
|
||||||
|
[TestCase("red", "this red colour", "this colour is surprisingly super awesome red and cool")]
|
||||||
|
[TestCase("red", "this colour is surprisingly super red very and cool", "this colour is surprisingly super very red and cool")]
|
||||||
|
public void WhenGivenTwoStrings_Scoring_ShouldGiveMoreWeightToTheStringCloserToIndexZero(
|
||||||
|
string queryString, string compareString1, string compareString2)
|
||||||
|
{
|
||||||
|
// When
|
||||||
|
var matcher = new StringMatcher { UserSettingSearchPrecision = SearchPrecisionScore.Regular };
|
||||||
|
|
||||||
|
// Given
|
||||||
|
var compareString1Result = matcher.FuzzyMatch(queryString, compareString1);
|
||||||
|
var compareString2Result = matcher.FuzzyMatch(queryString, compareString2);
|
||||||
|
|
||||||
|
Debug.WriteLine("");
|
||||||
|
Debug.WriteLine("###############################################");
|
||||||
|
Debug.WriteLine($"QueryString: \"{queryString}\"{Environment.NewLine}");
|
||||||
|
Debug.WriteLine(
|
||||||
|
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}");
|
||||||
|
Debug.WriteLine(
|
||||||
|
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
|
||||||
|
Debug.WriteLine("###############################################");
|
||||||
|
Debug.WriteLine("");
|
||||||
|
|
||||||
|
// Should
|
||||||
|
Assert.True(compareString1Result.Score > compareString2Result.Score,
|
||||||
|
$"Query: \"{queryString}\"{Environment.NewLine} " +
|
||||||
|
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
|
||||||
|
$"Should be greater than{Environment.NewLine}" +
|
||||||
|
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase("vim", "Vim", "ignoreDescription", "ignore.exe", "Vim Diff", "ignoreDescription", "ignore.exe")]
|
[TestCase("vim", "Vim", "ignoreDescription", "ignore.exe", "Vim Diff", "ignoreDescription", "ignore.exe")]
|
||||||
|
|
|
||||||
20
Flow.Launcher/Converters/TranslationConverter.cs
Normal file
20
Flow.Launcher/Converters/TranslationConverter.cs
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
160
Flow.Launcher/CustomShortcutSetting.xaml
Normal file
160
Flow.Launcher/CustomShortcutSetting.xaml
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
<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 customeQueryShortcutTitle}"
|
||||||
|
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 customQueryShortcut}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock
|
||||||
|
FontSize="14"
|
||||||
|
Text="{DynamicResource customeQueryShortcutTips}"
|
||||||
|
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}" />
|
||||||
|
|
||||||
|
<DockPanel
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
LastChildFill="True">
|
||||||
|
<Button
|
||||||
|
x:Name="btnTestShortcut"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
Padding="10,5,10,5"
|
||||||
|
Click="BtnTestShortcut_OnClick"
|
||||||
|
Content="{DynamicResource preview}"
|
||||||
|
DockPanel.Dock="Right" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="tbExpand"
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Text="{Binding Value}"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</DockPanel>
|
||||||
|
</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>
|
||||||
73
Flow.Launcher/CustomShortcutSetting.xaml.cs
Normal file
73
Flow.Launcher/CustomShortcutSetting.xaml.cs
Normal file
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -144,12 +144,18 @@
|
||||||
<system:String x:Key="showOpenResultHotkey">Show Hotkey</system:String>
|
<system:String x:Key="showOpenResultHotkey">Show Hotkey</system:String>
|
||||||
<system:String x:Key="showOpenResultHotkeyToolTip">Show result selection hotkey with results.</system:String>
|
<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="customQueryHotkey">Custom Query Hotkey</system:String>
|
||||||
|
<system:String x:Key="customQueryShortcut">Custom Query Shortcut</system:String>
|
||||||
<system:String x:Key="customQuery">Query</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="builtinShortcutDescription">Description</system:String>
|
||||||
<system:String x:Key="delete">Delete</system:String>
|
<system:String x:Key="delete">Delete</system:String>
|
||||||
<system:String x:Key="edit">Edit</system:String>
|
<system:String x:Key="edit">Edit</system:String>
|
||||||
<system:String x:Key="add">Add</system:String>
|
<system:String x:Key="add">Add</system:String>
|
||||||
<system:String x:Key="pleaseSelectAnItem">Please select an item</system:String>
|
<system:String x:Key="pleaseSelectAnItem">Please select an item</system:String>
|
||||||
<system:String x:Key="deleteCustomHotkeyWarning">Are you sure you want to delete {0} plugin hotkey?</system:String>
|
<system:String x:Key="deleteCustomHotkeyWarning">Are you sure you want to delete {0} plugin hotkey?</system:String>
|
||||||
|
<system:String x:Key="deleteCustomShortcutWarning">Are you sure you want to delete shortcut: {0} with expansion {1}?</system:String>
|
||||||
|
<system:String x:Key="shortcut_clipboard_description">Get text from clipboard.</system:String>
|
||||||
<system:String x:Key="queryWindowShadowEffect">Query window shadow effect</system:String>
|
<system:String x:Key="queryWindowShadowEffect">Query window shadow effect</system:String>
|
||||||
<system:String x:Key="shadowEffectCPUUsage">Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited.</system:String>
|
<system:String x:Key="shadowEffectCPUUsage">Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited.</system:String>
|
||||||
<system:String x:Key="windowWidthSize">Window Width Size</system:String>
|
<system:String x:Key="windowWidthSize">Window Width Size</system:String>
|
||||||
|
|
@ -241,6 +247,12 @@
|
||||||
<system:String x:Key="invalidPluginHotkey">Invalid plugin hotkey</system:String>
|
<system:String x:Key="invalidPluginHotkey">Invalid plugin hotkey</system:String>
|
||||||
<system:String x:Key="update">Update</system:String>
|
<system:String x:Key="update">Update</system:String>
|
||||||
|
|
||||||
|
<!-- Custom Query Shortcut Dialog -->
|
||||||
|
<system:String x:Key="customeQueryShortcutTitle">Custom Query Shortcut</system:String>
|
||||||
|
<system:String x:Key="customeQueryShortcutTips">Enter a shortcut that automatically expands to the specified query.</system:String>
|
||||||
|
<system:String x:Key="duplicateShortcut">Shortcut already exists, please enter a new Shortcut or edit the existing one.</system:String>
|
||||||
|
<system:String x:Key="emptyShortcut">Shortcut and/or its expansion is empty.</system:String>
|
||||||
|
|
||||||
<!-- Hotkey Control -->
|
<!-- Hotkey Control -->
|
||||||
<system:String x:Key="hotkeyUnavailable">Hotkey Unavailable</system:String>
|
<system:String x:Key="hotkeyUnavailable">Hotkey Unavailable</system:String>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@
|
||||||
<ContentControl>
|
<ContentControl>
|
||||||
<flowlauncher:ResultListBox x:Name="ResultListBox"
|
<flowlauncher:ResultListBox x:Name="ResultListBox"
|
||||||
DataContext="{Binding Results}"
|
DataContext="{Binding Results}"
|
||||||
PreviewMouseDown="OnPreviewMouseButtonDown" />
|
PreviewMouseLeftButtonUp="OnPreviewMouseButtonDown" />
|
||||||
</ContentControl>
|
</ContentControl>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Style="{DynamicResource WindowRadius}">
|
<Border Style="{DynamicResource WindowRadius}">
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
@ -20,6 +20,11 @@ using Flow.Launcher.Infrastructure;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
|
using System.Text;
|
||||||
|
using DataObject = System.Windows.DataObject;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using System.IO;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,12 +25,15 @@
|
||||||
VirtualizingStackPanel.IsVirtualizing="True"
|
VirtualizingStackPanel.IsVirtualizing="True"
|
||||||
VirtualizingStackPanel.VirtualizationMode="Standard"
|
VirtualizingStackPanel.VirtualizationMode="Standard"
|
||||||
Visibility="{Binding Visbility}"
|
Visibility="{Binding Visbility}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d"
|
||||||
|
PreviewMouseMove="ResultList_MouseMove"
|
||||||
|
PreviewMouseLeftButtonDown="ResultList_PreviewMouseLeftButtonDown">
|
||||||
<!-- IsSynchronizedWithCurrentItem: http://stackoverflow.com/a/7833798/2833083 -->
|
<!-- IsSynchronizedWithCurrentItem: http://stackoverflow.com/a/7833798/2833083 -->
|
||||||
|
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Button HorizontalAlignment="Stretch">
|
<Button
|
||||||
|
HorizontalAlignment="Stretch">
|
||||||
<Button.Template>
|
<Button.Template>
|
||||||
<ControlTemplate>
|
<ControlTemplate>
|
||||||
<ContentPresenter Content="{TemplateBinding Button.Content}" />
|
<ContentPresenter Content="{TemplateBinding Button.Content}" />
|
||||||
|
|
@ -84,7 +87,7 @@
|
||||||
x:Name="ImageIcon"
|
x:Name="ImageIcon"
|
||||||
Width="{Binding IconXY}"
|
Width="{Binding IconXY}"
|
||||||
Height="{Binding IconXY}"
|
Height="{Binding IconXY}"
|
||||||
Margin="0,0,0,0"
|
Margin="0,0,0,0" IsHitTestVisible="False"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Source="{Binding Image, TargetNullValue={x:Null}}"
|
Source="{Binding Image, TargetNullValue={x:Null}}"
|
||||||
Stretch="Uniform"
|
Stretch="Uniform"
|
||||||
|
|
@ -134,6 +137,7 @@
|
||||||
x:Name="Title"
|
x:Name="Title"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
DockPanel.Dock="Left"
|
DockPanel.Dock="Left"
|
||||||
|
IsHitTestVisible="False"
|
||||||
Style="{DynamicResource ItemTitleStyle}"
|
Style="{DynamicResource ItemTitleStyle}"
|
||||||
Text="{Binding Result.Title}"
|
Text="{Binding Result.Title}"
|
||||||
ToolTip="{Binding ShowTitleToolTip}">
|
ToolTip="{Binding ShowTitleToolTip}">
|
||||||
|
|
@ -147,6 +151,7 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="SubTitle"
|
x:Name="SubTitle"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
IsHitTestVisible="False"
|
||||||
Style="{DynamicResource ItemSubTitleStyle}"
|
Style="{DynamicResource ItemSubTitleStyle}"
|
||||||
Text="{Binding Result.SubTitle}"
|
Text="{Binding Result.SubTitle}"
|
||||||
ToolTip="{Binding ShowSubTitleToolTip}" />
|
ToolTip="{Binding ShowSubTitleToolTip}" />
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
using System.Windows;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher
|
namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
|
|
@ -24,7 +27,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private void OnMouseEnter(object sender, MouseEventArgs e)
|
private void OnMouseEnter(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
lock(_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
curItem = (ListBoxItem)sender;
|
curItem = (ListBoxItem)sender;
|
||||||
var p = e.GetPosition((IInputElement)sender);
|
var p = e.GetPosition((IInputElement)sender);
|
||||||
|
|
@ -34,7 +37,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private void OnMouseMove(object sender, MouseEventArgs e)
|
private void OnMouseMove(object sender, MouseEventArgs e)
|
||||||
{
|
{
|
||||||
lock(_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
var p = e.GetPosition((IInputElement)sender);
|
var p = e.GetPosition((IInputElement)sender);
|
||||||
if (_lastpos != p)
|
if (_lastpos != p)
|
||||||
|
|
@ -46,7 +49,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
lock(_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
if (curItem != null)
|
if (curItem != null)
|
||||||
{
|
{
|
||||||
|
|
@ -54,5 +57,51 @@ namespace Flow.Launcher
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Point start;
|
||||||
|
private string path;
|
||||||
|
private string query;
|
||||||
|
|
||||||
|
private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
|
||||||
|
return;
|
||||||
|
|
||||||
|
path = result.Result.CopyText;
|
||||||
|
query = result.Result.OriginQuery.RawQuery;
|
||||||
|
start = e.GetPosition(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResultList_MouseMove(object sender, MouseEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.LeftButton != MouseButtonState.Pressed)
|
||||||
|
{
|
||||||
|
start = default;
|
||||||
|
path = string.Empty;
|
||||||
|
query = string.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(path) && !Directory.Exists(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Point mousePosition = e.GetPosition(null);
|
||||||
|
Vector diff = this.start - mousePosition;
|
||||||
|
|
||||||
|
if (Math.Abs(diff.X) < SystemParameters.MinimumHorizontalDragDistance
|
||||||
|
|| Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var data = new DataObject(DataFormats.FileDrop, new[]
|
||||||
|
{
|
||||||
|
path
|
||||||
|
});
|
||||||
|
DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
|
||||||
|
|
||||||
|
App.API.ChangeQuery(query, true);
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
<converters:BorderClipConverter x:Key="BorderClipConverter" />
|
<converters:BorderClipConverter x:Key="BorderClipConverter" />
|
||||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||||
<converters:TextConverter x:Key="TextConverter" />
|
<converters:TextConverter x:Key="TextConverter" />
|
||||||
|
<converters:TranlationConverter x:Key="TranlationConverter" />
|
||||||
<CollectionViewSource x:Key="SortedFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
|
<CollectionViewSource x:Key="SortedFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
|
||||||
<CollectionViewSource.SortDescriptions>
|
<CollectionViewSource.SortDescriptions>
|
||||||
<scm:SortDescription PropertyName="Source" />
|
<scm:SortDescription PropertyName="Source" />
|
||||||
|
|
@ -2257,9 +2258,17 @@
|
||||||
<RowDefinition Height="43" />
|
<RowDefinition Height="43" />
|
||||||
<RowDefinition Height="80" />
|
<RowDefinition Height="80" />
|
||||||
<RowDefinition Height="146" />
|
<RowDefinition Height="146" />
|
||||||
|
|
||||||
<RowDefinition Height="50" />
|
<RowDefinition Height="50" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="50" />
|
<RowDefinition Height="50" />
|
||||||
|
|
||||||
|
<RowDefinition Height="50" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="50" />
|
||||||
|
|
||||||
|
<RowDefinition Height="50" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
|
|
@ -2364,6 +2373,7 @@
|
||||||
Text="{DynamicResource customQueryHotkey}" />
|
Text="{DynamicResource customQueryHotkey}" />
|
||||||
<ListView
|
<ListView
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
|
MinHeight="160"
|
||||||
Margin="0,0,0,0"
|
Margin="0,0,0,0"
|
||||||
Background="{DynamicResource Color02B}"
|
Background="{DynamicResource Color02B}"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
|
|
@ -2404,7 +2414,7 @@
|
||||||
<Button
|
<Button
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
Click="OnnEditCustomHotkeyClick"
|
Click="OnEditCustomHotkeyClick"
|
||||||
Content="{DynamicResource edit}" />
|
Content="{DynamicResource edit}" />
|
||||||
<Button
|
<Button
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
|
|
@ -2412,6 +2422,104 @@
|
||||||
Click="OnAddCustomHotkeyClick"
|
Click="OnAddCustomHotkeyClick"
|
||||||
Content="{DynamicResource add}" />
|
Content="{DynamicResource add}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="6"
|
||||||
|
Margin="0,0,12,2"
|
||||||
|
Padding="0,12,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="14"
|
||||||
|
Foreground="{DynamicResource Color05B}"
|
||||||
|
Text="{DynamicResource customQueryShortcut}" />
|
||||||
|
<ListView
|
||||||
|
Grid.Row="7"
|
||||||
|
Name="customShortcutView"
|
||||||
|
MinHeight="160"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Background="{DynamicResource Color02B}"
|
||||||
|
BorderBrush="DarkGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
ItemsSource="{Binding CustomShortcuts}"
|
||||||
|
SelectedItem="{Binding SelectedCustomShortcut}"
|
||||||
|
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
||||||
|
<ListView.View>
|
||||||
|
<GridView>
|
||||||
|
<GridViewColumn Width="180" Header="{DynamicResource customShortcut}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Key}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
<GridViewColumn Width="540" Header="{DynamicResource customShortcutExpansion}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Value}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="8"
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="10"
|
||||||
|
Click="OnDeleteCustomShortCutClick"
|
||||||
|
Content="{DynamicResource delete}" />
|
||||||
|
<Button
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="10"
|
||||||
|
Click="OnEditCustomShortCutClick"
|
||||||
|
Content="{DynamicResource edit}" />
|
||||||
|
<Button
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="10,10,0,10"
|
||||||
|
Click="OnAddCustomShortCutClick"
|
||||||
|
Content="{DynamicResource add}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="9"
|
||||||
|
Margin="0,0,12,2"
|
||||||
|
Padding="0,12,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="14"
|
||||||
|
Foreground="{DynamicResource Color05B}"
|
||||||
|
Text="Built-in Shortcuts" />
|
||||||
|
<ListView
|
||||||
|
Grid.Row="10"
|
||||||
|
MinHeight="160"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Background="{DynamicResource Color02B}"
|
||||||
|
BorderBrush="DarkGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
ItemsSource="{Binding BuiltinShortcuts}"
|
||||||
|
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
||||||
|
<ListView.View>
|
||||||
|
<GridView>
|
||||||
|
<GridViewColumn Width="180" Header="{DynamicResource customShortcut}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Key}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
<GridViewColumn Width="540" Header="{DynamicResource builtinShortcutDescription}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Description, Converter={StaticResource TranlationConverter}}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Border>
|
</Border>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ namespace Flow.Launcher
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
|
private void OnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var item = viewModel.SelectedCustomPluginHotkey;
|
var item = viewModel.SelectedCustomPluginHotkey;
|
||||||
if (item != null)
|
if (item != null)
|
||||||
|
|
@ -385,11 +385,34 @@ namespace Flow.Launcher
|
||||||
restoreButton.Visibility = Visibility.Collapsed;
|
restoreButton.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_StateChanged(object sender, EventArgs e)
|
private void Window_StateChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
RefreshMaximizeRestoreButton();
|
RefreshMaximizeRestoreButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Shortcut
|
||||||
|
|
||||||
|
private void OnDeleteCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
viewModel.DeleteSelectedCustomShortcut();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEditCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (viewModel.EditSelectedCustomShortcut())
|
||||||
|
{
|
||||||
|
customShortcutView.Items.Refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAddCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
viewModel.AddCustomShortcut();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
private CollectionView pluginListView;
|
private CollectionView pluginListView;
|
||||||
private CollectionView pluginStoreView;
|
private CollectionView pluginStoreView;
|
||||||
|
|
||||||
|
|
@ -467,6 +490,7 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
ClockDisplay();
|
ClockDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClockDisplay()
|
public void ClockDisplay()
|
||||||
{
|
{
|
||||||
if (settings.UseClock)
|
if (settings.UseClock)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ using Flow.Launcher.Plugin.SharedCommands;
|
||||||
using Flow.Launcher.Storage;
|
using Flow.Launcher.Storage;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Microsoft.VisualStudio.Threading;
|
using Microsoft.VisualStudio.Threading;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using ISavable = Flow.Launcher.Plugin.ISavable;
|
using ISavable = Flow.Launcher.Plugin.ISavable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
@ -621,7 +622,9 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
_updateSource?.Cancel();
|
_updateSource?.Cancel();
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(QueryText))
|
var query = ConstructQuery(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts);
|
||||||
|
|
||||||
|
if (query == null) // shortcut expanded
|
||||||
{
|
{
|
||||||
Results.Clear();
|
Results.Clear();
|
||||||
Results.Visbility = Visibility.Collapsed;
|
Results.Visbility = Visibility.Collapsed;
|
||||||
|
|
@ -645,8 +648,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
if (currentCancellationToken.IsCancellationRequested)
|
if (currentCancellationToken.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var query = QueryBuilder.Build(QueryText, PluginManager.NonGlobalPlugins);
|
|
||||||
|
|
||||||
// handle the exclusiveness of plugin using action keyword
|
// handle the exclusiveness of plugin using action keyword
|
||||||
RemoveOldQueryResults(query);
|
RemoveOldQueryResults(query);
|
||||||
|
|
@ -736,6 +738,40 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Query ConstructQuery(string queryText, IEnumerable<CustomShortcutModel> customShortcuts, IEnumerable<BuiltinShortcutModel> builtInShortcuts)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(queryText))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder queryBuilder = new(queryText);
|
||||||
|
StringBuilder queryBuilderTmp = new(queryText);
|
||||||
|
|
||||||
|
foreach (var shortcut in customShortcuts)
|
||||||
|
{
|
||||||
|
if (queryBuilder.Equals(shortcut.Key))
|
||||||
|
{
|
||||||
|
queryBuilder.Replace(shortcut.Key, shortcut.Expand());
|
||||||
|
}
|
||||||
|
|
||||||
|
queryBuilder.Replace('@' + shortcut.Key, shortcut.Expand());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var shortcut in builtInShortcuts)
|
||||||
|
{
|
||||||
|
queryBuilder.Replace(shortcut.Key, shortcut.Expand());
|
||||||
|
queryBuilderTmp.Replace(shortcut.Key, shortcut.Expand());
|
||||||
|
}
|
||||||
|
|
||||||
|
// show expanded builtin shortcuts
|
||||||
|
// use private field to avoid infinite recursion
|
||||||
|
_queryText = queryBuilderTmp.ToString();
|
||||||
|
|
||||||
|
var query = QueryBuilder.Build(queryBuilder.ToString().Trim(), PluginManager.NonGlobalPlugins);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
private void RemoveOldQueryResults(Query query)
|
private void RemoveOldQueryResults(Query query)
|
||||||
{
|
{
|
||||||
if (_lastQuery?.ActionKeyword != query?.ActionKeyword)
|
if (_lastQuery?.ActionKeyword != query?.ActionKeyword)
|
||||||
|
|
@ -966,28 +1002,26 @@ namespace Flow.Launcher.ViewModel
|
||||||
var result = Results.SelectedItem?.Result;
|
var result = Results.SelectedItem?.Result;
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
string copyText = string.IsNullOrEmpty(result.CopyText) ? result.SubTitle : result.CopyText;
|
string copyText = result.CopyText;
|
||||||
var isFile = File.Exists(copyText);
|
var isFile = File.Exists(copyText);
|
||||||
var isFolder = Directory.Exists(copyText);
|
var isFolder = Directory.Exists(copyText);
|
||||||
if (isFile || isFolder)
|
if (isFile || isFolder)
|
||||||
{
|
{
|
||||||
var paths = new StringCollection();
|
var paths = new StringCollection
|
||||||
paths.Add(copyText);
|
{
|
||||||
|
copyText
|
||||||
|
};
|
||||||
|
|
||||||
Clipboard.SetFileDropList(paths);
|
Clipboard.SetFileDropList(paths);
|
||||||
App.API.ShowMsg(
|
App.API.ShowMsg(
|
||||||
App.API.GetTranslation("copy")
|
$"{App.API.GetTranslation("copy")} {(isFile ? App.API.GetTranslation("fileTitle") : App.API.GetTranslation("folderTitle"))}",
|
||||||
+ " "
|
|
||||||
+ (isFile ? App.API.GetTranslation("fileTitle") : App.API.GetTranslation("folderTitle")),
|
|
||||||
App.API.GetTranslation("completedSuccessfully"));
|
App.API.GetTranslation("completedSuccessfully"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Clipboard.SetDataObject(copyText.ToString());
|
Clipboard.SetDataObject(copyText);
|
||||||
App.API.ShowMsg(
|
App.API.ShowMsg(
|
||||||
App.API.GetTranslation("copy")
|
$"{App.API.GetTranslation("copy")} {App.API.GetTranslation("textTitle")}",
|
||||||
+ " "
|
|
||||||
+ App.API.GetTranslation("textTitle"),
|
|
||||||
App.API.GetTranslation("completedSuccessfully"));
|
App.API.GetTranslation("completedSuccessfully"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ using Flow.Launcher.Infrastructure.Storage;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.ViewModel
|
namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
|
|
@ -212,11 +213,19 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<string> OpenResultModifiersList => new List<string> { KeyConstant.Alt, KeyConstant.Ctrl, $"{KeyConstant.Ctrl}+{KeyConstant.Alt}" };
|
public List<string> OpenResultModifiersList => new List<string>
|
||||||
|
{
|
||||||
|
KeyConstant.Alt,
|
||||||
|
KeyConstant.Ctrl,
|
||||||
|
$"{KeyConstant.Ctrl}+{KeyConstant.Alt}"
|
||||||
|
};
|
||||||
private Internationalization _translater => InternationalizationManager.Instance;
|
private Internationalization _translater => InternationalizationManager.Instance;
|
||||||
public List<Language> Languages => _translater.LoadAvailableLanguages();
|
public List<Language> Languages => _translater.LoadAvailableLanguages();
|
||||||
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);
|
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);
|
||||||
|
|
||||||
|
public ObservableCollection<CustomShortcutModel> CustomShortcuts => Settings.CustomShortcuts;
|
||||||
|
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts => Settings.BuiltinShortcuts;
|
||||||
|
|
||||||
public string TestProxy()
|
public string TestProxy()
|
||||||
{
|
{
|
||||||
var proxyServer = Settings.Proxy.Server;
|
var proxyServer = Settings.Proxy.Server;
|
||||||
|
|
@ -275,7 +284,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
var metadatas = PluginManager.AllPlugins
|
var metadatas = PluginManager.AllPlugins
|
||||||
.OrderBy(x => x.Metadata.Disabled)
|
.OrderBy(x => x.Metadata.Disabled)
|
||||||
.ThenBy(y => y.Metadata.Name)
|
.ThenBy(y => y.Metadata.Name)
|
||||||
.Select(p => new PluginViewModel { PluginPair = p })
|
.Select(p => new PluginViewModel
|
||||||
|
{
|
||||||
|
PluginPair = p
|
||||||
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
return metadatas;
|
return metadatas;
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +409,11 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
var key = $"ColorScheme{e}";
|
var key = $"ColorScheme{e}";
|
||||||
var display = _translater.GetTranslation(key);
|
var display = _translater.GetTranslation(key);
|
||||||
var m = new ColorScheme { Display = display, Value = e, };
|
var m = new ColorScheme
|
||||||
|
{
|
||||||
|
Display = display,
|
||||||
|
Value = e,
|
||||||
|
};
|
||||||
modes.Add(m);
|
modes.Add(m);
|
||||||
}
|
}
|
||||||
return modes;
|
return modes;
|
||||||
|
|
@ -522,7 +538,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
bitmap.DecodePixelWidth = 800;
|
bitmap.DecodePixelWidth = 800;
|
||||||
bitmap.DecodePixelHeight = 600;
|
bitmap.DecodePixelHeight = 600;
|
||||||
bitmap.EndInit();
|
bitmap.EndInit();
|
||||||
var brush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
|
var brush = new ImageBrush(bitmap)
|
||||||
|
{
|
||||||
|
Stretch = Stretch.UniformToFill
|
||||||
|
};
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -550,19 +569,19 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
Title = "WebSearch",
|
Title = "WebSearch",
|
||||||
SubTitle = "Search the web with different search engine support",
|
SubTitle = "Search the web with different search engine support",
|
||||||
IcoPath =Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
||||||
},
|
},
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = "Program",
|
Title = "Program",
|
||||||
SubTitle = "Launch programs as admin or a different user",
|
SubTitle = "Launch programs as admin or a different user",
|
||||||
IcoPath =Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Program\Images\program.png")
|
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Program\Images\program.png")
|
||||||
},
|
},
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = "ProcessKiller",
|
Title = "ProcessKiller",
|
||||||
SubTitle = "Terminate unwanted processes",
|
SubTitle = "Terminate unwanted processes",
|
||||||
IcoPath =Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var vm = new ResultsViewModel(Settings);
|
var vm = new ResultsViewModel(Settings);
|
||||||
|
|
@ -576,8 +595,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Fonts.SystemFontFamilies.Count(o =>
|
if (Fonts.SystemFontFamilies.Count(o =>
|
||||||
o.FamilyNames.Values != null &&
|
o.FamilyNames.Values != null &&
|
||||||
o.FamilyNames.Values.Contains(Settings.QueryBoxFont)) > 0)
|
o.FamilyNames.Values.Contains(Settings.QueryBoxFont)) > 0)
|
||||||
{
|
{
|
||||||
var font = new FontFamily(Settings.QueryBoxFont);
|
var font = new FontFamily(Settings.QueryBoxFont);
|
||||||
return font;
|
return font;
|
||||||
|
|
@ -604,7 +623,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
Settings.QueryBoxFontStyle,
|
Settings.QueryBoxFontStyle,
|
||||||
Settings.QueryBoxFontWeight,
|
Settings.QueryBoxFontWeight,
|
||||||
Settings.QueryBoxFontStretch
|
Settings.QueryBoxFontStretch
|
||||||
));
|
));
|
||||||
return typeface;
|
return typeface;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
|
|
@ -621,8 +640,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Fonts.SystemFontFamilies.Count(o =>
|
if (Fonts.SystemFontFamilies.Count(o =>
|
||||||
o.FamilyNames.Values != null &&
|
o.FamilyNames.Values != null &&
|
||||||
o.FamilyNames.Values.Contains(Settings.ResultFont)) > 0)
|
o.FamilyNames.Values.Contains(Settings.ResultFont)) > 0)
|
||||||
{
|
{
|
||||||
var font = new FontFamily(Settings.ResultFont);
|
var font = new FontFamily(Settings.ResultFont);
|
||||||
return font;
|
return font;
|
||||||
|
|
@ -649,7 +668,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
Settings.ResultFontStyle,
|
Settings.ResultFontStyle,
|
||||||
Settings.ResultFontWeight,
|
Settings.ResultFontWeight,
|
||||||
Settings.ResultFontStretch
|
Settings.ResultFontStretch
|
||||||
));
|
));
|
||||||
return typeface;
|
return typeface;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
|
|
@ -671,6 +690,65 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region shortcut
|
||||||
|
|
||||||
|
public CustomShortcutModel? SelectedCustomShortcut { get; set; }
|
||||||
|
|
||||||
|
public void DeleteSelectedCustomShortcut()
|
||||||
|
{
|
||||||
|
var item = SelectedCustomShortcut;
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string deleteWarning = string.Format(
|
||||||
|
InternationalizationManager.Instance.GetTranslation("deleteCustomShortcutWarning"),
|
||||||
|
item?.Key, item?.Value);
|
||||||
|
if (MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"),
|
||||||
|
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||||
|
{
|
||||||
|
Settings.CustomShortcuts.Remove(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EditSelectedCustomShortcut()
|
||||||
|
{
|
||||||
|
var item = SelectedCustomShortcut;
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var shortcutSettingWindow = new CustomShortcutSetting(item.Key, item.Value, this);
|
||||||
|
if (shortcutSettingWindow.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
item.Key = shortcutSettingWindow.Key;
|
||||||
|
item.Value = shortcutSettingWindow.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddCustomShortcut()
|
||||||
|
{
|
||||||
|
var shortcutSettingWindow = new CustomShortcutSetting(this);
|
||||||
|
if (shortcutSettingWindow.ShowDialog() == true)
|
||||||
|
{
|
||||||
|
var shortcut = new CustomShortcutModel(shortcutSettingWindow.Key, shortcutSettingWindow.Value);
|
||||||
|
Settings.CustomShortcuts.Add(shortcut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShortcutExists(string key)
|
||||||
|
{
|
||||||
|
return Settings.CustomShortcuts.Any(x => x.Key == key) || Settings.BuiltinShortcuts.Any(x => x.Key == key);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region about
|
#region about
|
||||||
|
|
||||||
public string Website => Constant.Website;
|
public string Website => Constant.Website;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
contextMenu = new ContextMenu(Context);
|
contextMenu = new ContextMenu(Context);
|
||||||
pluginManager = new PluginsManager(Context, Settings);
|
pluginManager = new PluginsManager(Context, Settings);
|
||||||
|
|
||||||
await pluginManager.UpdateManifestAsync();
|
_ = pluginManager.UpdateManifestAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Result> LoadContextMenus(Result selectedResult)
|
public List<Result> LoadContextMenus(Result selectedResult)
|
||||||
|
|
@ -74,4 +74,4 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
||||||
return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description");
|
return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,9 @@
|
||||||
|
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_excutable_types">File Suffixes</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_excutable_types">File Suffixes</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_types">URL Protocols</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_types">URL Protocols</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_steam">Steam Games</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_epic">Epic Games</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_http">Http/Https</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_custom_urls">Custom URL Protocols</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_custom_urls">Custom URL Protocols</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_custom_file_types">Custom File Suffixes</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_custom_file_types">Custom File Suffixes</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_tooltip">
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_tooltip">
|
||||||
|
|
|
||||||
|
|
@ -189,9 +189,9 @@
|
||||||
FontSize="16"
|
FontSize="16"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_suffixes_URL_types}" />
|
Text="{DynamicResource flowlauncher_plugin_program_suffixes_URL_types}" />
|
||||||
<CheckBox Name="steam" Margin="10,0,0,0" IsChecked="{Binding ProtocolsStatus[steam]}">Steam Games</CheckBox>
|
<CheckBox Name="steam" Margin="10,0,0,0" IsChecked="{Binding ProtocolsStatus[steam]}" Content="{DynamicResource flowlauncher_plugin_program_suffixes_URL_steam}"></CheckBox>
|
||||||
<CheckBox Name="epic" Margin="10,0,0,0" IsChecked="{Binding ProtocolsStatus[epic]}">Epic Games</CheckBox>
|
<CheckBox Name="epic" Margin="10,0,0,0" IsChecked="{Binding ProtocolsStatus[epic]}" Content="{DynamicResource flowlauncher_plugin_program_suffixes_URL_epic}"></CheckBox>
|
||||||
<CheckBox Name="http" Margin="10,0,0,0" IsChecked="{Binding ProtocolsStatus[http]}">Http/Https</CheckBox>
|
<CheckBox Name="http" Margin="10,0,0,0" IsChecked="{Binding ProtocolsStatus[http]}" Content="{DynamicResource flowlauncher_plugin_program_suffixes_URL_http}"></CheckBox>
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="CustomProtocol"
|
Name="CustomProtocol"
|
||||||
Margin="10,0,0,0"
|
Margin="10,0,0,0"
|
||||||
|
|
|
||||||
|
|
@ -390,7 +390,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
_ => Win32Program(x)
|
_ => Win32Program(x)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return programs;
|
return programs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -411,7 +410,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ShortcutExtension => LnkProgram(x),
|
ShortcutExtension => LnkProgram(x),
|
||||||
UrlExtension => UrlProgram(x),
|
UrlExtension => UrlProgram(x),
|
||||||
_ => Win32Program(x)
|
_ => Win32Program(x)
|
||||||
}).Where(x => x.Valid);
|
});
|
||||||
return programs;
|
return programs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -569,7 +568,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
|
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
|
||||||
|
|
||||||
return programs.Concat(autoIndexPrograms).Distinct().ToArray();
|
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();
|
||||||
}
|
}
|
||||||
#if DEBUG //This is to make developer aware of any unhandled exception and add in handling.
|
#if DEBUG //This is to make developer aware of any unhandled exception and add in handling.
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Windows.Foundation.Metadata;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program
|
namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
|
|
@ -11,7 +12,10 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
public DateTime LastIndexTime { get; set; }
|
public DateTime LastIndexTime { get; set; }
|
||||||
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
|
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
|
||||||
public List<DisabledProgramSource> DisabledProgramSources { get; set; } = new List<DisabledProgramSource>();
|
public List<DisabledProgramSource> DisabledProgramSources { get; set; } = new List<DisabledProgramSource>();
|
||||||
public string[] CustomSuffixes { get; set; } = Array.Empty<string>();
|
|
||||||
|
[Obsolete, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
|
public string[] ProgramSuffixes { get; set; } = null;
|
||||||
|
public string[] CustomSuffixes { get; set; } = Array.Empty<string>(); // Custom suffixes only
|
||||||
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
|
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
|
||||||
|
|
||||||
public Dictionary<string, bool> BuiltinSuffixesStatus { get; set; } = new Dictionary<string, bool>{
|
public Dictionary<string, bool> BuiltinSuffixesStatus { get; set; } = new Dictionary<string, bool>{
|
||||||
|
|
@ -32,6 +36,7 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
|
|
||||||
public string[] GetSuffixes()
|
public string[] GetSuffixes()
|
||||||
{
|
{
|
||||||
|
RemoveRedundantSuffixes();
|
||||||
List<string> extensions = new List<string>();
|
List<string> extensions = new List<string>();
|
||||||
foreach (var item in BuiltinSuffixesStatus)
|
foreach (var item in BuiltinSuffixesStatus)
|
||||||
{
|
{
|
||||||
|
|
@ -84,6 +89,24 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RemoveRedundantSuffixes()
|
||||||
|
{
|
||||||
|
// Migrate to new settings
|
||||||
|
// CustomSuffixes no longer contains custom suffixes
|
||||||
|
// users has tweaked the settings
|
||||||
|
// or this function has been executed once
|
||||||
|
if (UseCustomSuffixes == true || ProgramSuffixes == null)
|
||||||
|
return;
|
||||||
|
var suffixes = ProgramSuffixes.ToList();
|
||||||
|
foreach(var item in BuiltinSuffixesStatus)
|
||||||
|
{
|
||||||
|
suffixes.Remove(item.Key);
|
||||||
|
}
|
||||||
|
CustomSuffixes = suffixes.ToArray(); // Custom suffixes
|
||||||
|
UseCustomSuffixes = CustomSuffixes.Length != 0; // Search custom suffixes or not
|
||||||
|
ProgramSuffixes = null;
|
||||||
|
}
|
||||||
|
|
||||||
public bool EnableStartMenuSource { get; set; } = true;
|
public bool EnableStartMenuSource { get; set; } = true;
|
||||||
public bool EnableDescription { get; set; } = false;
|
public bool EnableDescription { get; set; } = false;
|
||||||
public bool HideAppsPath { get; set; } = true;
|
public bool HideAppsPath { get; set; } = true;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue