mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge 'dev' into 'velopack'
This commit is contained in:
commit
f9bb3e6aa7
161 changed files with 4644 additions and 2673 deletions
|
|
@ -58,7 +58,7 @@ dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||||
###############################
|
###############################
|
||||||
# Style Definitions
|
# Style Definitions
|
||||||
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
|
||||||
# Use PascalCase for constant fields
|
# Use PascalCase for constant fields
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
|
||||||
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
|
||||||
|
|
@ -134,7 +134,7 @@ csharp_preserve_single_line_statements = true
|
||||||
csharp_preserve_single_line_blocks = true
|
csharp_preserve_single_line_blocks = true
|
||||||
csharp_using_directive_placement = outside_namespace:silent
|
csharp_using_directive_placement = outside_namespace:silent
|
||||||
csharp_prefer_simple_using_statement = true:suggestion
|
csharp_prefer_simple_using_statement = true:suggestion
|
||||||
csharp_style_namespace_declarations = block_scoped:silent
|
csharp_style_namespace_declarations = file_scoped:silent
|
||||||
csharp_style_prefer_method_group_conversion = true:silent
|
csharp_style_prefer_method_group_conversion = true:silent
|
||||||
csharp_style_expression_bodied_lambdas = true:silent
|
csharp_style_expression_bodied_lambdas = true:silent
|
||||||
csharp_style_expression_bodied_local_functions = false:silent
|
csharp_style_expression_bodied_local_functions = false:silent
|
||||||
|
|
|
||||||
3
.github/actions/spelling/allow.txt
vendored
3
.github/actions/spelling/allow.txt
vendored
|
|
@ -21,3 +21,6 @@ vkcode
|
||||||
winget
|
winget
|
||||||
workaround
|
workaround
|
||||||
nupkg
|
nupkg
|
||||||
|
Firefox
|
||||||
|
Português
|
||||||
|
Português (Brasil)
|
||||||
|
|
|
||||||
2
.github/actions/spelling/expect.txt
vendored
2
.github/actions/spelling/expect.txt
vendored
|
|
@ -74,6 +74,7 @@ WCA_ACCENT_POLICY
|
||||||
HGlobal
|
HGlobal
|
||||||
dopusrt
|
dopusrt
|
||||||
firefox
|
firefox
|
||||||
|
Firefox
|
||||||
msedge
|
msedge
|
||||||
svgc
|
svgc
|
||||||
ime
|
ime
|
||||||
|
|
@ -97,6 +98,7 @@ Português
|
||||||
Português (Brasil)
|
Português (Brasil)
|
||||||
Italiano
|
Italiano
|
||||||
Slovenský
|
Slovenský
|
||||||
|
Tiếng Việt
|
||||||
Droplex
|
Droplex
|
||||||
Preinstalled
|
Preinstalled
|
||||||
errormetadatafile
|
errormetadatafile
|
||||||
|
|
|
||||||
24
.github/workflows/default_plugins.yml
vendored
24
.github/workflows/default_plugins.yml
vendored
|
|
@ -65,7 +65,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish BrowserBookmark
|
- name: Publish BrowserBookmark
|
||||||
if: steps.changes.outputs.browserbookmark == 'true'
|
if: steps.changes.outputs.browserbookmark == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.BrowserBookmark"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.BrowserBookmark"
|
||||||
files: "Flow.Launcher.Plugin.BrowserBookmark.zip"
|
files: "Flow.Launcher.Plugin.BrowserBookmark.zip"
|
||||||
|
|
@ -92,7 +92,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish Calculator
|
- name: Publish Calculator
|
||||||
if: steps.changes.outputs.calculator == 'true'
|
if: steps.changes.outputs.calculator == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Calculator"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.Calculator"
|
||||||
files: "Flow.Launcher.Plugin.Calculator.zip"
|
files: "Flow.Launcher.Plugin.Calculator.zip"
|
||||||
|
|
@ -119,7 +119,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish Explorer
|
- name: Publish Explorer
|
||||||
if: steps.changes.outputs.explorer == 'true'
|
if: steps.changes.outputs.explorer == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Explorer"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.Explorer"
|
||||||
files: "Flow.Launcher.Plugin.Explorer.zip"
|
files: "Flow.Launcher.Plugin.Explorer.zip"
|
||||||
|
|
@ -146,7 +146,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish PluginIndicator
|
- name: Publish PluginIndicator
|
||||||
if: steps.changes.outputs.pluginindicator == 'true'
|
if: steps.changes.outputs.pluginindicator == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginIndicator"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginIndicator"
|
||||||
files: "Flow.Launcher.Plugin.PluginIndicator.zip"
|
files: "Flow.Launcher.Plugin.PluginIndicator.zip"
|
||||||
|
|
@ -173,7 +173,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish PluginsManager
|
- name: Publish PluginsManager
|
||||||
if: steps.changes.outputs.pluginsmanager == 'true'
|
if: steps.changes.outputs.pluginsmanager == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginsManager"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginsManager"
|
||||||
files: "Flow.Launcher.Plugin.PluginsManager.zip"
|
files: "Flow.Launcher.Plugin.PluginsManager.zip"
|
||||||
|
|
@ -200,7 +200,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish ProcessKiller
|
- name: Publish ProcessKiller
|
||||||
if: steps.changes.outputs.processkiller == 'true'
|
if: steps.changes.outputs.processkiller == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller"
|
||||||
files: "Flow.Launcher.Plugin.ProcessKiller.zip"
|
files: "Flow.Launcher.Plugin.ProcessKiller.zip"
|
||||||
|
|
@ -227,7 +227,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish Program
|
- name: Publish Program
|
||||||
if: steps.changes.outputs.program == 'true'
|
if: steps.changes.outputs.program == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Program"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.Program"
|
||||||
files: "Flow.Launcher.Plugin.Program.zip"
|
files: "Flow.Launcher.Plugin.Program.zip"
|
||||||
|
|
@ -254,7 +254,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish Shell
|
- name: Publish Shell
|
||||||
if: steps.changes.outputs.shell == 'true'
|
if: steps.changes.outputs.shell == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Shell"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.Shell"
|
||||||
files: "Flow.Launcher.Plugin.Shell.zip"
|
files: "Flow.Launcher.Plugin.Shell.zip"
|
||||||
|
|
@ -281,7 +281,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish Sys
|
- name: Publish Sys
|
||||||
if: steps.changes.outputs.sys == 'true'
|
if: steps.changes.outputs.sys == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Sys"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.Sys"
|
||||||
files: "Flow.Launcher.Plugin.Sys.zip"
|
files: "Flow.Launcher.Plugin.Sys.zip"
|
||||||
|
|
@ -308,7 +308,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish Url
|
- name: Publish Url
|
||||||
if: steps.changes.outputs.url == 'true'
|
if: steps.changes.outputs.url == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Url"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.Url"
|
||||||
files: "Flow.Launcher.Plugin.Url.zip"
|
files: "Flow.Launcher.Plugin.Url.zip"
|
||||||
|
|
@ -335,7 +335,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish WebSearch
|
- name: Publish WebSearch
|
||||||
if: steps.changes.outputs.websearch == 'true'
|
if: steps.changes.outputs.websearch == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.WebSearch"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.WebSearch"
|
||||||
files: "Flow.Launcher.Plugin.WebSearch.zip"
|
files: "Flow.Launcher.Plugin.WebSearch.zip"
|
||||||
|
|
@ -362,7 +362,7 @@ jobs:
|
||||||
|
|
||||||
- name: Publish WindowsSettings
|
- name: Publish WindowsSettings
|
||||||
if: steps.changes.outputs.windowssettings == 'true'
|
if: steps.changes.outputs.windowssettings == 'true'
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.WindowsSettings"
|
repository: "Flow-Launcher/Flow.Launcher.Plugin.WindowsSettings"
|
||||||
files: "Flow.Launcher.Plugin.WindowsSettings.zip"
|
files: "Flow.Launcher.Plugin.WindowsSettings.zip"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Flow.Launcher.Core.Resource
|
namespace Flow.Launcher.Core.Resource
|
||||||
{
|
{
|
||||||
|
|
@ -27,6 +27,8 @@ namespace Flow.Launcher.Core.Resource
|
||||||
public static Language Turkish = new Language("tr", "Türkçe");
|
public static Language Turkish = new Language("tr", "Türkçe");
|
||||||
public static Language Czech = new Language("cs", "čeština");
|
public static Language Czech = new Language("cs", "čeština");
|
||||||
public static Language Arabic = new Language("ar", "اللغة العربية");
|
public static Language Arabic = new Language("ar", "اللغة العربية");
|
||||||
|
public static Language Vietnamese = new Language("vi-vn", "Tiếng Việt");
|
||||||
|
|
||||||
|
|
||||||
public static List<Language> GetAvailableLanguages()
|
public static List<Language> GetAvailableLanguages()
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +56,8 @@ namespace Flow.Launcher.Core.Resource
|
||||||
Slovak,
|
Slovak,
|
||||||
Turkish,
|
Turkish,
|
||||||
Czech,
|
Czech,
|
||||||
Arabic
|
Arabic,
|
||||||
|
Vietnamese
|
||||||
};
|
};
|
||||||
return languages;
|
return languages;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ namespace Flow.Launcher.Infrastructure
|
||||||
public static class Constant
|
public static class Constant
|
||||||
{
|
{
|
||||||
public const string FlowLauncher = "Flow.Launcher";
|
public const string FlowLauncher = "Flow.Launcher";
|
||||||
|
public const string FlowLauncherFullName = "Flow Launcher";
|
||||||
public const string Plugins = "Plugins";
|
public const string Plugins = "Plugins";
|
||||||
public const string PluginMetadataFileName = "plugin.json";
|
public const string PluginMetadataFileName = "plugin.json";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MemoryPack" Version="1.10.0" />
|
<PackageReference Include="MemoryPack" Version="1.21.1" />
|
||||||
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.7.30" />
|
<PackageReference Include="Microsoft.VisualStudio.Threading" Version="17.7.30" />
|
||||||
<PackageReference Include="NLog" Version="4.7.10" />
|
<PackageReference Include="NLog" Version="4.7.10" />
|
||||||
<PackageReference Include="NLog.Schema" Version="4.7.10" />
|
<PackageReference Include="NLog.Schema" Version="4.7.10" />
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.Windows.Input;
|
||||||
|
|
||||||
namespace Flow.Launcher.Infrastructure.Hotkey
|
namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
{
|
{
|
||||||
public class HotkeyModel
|
public record struct HotkeyModel
|
||||||
{
|
{
|
||||||
public bool Alt { get; set; }
|
public bool Alt { get; set; }
|
||||||
public bool Shift { get; set; }
|
public bool Shift { get; set; }
|
||||||
|
|
@ -17,8 +17,7 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
|
|
||||||
private static readonly Dictionary<Key, string> specialSymbolDictionary = new Dictionary<Key, string>
|
private static readonly Dictionary<Key, string> specialSymbolDictionary = new Dictionary<Key, string>
|
||||||
{
|
{
|
||||||
{Key.Space, "Space"},
|
{ Key.Space, "Space" }, { Key.Oem3, "~" }
|
||||||
{Key.Oem3, "~"}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public ModifierKeys ModifierKeys
|
public ModifierKeys ModifierKeys
|
||||||
|
|
@ -30,18 +29,22 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
{
|
{
|
||||||
modifierKeys |= ModifierKeys.Alt;
|
modifierKeys |= ModifierKeys.Alt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Shift)
|
if (Shift)
|
||||||
{
|
{
|
||||||
modifierKeys |= ModifierKeys.Shift;
|
modifierKeys |= ModifierKeys.Shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Win)
|
if (Win)
|
||||||
{
|
{
|
||||||
modifierKeys |= ModifierKeys.Windows;
|
modifierKeys |= ModifierKeys.Windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Ctrl)
|
if (Ctrl)
|
||||||
{
|
{
|
||||||
modifierKeys |= ModifierKeys.Control;
|
modifierKeys |= ModifierKeys.Control;
|
||||||
}
|
}
|
||||||
|
|
||||||
return modifierKeys;
|
return modifierKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -66,31 +69,37 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<string> keys = hotkeyString.Replace(" ", "").Split('+').ToList();
|
List<string> keys = hotkeyString.Replace(" ", "").Split('+').ToList();
|
||||||
if (keys.Contains("Alt"))
|
if (keys.Contains("Alt"))
|
||||||
{
|
{
|
||||||
Alt = true;
|
Alt = true;
|
||||||
keys.Remove("Alt");
|
keys.Remove("Alt");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.Contains("Shift"))
|
if (keys.Contains("Shift"))
|
||||||
{
|
{
|
||||||
Shift = true;
|
Shift = true;
|
||||||
keys.Remove("Shift");
|
keys.Remove("Shift");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.Contains("Win"))
|
if (keys.Contains("Win"))
|
||||||
{
|
{
|
||||||
Win = true;
|
Win = true;
|
||||||
keys.Remove("Win");
|
keys.Remove("Win");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.Contains("Ctrl"))
|
if (keys.Contains("Ctrl"))
|
||||||
{
|
{
|
||||||
Ctrl = true;
|
Ctrl = true;
|
||||||
keys.Remove("Ctrl");
|
keys.Remove("Ctrl");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keys.Count == 1)
|
if (keys.Count == 1)
|
||||||
{
|
{
|
||||||
string charKey = keys[0];
|
string charKey = keys[0];
|
||||||
KeyValuePair<Key, string>? specialSymbolPair = specialSymbolDictionary.FirstOrDefault(pair => pair.Value == charKey);
|
KeyValuePair<Key, string>? specialSymbolPair =
|
||||||
|
specialSymbolDictionary.FirstOrDefault(pair => pair.Value == charKey);
|
||||||
if (specialSymbolPair.Value.Value != null)
|
if (specialSymbolPair.Value.Value != null)
|
||||||
{
|
{
|
||||||
CharKey = specialSymbolPair.Value.Key;
|
CharKey = specialSymbolPair.Value.Key;
|
||||||
|
|
@ -103,7 +112,6 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
}
|
}
|
||||||
catch (ArgumentException)
|
catch (ArgumentException)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -111,33 +119,39 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
List<string> keys = new List<string>();
|
return string.Join(" + ", EnumerateDisplayKeys());
|
||||||
if (Ctrl)
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> EnumerateDisplayKeys()
|
||||||
|
{
|
||||||
|
if (Ctrl && CharKey is not (Key.LeftCtrl or Key.RightCtrl))
|
||||||
{
|
{
|
||||||
keys.Add("Ctrl");
|
yield return "Ctrl";
|
||||||
}
|
}
|
||||||
if (Alt)
|
|
||||||
|
if (Alt && CharKey is not (Key.LeftAlt or Key.RightAlt))
|
||||||
{
|
{
|
||||||
keys.Add("Alt");
|
yield return "Alt";
|
||||||
}
|
}
|
||||||
if (Shift)
|
|
||||||
|
if (Shift && CharKey is not (Key.LeftShift or Key.RightShift))
|
||||||
{
|
{
|
||||||
keys.Add("Shift");
|
yield return "Shift";
|
||||||
}
|
}
|
||||||
if (Win)
|
|
||||||
|
if (Win && CharKey is not (Key.LWin or Key.RWin))
|
||||||
{
|
{
|
||||||
keys.Add("Win");
|
yield return "Win";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CharKey != Key.None)
|
if (CharKey != Key.None)
|
||||||
{
|
{
|
||||||
keys.Add(specialSymbolDictionary.ContainsKey(CharKey)
|
yield return specialSymbolDictionary.TryGetValue(CharKey, out var value)
|
||||||
? specialSymbolDictionary[CharKey]
|
? value
|
||||||
: CharKey.ToString());
|
: CharKey.ToString();
|
||||||
}
|
}
|
||||||
return string.Join(" + ", keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Validate hotkey
|
/// Validate hotkey
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -164,11 +178,13 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
{
|
{
|
||||||
KeyGesture keyGesture = new KeyGesture(CharKey, ModifierKeys);
|
KeyGesture keyGesture = new KeyGesture(CharKey, ModifierKeys);
|
||||||
}
|
}
|
||||||
catch (System.Exception e) when (e is NotSupportedException || e is InvalidEnumArgumentException)
|
catch (System.Exception e) when
|
||||||
|
(e is NotSupportedException || e is InvalidEnumArgumentException)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ModifierKeys == ModifierKeys.None)
|
if (ModifierKeys == ModifierKeys.None)
|
||||||
{
|
{
|
||||||
return !IsPrintableCharacter(CharKey);
|
return !IsPrintableCharacter(CharKey);
|
||||||
|
|
@ -206,18 +222,6 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
||||||
key == Key.Decimal;
|
key == Key.Decimal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (obj is HotkeyModel other)
|
|
||||||
{
|
|
||||||
return ModifierKeys == other.ModifierKeys && CharKey == other.CharKey;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return HashCode.Combine(ModifierKeys, CharKey);
|
return HashCode.Combine(ModifierKeys, CharKey);
|
||||||
|
|
|
||||||
17
Flow.Launcher.Infrastructure/Hotkey/IHotkeySettings.cs
Normal file
17
Flow.Launcher.Infrastructure/Hotkey/IHotkeySettings.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface that you should implement in your settings class to be able to pass it to
|
||||||
|
/// <c>Flow.Launcher.HotkeyControlDialog</c>. It allows the dialog to display the hotkeys that have already been
|
||||||
|
/// registered, and optionally provide a way to unregister them.
|
||||||
|
/// </summary>
|
||||||
|
public interface IHotkeySettings
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A list of hotkeys that have already been registered. The dialog will display these hotkeys and provide a way to
|
||||||
|
/// unregister them.
|
||||||
|
/// </summary>
|
||||||
|
public List<RegisteredHotkeyData> RegisteredHotkeys { get; }
|
||||||
|
}
|
||||||
119
Flow.Launcher.Infrastructure/Hotkey/RegisteredHotkeyData.cs
Normal file
119
Flow.Launcher.Infrastructure/Hotkey/RegisteredHotkeyData.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a hotkey that has been registered. Used in <c>Flow.Launcher.HotkeyControlDialog</c> via
|
||||||
|
/// <see cref="UserSettings"/> and <see cref="IHotkeySettings"/> to display errors if user tries to register a hotkey
|
||||||
|
/// that has already been registered, and optionally provides a way to unregister the hotkey.
|
||||||
|
/// </summary>
|
||||||
|
public record RegisteredHotkeyData
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="HotkeyModel"/> representation of this hotkey.
|
||||||
|
/// </summary>
|
||||||
|
public HotkeyModel Hotkey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// String key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||||
|
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||||
|
/// </summary>
|
||||||
|
public string DescriptionResourceKey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Array of values that will replace <c>{0}</c>, <c>{1}</c>, <c>{2}</c>, etc. in the localized string found via
|
||||||
|
/// <see cref="DescriptionResourceKey"/>.
|
||||||
|
/// </summary>
|
||||||
|
public object?[] DescriptionFormatVariables { get; } = Array.Empty<object?>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that
|
||||||
|
/// this hotkey can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||||
|
/// </summary>
|
||||||
|
public Action? RemoveHotkey { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of <c>RegisteredHotkeyData</c>. Assumes that the key specified in
|
||||||
|
/// <c>descriptionResourceKey</c> doesn't need any arguments for <c>string.Format</c>. If it does,
|
||||||
|
/// use one of the other constructors.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hotkey">
|
||||||
|
/// The hotkey this class will represent.
|
||||||
|
/// Example values: <c>F1</c>, <c>Ctrl+Shift+Enter</c>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="descriptionResourceKey">
|
||||||
|
/// The key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||||
|
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="removeHotkey">
|
||||||
|
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that this hotkey
|
||||||
|
/// can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||||
|
/// </param>
|
||||||
|
public RegisteredHotkeyData(string hotkey, string descriptionResourceKey, Action? removeHotkey = null)
|
||||||
|
{
|
||||||
|
Hotkey = new HotkeyModel(hotkey);
|
||||||
|
DescriptionResourceKey = descriptionResourceKey;
|
||||||
|
RemoveHotkey = removeHotkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of <c>RegisteredHotkeyData</c>. Assumes that the key specified in
|
||||||
|
/// <c>descriptionResourceKey</c> needs exactly one argument for <c>string.Format</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hotkey">
|
||||||
|
/// The hotkey this class will represent.
|
||||||
|
/// Example values: <c>F1</c>, <c>Ctrl+Shift+Enter</c>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="descriptionResourceKey">
|
||||||
|
/// The key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||||
|
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="descriptionFormatVariable">
|
||||||
|
/// The value that will replace <c>{0}</c> in the localized string found via <c>description</c>.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="removeHotkey">
|
||||||
|
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that this hotkey
|
||||||
|
/// can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||||
|
/// </param>
|
||||||
|
public RegisteredHotkeyData(
|
||||||
|
string hotkey, string descriptionResourceKey, object? descriptionFormatVariable, Action? removeHotkey = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Hotkey = new HotkeyModel(hotkey);
|
||||||
|
DescriptionResourceKey = descriptionResourceKey;
|
||||||
|
DescriptionFormatVariables = new[] { descriptionFormatVariable };
|
||||||
|
RemoveHotkey = removeHotkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an instance of <c>RegisteredHotkeyData</c>. Assumes that the key specified in
|
||||||
|
/// <paramref name="descriptionResourceKey"/> needs multiple arguments for <c>string.Format</c>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hotkey">
|
||||||
|
/// The hotkey this class will represent.
|
||||||
|
/// Example values: <c>F1</c>, <c>Ctrl+Shift+Enter</c>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="descriptionResourceKey">
|
||||||
|
/// The key in the localization dictionary that represents this hotkey. For example, <c>ReloadPluginHotkey</c>,
|
||||||
|
/// which represents the string "Reload Plugins Data" in <c>en.xaml</c>
|
||||||
|
/// </param>
|
||||||
|
/// <param name="descriptionFormatVariables">
|
||||||
|
/// Array of values that will replace <c>{0}</c>, <c>{1}</c>, <c>{2}</c>, etc.
|
||||||
|
/// in the localized string found via <c>description</c>.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="removeHotkey">
|
||||||
|
/// An action that, when called, will unregister this hotkey. If it's <c>null</c>, it's assumed that this hotkey
|
||||||
|
/// can't be unregistered, and the "Overwrite" option will not appear in the hotkey dialog.
|
||||||
|
/// </param>
|
||||||
|
public RegisteredHotkeyData(
|
||||||
|
string hotkey, string descriptionResourceKey, object?[] descriptionFormatVariables, Action? removeHotkey = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Hotkey = new HotkeyModel(hotkey);
|
||||||
|
DescriptionResourceKey = descriptionResourceKey;
|
||||||
|
DescriptionFormatVariables = descriptionFormatVariables;
|
||||||
|
RemoveHotkey = removeHotkey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,13 +4,14 @@ using System.Collections.ObjectModel;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
{
|
{
|
||||||
public class Settings : BaseModel
|
public class Settings : BaseModel, IHotkeySettings
|
||||||
{
|
{
|
||||||
private string language = "en";
|
private string language = "en";
|
||||||
private string _theme = Constant.DefaultTheme;
|
private string _theme = Constant.DefaultTheme;
|
||||||
|
|
@ -20,6 +21,16 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
public bool ShowOpenResultHotkey { get; set; } = true;
|
public bool ShowOpenResultHotkey { get; set; } = true;
|
||||||
public double WindowSize { get; set; } = 580;
|
public double WindowSize { get; set; } = 580;
|
||||||
public string PreviewHotkey { get; set; } = $"F1";
|
public string PreviewHotkey { get; set; } = $"F1";
|
||||||
|
public string AutoCompleteHotkey { get; set; } = $"{KeyConstant.Ctrl} + Tab";
|
||||||
|
public string AutoCompleteHotkey2 { get; set; } = $"";
|
||||||
|
public string SelectNextItemHotkey { get; set; } = $"Tab";
|
||||||
|
public string SelectNextItemHotkey2 { get; set; } = $"";
|
||||||
|
public string SelectPrevItemHotkey { get; set; } = $"Shift + Tab";
|
||||||
|
public string SelectPrevItemHotkey2 { get; set; } = $"";
|
||||||
|
public string SelectNextPageHotkey { get; set; } = $"PageUp";
|
||||||
|
public string SelectPrevPageHotkey { get; set; } = $"PageDown";
|
||||||
|
public string OpenContextMenuHotkey { get; set; } = $"Ctrl+O";
|
||||||
|
public string SettingWindowHotkey { get; set; } = $"Ctrl+I";
|
||||||
|
|
||||||
public string Language
|
public string Language
|
||||||
{
|
{
|
||||||
|
|
@ -54,6 +65,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
public bool UseGlyphIcons { get; set; } = true;
|
public bool UseGlyphIcons { get; set; } = true;
|
||||||
public bool UseAnimation { get; set; } = true;
|
public bool UseAnimation { get; set; } = true;
|
||||||
public bool UseSound { get; set; } = true;
|
public bool UseSound { get; set; } = true;
|
||||||
|
public double SoundVolume { get; set; } = 50;
|
||||||
|
|
||||||
public bool UseClock { get; set; } = true;
|
public bool UseClock { get; set; } = true;
|
||||||
public bool UseDate { get; set; } = false;
|
public bool UseDate { get; set; } = false;
|
||||||
public string TimeFormat { get; set; } = "hh:mm tt";
|
public string TimeFormat { get; set; } = "hh:mm tt";
|
||||||
|
|
@ -195,17 +208,17 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
|
|
||||||
public double WindowLeft { get; set; }
|
public double WindowLeft { get; set; }
|
||||||
public double WindowTop { get; set; }
|
public double WindowTop { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom left position on selected monitor
|
/// Custom left position on selected monitor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double CustomWindowLeft { get; set; } = 0;
|
public double CustomWindowLeft { get; set; } = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Custom top position on selected monitor
|
/// Custom top position on selected monitor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double CustomWindowTop { get; set; } = 0;
|
public double CustomWindowTop { get; set; } = 0;
|
||||||
|
|
||||||
public int MaxResultsToShow { get; set; } = 5;
|
public int MaxResultsToShow { get; set; } = 5;
|
||||||
public int ActivateTimes { get; set; }
|
public int ActivateTimes { get; set; }
|
||||||
|
|
||||||
|
|
@ -217,7 +230,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
|
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new()
|
||||||
{
|
{
|
||||||
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
|
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText),
|
||||||
new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath)
|
new BuiltinShortcutModel("{active_explorer_path}", "shortcut_active_explorer_path", FileExplorerHelper.GetActiveExplorerPath)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -241,7 +254,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
|
|
||||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
public SearchWindowScreens SearchWindowScreen { get; set; } = SearchWindowScreens.Cursor;
|
public SearchWindowScreens SearchWindowScreen { get; set; } = SearchWindowScreens.Cursor;
|
||||||
|
|
||||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
public SearchWindowAligns SearchWindowAlign { get; set; } = SearchWindowAligns.Center;
|
public SearchWindowAligns SearchWindowAlign { get; set; } = SearchWindowAligns.Center;
|
||||||
|
|
||||||
|
|
@ -261,6 +274,82 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
|
|
||||||
// This needs to be loaded last by staying at the bottom
|
// This needs to be loaded last by staying at the bottom
|
||||||
public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
|
public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public List<RegisteredHotkeyData> RegisteredHotkeys
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var list = new List<RegisteredHotkeyData>
|
||||||
|
{
|
||||||
|
new("Up", "HotkeyLeftRightDesc"),
|
||||||
|
new("Down", "HotkeyLeftRightDesc"),
|
||||||
|
new("Left", "HotkeyUpDownDesc"),
|
||||||
|
new("Right", "HotkeyUpDownDesc"),
|
||||||
|
new("Escape", "HotkeyESCDesc"),
|
||||||
|
new("F5", "ReloadPluginHotkey"),
|
||||||
|
new("Alt+Home", "HotkeySelectFirstResult"),
|
||||||
|
new("Alt+End", "HotkeySelectLastResult"),
|
||||||
|
new("Ctrl+R", "HotkeyRequery"),
|
||||||
|
new("Ctrl+H", "ToggleHistoryHotkey"),
|
||||||
|
new("Ctrl+OemCloseBrackets", "QuickWidthHotkey"),
|
||||||
|
new("Ctrl+OemOpenBrackets", "QuickWidthHotkey"),
|
||||||
|
new("Ctrl+OemPlus", "QuickHeightHotkey"),
|
||||||
|
new("Ctrl+OemMinus", "QuickHeightHotkey"),
|
||||||
|
new("Ctrl+Shift+Enter", "HotkeyCtrlShiftEnterDesc"),
|
||||||
|
new("Shift+Enter", "OpenContextMenuHotkey"),
|
||||||
|
new("Enter", "HotkeyRunDesc"),
|
||||||
|
new("Ctrl+Enter", "OpenContainFolderHotkey"),
|
||||||
|
new("Alt+Enter", "HotkeyOpenResult"),
|
||||||
|
new("Ctrl+F12", "ToggleGameModeHotkey"),
|
||||||
|
new("Ctrl+Shift+C", "CopyFilePathHotkey"),
|
||||||
|
|
||||||
|
new($"{OpenResultModifiers}+D1", "HotkeyOpenResultN", 1),
|
||||||
|
new($"{OpenResultModifiers}+D2", "HotkeyOpenResultN", 2),
|
||||||
|
new($"{OpenResultModifiers}+D3", "HotkeyOpenResultN", 3),
|
||||||
|
new($"{OpenResultModifiers}+D4", "HotkeyOpenResultN", 4),
|
||||||
|
new($"{OpenResultModifiers}+D5", "HotkeyOpenResultN", 5),
|
||||||
|
new($"{OpenResultModifiers}+D6", "HotkeyOpenResultN", 6),
|
||||||
|
new($"{OpenResultModifiers}+D7", "HotkeyOpenResultN", 7),
|
||||||
|
new($"{OpenResultModifiers}+D8", "HotkeyOpenResultN", 8),
|
||||||
|
new($"{OpenResultModifiers}+D9", "HotkeyOpenResultN", 9),
|
||||||
|
new($"{OpenResultModifiers}+D0", "HotkeyOpenResultN", 10)
|
||||||
|
};
|
||||||
|
|
||||||
|
if(!string.IsNullOrEmpty(Hotkey))
|
||||||
|
list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(PreviewHotkey))
|
||||||
|
list.Add(new(PreviewHotkey, "previewHotkey", () => PreviewHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(AutoCompleteHotkey))
|
||||||
|
list.Add(new(AutoCompleteHotkey, "autoCompleteHotkey", () => AutoCompleteHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(AutoCompleteHotkey2))
|
||||||
|
list.Add(new(AutoCompleteHotkey2, "autoCompleteHotkey", () => AutoCompleteHotkey2 = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SelectNextItemHotkey))
|
||||||
|
list.Add(new(SelectNextItemHotkey, "SelectNextItemHotkey", () => SelectNextItemHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SelectNextItemHotkey2))
|
||||||
|
list.Add(new(SelectNextItemHotkey2, "SelectNextItemHotkey", () => SelectNextItemHotkey2 = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SelectPrevItemHotkey))
|
||||||
|
list.Add(new(SelectPrevItemHotkey, "SelectPrevItemHotkey", () => SelectPrevItemHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SelectPrevItemHotkey2))
|
||||||
|
list.Add(new(SelectPrevItemHotkey2, "SelectPrevItemHotkey", () => SelectPrevItemHotkey2 = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SettingWindowHotkey))
|
||||||
|
list.Add(new(SettingWindowHotkey, "SettingWindowHotkey", () => SettingWindowHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(OpenContextMenuHotkey))
|
||||||
|
list.Add(new(OpenContextMenuHotkey, "OpenContextMenuHotkey", () => OpenContextMenuHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SelectNextPageHotkey))
|
||||||
|
list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = ""));
|
||||||
|
if(!string.IsNullOrEmpty(SelectPrevPageHotkey))
|
||||||
|
list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = ""));
|
||||||
|
|
||||||
|
foreach (var customPluginHotkey in CustomPluginHotkeys)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(customPluginHotkey.Hotkey))
|
||||||
|
list.Add(new(customPluginHotkey.Hotkey, "customQueryHotkey", () => customPluginHotkey.Hotkey = ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum LastQueryMode
|
public enum LastQueryMode
|
||||||
|
|
@ -276,7 +365,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
Light,
|
Light,
|
||||||
Dark
|
Dark
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SearchWindowScreens
|
public enum SearchWindowScreens
|
||||||
{
|
{
|
||||||
RememberLastLaunchLocation,
|
RememberLastLaunchLocation,
|
||||||
|
|
@ -285,7 +374,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
Primary,
|
Primary,
|
||||||
Custom
|
Custom
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum SearchWindowAligns
|
public enum SearchWindowAligns
|
||||||
{
|
{
|
||||||
Center,
|
Center,
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,10 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>4.2.0</Version>
|
<Version>4.3.0</Version>
|
||||||
<PackageVersion>4.2.0</PackageVersion>
|
<PackageVersion>4.3.0</PackageVersion>
|
||||||
<AssemblyVersion>4.2.0</AssemblyVersion>
|
<AssemblyVersion>4.3.0</AssemblyVersion>
|
||||||
<FileVersion>4.2.0</FileVersion>
|
<FileVersion>4.3.0</FileVersion>
|
||||||
<PackageId>Flow.Launcher.Plugin</PackageId>
|
<PackageId>Flow.Launcher.Plugin</PackageId>
|
||||||
<Authors>Flow-Launcher</Authors>
|
<Authors>Flow-Launcher</Authors>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
|
|
|
||||||
|
|
@ -291,5 +291,12 @@ namespace Flow.Launcher.Plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public bool IsGameModeOn();
|
public bool IsGameModeOn();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reloads the query.
|
||||||
|
/// This method should run
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reselect">Choose the first result after reload if true; keep the last selected result if false. Default is true.</param>
|
||||||
|
public void ReQuery(bool reselect = true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,31 @@ namespace Flow.Launcher.Plugin
|
||||||
return Title + SubTitle + Score;
|
return Title + SubTitle + Score;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clones the current result
|
||||||
|
/// </summary>
|
||||||
|
public Result Clone()
|
||||||
|
{
|
||||||
|
return new Result
|
||||||
|
{
|
||||||
|
Title = Title,
|
||||||
|
SubTitle = SubTitle,
|
||||||
|
ActionKeywordAssigned = ActionKeywordAssigned,
|
||||||
|
CopyText = CopyText,
|
||||||
|
AutoCompleteText = AutoCompleteText,
|
||||||
|
IcoPath = IcoPath,
|
||||||
|
RoundedIcon = RoundedIcon,
|
||||||
|
Icon = Icon,
|
||||||
|
Glyph = Glyph,
|
||||||
|
Action = Action,
|
||||||
|
AsyncAction = AsyncAction,
|
||||||
|
Score = Score,
|
||||||
|
TitleHighlightData = TitleHighlightData,
|
||||||
|
OriginQuery = OriginQuery,
|
||||||
|
PluginDirectory = PluginDirectory
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Additional data associated with this result
|
/// Additional data associated with this result
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -3,39 +3,38 @@ using System.Globalization;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
{
|
|
||||||
internal class BoolToIMEConversionModeConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return value switch
|
|
||||||
{
|
|
||||||
true => ImeConversionModeValues.Alphanumeric,
|
|
||||||
_ => ImeConversionModeValues.DoNotCare
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
internal class BoolToIMEConversionModeConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return value switch
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
true => ImeConversionModeValues.Alphanumeric,
|
||||||
}
|
_ => ImeConversionModeValues.DoNotCare
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class BoolToIMEStateConverter : IValueConverter
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
throw new NotImplementedException();
|
||||||
{
|
}
|
||||||
return value switch
|
}
|
||||||
{
|
|
||||||
true => InputMethodState.Off,
|
internal class BoolToIMEStateConverter : IValueConverter
|
||||||
_ => InputMethodState.DoNotCare
|
{
|
||||||
};
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
}
|
{
|
||||||
|
return value switch
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
{
|
||||||
{
|
true => InputMethodState.Off,
|
||||||
throw new NotImplementedException();
|
_ => InputMethodState.DoNotCare
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,40 +2,39 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
public class BoolToVisibilityConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class BoolToVisibilityConverter : IValueConverter
|
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
|
return (value, parameter) switch
|
||||||
{
|
{
|
||||||
return (value, parameter) switch
|
(true, not null) => Visibility.Collapsed,
|
||||||
{
|
(_, not null) => Visibility.Visible,
|
||||||
(true, not null) => Visibility.Collapsed,
|
|
||||||
(_, not null) => Visibility.Visible,
|
|
||||||
|
|
||||||
(true, null) => Visibility.Visible,
|
(true, null) => Visibility.Visible,
|
||||||
(_, null) => Visibility.Collapsed
|
(_, null) => Visibility.Collapsed
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SplitterConverter : IValueConverter
|
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
|
||||||
/* Prevents the dragging part of the preview area from working when preview is turned off. */
|
}
|
||||||
{
|
|
||||||
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
|
public class SplitterConverter : IValueConverter
|
||||||
{
|
/* Prevents the dragging part of the preview area from working when preview is turned off. */
|
||||||
return (value, parameter) switch
|
{
|
||||||
{
|
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
|
||||||
(true, not null) => 0,
|
{
|
||||||
(_, not null) => 5,
|
return (value, parameter) switch
|
||||||
|
{
|
||||||
(true, null) => 5,
|
(true, not null) => 0,
|
||||||
(_, null) => 0
|
(_, not null) => 5,
|
||||||
};
|
|
||||||
}
|
(true, null) => 5,
|
||||||
|
(_, null) => 0
|
||||||
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,43 +7,41 @@ using System.Windows.Shapes;
|
||||||
|
|
||||||
// For Clipping inside listbox item
|
// For Clipping inside listbox item
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
public class BorderClipConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
public class BorderClipConverter : IMultiValueConverter
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
if (values is not [double width, double height, CornerRadius radius])
|
||||||
{
|
{
|
||||||
if (values is not [double width, double height, CornerRadius radius])
|
return DependencyProperty.UnsetValue;
|
||||||
{
|
|
||||||
return DependencyProperty.UnsetValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Path myPath = new Path();
|
|
||||||
if (width < Double.Epsilon || height < Double.Epsilon)
|
|
||||||
{
|
|
||||||
return Geometry.Empty;
|
|
||||||
}
|
|
||||||
var radiusHeight = radius.TopLeft;
|
|
||||||
|
|
||||||
// Drawing Round box for bottom round, and rect for top area of listbox.
|
|
||||||
var corner = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft);
|
|
||||||
var box = new RectangleGeometry(new Rect(0, 0, width, radiusHeight), 0, 0);
|
|
||||||
|
|
||||||
GeometryGroup myGeometryGroup = new GeometryGroup();
|
|
||||||
myGeometryGroup.Children.Add(corner);
|
|
||||||
myGeometryGroup.Children.Add(box);
|
|
||||||
|
|
||||||
CombinedGeometry c1 = new CombinedGeometry(GeometryCombineMode.Union, corner, box);
|
|
||||||
myPath.Data = c1;
|
|
||||||
|
|
||||||
myPath.Data.Freeze();
|
|
||||||
return myPath.Data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
Path myPath = new Path();
|
||||||
|
if (width < Double.Epsilon || height < Double.Epsilon)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
return Geometry.Empty;
|
||||||
}
|
}
|
||||||
|
var radiusHeight = radius.TopLeft;
|
||||||
|
|
||||||
|
// Drawing Round box for bottom round, and rect for top area of listbox.
|
||||||
|
var corner = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft);
|
||||||
|
var box = new RectangleGeometry(new Rect(0, 0, width, radiusHeight), 0, 0);
|
||||||
|
|
||||||
|
GeometryGroup myGeometryGroup = new GeometryGroup();
|
||||||
|
myGeometryGroup.Children.Add(corner);
|
||||||
|
myGeometryGroup.Children.Add(box);
|
||||||
|
|
||||||
|
CombinedGeometry c1 = new CombinedGeometry(GeometryCombineMode.Union, corner, box);
|
||||||
|
myPath.Data = c1;
|
||||||
|
|
||||||
|
myPath.Data.Freeze();
|
||||||
|
return myPath.Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,17 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
{
|
|
||||||
public class DateTimeFormatToNowConverter : IValueConverter
|
|
||||||
{
|
|
||||||
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
public class DateTimeFormatToNowConverter : IValueConverter
|
||||||
{
|
{
|
||||||
return value is not string format ? null : DateTime.Now.ToString(format);
|
|
||||||
}
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
{
|
||||||
{
|
return value is not string format ? null : DateTime.Now.ToString(format);
|
||||||
throw new NotImplementedException();
|
}
|
||||||
}
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,22 @@ using System.Globalization;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
public class DiameterToCenterPointConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class DiameterToCenterPointConverter : IValueConverter
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
if (value is double d)
|
||||||
{
|
{
|
||||||
if (value is double d)
|
return new Point(d / 2, d / 2);
|
||||||
{
|
|
||||||
return new Point(d / 2, d / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Point(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
return new Point(0, 0);
|
||||||
{
|
}
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,45 +5,44 @@ using System.Windows;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
public class HighlightTextConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
public class HighlightTextConverter : IMultiValueConverter
|
public object Convert(object[] value, Type targetType, object parameter, CultureInfo cultureInfo)
|
||||||
{
|
{
|
||||||
public object Convert(object[] value, Type targetType, object parameter, CultureInfo cultureInfo)
|
if (value.Length < 2)
|
||||||
{
|
return new Run(string.Empty);
|
||||||
if (value.Length < 2)
|
|
||||||
return new Run(string.Empty);
|
|
||||||
|
|
||||||
if (value[0] is not string text)
|
|
||||||
return new Run(string.Empty);
|
|
||||||
|
|
||||||
if (value[1] is not List<int> { Count: > 0 } highlightData)
|
|
||||||
// No highlight data, just return the text
|
|
||||||
return new Run(text);
|
|
||||||
|
|
||||||
var highlightStyle = (Style)Application.Current.FindResource("HighlightStyle");
|
|
||||||
var textBlock = new Span();
|
|
||||||
|
|
||||||
for (var i = 0; i < text.Length; i++)
|
if (value[0] is not string text)
|
||||||
|
return new Run(string.Empty);
|
||||||
|
|
||||||
|
if (value[1] is not List<int> { Count: > 0 } highlightData)
|
||||||
|
// No highlight data, just return the text
|
||||||
|
return new Run(text);
|
||||||
|
|
||||||
|
var highlightStyle = (Style)Application.Current.FindResource("HighlightStyle");
|
||||||
|
var textBlock = new Span();
|
||||||
|
|
||||||
|
for (var i = 0; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
var currentCharacter = text.Substring(i, 1);
|
||||||
|
var run = new Run(currentCharacter)
|
||||||
{
|
{
|
||||||
var currentCharacter = text.Substring(i, 1);
|
Style = ShouldHighlight(highlightData, i) ? highlightStyle : null
|
||||||
var run = new Run(currentCharacter)
|
};
|
||||||
{
|
textBlock.Inlines.Add(run);
|
||||||
Style = ShouldHighlight(highlightData, i) ? highlightStyle : null
|
|
||||||
};
|
|
||||||
textBlock.Inlines.Add(run);
|
|
||||||
}
|
|
||||||
return textBlock;
|
|
||||||
}
|
}
|
||||||
|
return textBlock;
|
||||||
|
}
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
|
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
return new[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
|
return new[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool ShouldHighlight(List<int> highlightData, int index)
|
private bool ShouldHighlight(List<int> highlightData, int index)
|
||||||
{
|
{
|
||||||
return highlightData.Contains(index);
|
return highlightData.Contains(index);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,19 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
{
|
|
||||||
public class IconRadiusConverter : IMultiValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (values is not [double size, bool isIconCircular])
|
|
||||||
throw new ArgumentException("IconRadiusConverter must have 2 parameters: [double, bool]");
|
|
||||||
|
|
||||||
return isIconCircular ? size / 2 : size;
|
public class IconRadiusConverter : IMultiValueConverter
|
||||||
}
|
{
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
if (values is not [double size, bool isIconCircular])
|
||||||
}
|
throw new ArgumentException("IconRadiusConverter must have 2 parameters: [double, bool]");
|
||||||
|
|
||||||
|
return isIconCircular ? size / 2 : size;
|
||||||
|
}
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,23 @@ using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||||
|
public class OpenResultHotkeyVisibilityConverter : IValueConverter
|
||||||
{
|
{
|
||||||
[ValueConversion(typeof(bool), typeof(Visibility))]
|
private const int MaxVisibleHotkeys = 10;
|
||||||
public class OpenResultHotkeyVisibilityConverter : IValueConverter
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
private const int MaxVisibleHotkeys = 10;
|
var number = int.MaxValue;
|
||||||
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
if (value is ListBoxItem listBoxItem
|
||||||
{
|
&& ItemsControl.ItemsControlFromItemContainer(listBoxItem) is ListBox listBox)
|
||||||
var number = int.MaxValue;
|
number = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
|
||||||
|
|
||||||
if (value is ListBoxItem listBoxItem
|
return number <= MaxVisibleHotkeys ? Visibility.Visible : Visibility.Collapsed;
|
||||||
&& ItemsControl.ItemsControlFromItemContainer(listBoxItem) is ListBox listBox)
|
|
||||||
number = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
|
|
||||||
|
|
||||||
return number <= MaxVisibleHotkeys ? Visibility.Visible : Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new InvalidOperationException();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,22 @@ using System.Globalization;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
public class OrdinalConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public class OrdinalConverter : IValueConverter
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
if (value is not ListBoxItem listBoxItem
|
||||||
|
|| ItemsControl.ItemsControlFromItemContainer(listBoxItem) is not ListBox listBox)
|
||||||
{
|
{
|
||||||
if (value is not ListBoxItem listBoxItem
|
return 0;
|
||||||
|| ItemsControl.ItemsControlFromItemContainer(listBoxItem) is not ListBox listBox)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var res = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
|
|
||||||
return res == 10 ? 0 : res; // 10th item => HOTKEY+0
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new InvalidOperationException();
|
var res = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
|
||||||
|
return res == 10 ? 0 : res; // 10th item => HOTKEY+0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,63 +6,62 @@ using System.Windows.Media;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
|
|
||||||
|
public class QuerySuggestionBoxConverter : IMultiValueConverter
|
||||||
{
|
{
|
||||||
public class QuerySuggestionBoxConverter : IMultiValueConverter
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
// values[0] is TextBox: The textbox displaying the autocomplete suggestion
|
||||||
|
// values[1] is ResultViewModel: Currently selected item in the list
|
||||||
|
// values[2] is string: Query text
|
||||||
|
if (
|
||||||
|
values.Length != 3 ||
|
||||||
|
values[0] is not TextBox queryTextBox ||
|
||||||
|
values[1] is null ||
|
||||||
|
values[2] is not string queryText ||
|
||||||
|
string.IsNullOrEmpty(queryText)
|
||||||
|
)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
if (values[1] is not ResultViewModel selectedItem)
|
||||||
|
return Binding.DoNothing;
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
// values[0] is TextBox: The textbox displaying the autocomplete suggestion
|
var selectedResult = selectedItem.Result;
|
||||||
// values[1] is ResultViewModel: Currently selected item in the list
|
var selectedResultActionKeyword = string.IsNullOrEmpty(selectedResult.ActionKeywordAssigned) ? "" : selectedResult.ActionKeywordAssigned + " ";
|
||||||
// values[2] is string: Query text
|
var selectedResultPossibleSuggestion = selectedResultActionKeyword + selectedResult.Title;
|
||||||
if (
|
|
||||||
values.Length != 3 ||
|
if (!selectedResultPossibleSuggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
|
||||||
values[0] is not TextBox queryTextBox ||
|
|
||||||
values[1] is null ||
|
|
||||||
values[2] is not string queryText ||
|
|
||||||
string.IsNullOrEmpty(queryText)
|
|
||||||
)
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
if (values[1] is not ResultViewModel selectedItem)
|
|
||||||
return Binding.DoNothing;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var selectedResult = selectedItem.Result;
|
|
||||||
var selectedResultActionKeyword = string.IsNullOrEmpty(selectedResult.ActionKeywordAssigned) ? "" : selectedResult.ActionKeywordAssigned + " ";
|
|
||||||
var selectedResultPossibleSuggestion = selectedResultActionKeyword + selectedResult.Title;
|
|
||||||
|
|
||||||
if (!selectedResultPossibleSuggestion.StartsWith(queryText, StringComparison.CurrentCultureIgnoreCase))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
|
|
||||||
// For AutocompleteQueryCommand.
|
// For AutocompleteQueryCommand.
|
||||||
// When user typed lower case and result title is uppercase, we still want to display suggestion
|
// When user typed lower case and result title is uppercase, we still want to display suggestion
|
||||||
selectedItem.QuerySuggestionText = queryText + selectedResultPossibleSuggestion.Substring(queryText.Length);
|
selectedItem.QuerySuggestionText = queryText + selectedResultPossibleSuggestion.Substring(queryText.Length);
|
||||||
|
|
||||||
// Check if Text will be larger than our QueryTextBox
|
// Check if Text will be larger than our QueryTextBox
|
||||||
Typeface typeface = new Typeface(queryTextBox.FontFamily, queryTextBox.FontStyle, queryTextBox.FontWeight, queryTextBox.FontStretch);
|
Typeface typeface = new Typeface(queryTextBox.FontFamily, queryTextBox.FontStyle, queryTextBox.FontWeight, queryTextBox.FontStretch);
|
||||||
// TODO: Obsolete warning?
|
// TODO: Obsolete warning?
|
||||||
var ft = new FormattedText(queryTextBox.Text, CultureInfo.DefaultThreadCurrentCulture, System.Windows.FlowDirection.LeftToRight, typeface, queryTextBox.FontSize, Brushes.Black);
|
var ft = new FormattedText(queryTextBox.Text, CultureInfo.DefaultThreadCurrentCulture, System.Windows.FlowDirection.LeftToRight, typeface, queryTextBox.FontSize, Brushes.Black);
|
||||||
|
|
||||||
var offset = queryTextBox.Padding.Right;
|
var offset = queryTextBox.Padding.Right;
|
||||||
|
|
||||||
if (ft.Width + offset > queryTextBox.ActualWidth || queryTextBox.HorizontalOffset != 0)
|
if (ft.Width + offset > queryTextBox.ActualWidth || queryTextBox.HorizontalOffset != 0)
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
return selectedItem.QuerySuggestionText;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Exception(nameof(QuerySuggestionBoxConverter), "fail to convert text for suggestion box", e);
|
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
|
||||||
|
return selectedItem.QuerySuggestionText;
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
Log.Exception(nameof(QuerySuggestionBoxConverter), "fail to convert text for suggestion box", e);
|
||||||
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,28 +3,27 @@ using System.Globalization;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
{
|
|
||||||
class StringToKeyBindingConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (parameter is not string mode || value is not string hotkeyStr)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var converter = new KeyGestureConverter();
|
|
||||||
var key = (KeyGesture)converter.ConvertFromString(hotkeyStr);
|
|
||||||
return mode switch
|
|
||||||
{
|
|
||||||
"key" => key?.Key,
|
|
||||||
"modifiers" => key?.Modifiers,
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
class StringToKeyBindingConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (parameter is not string mode || value is not string hotkeyStr)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var converter = new KeyGestureConverter();
|
||||||
|
var key = (KeyGesture)converter.ConvertFromString(hotkeyStr);
|
||||||
|
return mode switch
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
"key" => key?.Key,
|
||||||
}
|
"modifiers" => key?.Modifiers,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,28 +4,27 @@ using System.Windows.Data;
|
||||||
using Flow.Launcher.Core.Resource;
|
using Flow.Launcher.Core.Resource;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.Converters
|
namespace Flow.Launcher.Converters;
|
||||||
{
|
|
||||||
public class TextConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
var id = value?.ToString();
|
|
||||||
var translationKey = id switch
|
|
||||||
{
|
|
||||||
PluginStoreItemViewModel.NewRelease => "pluginStore_NewRelease",
|
|
||||||
PluginStoreItemViewModel.RecentlyUpdated => "pluginStore_RecentlyUpdated",
|
|
||||||
PluginStoreItemViewModel.None => "pluginStore_None",
|
|
||||||
PluginStoreItemViewModel.Installed => "pluginStore_Installed",
|
|
||||||
_ => null
|
|
||||||
};
|
|
||||||
|
|
||||||
if (translationKey is null)
|
|
||||||
return id;
|
|
||||||
|
|
||||||
return InternationalizationManager.Instance.GetTranslation(translationKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new InvalidOperationException();
|
public class TextConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
var id = value?.ToString();
|
||||||
|
var translationKey = id switch
|
||||||
|
{
|
||||||
|
PluginStoreItemViewModel.NewRelease => "pluginStore_NewRelease",
|
||||||
|
PluginStoreItemViewModel.RecentlyUpdated => "pluginStore_RecentlyUpdated",
|
||||||
|
PluginStoreItemViewModel.None => "pluginStore_None",
|
||||||
|
PluginStoreItemViewModel.Installed => "pluginStore_Installed",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (translationKey is null)
|
||||||
|
return id;
|
||||||
|
|
||||||
|
return InternationalizationManager.Instance.GetTranslation(translationKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@
|
||||||
x:Class="Flow.Launcher.CustomQueryHotkeySetting"
|
x:Class="Flow.Launcher.CustomQueryHotkeySetting"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
|
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
|
||||||
Title="{DynamicResource customeQueryHotkeyTitle}"
|
Title="{DynamicResource customeQueryHotkeyTitle}"
|
||||||
Width="530"
|
Width="530"
|
||||||
Background="{DynamicResource PopuBGColor}"
|
Background="{DynamicResource PopuBGColor}"
|
||||||
|
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||||
Foreground="{DynamicResource PopupTextColor}"
|
Foreground="{DynamicResource PopupTextColor}"
|
||||||
Icon="Images\app.png"
|
Icon="Images\app.png"
|
||||||
MouseDown="window_MouseDown"
|
MouseDown="window_MouseDown"
|
||||||
|
|
@ -60,94 +62,76 @@
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="26,0,26,0">
|
<StackPanel Margin="26,0,26,0">
|
||||||
<StackPanel Grid.Row="0" Margin="0,0,0,12">
|
<TextBlock
|
||||||
<TextBlock
|
Margin="0,0,0,12"
|
||||||
Grid.Column="0"
|
FontSize="20"
|
||||||
Margin="0,0,0,0"
|
FontWeight="SemiBold"
|
||||||
FontSize="20"
|
Text="{DynamicResource customeQueryHotkeyTitle}"
|
||||||
FontWeight="SemiBold"
|
TextAlignment="Left" />
|
||||||
Text="{DynamicResource customeQueryHotkeyTitle}"
|
<TextBlock
|
||||||
TextAlignment="Left" />
|
FontSize="14"
|
||||||
</StackPanel>
|
Text="{DynamicResource customeQueryHotkeyTips}"
|
||||||
<StackPanel>
|
TextAlignment="Left"
|
||||||
<TextBlock
|
TextWrapping="WrapWithOverflow" />
|
||||||
FontSize="14"
|
<Image
|
||||||
Text="{DynamicResource customeQueryHotkeyTips}"
|
Width="478"
|
||||||
TextAlignment="Left"
|
Margin="0,20,0,0"
|
||||||
TextWrapping="WrapWithOverflow" />
|
Source="/Images/illustration_01.png" />
|
||||||
<Image
|
|
||||||
Width="478"
|
|
||||||
Margin="0,20,0,0"
|
|
||||||
Source="/Images/illustration_01.png" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
|
<Grid Width="478" Margin="0,20,0,0">
|
||||||
<Grid Width="478">
|
<Grid.RowDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<RowDefinition />
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition />
|
</Grid.RowDefinitions>
|
||||||
</Grid.RowDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBlock
|
|
||||||
Grid.Row="0"
|
<TextBlock
|
||||||
Grid.Column="0"
|
Grid.Row="0"
|
||||||
Margin="10"
|
Grid.Column="0"
|
||||||
HorizontalAlignment="Left"
|
Margin="10"
|
||||||
VerticalAlignment="Center"
|
HorizontalAlignment="Left"
|
||||||
FontSize="14"
|
VerticalAlignment="Center"
|
||||||
Text="{DynamicResource hotkey}" />
|
FontSize="14"
|
||||||
<StackPanel
|
Text="{DynamicResource hotkey}" />
|
||||||
Grid.Row="0"
|
<flowlauncher:HotkeyControl
|
||||||
Grid.Column="1"
|
x:Name="HotkeyControl"
|
||||||
Orientation="Horizontal">
|
Grid.Row="0"
|
||||||
<flowlauncher:HotkeyControl
|
Grid.Column="1"
|
||||||
x:Name="ctlHotkey"
|
Grid.ColumnSpan="2"
|
||||||
Grid.Column="1"
|
Margin="10,0,10,0"
|
||||||
Width="200"
|
HorizontalAlignment="Left"
|
||||||
Height="36"
|
VerticalAlignment="Center"
|
||||||
Margin="10,0,10,0"
|
HorizontalContentAlignment="Left"
|
||||||
HorizontalAlignment="Left"
|
HotkeySettings="{Binding Settings}"
|
||||||
VerticalAlignment="Center"
|
DefaultHotkey="" />
|
||||||
HorizontalContentAlignment="Left" />
|
<TextBlock
|
||||||
<TextBlock
|
Grid.Row="1"
|
||||||
Grid.Row="1"
|
Grid.Column="0"
|
||||||
Grid.Column="0"
|
Margin="10"
|
||||||
Margin="10"
|
HorizontalAlignment="Left"
|
||||||
HorizontalAlignment="Left"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
FontSize="14"
|
||||||
FontSize="14"
|
Text="{DynamicResource customQuery}" />
|
||||||
Text="{DynamicResource actionKeyword}" />
|
<TextBox
|
||||||
</StackPanel>
|
x:Name="tbAction"
|
||||||
<TextBlock
|
Grid.Row="1"
|
||||||
Grid.Row="1"
|
Grid.Column="1"
|
||||||
Grid.Column="0"
|
Margin="10"
|
||||||
Margin="10"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalAlignment="Left"
|
VerticalAlignment="Center" />
|
||||||
VerticalAlignment="Center"
|
<Button
|
||||||
FontSize="14"
|
x:Name="btnTestActionKeyword"
|
||||||
Text="{DynamicResource customQuery}" />
|
Grid.Row="1"
|
||||||
<DockPanel
|
Grid.Column="2"
|
||||||
Grid.Row="1"
|
Margin="0,0,10,0"
|
||||||
Grid.Column="1"
|
Padding="10,5,10,5"
|
||||||
LastChildFill="True">
|
Click="BtnTestActionKeyword_OnClick"
|
||||||
<Button
|
Content="{DynamicResource preview}" />
|
||||||
x:Name="btnTestActionKeyword"
|
</Grid>
|
||||||
Margin="0,0,10,0"
|
|
||||||
Padding="10,5,10,5"
|
|
||||||
Click="BtnTestActionKeyword_OnClick"
|
|
||||||
Content="{DynamicResource preview}"
|
|
||||||
DockPanel.Dock="Right" />
|
|
||||||
<TextBox
|
|
||||||
x:Name="tbAction"
|
|
||||||
Margin="10"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Center" />
|
|
||||||
</DockPanel>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Border
|
<Border
|
||||||
|
|
@ -174,4 +158,4 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher
|
namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
|
|
@ -14,13 +15,13 @@ namespace Flow.Launcher
|
||||||
private SettingWindow _settingWidow;
|
private SettingWindow _settingWidow;
|
||||||
private bool update;
|
private bool update;
|
||||||
private CustomPluginHotkey updateCustomHotkey;
|
private CustomPluginHotkey updateCustomHotkey;
|
||||||
private Settings _settings;
|
public Settings Settings { get; }
|
||||||
|
|
||||||
public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings)
|
public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings)
|
||||||
{
|
{
|
||||||
_settingWidow = settingWidow;
|
_settingWidow = settingWidow;
|
||||||
|
Settings = settings;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_settings = settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -32,36 +33,21 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
if (!update)
|
if (!update)
|
||||||
{
|
{
|
||||||
if (!ctlHotkey.CurrentHotkeyAvailable)
|
Settings.CustomPluginHotkeys ??= new ObservableCollection<CustomPluginHotkey>();
|
||||||
{
|
|
||||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("hotkeyIsNotUnavailable"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_settings.CustomPluginHotkeys == null)
|
|
||||||
{
|
|
||||||
_settings.CustomPluginHotkeys = new ObservableCollection<CustomPluginHotkey>();
|
|
||||||
}
|
|
||||||
|
|
||||||
var pluginHotkey = new CustomPluginHotkey
|
var pluginHotkey = new CustomPluginHotkey
|
||||||
{
|
{
|
||||||
Hotkey = ctlHotkey.CurrentHotkey.ToString(),
|
Hotkey = HotkeyControl.CurrentHotkey.ToString(), ActionKeyword = tbAction.Text
|
||||||
ActionKeyword = tbAction.Text
|
|
||||||
};
|
};
|
||||||
_settings.CustomPluginHotkeys.Add(pluginHotkey);
|
Settings.CustomPluginHotkeys.Add(pluginHotkey);
|
||||||
|
|
||||||
HotKeyMapper.SetCustomQueryHotkey(pluginHotkey);
|
HotKeyMapper.SetCustomQueryHotkey(pluginHotkey);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (updateCustomHotkey.Hotkey != ctlHotkey.CurrentHotkey.ToString() && !ctlHotkey.CurrentHotkeyAvailable)
|
|
||||||
{
|
|
||||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("hotkeyIsNotUnavailable"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var oldHotkey = updateCustomHotkey.Hotkey;
|
var oldHotkey = updateCustomHotkey.Hotkey;
|
||||||
updateCustomHotkey.ActionKeyword = tbAction.Text;
|
updateCustomHotkey.ActionKeyword = tbAction.Text;
|
||||||
updateCustomHotkey.Hotkey = ctlHotkey.CurrentHotkey.ToString();
|
updateCustomHotkey.Hotkey = HotkeyControl.CurrentHotkey.ToString();
|
||||||
//remove origin hotkey
|
//remove origin hotkey
|
||||||
HotKeyMapper.RemoveHotkey(oldHotkey);
|
HotKeyMapper.RemoveHotkey(oldHotkey);
|
||||||
HotKeyMapper.SetCustomQueryHotkey(updateCustomHotkey);
|
HotKeyMapper.SetCustomQueryHotkey(updateCustomHotkey);
|
||||||
|
|
@ -70,9 +56,11 @@ namespace Flow.Launcher
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateItem(CustomPluginHotkey item)
|
public void UpdateItem(CustomPluginHotkey item)
|
||||||
{
|
{
|
||||||
updateCustomHotkey = _settings.CustomPluginHotkeys.FirstOrDefault(o => o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey);
|
updateCustomHotkey = Settings.CustomPluginHotkeys.FirstOrDefault(o =>
|
||||||
|
o.ActionKeyword == item.ActionKeyword && o.Hotkey == item.Hotkey);
|
||||||
if (updateCustomHotkey == null)
|
if (updateCustomHotkey == null)
|
||||||
{
|
{
|
||||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidPluginHotkey"));
|
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidPluginHotkey"));
|
||||||
|
|
@ -81,7 +69,7 @@ namespace Flow.Launcher
|
||||||
}
|
}
|
||||||
|
|
||||||
tbAction.Text = updateCustomHotkey.ActionKeyword;
|
tbAction.Text = updateCustomHotkey.ActionKeyword;
|
||||||
_ = ctlHotkey.SetHotkeyAsync(updateCustomHotkey.Hotkey, false);
|
HotkeyControl.SetHotkey(updateCustomHotkey.Hotkey, false);
|
||||||
update = true;
|
update = true;
|
||||||
lblAdd.Text = InternationalizationManager.Instance.GetTranslation("update");
|
lblAdd.Text = InternationalizationManager.Instance.GetTranslation("update");
|
||||||
}
|
}
|
||||||
|
|
@ -101,12 +89,10 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
|
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
|
||||||
{
|
{
|
||||||
TextBox textBox = Keyboard.FocusedElement as TextBox;
|
if (Keyboard.FocusedElement is not TextBox textBox) return;
|
||||||
if (textBox != null)
|
|
||||||
{
|
TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||||
TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
textBox.MoveFocus(tRequest);
|
||||||
textBox.MoveFocus(tRequest);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,57 +3,56 @@ using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
public class AutoStartup
|
||||||
{
|
{
|
||||||
public class AutoStartup
|
private const string StartupPath = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
|
||||||
|
|
||||||
|
public static bool IsEnabled
|
||||||
{
|
{
|
||||||
private const string StartupPath = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
|
get
|
||||||
|
|
||||||
public static bool IsEnabled
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
|
||||||
var path = key?.GetValue(Constant.FlowLauncher) as string;
|
|
||||||
return path == Constant.ExecutablePath;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Log.Error("AutoStartup", $"Ignoring non-critical registry error (querying if enabled): {e}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Disable()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||||
key?.DeleteValue(Constant.FlowLauncher, false);
|
var path = key?.GetValue(Constant.FlowLauncher) as string;
|
||||||
|
return path == Constant.ExecutablePath;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Log.Error("AutoStartup", $"Failed to disable auto-startup: {e}");
|
Log.Error("AutoStartup", $"Ignoring non-critical registry error (querying if enabled): {e}");
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Enable()
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Disable()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||||
{
|
key?.DeleteValue(Constant.FlowLauncher, false);
|
||||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
}
|
||||||
key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\"");
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
catch (Exception e)
|
Log.Error("AutoStartup", $"Failed to disable auto-startup: {e}");
|
||||||
{
|
throw;
|
||||||
Log.Error("AutoStartup", $"Failed to enable auto-startup: {e}");
|
}
|
||||||
throw;
|
}
|
||||||
}
|
|
||||||
|
internal static void Enable()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||||
|
key?.SetValue(Constant.FlowLauncher, $"\"{Constant.ExecutablePath}\"");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.Error("AutoStartup", $"Failed to enable auto-startup: {e}");
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,70 +4,69 @@ using System.Runtime.InteropServices;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
public class DwmDropShadow
|
||||||
{
|
{
|
||||||
public class DwmDropShadow
|
|
||||||
|
[DllImport("dwmapi.dll", PreserveSig = true)]
|
||||||
|
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
|
||||||
|
|
||||||
|
[DllImport("dwmapi.dll")]
|
||||||
|
private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Drops a standard shadow to a WPF Window, even if the window isborderless. Only works with DWM (Vista and Seven).
|
||||||
|
/// This method is much more efficient than setting AllowsTransparency to true and using the DropShadow effect,
|
||||||
|
/// as AllowsTransparency involves a huge permormance issue (hardware acceleration is turned off for all the window).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">Window to which the shadow will be applied</param>
|
||||||
|
public static void DropShadowToWindow(Window window)
|
||||||
{
|
{
|
||||||
|
if (!DropShadow(window))
|
||||||
[DllImport("dwmapi.dll", PreserveSig = true)]
|
|
||||||
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
|
|
||||||
|
|
||||||
[DllImport("dwmapi.dll")]
|
|
||||||
private static extern int DwmExtendFrameIntoClientArea(IntPtr hWnd, ref Margins pMarInset);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Drops a standard shadow to a WPF Window, even if the window isborderless. Only works with DWM (Vista and Seven).
|
|
||||||
/// This method is much more efficient than setting AllowsTransparency to true and using the DropShadow effect,
|
|
||||||
/// as AllowsTransparency involves a huge permormance issue (hardware acceleration is turned off for all the window).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">Window to which the shadow will be applied</param>
|
|
||||||
public static void DropShadowToWindow(Window window)
|
|
||||||
{
|
{
|
||||||
if (!DropShadow(window))
|
window.SourceInitialized += window_SourceInitialized;
|
||||||
{
|
|
||||||
window.SourceInitialized += window_SourceInitialized;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void window_SourceInitialized(object sender, EventArgs e) //fixed typo
|
private static void window_SourceInitialized(object sender, EventArgs e) //fixed typo
|
||||||
|
{
|
||||||
|
Window window = (Window)sender;
|
||||||
|
|
||||||
|
DropShadow(window);
|
||||||
|
|
||||||
|
window.SourceInitialized -= window_SourceInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The actual method that makes API calls to drop the shadow to the window
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">Window to which the shadow will be applied</param>
|
||||||
|
/// <returns>True if the method succeeded, false if not</returns>
|
||||||
|
private static bool DropShadow(Window window)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Window window = (Window)sender;
|
WindowInteropHelper helper = new WindowInteropHelper(window);
|
||||||
|
int val = 2;
|
||||||
|
int ret1 = DwmSetWindowAttribute(helper.Handle, 2, ref val, 4);
|
||||||
|
|
||||||
DropShadow(window);
|
if (ret1 == 0)
|
||||||
|
|
||||||
window.SourceInitialized -= window_SourceInitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The actual method that makes API calls to drop the shadow to the window
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">Window to which the shadow will be applied</param>
|
|
||||||
/// <returns>True if the method succeeded, false if not</returns>
|
|
||||||
private static bool DropShadow(Window window)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
WindowInteropHelper helper = new WindowInteropHelper(window);
|
Margins m = new Margins { Bottom = 0, Left = 0, Right = 0, Top = 0 };
|
||||||
int val = 2;
|
int ret2 = DwmExtendFrameIntoClientArea(helper.Handle, ref m);
|
||||||
int ret1 = DwmSetWindowAttribute(helper.Handle, 2, ref val, 4);
|
return ret2 == 0;
|
||||||
|
|
||||||
if (ret1 == 0)
|
|
||||||
{
|
|
||||||
Margins m = new Margins { Bottom = 0, Left = 0, Right = 0, Top = 0 };
|
|
||||||
int ret2 = DwmExtendFrameIntoClientArea(helper.Handle, ref m);
|
|
||||||
return ret2 == 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
else
|
||||||
{
|
{
|
||||||
// Probably dwmapi.dll not found (incompatible OS)
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// Probably dwmapi.dll not found (incompatible OS)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,68 +2,67 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
public class DataWebRequestFactory : IWebRequestCreate
|
||||||
{
|
{
|
||||||
public class DataWebRequestFactory : IWebRequestCreate
|
class DataWebRequest : WebRequest
|
||||||
{
|
{
|
||||||
class DataWebRequest : WebRequest
|
private readonly Uri _uri;
|
||||||
|
|
||||||
|
public DataWebRequest(Uri uri)
|
||||||
{
|
{
|
||||||
private readonly Uri m_uri;
|
_uri = uri;
|
||||||
|
|
||||||
public DataWebRequest(Uri uri)
|
|
||||||
{
|
|
||||||
m_uri = uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override WebResponse GetResponse()
|
|
||||||
{
|
|
||||||
return new DataWebResponse(m_uri);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DataWebResponse : WebResponse
|
public override WebResponse GetResponse()
|
||||||
{
|
{
|
||||||
private readonly string m_contentType;
|
return new DataWebResponse(_uri);
|
||||||
private readonly byte[] m_data;
|
|
||||||
|
|
||||||
public DataWebResponse(Uri uri)
|
|
||||||
{
|
|
||||||
string uriString = uri.AbsoluteUri;
|
|
||||||
|
|
||||||
int commaIndex = uriString.IndexOf(',');
|
|
||||||
var headers = uriString.Substring(0, commaIndex).Split(';');
|
|
||||||
m_contentType = headers[0];
|
|
||||||
string dataString = uriString.Substring(commaIndex + 1);
|
|
||||||
m_data = Convert.FromBase64String(dataString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ContentType
|
|
||||||
{
|
|
||||||
get { return m_contentType; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long ContentLength
|
|
||||||
{
|
|
||||||
get { return m_data.Length; }
|
|
||||||
set
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Stream GetResponseStream()
|
|
||||||
{
|
|
||||||
return new MemoryStream(m_data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebRequest Create(Uri uri)
|
|
||||||
{
|
|
||||||
return new DataWebRequest(uri);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DataWebResponse : WebResponse
|
||||||
|
{
|
||||||
|
private readonly string _contentType;
|
||||||
|
private readonly byte[] _data;
|
||||||
|
|
||||||
|
public DataWebResponse(Uri uri)
|
||||||
|
{
|
||||||
|
string uriString = uri.AbsoluteUri;
|
||||||
|
|
||||||
|
int commaIndex = uriString.IndexOf(',');
|
||||||
|
var headers = uriString.Substring(0, commaIndex).Split(';');
|
||||||
|
_contentType = headers[0];
|
||||||
|
string dataString = uriString.Substring(commaIndex + 1);
|
||||||
|
_data = Convert.FromBase64String(dataString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ContentType
|
||||||
|
{
|
||||||
|
get { return _contentType; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long ContentLength
|
||||||
|
{
|
||||||
|
get { return _data.Length; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Stream GetResponseStream()
|
||||||
|
{
|
||||||
|
return new MemoryStream(_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public WebRequest Create(Uri uri)
|
||||||
|
{
|
||||||
|
return new DataWebRequest(uri);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,45 +4,52 @@ using NLog;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Exception;
|
using Flow.Launcher.Infrastructure.Exception;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
public static class ErrorReporting
|
||||||
{
|
{
|
||||||
public static class ErrorReporting
|
private static void Report(Exception e)
|
||||||
{
|
{
|
||||||
private static void Report(Exception e)
|
var logger = LogManager.GetLogger("UnHandledException");
|
||||||
{
|
logger.Fatal(ExceptionFormatter.FormatExcpetion(e));
|
||||||
var logger = LogManager.GetLogger("UnHandledException");
|
var reportWindow = new ReportWindow(e);
|
||||||
logger.Fatal(ExceptionFormatter.FormatExcpetion(e));
|
reportWindow.Show();
|
||||||
var reportWindow = new ReportWindow(e);
|
}
|
||||||
reportWindow.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void UnhandledExceptionHandle(object sender, UnhandledExceptionEventArgs e)
|
public static void UnhandledExceptionHandle(object sender, UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
//handle non-ui thread exceptions
|
//handle non-ui thread exceptions
|
||||||
Report((Exception)e.ExceptionObject);
|
Report((Exception)e.ExceptionObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
public static void DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
//handle ui thread exceptions
|
//handle ui thread exceptions
|
||||||
Report(e.Exception);
|
Report(e.Exception);
|
||||||
//prevent application exist, so the user can copy prompted error info
|
//prevent application exist, so the user can copy prompted error info
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string RuntimeInfo()
|
|
||||||
{
|
|
||||||
var info = $"\nFlow Launcher version: {Constant.Version}" +
|
|
||||||
$"\nOS Version: {ExceptionFormatter.GetWindowsFullVersionFromRegistry()}" +
|
|
||||||
$"\nIntPtr Length: {IntPtr.Size}" +
|
|
||||||
$"\nx64: {Environment.Is64BitOperatingSystem}";
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string DependenciesInfo()
|
public static string RuntimeInfo()
|
||||||
{
|
{
|
||||||
var info = $"\nPython Path: {Constant.PythonPath}\nNode Path: {Constant.NodePath}";
|
var info =
|
||||||
return info;
|
$"""
|
||||||
}
|
|
||||||
|
Flow Launcher version: {Constant.Version}
|
||||||
|
OS Version: {ExceptionFormatter.GetWindowsFullVersionFromRegistry()}
|
||||||
|
IntPtr Length: {IntPtr.Size}
|
||||||
|
x64: {Environment.Is64BitOperatingSystem}
|
||||||
|
""";
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string DependenciesInfo()
|
||||||
|
{
|
||||||
|
var info = $"""
|
||||||
|
|
||||||
|
Python Path: {Constant.PythonPath}
|
||||||
|
Node Path: {Constant.NodePath}
|
||||||
|
""";
|
||||||
|
return info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,97 +7,96 @@ using Flow.Launcher.Core.Resource;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
internal static class HotKeyMapper
|
||||||
{
|
{
|
||||||
internal static class HotKeyMapper
|
private static Settings _settings;
|
||||||
|
private static MainViewModel _mainViewModel;
|
||||||
|
|
||||||
|
internal static void Initialize(MainViewModel mainVM)
|
||||||
{
|
{
|
||||||
private static Settings settings;
|
_mainViewModel = mainVM;
|
||||||
private static MainViewModel mainViewModel;
|
_settings = _mainViewModel.Settings;
|
||||||
|
|
||||||
internal static void Initialize(MainViewModel mainVM)
|
SetHotkey(_settings.Hotkey, OnToggleHotkey);
|
||||||
|
LoadCustomPluginHotkey();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnToggleHotkey(object sender, HotkeyEventArgs args)
|
||||||
|
{
|
||||||
|
if (!_mainViewModel.ShouldIgnoreHotkeys())
|
||||||
|
_mainViewModel.ToggleFlowLauncher();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
|
||||||
|
{
|
||||||
|
var hotkey = new HotkeyModel(hotkeyStr);
|
||||||
|
SetHotkey(hotkey, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
|
||||||
|
{
|
||||||
|
string hotkeyStr = hotkey.ToString();
|
||||||
|
try
|
||||||
{
|
{
|
||||||
mainViewModel = mainVM;
|
HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action);
|
||||||
settings = mainViewModel.Settings;
|
|
||||||
|
|
||||||
SetHotkey(settings.Hotkey, OnToggleHotkey);
|
|
||||||
LoadCustomPluginHotkey();
|
|
||||||
}
|
}
|
||||||
|
catch (Exception)
|
||||||
internal static void OnToggleHotkey(object sender, HotkeyEventArgs args)
|
|
||||||
{
|
{
|
||||||
if (!mainViewModel.ShouldIgnoreHotkeys())
|
string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
||||||
mainViewModel.ToggleFlowLauncher();
|
string errorMsgTitle = InternationalizationManager.Instance.GetTranslation("MessageBoxTitle");
|
||||||
}
|
MessageBox.Show(errorMsg,errorMsgTitle);
|
||||||
|
|
||||||
private static void SetHotkey(string hotkeyStr, EventHandler<HotkeyEventArgs> action)
|
|
||||||
{
|
|
||||||
var hotkey = new HotkeyModel(hotkeyStr);
|
|
||||||
SetHotkey(hotkey, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void SetHotkey(HotkeyModel hotkey, EventHandler<HotkeyEventArgs> action)
|
|
||||||
{
|
|
||||||
string hotkeyStr = hotkey.ToString();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
string errorMsg = string.Format(InternationalizationManager.Instance.GetTranslation("registerHotkeyFailed"), hotkeyStr);
|
|
||||||
string errorMsgTitle = InternationalizationManager.Instance.GetTranslation("MessageBoxTitle");
|
|
||||||
MessageBox.Show(errorMsg,errorMsgTitle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void RemoveHotkey(string hotkeyStr)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(hotkeyStr))
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.Remove(hotkeyStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void LoadCustomPluginHotkey()
|
|
||||||
{
|
|
||||||
if (settings.CustomPluginHotkeys == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (CustomPluginHotkey hotkey in settings.CustomPluginHotkeys)
|
|
||||||
{
|
|
||||||
SetCustomQueryHotkey(hotkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void SetCustomQueryHotkey(CustomPluginHotkey hotkey)
|
|
||||||
{
|
|
||||||
SetHotkey(hotkey.Hotkey, (s, e) =>
|
|
||||||
{
|
|
||||||
if (mainViewModel.ShouldIgnoreHotkeys())
|
|
||||||
return;
|
|
||||||
|
|
||||||
mainViewModel.Show();
|
|
||||||
mainViewModel.ChangeQueryText(hotkey.ActionKeyword, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool CheckAvailability(HotkeyModel currentHotkey)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.AddOrReplace("HotkeyAvailabilityTest", currentHotkey.CharKey, currentHotkey.ModifierKeys, (sender, e) => { });
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
HotkeyManager.Current.Remove("HotkeyAvailabilityTest");
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static void RemoveHotkey(string hotkeyStr)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(hotkeyStr))
|
||||||
|
{
|
||||||
|
HotkeyManager.Current.Remove(hotkeyStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void LoadCustomPluginHotkey()
|
||||||
|
{
|
||||||
|
if (_settings.CustomPluginHotkeys == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (CustomPluginHotkey hotkey in _settings.CustomPluginHotkeys)
|
||||||
|
{
|
||||||
|
SetCustomQueryHotkey(hotkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void SetCustomQueryHotkey(CustomPluginHotkey hotkey)
|
||||||
|
{
|
||||||
|
SetHotkey(hotkey.Hotkey, (s, e) =>
|
||||||
|
{
|
||||||
|
if (_mainViewModel.ShouldIgnoreHotkeys())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_mainViewModel.Show();
|
||||||
|
_mainViewModel.ChangeQueryText(hotkey.ActionKeyword, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool CheckAvailability(HotkeyModel currentHotkey)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HotkeyManager.Current.AddOrReplace("HotkeyAvailabilityTest", currentHotkey.CharKey, currentHotkey.ModifierKeys, (sender, e) => { });
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
HotkeyManager.Current.Remove("HotkeyAvailabilityTest");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,27 +2,26 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
{
|
|
||||||
public static class SingletonWindowOpener
|
|
||||||
{
|
|
||||||
public static T Open<T>(params object[] args) where T : Window
|
|
||||||
{
|
|
||||||
var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.GetType() == typeof(T))
|
|
||||||
?? (T)Activator.CreateInstance(typeof(T), args);
|
|
||||||
|
|
||||||
// Fix UI bug
|
|
||||||
// Add `window.WindowState = WindowState.Normal`
|
|
||||||
// If only use `window.Show()`, Settings-window doesn't show when minimized in taskbar
|
|
||||||
// Not sure why this works tho
|
|
||||||
// Probably because, when `.Show()` fails, `window.WindowState == Minimized` (not `Normal`)
|
|
||||||
// https://stackoverflow.com/a/59719760/4230390
|
|
||||||
window.WindowState = WindowState.Normal;
|
|
||||||
window.Show();
|
|
||||||
|
|
||||||
window.Focus();
|
|
||||||
|
|
||||||
return (T)window;
|
public static class SingletonWindowOpener
|
||||||
}
|
{
|
||||||
|
public static T Open<T>(params object[] args) where T : Window
|
||||||
|
{
|
||||||
|
var window = Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.GetType() == typeof(T))
|
||||||
|
?? (T)Activator.CreateInstance(typeof(T), args);
|
||||||
|
|
||||||
|
// Fix UI bug
|
||||||
|
// Add `window.WindowState = WindowState.Normal`
|
||||||
|
// If only use `window.Show()`, Settings-window doesn't show when minimized in taskbar
|
||||||
|
// Not sure why this works tho
|
||||||
|
// Probably because, when `.Show()` fails, `window.WindowState == Minimized` (not `Normal`)
|
||||||
|
// https://stackoverflow.com/a/59719760/4230390
|
||||||
|
window.WindowState = WindowState.Normal;
|
||||||
|
window.Show();
|
||||||
|
|
||||||
|
window.Focus();
|
||||||
|
|
||||||
|
return (T)window;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,23 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
{
|
|
||||||
public static class SyntaxSugars
|
|
||||||
{
|
|
||||||
public static TResult CallOrRescueDefault<TResult>(Func<TResult> callback)
|
|
||||||
{
|
|
||||||
return CallOrRescueDefault(callback, default(TResult));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TResult CallOrRescueDefault<TResult>(Func<TResult> callback, TResult def)
|
public static class SyntaxSugars
|
||||||
|
{
|
||||||
|
public static TResult CallOrRescueDefault<TResult>(Func<TResult> callback)
|
||||||
|
{
|
||||||
|
return CallOrRescueDefault(callback, default(TResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TResult CallOrRescueDefault<TResult>(Func<TResult> callback, TResult def)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
try
|
return callback();
|
||||||
{
|
}
|
||||||
return callback();
|
catch
|
||||||
}
|
{
|
||||||
catch
|
return def;
|
||||||
{
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,44 +5,43 @@ using System.Text;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
public static class WallpaperPathRetrieval
|
||||||
{
|
{
|
||||||
public static class WallpaperPathRetrieval
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
||||||
|
private static extern Int32 SystemParametersInfo(UInt32 action,
|
||||||
|
Int32 uParam, StringBuilder vParam, UInt32 winIni);
|
||||||
|
private static readonly UInt32 SPI_GETDESKWALLPAPER = 0x73;
|
||||||
|
private static int MAX_PATH = 260;
|
||||||
|
|
||||||
|
public static string GetWallpaperPath()
|
||||||
{
|
{
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
var wallpaper = new StringBuilder(MAX_PATH);
|
||||||
private static extern Int32 SystemParametersInfo(UInt32 action,
|
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0);
|
||||||
Int32 uParam, StringBuilder vParam, UInt32 winIni);
|
|
||||||
private static readonly UInt32 SPI_GETDESKWALLPAPER = 0x73;
|
|
||||||
private static int MAX_PATH = 260;
|
|
||||||
|
|
||||||
public static string GetWallpaperPath()
|
var str = wallpaper.ToString();
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Color GetWallpaperColor()
|
||||||
|
{
|
||||||
|
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", true);
|
||||||
|
var result = key?.GetValue("Background", null);
|
||||||
|
if (result is string strResult)
|
||||||
{
|
{
|
||||||
var wallpaper = new StringBuilder(MAX_PATH);
|
try
|
||||||
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0);
|
{
|
||||||
|
var parts = strResult.Trim().Split(new[] {' '}, 3).Select(byte.Parse).ToList();
|
||||||
var str = wallpaper.ToString();
|
return Color.FromRgb(parts[0], parts[1], parts[2]);
|
||||||
if (string.IsNullOrEmpty(str))
|
}
|
||||||
return null;
|
catch
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Color GetWallpaperColor()
|
|
||||||
{
|
|
||||||
RegistryKey key = Registry.CurrentUser.OpenSubKey("Control Panel\\Colors", true);
|
|
||||||
var result = key.GetValue(@"Background", null);
|
|
||||||
if (result != null && result is string)
|
|
||||||
{
|
{
|
||||||
try
|
|
||||||
{
|
|
||||||
var parts = result.ToString().Trim().Split(new[] {' '}, 3).Select(byte.Parse).ToList();
|
|
||||||
return Color.FromRgb(parts[0], parts[1], parts[2]);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return Colors.Transparent;
|
|
||||||
}
|
}
|
||||||
|
return Colors.Transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,156 +8,152 @@ using System.Windows.Interop;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Point = System.Windows.Point;
|
using Point = System.Windows.Point;
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
public class WindowsInteropHelper
|
||||||
{
|
{
|
||||||
public class WindowsInteropHelper
|
private const int GWL_STYLE = -16; //WPF's Message code for Title Bar's Style
|
||||||
|
private const int WS_SYSMENU = 0x80000; //WPF's Message code for System Menu
|
||||||
|
private static IntPtr _hwnd_shell;
|
||||||
|
private static IntPtr _hwnd_desktop;
|
||||||
|
|
||||||
|
//Accessors for shell and desktop handlers
|
||||||
|
//Will set the variables once and then will return them
|
||||||
|
private static IntPtr HWND_SHELL
|
||||||
{
|
{
|
||||||
private const int GWL_STYLE = -16; //WPF's Message code for Title Bar's Style
|
get
|
||||||
private const int WS_SYSMENU = 0x80000; //WPF's Message code for System Menu
|
|
||||||
private static IntPtr _hwnd_shell;
|
|
||||||
private static IntPtr _hwnd_desktop;
|
|
||||||
|
|
||||||
//Accessors for shell and desktop handlers
|
|
||||||
//Will set the variables once and then will return them
|
|
||||||
private static IntPtr HWND_SHELL
|
|
||||||
{
|
{
|
||||||
get
|
return _hwnd_shell != IntPtr.Zero ? _hwnd_shell : _hwnd_shell = GetShellWindow();
|
||||||
{
|
|
||||||
return _hwnd_shell != IntPtr.Zero ? _hwnd_shell : _hwnd_shell = GetShellWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private static IntPtr HWND_DESKTOP
|
}
|
||||||
|
private static IntPtr HWND_DESKTOP
|
||||||
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
get
|
return _hwnd_desktop != IntPtr.Zero ? _hwnd_desktop : _hwnd_desktop = GetDesktopWindow();
|
||||||
{
|
|
||||||
return _hwnd_desktop != IntPtr.Zero ? _hwnd_desktop : _hwnd_desktop = GetDesktopWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
internal static extern IntPtr GetForegroundWindow();
|
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
internal static extern IntPtr GetDesktopWindow();
|
internal static extern IntPtr GetForegroundWindow();
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
[DllImport("user32.dll")]
|
||||||
internal static extern IntPtr GetShellWindow();
|
internal static extern IntPtr GetDesktopWindow();
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
[DllImport("user32.dll")]
|
||||||
internal static extern int GetWindowRect(IntPtr hwnd, out RECT rc);
|
internal static extern IntPtr GetShellWindow();
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
internal static extern int GetWindowRect(IntPtr hwnd, out RECT rc);
|
||||||
|
|
||||||
[DllImport("user32.DLL")]
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||||
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||||
|
|
||||||
|
[DllImport("user32.DLL")]
|
||||||
|
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
||||||
|
|
||||||
|
|
||||||
const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
|
const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
|
||||||
const string WINDOW_CLASS_WINTAB = "Flip3D";
|
const string WINDOW_CLASS_WINTAB = "Flip3D";
|
||||||
const string WINDOW_CLASS_PROGMAN = "Progman";
|
const string WINDOW_CLASS_PROGMAN = "Progman";
|
||||||
const string WINDOW_CLASS_WORKERW = "WorkerW";
|
const string WINDOW_CLASS_WORKERW = "WorkerW";
|
||||||
|
|
||||||
public static bool IsWindowFullscreen()
|
public static bool IsWindowFullscreen()
|
||||||
|
{
|
||||||
|
//get current active window
|
||||||
|
IntPtr hWnd = GetForegroundWindow();
|
||||||
|
|
||||||
|
if (hWnd.Equals(IntPtr.Zero))
|
||||||
{
|
{
|
||||||
//get current active window
|
|
||||||
IntPtr hWnd = GetForegroundWindow();
|
|
||||||
|
|
||||||
if (!hWnd.Equals(IntPtr.Zero))
|
|
||||||
{
|
|
||||||
//if current active window is NOT desktop or shell
|
|
||||||
if (!(hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL)))
|
|
||||||
{
|
|
||||||
StringBuilder sb = new StringBuilder(256);
|
|
||||||
GetClassName(hWnd, sb, sb.Capacity);
|
|
||||||
string windowClass = sb.ToString();
|
|
||||||
|
|
||||||
//for Win+Tab (Flip3D)
|
|
||||||
if (windowClass == WINDOW_CLASS_WINTAB)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RECT appBounds;
|
|
||||||
GetWindowRect(hWnd, out appBounds);
|
|
||||||
|
|
||||||
//for console (ConsoleWindowClass), we have to check for negative dimensions
|
|
||||||
if (windowClass == WINDOW_CLASS_CONSOLE)
|
|
||||||
{
|
|
||||||
return appBounds.Top < 0 && appBounds.Bottom < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//for desktop (Progman or WorkerW, depends on the system), we have to check
|
|
||||||
if (windowClass == WINDOW_CLASS_PROGMAN || windowClass == WINDOW_CLASS_WORKERW)
|
|
||||||
{
|
|
||||||
IntPtr hWndDesktop = FindWindowEx(hWnd, IntPtr.Zero, "SHELLDLL_DefView", null);
|
|
||||||
hWndDesktop = FindWindowEx(hWndDesktop, IntPtr.Zero, "SysListView32", "FolderView");
|
|
||||||
if (!hWndDesktop.Equals(IntPtr.Zero))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
|
|
||||||
if ((appBounds.Bottom - appBounds.Top) == screenBounds.Height && (appBounds.Right - appBounds.Left) == screenBounds.Width)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
//if current active window is desktop or shell, exit early
|
||||||
/// disable windows toolbar's control box
|
if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
|
||||||
/// this will also disable system menu with Alt+Space hotkey
|
|
||||||
/// </summary>
|
|
||||||
public static void DisableControlBox(Window win)
|
|
||||||
{
|
{
|
||||||
var hwnd = new WindowInteropHelper(win).Handle;
|
return false;
|
||||||
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
StringBuilder sb = new StringBuilder(256);
|
||||||
/// Transforms pixels to Device Independent Pixels used by WPF
|
GetClassName(hWnd, sb, sb.Capacity);
|
||||||
/// </summary>
|
string windowClass = sb.ToString();
|
||||||
/// <param name="visual">current window, required to get presentation source</param>
|
|
||||||
/// <param name="unitX">horizontal position in pixels</param>
|
//for Win+Tab (Flip3D)
|
||||||
/// <param name="unitY">vertical position in pixels</param>
|
if (windowClass == WINDOW_CLASS_WINTAB)
|
||||||
/// <returns>point containing device independent pixels</returns>
|
|
||||||
public static Point TransformPixelsToDIP(Visual visual, double unitX, double unitY)
|
|
||||||
{
|
{
|
||||||
Matrix matrix;
|
return false;
|
||||||
var source = PresentationSource.FromVisual(visual);
|
}
|
||||||
if (source != null)
|
|
||||||
|
RECT appBounds;
|
||||||
|
GetWindowRect(hWnd, out appBounds);
|
||||||
|
|
||||||
|
//for console (ConsoleWindowClass), we have to check for negative dimensions
|
||||||
|
if (windowClass == WINDOW_CLASS_CONSOLE)
|
||||||
|
{
|
||||||
|
return appBounds.Top < 0 && appBounds.Bottom < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//for desktop (Progman or WorkerW, depends on the system), we have to check
|
||||||
|
if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
|
||||||
|
{
|
||||||
|
IntPtr hWndDesktop = FindWindowEx(hWnd, IntPtr.Zero, "SHELLDLL_DefView", null);
|
||||||
|
hWndDesktop = FindWindowEx(hWndDesktop, IntPtr.Zero, "SysListView32", "FolderView");
|
||||||
|
if (!hWndDesktop.Equals(IntPtr.Zero))
|
||||||
{
|
{
|
||||||
matrix = source.CompositionTarget.TransformFromDevice;
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
using (var src = new HwndSource(new HwndSourceParameters()))
|
|
||||||
{
|
|
||||||
matrix = src.CompositionTarget.TransformFromDevice;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
|
||||||
|
return (appBounds.Bottom - appBounds.Top) == screenBounds.Height && (appBounds.Right - appBounds.Left) == screenBounds.Width;
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
/// <summary>
|
||||||
public struct RECT
|
/// disable windows toolbar's control box
|
||||||
|
/// this will also disable system menu with Alt+Space hotkey
|
||||||
|
/// </summary>
|
||||||
|
public static void DisableControlBox(Window win)
|
||||||
|
{
|
||||||
|
var hwnd = new WindowInteropHelper(win).Handle;
|
||||||
|
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transforms pixels to Device Independent Pixels used by WPF
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="visual">current window, required to get presentation source</param>
|
||||||
|
/// <param name="unitX">horizontal position in pixels</param>
|
||||||
|
/// <param name="unitY">vertical position in pixels</param>
|
||||||
|
/// <returns>point containing device independent pixels</returns>
|
||||||
|
public static Point TransformPixelsToDIP(Visual visual, double unitX, double unitY)
|
||||||
|
{
|
||||||
|
Matrix matrix;
|
||||||
|
var source = PresentationSource.FromVisual(visual);
|
||||||
|
if (source is not null)
|
||||||
{
|
{
|
||||||
public int Left;
|
matrix = source.CompositionTarget.TransformFromDevice;
|
||||||
public int Top;
|
|
||||||
public int Right;
|
|
||||||
public int Bottom;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using var src = new HwndSource(new HwndSourceParameters());
|
||||||
|
matrix = src.CompositionTarget.TransformFromDevice;
|
||||||
|
}
|
||||||
|
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct RECT
|
||||||
|
{
|
||||||
|
public int Left;
|
||||||
|
public int Top;
|
||||||
|
public int Right;
|
||||||
|
public int Bottom;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,54 +3,75 @@
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:input="clr-namespace:System.Windows.Input;assembly=PresentationCore"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
Height="24"
|
|
||||||
d:DesignHeight="300"
|
|
||||||
d:DesignWidth="300"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid>
|
<Button
|
||||||
<Grid.ColumnDefinitions>
|
Width="Auto"
|
||||||
<ColumnDefinition Width="200" />
|
FontSize="13"
|
||||||
</Grid.ColumnDefinitions>
|
FontWeight="Bold"
|
||||||
<Popup
|
Foreground="{DynamicResource Color01B}"
|
||||||
x:Name="popup"
|
Click="GetNewHotkey">
|
||||||
AllowDrop="True"
|
<Button.Template>
|
||||||
AllowsTransparency="True"
|
<ControlTemplate TargetType="Button">
|
||||||
IsOpen="{Binding IsKeyboardFocused, ElementName=tbHotkey, Mode=OneWay}"
|
<Border
|
||||||
Placement="Top"
|
x:Name="ButtonBorder"
|
||||||
PlacementTarget="{Binding ElementName=tbHotkey}"
|
Padding="5,0,5,0"
|
||||||
PopupAnimation="Fade"
|
Background="{DynamicResource ButtonBackgroundColor}"
|
||||||
StaysOpen="True"
|
BorderBrush="{DynamicResource ButtonInsideBorder}"
|
||||||
VerticalOffset="-5">
|
BorderThickness="1"
|
||||||
<Border
|
CornerRadius="5">
|
||||||
Width="140"
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
Height="30"
|
</Border>
|
||||||
Background="{DynamicResource Color01B}"
|
<ControlTemplate.Triggers>
|
||||||
BorderBrush="{DynamicResource Color21B}"
|
<MultiTrigger>
|
||||||
BorderThickness="1"
|
<MultiTrigger.Conditions>
|
||||||
CornerRadius="4">
|
<Condition Property="IsMouseOver" Value="True" />
|
||||||
<TextBlock
|
<Condition Property="IsPressed" Value="True" />
|
||||||
x:Name="tbMsg"
|
</MultiTrigger.Conditions>
|
||||||
Margin="0,0,0,0"
|
<Setter TargetName="ButtonBorder" Property="Background"
|
||||||
HorizontalAlignment="Center"
|
Value="{DynamicResource ButtonMousePressed}" />
|
||||||
VerticalAlignment="Center"
|
<Setter TargetName="ButtonBorder" Property="BorderBrush"
|
||||||
FontSize="13"
|
Value="{DynamicResource ButtonMousePressedInsideBorder}" />
|
||||||
FontWeight="SemiBold"
|
</MultiTrigger>
|
||||||
Foreground="{DynamicResource Color05B}"
|
<MultiTrigger>
|
||||||
Text="{DynamicResource flowlauncherPressHotkey}"
|
<MultiTrigger.Conditions>
|
||||||
Visibility="Visible" />
|
<Condition Property="IsMouseOver" Value="True" />
|
||||||
</Border>
|
</MultiTrigger.Conditions>
|
||||||
</Popup>
|
<Setter TargetName="ButtonBorder" Property="Background"
|
||||||
|
Value="{DynamicResource ButtonMouseOver}" />
|
||||||
<TextBox
|
</MultiTrigger>
|
||||||
x:Name="tbHotkey"
|
<MultiTrigger>
|
||||||
Margin="0,0,18,0"
|
<MultiTrigger.Conditions>
|
||||||
VerticalContentAlignment="Center"
|
<Condition Property="IsPressed" Value="True" />
|
||||||
input:InputMethod.IsInputMethodEnabled="False"
|
</MultiTrigger.Conditions>
|
||||||
GotFocus="tbHotkey_GotFocus"
|
<Setter TargetName="ButtonBorder" Property="Background"
|
||||||
LostFocus="tbHotkey_LostFocus"
|
Value="{DynamicResource ButtonMousePressed}" />
|
||||||
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
|
<Setter TargetName="ButtonBorder" Property="BorderBrush"
|
||||||
TabIndex="100" />
|
Value="{DynamicResource CustomContextHover}" />
|
||||||
</Grid>
|
</MultiTrigger>
|
||||||
</UserControl>
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Button.Template>
|
||||||
|
<Button.Content>
|
||||||
|
<ItemsControl x:Name="HotkeyList">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border
|
||||||
|
Margin="2,5,2,5"
|
||||||
|
Padding="10,5,10,5"
|
||||||
|
Background="{DynamicResource AccentButtonBackground}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="5">
|
||||||
|
<TextBlock Text="{Binding}" />
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Button.Content>
|
||||||
|
</Button>
|
||||||
|
</UserControl>
|
||||||
|
|
|
||||||
|
|
@ -1,141 +1,204 @@
|
||||||
using System;
|
#nullable enable
|
||||||
|
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
|
||||||
using Flow.Launcher.Core.Resource;
|
using Flow.Launcher.Core.Resource;
|
||||||
using Flow.Launcher.Helper;
|
using Flow.Launcher.Helper;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
using Flow.Launcher.Plugin;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Flow.Launcher
|
namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
public partial class HotkeyControl : UserControl
|
public partial class HotkeyControl
|
||||||
{
|
{
|
||||||
public HotkeyModel CurrentHotkey { get; private set; }
|
public IHotkeySettings HotkeySettings {
|
||||||
public bool CurrentHotkeyAvailable { get; private set; }
|
get { return (IHotkeySettings)GetValue(HotkeySettingsProperty); }
|
||||||
|
set { SetValue(HotkeySettingsProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
public event EventHandler HotkeyChanged;
|
public static readonly DependencyProperty HotkeySettingsProperty = DependencyProperty.Register(
|
||||||
|
nameof(HotkeySettings),
|
||||||
|
typeof(IHotkeySettings),
|
||||||
|
typeof(HotkeyControl),
|
||||||
|
new PropertyMetadata()
|
||||||
|
);
|
||||||
|
public string WindowTitle {
|
||||||
|
get { return (string)GetValue(WindowTitleProperty); }
|
||||||
|
set { SetValue(WindowTitleProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty WindowTitleProperty = DependencyProperty.Register(
|
||||||
|
nameof(WindowTitle),
|
||||||
|
typeof(string),
|
||||||
|
typeof(HotkeyControl),
|
||||||
|
new PropertyMetadata(string.Empty)
|
||||||
|
);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Designed for Preview Hotkey and KeyGesture.
|
/// Designed for Preview Hotkey and KeyGesture.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ValidateKeyGesture { get; set; } = false;
|
public static readonly DependencyProperty ValidateKeyGestureProperty = DependencyProperty.Register(
|
||||||
|
nameof(ValidateKeyGesture),
|
||||||
|
typeof(bool),
|
||||||
|
typeof(HotkeyControl),
|
||||||
|
new PropertyMetadata(default(bool))
|
||||||
|
);
|
||||||
|
|
||||||
protected virtual void OnHotkeyChanged() => HotkeyChanged?.Invoke(this, EventArgs.Empty);
|
public bool ValidateKeyGesture
|
||||||
|
|
||||||
public HotkeyControl()
|
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
get { return (bool)GetValue(ValidateKeyGestureProperty); }
|
||||||
|
set { SetValue(ValidateKeyGestureProperty, value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private CancellationTokenSource hotkeyUpdateSource;
|
public static readonly DependencyProperty DefaultHotkeyProperty = DependencyProperty.Register(
|
||||||
|
nameof(DefaultHotkey),
|
||||||
|
typeof(string),
|
||||||
|
typeof(HotkeyControl),
|
||||||
|
new PropertyMetadata(default(string))
|
||||||
|
);
|
||||||
|
|
||||||
private void TbHotkey_OnPreviewKeyDown(object sender, KeyEventArgs e)
|
public string DefaultHotkey
|
||||||
{
|
{
|
||||||
hotkeyUpdateSource?.Cancel();
|
get { return (string)GetValue(DefaultHotkeyProperty); }
|
||||||
hotkeyUpdateSource?.Dispose();
|
set { SetValue(DefaultHotkeyProperty, value); }
|
||||||
hotkeyUpdateSource = new();
|
}
|
||||||
var token = hotkeyUpdateSource.Token;
|
|
||||||
e.Handled = true;
|
|
||||||
|
|
||||||
//when alt is pressed, the real key should be e.SystemKey
|
private static void OnHotkeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
|
{
|
||||||
|
if (d is not HotkeyControl hotkeyControl)
|
||||||
SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
|
|
||||||
|
|
||||||
var hotkeyModel = new HotkeyModel(
|
|
||||||
specialKeyState.AltPressed,
|
|
||||||
specialKeyState.ShiftPressed,
|
|
||||||
specialKeyState.WinPressed,
|
|
||||||
specialKeyState.CtrlPressed,
|
|
||||||
key);
|
|
||||||
|
|
||||||
if (hotkeyModel.Equals(CurrentHotkey))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = Dispatcher.InvokeAsync(async () =>
|
hotkeyControl.SetKeysToDisplay(new HotkeyModel(hotkeyControl.Hotkey));
|
||||||
{
|
hotkeyControl.CurrentHotkey = new HotkeyModel(hotkeyControl.Hotkey);
|
||||||
await Task.Delay(500, token);
|
|
||||||
if (!token.IsCancellationRequested)
|
|
||||||
await SetHotkeyAsync(hotkeyModel);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SetHotkeyAsync(HotkeyModel keyModel, bool triggerValidate = true)
|
|
||||||
{
|
|
||||||
tbHotkey.Text = keyModel.ToString();
|
|
||||||
tbHotkey.Select(tbHotkey.Text.Length, 0);
|
|
||||||
|
|
||||||
|
public static readonly DependencyProperty ChangeHotkeyProperty = DependencyProperty.Register(
|
||||||
|
nameof(ChangeHotkey),
|
||||||
|
typeof(ICommand),
|
||||||
|
typeof(HotkeyControl),
|
||||||
|
new PropertyMetadata(default(ICommand))
|
||||||
|
);
|
||||||
|
|
||||||
|
public ICommand? ChangeHotkey
|
||||||
|
{
|
||||||
|
get { return (ICommand)GetValue(ChangeHotkeyProperty); }
|
||||||
|
set { SetValue(ChangeHotkeyProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static readonly DependencyProperty HotkeyProperty = DependencyProperty.Register(
|
||||||
|
nameof(Hotkey),
|
||||||
|
typeof(string),
|
||||||
|
typeof(HotkeyControl),
|
||||||
|
new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnHotkeyChanged)
|
||||||
|
);
|
||||||
|
|
||||||
|
public string Hotkey
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(HotkeyProperty); }
|
||||||
|
set { SetValue(HotkeyProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeyControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
HotkeyList.ItemsSource = KeysToDisplay;
|
||||||
|
SetKeysToDisplay(CurrentHotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
|
||||||
|
hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
|
||||||
|
|
||||||
|
public string EmptyHotkey => InternationalizationManager.Instance.GetTranslation("none");
|
||||||
|
|
||||||
|
public ObservableCollection<string> KeysToDisplay { get; set; } = new();
|
||||||
|
|
||||||
|
public HotkeyModel CurrentHotkey { get; private set; } = new(false, false, false, false, Key.None);
|
||||||
|
|
||||||
|
|
||||||
|
public void GetNewHotkey(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
OpenHotkeyDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenHotkeyDialog()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(Hotkey))
|
||||||
|
{
|
||||||
|
HotKeyMapper.RemoveHotkey(Hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dialog = new HotkeyControlDialog(Hotkey, DefaultHotkey, HotkeySettings, WindowTitle);
|
||||||
|
await dialog.ShowAsync();
|
||||||
|
switch (dialog.ResultType)
|
||||||
|
{
|
||||||
|
case HotkeyControlDialog.EResultType.Cancel:
|
||||||
|
SetHotkey(Hotkey);
|
||||||
|
return;
|
||||||
|
case HotkeyControlDialog.EResultType.Save:
|
||||||
|
SetHotkey(dialog.ResultValue);
|
||||||
|
break;
|
||||||
|
case HotkeyControlDialog.EResultType.Delete:
|
||||||
|
Delete();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void SetHotkey(HotkeyModel keyModel, bool triggerValidate = true)
|
||||||
|
{
|
||||||
if (triggerValidate)
|
if (triggerValidate)
|
||||||
{
|
{
|
||||||
bool hotkeyAvailable = CheckHotkeyAvailability(keyModel, ValidateKeyGesture);
|
bool hotkeyAvailable = CheckHotkeyAvailability(keyModel, ValidateKeyGesture);
|
||||||
CurrentHotkeyAvailable = hotkeyAvailable;
|
|
||||||
SetMessage(hotkeyAvailable);
|
|
||||||
OnHotkeyChanged();
|
|
||||||
|
|
||||||
var token = hotkeyUpdateSource.Token;
|
if (!hotkeyAvailable)
|
||||||
await Task.Delay(500, token);
|
|
||||||
if (token.IsCancellationRequested)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (CurrentHotkeyAvailable)
|
|
||||||
{
|
{
|
||||||
CurrentHotkey = keyModel;
|
return;
|
||||||
// To trigger LostFocus
|
|
||||||
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null);
|
|
||||||
Keyboard.ClearFocus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hotkey = keyModel.ToString();
|
||||||
|
SetKeysToDisplay(CurrentHotkey);
|
||||||
|
ChangeHotkey?.Execute(keyModel);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CurrentHotkey = keyModel;
|
Hotkey = keyModel.ToString();
|
||||||
|
ChangeHotkey?.Execute(keyModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SetHotkeyAsync(string keyStr, bool triggerValidate = true)
|
public void Delete()
|
||||||
{
|
{
|
||||||
return SetHotkeyAsync(new HotkeyModel(keyStr), triggerValidate);
|
if (!string.IsNullOrEmpty(Hotkey))
|
||||||
|
HotKeyMapper.RemoveHotkey(Hotkey);
|
||||||
|
Hotkey = "";
|
||||||
|
SetKeysToDisplay(new HotkeyModel(false, false, false, false, Key.None));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) => hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
|
private void SetKeysToDisplay(HotkeyModel? hotkey)
|
||||||
|
|
||||||
public new bool IsFocused => tbHotkey.IsFocused;
|
|
||||||
|
|
||||||
private void tbHotkey_LostFocus(object sender, RoutedEventArgs e)
|
|
||||||
{
|
{
|
||||||
tbHotkey.Text = CurrentHotkey?.ToString() ?? "";
|
KeysToDisplay.Clear();
|
||||||
tbHotkey.Select(tbHotkey.Text.Length, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tbHotkey_GotFocus(object sender, RoutedEventArgs e)
|
if (hotkey == null || hotkey == default(HotkeyModel))
|
||||||
{
|
|
||||||
ResetMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ResetMessage()
|
|
||||||
{
|
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("flowlauncherPressHotkey");
|
|
||||||
tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetMessage(bool hotkeyAvailable)
|
|
||||||
{
|
|
||||||
if (!hotkeyAvailable)
|
|
||||||
{
|
{
|
||||||
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
|
KeysToDisplay.Add(EmptyHotkey);
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
foreach (var key in hotkey.Value.EnumerateDisplayKeys()!)
|
||||||
{
|
{
|
||||||
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
|
KeysToDisplay.Add(key);
|
||||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
|
|
||||||
}
|
}
|
||||||
tbMsg.Visibility = Visibility.Visible;
|
}
|
||||||
|
|
||||||
|
public void SetHotkey(string? keyStr, bool triggerValidate = true)
|
||||||
|
{
|
||||||
|
SetHotkey(new HotkeyModel(keyStr), triggerValidate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
169
Flow.Launcher/HotkeyControlDialog.xaml
Normal file
169
Flow.Launcher/HotkeyControlDialog.xaml
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
<ui:ContentDialog
|
||||||
|
x:Class="Flow.Launcher.HotkeyControlDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
|
Background="{DynamicResource PopuBGColor}"
|
||||||
|
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||||
|
BorderThickness="0,1,0,0"
|
||||||
|
CornerRadius="8"
|
||||||
|
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||||
|
Foreground="{DynamicResource PopupTextColor}"
|
||||||
|
PreviewKeyDown="OnPreviewKeyDown"
|
||||||
|
Style="{DynamicResource ContentDialog}">
|
||||||
|
<ui:ContentDialog.Resources>
|
||||||
|
<Thickness x:Key="ContentDialogPadding">0</Thickness>
|
||||||
|
<Thickness x:Key="ContentDialogTitleMargin">0</Thickness>
|
||||||
|
</ui:ContentDialog.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="100" />
|
||||||
|
<RowDefinition Height="80" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Window title and the keys in the hotkey -->
|
||||||
|
<Grid Grid.Row="0" Margin="26,12,26,0">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
Text="{Binding WindowTitle}"
|
||||||
|
TextAlignment="Left" />
|
||||||
|
<TextBlock FontSize="14" Text="{DynamicResource hotkeyRegGuide}" />
|
||||||
|
</StackPanel>
|
||||||
|
<Border
|
||||||
|
Grid.Row="1"
|
||||||
|
Width="450"
|
||||||
|
Height="100"
|
||||||
|
Margin="0,100,0,0"
|
||||||
|
Padding="26,12,26,0">
|
||||||
|
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||||
|
<ItemsControl ItemsSource="{Binding KeysToDisplay}">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border
|
||||||
|
MinWidth="50"
|
||||||
|
MinHeight="50"
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
Padding="8"
|
||||||
|
Background="{DynamicResource AccentButtonBackground}"
|
||||||
|
CornerRadius="6">
|
||||||
|
<TextBlock
|
||||||
|
Margin="5,0,5,0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="18"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{DynamicResource Color01B}"
|
||||||
|
Text="{Binding}" />
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Warning message for when something went wrong with the new hotkey. -->
|
||||||
|
<Border Grid.Row="1">
|
||||||
|
|
||||||
|
<Border
|
||||||
|
x:Name="Alert"
|
||||||
|
Width="420"
|
||||||
|
Padding="0, 10"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Background="{DynamicResource InfoBarWarningBG}"
|
||||||
|
BorderBrush="{DynamicResource InfoBarBD}"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="5"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<Grid VerticalAlignment="Center">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ui:FontIcon
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="20,0,14,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="15"
|
||||||
|
Foreground="{DynamicResource InfoBarWarningIcon}"
|
||||||
|
Glyph="" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
x:Name="tbMsg"
|
||||||
|
Margin="0,0,0,2"
|
||||||
|
Padding="0,0,8,0"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
FontSize="13"
|
||||||
|
FontWeight="SemiBold"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Foreground="{DynamicResource Color05B}" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Action buttons at the bottom of the dialog -->
|
||||||
|
<Border
|
||||||
|
Grid.Row="2"
|
||||||
|
Background="{DynamicResource PopupButtonAreaBGColor}"
|
||||||
|
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||||
|
BorderThickness="0,1,0,0"
|
||||||
|
CornerRadius="0 0 8 8">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
x:Name="OverwriteBtn"
|
||||||
|
Height="30"
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="0,0,4,0"
|
||||||
|
Click="Overwrite"
|
||||||
|
Content="{DynamicResource commonOverwrite}"
|
||||||
|
Visibility="Collapsed"
|
||||||
|
Style="{StaticResource AccentButtonStyle}" />
|
||||||
|
<Button
|
||||||
|
x:Name="SaveBtn"
|
||||||
|
Height="30"
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="0,0,4,0"
|
||||||
|
Click="Save"
|
||||||
|
Content="{DynamicResource commonSave}"
|
||||||
|
Style="{StaticResource AccentButtonStyle}" />
|
||||||
|
<Button
|
||||||
|
Height="30"
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="4,0,4,0"
|
||||||
|
Click="Reset"
|
||||||
|
Content="{DynamicResource commonReset}" />
|
||||||
|
<Button
|
||||||
|
Height="30"
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="4,0,4,0"
|
||||||
|
Click="Delete"
|
||||||
|
Content="{DynamicResource commonDelete}" />
|
||||||
|
<Button
|
||||||
|
Height="30"
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="4,0,0,0"
|
||||||
|
Click="Cancel"
|
||||||
|
Content="{DynamicResource commonCancel}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</ui:ContentDialog>
|
||||||
179
Flow.Launcher/HotkeyControlDialog.xaml.cs
Normal file
179
Flow.Launcher/HotkeyControlDialog.xaml.cs
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Flow.Launcher.Core.Resource;
|
||||||
|
using Flow.Launcher.Helper;
|
||||||
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
using Flow.Launcher.Plugin;
|
||||||
|
using ModernWpf.Controls;
|
||||||
|
|
||||||
|
namespace Flow.Launcher;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
public partial class HotkeyControlDialog : ContentDialog
|
||||||
|
{
|
||||||
|
private IHotkeySettings _hotkeySettings;
|
||||||
|
private Action? _overwriteOtherHotkey;
|
||||||
|
private string DefaultHotkey { get; }
|
||||||
|
public string WindowTitle { get; }
|
||||||
|
public HotkeyModel CurrentHotkey { get; private set; }
|
||||||
|
public ObservableCollection<string> KeysToDisplay { get; } = new();
|
||||||
|
|
||||||
|
public enum EResultType
|
||||||
|
{
|
||||||
|
Cancel,
|
||||||
|
Save,
|
||||||
|
Delete
|
||||||
|
}
|
||||||
|
|
||||||
|
public EResultType ResultType { get; private set; } = EResultType.Cancel;
|
||||||
|
public string ResultValue { get; private set; } = string.Empty;
|
||||||
|
public static string EmptyHotkey => InternationalizationManager.Instance.GetTranslation("none");
|
||||||
|
|
||||||
|
public HotkeyControlDialog(string hotkey, string defaultHotkey, IHotkeySettings hotkeySettings, string windowTitle = "")
|
||||||
|
{
|
||||||
|
WindowTitle = windowTitle switch
|
||||||
|
{
|
||||||
|
"" or null => InternationalizationManager.Instance.GetTranslation("hotkeyRegTitle"),
|
||||||
|
_ => windowTitle
|
||||||
|
};
|
||||||
|
DefaultHotkey = defaultHotkey;
|
||||||
|
CurrentHotkey = new HotkeyModel(hotkey);
|
||||||
|
_hotkeySettings = hotkeySettings;
|
||||||
|
SetKeysToDisplay(CurrentHotkey);
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Reset(object sender, RoutedEventArgs routedEventArgs)
|
||||||
|
{
|
||||||
|
SetKeysToDisplay(new HotkeyModel(DefaultHotkey));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Delete(object sender, RoutedEventArgs routedEventArgs)
|
||||||
|
{
|
||||||
|
KeysToDisplay.Clear();
|
||||||
|
KeysToDisplay.Add(EmptyHotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object sender, RoutedEventArgs routedEventArgs)
|
||||||
|
{
|
||||||
|
ResultType = EResultType.Cancel;
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save(object sender, RoutedEventArgs routedEventArgs)
|
||||||
|
{
|
||||||
|
if (KeysToDisplay.Count == 1 && KeysToDisplay[0] == EmptyHotkey)
|
||||||
|
{
|
||||||
|
ResultType = EResultType.Delete;
|
||||||
|
Hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ResultType = EResultType.Save;
|
||||||
|
ResultValue = string.Join("+", KeysToDisplay);
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
|
||||||
|
//when alt is pressed, the real key should be e.SystemKey
|
||||||
|
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
|
||||||
|
|
||||||
|
SpecialKeyState specialKeyState = GlobalHotkey.CheckModifiers();
|
||||||
|
|
||||||
|
var hotkeyModel = new HotkeyModel(
|
||||||
|
specialKeyState.AltPressed,
|
||||||
|
specialKeyState.ShiftPressed,
|
||||||
|
specialKeyState.WinPressed,
|
||||||
|
specialKeyState.CtrlPressed,
|
||||||
|
key);
|
||||||
|
|
||||||
|
CurrentHotkey = hotkeyModel;
|
||||||
|
SetKeysToDisplay(CurrentHotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetKeysToDisplay(HotkeyModel? hotkey)
|
||||||
|
{
|
||||||
|
_overwriteOtherHotkey = null;
|
||||||
|
KeysToDisplay.Clear();
|
||||||
|
|
||||||
|
if (hotkey == null || hotkey == default(HotkeyModel))
|
||||||
|
{
|
||||||
|
KeysToDisplay.Add(EmptyHotkey);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var key in hotkey.Value.EnumerateDisplayKeys()!)
|
||||||
|
{
|
||||||
|
KeysToDisplay.Add(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tbMsg == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_hotkeySettings.RegisteredHotkeys.FirstOrDefault(v => v.Hotkey == hotkey) is { } registeredHotkeyData)
|
||||||
|
{
|
||||||
|
var description = string.Format(
|
||||||
|
InternationalizationManager.Instance.GetTranslation(registeredHotkeyData.DescriptionResourceKey),
|
||||||
|
registeredHotkeyData.DescriptionFormatVariables
|
||||||
|
);
|
||||||
|
Alert.Visibility = Visibility.Visible;
|
||||||
|
if (registeredHotkeyData.RemoveHotkey is not null)
|
||||||
|
{
|
||||||
|
tbMsg.Text = string.Format(
|
||||||
|
InternationalizationManager.Instance.GetTranslation("hotkeyUnavailableEditable"),
|
||||||
|
description
|
||||||
|
);
|
||||||
|
SaveBtn.IsEnabled = false;
|
||||||
|
SaveBtn.Visibility = Visibility.Collapsed;
|
||||||
|
OverwriteBtn.IsEnabled = true;
|
||||||
|
OverwriteBtn.Visibility = Visibility.Visible;
|
||||||
|
_overwriteOtherHotkey = registeredHotkeyData.RemoveHotkey;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tbMsg.Text = string.Format(
|
||||||
|
InternationalizationManager.Instance.GetTranslation("hotkeyUnavailableUneditable"),
|
||||||
|
description
|
||||||
|
);
|
||||||
|
SaveBtn.IsEnabled = false;
|
||||||
|
SaveBtn.Visibility = Visibility.Visible;
|
||||||
|
OverwriteBtn.IsEnabled = false;
|
||||||
|
OverwriteBtn.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OverwriteBtn.IsEnabled = false;
|
||||||
|
OverwriteBtn.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
|
if (!CheckHotkeyAvailability(hotkey.Value, true))
|
||||||
|
{
|
||||||
|
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
|
||||||
|
Alert.Visibility = Visibility.Visible;
|
||||||
|
SaveBtn.IsEnabled = false;
|
||||||
|
SaveBtn.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Alert.Visibility = Visibility.Collapsed;
|
||||||
|
SaveBtn.IsEnabled = true;
|
||||||
|
SaveBtn.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
|
||||||
|
hotkey.Validate(validateKeyGesture) && HotKeyMapper.CheckAvailability(hotkey);
|
||||||
|
|
||||||
|
private void Overwrite(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_overwriteOtherHotkey?.Invoke();
|
||||||
|
Save(sender, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
||||||
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Tmavý</system:String>
|
<system:String x:Key="ColorSchemeDark">Tmavý</system:String>
|
||||||
<system:String x:Key="SoundEffect">Zvukový efekt</system:String>
|
<system:String x:Key="SoundEffect">Zvukový efekt</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Přehrát krátký zvuk při otevření okna vyhledávání</system:String>
|
<system:String x:Key="SoundEffectTip">Přehrát krátký zvuk při otevření okna vyhledávání</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animace</system:String>
|
<system:String x:Key="Animation">Animace</system:String>
|
||||||
<system:String x:Key="AnimationTip">Použít animaci v UI</system:String>
|
<system:String x:Key="AnimationTip">Použít animaci v UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Rychlost animace</system:String>
|
<system:String x:Key="AnimationSpeed">Rychlost animace</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
||||||
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dunkel</system:String>
|
<system:String x:Key="ColorSchemeDark">Dunkel</system:String>
|
||||||
<system:String x:Key="SoundEffect">Soundeffekt</system:String>
|
<system:String x:Key="SoundEffect">Soundeffekt</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Ton abspielen, wenn das Suchfenster geöffnet wird</system:String>
|
<system:String x:Key="SoundEffectTip">Ton abspielen, wenn das Suchfenster geöffnet wird</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Animationen in der Oberfläche verwenden</system:String>
|
<system:String x:Key="AnimationTip">Animationen in der Oberfläche verwenden</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
||||||
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
@ -170,14 +172,35 @@
|
||||||
<!-- Setting Hotkey -->
|
<!-- Setting Hotkey -->
|
||||||
<system:String x:Key="hotkey">Hotkey</system:String>
|
<system:String x:Key="hotkey">Hotkey</system:String>
|
||||||
<system:String x:Key="hotkeys">Hotkeys</system:String>
|
<system:String x:Key="hotkeys">Hotkeys</system:String>
|
||||||
<system:String x:Key="flowlauncherHotkey">Flow Launcher Hotkey</system:String>
|
<system:String x:Key="flowlauncherHotkey">Open Flow Launcher</system:String>
|
||||||
<system:String x:Key="flowlauncherHotkeyToolTip">Enter shortcut to show/hide Flow Launcher.</system:String>
|
<system:String x:Key="flowlauncherHotkeyToolTip">Enter shortcut to show/hide Flow Launcher.</system:String>
|
||||||
<system:String x:Key="previewHotkey">Preview Hotkey</system:String>
|
<system:String x:Key="previewHotkey">Toggle Preview</system:String>
|
||||||
<system:String x:Key="previewHotkeyToolTip">Enter shortcut to show/hide preview in search window.</system:String>
|
<system:String x:Key="previewHotkeyToolTip">Enter shortcut to show/hide preview in search window.</system:String>
|
||||||
|
<system:String x:Key="hotkeyPresets">Hotkey Presets</system:String>
|
||||||
|
<system:String x:Key="hotkeyPresetsToolTip">List of currently registered hotkeys</system:String>
|
||||||
<system:String x:Key="openResultModifiers">Open Result Modifier Key</system:String>
|
<system:String x:Key="openResultModifiers">Open Result Modifier Key</system:String>
|
||||||
<system:String x:Key="openResultModifiersToolTip">Select a modifier key to open selected result via keyboard.</system:String>
|
<system:String x:Key="openResultModifiersToolTip">Select a modifier key to open selected result via keyboard.</system:String>
|
||||||
<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="autoCompleteHotkey">Auto Complete</system:String>
|
||||||
|
<system:String x:Key="autoCompleteHotkeyToolTip">Runs autocomplete for the selected items.</system:String>
|
||||||
|
<system:String x:Key="SelectNextItemHotkey">Select Next Item</system:String>
|
||||||
|
<system:String x:Key="SelectPrevItemHotkey">Select Previous Item</system:String>
|
||||||
|
<system:String x:Key="SelectNextPageHotkey">Next Page</system:String>
|
||||||
|
<system:String x:Key="SelectPrevPageHotkey">Previous Page</system:String>
|
||||||
|
<system:String x:Key="OpenContextMenuHotkey">Open Context Menu</system:String>
|
||||||
|
<system:String x:Key="SettingWindowHotkey">Open Setting Window</system:String>
|
||||||
|
<system:String x:Key="CopyFilePathHotkey">Copy File Path</system:String>
|
||||||
|
<system:String x:Key="ToggleGameModeHotkey">Toggle Game Mode</system:String>
|
||||||
|
<system:String x:Key="ToggleHistoryHotkey">Toggle History</system:String>
|
||||||
|
<system:String x:Key="OpenContainFolderHotkey">Open Containing Folder</system:String>
|
||||||
|
<system:String x:Key="RunAsAdminHotkey">Run As Admin</system:String>
|
||||||
|
<system:String x:Key="RequeryHotkey">Refresh Search Results</system:String>
|
||||||
|
<system:String x:Key="ReloadPluginHotkey">Reload Plugins Data</system:String>
|
||||||
|
<system:String x:Key="QuickWidthHotkey">Quick Adjust Window Width</system:String>
|
||||||
|
<system:String x:Key="QuickHeightHotkey">Quick Adjust Window Height</system:String>
|
||||||
|
<system:String x:Key="ReloadPluginHotkeyToolTip">Use when require plugins to reload and update their existing data.</system:String>
|
||||||
|
<system:String x:Key="AdditionalHotkeyToolTip">You can add one more hotkey for this function.</system:String>
|
||||||
<system:String x:Key="customQueryHotkey">Custom Query Hotkeys</system:String>
|
<system:String x:Key="customQueryHotkey">Custom Query Hotkeys</system:String>
|
||||||
<system:String x:Key="customQueryShortcut">Custom Query Shortcuts</system:String>
|
<system:String x:Key="customQueryShortcut">Custom Query Shortcuts</system:String>
|
||||||
<system:String x:Key="builtinShortcuts">Built-in Shortcuts</system:String>
|
<system:String x:Key="builtinShortcuts">Built-in Shortcuts</system:String>
|
||||||
|
|
@ -188,6 +211,7 @@
|
||||||
<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="none">None</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="deleteCustomShortcutWarning">Are you sure you want to delete shortcut: {0} with expansion {1}?</system:String>
|
||||||
|
|
@ -286,6 +310,11 @@
|
||||||
<system:String x:Key="hotkeyIsNotUnavailable">Hotkey is unavailable, please select a new hotkey</system:String>
|
<system:String x:Key="hotkeyIsNotUnavailable">Hotkey is unavailable, please select a new hotkey</system:String>
|
||||||
<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>
|
||||||
|
<system:String x:Key="hotkeyRegTitle">Binding Hotkey</system:String>
|
||||||
|
<system:String x:Key="hotkeyUnavailable">Current hotkey is unavailable.</system:String>
|
||||||
|
<system:String x:Key="hotkeyUnavailableUneditable">This hotkey is reserved for "{0}" and can't be used. Please choose another hotkey.</system:String>
|
||||||
|
<system:String x:Key="hotkeyUnavailableEditable">This hotkey is already in use by "{0}". If you press "Overwrite", it will be removed from "{0}".</system:String>
|
||||||
|
<system:String x:Key="hotkeyRegGuide">Press the keys you want to use for this function.</system:String>
|
||||||
|
|
||||||
<!-- Custom Query Shortcut Dialog -->
|
<!-- Custom Query Shortcut Dialog -->
|
||||||
<system:String x:Key="customeQueryShortcutTitle">Custom Query Shortcut</system:String>
|
<system:String x:Key="customeQueryShortcutTitle">Custom Query Shortcut</system:String>
|
||||||
|
|
@ -295,8 +324,12 @@
|
||||||
<system:String x:Key="duplicateShortcut">Shortcut already exists, please enter a new Shortcut or edit the existing one.</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>
|
<system:String x:Key="emptyShortcut">Shortcut and/or its expansion is empty.</system:String>
|
||||||
|
|
||||||
<!-- Hotkey Control -->
|
<!-- Common Action -->
|
||||||
<system:String x:Key="hotkeyUnavailable">Hotkey Unavailable</system:String>
|
<system:String x:Key="commonSave">Save</system:String>
|
||||||
|
<system:String x:Key="commonOverwrite">Overwrite</system:String>
|
||||||
|
<system:String x:Key="commonCancel">Cancel</system:String>
|
||||||
|
<system:String x:Key="commonReset">Reset</system:String>
|
||||||
|
<system:String x:Key="commonDelete">Delete</system:String>
|
||||||
|
|
||||||
<!-- Crash Reporter -->
|
<!-- Crash Reporter -->
|
||||||
<system:String x:Key="reportWindow_version">Version</system:String>
|
<system:String x:Key="reportWindow_version">Version</system:String>
|
||||||
|
|
@ -366,6 +399,12 @@
|
||||||
<system:String x:Key="HotkeyCtrlIDesc">Open Setting Window</system:String>
|
<system:String x:Key="HotkeyCtrlIDesc">Open Setting Window</system:String>
|
||||||
<system:String x:Key="HotkeyF5Desc">Reload Plugin Data</system:String>
|
<system:String x:Key="HotkeyF5Desc">Reload Plugin Data</system:String>
|
||||||
|
|
||||||
|
<system:String x:Key="HotkeySelectFirstResult">Select first result</system:String>
|
||||||
|
<system:String x:Key="HotkeySelectLastResult">Select last result</system:String>
|
||||||
|
<system:String x:Key="HotkeyRequery">Run current query again</system:String>
|
||||||
|
<system:String x:Key="HotkeyOpenResult">Open result</system:String>
|
||||||
|
<system:String x:Key="HotkeyOpenResultN">Open result #{0}</system:String>
|
||||||
|
|
||||||
<system:String x:Key="RecommendWeather">Weather</system:String>
|
<system:String x:Key="RecommendWeather">Weather</system:String>
|
||||||
<system:String x:Key="RecommendWeatherDesc">Weather in Google Result</system:String>
|
<system:String x:Key="RecommendWeatherDesc">Weather in Google Result</system:String>
|
||||||
<system:String x:Key="RecommendShell">> ping 8.8.8.8</system:String>
|
<system:String x:Key="RecommendShell">> ping 8.8.8.8</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Oscuro</system:String>
|
<system:String x:Key="ColorSchemeDark">Oscuro</system:String>
|
||||||
<system:String x:Key="SoundEffect">Efectos de Sonido</system:String>
|
<system:String x:Key="SoundEffect">Efectos de Sonido</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Reproducir un sonido al abrir la ventana de búsqueda</system:String>
|
<system:String x:Key="SoundEffectTip">Reproducir un sonido al abrir la ventana de búsqueda</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animación</system:String>
|
<system:String x:Key="Animation">Animación</system:String>
|
||||||
<system:String x:Key="AnimationTip">Usar Animación en la Interfaz</system:String>
|
<system:String x:Key="AnimationTip">Usar Animación en la Interfaz</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
<system:String x:Key="LastQuerySelected">Seleccionar la última consulta</system:String>
|
<system:String x:Key="LastQuerySelected">Seleccionar la última consulta</system:String>
|
||||||
<system:String x:Key="LastQueryEmpty">Limpiar la última consulta</system:String>
|
<system:String x:Key="LastQueryEmpty">Limpiar la última consulta</system:String>
|
||||||
<system:String x:Key="maxShowResults">Número máximo de resultados mostrados</system:String>
|
<system:String x:Key="maxShowResults">Número máximo de resultados mostrados</system:String>
|
||||||
<system:String x:Key="maxShowResultsToolTip">También puede ajustarlo rápidamente usando CTRL+Más y CTRL+Menos.</system:String>
|
<system:String x:Key="maxShowResultsToolTip">También puede ajustarse rápidamente usando Ctrl+Más y Ctrl+Menos.</system:String>
|
||||||
<system:String x:Key="ignoreHotkeysOnFullscreen">Ignorar atajos de teclado en modo pantalla completa</system:String>
|
<system:String x:Key="ignoreHotkeysOnFullscreen">Ignorar atajos de teclado en modo pantalla completa</system:String>
|
||||||
<system:String x:Key="ignoreHotkeysOnFullscreenToolTip">No permite activar Flow Launcher con aplicaciones a pantalla completa (Recomendado para juegos).</system:String>
|
<system:String x:Key="ignoreHotkeysOnFullscreenToolTip">No permite activar Flow Launcher con aplicaciones a pantalla completa (Recomendado para juegos).</system:String>
|
||||||
<system:String x:Key="defaultFileManager">Administrador de archivos predeterminado</system:String>
|
<system:String x:Key="defaultFileManager">Administrador de archivos predeterminado</system:String>
|
||||||
|
|
@ -73,13 +73,13 @@
|
||||||
<system:String x:Key="hideOnStartup">Ocultar Flow Launcher al inicio</system:String>
|
<system:String x:Key="hideOnStartup">Ocultar Flow Launcher al inicio</system:String>
|
||||||
<system:String x:Key="hideNotifyIcon">Ocultar icono en la bandeja del sistema</system:String>
|
<system:String x:Key="hideNotifyIcon">Ocultar icono en la bandeja del sistema</system:String>
|
||||||
<system:String x:Key="hideNotifyIconToolTip">Cuando el icono está oculto en la bandeja del sistema, se puede abrir el menú de configuración haciendo clic con el botón derecho en la ventana de búsqueda.</system:String>
|
<system:String x:Key="hideNotifyIconToolTip">Cuando el icono está oculto en la bandeja del sistema, se puede abrir el menú de configuración haciendo clic con el botón derecho en la ventana de búsqueda.</system:String>
|
||||||
<system:String x:Key="querySearchPrecision">Precisión en la búsqueda de consultas</system:String>
|
<system:String x:Key="querySearchPrecision">Precisión de búsqueda en consultas</system:String>
|
||||||
<system:String x:Key="querySearchPrecisionToolTip">Cambia la puntuación mínima requerida para la coincidencia de los resultados.</system:String>
|
<system:String x:Key="querySearchPrecisionToolTip">Cambia la puntuación mínima requerida para la coincidencia de los resultados.</system:String>
|
||||||
<system:String x:Key="ShouldUsePinyin">Buscar con Pinyin</system:String>
|
<system:String x:Key="ShouldUsePinyin">Buscar con Pinyin</system:String>
|
||||||
<system:String x:Key="ShouldUsePinyinToolTip">Permite utilizar Pinyin para la búsqueda. Pinyin es el sistema estándar de ortografía romanizado para traducir chino.</system:String>
|
<system:String x:Key="ShouldUsePinyinToolTip">Permite utilizar Pinyin para la búsqueda. Pinyin es el sistema estándar de ortografía romanizado para traducir chino.</system:String>
|
||||||
<system:String x:Key="AlwaysPreview">Mostrar siempre vista previa</system:String>
|
<system:String x:Key="AlwaysPreview">Mostrar siempre vista previa</system:String>
|
||||||
<system:String x:Key="AlwaysPreviewToolTip">Muestra siempre el panel de vista previa al iniciar Flow. Pulse {0} para mostrar/ocultar la vista previa.</system:String>
|
<system:String x:Key="AlwaysPreviewToolTip">Muestra siempre el panel de vista previa al iniciar Flow. Pulse {0} para mostrar/ocultar la vista previa.</system:String>
|
||||||
<system:String x:Key="shadowEffectNotAllowed">El efecto de sombra no está permitido mientras el tema actual tenga el efecto de desenfoque activado</system:String>
|
<system:String x:Key="shadowEffectNotAllowed">El efecto de sombra no está permitido si el tema actual tiene activado el efecto de desenfoque</system:String>
|
||||||
|
|
||||||
<!-- Setting Plugin -->
|
<!-- Setting Plugin -->
|
||||||
<system:String x:Key="searchplugin">Buscar complemento</system:String>
|
<system:String x:Key="searchplugin">Buscar complemento</system:String>
|
||||||
|
|
@ -154,8 +154,10 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Oscuro</system:String>
|
<system:String x:Key="ColorSchemeDark">Oscuro</system:String>
|
||||||
<system:String x:Key="SoundEffect">Efecto de sonido</system:String>
|
<system:String x:Key="SoundEffect">Efecto de sonido</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Reproduce un pequeño sonido cuando se abre el cuadro de búsqueda</system:String>
|
<system:String x:Key="SoundEffectTip">Reproduce un pequeño sonido cuando se abre el cuadro de búsqueda</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Volumen del efecto de sonido</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Ajusta el volumen del efecto de sonido</system:String>
|
||||||
<system:String x:Key="Animation">Animación</system:String>
|
<system:String x:Key="Animation">Animación</system:String>
|
||||||
<system:String x:Key="AnimationTip">Usar animación en la Interfaz de Usuario</system:String>
|
<system:String x:Key="AnimationTip">Usa animación en la Interfaz de Usuario</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Velocidad de animación</system:String>
|
<system:String x:Key="AnimationSpeed">Velocidad de animación</system:String>
|
||||||
<system:String x:Key="AnimationSpeedTip">Velocidad de animación de la interfaz de usuario</system:String>
|
<system:String x:Key="AnimationSpeedTip">Velocidad de animación de la interfaz de usuario</system:String>
|
||||||
<system:String x:Key="AnimationSpeedSlow">Lenta</system:String>
|
<system:String x:Key="AnimationSpeedSlow">Lenta</system:String>
|
||||||
|
|
@ -170,7 +172,7 @@
|
||||||
<system:String x:Key="hotkeys">Atajos de teclado</system:String>
|
<system:String x:Key="hotkeys">Atajos de teclado</system:String>
|
||||||
<system:String x:Key="flowlauncherHotkey">Atajo de teclado de Flow Launcher</system:String>
|
<system:String x:Key="flowlauncherHotkey">Atajo de teclado de Flow Launcher</system:String>
|
||||||
<system:String x:Key="flowlauncherHotkeyToolTip">Introduzca el atajo de teclado para mostrar/ocultar Flow Launcher.</system:String>
|
<system:String x:Key="flowlauncherHotkeyToolTip">Introduzca el atajo de teclado para mostrar/ocultar Flow Launcher.</system:String>
|
||||||
<system:String x:Key="previewHotkey">Atajo de teclado para vista previa</system:String>
|
<system:String x:Key="previewHotkey">Acceso directo para vista previa</system:String>
|
||||||
<system:String x:Key="previewHotkeyToolTip">Introduzca el acceso directo para mostrar/ocultar la vista previa en la ventana de búsqueda.</system:String>
|
<system:String x:Key="previewHotkeyToolTip">Introduzca el acceso directo para mostrar/ocultar la vista previa en la ventana de búsqueda.</system:String>
|
||||||
<system:String x:Key="openResultModifiers">Tecla modificadora para abrir resultado</system:String>
|
<system:String x:Key="openResultModifiers">Tecla modificadora para abrir resultado</system:String>
|
||||||
<system:String x:Key="openResultModifiersToolTip">Seleccione una tecla modificadora para abrir el resultado seleccionado con el teclado.</system:String>
|
<system:String x:Key="openResultModifiersToolTip">Seleccione una tecla modificadora para abrir el resultado seleccionado con el teclado.</system:String>
|
||||||
|
|
@ -194,7 +196,7 @@
|
||||||
<system:String x:Key="queryWindowShadowEffect">Efecto de sombra de la ventana de consultas</system:String>
|
<system:String x:Key="queryWindowShadowEffect">Efecto de sombra de la ventana de consultas</system:String>
|
||||||
<system:String x:Key="shadowEffectCPUUsage">El efecto de sombra hace un uso sustancial de la GPU. No se recomienda para ordenadores de rendimiento limitado.</system:String>
|
<system:String x:Key="shadowEffectCPUUsage">El efecto de sombra hace un uso sustancial de la GPU. No se recomienda para ordenadores de rendimiento limitado.</system:String>
|
||||||
<system:String x:Key="windowWidthSize">Tamaño del ancho de la ventana</system:String>
|
<system:String x:Key="windowWidthSize">Tamaño del ancho de la ventana</system:String>
|
||||||
<system:String x:Key="windowWidthSizeToolTip">También puede ajustarlo rápidamente usando Ctrl+[y Ctrl+].</system:String>
|
<system:String x:Key="windowWidthSizeToolTip">También puede ajustarse rápidamente usando Ctrl+[ y Ctrl+].</system:String>
|
||||||
<system:String x:Key="useGlyphUI">Usar iconos Segoe Fluent</system:String>
|
<system:String x:Key="useGlyphUI">Usar iconos Segoe Fluent</system:String>
|
||||||
<system:String x:Key="useGlyphUIEffect">Usa iconos Segoe Fluent para los resultados de la consulta cuando sean compatibles</system:String>
|
<system:String x:Key="useGlyphUIEffect">Usa iconos Segoe Fluent para los resultados de la consulta cuando sean compatibles</system:String>
|
||||||
<system:String x:Key="flowlauncherPressHotkey">Pulsar Tecla</system:String>
|
<system:String x:Key="flowlauncherPressHotkey">Pulsar Tecla</system:String>
|
||||||
|
|
@ -296,7 +298,7 @@ Si añade un prefijo "@" al introducir un acceso directo, éste coinci
|
||||||
<system:String x:Key="emptyShortcut">El acceso directo y/o su expansión están vacíos.</system:String>
|
<system:String x:Key="emptyShortcut">El acceso directo y/o su expansión están vacíos.</system:String>
|
||||||
|
|
||||||
<!-- Hotkey Control -->
|
<!-- Hotkey Control -->
|
||||||
<system:String x:Key="hotkeyUnavailable">Atajo de teclado no disponible</system:String>
|
<system:String x:Key="hotkeyUnavailable">No disponible</system:String>
|
||||||
|
|
||||||
<!-- Crash Reporter -->
|
<!-- Crash Reporter -->
|
||||||
<system:String x:Key="reportWindow_version">Versión</system:String>
|
<system:String x:Key="reportWindow_version">Versión</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Sombre</system:String>
|
<system:String x:Key="ColorSchemeDark">Sombre</system:String>
|
||||||
<system:String x:Key="SoundEffect">Effet Sonore</system:String>
|
<system:String x:Key="SoundEffect">Effet Sonore</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Jouer un petit son lorsque la fenêtre de recherche s'ouvre</system:String>
|
<system:String x:Key="SoundEffectTip">Jouer un petit son lorsque la fenêtre de recherche s'ouvre</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Volume de l'effet sonore</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Ajuster le volume de l'effet sonore</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Utiliser l'animation dans l'interface</system:String>
|
<system:String x:Key="AnimationTip">Utiliser l'animation dans l'interface</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Vitesse d'animation</system:String>
|
<system:String x:Key="AnimationSpeed">Vitesse d'animation</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Scuro</system:String>
|
<system:String x:Key="ColorSchemeDark">Scuro</system:String>
|
||||||
<system:String x:Key="SoundEffect">Effetto sonoro</system:String>
|
<system:String x:Key="SoundEffect">Effetto sonoro</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Riproduce un piccolo suono all'apertura della finestra di ricerca</system:String>
|
<system:String x:Key="SoundEffectTip">Riproduce un piccolo suono all'apertura della finestra di ricerca</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animazione</system:String>
|
<system:String x:Key="Animation">Animazione</system:String>
|
||||||
<system:String x:Key="AnimationTip">Usa l'animazione nell'interfaccia utente</system:String>
|
<system:String x:Key="AnimationTip">Usa l'animazione nell'interfaccia utente</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Velocità di animazione</system:String>
|
<system:String x:Key="AnimationSpeed">Velocità di animazione</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
||||||
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">어둡게</system:String>
|
<system:String x:Key="ColorSchemeDark">어둡게</system:String>
|
||||||
<system:String x:Key="SoundEffect">소리 효과</system:String>
|
<system:String x:Key="SoundEffect">소리 효과</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">검색창을 열 때 작은 소리를 재생합니다.</system:String>
|
<system:String x:Key="SoundEffectTip">검색창을 열 때 작은 소리를 재생합니다.</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">애니메이션</system:String>
|
<system:String x:Key="Animation">애니메이션</system:String>
|
||||||
<system:String x:Key="AnimationTip">일부 UI에 애니메이션을 사용합니다.</system:String>
|
<system:String x:Key="AnimationTip">일부 UI에 애니메이션을 사용합니다.</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
||||||
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Donker</system:String>
|
<system:String x:Key="ColorSchemeDark">Donker</system:String>
|
||||||
<system:String x:Key="SoundEffect">Geluidseffect</system:String>
|
<system:String x:Key="SoundEffect">Geluidseffect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Een klein geluid afspelen wanneer het zoekvenster wordt geopend</system:String>
|
<system:String x:Key="SoundEffectTip">Een klein geluid afspelen wanneer het zoekvenster wordt geopend</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animatie</system:String>
|
<system:String x:Key="Animation">Animatie</system:String>
|
||||||
<system:String x:Key="AnimationTip">Animatie gebruiken in UI</system:String>
|
<system:String x:Key="AnimationTip">Animatie gebruiken in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Ciemny</system:String>
|
<system:String x:Key="ColorSchemeDark">Ciemny</system:String>
|
||||||
<system:String x:Key="SoundEffect">Efekty dźwiękowe</system:String>
|
<system:String x:Key="SoundEffect">Efekty dźwiękowe</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Odtwarzaj krótki dźwięk po otwarciu okna wyszukiwania</system:String>
|
<system:String x:Key="SoundEffectTip">Odtwarzaj krótki dźwięk po otwarciu okna wyszukiwania</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animacja</system:String>
|
<system:String x:Key="Animation">Animacja</system:String>
|
||||||
<system:String x:Key="AnimationTip">Użyj animacji w interfejsie użytkownika</system:String>
|
<system:String x:Key="AnimationTip">Użyj animacji w interfejsie użytkownika</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Szybkość animacji</system:String>
|
<system:String x:Key="AnimationSpeed">Szybkość animacji</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Escuro</system:String>
|
<system:String x:Key="ColorSchemeDark">Escuro</system:String>
|
||||||
<system:String x:Key="SoundEffect">Efeito Sonoro</system:String>
|
<system:String x:Key="SoundEffect">Efeito Sonoro</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Reproduzir um pequeno som ao abrir a janela de pesquisa</system:String>
|
<system:String x:Key="SoundEffectTip">Reproduzir um pequeno som ao abrir a janela de pesquisa</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animação</system:String>
|
<system:String x:Key="Animation">Animação</system:String>
|
||||||
<system:String x:Key="AnimationTip">Utilizar Animação na Interface</system:String>
|
<system:String x:Key="AnimationTip">Utilizar Animação na Interface</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Velocidade de Animação</system:String>
|
<system:String x:Key="AnimationSpeed">Velocidade de Animação</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Escuro</system:String>
|
<system:String x:Key="ColorSchemeDark">Escuro</system:String>
|
||||||
<system:String x:Key="SoundEffect">Efeitos sonoros</system:String>
|
<system:String x:Key="SoundEffect">Efeitos sonoros</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Reproduzir um som ao abrir a janela de pesquisa</system:String>
|
<system:String x:Key="SoundEffectTip">Reproduzir um som ao abrir a janela de pesquisa</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Volume dos efeitos sonoros</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Ajustar volume dos efeitos sonoros</system:String>
|
||||||
<system:String x:Key="Animation">Animação</system:String>
|
<system:String x:Key="Animation">Animação</system:String>
|
||||||
<system:String x:Key="AnimationTip">Utilizar animações na aplicação</system:String>
|
<system:String x:Key="AnimationTip">Utilizar animações na aplicação</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Velocidade da animação</system:String>
|
<system:String x:Key="AnimationSpeed">Velocidade da animação</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Тёмная</system:String>
|
<system:String x:Key="ColorSchemeDark">Тёмная</system:String>
|
||||||
<system:String x:Key="SoundEffect">Звуковой эффект</system:String>
|
<system:String x:Key="SoundEffect">Звуковой эффект</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Воспроизведение небольшого звука при открытии окна поиска</system:String>
|
<system:String x:Key="SoundEffectTip">Воспроизведение небольшого звука при открытии окна поиска</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Анимация</system:String>
|
<system:String x:Key="Animation">Анимация</system:String>
|
||||||
<system:String x:Key="AnimationTip">Использование анимации в меню</system:String>
|
<system:String x:Key="AnimationTip">Использование анимации в меню</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Скорость анимации</system:String>
|
<system:String x:Key="AnimationSpeed">Скорость анимации</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Tmavá</system:String>
|
<system:String x:Key="ColorSchemeDark">Tmavá</system:String>
|
||||||
<system:String x:Key="SoundEffect">Zvukový efekt</system:String>
|
<system:String x:Key="SoundEffect">Zvukový efekt</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Po otvorení okna vyhľadávania prehrať krátky zvuk</system:String>
|
<system:String x:Key="SoundEffectTip">Po otvorení okna vyhľadávania prehrať krátky zvuk</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Hlasitosť zvukového efektu</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Upraviť hlasitosť zvukového efektu</system:String>
|
||||||
<system:String x:Key="Animation">Animácia</system:String>
|
<system:String x:Key="Animation">Animácia</system:String>
|
||||||
<system:String x:Key="AnimationTip">Animovať používateľské rozhranie</system:String>
|
<system:String x:Key="AnimationTip">Animovať používateľské rozhranie</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Rýchlosť animácie</system:String>
|
<system:String x:Key="AnimationSpeed">Rýchlosť animácie</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
<system:String x:Key="ColorSchemeDark">Dark</system:String>
|
||||||
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
<system:String x:Key="SoundEffect">Sound Effect</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animation</system:String>
|
<system:String x:Key="Animation">Animation</system:String>
|
||||||
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Koyu</system:String>
|
<system:String x:Key="ColorSchemeDark">Koyu</system:String>
|
||||||
<system:String x:Key="SoundEffect">Ses Efekti</system:String>
|
<system:String x:Key="SoundEffect">Ses Efekti</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Arama penceresi açıldığında küçük bir ses oynat</system:String>
|
<system:String x:Key="SoundEffectTip">Arama penceresi açıldığında küçük bir ses oynat</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">Animasyon</system:String>
|
<system:String x:Key="Animation">Animasyon</system:String>
|
||||||
<system:String x:Key="AnimationTip">Arayüzde Animasyon Kullan</system:String>
|
<system:String x:Key="AnimationTip">Arayüzde Animasyon Kullan</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">Темна</system:String>
|
<system:String x:Key="ColorSchemeDark">Темна</system:String>
|
||||||
<system:String x:Key="SoundEffect">Звуковий ефект</system:String>
|
<system:String x:Key="SoundEffect">Звуковий ефект</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">Відтворювати невеликий звук при відкритті вікна пошуку</system:String>
|
<system:String x:Key="SoundEffectTip">Відтворювати невеликий звук при відкритті вікна пошуку</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Гучність звукового ефекту</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Налаштуйте гучність звукового ефекту</system:String>
|
||||||
<system:String x:Key="Animation">Анімація</system:String>
|
<system:String x:Key="Animation">Анімація</system:String>
|
||||||
<system:String x:Key="AnimationTip">Використовувати анімацію в інтерфейсі</system:String>
|
<system:String x:Key="AnimationTip">Використовувати анімацію в інтерфейсі</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Швидкість анімації</system:String>
|
<system:String x:Key="AnimationSpeed">Швидкість анімації</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">深色</system:String>
|
<system:String x:Key="ColorSchemeDark">深色</system:String>
|
||||||
<system:String x:Key="SoundEffect">音效</system:String>
|
<system:String x:Key="SoundEffect">音效</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">启用激活音效</system:String>
|
<system:String x:Key="SoundEffectTip">启用激活音效</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">音效音量</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">调整音效音量</system:String>
|
||||||
<system:String x:Key="Animation">动画</system:String>
|
<system:String x:Key="Animation">动画</system:String>
|
||||||
<system:String x:Key="AnimationTip">启用动画</system:String>
|
<system:String x:Key="AnimationTip">启用动画</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">动画速度</system:String>
|
<system:String x:Key="AnimationSpeed">动画速度</system:String>
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,8 @@
|
||||||
<system:String x:Key="ColorSchemeDark">暗色系</system:String>
|
<system:String x:Key="ColorSchemeDark">暗色系</system:String>
|
||||||
<system:String x:Key="SoundEffect">音效</system:String>
|
<system:String x:Key="SoundEffect">音效</system:String>
|
||||||
<system:String x:Key="SoundEffectTip">搜尋窗口打開時播放音效</system:String>
|
<system:String x:Key="SoundEffectTip">搜尋窗口打開時播放音效</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolume">Sound Effect Volume</system:String>
|
||||||
|
<system:String x:Key="SoundEffectVolumeTip">Adjust the volume of the sound effect</system:String>
|
||||||
<system:String x:Key="Animation">動畫</system:String>
|
<system:String x:Key="Animation">動畫</system:String>
|
||||||
<system:String x:Key="AnimationTip">使用介面動畫</system:String>
|
<system:String x:Key="AnimationTip">使用介面動畫</system:String>
|
||||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||||
|
|
|
||||||
|
|
@ -46,47 +46,14 @@
|
||||||
<Window.InputBindings>
|
<Window.InputBindings>
|
||||||
<KeyBinding Key="Escape" Command="{Binding EscCommand}" />
|
<KeyBinding Key="Escape" Command="{Binding EscCommand}" />
|
||||||
<KeyBinding Key="F5" Command="{Binding ReloadPluginDataCommand}" />
|
<KeyBinding Key="F5" Command="{Binding ReloadPluginDataCommand}" />
|
||||||
<KeyBinding Key="Tab" Command="{Binding AutocompleteQueryCommand}" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="Tab"
|
|
||||||
Command="{Binding AutocompleteQueryCommand}"
|
|
||||||
Modifiers="Shift" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="I"
|
|
||||||
Command="{Binding OpenSettingCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="N"
|
|
||||||
Command="{Binding SelectNextItemCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="J"
|
|
||||||
Command="{Binding SelectNextItemCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="D"
|
|
||||||
Command="{Binding SelectNextPageCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="P"
|
|
||||||
Command="{Binding SelectPrevItemCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="K"
|
|
||||||
Command="{Binding SelectPrevItemCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
|
||||||
Key="U"
|
|
||||||
Command="{Binding SelectPrevPageCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
<KeyBinding
|
||||||
Key="Home"
|
Key="Home"
|
||||||
Command="{Binding SelectFirstResultCommand}"
|
Command="{Binding SelectFirstResultCommand}"
|
||||||
Modifiers="Alt" />
|
Modifiers="Alt" />
|
||||||
<KeyBinding
|
<KeyBinding
|
||||||
Key="O"
|
Key="End"
|
||||||
Command="{Binding LoadContextMenuCommand}"
|
Command="{Binding SelectLastResultCommand}"
|
||||||
Modifiers="Ctrl" />
|
Modifiers="Alt" />
|
||||||
<KeyBinding
|
<KeyBinding
|
||||||
Key="R"
|
Key="R"
|
||||||
Command="{Binding ReQueryCommand}"
|
Command="{Binding ReQueryCommand}"
|
||||||
|
|
@ -111,10 +78,6 @@
|
||||||
Key="OemMinus"
|
Key="OemMinus"
|
||||||
Command="{Binding DecreaseMaxResultCommand}"
|
Command="{Binding DecreaseMaxResultCommand}"
|
||||||
Modifiers="Control" />
|
Modifiers="Control" />
|
||||||
<KeyBinding
|
|
||||||
Key="H"
|
|
||||||
Command="{Binding LoadHistoryCommand}"
|
|
||||||
Modifiers="Ctrl" />
|
|
||||||
<KeyBinding
|
<KeyBinding
|
||||||
Key="Enter"
|
Key="Enter"
|
||||||
Command="{Binding OpenResultCommand}"
|
Command="{Binding OpenResultCommand}"
|
||||||
|
|
@ -188,12 +151,52 @@
|
||||||
Modifiers="Ctrl" />
|
Modifiers="Ctrl" />
|
||||||
<KeyBinding
|
<KeyBinding
|
||||||
Key="C"
|
Key="C"
|
||||||
Modifiers="Ctrl+Shift"
|
Command="{Binding CopyAlternativeCommand}"
|
||||||
Command="{Binding CopyAlternativeCommand}" />
|
Modifiers="Ctrl+Shift" />
|
||||||
<KeyBinding
|
<KeyBinding
|
||||||
Key="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
Key="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
Command="{Binding TogglePreviewCommand}"
|
Command="{Binding TogglePreviewCommand}"
|
||||||
Modifiers="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
Modifiers="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding AutoCompleteHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding AutocompleteQueryCommand}"
|
||||||
|
Modifiers="{Binding AutoCompleteHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding AutoCompleteHotkey2, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding AutocompleteQueryCommand}"
|
||||||
|
Modifiers="{Binding AutoCompleteHotkey2, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SelectNextItemHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding SelectNextItemCommand}"
|
||||||
|
Modifiers="{Binding SelectNextItemHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SelectPrevItemHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding SelectPrevItemCommand}"
|
||||||
|
Modifiers="{Binding SelectPrevItemHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SelectNextItemHotkey2, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding SelectNextItemCommand}"
|
||||||
|
Modifiers="{Binding SelectNextItemHotkey2, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SelectPrevItemHotkey2, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding SelectPrevItemCommand}"
|
||||||
|
Modifiers="{Binding SelectPrevItemHotkey2, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SettingWindowHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding OpenSettingCommand}"
|
||||||
|
Modifiers="{Binding SettingWindowHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding OpenContextMenuHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding LoadContextMenuCommand}"
|
||||||
|
Modifiers="{Binding OpenContextMenuHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SelectNextPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding SelectNextPageCommand}"
|
||||||
|
Modifiers="{Binding SelectNextPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
|
<KeyBinding
|
||||||
|
Key="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||||
|
Command="{Binding SelectPrevPageCommand}"
|
||||||
|
Modifiers="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||||
</Window.InputBindings>
|
</Window.InputBindings>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
|
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
|
||||||
|
|
@ -216,6 +219,7 @@
|
||||||
<TextBox
|
<TextBox
|
||||||
x:Name="QueryTextBox"
|
x:Name="QueryTextBox"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
|
AutomationProperties.Name="{Binding Results.SelectedItem.Result.Title}"
|
||||||
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
|
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
|
||||||
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
|
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
|
||||||
PreviewDragOver="OnPreviewDragOver"
|
PreviewDragOver="OnPreviewDragOver"
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ using Key = System.Windows.Input.Key;
|
||||||
using System.Media;
|
using System.Media;
|
||||||
using static Flow.Launcher.ViewModel.SettingWindowViewModel;
|
using static Flow.Launcher.ViewModel.SettingWindowViewModel;
|
||||||
using DataObject = System.Windows.DataObject;
|
using DataObject = System.Windows.DataObject;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace Flow.Launcher
|
namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
|
|
@ -33,14 +36,17 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
#region Private Fields
|
#region Private Fields
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
public static extern IntPtr SetForegroundWindow(IntPtr hwnd);
|
||||||
|
|
||||||
private readonly Storyboard _progressBarStoryboard = new Storyboard();
|
private readonly Storyboard _progressBarStoryboard = new Storyboard();
|
||||||
private bool isProgressBarStoryboardPaused;
|
private bool isProgressBarStoryboardPaused;
|
||||||
private Settings _settings;
|
private Settings _settings;
|
||||||
private NotifyIcon _notifyIcon;
|
private NotifyIcon _notifyIcon;
|
||||||
private ContextMenu contextMenu;
|
private ContextMenu contextMenu = new ContextMenu();
|
||||||
private MainViewModel _viewModel;
|
private MainViewModel _viewModel;
|
||||||
private bool _animating;
|
private bool _animating;
|
||||||
SoundPlayer animationSound = new SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav");
|
MediaPlayer animationSound = new MediaPlayer();
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
@ -52,6 +58,9 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
InitializePosition();
|
InitializePosition();
|
||||||
|
|
||||||
|
animationSound.Open(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav"));
|
||||||
|
|
||||||
DataObject.AddPastingHandler(QueryTextBox, OnPaste);
|
DataObject.AddPastingHandler(QueryTextBox, OnPaste);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,6 +137,8 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
if (_settings.UseSound)
|
if (_settings.UseSound)
|
||||||
{
|
{
|
||||||
|
animationSound.Position = TimeSpan.Zero;
|
||||||
|
animationSound.Volume = _settings.SoundVolume / 100.0;
|
||||||
animationSound.Play();
|
animationSound.Play();
|
||||||
}
|
}
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
|
|
@ -264,12 +275,11 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
_notifyIcon = new NotifyIcon
|
_notifyIcon = new NotifyIcon
|
||||||
{
|
{
|
||||||
Text = Infrastructure.Constant.FlowLauncher,
|
Text = Infrastructure.Constant.FlowLauncherFullName,
|
||||||
Icon = Properties.Resources.app,
|
Icon = Properties.Resources.app,
|
||||||
Visible = !_settings.HideNotifyIcon
|
Visible = !_settings.HideNotifyIcon
|
||||||
};
|
};
|
||||||
|
|
||||||
contextMenu = new ContextMenu();
|
|
||||||
|
|
||||||
var openIcon = new FontIcon
|
var openIcon = new FontIcon
|
||||||
{
|
{
|
||||||
|
|
@ -277,7 +287,8 @@ namespace Flow.Launcher
|
||||||
};
|
};
|
||||||
var open = new MenuItem
|
var open = new MenuItem
|
||||||
{
|
{
|
||||||
Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")", Icon = openIcon
|
Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")",
|
||||||
|
Icon = openIcon
|
||||||
};
|
};
|
||||||
var gamemodeIcon = new FontIcon
|
var gamemodeIcon = new FontIcon
|
||||||
{
|
{
|
||||||
|
|
@ -285,7 +296,8 @@ namespace Flow.Launcher
|
||||||
};
|
};
|
||||||
var gamemode = new MenuItem
|
var gamemode = new MenuItem
|
||||||
{
|
{
|
||||||
Header = InternationalizationManager.Instance.GetTranslation("GameMode"), Icon = gamemodeIcon
|
Header = InternationalizationManager.Instance.GetTranslation("GameMode"),
|
||||||
|
Icon = gamemodeIcon
|
||||||
};
|
};
|
||||||
var positionresetIcon = new FontIcon
|
var positionresetIcon = new FontIcon
|
||||||
{
|
{
|
||||||
|
|
@ -293,7 +305,8 @@ namespace Flow.Launcher
|
||||||
};
|
};
|
||||||
var positionreset = new MenuItem
|
var positionreset = new MenuItem
|
||||||
{
|
{
|
||||||
Header = InternationalizationManager.Instance.GetTranslation("PositionReset"), Icon = positionresetIcon
|
Header = InternationalizationManager.Instance.GetTranslation("PositionReset"),
|
||||||
|
Icon = positionresetIcon
|
||||||
};
|
};
|
||||||
var settingsIcon = new FontIcon
|
var settingsIcon = new FontIcon
|
||||||
{
|
{
|
||||||
|
|
@ -301,7 +314,8 @@ namespace Flow.Launcher
|
||||||
};
|
};
|
||||||
var settings = new MenuItem
|
var settings = new MenuItem
|
||||||
{
|
{
|
||||||
Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"), Icon = settingsIcon
|
Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"),
|
||||||
|
Icon = settingsIcon
|
||||||
};
|
};
|
||||||
var exitIcon = new FontIcon
|
var exitIcon = new FontIcon
|
||||||
{
|
{
|
||||||
|
|
@ -309,7 +323,8 @@ namespace Flow.Launcher
|
||||||
};
|
};
|
||||||
var exit = new MenuItem
|
var exit = new MenuItem
|
||||||
{
|
{
|
||||||
Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"), Icon = exitIcon
|
Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"),
|
||||||
|
Icon = exitIcon
|
||||||
};
|
};
|
||||||
|
|
||||||
open.Click += (o, e) => _viewModel.ToggleFlowLauncher();
|
open.Click += (o, e) => _viewModel.ToggleFlowLauncher();
|
||||||
|
|
@ -327,7 +342,6 @@ namespace Flow.Launcher
|
||||||
contextMenu.Items.Add(settings);
|
contextMenu.Items.Add(settings);
|
||||||
contextMenu.Items.Add(exit);
|
contextMenu.Items.Add(exit);
|
||||||
|
|
||||||
_notifyIcon.ContextMenuStrip = new ContextMenuStrip(); // it need for close the context menu. if not, context menu can't close.
|
|
||||||
_notifyIcon.MouseClick += (o, e) =>
|
_notifyIcon.MouseClick += (o, e) =>
|
||||||
{
|
{
|
||||||
switch (e.Button)
|
switch (e.Button)
|
||||||
|
|
@ -335,9 +349,15 @@ namespace Flow.Launcher
|
||||||
case MouseButtons.Left:
|
case MouseButtons.Left:
|
||||||
_viewModel.ToggleFlowLauncher();
|
_viewModel.ToggleFlowLauncher();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MouseButtons.Right:
|
case MouseButtons.Right:
|
||||||
|
|
||||||
contextMenu.IsOpen = true;
|
contextMenu.IsOpen = true;
|
||||||
|
// Get context menu handle and bring it to the foreground
|
||||||
|
if (PresentationSource.FromVisual(contextMenu) is HwndSource hwndSource)
|
||||||
|
{
|
||||||
|
_ = SetForegroundWindow(hwndSource.Handle);
|
||||||
|
}
|
||||||
|
contextMenu.Focus();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,8 @@ namespace Flow.Launcher
|
||||||
public void RegisterGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Add(callback);
|
public void RegisterGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Add(callback);
|
||||||
public void RemoveGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Remove(callback);
|
public void RemoveGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Remove(callback);
|
||||||
|
|
||||||
|
public void ReQuery(bool reselect = true) => _mainVM.ReQuery(reselect);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Methods
|
#region Private Methods
|
||||||
|
|
|
||||||
117
Flow.Launcher/Resources/Controls/Card.xaml
Normal file
117
Flow.Launcher/Resources/Controls/Card.xaml
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
<UserControl
|
||||||
|
x:Class="Flow.Launcher.Resources.Controls.Card"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Template>
|
||||||
|
<ControlTemplate TargetType="UserControl">
|
||||||
|
<Border x:Name="BD" HorizontalAlignment="Stretch">
|
||||||
|
<Border.Style>
|
||||||
|
<Style TargetType="{x:Type Border}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Color00B}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="CornerRadius" Value="5" />
|
||||||
|
<Setter Property="MinHeight" Value="68" />
|
||||||
|
<Setter Property="Margin" Value="0,4,0,0" />
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource AncestorType=local:Card}}" Value="Inside">
|
||||||
|
<Setter Property="BorderThickness" Value="0,1,0,0" />
|
||||||
|
<Setter Property="CornerRadius" Value="0" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource AncestorType=local:Card}}" Value="InsideFit">
|
||||||
|
<Setter Property="BorderThickness" Value="0,1,0,0" />
|
||||||
|
<Setter Property="CornerRadius" Value="0" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="Padding" Value="38,0,26,0" />
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Style>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition
|
||||||
|
Width="auto"
|
||||||
|
MinWidth="20"
|
||||||
|
MaxWidth="60" />
|
||||||
|
<ColumnDefinition Width="8*" />
|
||||||
|
<ColumnDefinition Width="Auto" MinWidth="30" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ContentControl
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{TemplateBinding Content}" />
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel.Style>
|
||||||
|
<Style TargetType="{x:Type StackPanel}">
|
||||||
|
<Setter Property="Grid.Column" Value="1" />
|
||||||
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||||
|
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Style>
|
||||||
|
<TextBlock x:Name="ItemTitle" Text="{Binding Title, RelativeSource={RelativeSource AncestorType=local:Card}}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="TextWrapping" Value="Wrap" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock x:Name="SubTitle" Text="{Binding Sub, RelativeSource={RelativeSource AncestorType=local:Card}}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ElementName=SubTitle, Path=Text}" Value="{x:Static sys:String.Empty}">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color04B}" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="Padding" Value="0,0,24,0" />
|
||||||
|
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock x:Name="ItemIcon" Text="{Binding Icon, RelativeSource={RelativeSource AncestorType=local:Card}}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ElementName=ItemIcon, Path=Text}" Value="{x:Static sys:String.Empty}">
|
||||||
|
<Setter Property="Margin" Value="24,0,0,0" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
<Setter Property="Grid.Column" Value="0" />
|
||||||
|
<Setter Property="Margin" Value="24,0,16,0" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="FontSize" Value="20" />
|
||||||
|
<Setter Property="FontFamily" Value="/Resources/#Segoe Fluent Icons" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</UserControl.Template>
|
||||||
|
</UserControl>
|
||||||
63
Flow.Launcher/Resources/Controls/Card.xaml.cs
Normal file
63
Flow.Launcher/Resources/Controls/Card.xaml.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
using System.Windows;
|
||||||
|
using UserControl = System.Windows.Controls.UserControl;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Resources.Controls
|
||||||
|
{
|
||||||
|
public partial class Card : UserControl
|
||||||
|
{
|
||||||
|
public enum CardType
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Inside,
|
||||||
|
InsideFit
|
||||||
|
}
|
||||||
|
|
||||||
|
public Card()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(TitleProperty); }
|
||||||
|
set { SetValue(TitleProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty TitleProperty =
|
||||||
|
DependencyProperty.Register(nameof(Title), typeof(string), typeof(Card), new PropertyMetadata(string.Empty));
|
||||||
|
|
||||||
|
public string Sub
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(SubProperty); }
|
||||||
|
set { SetValue(SubProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty SubProperty =
|
||||||
|
DependencyProperty.Register(nameof(Sub), typeof(string), typeof(Card), new PropertyMetadata(string.Empty));
|
||||||
|
|
||||||
|
public string Icon
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(IconProperty); }
|
||||||
|
set { SetValue(IconProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty IconProperty =
|
||||||
|
DependencyProperty.Register(nameof(Icon), typeof(string), typeof(Card), new PropertyMetadata(string.Empty));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets additional content for the UserControl
|
||||||
|
/// </summary>
|
||||||
|
public object AdditionalContent
|
||||||
|
{
|
||||||
|
get { return (object)GetValue(AdditionalContentProperty); }
|
||||||
|
set { SetValue(AdditionalContentProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty AdditionalContentProperty =
|
||||||
|
DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(Card),
|
||||||
|
new PropertyMetadata(null));
|
||||||
|
public CardType Type
|
||||||
|
{
|
||||||
|
get { return (CardType)GetValue(TypeProperty); }
|
||||||
|
set { SetValue(TypeProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty TypeProperty =
|
||||||
|
DependencyProperty.Register(nameof(Type), typeof(CardType), typeof(Card),
|
||||||
|
new PropertyMetadata(CardType.Default));
|
||||||
|
}
|
||||||
|
}
|
||||||
313
Flow.Launcher/Resources/Controls/ExCard.xaml
Normal file
313
Flow.Launcher/Resources/Controls/ExCard.xaml
Normal file
|
|
@ -0,0 +1,313 @@
|
||||||
|
<UserControl
|
||||||
|
x:Class="Flow.Launcher.Resources.Controls.ExCard"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Template>
|
||||||
|
<ControlTemplate TargetType="UserControl">
|
||||||
|
<Expander
|
||||||
|
x:Name="expanderHeader"
|
||||||
|
Padding="0"
|
||||||
|
BorderThickness="1"
|
||||||
|
IsExpanded="{Binding Mode=TwoWay, Path=IsExpanded}"
|
||||||
|
SnapsToDevicePixels="False">
|
||||||
|
<Expander.Style>
|
||||||
|
<Style TargetType="{x:Type Expander}">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Color00B}" />
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Expander}">
|
||||||
|
<Border
|
||||||
|
x:Name="Bd"
|
||||||
|
Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
CornerRadius="5"
|
||||||
|
SnapsToDevicePixels="true">
|
||||||
|
<DockPanel>
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="HeaderSite"
|
||||||
|
MinWidth="0"
|
||||||
|
MinHeight="68"
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
Padding="0,0,0,0"
|
||||||
|
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
Content="{TemplateBinding Header}"
|
||||||
|
ContentTemplate="{TemplateBinding HeaderTemplate}"
|
||||||
|
ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"
|
||||||
|
DockPanel.Dock="Top"
|
||||||
|
FocusVisualStyle="{DynamicResource ExpanderHeaderFocusVisual}"
|
||||||
|
FontFamily="{TemplateBinding FontFamily}"
|
||||||
|
FontSize="{TemplateBinding FontSize}"
|
||||||
|
FontStretch="{TemplateBinding FontStretch}"
|
||||||
|
FontStyle="{TemplateBinding FontStyle}"
|
||||||
|
FontWeight="{TemplateBinding FontWeight}"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
|
||||||
|
<ToggleButton.Style>
|
||||||
|
<Style TargetType="{x:Type ToggleButton}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||||
|
<Border
|
||||||
|
x:Name="ToggleBtn"
|
||||||
|
Padding="{TemplateBinding Padding}"
|
||||||
|
Background="{DynamicResource Color00B}"
|
||||||
|
ClipToBounds="True"
|
||||||
|
CornerRadius="5">
|
||||||
|
<Grid SnapsToDevicePixels="True">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="30" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ContentPresenter
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
Content="{TemplateBinding Content}"
|
||||||
|
RecognizesAccessKey="True"
|
||||||
|
SnapsToDevicePixels="True" />
|
||||||
|
<Grid
|
||||||
|
x:Name="ChevronGrid"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="0,0,18,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
RenderTransformOrigin="0.5, 0.5">
|
||||||
|
<Grid.RenderTransform>
|
||||||
|
<RotateTransform Angle="0" />
|
||||||
|
</Grid.RenderTransform>
|
||||||
|
<Ellipse
|
||||||
|
x:Name="circle"
|
||||||
|
Width="19"
|
||||||
|
Height="19"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Stroke="Transparent" />
|
||||||
|
<Path
|
||||||
|
x:Name="arrow"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Data="M 1,1.5 L 4.5,5 L 8,1.5"
|
||||||
|
SnapsToDevicePixels="false"
|
||||||
|
Stroke="#666"
|
||||||
|
StrokeThickness="1" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsChecked" Value="true">
|
||||||
|
<Setter TargetName="arrow" Property="Data" Value="M 1,4.5 L 4.5,1 L 8,4.5" />
|
||||||
|
<Setter TargetName="ToggleBtn" Property="CornerRadius" Value="5 5 0 0" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsMouseOver" Value="true">
|
||||||
|
<Setter TargetName="circle" Property="Stroke" Value="Transparent" />
|
||||||
|
<Setter TargetName="arrow" Property="Stroke" Value="{DynamicResource Color05B}" />
|
||||||
|
<Setter TargetName="ToggleBtn" Property="Background" Value="{DynamicResource CustomExpanderHover}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="true">
|
||||||
|
<Setter TargetName="circle" Property="Stroke" Value="Transparent" />
|
||||||
|
<Setter TargetName="circle" Property="StrokeThickness" Value="1.5" />
|
||||||
|
<Setter TargetName="arrow" Property="Stroke" Value="{DynamicResource Color17B}" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
|
||||||
|
</Style>
|
||||||
|
</ToggleButton.Style>
|
||||||
|
</ToggleButton>
|
||||||
|
<Border x:Name="ContentPresenterBorder" BorderThickness="0">
|
||||||
|
<ContentPresenter
|
||||||
|
x:Name="ExpandSite"
|
||||||
|
Margin="{TemplateBinding Padding}"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
DockPanel.Dock="Bottom"
|
||||||
|
Focusable="false" />
|
||||||
|
<Border.LayoutTransform>
|
||||||
|
<ScaleTransform ScaleY="0" />
|
||||||
|
</Border.LayoutTransform>
|
||||||
|
</Border>
|
||||||
|
</DockPanel>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsExpanded" Value="true">
|
||||||
|
<Setter TargetName="ExpandSite" Property="Visibility" Value="Visible" />
|
||||||
|
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="0,0,0,0" />
|
||||||
|
<Trigger.EnterActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation
|
||||||
|
Storyboard.TargetName="ContentPresenterBorder"
|
||||||
|
Storyboard.TargetProperty="(Border.LayoutTransform).(ScaleTransform.ScaleY)"
|
||||||
|
From="0.0"
|
||||||
|
To="1.0"
|
||||||
|
Duration="00:00:00.00" />
|
||||||
|
<DoubleAnimation
|
||||||
|
Storyboard.TargetName="ContentPresenterBorder"
|
||||||
|
Storyboard.TargetProperty="(Border.Opacity)"
|
||||||
|
From="0.0"
|
||||||
|
To="1.0"
|
||||||
|
Duration="00:00:00.00" />
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</Trigger.EnterActions>
|
||||||
|
<Trigger.ExitActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation
|
||||||
|
Storyboard.TargetName="ContentPresenterBorder"
|
||||||
|
Storyboard.TargetProperty="(Border.LayoutTransform).(ScaleTransform.ScaleY)"
|
||||||
|
From="1.0"
|
||||||
|
To="0"
|
||||||
|
Duration="00:00:00.00" />
|
||||||
|
<!-- Animation 00:00:00.167 -->
|
||||||
|
<DoubleAnimation
|
||||||
|
Storyboard.TargetName="ContentPresenterBorder"
|
||||||
|
Storyboard.TargetProperty="(Border.Opacity)"
|
||||||
|
From="1.0"
|
||||||
|
To="0.0"
|
||||||
|
Duration="00:00:00.00" />
|
||||||
|
<!-- Animation 00:00:00.167 -->
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</Trigger.ExitActions>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="ExpandDirection" Value="Right">
|
||||||
|
<Setter TargetName="ExpandSite" Property="DockPanel.Dock" Value="Right" />
|
||||||
|
<Setter TargetName="HeaderSite" Property="DockPanel.Dock" Value="Left" />
|
||||||
|
<Setter TargetName="HeaderSite" Property="Style" Value="{StaticResource ExpanderRightHeaderStyle}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="ExpandDirection" Value="Up">
|
||||||
|
<Setter TargetName="ExpandSite" Property="DockPanel.Dock" Value="Top" />
|
||||||
|
<Setter TargetName="HeaderSite" Property="DockPanel.Dock" Value="Bottom" />
|
||||||
|
<Setter TargetName="HeaderSite" Property="Style" Value="{StaticResource ExpanderUpHeaderStyle}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="ExpandDirection" Value="Left">
|
||||||
|
<Setter TargetName="ExpandSite" Property="DockPanel.Dock" Value="Left" />
|
||||||
|
<Setter TargetName="HeaderSite" Property="DockPanel.Dock" Value="Right" />
|
||||||
|
<Setter TargetName="HeaderSite" Property="Style" Value="{StaticResource ExpanderLeftHeaderStyle}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="false">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Expander.Style>
|
||||||
|
<Expander.Header>
|
||||||
|
<Border Margin="0" Padding="0,12,0,12">
|
||||||
|
<Grid Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Expander}}, Path=ActualWidth}" HorizontalAlignment="Left">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition
|
||||||
|
Width="auto"
|
||||||
|
MinWidth="20"
|
||||||
|
MaxWidth="60" />
|
||||||
|
<ColumnDefinition Width="7*" />
|
||||||
|
<ColumnDefinition Width="Auto" MinWidth="30" />
|
||||||
|
<ColumnDefinition Width="Auto" MinWidth="30" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ContentControl
|
||||||
|
x:Name="firstContentPresenter"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="0,0,14,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Content="{Binding SideContent, RelativeSource={RelativeSource AncestorType=local:ExCard}}" />
|
||||||
|
<TextBlock
|
||||||
|
x:Name="ItemIcon"
|
||||||
|
Grid.Column="0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{Binding Icon, RelativeSource={RelativeSource AncestorType=local:ExCard}}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ElementName=ItemIcon, Path=Text}" Value="{x:Static sys:String.Empty}">
|
||||||
|
<Setter Property="Margin" Value="24,0,0,0" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
<Setter Property="Grid.Column" Value="0" />
|
||||||
|
<Setter Property="Margin" Value="24,0,16,0" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="FontSize" Value="20" />
|
||||||
|
<Setter Property="FontFamily" Value="/Resources/#Segoe Fluent Icons" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
<StackPanel Grid.Column="1" Margin="0,0,14,0">
|
||||||
|
<StackPanel.Style>
|
||||||
|
<Style TargetType="{x:Type StackPanel}">
|
||||||
|
<Setter Property="Grid.Column" Value="1" />
|
||||||
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||||
|
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Style>
|
||||||
|
<TextBlock x:Name="ItemTitle" Text="{Binding Title, RelativeSource={RelativeSource AncestorType=local:ExCard}}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="TextWrapping" Value="Wrap" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock x:Name="SubTitle" Text="{Binding Sub, RelativeSource={RelativeSource AncestorType=local:ExCard}}">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ElementName=SubTitle, Path=Text}" Value="{x:Static sys:String.Empty}">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color04B}" />
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="Margin" Value="0,0,0,0" />
|
||||||
|
<Setter Property="Padding" Value="0,0,24,0" />
|
||||||
|
<Setter Property="TextWrapping" Value="WrapWithOverflow" />
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Expander.Header>
|
||||||
|
<Grid
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="4"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
FlowDirection="LeftToRight">
|
||||||
|
<StackPanel Margin="0,0,0,0" Orientation="Vertical">
|
||||||
|
<ContentControl
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.ColumnSpan="4"
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="{TemplateBinding Content}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Expander>
|
||||||
|
</ControlTemplate>
|
||||||
|
</UserControl.Template>
|
||||||
|
</UserControl>
|
||||||
57
Flow.Launcher/Resources/Controls/ExCard.xaml.cs
Normal file
57
Flow.Launcher/Resources/Controls/ExCard.xaml.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Resources.Controls
|
||||||
|
{
|
||||||
|
public partial class ExCard : UserControl
|
||||||
|
{
|
||||||
|
public ExCard()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(TitleProperty); }
|
||||||
|
set { SetValue(TitleProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty TitleProperty =
|
||||||
|
DependencyProperty.Register(nameof(Title), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty));
|
||||||
|
|
||||||
|
public string Sub
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(SubProperty); }
|
||||||
|
set { SetValue(SubProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty SubProperty =
|
||||||
|
DependencyProperty.Register(nameof(Sub), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty));
|
||||||
|
|
||||||
|
public string Icon
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(IconProperty); }
|
||||||
|
set { SetValue(IconProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty IconProperty =
|
||||||
|
DependencyProperty.Register(nameof(Icon), typeof(string), typeof(ExCard), new PropertyMetadata(string.Empty));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets additional content for the UserControl
|
||||||
|
/// </summary>
|
||||||
|
public object AdditionalContent
|
||||||
|
{
|
||||||
|
get { return (object)GetValue(AdditionalContentProperty); }
|
||||||
|
set { SetValue(AdditionalContentProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty AdditionalContentProperty =
|
||||||
|
DependencyProperty.Register(nameof(AdditionalContent), typeof(object), typeof(ExCard),
|
||||||
|
new PropertyMetadata(null));
|
||||||
|
|
||||||
|
public object SideContent
|
||||||
|
{
|
||||||
|
get { return (object)GetValue(SideContentProperty); }
|
||||||
|
set { SetValue(SideContentProperty, value); }
|
||||||
|
}
|
||||||
|
public static readonly DependencyProperty SideContentProperty =
|
||||||
|
DependencyProperty.Register(nameof(SideContent), typeof(object), typeof(ExCard),
|
||||||
|
new PropertyMetadata(null));
|
||||||
|
}
|
||||||
|
}
|
||||||
74
Flow.Launcher/Resources/Controls/HotkeyDisplay.xaml
Normal file
74
Flow.Launcher/Resources/Controls/HotkeyDisplay.xaml
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
<UserControl
|
||||||
|
x:Class="Flow.Launcher.Resources.Controls.HotkeyDisplay"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid>
|
||||||
|
<Button
|
||||||
|
Width="Auto"
|
||||||
|
FontSize="13"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Foreground="{DynamicResource Color01B}">
|
||||||
|
<Button.Template>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border
|
||||||
|
x:Name="ButtonBorder"
|
||||||
|
BorderBrush="{DynamicResource ButtonInsideBorder}"
|
||||||
|
CornerRadius="5">
|
||||||
|
<Border.Style>
|
||||||
|
<Style TargetType="{x:Type Border}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Color12B}" />
|
||||||
|
<Setter Property="Padding" Value="5,0,5,0" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource AncestorType=local:HotkeyDisplay}}" Value="Small">
|
||||||
|
<Setter Property="Background" Value="Transparent" />
|
||||||
|
<Setter Property="Padding" Value="0,0,0,0" />
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Style>
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Button.Template>
|
||||||
|
<Button.Content>
|
||||||
|
<ItemsControl x:Name="KeysControl">
|
||||||
|
<ItemsControl.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal" />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ItemsControl.ItemsPanel>
|
||||||
|
<ItemsControl.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Border BorderThickness="1" CornerRadius="5">
|
||||||
|
<Border.Style>
|
||||||
|
<Style TargetType="{x:Type Border}">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" />
|
||||||
|
<Setter Property="Padding" Value="10,5,10,5" />
|
||||||
|
<Setter Property="Margin" Value="2,5,2,5" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Type, RelativeSource={RelativeSource AncestorType=local:HotkeyDisplay}}" Value="Small">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AccentButtonBackground}" />
|
||||||
|
<Setter Property="Padding" Value="10,5,10,5" />
|
||||||
|
<Setter Property="Margin" Value="2,0,2,0" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Style>
|
||||||
|
<TextBlock Foreground="{DynamicResource AccentButtonForegroundPointerOver}" Text="{Binding}" />
|
||||||
|
</Border>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsControl.ItemTemplate>
|
||||||
|
</ItemsControl>
|
||||||
|
</Button.Content>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
63
Flow.Launcher/Resources/Controls/HotkeyDisplay.xaml.cs
Normal file
63
Flow.Launcher/Resources/Controls/HotkeyDisplay.xaml.cs
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Resources.Controls
|
||||||
|
{
|
||||||
|
public partial class HotkeyDisplay : UserControl
|
||||||
|
{
|
||||||
|
public enum DisplayType
|
||||||
|
{
|
||||||
|
Default,
|
||||||
|
Small
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeyDisplay()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
//List<string> stringList =e.NewValue.Split('+').ToList();
|
||||||
|
Values = new ObservableCollection<string>();
|
||||||
|
KeysControl.ItemsSource = Values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Keys
|
||||||
|
{
|
||||||
|
get { return (string)GetValue(KeysProperty); }
|
||||||
|
set { SetValue(KeysProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty KeysProperty =
|
||||||
|
DependencyProperty.Register(nameof(Keys), typeof(string), typeof(HotkeyDisplay),
|
||||||
|
new PropertyMetadata(string.Empty, keyChanged));
|
||||||
|
|
||||||
|
public DisplayType Type
|
||||||
|
{
|
||||||
|
get { return (DisplayType)GetValue(TypeProperty); }
|
||||||
|
set { SetValue(TypeProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty TypeProperty =
|
||||||
|
DependencyProperty.Register(nameof(Type), typeof(DisplayType), typeof(HotkeyDisplay),
|
||||||
|
new PropertyMetadata(DisplayType.Default));
|
||||||
|
|
||||||
|
private static void keyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var control = d as UserControl;
|
||||||
|
if (null == control) return; // This should not be possible
|
||||||
|
|
||||||
|
var newValue = e.NewValue as string;
|
||||||
|
if (null == newValue) return;
|
||||||
|
|
||||||
|
if (d is not HotkeyDisplay hotkeyDisplay)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hotkeyDisplay.Values.Clear();
|
||||||
|
foreach (var key in newValue.Split('+'))
|
||||||
|
{
|
||||||
|
hotkeyDisplay.Values.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<string> Values { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3283,5 +3283,416 @@
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- Content Dialog -->
|
||||||
|
<Style x:Key="ContentDialog" TargetType="ui:ContentDialog">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ContentDialogForeground}" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource ContentDialogBackground}" />
|
||||||
|
<Setter Property="BorderThickness" Value="{DynamicResource ContentDialogBorderWidth}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ContentDialogBorderBrush}" />
|
||||||
|
<Setter Property="IsTabStop" Value="False" />
|
||||||
|
<Setter Property="CornerRadius" Value="{DynamicResource OverlayCornerRadius}" />
|
||||||
|
<Setter Property="PrimaryButtonStyle" Value="{DynamicResource DefaultButtonStyle}" />
|
||||||
|
<Setter Property="SecondaryButtonStyle" Value="{DynamicResource DefaultButtonStyle}" />
|
||||||
|
<Setter Property="CloseButtonStyle" Value="{DynamicResource DefaultButtonStyle}" />
|
||||||
|
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
|
||||||
|
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled" />
|
||||||
|
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
|
||||||
|
<Setter Property="IsShadowEnabled" Value="{DynamicResource {x:Static SystemParameters.DropShadowKey}}" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="ui:ContentDialog">
|
||||||
|
<Border x:Name="Container">
|
||||||
|
<VisualStateManager.CustomVisualStateManager>
|
||||||
|
<ui:SimpleVisualStateManager />
|
||||||
|
</VisualStateManager.CustomVisualStateManager>
|
||||||
|
<Grid
|
||||||
|
x:Name="LayoutRoot"
|
||||||
|
Background="{DynamicResource ContentDialogOverlayBG}"
|
||||||
|
SnapsToDevicePixels="True"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<Grid
|
||||||
|
x:Name="BackgroundElement"
|
||||||
|
MinWidth="{DynamicResource ContentDialogMinWidth}"
|
||||||
|
MinHeight="{DynamicResource ContentDialogMinHeight}"
|
||||||
|
MaxWidth="{DynamicResource ContentDialogMaxWidth}"
|
||||||
|
MaxHeight="{DynamicResource ContentDialogMaxHeight}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FlowDirection="{TemplateBinding FlowDirection}"
|
||||||
|
RenderTransformOrigin="0.5,0.5">
|
||||||
|
<Grid.RenderTransform>
|
||||||
|
<ScaleTransform x:Name="ScaleTransform" />
|
||||||
|
</Grid.RenderTransform>
|
||||||
|
<ui:ThemeShadowChrome
|
||||||
|
x:Name="Shdw"
|
||||||
|
Margin="{DynamicResource ContentDialogBorderWidth}"
|
||||||
|
CornerRadius="{TemplateBinding CornerRadius}"
|
||||||
|
IsShadowEnabled="{TemplateBinding IsShadowEnabled}" />
|
||||||
|
<Border
|
||||||
|
Background="{TemplateBinding Background}"
|
||||||
|
BorderBrush="{TemplateBinding BorderBrush}"
|
||||||
|
BorderThickness="{TemplateBinding BorderThickness}"
|
||||||
|
CornerRadius="{TemplateBinding CornerRadius}">
|
||||||
|
<Border x:Name="DialogSpace" Padding="{DynamicResource ContentDialogPadding}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ScrollViewer
|
||||||
|
x:Name="ContentScrollViewer"
|
||||||
|
Margin="{DynamicResource ContentDialogContentScrollViewerMargin}"
|
||||||
|
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||||
|
IsTabStop="False"
|
||||||
|
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ContentControl
|
||||||
|
x:Name="Title"
|
||||||
|
Margin="{DynamicResource ContentDialogTitleMargin}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Content="{TemplateBinding Title}"
|
||||||
|
ContentTemplate="{TemplateBinding TitleTemplate}"
|
||||||
|
FontFamily="{DynamicResource {x:Static SystemFonts.MessageFontFamilyKey}}"
|
||||||
|
FontSize="20"
|
||||||
|
FontWeight="Normal"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
|
IsTabStop="False"
|
||||||
|
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
|
||||||
|
<ContentControl.Template>
|
||||||
|
<ControlTemplate TargetType="ContentControl">
|
||||||
|
<ui:ContentPresenterEx
|
||||||
|
Margin="{TemplateBinding Padding}"
|
||||||
|
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
Content="{TemplateBinding Content}"
|
||||||
|
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</ContentControl.Template>
|
||||||
|
</ContentControl>
|
||||||
|
<ui:ContentPresenterEx
|
||||||
|
x:Name="Content"
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="{DynamicResource ContentDialogContentMargin}"
|
||||||
|
Content="{TemplateBinding Content}"
|
||||||
|
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||||
|
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
|
||||||
|
TextElement.FontFamily="{DynamicResource ContentControlThemeFontFamily}"
|
||||||
|
TextElement.FontSize="{DynamicResource ControlContentThemeFontSize}"
|
||||||
|
TextElement.Foreground="{TemplateBinding Foreground}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
<Grid
|
||||||
|
x:Name="CommandSpace"
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="{DynamicResource ContentDialogCommandSpaceMargin}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
KeyboardNavigation.DirectionalNavigation="Contained">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="0.5*" />
|
||||||
|
<ColumnDefinition Width="0.5*" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button
|
||||||
|
x:Name="PrimaryButton"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,2,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Content="{TemplateBinding PrimaryButtonText}"
|
||||||
|
IsEnabled="{TemplateBinding IsPrimaryButtonEnabled}"
|
||||||
|
Style="{TemplateBinding PrimaryButtonStyle}" />
|
||||||
|
<Button
|
||||||
|
x:Name="SecondaryButton"
|
||||||
|
Grid.Column="1"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
Margin="2,0,2,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Content="{TemplateBinding SecondaryButtonText}"
|
||||||
|
IsEnabled="{TemplateBinding IsSecondaryButtonEnabled}"
|
||||||
|
Style="{TemplateBinding SecondaryButtonStyle}" />
|
||||||
|
<Button
|
||||||
|
x:Name="CloseButton"
|
||||||
|
Grid.Column="3"
|
||||||
|
Margin="2,0,0,0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
Content="{TemplateBinding CloseButtonText}"
|
||||||
|
Style="{TemplateBinding CloseButtonStyle}" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<VisualStateManager.VisualStateGroups>
|
||||||
|
<VisualStateGroup x:Name="DialogShowingStates">
|
||||||
|
<VisualStateGroup.Transitions>
|
||||||
|
<VisualTransition To="DialogHidden">
|
||||||
|
<Storyboard>
|
||||||
|
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="SnapsToDevicePixels">
|
||||||
|
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
|
||||||
|
</BooleanAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="IsHitTestVisible">
|
||||||
|
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
|
||||||
|
</BooleanAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleX">
|
||||||
|
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
|
||||||
|
<SplineDoubleKeyFrame
|
||||||
|
KeySpline="0.1,0.9 0.2,1.0"
|
||||||
|
KeyTime="0:0:0.5"
|
||||||
|
Value="1.05" />
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleY">
|
||||||
|
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
|
||||||
|
<SplineDoubleKeyFrame
|
||||||
|
KeySpline="0.1,0.9 0.2,1.0"
|
||||||
|
KeyTime="0:0:0.5"
|
||||||
|
Value="1.05" />
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Opacity">
|
||||||
|
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.0" />
|
||||||
|
<LinearDoubleKeyFrame KeyTime="0:0:0.083" Value="0.0" />
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualTransition>
|
||||||
|
<VisualTransition To="DialogShowing">
|
||||||
|
<Storyboard>
|
||||||
|
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="SnapsToDevicePixels">
|
||||||
|
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="False" />
|
||||||
|
</BooleanAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleX">
|
||||||
|
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.05" />
|
||||||
|
<SplineDoubleKeyFrame
|
||||||
|
KeySpline="0.1,0.9 0.2,1.0"
|
||||||
|
KeyTime="0:0:0.5"
|
||||||
|
Value="1.0" />
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ScaleTransform" Storyboard.TargetProperty="ScaleY">
|
||||||
|
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.05" />
|
||||||
|
<SplineDoubleKeyFrame
|
||||||
|
KeySpline="0.1,0.9 0.2,1.0"
|
||||||
|
KeyTime="0:0:0.5"
|
||||||
|
Value="1.0" />
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Opacity">
|
||||||
|
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0.0" />
|
||||||
|
<LinearDoubleKeyFrame KeyTime="0:0:0.167" Value="1.0" />
|
||||||
|
</DoubleAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualTransition>
|
||||||
|
</VisualStateGroup.Transitions>
|
||||||
|
<VisualState x:Name="DialogHidden" />
|
||||||
|
<VisualState x:Name="DialogShowing">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="(KeyboardNavigation.TabNavigation)">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static KeyboardNavigationMode.Cycle}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="DialogShowingWithoutSmokeLayer">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="Background">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Null}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="DialogSizingStates">
|
||||||
|
<VisualState x:Name="DefaultDialogSizing" />
|
||||||
|
<VisualState x:Name="FullDialogSizing">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="VerticalAlignment">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static VerticalAlignment.Stretch}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="ButtonsVisibilityStates">
|
||||||
|
<VisualState x:Name="AllVisible" />
|
||||||
|
<VisualState x:Name="NoneVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CommandSpace" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="PrimaryVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="2,0,0,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="SecondaryVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="2,0,0,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="CloseVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="2,0,0,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="PrimaryAndSecondaryVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="2,0,0,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="PrimaryAndCloseVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="2,0,0,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="SecondaryAndCloseVisible">
|
||||||
|
<Storyboard>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="0" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="SecondaryButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="0,0,2,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="(Grid.Column)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<Int32AnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="(Grid.ColumnSpan)">
|
||||||
|
<DiscreteInt32KeyFrame KeyTime="0:0:0" Value="2" />
|
||||||
|
</Int32AnimationUsingKeyFrames>
|
||||||
|
<ThicknessAnimationUsingKeyFrames Storyboard.TargetName="CloseButton" Storyboard.TargetProperty="Margin">
|
||||||
|
<DiscreteThicknessKeyFrame KeyTime="0:0:0" Value="2,0,0,0" />
|
||||||
|
</ThicknessAnimationUsingKeyFrames>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PrimaryButton" Storyboard.TargetProperty="Visibility">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Collapsed}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="DefaultButtonStates">
|
||||||
|
<VisualState x:Name="NoDefaultButton" />
|
||||||
|
<VisualState x:Name="PrimaryAsDefaultButton" />
|
||||||
|
<VisualState x:Name="SecondaryAsDefaultButton" />
|
||||||
|
<VisualState x:Name="CloseAsDefaultButton" />
|
||||||
|
</VisualStateGroup>
|
||||||
|
<VisualStateGroup x:Name="DialogBorderStates">
|
||||||
|
<VisualState x:Name="NoBorder" />
|
||||||
|
<VisualState x:Name="AccentColorBorder">
|
||||||
|
<Storyboard>
|
||||||
|
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="BackgroundElement" Storyboard.TargetProperty="BorderBrush">
|
||||||
|
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{DynamicResource SystemControlForegroundAccentBrush}" />
|
||||||
|
</ObjectAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsShadowEnabled" Value="False">
|
||||||
|
<Setter TargetName="Shdw" Property="Visibility" Value="Collapsed" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="DefaultButton" Value="Primary">
|
||||||
|
<Setter TargetName="PrimaryButton" Property="Style" Value="{DynamicResource AccentButtonStyle}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="DefaultButton" Value="Secondary">
|
||||||
|
<Setter TargetName="SecondaryButton" Property="Style" Value="{DynamicResource AccentButtonStyle}" />
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="DefaultButton" Value="Close">
|
||||||
|
<Setter TargetName="CloseButton" Property="Style" Value="{DynamicResource AccentButtonStyle}" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,16 @@
|
||||||
<Color x:Key="NumberBoxColor26">#ffffff</Color>
|
<Color x:Key="NumberBoxColor26">#ffffff</Color>
|
||||||
<Color x:Key="HoverStoreGrid">#272727</Color>
|
<Color x:Key="HoverStoreGrid">#272727</Color>
|
||||||
|
|
||||||
|
<!-- Resources for HotkeyControl -->
|
||||||
|
<SolidColorBrush x:Key="CustomHotkeyHover" Color="#323232" />
|
||||||
|
<!-- Resources for Expander -->
|
||||||
|
<SolidColorBrush x:Key="CustomExpanderHover" Color="#323232" />
|
||||||
|
<!-- Resource for ContentDialog -->
|
||||||
|
<SolidColorBrush x:Key="ContentDialogOverlayBG" Color="#4D000000" />
|
||||||
|
<!-- Infobar Warning -->
|
||||||
|
<SolidColorBrush x:Key="InfoBarWarningIcon" Color="#FCE100" />
|
||||||
|
<SolidColorBrush x:Key="InfoBarWarningBG" Color="#433519" />
|
||||||
|
<SolidColorBrush x:Key="InfoBarBD" Color="#19000000" />
|
||||||
|
|
||||||
<SolidColorBrush x:Key="ButtonOutBorder" Color="Transparent" />
|
<SolidColorBrush x:Key="ButtonOutBorder" Color="Transparent" />
|
||||||
<SolidColorBrush x:Key="ButtonInsideBorder" Color="#3f3f3f" />
|
<SolidColorBrush x:Key="ButtonInsideBorder" Color="#3f3f3f" />
|
||||||
|
|
@ -772,7 +782,7 @@
|
||||||
<m:StaticResource x:Key="ContentDialogForeground" ResourceKey="SystemControlPageTextBaseHighBrush" />
|
<m:StaticResource x:Key="ContentDialogForeground" ResourceKey="SystemControlPageTextBaseHighBrush" />
|
||||||
<m:StaticResource x:Key="ContentDialogBackground" ResourceKey="SystemControlPageBackgroundAltHighBrush" />
|
<m:StaticResource x:Key="ContentDialogBackground" ResourceKey="SystemControlPageBackgroundAltHighBrush" />
|
||||||
<m:StaticResource x:Key="ContentDialogBorderBrush" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
<m:StaticResource x:Key="ContentDialogBorderBrush" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||||
<m:StaticResource x:Key="ContentDialogLightDismissOverlayBackground" ResourceKey="SystemControlPageBackgroundMediumAltMediumBrush" />
|
<m:StaticResource x:Key="ContentDialogLightDismissOverlayBackground" ResourceKey="ContentDialogOverlayBG" />
|
||||||
|
|
||||||
<!-- Resources for DataGrid -->
|
<!-- Resources for DataGrid -->
|
||||||
<sys:Double x:Key="ListAccentLowOpacity">0.6</sys:Double>
|
<sys:Double x:Key="ListAccentLowOpacity">0.6</sys:Double>
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,17 @@
|
||||||
<Color x:Key="NumberBoxColor26">#1b1b1b</Color>
|
<Color x:Key="NumberBoxColor26">#1b1b1b</Color>
|
||||||
<Color x:Key="HoverStoreGrid">#f6f6f6</Color>
|
<Color x:Key="HoverStoreGrid">#f6f6f6</Color>
|
||||||
|
|
||||||
|
<!-- Resources for HotkeyControl -->
|
||||||
|
<SolidColorBrush x:Key="CustomHotkeyHover" Color="#f6f6f6" />
|
||||||
|
<!-- Resources for Expander -->
|
||||||
|
<SolidColorBrush x:Key="CustomExpanderHover" Color="#f6f6f6" />
|
||||||
|
<!-- Resource for ContentDialog -->
|
||||||
|
<SolidColorBrush x:Key="ContentDialogOverlayBG" Color="#4D000000" />
|
||||||
|
<!-- Infobar Warning -->
|
||||||
|
<SolidColorBrush x:Key="InfoBarWarningIcon" Color="#9D5D00" />
|
||||||
|
<SolidColorBrush x:Key="InfoBarWarningBG" Color="#FFF4CE" />
|
||||||
|
<SolidColorBrush x:Key="InfoBarBD" Color="#0F000000" />
|
||||||
|
|
||||||
|
|
||||||
<SolidColorBrush x:Key="ButtonOutBorder" Color="#e5e5e5" />
|
<SolidColorBrush x:Key="ButtonOutBorder" Color="#e5e5e5" />
|
||||||
<SolidColorBrush x:Key="ButtonInsideBorder" Color="#d3d3d3" />
|
<SolidColorBrush x:Key="ButtonInsideBorder" Color="#d3d3d3" />
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
Title="WelcomePage2"
|
Title="WelcomePage2"
|
||||||
|
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<converters:BorderClipConverter x:Key="BorderClipConverter" />
|
<converters:BorderClipConverter x:Key="BorderClipConverter" />
|
||||||
|
|
@ -110,12 +111,13 @@
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Text="{DynamicResource flowlauncherHotkey}" />
|
Text="{DynamicResource flowlauncherHotkey}" />
|
||||||
<flowlauncher:HotkeyControl
|
<flowlauncher:HotkeyControl
|
||||||
x:Name="HotkeyControl"
|
Margin="0,8,0,0"
|
||||||
Width="300"
|
ChangeHotkey="{Binding SetTogglingHotkeyCommand}"
|
||||||
Height="35"
|
DefaultHotkey="Alt+Space"
|
||||||
Margin="-206,10,0,0"
|
Hotkey="{Binding Settings.Hotkey}"
|
||||||
GotFocus="HotkeyControl_OnGotFocus"
|
HotkeySettings="{Binding Settings}"
|
||||||
LostFocus="HotkeyControl_OnLostFocus"/>
|
ValidateKeyGesture="True"
|
||||||
|
WindowTitle="{DynamicResource flowlauncherHotkey}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,14 @@ using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using Flow.Launcher.ViewModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.Resources.Pages
|
namespace Flow.Launcher.Resources.Pages
|
||||||
{
|
{
|
||||||
public partial class WelcomePage2
|
public partial class WelcomePage2
|
||||||
{
|
{
|
||||||
private Settings Settings { get; set; }
|
public Settings Settings { get; set; }
|
||||||
|
|
||||||
private Brush tbMsgForegroundColorOriginal;
|
|
||||||
|
|
||||||
private string tbMsgTextOriginal;
|
|
||||||
|
|
||||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||||
{
|
{
|
||||||
|
|
@ -22,31 +20,14 @@ namespace Flow.Launcher.Resources.Pages
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
else
|
else
|
||||||
throw new ArgumentException("Unexpected Parameter setting.");
|
throw new ArgumentException("Unexpected Parameter setting.");
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
tbMsgTextOriginal = HotkeyControl.tbMsg.Text;
|
|
||||||
tbMsgForegroundColorOriginal = HotkeyControl.tbMsg.Foreground;
|
|
||||||
|
|
||||||
HotkeyControl.SetHotkeyAsync(Settings.Hotkey, false);
|
|
||||||
}
|
}
|
||||||
private void HotkeyControl_OnGotFocus(object sender, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
HotKeyMapper.RemoveHotkey(Settings.Hotkey);
|
|
||||||
}
|
|
||||||
private void HotkeyControl_OnLostFocus(object sender, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
if (HotkeyControl.CurrentHotkeyAvailable)
|
|
||||||
{
|
|
||||||
HotKeyMapper.SetHotkey(HotkeyControl.CurrentHotkey, HotKeyMapper.OnToggleHotkey);
|
|
||||||
Settings.Hotkey = HotkeyControl.CurrentHotkey.ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HotKeyMapper.SetHotkey(new HotkeyModel(Settings.Hotkey), HotKeyMapper.OnToggleHotkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
HotkeyControl.tbMsg.Text = tbMsgTextOriginal;
|
[RelayCommand]
|
||||||
HotkeyControl.tbMsg.Foreground = tbMsgForegroundColorOriginal;
|
private static void SetTogglingHotkey(HotkeyModel hotkey)
|
||||||
|
{
|
||||||
|
HotKeyMapper.SetHotkey(hotkey, HotKeyMapper.OnToggleHotkey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@
|
||||||
x:Class="Flow.Launcher.Resources.Pages.WelcomePage3"
|
x:Class="Flow.Launcher.Resources.Pages.WelcomePage3"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
|
xmlns:local="clr-namespace:Flow.Launcher.Resources.Pages"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
Title="WelcomePage3"
|
Title="WelcomePage3"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<Style x:Key="KbdLine" TargetType="Border">
|
<Style x:Key="KbdLine" TargetType="Border">
|
||||||
|
|
@ -27,301 +29,86 @@
|
||||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||||
</Style>
|
</Style>
|
||||||
</Page.Resources>
|
</Page.Resources>
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
<Grid>
|
||||||
<Grid>
|
<Grid.RowDefinitions>
|
||||||
<Grid.RowDefinitions>
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="0" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition />
|
</Grid.RowDefinitions>
|
||||||
</Grid.RowDefinitions>
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
<Border Grid.Row="0" HorizontalAlignment="Stretch">
|
Margin="24,20,24,14"
|
||||||
<Border.Background>
|
FontSize="20"
|
||||||
<LinearGradientBrush StartPoint="0 0" EndPoint="1 1">
|
FontWeight="SemiBold"
|
||||||
<LinearGradientBrush.GradientStops>
|
Text="{DynamicResource Welcome_Page3_Title}" />
|
||||||
<GradientStop Offset="0.0" Color="#16af7b" />
|
<ScrollViewer
|
||||||
<GradientStop Offset="1.0" Color="#34c191" />
|
Grid.Row="1"
|
||||||
</LinearGradientBrush.GradientStops>
|
Height="478"
|
||||||
</LinearGradientBrush>
|
Margin="0,0,0,0"
|
||||||
</Border.Background>
|
HorizontalAlignment="Stretch"
|
||||||
|
FontSize="13">
|
||||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
<StackPanel Margin="24,0,24,0">
|
||||||
<Image
|
<Border
|
||||||
Width="300"
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
Height="100"
|
BorderThickness="0"
|
||||||
Margin="0,0,0,0"
|
CornerRadius="5">
|
||||||
Source="../../images/page_img02.png"
|
<StackPanel>
|
||||||
Style="{DynamicResource StyleImageFadeIn}" />
|
<cc:Card
|
||||||
</StackPanel>
|
Title="{DynamicResource HotkeyUpDownDesc}"
|
||||||
</Border>
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
<ScrollViewer
|
|
||||||
Grid.Row="1"
|
|
||||||
HorizontalScrollBarVisibility="Auto"
|
|
||||||
VerticalScrollBarVisibility="Auto">
|
|
||||||
<Grid>
|
|
||||||
<StackPanel Margin="24,20,24,20">
|
|
||||||
<StackPanel Margin="0,0,0,10">
|
|
||||||
<TextBlock
|
|
||||||
FontSize="20"
|
|
||||||
FontWeight="SemiBold"
|
|
||||||
Text="{DynamicResource Welcome_Page3_Title}" />
|
|
||||||
</StackPanel>
|
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel
|
<cc:HotkeyDisplay Keys="←+→" Type="Small" />
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}">←</TextBlock>
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">,</TextBlock>
|
|
||||||
<Border Margin="5,0,0,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}">→</TextBlock>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyUpDownDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
Title="{DynamicResource HotkeyLeftRightDesc}"
|
||||||
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel
|
<cc:HotkeyDisplay Keys="↑+↓" Type="Small" />
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}">↑</TextBlock>
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">,</TextBlock>
|
|
||||||
<Border Margin="5,0,0,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}">↓</TextBlock>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyLeftRightDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
Title="{DynamicResource HotkeyESCDesc}"
|
||||||
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel
|
<cc:HotkeyDisplay Keys="ESC" Type="Small" />
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}">Enter</TextBlock>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyRunDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
Title="{DynamicResource HotkeyRunDesc}"
|
||||||
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
|
<cc:HotkeyDisplay Keys="ENTER" Type="Small" />
|
||||||
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource HotkeyShiftEnterDesc}"
|
||||||
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel
|
<cc:HotkeyDisplay Keys="SHIFT+ENTER" Type="Small" />
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="ESC" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyESCDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
Title="{DynamicResource HotkeyCtrlEnterDesc}"
|
||||||
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel
|
<cc:HotkeyDisplay Keys="CTRL+ENTER" Type="Small" />
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Tab" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyTabDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
Title="{DynamicResource HotkeyCtrlShiftEnterDesc}"
|
||||||
|
BorderThickness="0,0,0,0"
|
||||||
|
Type="Inside">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<StackPanel
|
<cc:HotkeyDisplay Keys="CTRL+SHIFT+ENTER" Type="Small" />
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Shift" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">+</TextBlock>
|
|
||||||
<Border Margin="5,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="ENTER" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyShiftEnterDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</cc:Card>
|
||||||
|
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<StackPanel
|
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Ctrl" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">+</TextBlock>
|
|
||||||
<Border Margin="5,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="ENTER" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyCtrlEnterDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<StackPanel
|
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Ctrl" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">+</TextBlock>
|
|
||||||
<Border Margin="5,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Shift" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">+</TextBlock>
|
|
||||||
<Border Margin="5,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="ENTER" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyCtrlShiftEnterDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<StackPanel
|
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Ctrl" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">+</TextBlock>
|
|
||||||
<Border Margin="5,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="H" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyCtrlHDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<StackPanel
|
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="Ctrl" />
|
|
||||||
</Border>
|
|
||||||
<TextBlock VerticalAlignment="Center">+</TextBlock>
|
|
||||||
<Border Margin="5,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="I" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyCtrlIDesc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<Border Style="{DynamicResource KbdLine}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<StackPanel
|
|
||||||
Width="210"
|
|
||||||
Margin="20,5,4,5"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Border Margin="0,0,5,0" Style="{DynamicResource Kbd}">
|
|
||||||
<TextBlock Style="{DynamicResource KbdText}" Text="F5" />
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel VerticalAlignment="Center">
|
|
||||||
<TextBlock
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="13"
|
|
||||||
Text="{DynamicResource HotkeyF5Desc}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Border>
|
||||||
</ScrollViewer>
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
|
||||||
</ui:Page>
|
</ui:Page>
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,6 +2,7 @@
|
||||||
x:Class="Flow.Launcher.SettingWindow"
|
x:Class="Flow.Launcher.SettingWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||||
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
|
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
|
||||||
xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core"
|
xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
|
@ -67,6 +68,20 @@
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style x:Key="SwitchFocusVisualStyleKey">
|
||||||
|
<Setter Property="Control.Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate>
|
||||||
|
<Rectangle
|
||||||
|
Margin="-8,-4,-8,-4"
|
||||||
|
RadiusX="5"
|
||||||
|
RadiusY="5"
|
||||||
|
Stroke="{DynamicResource Color05B}"
|
||||||
|
StrokeThickness="2" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
<Style x:Key="SettingGrid" TargetType="ItemsControl">
|
<Style x:Key="SettingGrid" TargetType="ItemsControl">
|
||||||
<Setter Property="Focusable" Value="False" />
|
<Setter Property="Focusable" Value="False" />
|
||||||
<Setter Property="Margin" Value="0" />
|
<Setter Property="Margin" Value="0" />
|
||||||
|
|
@ -137,6 +152,7 @@
|
||||||
<Setter Property="Grid.Column" Value="2" />
|
<Setter Property="Grid.Column" Value="2" />
|
||||||
<Setter Property="FocusVisualMargin" Value="5" />
|
<Setter Property="FocusVisualMargin" Value="5" />
|
||||||
<Setter Property="Width" Value="Auto" />
|
<Setter Property="Width" Value="Auto" />
|
||||||
|
<Setter Property="FocusVisualStyle" Value="{DynamicResource SwitchFocusVisualStyleKey}" />
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
||||||
<Setter Property="OffContent" Value="{DynamicResource disable}" />
|
<Setter Property="OffContent" Value="{DynamicResource disable}" />
|
||||||
|
|
@ -447,7 +463,10 @@
|
||||||
IsItemsHost="true"
|
IsItemsHost="true"
|
||||||
LastChildFill="False" />
|
LastChildFill="False" />
|
||||||
<Border Grid.Column="1">
|
<Border Grid.Column="1">
|
||||||
<ContentPresenter Grid.Column="1" ContentSource="SelectedContent" />
|
<ContentPresenter
|
||||||
|
x:Name="PART_SelectedContentHost"
|
||||||
|
Grid.Column="1"
|
||||||
|
ContentSource="SelectedContent" />
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
|
|
@ -693,7 +712,7 @@
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
Margin="0,30,0,0"
|
Margin="0,30,0,0"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
Style="{DynamicResource SettingGroupBox}">
|
Style="{DynamicResource SettingGroupBox}">
|
||||||
|
|
@ -720,7 +739,7 @@
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="SelectScreen"
|
x:Name="SelectScreen"
|
||||||
MinWidth="160"
|
MinWidth="160"
|
||||||
Margin="0,0,18,0"
|
Margin="0,0,18,0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
ItemsSource="{Binding ScreenNumbers}"
|
ItemsSource="{Binding ScreenNumbers}"
|
||||||
|
|
@ -738,14 +757,12 @@
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Style="{StaticResource Glyph}">
|
<TextBlock Style="{StaticResource Glyph}">
|
||||||

|

|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Separator
|
<Separator Width="Auto" BorderThickness="1">
|
||||||
Width="Auto"
|
|
||||||
BorderThickness="1">
|
|
||||||
<Separator.Style>
|
<Separator.Style>
|
||||||
<Style BasedOn="{StaticResource SettingSeparatorStyle}" TargetType="Separator">
|
<Style BasedOn="{StaticResource SettingSeparatorStyle}" TargetType="Separator">
|
||||||
<Setter Property="Visibility" Value="Visible" />
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
|
@ -758,9 +775,7 @@
|
||||||
</Separator.Style>
|
</Separator.Style>
|
||||||
</Separator>
|
</Separator>
|
||||||
|
|
||||||
<Border
|
<Border Margin="0" BorderThickness="0">
|
||||||
Margin="0"
|
|
||||||
BorderThickness="0">
|
|
||||||
<Border.Style>
|
<Border.Style>
|
||||||
<Style BasedOn="{StaticResource SettingGroupBox}" TargetType="Border">
|
<Style BasedOn="{StaticResource SettingGroupBox}" TargetType="Border">
|
||||||
<Setter Property="Visibility" Value="Visible" />
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
|
@ -786,8 +801,7 @@
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
ItemsSource="{Binding SearchWindowAligns}"
|
ItemsSource="{Binding SearchWindowAligns}"
|
||||||
SelectedValue="{Binding Settings.SearchWindowAlign}"
|
SelectedValue="{Binding Settings.SearchWindowAlign}"
|
||||||
SelectedValuePath="Value">
|
SelectedValuePath="Value" />
|
||||||
</ComboBox>
|
|
||||||
<StackPanel Margin="0,0,18,0" Orientation="Horizontal">
|
<StackPanel Margin="0,0,18,0" Orientation="Horizontal">
|
||||||
<StackPanel.Style>
|
<StackPanel.Style>
|
||||||
<Style TargetType="StackPanel">
|
<Style TargetType="StackPanel">
|
||||||
|
|
@ -817,7 +831,7 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock Style="{StaticResource Glyph}">
|
<TextBlock Style="{StaticResource Glyph}">
|
||||||

|

|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
@ -2446,8 +2460,7 @@
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
ItemsSource="{Binding AnimationSpeeds}"
|
ItemsSource="{Binding AnimationSpeeds}"
|
||||||
SelectedValue="{Binding Settings.AnimationSpeed}"
|
SelectedValue="{Binding Settings.AnimationSpeed}"
|
||||||
SelectedValuePath="Value">
|
SelectedValuePath="Value" />
|
||||||
</ComboBox>
|
|
||||||
<StackPanel Margin="0,0,18,0" Orientation="Horizontal">
|
<StackPanel Margin="0,0,18,0" Orientation="Horizontal">
|
||||||
<StackPanel.Style>
|
<StackPanel.Style>
|
||||||
<Style TargetType="StackPanel">
|
<Style TargetType="StackPanel">
|
||||||
|
|
@ -2474,27 +2487,81 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
Margin="0"
|
Margin="0,12,0,12"
|
||||||
BorderThickness="0"
|
Padding="0"
|
||||||
|
CornerRadius="5"
|
||||||
Style="{DynamicResource SettingGroupBox}">
|
Style="{DynamicResource SettingGroupBox}">
|
||||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
<StackPanel Orientation="Vertical">
|
||||||
<StackPanel Style="{StaticResource TextPanel}">
|
<Border
|
||||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource SoundEffect}" />
|
Margin="0"
|
||||||
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource SoundEffectTip}" />
|
BorderThickness="0"
|
||||||
</StackPanel>
|
Style="{DynamicResource SettingGroupBox}">
|
||||||
<ui:ToggleSwitch
|
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||||
|
<StackPanel Style="{StaticResource TextPanel}">
|
||||||
|
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource SoundEffect}" />
|
||||||
|
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource SoundEffectTip}" />
|
||||||
|
</StackPanel>
|
||||||
|
<ui:ToggleSwitch
|
||||||
|
x:Name="SoundEffect"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
IsOn="{Binding UseSound, Mode=TwoWay}"
|
IsOn="{Binding UseSound, Mode=TwoWay}"
|
||||||
OffContent="{DynamicResource disable}"
|
OffContent="{DynamicResource disable}"
|
||||||
OnContent="{DynamicResource enable}"
|
OnContent="{DynamicResource enable}"
|
||||||
Style="{DynamicResource SideToggleSwitch}" />
|
Style="{DynamicResource SideToggleSwitch}" />
|
||||||
<TextBlock Style="{StaticResource Glyph}">
|
<TextBlock Style="{StaticResource Glyph}">
|
||||||
|

|
||||||
|
</TextBlock>
|
||||||
|
</ItemsControl>
|
||||||
|
</Border>
|
||||||
|
<Separator
|
||||||
|
Width="Auto"
|
||||||
|
BorderThickness="1"
|
||||||
|
Style="{StaticResource SettingSeparatorStyle}" />
|
||||||
|
<Border Margin="0" BorderThickness="0">
|
||||||
|
<Border.Style>
|
||||||
|
<Style BasedOn="{StaticResource SettingGroupBox}" TargetType="Border">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ElementName=SoundEffect, Path=IsOn}" Value="True">
|
||||||
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Border.Style>
|
||||||
|
|
||||||
|
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||||
|
<StackPanel Style="{StaticResource TextPanel}">
|
||||||
|
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource SoundEffectVolume}" />
|
||||||
|
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource SoundEffectVolumeTip}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Width="Auto"
|
||||||
|
Margin="0,0,8,2"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Foreground="{DynamicResource Color05B}"
|
||||||
|
Text="{Binding ElementName=SoundEffectValue, Path=Value, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
TextAlignment="Right" />
|
||||||
|
<Slider
|
||||||
|
Name="SoundEffectValue"
|
||||||
|
Width="250"
|
||||||
|
Margin="0,0,18,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
IsMoveToPointEnabled="True"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
Maximum="100"
|
||||||
|
Minimum="0"
|
||||||
|
TickFrequency="1"
|
||||||
|
Value="{Binding SoundEffectVolume, Mode=TwoWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
<TextBlock Style="{StaticResource Glyph}">
|
||||||

|

|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<Border Margin="0,12,0,12" Style="{DynamicResource SettingGroupBox}">
|
<Border Margin="0,12,0,12" Style="{DynamicResource SettingGroupBox}">
|
||||||
|
|
@ -2581,63 +2648,39 @@
|
||||||
<StackPanel Margin="5,18,18,10">
|
<StackPanel Margin="5,18,18,10">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0,5,0,2"
|
Margin="0,5,0,6"
|
||||||
FontSize="30"
|
FontSize="30"
|
||||||
Style="{StaticResource PageTitle}"
|
Style="{StaticResource PageTitle}"
|
||||||
Text="{DynamicResource hotkeys}"
|
Text="{DynamicResource hotkeys}"
|
||||||
TextAlignment="left" />
|
TextAlignment="left" />
|
||||||
|
|
||||||
<StackPanel Grid.Row="1">
|
<StackPanel Grid.Row="1">
|
||||||
<Border Margin="0,8,0,0" Style="{DynamicResource SettingGroupBox}">
|
<cc:Card
|
||||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
Title="{DynamicResource flowlauncherHotkey}"
|
||||||
<StackPanel Style="{StaticResource TextPanel}">
|
Icon=""
|
||||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource flowlauncherHotkey}" />
|
Sub="{DynamicResource flowlauncherHotkeyToolTip}">
|
||||||
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource flowlauncherHotkeyToolTip}" />
|
<flowlauncher:HotkeyControl
|
||||||
</StackPanel>
|
ChangeHotkey="{Binding SetTogglingHotkeyCommand}"
|
||||||
<flowlauncher:HotkeyControl
|
DefaultHotkey="Alt+Space"
|
||||||
x:Name="HotkeyControl"
|
Hotkey="{Binding Settings.Hotkey}"
|
||||||
Grid.Row="0"
|
HotkeySettings="{Binding Settings}"
|
||||||
Grid.Column="2"
|
ValidateKeyGesture="True"
|
||||||
Width="300"
|
WindowTitle="{DynamicResource flowlauncherHotkey}" />
|
||||||
Height="35"
|
</cc:Card>
|
||||||
Margin="0,0,0,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
HorizontalContentAlignment="Right"
|
|
||||||
GotFocus="OnHotkeyControlFocused"
|
|
||||||
Loaded="OnHotkeyControlLoaded"
|
|
||||||
LostFocus="OnHotkeyControlFocusLost" />
|
|
||||||
|
|
||||||
<TextBlock Style="{StaticResource Glyph}">
|
|
||||||

|
|
||||||
</TextBlock>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel Grid.Row="2">
|
<StackPanel Grid.Row="2">
|
||||||
<Border Margin="0,8,0,0" Style="{DynamicResource SettingGroupBox}">
|
<cc:Card
|
||||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
Title="{DynamicResource previewHotkey}"
|
||||||
<StackPanel Style="{StaticResource TextPanel}">
|
Icon=""
|
||||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource previewHotkey}" />
|
Sub="{DynamicResource previewHotkeyToolTip}">
|
||||||
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource previewHotkeyToolTip}" />
|
<flowlauncher:HotkeyControl
|
||||||
</StackPanel>
|
DefaultHotkey="F1"
|
||||||
<flowlauncher:HotkeyControl
|
Hotkey="{Binding Settings.PreviewHotkey}"
|
||||||
x:Name="PreviewHotkeyControl"
|
HotkeySettings="{Binding Settings}"
|
||||||
Grid.Row="0"
|
ValidateKeyGesture="False"
|
||||||
Grid.Column="2"
|
WindowTitle="{DynamicResource previewHotkey}" />
|
||||||
Width="300"
|
</cc:Card>
|
||||||
Height="35"
|
|
||||||
Margin="0,0,0,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
HorizontalContentAlignment="Right"
|
|
||||||
Loaded="OnPreviewHotkeyControlLoaded"
|
|
||||||
LostFocus="OnPreviewHotkeyControlFocusLost"
|
|
||||||
ValidateKeyGesture="True" />
|
|
||||||
<TextBlock Style="{StaticResource Glyph}">
|
|
||||||

|
|
||||||
</TextBlock>
|
|
||||||
</ItemsControl>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Border
|
<Border
|
||||||
|
|
@ -2697,163 +2740,374 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<TextBlock
|
<StackPanel Grid.Row="2">
|
||||||
Grid.Row="4"
|
<cc:ExCard
|
||||||
Margin="0,10,12,10"
|
Title="{DynamicResource hotkeyPresets}"
|
||||||
Padding="0,12,0,0"
|
Margin="0,14,0,0"
|
||||||
VerticalAlignment="Center"
|
Icon=""
|
||||||
FontSize="14"
|
Sub="{DynamicResource hotkeyPresetsToolTip}">
|
||||||
Foreground="{DynamicResource Color05B}"
|
<StackPanel>
|
||||||
Text="{DynamicResource customQueryHotkey}" />
|
<cc:Card
|
||||||
<ListView
|
Title="{DynamicResource OpenContainFolderHotkey}"
|
||||||
Grid.Row="5"
|
Icon=""
|
||||||
MinHeight="160"
|
Type="Inside">
|
||||||
Margin="0,0,0,0"
|
<cc:HotkeyDisplay Keys="Ctrl+Enter" />
|
||||||
Background="{DynamicResource Color02B}"
|
</cc:Card>
|
||||||
BorderBrush="DarkGray"
|
<cc:Card
|
||||||
BorderThickness="1"
|
Title="{DynamicResource RunAsAdminHotkey}"
|
||||||
ItemsSource="{Binding Settings.CustomPluginHotkeys}"
|
Icon=""
|
||||||
SelectedItem="{Binding SelectedCustomPluginHotkey}"
|
Type="Inside">
|
||||||
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
<cc:HotkeyDisplay Keys="Ctrl+Shift+Enter" />
|
||||||
<ListView.View>
|
</cc:Card>
|
||||||
<GridView>
|
<cc:Card
|
||||||
<GridViewColumn Width="180" Header="{DynamicResource hotkey}">
|
Title="{DynamicResource ToggleHistoryHotkey}"
|
||||||
<GridViewColumn.CellTemplate>
|
Icon=""
|
||||||
<DataTemplate DataType="userSettings:CustomPluginHotkey">
|
Type="Inside">
|
||||||
<TextBlock Text="{Binding Hotkey}" />
|
<cc:HotkeyDisplay Keys="Ctrl+H" />
|
||||||
</DataTemplate>
|
</cc:Card>
|
||||||
</GridViewColumn.CellTemplate>
|
<cc:Card
|
||||||
</GridViewColumn>
|
Title="{DynamicResource CopyFilePathHotkey}"
|
||||||
<GridViewColumn Width="430" Header="{DynamicResource customQuery}">
|
Icon=""
|
||||||
<GridViewColumn.CellTemplate>
|
Type="Inside">
|
||||||
<DataTemplate DataType="userSettings:CustomPluginHotkey">
|
<cc:HotkeyDisplay Keys="Ctrl+Shift+C" />
|
||||||
<TextBlock Text="{Binding ActionKeyword}" />
|
</cc:Card>
|
||||||
</DataTemplate>
|
<cc:Card
|
||||||
</GridViewColumn.CellTemplate>
|
Title="{DynamicResource OpenContextMenuHotkey}"
|
||||||
</GridViewColumn>
|
Icon=""
|
||||||
</GridView>
|
Type="Inside">
|
||||||
</ListView.View>
|
<flowlauncher:HotkeyControl
|
||||||
</ListView>
|
DefaultHotkey="Ctrl+I"
|
||||||
<StackPanel
|
Hotkey="{Binding Settings.OpenContextMenuHotkey}"
|
||||||
Grid.Row="6"
|
HotkeySettings="{Binding Settings}"
|
||||||
Margin="0"
|
ValidateKeyGesture="False" />
|
||||||
HorizontalAlignment="Right"
|
</cc:Card>
|
||||||
VerticalAlignment="Top"
|
<cc:Card
|
||||||
Orientation="Horizontal">
|
Title="{DynamicResource OpenContextMenuHotkey}"
|
||||||
<Button
|
Icon=""
|
||||||
MinWidth="100"
|
Type="Inside">
|
||||||
Margin="10"
|
<cc:HotkeyDisplay Keys="Shift+Enter" />
|
||||||
Click="OnDeleteCustomHotkeyClick"
|
</cc:Card>
|
||||||
Content="{DynamicResource delete}" />
|
|
||||||
<Button
|
<cc:Card
|
||||||
MinWidth="100"
|
Title="{DynamicResource SettingWindowHotkey}"
|
||||||
Margin="10"
|
Icon=""
|
||||||
Click="OnEditCustomHotkeyClick"
|
Type="Inside">
|
||||||
Content="{DynamicResource edit}" />
|
<flowlauncher:HotkeyControl
|
||||||
<Button
|
DefaultHotkey="Ctrl+I"
|
||||||
MinWidth="100"
|
Hotkey="{Binding Settings.SettingWindowHotkey}"
|
||||||
Margin="10,10,0,10"
|
HotkeySettings="{Binding Settings}"
|
||||||
Click="OnAddCustomHotkeyClick"
|
ValidateKeyGesture="False" />
|
||||||
Content="{DynamicResource add}" />
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource ToggleGameModeHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Type="Inside">
|
||||||
|
<cc:HotkeyDisplay Keys="Ctrl+F12" />
|
||||||
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource RequeryHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Type="Inside">
|
||||||
|
<cc:HotkeyDisplay Keys="Ctrl+R" />
|
||||||
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource ReloadPluginHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Sub="{DynamicResource ReloadPluginHotkeyToolTip}"
|
||||||
|
Type="Inside">
|
||||||
|
<cc:HotkeyDisplay Keys="F5" />
|
||||||
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource SelectPrevPageHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Type="Inside">
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey=""
|
||||||
|
Hotkey="{Binding Settings.SelectPrevPageHotkey}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource SelectNextPageHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Type="Inside">
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey=""
|
||||||
|
Hotkey="{Binding Settings.SelectNextPageHotkey}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:Card>
|
||||||
|
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource QuickWidthHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Type="Inside">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<cc:HotkeyDisplay Keys="Ctrl+[" />
|
||||||
|
<cc:HotkeyDisplay Margin="4,0,0,0" Keys="Ctrl+]" />
|
||||||
|
</StackPanel>
|
||||||
|
</cc:Card>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource QuickHeightHotkey}"
|
||||||
|
Icon=""
|
||||||
|
Type="Inside">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<cc:HotkeyDisplay Keys="Ctrl+Plus" />
|
||||||
|
<cc:HotkeyDisplay Margin="4,0,0,0" Keys="Ctrl+Minus" />
|
||||||
|
</StackPanel>
|
||||||
|
</cc:Card>
|
||||||
|
</StackPanel>
|
||||||
|
</cc:ExCard>
|
||||||
|
|
||||||
|
|
||||||
|
<cc:ExCard
|
||||||
|
Title="{DynamicResource autoCompleteHotkey}"
|
||||||
|
Margin="0,14,0,0"
|
||||||
|
Icon=""
|
||||||
|
Sub="{DynamicResource autoCompleteHotkeyToolTip}">
|
||||||
|
<cc:ExCard.SideContent>
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey="Ctrl+Tab"
|
||||||
|
Hotkey="{Binding Settings.AutoCompleteHotkey}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:ExCard.SideContent>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource autoCompleteHotkey}"
|
||||||
|
Sub="{DynamicResource AdditionalHotkeyToolTip}"
|
||||||
|
Type="InsideFit">
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey=""
|
||||||
|
Hotkey="{Binding Settings.AutoCompleteHotkey2}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:Card>
|
||||||
|
</cc:ExCard>
|
||||||
|
|
||||||
|
<cc:ExCard
|
||||||
|
Title="{DynamicResource SelectPrevItemHotkey}"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
Icon="">
|
||||||
|
<cc:ExCard.SideContent>
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey="Shift+Tab"
|
||||||
|
Hotkey="{Binding Settings.SelectPrevItemHotkey}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:ExCard.SideContent>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource SelectPrevItemHotkey}"
|
||||||
|
Sub="{DynamicResource AdditionalHotkeyToolTip}"
|
||||||
|
Type="InsideFit">
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey=""
|
||||||
|
Hotkey="{Binding Settings.SelectPrevItemHotkey2}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:Card>
|
||||||
|
</cc:ExCard>
|
||||||
|
|
||||||
|
<cc:ExCard
|
||||||
|
Title="{DynamicResource SelectNextItemHotkey}"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
Icon="">
|
||||||
|
<cc:ExCard.SideContent>
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey="Tab"
|
||||||
|
Hotkey="{Binding Settings.SelectNextItemHotkey}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:ExCard.SideContent>
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource SelectNextItemHotkey}"
|
||||||
|
Sub="{DynamicResource AdditionalHotkeyToolTip}"
|
||||||
|
Type="InsideFit">
|
||||||
|
<flowlauncher:HotkeyControl
|
||||||
|
DefaultHotkey=""
|
||||||
|
Hotkey="{Binding Settings.SelectNextItemHotkey2}"
|
||||||
|
HotkeySettings="{Binding Settings}"
|
||||||
|
ValidateKeyGesture="False" />
|
||||||
|
</cc:Card>
|
||||||
|
</cc:ExCard>
|
||||||
|
|
||||||
|
<cc:ExCard
|
||||||
|
Title="{DynamicResource customQueryHotkey}"
|
||||||
|
Margin="0,20,0,0"
|
||||||
|
Icon="">
|
||||||
|
<StackPanel Margin="0,0,0,0">
|
||||||
|
<Separator
|
||||||
|
Width="Auto"
|
||||||
|
Margin="0"
|
||||||
|
BorderThickness="1"
|
||||||
|
Style="{StaticResource SettingSeparatorStyle}" />
|
||||||
|
<StackPanel Margin="18,18,18,0">
|
||||||
|
<ListView
|
||||||
|
Grid.Row="5"
|
||||||
|
MinHeight="160"
|
||||||
|
Margin="0,0,0,0"
|
||||||
|
Background="{DynamicResource Color02B}"
|
||||||
|
BorderBrush="DarkGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
ItemsSource="{Binding Settings.CustomPluginHotkeys}"
|
||||||
|
SelectedItem="{Binding SelectedCustomPluginHotkey}"
|
||||||
|
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
||||||
|
<ListView.View>
|
||||||
|
<GridView>
|
||||||
|
<GridViewColumn Width="180" Header="{DynamicResource hotkey}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate DataType="userSettings:CustomPluginHotkey">
|
||||||
|
<TextBlock Text="{Binding Hotkey}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
<GridViewColumn Width="430" Header="{DynamicResource customQuery}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate DataType="userSettings:CustomPluginHotkey">
|
||||||
|
<TextBlock Text="{Binding ActionKeyword}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="6"
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="10"
|
||||||
|
Click="OnDeleteCustomHotkeyClick"
|
||||||
|
Content="{DynamicResource delete}" />
|
||||||
|
<Button
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="10"
|
||||||
|
Click="OnEditCustomHotkeyClick"
|
||||||
|
Content="{DynamicResource edit}" />
|
||||||
|
<Button
|
||||||
|
MinWidth="100"
|
||||||
|
Margin="10,10,0,10"
|
||||||
|
Click="OnAddCustomHotkeyClick"
|
||||||
|
Content="{DynamicResource add}" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</cc:ExCard>
|
||||||
|
|
||||||
|
<cc:ExCard
|
||||||
|
Title="{DynamicResource customQueryShortcut}"
|
||||||
|
Margin="0,4,0,0"
|
||||||
|
Icon="">
|
||||||
|
<StackPanel>
|
||||||
|
<Separator
|
||||||
|
Width="Auto"
|
||||||
|
Margin="0"
|
||||||
|
BorderThickness="1"
|
||||||
|
Style="{StaticResource SettingSeparatorStyle}" />
|
||||||
|
<StackPanel Margin="18,12,18,0">
|
||||||
|
<ListView
|
||||||
|
Grid.Row="8"
|
||||||
|
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="430" Header="{DynamicResource customShortcutExpansion}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Value}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
|
<StackPanel
|
||||||
|
Grid.Row="9"
|
||||||
|
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>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</cc:ExCard>
|
||||||
|
|
||||||
|
<cc:ExCard
|
||||||
|
Title="{DynamicResource builtinShortcuts}"
|
||||||
|
Margin="0,4,0,14"
|
||||||
|
Icon="">
|
||||||
|
<StackPanel>
|
||||||
|
<Separator
|
||||||
|
Width="Auto"
|
||||||
|
Margin="0"
|
||||||
|
BorderThickness="1"
|
||||||
|
Style="{StaticResource SettingSeparatorStyle}" />
|
||||||
|
<StackPanel Margin="16,8,16,0">
|
||||||
|
<ListView
|
||||||
|
Grid.Row="11"
|
||||||
|
MinHeight="160"
|
||||||
|
Margin="0,6,0,16"
|
||||||
|
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="430" Header="{DynamicResource builtinShortcutDescription}">
|
||||||
|
<GridViewColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding Description, Converter={StaticResource TranslationConverter}}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</GridViewColumn.CellTemplate>
|
||||||
|
</GridViewColumn>
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</cc:ExCard>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<TextBlock
|
|
||||||
Grid.Row="7"
|
|
||||||
Margin="0,0,12,2"
|
|
||||||
Padding="0,12,0,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="14"
|
|
||||||
Foreground="{DynamicResource Color05B}"
|
|
||||||
Text="{DynamicResource customQueryShortcut}" />
|
|
||||||
<ListView
|
|
||||||
Name="customShortcutView"
|
|
||||||
Grid.Row="8"
|
|
||||||
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="430" Header="{DynamicResource customShortcutExpansion}">
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Text="{Binding Value}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
</GridView>
|
|
||||||
</ListView.View>
|
|
||||||
</ListView>
|
|
||||||
<StackPanel
|
|
||||||
Grid.Row="9"
|
|
||||||
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="10"
|
|
||||||
Margin="0,0,12,2"
|
|
||||||
Padding="0,12,0,0"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
FontSize="14"
|
|
||||||
Foreground="{DynamicResource Color05B}"
|
|
||||||
Text="{DynamicResource builtinShortcuts}" />
|
|
||||||
<ListView
|
|
||||||
Grid.Row="11"
|
|
||||||
MinHeight="160"
|
|
||||||
Margin="0,6,0,20"
|
|
||||||
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="430" Header="{DynamicResource builtinShortcutDescription}">
|
|
||||||
<GridViewColumn.CellTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Text="{Binding Description, Converter={StaticResource TranslationConverter}}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</GridViewColumn.CellTemplate>
|
|
||||||
</GridViewColumn>
|
|
||||||
</GridView>
|
|
||||||
</ListView.View>
|
|
||||||
</ListView>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ using System.Windows.Forms;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
|
using NHotkey;
|
||||||
using Button = System.Windows.Controls.Button;
|
using Button = System.Windows.Controls.Button;
|
||||||
using Control = System.Windows.Controls.Control;
|
using Control = System.Windows.Controls.Control;
|
||||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||||
|
|
@ -110,41 +111,9 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
#region Hotkey
|
#region Hotkey
|
||||||
|
|
||||||
private void OnHotkeyControlLoaded(object sender, RoutedEventArgs e)
|
private void OnToggleHotkey(object sender, HotkeyEventArgs e)
|
||||||
{
|
{
|
||||||
_ = HotkeyControl.SetHotkeyAsync(viewModel.Settings.Hotkey, false);
|
HotKeyMapper.OnToggleHotkey(sender, e);
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHotkeyControlFocused(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
HotKeyMapper.RemoveHotkey(settings.Hotkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnHotkeyControlFocusLost(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (HotkeyControl.CurrentHotkeyAvailable)
|
|
||||||
{
|
|
||||||
HotKeyMapper.SetHotkey(HotkeyControl.CurrentHotkey, HotKeyMapper.OnToggleHotkey);
|
|
||||||
HotKeyMapper.RemoveHotkey(settings.Hotkey);
|
|
||||||
settings.Hotkey = HotkeyControl.CurrentHotkey.ToString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HotKeyMapper.SetHotkey(new HotkeyModel(settings.Hotkey), HotKeyMapper.OnToggleHotkey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPreviewHotkeyControlLoaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_ = PreviewHotkeyControl.SetHotkeyAsync(settings.PreviewHotkey, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnPreviewHotkeyControlFocusLost(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (PreviewHotkeyControl.CurrentHotkeyAvailable)
|
|
||||||
{
|
|
||||||
settings.PreviewHotkey = PreviewHotkeyControl.CurrentHotkey.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDeleteCustomHotkeyClick(object sender, RoutedEventArgs e)
|
private void OnDeleteCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -391,7 +360,7 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
if (viewModel.EditSelectedCustomShortcut())
|
if (viewModel.EditSelectedCustomShortcut())
|
||||||
{
|
{
|
||||||
customShortcutView.Items.Refresh();
|
//customShortcutView.Items.Refresh(); Should Fix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,36 @@ namespace Flow.Launcher.ViewModel
|
||||||
case nameof(Settings.PreviewHotkey):
|
case nameof(Settings.PreviewHotkey):
|
||||||
OnPropertyChanged(nameof(PreviewHotkey));
|
OnPropertyChanged(nameof(PreviewHotkey));
|
||||||
break;
|
break;
|
||||||
|
case nameof(Settings.AutoCompleteHotkey):
|
||||||
|
OnPropertyChanged(nameof(AutoCompleteHotkey));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.AutoCompleteHotkey2):
|
||||||
|
OnPropertyChanged(nameof(AutoCompleteHotkey2));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SelectNextItemHotkey):
|
||||||
|
OnPropertyChanged(nameof(SelectNextItemHotkey));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SelectNextItemHotkey2):
|
||||||
|
OnPropertyChanged(nameof(SelectNextItemHotkey2));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SelectPrevItemHotkey):
|
||||||
|
OnPropertyChanged(nameof(SelectPrevItemHotkey));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SelectPrevItemHotkey2):
|
||||||
|
OnPropertyChanged(nameof(SelectPrevItemHotkey2));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SelectNextPageHotkey):
|
||||||
|
OnPropertyChanged(nameof(SelectNextPageHotkey));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SelectPrevPageHotkey):
|
||||||
|
OnPropertyChanged(nameof(SelectPrevPageHotkey));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.OpenContextMenuHotkey):
|
||||||
|
OnPropertyChanged(nameof(OpenContextMenuHotkey));
|
||||||
|
break;
|
||||||
|
case nameof(Settings.SettingWindowHotkey):
|
||||||
|
OnPropertyChanged(nameof(SettingWindowHotkey));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -210,7 +240,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void ReQuery()
|
public void ReQuery()
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (SelectedIsFromQueryResults())
|
||||||
{
|
{
|
||||||
|
|
@ -218,6 +248,14 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ReQuery(bool reselect)
|
||||||
|
{
|
||||||
|
if (SelectedIsFromQueryResults())
|
||||||
|
{
|
||||||
|
QueryResults(isReQuery: true, reSelect: reselect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void LoadContextMenu()
|
private void LoadContextMenu()
|
||||||
{
|
{
|
||||||
|
|
@ -334,6 +372,13 @@ namespace Flow.Launcher.ViewModel
|
||||||
SelectedResults.SelectFirstResult();
|
SelectedResults.SelectFirstResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void SelectLastResult()
|
||||||
|
{
|
||||||
|
SelectedResults.SelectLastResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void SelectPrevPage()
|
private void SelectPrevPage()
|
||||||
{
|
{
|
||||||
|
|
@ -619,25 +664,33 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public string OpenResultCommandModifiers => Settings.OpenResultModifiers;
|
public string OpenResultCommandModifiers => Settings.OpenResultModifiers;
|
||||||
|
|
||||||
public string PreviewHotkey
|
public string VerifyOrSetDefaultHotkey(string hotkey, string defaultHotkey)
|
||||||
{
|
{
|
||||||
get
|
try
|
||||||
{
|
{
|
||||||
// TODO try to patch issue #1755
|
var converter = new KeyGestureConverter();
|
||||||
// Added in v1.14.0, remove after v1.16.0.
|
var key = (KeyGesture)converter.ConvertFromString(hotkey);
|
||||||
try
|
|
||||||
{
|
|
||||||
var converter = new KeyGestureConverter();
|
|
||||||
var key = (KeyGesture)converter.ConvertFromString(Settings.PreviewHotkey);
|
|
||||||
}
|
|
||||||
catch (Exception e) when (e is NotSupportedException || e is InvalidEnumArgumentException)
|
|
||||||
{
|
|
||||||
Settings.PreviewHotkey = "F1";
|
|
||||||
}
|
|
||||||
|
|
||||||
return Settings.PreviewHotkey;
|
|
||||||
}
|
}
|
||||||
|
catch (Exception e) when (e is NotSupportedException || e is InvalidEnumArgumentException)
|
||||||
|
{
|
||||||
|
return defaultHotkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hotkey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string PreviewHotkey => VerifyOrSetDefaultHotkey(Settings.PreviewHotkey, "F1");
|
||||||
|
public string AutoCompleteHotkey => VerifyOrSetDefaultHotkey(Settings.AutoCompleteHotkey, "Ctrl+Tab");
|
||||||
|
public string AutoCompleteHotkey2 => VerifyOrSetDefaultHotkey(Settings.AutoCompleteHotkey2, "");
|
||||||
|
public string SelectNextItemHotkey => VerifyOrSetDefaultHotkey(Settings.SelectNextItemHotkey, "Tab");
|
||||||
|
public string SelectNextItemHotkey2 => VerifyOrSetDefaultHotkey(Settings.SelectNextItemHotkey2, "");
|
||||||
|
public string SelectPrevItemHotkey => VerifyOrSetDefaultHotkey(Settings.SelectPrevItemHotkey, "Shift+Tab");
|
||||||
|
public string SelectPrevItemHotkey2 => VerifyOrSetDefaultHotkey(Settings.SelectPrevItemHotkey2, "");
|
||||||
|
public string SelectNextPageHotkey => VerifyOrSetDefaultHotkey(Settings.SelectNextPageHotkey, "");
|
||||||
|
public string SelectPrevPageHotkey => VerifyOrSetDefaultHotkey(Settings.SelectPrevPageHotkey, "");
|
||||||
|
public string OpenContextMenuHotkey => VerifyOrSetDefaultHotkey(Settings.OpenContextMenuHotkey, "Ctrl+O");
|
||||||
|
public string SettingWindowHotkey => VerifyOrSetDefaultHotkey(Settings.SettingWindowHotkey, "Ctrl+I");
|
||||||
|
|
||||||
|
|
||||||
public string Image => Constant.QueryTextBoxIconImagePath;
|
public string Image => Constant.QueryTextBoxIconImagePath;
|
||||||
|
|
||||||
|
|
@ -680,20 +733,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
List<Result> results;
|
List<Result> results;
|
||||||
if (selected == lastContextMenuResult)
|
if (selected == lastContextMenuResult)
|
||||||
{
|
{
|
||||||
// Use copy to keep the original results unchanged
|
results = lastContextMenuResults;
|
||||||
results = lastContextMenuResults.ConvertAll(result => new Result
|
|
||||||
{
|
|
||||||
Title = result.Title,
|
|
||||||
SubTitle = result.SubTitle,
|
|
||||||
IcoPath = result.IcoPath,
|
|
||||||
PluginDirectory = result.PluginDirectory,
|
|
||||||
Action = result.Action,
|
|
||||||
ContextData = result.ContextData,
|
|
||||||
Glyph = result.Glyph,
|
|
||||||
OriginQuery = result.OriginQuery,
|
|
||||||
Score = result.Score,
|
|
||||||
AsyncAction = result.AsyncAction,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -707,7 +747,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(query))
|
if (!string.IsNullOrEmpty(query))
|
||||||
{
|
{
|
||||||
var filtered = results.Where
|
var filtered = results.Select(x => x.Clone()).Where
|
||||||
(
|
(
|
||||||
r =>
|
r =>
|
||||||
{
|
{
|
||||||
|
|
@ -775,7 +815,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
||||||
|
|
||||||
private async void QueryResults(bool isReQuery = false)
|
private async void QueryResults(bool isReQuery = false, bool reSelect = true)
|
||||||
{
|
{
|
||||||
_updateSource?.Cancel();
|
_updateSource?.Cancel();
|
||||||
|
|
||||||
|
|
@ -850,7 +890,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
||||||
{
|
{
|
||||||
false => QueryTask(plugin),
|
false => QueryTask(plugin, reSelect),
|
||||||
true => Task.CompletedTask
|
true => Task.CompletedTask
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
|
|
@ -878,7 +918,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local function
|
// Local function
|
||||||
async Task QueryTask(PluginPair plugin)
|
async Task QueryTask(PluginPair plugin, bool reSelect = true)
|
||||||
{
|
{
|
||||||
// Since it is wrapped within a ThreadPool Thread, the synchronous context is null
|
// Since it is wrapped within a ThreadPool Thread, the synchronous context is null
|
||||||
// Task.Yield will force it to run in ThreadPool
|
// Task.Yield will force it to run in ThreadPool
|
||||||
|
|
@ -892,7 +932,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
results ??= _emptyResult;
|
results ??= _emptyResult;
|
||||||
|
|
||||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query,
|
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query,
|
||||||
currentCancellationToken)))
|
currentCancellationToken, reSelect)))
|
||||||
{
|
{
|
||||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||||
}
|
}
|
||||||
|
|
@ -1133,7 +1173,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// To avoid deadlock, this method should not called from main thread
|
/// To avoid deadlock, this method should not called from main thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateResultView(IEnumerable<ResultsForUpdate> resultsForUpdates)
|
public void UpdateResultView(ICollection<ResultsForUpdate> resultsForUpdates)
|
||||||
{
|
{
|
||||||
if (!resultsForUpdates.Any())
|
if (!resultsForUpdates.Any())
|
||||||
return;
|
return;
|
||||||
|
|
@ -1172,7 +1212,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Results.AddResults(resultsForUpdates, token);
|
// it should be the same for all results
|
||||||
|
bool reSelect = resultsForUpdates.First().ReSelectFirstResult;
|
||||||
|
|
||||||
|
Results.AddResults(resultsForUpdates, token, reSelect);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -4,23 +4,13 @@ using System.Threading;
|
||||||
|
|
||||||
namespace Flow.Launcher.ViewModel
|
namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
public struct ResultsForUpdate
|
public record struct ResultsForUpdate(
|
||||||
|
IReadOnlyList<Result> Results,
|
||||||
|
PluginMetadata Metadata,
|
||||||
|
Query Query,
|
||||||
|
CancellationToken Token,
|
||||||
|
bool ReSelectFirstResult = true)
|
||||||
{
|
{
|
||||||
public IReadOnlyList<Result> Results { get; }
|
public string ID { get; } = Metadata.ID;
|
||||||
|
|
||||||
public PluginMetadata Metadata { get; }
|
|
||||||
public string ID { get; }
|
|
||||||
|
|
||||||
public Query Query { get; }
|
|
||||||
public CancellationToken Token { get; }
|
|
||||||
|
|
||||||
public ResultsForUpdate(IReadOnlyList<Result> results, PluginMetadata metadata, Query query, CancellationToken token)
|
|
||||||
{
|
|
||||||
Results = results;
|
|
||||||
Metadata = metadata;
|
|
||||||
Query = query;
|
|
||||||
Token = token;
|
|
||||||
ID = metadata.ID;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,11 @@ namespace Flow.Launcher.ViewModel
|
||||||
SelectedIndex = NewIndex(0);
|
SelectedIndex = NewIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SelectLastResult()
|
||||||
|
{
|
||||||
|
SelectedIndex = NewIndex(Results.Count - 1);
|
||||||
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
lock (_collectionLock)
|
lock (_collectionLock)
|
||||||
|
|
@ -147,23 +152,23 @@ namespace Flow.Launcher.ViewModel
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// To avoid deadlock, this method should not called from main thread
|
/// To avoid deadlock, this method should not called from main thread
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void AddResults(IEnumerable<ResultsForUpdate> resultsForUpdates, CancellationToken token)
|
public void AddResults(IEnumerable<ResultsForUpdate> resultsForUpdates, CancellationToken token, bool reselect = true)
|
||||||
{
|
{
|
||||||
var newResults = NewResults(resultsForUpdates);
|
var newResults = NewResults(resultsForUpdates);
|
||||||
|
|
||||||
if (token.IsCancellationRequested)
|
if (token.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UpdateResults(newResults, token);
|
UpdateResults(newResults, token, reselect);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateResults(List<ResultViewModel> newResults, CancellationToken token = default)
|
private void UpdateResults(List<ResultViewModel> newResults, CancellationToken token = default, bool reselect = true)
|
||||||
{
|
{
|
||||||
lock (_collectionLock)
|
lock (_collectionLock)
|
||||||
{
|
{
|
||||||
// update UI in one run, so it can avoid UI flickering
|
// update UI in one run, so it can avoid UI flickering
|
||||||
Results.Update(newResults, token);
|
Results.Update(newResults, token);
|
||||||
if (Results.Any())
|
if (reselect && Results.Any())
|
||||||
SelectedItem = Results[0];
|
SelectedItem = Results[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ using Flow.Launcher.Plugin.SharedModels;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
|
||||||
namespace Flow.Launcher.ViewModel
|
namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
|
|
@ -63,9 +65,17 @@ namespace Flow.Launcher.ViewModel
|
||||||
case nameof(Settings.PreviewHotkey):
|
case nameof(Settings.PreviewHotkey):
|
||||||
OnPropertyChanged(nameof(AlwaysPreviewToolTip));
|
OnPropertyChanged(nameof(AlwaysPreviewToolTip));
|
||||||
break;
|
break;
|
||||||
|
case nameof(Settings.SoundVolume):
|
||||||
|
OnPropertyChanged(nameof(SoundEffectVolume));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
public void SetTogglingHotkey(HotkeyModel hotkey)
|
||||||
|
{
|
||||||
|
HotKeyMapper.SetHotkey(hotkey, HotKeyMapper.OnToggleHotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Settings Settings { get; set; }
|
public Settings Settings { get; set; }
|
||||||
|
|
@ -107,13 +117,15 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"), e.Message);
|
Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"),
|
||||||
|
e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is only required to set at startup. When portable mode enabled/disabled a restart is always required
|
// This is only required to set at startup. When portable mode enabled/disabled a restart is always required
|
||||||
private bool _portableMode = DataLocation.PortableDataLocationInUse();
|
private bool _portableMode = DataLocation.PortableDataLocationInUse();
|
||||||
|
|
||||||
public bool PortableMode
|
public bool PortableMode
|
||||||
{
|
{
|
||||||
get => _portableMode;
|
get => _portableMode;
|
||||||
|
|
@ -182,6 +194,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<LastQueryMode> _lastQueryModes = new List<LastQueryMode>();
|
private List<LastQueryMode> _lastQueryModes = new List<LastQueryMode>();
|
||||||
|
|
||||||
public List<LastQueryMode> LastQueryModes
|
public List<LastQueryMode> LastQueryModes
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -190,6 +203,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
_lastQueryModes = InitLastQueryModes();
|
_lastQueryModes = InitLastQueryModes();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _lastQueryModes;
|
return _lastQueryModes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -197,17 +211,16 @@ namespace Flow.Launcher.ViewModel
|
||||||
private List<LastQueryMode> InitLastQueryModes()
|
private List<LastQueryMode> InitLastQueryModes()
|
||||||
{
|
{
|
||||||
var modes = new List<LastQueryMode>();
|
var modes = new List<LastQueryMode>();
|
||||||
var enums = (Infrastructure.UserSettings.LastQueryMode[])Enum.GetValues(typeof(Infrastructure.UserSettings.LastQueryMode));
|
var enums = (Infrastructure.UserSettings.LastQueryMode[])Enum.GetValues(
|
||||||
|
typeof(Infrastructure.UserSettings.LastQueryMode));
|
||||||
foreach (var e in enums)
|
foreach (var e in enums)
|
||||||
{
|
{
|
||||||
var key = $"LastQuery{e}";
|
var key = $"LastQuery{e}";
|
||||||
var display = _translater.GetTranslation(key);
|
var display = _translater.GetTranslation(key);
|
||||||
var m = new LastQueryMode
|
var m = new LastQueryMode { Display = display, Value = e, };
|
||||||
{
|
|
||||||
Display = display, Value = e,
|
|
||||||
};
|
|
||||||
modes.Add(m);
|
modes.Add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,15 +277,15 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public List<string> OpenResultModifiersList => new List<string>
|
public List<string> OpenResultModifiersList => new List<string>
|
||||||
{
|
{
|
||||||
KeyConstant.Alt,
|
KeyConstant.Alt, KeyConstant.Ctrl, $"{KeyConstant.Ctrl}+{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 string AlwaysPreviewToolTip => string.Format(_translater.GetTranslation("AlwaysPreviewToolTip"), Settings.PreviewHotkey);
|
public string AlwaysPreviewToolTip =>
|
||||||
|
string.Format(_translater.GetTranslation("AlwaysPreviewToolTip"), Settings.PreviewHotkey);
|
||||||
|
|
||||||
public string TestProxy()
|
public string TestProxy()
|
||||||
{
|
{
|
||||||
|
|
@ -282,6 +295,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
return InternationalizationManager.Instance.GetTranslation("serverCantBeEmpty");
|
return InternationalizationManager.Instance.GetTranslation("serverCantBeEmpty");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.Proxy.Port <= 0)
|
if (Settings.Proxy.Port <= 0)
|
||||||
{
|
{
|
||||||
return InternationalizationManager.Instance.GetTranslation("portCantBeEmpty");
|
return InternationalizationManager.Instance.GetTranslation("portCantBeEmpty");
|
||||||
|
|
@ -300,6 +314,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
Credentials = new NetworkCredential(proxyUserName, Settings.Proxy.Password)
|
Credentials = new NetworkCredential(proxyUserName, Settings.Proxy.Password)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = (HttpWebResponse)request.GetResponse();
|
var response = (HttpWebResponse)request.GetResponse();
|
||||||
|
|
@ -330,10 +345,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
get => PluginManager.AllPlugins
|
get => 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
|
.Select(p => new PluginViewModel { PluginPair = p })
|
||||||
{
|
|
||||||
PluginPair = p
|
|
||||||
})
|
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -380,8 +392,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
await PluginsManifest.UpdateManifestAsync();
|
await PluginsManifest.UpdateManifestAsync();
|
||||||
OnPropertyChanged(nameof(ExternalPlugins));
|
OnPropertyChanged(nameof(ExternalPlugins));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal void DisplayPluginQuery(string queryToDisplay, PluginPair plugin, int actionKeywordPosition = 0)
|
internal void DisplayPluginQuery(string queryToDisplay, PluginPair plugin, int actionKeywordPosition = 0)
|
||||||
{
|
{
|
||||||
|
|
@ -455,12 +466,10 @@ 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
|
var m = new ColorScheme { Display = display, Value = e, };
|
||||||
{
|
|
||||||
Display = display, Value = e,
|
|
||||||
};
|
|
||||||
modes.Add(m);
|
modes.Add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -481,13 +490,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
var key = $"SearchWindowScreen{e}";
|
var key = $"SearchWindowScreen{e}";
|
||||||
var display = _translater.GetTranslation(key);
|
var display = _translater.GetTranslation(key);
|
||||||
var m = new SearchWindowScreen
|
var m = new SearchWindowScreen { Display = display, Value = e, };
|
||||||
{
|
|
||||||
Display = display,
|
|
||||||
Value = e,
|
|
||||||
};
|
|
||||||
modes.Add(m);
|
modes.Add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -508,12 +514,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
var key = $"SearchWindowAlign{e}";
|
var key = $"SearchWindowAlign{e}";
|
||||||
var display = _translater.GetTranslation(key);
|
var display = _translater.GetTranslation(key);
|
||||||
var m = new SearchWindowAlign
|
var m = new SearchWindowAlign { Display = display, Value = e, };
|
||||||
{
|
|
||||||
Display = display, Value = e,
|
|
||||||
};
|
|
||||||
modes.Add(m);
|
modes.Add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return modes;
|
return modes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -528,6 +532,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
screenNumbers.Add(i);
|
screenNumbers.Add(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return screenNumbers;
|
return screenNumbers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -614,13 +619,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
var key = $"AnimationSpeed{e}";
|
var key = $"AnimationSpeed{e}";
|
||||||
var display = _translater.GetTranslation(key);
|
var display = _translater.GetTranslation(key);
|
||||||
var m = new AnimationSpeed
|
var m = new AnimationSpeed { Display = display, Value = e, };
|
||||||
{
|
|
||||||
Display = display,
|
|
||||||
Value = e,
|
|
||||||
};
|
|
||||||
speeds.Add(m);
|
speeds.Add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
return speeds;
|
return speeds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -631,6 +633,12 @@ namespace Flow.Launcher.ViewModel
|
||||||
set => Settings.UseSound = value;
|
set => Settings.UseSound = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double SoundEffectVolume
|
||||||
|
{
|
||||||
|
get => Settings.SoundVolume;
|
||||||
|
set => Settings.SoundVolume = value;
|
||||||
|
}
|
||||||
|
|
||||||
public bool UseClock
|
public bool UseClock
|
||||||
{
|
{
|
||||||
get => Settings.UseClock;
|
get => Settings.UseClock;
|
||||||
|
|
@ -681,10 +689,7 @@ 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)
|
var brush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
|
||||||
{
|
|
||||||
Stretch = Stretch.UniformToFill
|
|
||||||
};
|
|
||||||
return brush;
|
return brush;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -705,26 +710,36 @@ namespace Flow.Launcher.ViewModel
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
|
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
|
SubTitle =
|
||||||
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png")
|
InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
|
||||||
|
IcoPath =
|
||||||
|
Path.Combine(Constant.ProgramDirectory,
|
||||||
|
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png")
|
||||||
},
|
},
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
|
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
|
SubTitle =
|
||||||
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
|
||||||
|
IcoPath =
|
||||||
|
Path.Combine(Constant.ProgramDirectory,
|
||||||
|
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
||||||
},
|
},
|
||||||
new Result
|
new Result
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
|
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProgram"),
|
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProgram"),
|
||||||
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 = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
|
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
|
SubTitle =
|
||||||
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
|
||||||
|
IcoPath = Path.Combine(Constant.ProgramDirectory,
|
||||||
|
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var vm = new ResultsViewModel(Settings);
|
var vm = new ResultsViewModel(Settings);
|
||||||
|
|
@ -880,6 +895,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
SelectedCustomShortcut = item;
|
SelectedCustomShortcut = item;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -908,6 +924,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
public string Documentation => Constant.Documentation;
|
public string Documentation => Constant.Documentation;
|
||||||
public string Docs => Constant.Docs;
|
public string Docs => Constant.Docs;
|
||||||
public string Github => Constant.GitHub;
|
public string Github => Constant.GitHub;
|
||||||
|
|
||||||
public string Version
|
public string Version
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -922,7 +939,9 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string ActivatedTimes => string.Format(_translater.GetTranslation("about_activate_times"), Settings.ActivateTimes);
|
|
||||||
|
public string ActivatedTimes =>
|
||||||
|
string.Format(_translater.GetTranslation("about_activate_times"), Settings.ActivateTimes);
|
||||||
|
|
||||||
public string CheckLogFolder
|
public string CheckLogFolder
|
||||||
{
|
{
|
||||||
|
|
@ -930,7 +949,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
var logFiles = GetLogFiles();
|
var logFiles = GetLogFiles();
|
||||||
long size = logFiles.Sum(file => file.Length);
|
long size = logFiles.Sum(file => file.Length);
|
||||||
return string.Format("{0} ({1})", _translater.GetTranslation("clearlogfolder"), BytesToReadableString(size));
|
return string.Format("{0} ({1})", _translater.GetTranslation("clearlogfolder"),
|
||||||
|
BytesToReadableString(size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -967,10 +987,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
internal static string BytesToReadableString(long bytes)
|
internal static string BytesToReadableString(long bytes)
|
||||||
{
|
{
|
||||||
const int scale = 1024;
|
const int scale = 1024;
|
||||||
string[] orders = new string[]
|
string[] orders = new string[] { "GB", "MB", "KB", "B" };
|
||||||
{
|
|
||||||
"GB", "MB", "KB", "B"
|
|
||||||
};
|
|
||||||
long max = (long)Math.Pow(scale, orders.Length - 1);
|
long max = (long)Math.Pow(scale, orders.Length - 1);
|
||||||
|
|
||||||
foreach (string order in orders)
|
foreach (string order in orders)
|
||||||
|
|
@ -980,6 +997,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
max /= scale;
|
max /= scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
return "0 B";
|
return "0 B";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,10 @@
|
||||||
Title="{DynamicResource Welcome_Page1_Title}"
|
Title="{DynamicResource Welcome_Page1_Title}"
|
||||||
Width="550"
|
Width="550"
|
||||||
Height="650"
|
Height="650"
|
||||||
|
MinWidth="550"
|
||||||
|
MinHeight="650"
|
||||||
|
MaxWidth="550"
|
||||||
|
MaxHeight="650"
|
||||||
Activated="OnActivated"
|
Activated="OnActivated"
|
||||||
Background="{DynamicResource Color00B}"
|
Background="{DynamicResource Color00B}"
|
||||||
Foreground="{DynamicResource PopupTextColor}"
|
Foreground="{DynamicResource PopupTextColor}"
|
||||||
|
|
|
||||||
|
|
@ -3,23 +3,22 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
{
|
|
||||||
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
|
||||||
{
|
|
||||||
public override List<Bookmark> GetBookmarks()
|
|
||||||
{
|
|
||||||
return LoadChromeBookmarks();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Bookmark> LoadChromeBookmarks()
|
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
||||||
{
|
{
|
||||||
var bookmarks = new List<Bookmark>();
|
public override List<Bookmark> GetBookmarks()
|
||||||
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
{
|
||||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome"));
|
return LoadChromeBookmarks();
|
||||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary"));
|
|
||||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium"));
|
|
||||||
return bookmarks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private List<Bookmark> LoadChromeBookmarks()
|
||||||
|
{
|
||||||
|
var bookmarks = new List<Bookmark>();
|
||||||
|
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome\User Data"), "Google Chrome"));
|
||||||
|
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Google\Chrome SxS\User Data"), "Google Chrome Canary"));
|
||||||
|
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Chromium\User Data"), "Chromium"));
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,91 +4,90 @@ using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
|
|
||||||
|
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
||||||
{
|
{
|
||||||
public abstract class ChromiumBookmarkLoader : IBookmarkLoader
|
public abstract List<Bookmark> GetBookmarks();
|
||||||
|
|
||||||
|
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
|
||||||
{
|
{
|
||||||
public abstract List<Bookmark> GetBookmarks();
|
var bookmarks = new List<Bookmark>();
|
||||||
|
if (!Directory.Exists(browserDataPath)) return bookmarks;
|
||||||
|
var paths = Directory.GetDirectories(browserDataPath);
|
||||||
|
|
||||||
protected List<Bookmark> LoadBookmarks(string browserDataPath, string name)
|
foreach (var profile in paths)
|
||||||
{
|
{
|
||||||
var bookmarks = new List<Bookmark>();
|
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
||||||
if (!Directory.Exists(browserDataPath)) return bookmarks;
|
if (!File.Exists(bookmarkPath))
|
||||||
var paths = Directory.GetDirectories(browserDataPath);
|
continue;
|
||||||
|
|
||||||
foreach (var profile in paths)
|
Main.RegisterBookmarkFile(bookmarkPath);
|
||||||
{
|
|
||||||
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
|
||||||
if (!File.Exists(bookmarkPath))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Main.RegisterBookmarkFile(bookmarkPath);
|
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
||||||
|
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||||
|
}
|
||||||
|
|
||||||
var source = name + (Path.GetFileName(profile) == "Default" ? "" : $" ({Path.GetFileName(profile)})");
|
return bookmarks;
|
||||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
||||||
|
{
|
||||||
|
var bookmarks = new List<Bookmark>();
|
||||||
|
|
||||||
|
if (!File.Exists(path))
|
||||||
return bookmarks;
|
return bookmarks;
|
||||||
}
|
|
||||||
|
|
||||||
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
||||||
{
|
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
||||||
var bookmarks = new List<Bookmark>();
|
|
||||||
|
|
||||||
if (!File.Exists(path))
|
|
||||||
return bookmarks;
|
|
||||||
|
|
||||||
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
|
||||||
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
|
||||||
return bookmarks;
|
|
||||||
EnumerateRoot(rootElement, bookmarks, source);
|
|
||||||
return bookmarks;
|
return bookmarks;
|
||||||
}
|
EnumerateRoot(rootElement, bookmarks, source);
|
||||||
|
return bookmarks;
|
||||||
|
}
|
||||||
|
|
||||||
private void EnumerateRoot(JsonElement rootElement, ICollection<Bookmark> bookmarks, string source)
|
private void EnumerateRoot(JsonElement rootElement, ICollection<Bookmark> bookmarks, string source)
|
||||||
|
{
|
||||||
|
foreach (var folder in rootElement.EnumerateObject())
|
||||||
{
|
{
|
||||||
foreach (var folder in rootElement.EnumerateObject())
|
if (folder.Value.ValueKind != JsonValueKind.Object)
|
||||||
{
|
continue;
|
||||||
if (folder.Value.ValueKind != JsonValueKind.Object)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Fix for Opera. It stores bookmarks slightly different than chrome. See PR and bug report for this change for details.
|
// Fix for Opera. It stores bookmarks slightly different than chrome. See PR and bug report for this change for details.
|
||||||
// If various exceptions start to build up here consider splitting this Loader into multiple separate ones.
|
// If various exceptions start to build up here consider splitting this Loader into multiple separate ones.
|
||||||
if (folder.Name == "custom_root")
|
if (folder.Name == "custom_root")
|
||||||
EnumerateRoot(folder.Value, bookmarks, source);
|
EnumerateRoot(folder.Value, bookmarks, source);
|
||||||
else
|
else
|
||||||
EnumerateFolderBookmark(folder.Value, bookmarks, source);
|
EnumerateFolderBookmark(folder.Value, bookmarks, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnumerateFolderBookmark(JsonElement folderElement, ICollection<Bookmark> bookmarks,
|
||||||
|
string source)
|
||||||
|
{
|
||||||
|
if (!folderElement.TryGetProperty("children", out var childrenElement))
|
||||||
|
return;
|
||||||
|
foreach (var subElement in childrenElement.EnumerateArray())
|
||||||
|
{
|
||||||
|
if (subElement.TryGetProperty("type", out var type))
|
||||||
|
{
|
||||||
|
switch (type.GetString())
|
||||||
|
{
|
||||||
|
case "folder":
|
||||||
|
case "workspace": // Edge Workspace
|
||||||
|
EnumerateFolderBookmark(subElement, bookmarks, source);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bookmarks.Add(new Bookmark(
|
||||||
|
subElement.GetProperty("name").GetString(),
|
||||||
|
subElement.GetProperty("url").GetString(),
|
||||||
|
source));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
private void EnumerateFolderBookmark(JsonElement folderElement, ICollection<Bookmark> bookmarks,
|
|
||||||
string source)
|
|
||||||
{
|
|
||||||
if (!folderElement.TryGetProperty("children", out var childrenElement))
|
|
||||||
return;
|
|
||||||
foreach (var subElement in childrenElement.EnumerateArray())
|
|
||||||
{
|
{
|
||||||
if (subElement.TryGetProperty("type", out var type))
|
Log.Error(
|
||||||
{
|
$"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}");
|
||||||
switch (type.GetString())
|
|
||||||
{
|
|
||||||
case "folder":
|
|
||||||
case "workspace": // Edge Workspace
|
|
||||||
EnumerateFolderBookmark(subElement, bookmarks, source);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
bookmarks.Add(new Bookmark(
|
|
||||||
subElement.GetProperty("name").GetString(),
|
|
||||||
subElement.GetProperty("url").GetString(),
|
|
||||||
source));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Error(
|
|
||||||
$"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,56 +4,55 @@ using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
|
namespace Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
||||||
|
|
||||||
|
internal static class BookmarkLoader
|
||||||
{
|
{
|
||||||
internal static class BookmarkLoader
|
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
||||||
{
|
{
|
||||||
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||||
{
|
if (match.IsSearchPrecisionScoreMet())
|
||||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
return match;
|
||||||
if (match.IsSearchPrecisionScoreMet())
|
|
||||||
return match;
|
|
||||||
|
|
||||||
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static List<Bookmark> LoadAllBookmarks(Settings setting)
|
||||||
|
{
|
||||||
|
var allBookmarks = new List<Bookmark>();
|
||||||
|
|
||||||
|
if (setting.LoadChromeBookmark)
|
||||||
|
{
|
||||||
|
// Add Chrome bookmarks
|
||||||
|
var chromeBookmarks = new ChromeBookmarkLoader();
|
||||||
|
allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static List<Bookmark> LoadAllBookmarks(Settings setting)
|
if (setting.LoadFirefoxBookmark)
|
||||||
{
|
{
|
||||||
var allBookmarks = new List<Bookmark>();
|
// Add Firefox bookmarks
|
||||||
|
var mozBookmarks = new FirefoxBookmarkLoader();
|
||||||
if (setting.LoadChromeBookmark)
|
allBookmarks.AddRange(mozBookmarks.GetBookmarks());
|
||||||
{
|
|
||||||
// Add Chrome bookmarks
|
|
||||||
var chromeBookmarks = new ChromeBookmarkLoader();
|
|
||||||
allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setting.LoadFirefoxBookmark)
|
|
||||||
{
|
|
||||||
// Add Firefox bookmarks
|
|
||||||
var mozBookmarks = new FirefoxBookmarkLoader();
|
|
||||||
allBookmarks.AddRange(mozBookmarks.GetBookmarks());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (setting.LoadEdgeBookmark)
|
|
||||||
{
|
|
||||||
// Add Edge (Chromium) bookmarks
|
|
||||||
var edgeBookmarks = new EdgeBookmarkLoader();
|
|
||||||
allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var browser in setting.CustomChromiumBrowsers)
|
|
||||||
{
|
|
||||||
IBookmarkLoader loader = browser.BrowserType switch
|
|
||||||
{
|
|
||||||
BrowserType.Chromium => new CustomChromiumBookmarkLoader(browser),
|
|
||||||
BrowserType.Firefox => new CustomFirefoxBookmarkLoader(browser),
|
|
||||||
_ => new CustomChromiumBookmarkLoader(browser),
|
|
||||||
};
|
|
||||||
allBookmarks.AddRange(loader.GetBookmarks());
|
|
||||||
}
|
|
||||||
|
|
||||||
return allBookmarks.Distinct().ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (setting.LoadEdgeBookmark)
|
||||||
|
{
|
||||||
|
// Add Edge (Chromium) bookmarks
|
||||||
|
var edgeBookmarks = new EdgeBookmarkLoader();
|
||||||
|
allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var browser in setting.CustomChromiumBrowsers)
|
||||||
|
{
|
||||||
|
IBookmarkLoader loader = browser.BrowserType switch
|
||||||
|
{
|
||||||
|
BrowserType.Chromium => new CustomChromiumBookmarkLoader(browser),
|
||||||
|
BrowserType.Firefox => new CustomFirefoxBookmarkLoader(browser),
|
||||||
|
_ => new CustomChromiumBookmarkLoader(browser),
|
||||||
|
};
|
||||||
|
allBookmarks.AddRange(loader.GetBookmarks());
|
||||||
|
}
|
||||||
|
|
||||||
|
return allBookmarks.Distinct().ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
{
|
|
||||||
public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader
|
|
||||||
{
|
|
||||||
public CustomChromiumBookmarkLoader(CustomBrowser browser)
|
|
||||||
{
|
|
||||||
BrowserName = browser.Name;
|
|
||||||
BrowserDataPath = browser.DataDirectoryPath;
|
|
||||||
}
|
|
||||||
public string BrowserDataPath { get; init; }
|
|
||||||
public string BookmarkFilePath { get; init; }
|
|
||||||
public string BrowserName { get; init; }
|
|
||||||
|
|
||||||
public override List<Bookmark> GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName);
|
public class CustomChromiumBookmarkLoader : ChromiumBookmarkLoader
|
||||||
|
{
|
||||||
|
public CustomChromiumBookmarkLoader(CustomBrowser browser)
|
||||||
|
{
|
||||||
|
BrowserName = browser.Name;
|
||||||
|
BrowserDataPath = browser.DataDirectoryPath;
|
||||||
}
|
}
|
||||||
}
|
public string BrowserDataPath { get; init; }
|
||||||
|
public string BookmarkFilePath { get; init; }
|
||||||
|
public string BrowserName { get; init; }
|
||||||
|
|
||||||
|
public override List<Bookmark> GetBookmarks() => BrowserDataPath != null ? LoadBookmarks(BrowserDataPath, BrowserName) : LoadBookmarksFromFile(BookmarkFilePath, BrowserName);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,25 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
{
|
|
||||||
public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
|
||||||
{
|
|
||||||
public CustomFirefoxBookmarkLoader(CustomBrowser browser)
|
|
||||||
{
|
|
||||||
BrowserName = browser.Name;
|
|
||||||
BrowserDataPath = browser.DataDirectoryPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Path to places.sqlite
|
|
||||||
/// </summary>
|
|
||||||
public string BrowserDataPath { get; init; }
|
|
||||||
|
|
||||||
public string BrowserName { get; init; }
|
|
||||||
|
|
||||||
public override List<Bookmark> GetBookmarks()
|
public class CustomFirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||||
{
|
{
|
||||||
return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite"));
|
public CustomFirefoxBookmarkLoader(CustomBrowser browser)
|
||||||
}
|
{
|
||||||
|
BrowserName = browser.Name;
|
||||||
|
BrowserDataPath = browser.DataDirectoryPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Path to places.sqlite
|
||||||
|
/// </summary>
|
||||||
|
public string BrowserDataPath { get; init; }
|
||||||
|
|
||||||
|
public string BrowserName { get; init; }
|
||||||
|
|
||||||
|
public override List<Bookmark> GetBookmarks()
|
||||||
|
{
|
||||||
|
return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,20 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
{
|
|
||||||
public class EdgeBookmarkLoader : ChromiumBookmarkLoader
|
|
||||||
{
|
|
||||||
private List<Bookmark> LoadEdgeBookmarks()
|
|
||||||
{
|
|
||||||
var bookmarks = new List<Bookmark>();
|
|
||||||
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
|
||||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge"));
|
|
||||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev"));
|
|
||||||
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary"));
|
|
||||||
|
|
||||||
return bookmarks;
|
public class EdgeBookmarkLoader : ChromiumBookmarkLoader
|
||||||
}
|
{
|
||||||
|
private List<Bookmark> LoadEdgeBookmarks()
|
||||||
public override List<Bookmark> GetBookmarks() => LoadEdgeBookmarks();
|
{
|
||||||
|
var bookmarks = new List<Bookmark>();
|
||||||
|
var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||||
|
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge"));
|
||||||
|
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev"));
|
||||||
|
bookmarks.AddRange(LoadBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary"));
|
||||||
|
|
||||||
|
return bookmarks;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public override List<Bookmark> GetBookmarks() => LoadEdgeBookmarks();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,140 +5,133 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
|
|
||||||
|
public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader
|
||||||
{
|
{
|
||||||
public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader
|
public abstract List<Bookmark> GetBookmarks();
|
||||||
{
|
|
||||||
public abstract List<Bookmark> GetBookmarks();
|
|
||||||
|
|
||||||
private const string queryAllBookmarks = @"SELECT moz_places.url, moz_bookmarks.title
|
private const string QueryAllBookmarks = """
|
||||||
FROM moz_places
|
SELECT moz_places.url, moz_bookmarks.title
|
||||||
INNER JOIN moz_bookmarks ON (
|
FROM moz_places
|
||||||
|
INNER JOIN moz_bookmarks ON (
|
||||||
moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id
|
moz_bookmarks.fk NOT NULL AND moz_bookmarks.title NOT NULL AND moz_bookmarks.fk = moz_places.id
|
||||||
)
|
)
|
||||||
ORDER BY moz_places.visit_count DESC
|
ORDER BY moz_places.visit_count DESC
|
||||||
";
|
""";
|
||||||
|
|
||||||
private const string dbPathFormat = "Data Source ={0}";
|
private const string DbPathFormat = "Data Source ={0}";
|
||||||
|
|
||||||
protected static List<Bookmark> GetBookmarksFromPath(string placesPath)
|
protected static List<Bookmark> GetBookmarksFromPath(string placesPath)
|
||||||
{
|
{
|
||||||
// Return empty list if the places.sqlite file cannot be found
|
// Return empty list if the places.sqlite file cannot be found
|
||||||
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
||||||
return new List<Bookmark>();
|
return new List<Bookmark>();
|
||||||
|
|
||||||
var bookmarkList = new List<Bookmark>();
|
Main.RegisterBookmarkFile(placesPath);
|
||||||
|
|
||||||
Main.RegisterBookmarkFile(placesPath);
|
// create the connection string and init the connection
|
||||||
|
string dbPath = string.Format(DbPathFormat, placesPath);
|
||||||
|
using var dbConnection = new SqliteConnection(dbPath);
|
||||||
|
// Open connection to the database file and execute the query
|
||||||
|
dbConnection.Open();
|
||||||
|
var reader = new SqliteCommand(QueryAllBookmarks, dbConnection).ExecuteReader();
|
||||||
|
|
||||||
// create the connection string and init the connection
|
// return results in List<Bookmark> format
|
||||||
string dbPath = string.Format(dbPathFormat, placesPath);
|
return reader
|
||||||
using var dbConnection = new SqliteConnection(dbPath);
|
.Select(
|
||||||
// Open connection to the database file and execute the query
|
x => new Bookmark(
|
||||||
dbConnection.Open();
|
x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||||
var reader = new SqliteCommand(queryAllBookmarks, dbConnection).ExecuteReader();
|
x["url"].ToString()
|
||||||
|
)
|
||||||
// return results in List<Bookmark> format
|
)
|
||||||
bookmarkList = reader.Select(
|
.ToList();
|
||||||
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
}
|
||||||
x["url"].ToString())
|
}
|
||||||
).ToList();
|
|
||||||
|
|
||||||
return bookmarkList;
|
|
||||||
}
|
public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Searches the places.sqlite db and returns all bookmarks
|
||||||
|
/// </summary>
|
||||||
|
public override List<Bookmark> GetBookmarks()
|
||||||
|
{
|
||||||
|
return GetBookmarksFromPath(PlacesPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
/// Path to places.sqlite
|
||||||
|
/// </summary>
|
||||||
|
private string PlacesPath
|
||||||
{
|
{
|
||||||
/// <summary>
|
get
|
||||||
/// Searches the places.sqlite db and returns all bookmarks
|
|
||||||
/// </summary>
|
|
||||||
public override List<Bookmark> GetBookmarks()
|
|
||||||
{
|
{
|
||||||
return GetBookmarksFromPath(PlacesPath);
|
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
|
||||||
}
|
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Path to places.sqlite
|
|
||||||
/// </summary>
|
|
||||||
private string PlacesPath
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
|
|
||||||
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
|
|
||||||
|
|
||||||
if (!File.Exists(profileIni))
|
if (!File.Exists(profileIni))
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
// get firefox default profile directory from profiles.ini
|
// get firefox default profile directory from profiles.ini
|
||||||
string ini;
|
using var sReader = new StreamReader(profileIni);
|
||||||
using (var sReader = new StreamReader(profileIni))
|
var ini = sReader.ReadToEnd();
|
||||||
{
|
|
||||||
ini = sReader.ReadToEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Current profiles.ini structure example as of Firefox version 69.0.1
|
Current profiles.ini structure example as of Firefox version 69.0.1
|
||||||
|
|
||||||
[Install736426B0AF4A39CB]
|
|
||||||
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
|
|
||||||
Locked=1
|
|
||||||
|
|
||||||
[Profile2]
|
[Install736426B0AF4A39CB]
|
||||||
Name=newblahprofile
|
Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile
|
||||||
IsRelative=0
|
Locked=1
|
||||||
Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
|
|
||||||
|
|
||||||
[Profile1]
|
[Profile2]
|
||||||
Name=default
|
Name=newblahprofile
|
||||||
IsRelative=1
|
IsRelative=0
|
||||||
Path=Profiles/cydum7q4.default
|
Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code.
|
||||||
Default=1
|
|
||||||
|
|
||||||
[Profile0]
|
[Profile1]
|
||||||
Name=default-release
|
Name=default
|
||||||
IsRelative=1
|
IsRelative=1
|
||||||
Path=Profiles/7789f565.default-release
|
Path=Profiles/cydum7q4.default
|
||||||
|
Default=1
|
||||||
|
|
||||||
[General]
|
[Profile0]
|
||||||
StartWithLastProfile=1
|
Name=default-release
|
||||||
Version=2
|
IsRelative=1
|
||||||
*/
|
Path=Profiles/7789f565.default-release
|
||||||
|
|
||||||
var lines = ini.Split(new string[]
|
[General]
|
||||||
{
|
StartWithLastProfile=1
|
||||||
"\r\n"
|
Version=2
|
||||||
}, StringSplitOptions.None).ToList();
|
*/
|
||||||
|
var lines = ini.Split("\r\n").ToList();
|
||||||
|
|
||||||
var defaultProfileFolderNameRaw = lines.Where(x => x.Contains("Default=") && x != "Default=1").FirstOrDefault() ?? string.Empty;
|
var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
|
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
|
var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last();
|
||||||
|
|
||||||
var indexOfDefaultProfileAtttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
|
var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName);
|
||||||
|
|
||||||
// Seen in the example above, the IsRelative attribute is always above the Path attribute
|
// Seen in the example above, the IsRelative attribute is always above the Path attribute
|
||||||
var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1];
|
var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1];
|
||||||
|
|
||||||
return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0
|
return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0
|
||||||
? defaultProfileFolderName + @"\places.sqlite"
|
? defaultProfileFolderName + @"\places.sqlite"
|
||||||
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Extensions
|
public static class Extensions
|
||||||
{
|
{
|
||||||
public static IEnumerable<T> Select<T>(this SqliteDataReader reader, Func<SqliteDataReader, T> projection)
|
public static IEnumerable<T> Select<T>(this SqliteDataReader reader, Func<SqliteDataReader, T> projection)
|
||||||
{
|
{
|
||||||
while (reader.Read())
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
yield return projection(reader);
|
yield return projection(reader);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.2" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
|
|
||||||
|
public interface IBookmarkLoader
|
||||||
{
|
{
|
||||||
public interface IBookmarkLoader
|
public List<Bookmark> GetBookmarks();
|
||||||
{
|
}
|
||||||
public List<Bookmark> GetBookmarks();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
using Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
||||||
|
|
@ -12,233 +11,234 @@ using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||||
|
|
||||||
|
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable
|
||||||
{
|
{
|
||||||
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu, IDisposable
|
private static PluginInitContext _context;
|
||||||
|
|
||||||
|
private static List<Bookmark> _cachedBookmarks = new List<Bookmark>();
|
||||||
|
|
||||||
|
private static Settings _settings;
|
||||||
|
|
||||||
|
private static bool _initialized = false;
|
||||||
|
|
||||||
|
public void Init(PluginInitContext context)
|
||||||
{
|
{
|
||||||
private static PluginInitContext context;
|
_context = context;
|
||||||
|
|
||||||
private static List<Bookmark> cachedBookmarks = new List<Bookmark>();
|
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
||||||
|
|
||||||
private static Settings _settings;
|
LoadBookmarksIfEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
private static bool initialized = false;
|
private static void LoadBookmarksIfEnabled()
|
||||||
|
{
|
||||||
public void Init(PluginInitContext context)
|
if (_context.CurrentPluginMetadata.Disabled)
|
||||||
{
|
{
|
||||||
Main.context = context;
|
// Don't load or monitor files if disabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
_cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
||||||
|
_ = MonitorRefreshQueueAsync();
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Result> Query(Query query)
|
||||||
|
{
|
||||||
|
// For when the plugin being previously disabled and is now re-enabled
|
||||||
|
if (!_initialized)
|
||||||
|
{
|
||||||
LoadBookmarksIfEnabled();
|
LoadBookmarksIfEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void LoadBookmarksIfEnabled()
|
string param = query.Search.TrimStart();
|
||||||
|
|
||||||
|
// Should top results be returned? (true if no search parameters have been passed)
|
||||||
|
var topResults = string.IsNullOrEmpty(param);
|
||||||
|
|
||||||
|
|
||||||
|
if (!topResults)
|
||||||
{
|
{
|
||||||
if (context.CurrentPluginMetadata.Disabled)
|
// Since we mixed chrome and firefox bookmarks, we should order them again
|
||||||
{
|
return _cachedBookmarks
|
||||||
// Don't load or monitor files if disabled
|
.Select(
|
||||||
return;
|
c => new Result
|
||||||
}
|
|
||||||
|
|
||||||
cachedBookmarks = BookmarkLoader.LoadAllBookmarks(_settings);
|
|
||||||
_ = MonitorRefreshQueueAsync();
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
|
||||||
{
|
|
||||||
// For when the plugin being previously disabled and is now renabled
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
LoadBookmarksIfEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
string param = query.Search.TrimStart();
|
|
||||||
|
|
||||||
// Should top results be returned? (true if no search parameters have been passed)
|
|
||||||
var topResults = string.IsNullOrEmpty(param);
|
|
||||||
|
|
||||||
|
|
||||||
if (!topResults)
|
|
||||||
{
|
|
||||||
// Since we mixed chrome and firefox bookmarks, we should order them again
|
|
||||||
var returnList = cachedBookmarks.Select(c => new Result()
|
|
||||||
{
|
|
||||||
Title = c.Name,
|
|
||||||
SubTitle = c.Url,
|
|
||||||
IcoPath = @"Images\bookmark.png",
|
|
||||||
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
|
||||||
Action = _ =>
|
|
||||||
{
|
{
|
||||||
context.API.OpenUrl(c.Url);
|
Title = c.Name,
|
||||||
|
SubTitle = c.Url,
|
||||||
return true;
|
IcoPath = @"Images\bookmark.png",
|
||||||
},
|
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
||||||
ContextData = new BookmarkAttributes
|
Action = _ =>
|
||||||
{
|
|
||||||
Url = c.Url
|
|
||||||
}
|
|
||||||
}).Where(r => r.Score > 0);
|
|
||||||
return returnList.ToList();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return cachedBookmarks.Select(c => new Result()
|
|
||||||
{
|
|
||||||
Title = c.Name,
|
|
||||||
SubTitle = c.Url,
|
|
||||||
IcoPath = @"Images\bookmark.png",
|
|
||||||
Score = 5,
|
|
||||||
Action = _ =>
|
|
||||||
{
|
|
||||||
context.API.OpenUrl(c.Url);
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
ContextData = new BookmarkAttributes
|
|
||||||
{
|
|
||||||
Url = c.Url
|
|
||||||
}
|
|
||||||
}).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static Channel<byte> refreshQueue = Channel.CreateBounded<byte>(1);
|
|
||||||
|
|
||||||
private static SemaphoreSlim fileMonitorSemaphore = new(1, 1);
|
|
||||||
|
|
||||||
private static async Task MonitorRefreshQueueAsync()
|
|
||||||
{
|
|
||||||
if (fileMonitorSemaphore.CurrentCount < 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await fileMonitorSemaphore.WaitAsync();
|
|
||||||
var reader = refreshQueue.Reader;
|
|
||||||
while (await reader.WaitToReadAsync())
|
|
||||||
{
|
|
||||||
if (reader.TryRead(out _))
|
|
||||||
{
|
|
||||||
ReloadAllBookmarks(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fileMonitorSemaphore.Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly List<FileSystemWatcher> Watchers = new();
|
|
||||||
|
|
||||||
internal static void RegisterBookmarkFile(string path)
|
|
||||||
{
|
|
||||||
var directory = Path.GetDirectoryName(path);
|
|
||||||
if (!Directory.Exists(directory) || !File.Exists(path))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase)))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var watcher = new FileSystemWatcher(directory!);
|
|
||||||
watcher.Filter = Path.GetFileName(path);
|
|
||||||
|
|
||||||
watcher.NotifyFilter = NotifyFilters.FileName |
|
|
||||||
NotifyFilters.LastWrite |
|
|
||||||
NotifyFilters.Size;
|
|
||||||
|
|
||||||
watcher.Changed += static (_, _) =>
|
|
||||||
{
|
|
||||||
refreshQueue.Writer.TryWrite(default);
|
|
||||||
};
|
|
||||||
|
|
||||||
watcher.Renamed += static (_, _) =>
|
|
||||||
{
|
|
||||||
refreshQueue.Writer.TryWrite(default);
|
|
||||||
};
|
|
||||||
|
|
||||||
watcher.EnableRaisingEvents = true;
|
|
||||||
|
|
||||||
Watchers.Add(watcher);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReloadData()
|
|
||||||
{
|
|
||||||
ReloadAllBookmarks();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ReloadAllBookmarks(bool disposeFileWatchers = true)
|
|
||||||
{
|
|
||||||
cachedBookmarks.Clear();
|
|
||||||
if (disposeFileWatchers)
|
|
||||||
DisposeFileWatchers();
|
|
||||||
LoadBookmarksIfEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetTranslatedPluginTitle()
|
|
||||||
{
|
|
||||||
return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name");
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetTranslatedPluginDescription()
|
|
||||||
{
|
|
||||||
return context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description");
|
|
||||||
}
|
|
||||||
|
|
||||||
public Control CreateSettingPanel()
|
|
||||||
{
|
|
||||||
return new SettingsControl(_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Result> LoadContextMenus(Result selectedResult)
|
|
||||||
{
|
|
||||||
return new List<Result>()
|
|
||||||
{
|
|
||||||
new Result
|
|
||||||
{
|
|
||||||
Title = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"),
|
|
||||||
SubTitle = context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"),
|
|
||||||
Action = _ =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url);
|
_context.API.OpenUrl(c.Url);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
catch (Exception e)
|
ContextData = new BookmarkAttributes { Url = c.Url }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.Where(r => r.Score > 0)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return _cachedBookmarks
|
||||||
|
.Select(
|
||||||
|
c => new Result
|
||||||
|
{
|
||||||
|
Title = c.Name,
|
||||||
|
SubTitle = c.Url,
|
||||||
|
IcoPath = @"Images\bookmark.png",
|
||||||
|
Score = 5,
|
||||||
|
Action = _ =>
|
||||||
{
|
{
|
||||||
var message = "Failed to set url in clipboard";
|
_context.API.OpenUrl(c.Url);
|
||||||
Log.Exception("Main", message, e, "LoadContextMenus");
|
return true;
|
||||||
|
},
|
||||||
context.API.ShowMsg(message);
|
ContextData = new BookmarkAttributes { Url = c.Url }
|
||||||
|
}
|
||||||
return false;
|
)
|
||||||
}
|
.ToList();
|
||||||
},
|
|
||||||
IcoPath = "Images\\copylink.png",
|
|
||||||
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class BookmarkAttributes
|
|
||||||
{
|
|
||||||
internal string Url { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
DisposeFileWatchers();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DisposeFileWatchers()
|
|
||||||
{
|
|
||||||
foreach (var watcher in Watchers)
|
|
||||||
{
|
|
||||||
watcher.Dispose();
|
|
||||||
}
|
|
||||||
Watchers.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Channel<byte> _refreshQueue = Channel.CreateBounded<byte>(1);
|
||||||
|
|
||||||
|
private static SemaphoreSlim _fileMonitorSemaphore = new(1, 1);
|
||||||
|
|
||||||
|
private static async Task MonitorRefreshQueueAsync()
|
||||||
|
{
|
||||||
|
if (_fileMonitorSemaphore.CurrentCount < 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await _fileMonitorSemaphore.WaitAsync();
|
||||||
|
var reader = _refreshQueue.Reader;
|
||||||
|
while (await reader.WaitToReadAsync())
|
||||||
|
{
|
||||||
|
if (reader.TryRead(out _))
|
||||||
|
{
|
||||||
|
ReloadAllBookmarks(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_fileMonitorSemaphore.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly List<FileSystemWatcher> Watchers = new();
|
||||||
|
|
||||||
|
internal static void RegisterBookmarkFile(string path)
|
||||||
|
{
|
||||||
|
var directory = Path.GetDirectoryName(path);
|
||||||
|
if (!Directory.Exists(directory) || !File.Exists(path))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Watchers.Any(x => x.Path.Equals(directory, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var watcher = new FileSystemWatcher(directory!);
|
||||||
|
watcher.Filter = Path.GetFileName(path);
|
||||||
|
|
||||||
|
watcher.NotifyFilter = NotifyFilters.FileName |
|
||||||
|
NotifyFilters.LastWrite |
|
||||||
|
NotifyFilters.Size;
|
||||||
|
|
||||||
|
watcher.Changed += static (_, _) =>
|
||||||
|
{
|
||||||
|
_refreshQueue.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
|
||||||
|
watcher.Renamed += static (_, _) =>
|
||||||
|
{
|
||||||
|
_refreshQueue.Writer.TryWrite(default);
|
||||||
|
};
|
||||||
|
|
||||||
|
watcher.EnableRaisingEvents = true;
|
||||||
|
|
||||||
|
Watchers.Add(watcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReloadData()
|
||||||
|
{
|
||||||
|
ReloadAllBookmarks();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ReloadAllBookmarks(bool disposeFileWatchers = true)
|
||||||
|
{
|
||||||
|
_cachedBookmarks.Clear();
|
||||||
|
if (disposeFileWatchers)
|
||||||
|
DisposeFileWatchers();
|
||||||
|
LoadBookmarksIfEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTranslatedPluginTitle()
|
||||||
|
{
|
||||||
|
return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetTranslatedPluginDescription()
|
||||||
|
{
|
||||||
|
return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Control CreateSettingPanel()
|
||||||
|
{
|
||||||
|
return new SettingsControl(_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Result> LoadContextMenus(Result selectedResult)
|
||||||
|
{
|
||||||
|
return new List<Result>()
|
||||||
|
{
|
||||||
|
new Result
|
||||||
|
{
|
||||||
|
Title = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"),
|
||||||
|
SubTitle = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"),
|
||||||
|
Action = _ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
var message = "Failed to set url in clipboard";
|
||||||
|
Log.Exception("Main", message, e, "LoadContextMenus");
|
||||||
|
|
||||||
|
_context.API.ShowMsg(message);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IcoPath = @"Images\copylink.png",
|
||||||
|
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class BookmarkAttributes
|
||||||
|
{
|
||||||
|
internal string Url { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
DisposeFileWatchers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DisposeFileWatchers()
|
||||||
|
{
|
||||||
|
foreach (var watcher in Watchers)
|
||||||
|
{
|
||||||
|
watcher.Dispose();
|
||||||
|
}
|
||||||
|
Watchers.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,21 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
namespace Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
|
|
||||||
|
// Source may be important in the future
|
||||||
|
public record Bookmark(string Name, string Url, string Source = "")
|
||||||
{
|
{
|
||||||
// Source may be important in the future
|
public override int GetHashCode()
|
||||||
public record Bookmark(string Name, string Url, string Source = "")
|
|
||||||
{
|
{
|
||||||
public override int GetHashCode()
|
var hashName = Name?.GetHashCode() ?? 0;
|
||||||
{
|
var hashUrl = Url?.GetHashCode() ?? 0;
|
||||||
var hashName = Name?.GetHashCode() ?? 0;
|
return hashName ^ hashUrl;
|
||||||
var hashUrl = Url?.GetHashCode() ?? 0;
|
|
||||||
return hashName ^ hashUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Equals(Bookmark other)
|
|
||||||
{
|
|
||||||
return other != null && Name == other.Name && Url == other.Url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<CustomBrowser> CustomBrowsers { get; set; }= new();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public virtual bool Equals(Bookmark other)
|
||||||
|
{
|
||||||
|
return other != null && Name == other.Name && Url == other.Url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<CustomBrowser> CustomBrowsers { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,44 @@
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
namespace Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
{
|
|
||||||
public class CustomBrowser : BaseModel
|
|
||||||
{
|
|
||||||
private string _name;
|
|
||||||
private string _dataDirectoryPath;
|
|
||||||
private BrowserType browserType = BrowserType.Chromium;
|
|
||||||
|
|
||||||
public string Name
|
public class CustomBrowser : BaseModel
|
||||||
|
{
|
||||||
|
private string _name;
|
||||||
|
private string _dataDirectoryPath;
|
||||||
|
private BrowserType _browserType = BrowserType.Chromium;
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
get => _name;
|
_name = value;
|
||||||
set
|
OnPropertyChanged();
|
||||||
{
|
|
||||||
_name = value;
|
|
||||||
OnPropertyChanged(nameof(Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string DataDirectoryPath
|
|
||||||
{
|
|
||||||
get => _dataDirectoryPath;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_dataDirectoryPath = value;
|
|
||||||
OnPropertyChanged(nameof(DataDirectoryPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BrowserType BrowserType
|
|
||||||
{
|
|
||||||
get => browserType;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
browserType = value;
|
|
||||||
OnPropertyChanged(nameof(BrowserType));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum BrowserType
|
public string DataDirectoryPath
|
||||||
{
|
{
|
||||||
Chromium,
|
get => _dataDirectoryPath;
|
||||||
Firefox,
|
set
|
||||||
|
{
|
||||||
|
_dataDirectoryPath = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BrowserType BrowserType
|
||||||
|
{
|
||||||
|
get => _browserType;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_browserType = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum BrowserType
|
||||||
|
{
|
||||||
|
Chromium,
|
||||||
|
Firefox,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
namespace Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
|
|
||||||
|
public class Settings : BaseModel
|
||||||
{
|
{
|
||||||
public class Settings : BaseModel
|
public bool OpenInNewBrowserWindow { get; set; } = true;
|
||||||
{
|
|
||||||
public bool OpenInNewBrowserWindow { get; set; } = true;
|
|
||||||
|
|
||||||
public string BrowserPath { get; set; }
|
public string BrowserPath { get; set; }
|
||||||
|
|
||||||
public bool LoadChromeBookmark { get; set; } = true;
|
public bool LoadChromeBookmark { get; set; } = true;
|
||||||
public bool LoadFirefoxBookmark { get; set; } = true;
|
public bool LoadFirefoxBookmark { get; set; } = true;
|
||||||
public bool LoadEdgeBookmark { get; set; } = true;
|
public bool LoadEdgeBookmark { get; set; } = true;
|
||||||
|
|
||||||
public ObservableCollection<CustomBrowser> CustomChromiumBrowsers { get; set; } = new();
|
public ObservableCollection<CustomBrowser> CustomChromiumBrowsers { get; set; } = new();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue