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
|
||||
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.symbols = constant_fields
|
||||
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_using_directive_placement = outside_namespace:silent
|
||||
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_expression_bodied_lambdas = true: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
|
||||
workaround
|
||||
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
|
||||
dopusrt
|
||||
firefox
|
||||
Firefox
|
||||
msedge
|
||||
svgc
|
||||
ime
|
||||
|
|
@ -97,6 +98,7 @@ Português
|
|||
Português (Brasil)
|
||||
Italiano
|
||||
Slovenský
|
||||
Tiếng Việt
|
||||
Droplex
|
||||
Preinstalled
|
||||
errormetadatafile
|
||||
|
|
|
|||
24
.github/workflows/default_plugins.yml
vendored
24
.github/workflows/default_plugins.yml
vendored
|
|
@ -65,7 +65,7 @@ jobs:
|
|||
|
||||
- name: Publish BrowserBookmark
|
||||
if: steps.changes.outputs.browserbookmark == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.BrowserBookmark"
|
||||
files: "Flow.Launcher.Plugin.BrowserBookmark.zip"
|
||||
|
|
@ -92,7 +92,7 @@ jobs:
|
|||
|
||||
- name: Publish Calculator
|
||||
if: steps.changes.outputs.calculator == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Calculator"
|
||||
files: "Flow.Launcher.Plugin.Calculator.zip"
|
||||
|
|
@ -119,7 +119,7 @@ jobs:
|
|||
|
||||
- name: Publish Explorer
|
||||
if: steps.changes.outputs.explorer == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Explorer"
|
||||
files: "Flow.Launcher.Plugin.Explorer.zip"
|
||||
|
|
@ -146,7 +146,7 @@ jobs:
|
|||
|
||||
- name: Publish PluginIndicator
|
||||
if: steps.changes.outputs.pluginindicator == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginIndicator"
|
||||
files: "Flow.Launcher.Plugin.PluginIndicator.zip"
|
||||
|
|
@ -173,7 +173,7 @@ jobs:
|
|||
|
||||
- name: Publish PluginsManager
|
||||
if: steps.changes.outputs.pluginsmanager == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginsManager"
|
||||
files: "Flow.Launcher.Plugin.PluginsManager.zip"
|
||||
|
|
@ -200,7 +200,7 @@ jobs:
|
|||
|
||||
- name: Publish ProcessKiller
|
||||
if: steps.changes.outputs.processkiller == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller"
|
||||
files: "Flow.Launcher.Plugin.ProcessKiller.zip"
|
||||
|
|
@ -227,7 +227,7 @@ jobs:
|
|||
|
||||
- name: Publish Program
|
||||
if: steps.changes.outputs.program == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Program"
|
||||
files: "Flow.Launcher.Plugin.Program.zip"
|
||||
|
|
@ -254,7 +254,7 @@ jobs:
|
|||
|
||||
- name: Publish Shell
|
||||
if: steps.changes.outputs.shell == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Shell"
|
||||
files: "Flow.Launcher.Plugin.Shell.zip"
|
||||
|
|
@ -281,7 +281,7 @@ jobs:
|
|||
|
||||
- name: Publish Sys
|
||||
if: steps.changes.outputs.sys == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Sys"
|
||||
files: "Flow.Launcher.Plugin.Sys.zip"
|
||||
|
|
@ -308,7 +308,7 @@ jobs:
|
|||
|
||||
- name: Publish Url
|
||||
if: steps.changes.outputs.url == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.Url"
|
||||
files: "Flow.Launcher.Plugin.Url.zip"
|
||||
|
|
@ -335,7 +335,7 @@ jobs:
|
|||
|
||||
- name: Publish WebSearch
|
||||
if: steps.changes.outputs.websearch == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.WebSearch"
|
||||
files: "Flow.Launcher.Plugin.WebSearch.zip"
|
||||
|
|
@ -362,7 +362,7 @@ jobs:
|
|||
|
||||
- name: Publish WindowsSettings
|
||||
if: steps.changes.outputs.windowssettings == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
repository: "Flow-Launcher/Flow.Launcher.Plugin.WindowsSettings"
|
||||
files: "Flow.Launcher.Plugin.WindowsSettings.zip"
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
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 Czech = new Language("cs", "čeština");
|
||||
public static Language Arabic = new Language("ar", "اللغة العربية");
|
||||
public static Language Vietnamese = new Language("vi-vn", "Tiếng Việt");
|
||||
|
||||
|
||||
public static List<Language> GetAvailableLanguages()
|
||||
{
|
||||
|
|
@ -54,7 +56,8 @@ namespace Flow.Launcher.Core.Resource
|
|||
Slovak,
|
||||
Turkish,
|
||||
Czech,
|
||||
Arabic
|
||||
Arabic,
|
||||
Vietnamese
|
||||
};
|
||||
return languages;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ namespace Flow.Launcher.Infrastructure
|
|||
public static class Constant
|
||||
{
|
||||
public const string FlowLauncher = "Flow.Launcher";
|
||||
public const string FlowLauncherFullName = "Flow Launcher";
|
||||
public const string Plugins = "Plugins";
|
||||
public const string PluginMetadataFileName = "plugin.json";
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</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="NLog" 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
|
||||
{
|
||||
public class HotkeyModel
|
||||
public record struct HotkeyModel
|
||||
{
|
||||
public bool Alt { 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>
|
||||
{
|
||||
{Key.Space, "Space"},
|
||||
{Key.Oem3, "~"}
|
||||
{ Key.Space, "Space" }, { Key.Oem3, "~" }
|
||||
};
|
||||
|
||||
public ModifierKeys ModifierKeys
|
||||
|
|
@ -30,18 +29,22 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
{
|
||||
modifierKeys |= ModifierKeys.Alt;
|
||||
}
|
||||
|
||||
if (Shift)
|
||||
{
|
||||
modifierKeys |= ModifierKeys.Shift;
|
||||
}
|
||||
|
||||
if (Win)
|
||||
{
|
||||
modifierKeys |= ModifierKeys.Windows;
|
||||
}
|
||||
|
||||
if (Ctrl)
|
||||
{
|
||||
modifierKeys |= ModifierKeys.Control;
|
||||
}
|
||||
|
||||
return modifierKeys;
|
||||
}
|
||||
}
|
||||
|
|
@ -66,31 +69,37 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> keys = hotkeyString.Replace(" ", "").Split('+').ToList();
|
||||
if (keys.Contains("Alt"))
|
||||
{
|
||||
Alt = true;
|
||||
keys.Remove("Alt");
|
||||
}
|
||||
|
||||
if (keys.Contains("Shift"))
|
||||
{
|
||||
Shift = true;
|
||||
keys.Remove("Shift");
|
||||
}
|
||||
|
||||
if (keys.Contains("Win"))
|
||||
{
|
||||
Win = true;
|
||||
keys.Remove("Win");
|
||||
}
|
||||
|
||||
if (keys.Contains("Ctrl"))
|
||||
{
|
||||
Ctrl = true;
|
||||
keys.Remove("Ctrl");
|
||||
}
|
||||
|
||||
if (keys.Count == 1)
|
||||
{
|
||||
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)
|
||||
{
|
||||
CharKey = specialSymbolPair.Value.Key;
|
||||
|
|
@ -103,7 +112,6 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -111,33 +119,39 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
List<string> keys = new List<string>();
|
||||
if (Ctrl)
|
||||
return string.Join(" + ", EnumerateDisplayKeys());
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
keys.Add(specialSymbolDictionary.ContainsKey(CharKey)
|
||||
? specialSymbolDictionary[CharKey]
|
||||
: CharKey.ToString());
|
||||
yield return specialSymbolDictionary.TryGetValue(CharKey, out var value)
|
||||
? value
|
||||
: CharKey.ToString();
|
||||
}
|
||||
return string.Join(" + ", keys);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Validate hotkey
|
||||
/// </summary>
|
||||
|
|
@ -164,11 +178,13 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (ModifierKeys == ModifierKeys.None)
|
||||
{
|
||||
return !IsPrintableCharacter(CharKey);
|
||||
|
|
@ -206,18 +222,6 @@ namespace Flow.Launcher.Infrastructure.Hotkey
|
|||
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()
|
||||
{
|
||||
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.Text.Json.Serialization;
|
||||
using System.Windows;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
using Flow.Launcher.ViewModel;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.UserSettings
|
||||
{
|
||||
public class Settings : BaseModel
|
||||
public class Settings : BaseModel, IHotkeySettings
|
||||
{
|
||||
private string language = "en";
|
||||
private string _theme = Constant.DefaultTheme;
|
||||
|
|
@ -20,6 +21,16 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
public bool ShowOpenResultHotkey { get; set; } = true;
|
||||
public double WindowSize { get; set; } = 580;
|
||||
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
|
||||
{
|
||||
|
|
@ -54,6 +65,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
public bool UseGlyphIcons { get; set; } = true;
|
||||
public bool UseAnimation { get; set; } = true;
|
||||
public bool UseSound { get; set; } = true;
|
||||
public double SoundVolume { get; set; } = 50;
|
||||
|
||||
public bool UseClock { get; set; } = true;
|
||||
public bool UseDate { get; set; } = false;
|
||||
public string TimeFormat { get; set; } = "hh:mm tt";
|
||||
|
|
@ -195,17 +208,17 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
|
||||
public double WindowLeft { get; set; }
|
||||
public double WindowTop { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Custom left position on selected monitor
|
||||
/// </summary>
|
||||
public double CustomWindowLeft { get; set; } = 0;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Custom top position on selected monitor
|
||||
/// </summary>
|
||||
public double CustomWindowTop { get; set; } = 0;
|
||||
|
||||
|
||||
public int MaxResultsToShow { get; set; } = 5;
|
||||
public int ActivateTimes { get; set; }
|
||||
|
||||
|
|
@ -217,7 +230,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
[JsonIgnore]
|
||||
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)
|
||||
};
|
||||
|
||||
|
|
@ -241,7 +254,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public SearchWindowScreens SearchWindowScreen { get; set; } = SearchWindowScreens.Cursor;
|
||||
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
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
|
||||
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
|
||||
|
|
@ -276,7 +365,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
Light,
|
||||
Dark
|
||||
}
|
||||
|
||||
|
||||
public enum SearchWindowScreens
|
||||
{
|
||||
RememberLastLaunchLocation,
|
||||
|
|
@ -285,7 +374,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
Primary,
|
||||
Custom
|
||||
}
|
||||
|
||||
|
||||
public enum SearchWindowAligns
|
||||
{
|
||||
Center,
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>4.2.0</Version>
|
||||
<PackageVersion>4.2.0</PackageVersion>
|
||||
<AssemblyVersion>4.2.0</AssemblyVersion>
|
||||
<FileVersion>4.2.0</FileVersion>
|
||||
<Version>4.3.0</Version>
|
||||
<PackageVersion>4.3.0</PackageVersion>
|
||||
<AssemblyVersion>4.3.0</AssemblyVersion>
|
||||
<FileVersion>4.3.0</FileVersion>
|
||||
<PackageId>Flow.Launcher.Plugin</PackageId>
|
||||
<Authors>Flow-Launcher</Authors>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
|
|
|||
|
|
@ -291,5 +291,12 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
/// <returns></returns>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Additional data associated with this result
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -3,39 +3,38 @@ using System.Globalization;
|
|||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
namespace Flow.Launcher.Converters;
|
||||
|
||||
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)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
true => InputMethodState.Off,
|
||||
_ => InputMethodState.DoNotCare
|
||||
};
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
internal class BoolToIMEStateConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
true => InputMethodState.Off,
|
||||
_ => 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.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,
|
||||
(_, null) => Visibility.Collapsed
|
||||
};
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
|
||||
(true, null) => Visibility.Visible,
|
||||
(_, null) => Visibility.Collapsed
|
||||
};
|
||||
}
|
||||
|
||||
public class SplitterConverter : IValueConverter
|
||||
/* 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)
|
||||
{
|
||||
return (value, parameter) switch
|
||||
{
|
||||
(true, not 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();
|
||||
}
|
||||
|
||||
public class SplitterConverter : IValueConverter
|
||||
/* 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)
|
||||
{
|
||||
return (value, parameter) switch
|
||||
{
|
||||
(true, not 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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,43 +7,41 @@ using System.Windows.Shapes;
|
|||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
|
||||
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.Windows.Data;
|
||||
|
||||
namespace Flow.Launcher.Converters
|
||||
{
|
||||
public class DateTimeFormatToNowConverter : IValueConverter
|
||||
{
|
||||
namespace Flow.Launcher.Converters;
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value is not string format ? null : DateTime.Now.ToString(format);
|
||||
}
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
public class DateTimeFormatToNowConverter : IValueConverter
|
||||
{
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value is not string format ? null : DateTime.Now.ToString(format);
|
||||
}
|
||||
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.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(0, 0);
|
||||
return new Point(d / 2, d / 2);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
return new Point(0, 0);
|
||||
}
|
||||
|
||||
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.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[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();
|
||||
if (value.Length < 2)
|
||||
return new Run(string.Empty);
|
||||
|
||||
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);
|
||||
var run = new Run(currentCharacter)
|
||||
{
|
||||
Style = ShouldHighlight(highlightData, i) ? highlightStyle : null
|
||||
};
|
||||
textBlock.Inlines.Add(run);
|
||||
}
|
||||
return textBlock;
|
||||
Style = ShouldHighlight(highlightData, i) ? highlightStyle : null
|
||||
};
|
||||
textBlock.Inlines.Add(run);
|
||||
}
|
||||
return textBlock;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return new[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
|
||||
}
|
||||
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return new[] { DependencyProperty.UnsetValue, DependencyProperty.UnsetValue };
|
||||
}
|
||||
|
||||
private bool ShouldHighlight(List<int> highlightData, int index)
|
||||
{
|
||||
return highlightData.Contains(index);
|
||||
}
|
||||
private bool ShouldHighlight(List<int> highlightData, int index)
|
||||
{
|
||||
return highlightData.Contains(index);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,20 +2,19 @@
|
|||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
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]");
|
||||
namespace Flow.Launcher.Converters;
|
||||
|
||||
return isIconCircular ? size / 2 : size;
|
||||
}
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
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 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.Data;
|
||||
|
||||
namespace Flow.Launcher.Converters
|
||||
namespace Flow.Launcher.Converters;
|
||||
|
||||
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||
public class OpenResultHotkeyVisibilityConverter : IValueConverter
|
||||
{
|
||||
[ValueConversion(typeof(bool), typeof(Visibility))]
|
||||
public class OpenResultHotkeyVisibilityConverter : IValueConverter
|
||||
private const int MaxVisibleHotkeys = 10;
|
||||
|
||||
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)
|
||||
{
|
||||
var number = int.MaxValue;
|
||||
if (value is ListBoxItem listBoxItem
|
||||
&& ItemsControl.ItemsControlFromItemContainer(listBoxItem) is ListBox listBox)
|
||||
number = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
|
||||
|
||||
if (value is ListBoxItem listBoxItem
|
||||
&& 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();
|
||||
return number <= MaxVisibleHotkeys ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
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.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
|
||||
|| 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
|
||||
|
||||
return 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.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
|
||||
// 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)
|
||||
)
|
||||
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;
|
||||
|
||||
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.
|
||||
// When user typed lower case and result title is uppercase, we still want to display suggestion
|
||||
selectedItem.QuerySuggestionText = queryText + selectedResultPossibleSuggestion.Substring(queryText.Length);
|
||||
// For AutocompleteQueryCommand.
|
||||
// When user typed lower case and result title is uppercase, we still want to display suggestion
|
||||
selectedItem.QuerySuggestionText = queryText + selectedResultPossibleSuggestion.Substring(queryText.Length);
|
||||
|
||||
// Check if Text will be larger than our QueryTextBox
|
||||
Typeface typeface = new Typeface(queryTextBox.FontFamily, queryTextBox.FontStyle, queryTextBox.FontWeight, queryTextBox.FontStretch);
|
||||
// TODO: Obsolete warning?
|
||||
var ft = new FormattedText(queryTextBox.Text, CultureInfo.DefaultThreadCurrentCulture, System.Windows.FlowDirection.LeftToRight, typeface, queryTextBox.FontSize, Brushes.Black);
|
||||
// Check if Text will be larger than our QueryTextBox
|
||||
Typeface typeface = new Typeface(queryTextBox.FontFamily, queryTextBox.FontStyle, queryTextBox.FontWeight, queryTextBox.FontStretch);
|
||||
// TODO: Obsolete warning?
|
||||
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)
|
||||
return string.Empty;
|
||||
|
||||
return selectedItem.QuerySuggestionText;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception(nameof(QuerySuggestionBoxConverter), "fail to convert text for suggestion box", e);
|
||||
if (ft.Width + offset > queryTextBox.ActualWidth || queryTextBox.HorizontalOffset != 0)
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return selectedItem.QuerySuggestionText;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
catch (Exception e)
|
||||
{
|
||||
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.Input;
|
||||
|
||||
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
|
||||
};
|
||||
}
|
||||
namespace Flow.Launcher.Converters;
|
||||
|
||||
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.ViewModel;
|
||||
|
||||
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);
|
||||
}
|
||||
namespace Flow.Launcher.Converters;
|
||||
|
||||
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"
|
||||
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:flowlauncher="clr-namespace:Flow.Launcher"
|
||||
Title="{DynamicResource customeQueryHotkeyTitle}"
|
||||
Width="530"
|
||||
Background="{DynamicResource PopuBGColor}"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
Foreground="{DynamicResource PopupTextColor}"
|
||||
Icon="Images\app.png"
|
||||
MouseDown="window_MouseDown"
|
||||
|
|
@ -60,94 +62,76 @@
|
|||
</Grid>
|
||||
</StackPanel>
|
||||
<StackPanel Margin="26,0,26,0">
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,12">
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
Margin="0,0,0,0"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Text="{DynamicResource customeQueryHotkeyTitle}"
|
||||
TextAlignment="Left" />
|
||||
</StackPanel>
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
FontSize="14"
|
||||
Text="{DynamicResource customeQueryHotkeyTips}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
<Image
|
||||
Width="478"
|
||||
Margin="0,20,0,0"
|
||||
Source="/Images/illustration_01.png" />
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
Margin="0,0,0,12"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Text="{DynamicResource customeQueryHotkeyTitle}"
|
||||
TextAlignment="Left" />
|
||||
<TextBlock
|
||||
FontSize="14"
|
||||
Text="{DynamicResource customeQueryHotkeyTips}"
|
||||
TextAlignment="Left"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
<Image
|
||||
Width="478"
|
||||
Margin="0,20,0,0"
|
||||
Source="/Images/illustration_01.png" />
|
||||
|
||||
<StackPanel Margin="0,20,0,0" Orientation="Horizontal">
|
||||
<Grid Width="478">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource hotkey}" />
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Orientation="Horizontal">
|
||||
<flowlauncher:HotkeyControl
|
||||
x:Name="ctlHotkey"
|
||||
Grid.Column="1"
|
||||
Width="200"
|
||||
Height="36"
|
||||
Margin="10,0,10,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Left" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource actionKeyword}" />
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource customQuery}" />
|
||||
<DockPanel
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
LastChildFill="True">
|
||||
<Button
|
||||
x:Name="btnTestActionKeyword"
|
||||
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>
|
||||
<Grid Width="478" Margin="0,20,0,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource hotkey}" />
|
||||
<flowlauncher:HotkeyControl
|
||||
x:Name="HotkeyControl"
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="10,0,10,0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalContentAlignment="Left"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="" />
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource customQuery}" />
|
||||
<TextBox
|
||||
x:Name="tbAction"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center" />
|
||||
<Button
|
||||
x:Name="btnTestActionKeyword"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Margin="0,0,10,0"
|
||||
Padding="10,5,10,5"
|
||||
Click="BtnTestActionKeyword_OnClick"
|
||||
Content="{DynamicResource preview}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<Border
|
||||
|
|
@ -174,4 +158,4 @@
|
|||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
</Window>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.ViewModel;
|
||||
|
||||
namespace Flow.Launcher
|
||||
{
|
||||
|
|
@ -14,13 +15,13 @@ namespace Flow.Launcher
|
|||
private SettingWindow _settingWidow;
|
||||
private bool update;
|
||||
private CustomPluginHotkey updateCustomHotkey;
|
||||
private Settings _settings;
|
||||
public Settings Settings { get; }
|
||||
|
||||
public CustomQueryHotkeySetting(SettingWindow settingWidow, Settings settings)
|
||||
{
|
||||
_settingWidow = settingWidow;
|
||||
Settings = settings;
|
||||
InitializeComponent();
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
|
||||
|
|
@ -32,36 +33,21 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (!update)
|
||||
{
|
||||
if (!ctlHotkey.CurrentHotkeyAvailable)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("hotkeyIsNotUnavailable"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_settings.CustomPluginHotkeys == null)
|
||||
{
|
||||
_settings.CustomPluginHotkeys = new ObservableCollection<CustomPluginHotkey>();
|
||||
}
|
||||
Settings.CustomPluginHotkeys ??= new ObservableCollection<CustomPluginHotkey>();
|
||||
|
||||
var pluginHotkey = new CustomPluginHotkey
|
||||
{
|
||||
Hotkey = ctlHotkey.CurrentHotkey.ToString(),
|
||||
ActionKeyword = tbAction.Text
|
||||
Hotkey = HotkeyControl.CurrentHotkey.ToString(), ActionKeyword = tbAction.Text
|
||||
};
|
||||
_settings.CustomPluginHotkeys.Add(pluginHotkey);
|
||||
Settings.CustomPluginHotkeys.Add(pluginHotkey);
|
||||
|
||||
HotKeyMapper.SetCustomQueryHotkey(pluginHotkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (updateCustomHotkey.Hotkey != ctlHotkey.CurrentHotkey.ToString() && !ctlHotkey.CurrentHotkeyAvailable)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("hotkeyIsNotUnavailable"));
|
||||
return;
|
||||
}
|
||||
var oldHotkey = updateCustomHotkey.Hotkey;
|
||||
updateCustomHotkey.ActionKeyword = tbAction.Text;
|
||||
updateCustomHotkey.Hotkey = ctlHotkey.CurrentHotkey.ToString();
|
||||
updateCustomHotkey.Hotkey = HotkeyControl.CurrentHotkey.ToString();
|
||||
//remove origin hotkey
|
||||
HotKeyMapper.RemoveHotkey(oldHotkey);
|
||||
HotKeyMapper.SetCustomQueryHotkey(updateCustomHotkey);
|
||||
|
|
@ -70,9 +56,11 @@ namespace Flow.Launcher
|
|||
Close();
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidPluginHotkey"));
|
||||
|
|
@ -81,7 +69,7 @@ namespace Flow.Launcher
|
|||
}
|
||||
|
||||
tbAction.Text = updateCustomHotkey.ActionKeyword;
|
||||
_ = ctlHotkey.SetHotkeyAsync(updateCustomHotkey.Hotkey, false);
|
||||
HotkeyControl.SetHotkey(updateCustomHotkey.Hotkey, false);
|
||||
update = true;
|
||||
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 */
|
||||
{
|
||||
TextBox textBox = Keyboard.FocusedElement as TextBox;
|
||||
if (textBox != null)
|
||||
{
|
||||
TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
textBox.MoveFocus(tRequest);
|
||||
}
|
||||
if (Keyboard.FocusedElement is not TextBox textBox) return;
|
||||
|
||||
TraversalRequest tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
textBox.MoveFocus(tRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,57 +3,56 @@ using Flow.Launcher.Infrastructure;
|
|||
using Flow.Launcher.Infrastructure.Logger;
|
||||
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";
|
||||
|
||||
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()
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
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)
|
||||
{
|
||||
Log.Error("AutoStartup", $"Failed to disable auto-startup: {e}");
|
||||
throw;
|
||||
Log.Error("AutoStartup", $"Ignoring non-critical registry error (querying if enabled): {e}");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Enable()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Disable()
|
||||
{
|
||||
try
|
||||
{
|
||||
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;
|
||||
}
|
||||
using var key = Registry.CurrentUser.OpenSubKey(StartupPath, true);
|
||||
key?.DeleteValue(Constant.FlowLauncher, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("AutoStartup", $"Failed to disable 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.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)
|
||||
{
|
||||
|
||||
[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))
|
||||
{
|
||||
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);
|
||||
|
||||
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
|
||||
if (ret1 == 0)
|
||||
{
|
||||
WindowInteropHelper helper = new WindowInteropHelper(window);
|
||||
int val = 2;
|
||||
int ret1 = DwmSetWindowAttribute(helper.Handle, 2, ref val, 4);
|
||||
|
||||
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;
|
||||
}
|
||||
Margins m = new Margins { Bottom = 0, Left = 0, Right = 0, Top = 0 };
|
||||
int ret2 = DwmExtendFrameIntoClientArea(helper.Handle, ref m);
|
||||
return ret2 == 0;
|
||||
}
|
||||
catch (Exception)
|
||||
else
|
||||
{
|
||||
// Probably dwmapi.dll not found (incompatible OS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception)
|
||||
{
|
||||
// Probably dwmapi.dll not found (incompatible OS)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,68 +2,67 @@
|
|||
using System.IO;
|
||||
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;
|
||||
|
||||
public DataWebRequest(Uri uri)
|
||||
{
|
||||
m_uri = uri;
|
||||
}
|
||||
|
||||
public override WebResponse GetResponse()
|
||||
{
|
||||
return new DataWebResponse(m_uri);
|
||||
}
|
||||
_uri = uri;
|
||||
}
|
||||
|
||||
class DataWebResponse : WebResponse
|
||||
public override WebResponse GetResponse()
|
||||
{
|
||||
private readonly string m_contentType;
|
||||
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);
|
||||
return new DataWebResponse(_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.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 reportWindow = new ReportWindow(e);
|
||||
reportWindow.Show();
|
||||
}
|
||||
var logger = LogManager.GetLogger("UnHandledException");
|
||||
logger.Fatal(ExceptionFormatter.FormatExcpetion(e));
|
||||
var reportWindow = new ReportWindow(e);
|
||||
reportWindow.Show();
|
||||
}
|
||||
|
||||
public static void UnhandledExceptionHandle(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
//handle non-ui thread exceptions
|
||||
Report((Exception)e.ExceptionObject);
|
||||
}
|
||||
public static void UnhandledExceptionHandle(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
//handle non-ui thread exceptions
|
||||
Report((Exception)e.ExceptionObject);
|
||||
}
|
||||
|
||||
public static void DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
//handle ui thread exceptions
|
||||
Report(e.Exception);
|
||||
//prevent application exist, so the user can copy prompted error info
|
||||
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 void DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
//handle ui thread exceptions
|
||||
Report(e.Exception);
|
||||
//prevent application exist, so the user can copy prompted error info
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
public static string DependenciesInfo()
|
||||
{
|
||||
var info = $"\nPython Path: {Constant.PythonPath}\nNode Path: {Constant.NodePath}";
|
||||
return info;
|
||||
}
|
||||
public static string RuntimeInfo()
|
||||
{
|
||||
var 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 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;
|
||||
private static MainViewModel mainViewModel;
|
||||
_mainViewModel = mainVM;
|
||||
_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;
|
||||
settings = mainViewModel.Settings;
|
||||
|
||||
SetHotkey(settings.Hotkey, OnToggleHotkey);
|
||||
LoadCustomPluginHotkey();
|
||||
HotkeyManager.Current.AddOrReplace(hotkeyStr, hotkey.CharKey, hotkey.ModifierKeys, action);
|
||||
}
|
||||
|
||||
internal static void OnToggleHotkey(object sender, HotkeyEventArgs args)
|
||||
catch (Exception)
|
||||
{
|
||||
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
|
||||
{
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,27 +2,26 @@
|
|||
using System.Linq;
|
||||
using System.Windows;
|
||||
|
||||
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();
|
||||
namespace Flow.Launcher.Helper;
|
||||
|
||||
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;
|
||||
|
||||
namespace Flow.Launcher.Helper
|
||||
{
|
||||
public static class SyntaxSugars
|
||||
{
|
||||
public static TResult CallOrRescueDefault<TResult>(Func<TResult> callback)
|
||||
{
|
||||
return CallOrRescueDefault(callback, default(TResult));
|
||||
}
|
||||
namespace Flow.Launcher.Helper;
|
||||
|
||||
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();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return def;
|
||||
}
|
||||
return callback();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return def;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,44 +5,43 @@ using System.Text;
|
|||
using System.Windows.Media;
|
||||
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)]
|
||||
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;
|
||||
var wallpaper = new StringBuilder(MAX_PATH);
|
||||
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0);
|
||||
|
||||
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);
|
||||
SystemParametersInfo(SPI_GETDESKWALLPAPER, MAX_PATH, wallpaper, 0);
|
||||
|
||||
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 != null && result is string)
|
||||
try
|
||||
{
|
||||
var parts = strResult.Trim().Split(new[] {' '}, 3).Select(byte.Parse).ToList();
|
||||
return Color.FromRgb(parts[0], parts[1], parts[2]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
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 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
|
||||
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
|
||||
{
|
||||
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)]
|
||||
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", SetLastError = true)]
|
||||
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetDesktopWindow();
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetShellWindow();
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetDesktopWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowRect(IntPtr hwnd, out RECT rc);
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern IntPtr GetShellWindow();
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowRect(IntPtr hwnd, out RECT rc);
|
||||
|
||||
[DllImport("user32.DLL")]
|
||||
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
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_WINTAB = "Flip3D";
|
||||
const string WINDOW_CLASS_PROGMAN = "Progman";
|
||||
const string WINDOW_CLASS_WORKERW = "WorkerW";
|
||||
const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
|
||||
const string WINDOW_CLASS_WINTAB = "Flip3D";
|
||||
const string WINDOW_CLASS_PROGMAN = "Progman";
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// disable windows toolbar's control box
|
||||
/// this will also disable system menu with Alt+Space hotkey
|
||||
/// </summary>
|
||||
public static void DisableControlBox(Window win)
|
||||
//if current active window is desktop or shell, exit early
|
||||
if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(win).Handle;
|
||||
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <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)
|
||||
StringBuilder sb = new StringBuilder(256);
|
||||
GetClassName(hWnd, sb, sb.Capacity);
|
||||
string windowClass = sb.ToString();
|
||||
|
||||
//for Win+Tab (Flip3D)
|
||||
if (windowClass == WINDOW_CLASS_WINTAB)
|
||||
{
|
||||
Matrix matrix;
|
||||
var source = PresentationSource.FromVisual(visual);
|
||||
if (source != null)
|
||||
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 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)]
|
||||
public struct RECT
|
||||
/// <summary>
|
||||
/// 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;
|
||||
public int Top;
|
||||
public int Right;
|
||||
public int Bottom;
|
||||
matrix = source.CompositionTarget.TransformFromDevice;
|
||||
}
|
||||
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:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
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"
|
||||
Height="24"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Popup
|
||||
x:Name="popup"
|
||||
AllowDrop="True"
|
||||
AllowsTransparency="True"
|
||||
IsOpen="{Binding IsKeyboardFocused, ElementName=tbHotkey, Mode=OneWay}"
|
||||
Placement="Top"
|
||||
PlacementTarget="{Binding ElementName=tbHotkey}"
|
||||
PopupAnimation="Fade"
|
||||
StaysOpen="True"
|
||||
VerticalOffset="-5">
|
||||
<Border
|
||||
Width="140"
|
||||
Height="30"
|
||||
Background="{DynamicResource Color01B}"
|
||||
BorderBrush="{DynamicResource Color21B}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<TextBlock
|
||||
x:Name="tbMsg"
|
||||
Margin="0,0,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="13"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource flowlauncherPressHotkey}"
|
||||
Visibility="Visible" />
|
||||
</Border>
|
||||
</Popup>
|
||||
|
||||
<TextBox
|
||||
x:Name="tbHotkey"
|
||||
Margin="0,0,18,0"
|
||||
VerticalContentAlignment="Center"
|
||||
input:InputMethod.IsInputMethodEnabled="False"
|
||||
GotFocus="tbHotkey_GotFocus"
|
||||
LostFocus="tbHotkey_LostFocus"
|
||||
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
|
||||
TabIndex="100" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
<Button
|
||||
Width="Auto"
|
||||
FontSize="13"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource Color01B}"
|
||||
Click="GetNewHotkey">
|
||||
<Button.Template>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border
|
||||
x:Name="ButtonBorder"
|
||||
Padding="5,0,5,0"
|
||||
Background="{DynamicResource ButtonBackgroundColor}"
|
||||
BorderBrush="{DynamicResource ButtonInsideBorder}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
<Condition Property="IsPressed" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ButtonMousePressed}" />
|
||||
<Setter TargetName="ButtonBorder" Property="BorderBrush"
|
||||
Value="{DynamicResource ButtonMousePressedInsideBorder}" />
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ButtonMouseOver}" />
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsPressed" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="ButtonBorder" Property="Background"
|
||||
Value="{DynamicResource ButtonMousePressed}" />
|
||||
<Setter TargetName="ButtonBorder" Property="BorderBrush"
|
||||
Value="{DynamicResource CustomContextHover}" />
|
||||
</MultiTrigger>
|
||||
</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.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
using Flow.Launcher.Plugin;
|
||||
using System.Threading;
|
||||
|
||||
namespace Flow.Launcher
|
||||
{
|
||||
public partial class HotkeyControl : UserControl
|
||||
public partial class HotkeyControl
|
||||
{
|
||||
public HotkeyModel CurrentHotkey { get; private set; }
|
||||
public bool CurrentHotkeyAvailable { get; private set; }
|
||||
public IHotkeySettings HotkeySettings {
|
||||
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>
|
||||
/// Designed for Preview Hotkey and KeyGesture.
|
||||
/// </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 HotkeyControl()
|
||||
public bool ValidateKeyGesture
|
||||
{
|
||||
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();
|
||||
hotkeyUpdateSource?.Dispose();
|
||||
hotkeyUpdateSource = new();
|
||||
var token = hotkeyUpdateSource.Token;
|
||||
e.Handled = true;
|
||||
get { return (string)GetValue(DefaultHotkeyProperty); }
|
||||
set { SetValue(DefaultHotkeyProperty, value); }
|
||||
}
|
||||
|
||||
//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);
|
||||
|
||||
if (hotkeyModel.Equals(CurrentHotkey))
|
||||
private static void OnHotkeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is not HotkeyControl hotkeyControl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_ = Dispatcher.InvokeAsync(async () =>
|
||||
{
|
||||
await Task.Delay(500, token);
|
||||
if (!token.IsCancellationRequested)
|
||||
await SetHotkeyAsync(hotkeyModel);
|
||||
});
|
||||
hotkeyControl.SetKeysToDisplay(new HotkeyModel(hotkeyControl.Hotkey));
|
||||
hotkeyControl.CurrentHotkey = new HotkeyModel(hotkeyControl.Hotkey);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool hotkeyAvailable = CheckHotkeyAvailability(keyModel, ValidateKeyGesture);
|
||||
CurrentHotkeyAvailable = hotkeyAvailable;
|
||||
SetMessage(hotkeyAvailable);
|
||||
OnHotkeyChanged();
|
||||
|
||||
var token = hotkeyUpdateSource.Token;
|
||||
await Task.Delay(500, token);
|
||||
if (token.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
if (CurrentHotkeyAvailable)
|
||||
if (!hotkeyAvailable)
|
||||
{
|
||||
CurrentHotkey = keyModel;
|
||||
// To trigger LostFocus
|
||||
FocusManager.SetFocusedElement(FocusManager.GetFocusScope(this), null);
|
||||
Keyboard.ClearFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
Hotkey = keyModel.ToString();
|
||||
SetKeysToDisplay(CurrentHotkey);
|
||||
ChangeHotkey?.Execute(keyModel);
|
||||
}
|
||||
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);
|
||||
|
||||
public new bool IsFocused => tbHotkey.IsFocused;
|
||||
|
||||
private void tbHotkey_LostFocus(object sender, RoutedEventArgs e)
|
||||
private void SetKeysToDisplay(HotkeyModel? hotkey)
|
||||
{
|
||||
tbHotkey.Text = CurrentHotkey?.ToString() ?? "";
|
||||
tbHotkey.Select(tbHotkey.Text.Length, 0);
|
||||
}
|
||||
KeysToDisplay.Clear();
|
||||
|
||||
private void tbHotkey_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ResetMessage();
|
||||
}
|
||||
|
||||
private void ResetMessage()
|
||||
{
|
||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("flowlauncherPressHotkey");
|
||||
tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B");
|
||||
}
|
||||
|
||||
private void SetMessage(bool hotkeyAvailable)
|
||||
{
|
||||
if (!hotkeyAvailable)
|
||||
if (hotkey == null || hotkey == default(HotkeyModel))
|
||||
{
|
||||
tbMsg.Foreground = new SolidColorBrush(Colors.Red);
|
||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("hotkeyUnavailable");
|
||||
KeysToDisplay.Add(EmptyHotkey);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
foreach (var key in hotkey.Value.EnumerateDisplayKeys()!)
|
||||
{
|
||||
tbMsg.Foreground = new SolidColorBrush(Colors.Green);
|
||||
tbMsg.Text = InternationalizationManager.Instance.GetTranslation("success");
|
||||
KeysToDisplay.Add(key);
|
||||
}
|
||||
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="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="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="AnimationTip">Use Animation in UI</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="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="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="AnimationTip">Použít animaci v UI</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="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="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="AnimationTip">Use Animation in UI</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="SoundEffect">Soundeffekt</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="AnimationTip">Animationen in der Oberfläche verwenden</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="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="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="AnimationTip">Use Animation in UI</system:String>
|
||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||
|
|
@ -170,14 +172,35 @@
|
|||
<!-- Setting Hotkey -->
|
||||
<system:String x:Key="hotkey">Hotkey</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="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="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="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="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="customQueryShortcut">Custom Query 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="edit">Edit</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="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>
|
||||
|
|
@ -286,6 +310,11 @@
|
|||
<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="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 -->
|
||||
<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="emptyShortcut">Shortcut and/or its expansion is empty.</system:String>
|
||||
|
||||
<!-- Hotkey Control -->
|
||||
<system:String x:Key="hotkeyUnavailable">Hotkey Unavailable</system:String>
|
||||
<!-- Common Action -->
|
||||
<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 -->
|
||||
<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="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="RecommendWeatherDesc">Weather in Google Result</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="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="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="AnimationTip">Usar Animación en la Interfaz</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="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="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="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>
|
||||
|
|
@ -73,13 +73,13 @@
|
|||
<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="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="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="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="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 -->
|
||||
<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="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="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="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="AnimationSpeedTip">Velocidad de animación de la interfaz de usuario</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="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="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="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>
|
||||
|
|
@ -194,7 +196,7 @@
|
|||
<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="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="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>
|
||||
|
|
@ -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>
|
||||
|
||||
<!-- 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 -->
|
||||
<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="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="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="AnimationTip">Utiliser l'animation dans l'interface</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="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="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="AnimationTip">Usa l'animazione nell'interfaccia utente</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="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="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="AnimationTip">Use Animation in UI</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="SoundEffect">소리 효과</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="AnimationTip">일부 UI에 애니메이션을 사용합니다.</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="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="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="AnimationTip">Use Animation in UI</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="SoundEffect">Geluidseffect</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="AnimationTip">Animatie gebruiken in UI</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="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="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="AnimationTip">Użyj animacji w interfejsie użytkownika</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="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="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="AnimationTip">Utilizar Animação na Interface</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="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="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="AnimationTip">Utilizar animações na aplicaçã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="SoundEffect">Звуковой эффект</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="AnimationTip">Использование анимации в меню</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="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="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="AnimationTip">Animovať používateľské rozhranie</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="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="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="AnimationTip">Use Animation in UI</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="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="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="AnimationTip">Arayüzde Animasyon Kullan</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="SoundEffect">Звуковий ефект</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="AnimationTip">Використовувати анімацію в інтерфейсі</system:String>
|
||||
<system:String x:Key="AnimationSpeed">Швидкість анімації</system:String>
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@
|
|||
<system:String x:Key="ColorSchemeDark">深色</system:String>
|
||||
<system:String x:Key="SoundEffect">音效</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="AnimationTip">启用动画</system:String>
|
||||
<system:String x:Key="AnimationSpeed">动画速度</system:String>
|
||||
|
|
|
|||
|
|
@ -154,6 +154,8 @@
|
|||
<system:String x:Key="ColorSchemeDark">暗色系</system:String>
|
||||
<system:String x:Key="SoundEffect">音效</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="AnimationTip">使用介面動畫</system:String>
|
||||
<system:String x:Key="AnimationSpeed">Animation Speed</system:String>
|
||||
|
|
|
|||
|
|
@ -46,47 +46,14 @@
|
|||
<Window.InputBindings>
|
||||
<KeyBinding Key="Escape" Command="{Binding EscCommand}" />
|
||||
<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
|
||||
Key="Home"
|
||||
Command="{Binding SelectFirstResultCommand}"
|
||||
Modifiers="Alt" />
|
||||
<KeyBinding
|
||||
Key="O"
|
||||
Command="{Binding LoadContextMenuCommand}"
|
||||
Modifiers="Ctrl" />
|
||||
Key="End"
|
||||
Command="{Binding SelectLastResultCommand}"
|
||||
Modifiers="Alt" />
|
||||
<KeyBinding
|
||||
Key="R"
|
||||
Command="{Binding ReQueryCommand}"
|
||||
|
|
@ -111,10 +78,6 @@
|
|||
Key="OemMinus"
|
||||
Command="{Binding DecreaseMaxResultCommand}"
|
||||
Modifiers="Control" />
|
||||
<KeyBinding
|
||||
Key="H"
|
||||
Command="{Binding LoadHistoryCommand}"
|
||||
Modifiers="Ctrl" />
|
||||
<KeyBinding
|
||||
Key="Enter"
|
||||
Command="{Binding OpenResultCommand}"
|
||||
|
|
@ -188,12 +151,52 @@
|
|||
Modifiers="Ctrl" />
|
||||
<KeyBinding
|
||||
Key="C"
|
||||
Modifiers="Ctrl+Shift"
|
||||
Command="{Binding CopyAlternativeCommand}" />
|
||||
Command="{Binding CopyAlternativeCommand}"
|
||||
Modifiers="Ctrl+Shift" />
|
||||
<KeyBinding
|
||||
Key="{Binding PreviewHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||
Command="{Binding TogglePreviewCommand}"
|
||||
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>
|
||||
<Grid>
|
||||
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
|
||||
|
|
@ -216,6 +219,7 @@
|
|||
<TextBox
|
||||
x:Name="QueryTextBox"
|
||||
AllowDrop="True"
|
||||
AutomationProperties.Name="{Binding Results.SelectedItem.Result.Title}"
|
||||
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
|
||||
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
|
||||
PreviewDragOver="OnPreviewDragOver"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ using Key = System.Windows.Input.Key;
|
|||
using System.Media;
|
||||
using static Flow.Launcher.ViewModel.SettingWindowViewModel;
|
||||
using DataObject = System.Windows.DataObject;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Interop;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Flow.Launcher
|
||||
{
|
||||
|
|
@ -33,14 +36,17 @@ namespace Flow.Launcher
|
|||
{
|
||||
#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 bool isProgressBarStoryboardPaused;
|
||||
private Settings _settings;
|
||||
private NotifyIcon _notifyIcon;
|
||||
private ContextMenu contextMenu;
|
||||
private ContextMenu contextMenu = new ContextMenu();
|
||||
private MainViewModel _viewModel;
|
||||
private bool _animating;
|
||||
SoundPlayer animationSound = new SoundPlayer(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav");
|
||||
MediaPlayer animationSound = new MediaPlayer();
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -52,6 +58,9 @@ namespace Flow.Launcher
|
|||
|
||||
InitializeComponent();
|
||||
InitializePosition();
|
||||
|
||||
animationSound.Open(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav"));
|
||||
|
||||
DataObject.AddPastingHandler(QueryTextBox, OnPaste);
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +137,8 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (_settings.UseSound)
|
||||
{
|
||||
animationSound.Position = TimeSpan.Zero;
|
||||
animationSound.Volume = _settings.SoundVolume / 100.0;
|
||||
animationSound.Play();
|
||||
}
|
||||
UpdatePosition();
|
||||
|
|
@ -264,12 +275,11 @@ namespace Flow.Launcher
|
|||
{
|
||||
_notifyIcon = new NotifyIcon
|
||||
{
|
||||
Text = Infrastructure.Constant.FlowLauncher,
|
||||
Text = Infrastructure.Constant.FlowLauncherFullName,
|
||||
Icon = Properties.Resources.app,
|
||||
Visible = !_settings.HideNotifyIcon
|
||||
};
|
||||
|
||||
contextMenu = new ContextMenu();
|
||||
|
||||
var openIcon = new FontIcon
|
||||
{
|
||||
|
|
@ -277,7 +287,8 @@ namespace Flow.Launcher
|
|||
};
|
||||
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
|
||||
{
|
||||
|
|
@ -285,7 +296,8 @@ namespace Flow.Launcher
|
|||
};
|
||||
var gamemode = new MenuItem
|
||||
{
|
||||
Header = InternationalizationManager.Instance.GetTranslation("GameMode"), Icon = gamemodeIcon
|
||||
Header = InternationalizationManager.Instance.GetTranslation("GameMode"),
|
||||
Icon = gamemodeIcon
|
||||
};
|
||||
var positionresetIcon = new FontIcon
|
||||
{
|
||||
|
|
@ -293,7 +305,8 @@ namespace Flow.Launcher
|
|||
};
|
||||
var positionreset = new MenuItem
|
||||
{
|
||||
Header = InternationalizationManager.Instance.GetTranslation("PositionReset"), Icon = positionresetIcon
|
||||
Header = InternationalizationManager.Instance.GetTranslation("PositionReset"),
|
||||
Icon = positionresetIcon
|
||||
};
|
||||
var settingsIcon = new FontIcon
|
||||
{
|
||||
|
|
@ -301,7 +314,8 @@ namespace Flow.Launcher
|
|||
};
|
||||
var settings = new MenuItem
|
||||
{
|
||||
Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"), Icon = settingsIcon
|
||||
Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"),
|
||||
Icon = settingsIcon
|
||||
};
|
||||
var exitIcon = new FontIcon
|
||||
{
|
||||
|
|
@ -309,7 +323,8 @@ namespace Flow.Launcher
|
|||
};
|
||||
var exit = new MenuItem
|
||||
{
|
||||
Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"), Icon = exitIcon
|
||||
Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"),
|
||||
Icon = exitIcon
|
||||
};
|
||||
|
||||
open.Click += (o, e) => _viewModel.ToggleFlowLauncher();
|
||||
|
|
@ -327,7 +342,6 @@ namespace Flow.Launcher
|
|||
contextMenu.Items.Add(settings);
|
||||
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) =>
|
||||
{
|
||||
switch (e.Button)
|
||||
|
|
@ -335,9 +349,15 @@ namespace Flow.Launcher
|
|||
case MouseButtons.Left:
|
||||
_viewModel.ToggleFlowLauncher();
|
||||
break;
|
||||
|
||||
case MouseButtons.Right:
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -311,6 +311,8 @@ namespace Flow.Launcher
|
|||
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 ReQuery(bool reselect = true) => _mainVM.ReQuery(reselect);
|
||||
|
||||
#endregion
|
||||
|
||||
#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>
|
||||
|
||||
|
||||
<!-- 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>
|
||||
|
|
|
|||
|
|
@ -104,6 +104,16 @@
|
|||
<Color x:Key="NumberBoxColor26">#ffffff</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="ButtonInsideBorder" Color="#3f3f3f" />
|
||||
|
|
@ -772,7 +782,7 @@
|
|||
<m:StaticResource x:Key="ContentDialogForeground" ResourceKey="SystemControlPageTextBaseHighBrush" />
|
||||
<m:StaticResource x:Key="ContentDialogBackground" ResourceKey="SystemControlPageBackgroundAltHighBrush" />
|
||||
<m:StaticResource x:Key="ContentDialogBorderBrush" ResourceKey="SystemControlBackgroundBaseLowBrush" />
|
||||
<m:StaticResource x:Key="ContentDialogLightDismissOverlayBackground" ResourceKey="SystemControlPageBackgroundMediumAltMediumBrush" />
|
||||
<m:StaticResource x:Key="ContentDialogLightDismissOverlayBackground" ResourceKey="ContentDialogOverlayBG" />
|
||||
|
||||
<!-- Resources for DataGrid -->
|
||||
<sys:Double x:Key="ListAccentLowOpacity">0.6</sys:Double>
|
||||
|
|
|
|||
|
|
@ -95,6 +95,17 @@
|
|||
<Color x:Key="NumberBoxColor26">#1b1b1b</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="ButtonInsideBorder" Color="#d3d3d3" />
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
Title="WelcomePage2"
|
||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<converters:BorderClipConverter x:Key="BorderClipConverter" />
|
||||
|
|
@ -110,12 +111,13 @@
|
|||
FontWeight="SemiBold"
|
||||
Text="{DynamicResource flowlauncherHotkey}" />
|
||||
<flowlauncher:HotkeyControl
|
||||
x:Name="HotkeyControl"
|
||||
Width="300"
|
||||
Height="35"
|
||||
Margin="-206,10,0,0"
|
||||
GotFocus="HotkeyControl_OnGotFocus"
|
||||
LostFocus="HotkeyControl_OnLostFocus"/>
|
||||
Margin="0,8,0,0"
|
||||
ChangeHotkey="{Binding SetTogglingHotkeyCommand}"
|
||||
DefaultHotkey="Alt+Space"
|
||||
Hotkey="{Binding Settings.Hotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="True"
|
||||
WindowTitle="{DynamicResource flowlauncherHotkey}" />
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,14 @@ using System;
|
|||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Navigation;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.ViewModel;
|
||||
|
||||
namespace Flow.Launcher.Resources.Pages
|
||||
{
|
||||
public partial class WelcomePage2
|
||||
{
|
||||
private Settings Settings { get; set; }
|
||||
|
||||
private Brush tbMsgForegroundColorOriginal;
|
||||
|
||||
private string tbMsgTextOriginal;
|
||||
public Settings Settings { get; set; }
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
|
|
@ -22,31 +20,14 @@ namespace Flow.Launcher.Resources.Pages
|
|||
Settings = settings;
|
||||
else
|
||||
throw new ArgumentException("Unexpected Parameter setting.");
|
||||
|
||||
|
||||
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;
|
||||
HotkeyControl.tbMsg.Foreground = tbMsgForegroundColorOriginal;
|
||||
[RelayCommand]
|
||||
private static void SetTogglingHotkey(HotkeyModel hotkey)
|
||||
{
|
||||
HotKeyMapper.SetHotkey(hotkey, HotKeyMapper.OnToggleHotkey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,11 +2,13 @@
|
|||
x:Class="Flow.Launcher.Resources.Pages.WelcomePage3"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:local="clr-namespace:Flow.Launcher.Resources.Pages"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
Title="WelcomePage3"
|
||||
VerticalAlignment="Stretch"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<Style x:Key="KbdLine" TargetType="Border">
|
||||
|
|
@ -27,301 +29,86 @@
|
|||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
</Style>
|
||||
</Page.Resources>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="0" />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border Grid.Row="0" HorizontalAlignment="Stretch">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0 0" EndPoint="1 1">
|
||||
<LinearGradientBrush.GradientStops>
|
||||
<GradientStop Offset="0.0" Color="#16af7b" />
|
||||
<GradientStop Offset="1.0" Color="#34c191" />
|
||||
</LinearGradientBrush.GradientStops>
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||
<Image
|
||||
Width="300"
|
||||
Height="100"
|
||||
Margin="0,0,0,0"
|
||||
Source="../../images/page_img02.png"
|
||||
Style="{DynamicResource StyleImageFadeIn}" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<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}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="24,20,24,14"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
Text="{DynamicResource Welcome_Page3_Title}" />
|
||||
<ScrollViewer
|
||||
Grid.Row="1"
|
||||
Height="478"
|
||||
Margin="0,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
FontSize="13">
|
||||
<StackPanel Margin="24,0,24,0">
|
||||
<Border
|
||||
BorderBrush="{DynamicResource Color03B}"
|
||||
BorderThickness="0"
|
||||
CornerRadius="5">
|
||||
<StackPanel>
|
||||
<cc:Card
|
||||
Title="{DynamicResource HotkeyUpDownDesc}"
|
||||
BorderThickness="0,0,0,0"
|
||||
Type="Inside">
|
||||
<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}">←</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>
|
||||
<cc:HotkeyDisplay Keys="←+→" Type="Small" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{DynamicResource KbdLine}">
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource HotkeyLeftRightDesc}"
|
||||
BorderThickness="0,0,0,0"
|
||||
Type="Inside">
|
||||
<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}">↑</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>
|
||||
<cc:HotkeyDisplay Keys="↑+↓" Type="Small" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{DynamicResource KbdLine}">
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource HotkeyESCDesc}"
|
||||
BorderThickness="0,0,0,0"
|
||||
Type="Inside">
|
||||
<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}">Enter</TextBlock>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="13"
|
||||
Text="{DynamicResource HotkeyRunDesc}" />
|
||||
</StackPanel>
|
||||
<cc:HotkeyDisplay Keys="ESC" Type="Small" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{DynamicResource KbdLine}">
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
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
|
||||
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>
|
||||
<cc:HotkeyDisplay Keys="SHIFT+ENTER" Type="Small" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{DynamicResource KbdLine}">
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource HotkeyCtrlEnterDesc}"
|
||||
BorderThickness="0,0,0,0"
|
||||
Type="Inside">
|
||||
<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="Tab" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="13"
|
||||
Text="{DynamicResource HotkeyTabDesc}" />
|
||||
</StackPanel>
|
||||
<cc:HotkeyDisplay Keys="CTRL+ENTER" Type="Small" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Style="{DynamicResource KbdLine}">
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource HotkeyCtrlShiftEnterDesc}"
|
||||
BorderThickness="0,0,0,0"
|
||||
Type="Inside">
|
||||
<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="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>
|
||||
<cc:HotkeyDisplay Keys="CTRL+SHIFT+ENTER" Type="Small" />
|
||||
</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="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>
|
||||
</cc:Card>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
|
||||
</Grid>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</ui:Page>
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -2,6 +2,7 @@
|
|||
x:Class="Flow.Launcher.SettingWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
|
|
@ -67,6 +68,20 @@
|
|||
</Setter.Value>
|
||||
</Setter>
|
||||
</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">
|
||||
<Setter Property="Focusable" Value="False" />
|
||||
<Setter Property="Margin" Value="0" />
|
||||
|
|
@ -137,6 +152,7 @@
|
|||
<Setter Property="Grid.Column" Value="2" />
|
||||
<Setter Property="FocusVisualMargin" Value="5" />
|
||||
<Setter Property="Width" Value="Auto" />
|
||||
<Setter Property="FocusVisualStyle" Value="{DynamicResource SwitchFocusVisualStyleKey}" />
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
||||
<Setter Property="OffContent" Value="{DynamicResource disable}" />
|
||||
|
|
@ -447,7 +463,10 @@
|
|||
IsItemsHost="true"
|
||||
LastChildFill="False" />
|
||||
<Border Grid.Column="1">
|
||||
<ContentPresenter Grid.Column="1" ContentSource="SelectedContent" />
|
||||
<ContentPresenter
|
||||
x:Name="PART_SelectedContentHost"
|
||||
Grid.Column="1"
|
||||
ContentSource="SelectedContent" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
|
|
@ -693,7 +712,7 @@
|
|||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
<Border
|
||||
Margin="0,30,0,0"
|
||||
Padding="0"
|
||||
Style="{DynamicResource SettingGroupBox}">
|
||||
|
|
@ -720,7 +739,7 @@
|
|||
<ComboBox
|
||||
x:Name="SelectScreen"
|
||||
MinWidth="160"
|
||||
Margin="0,0,18,0"
|
||||
Margin="0,0,18,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding ScreenNumbers}"
|
||||
|
|
@ -738,14 +757,12 @@
|
|||
</ComboBox>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource Glyph}">
|
||||

|
||||

|
||||
</TextBlock>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Separator
|
||||
Width="Auto"
|
||||
BorderThickness="1">
|
||||
<Separator Width="Auto" BorderThickness="1">
|
||||
<Separator.Style>
|
||||
<Style BasedOn="{StaticResource SettingSeparatorStyle}" TargetType="Separator">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
|
|
@ -758,9 +775,7 @@
|
|||
</Separator.Style>
|
||||
</Separator>
|
||||
|
||||
<Border
|
||||
Margin="0"
|
||||
BorderThickness="0">
|
||||
<Border Margin="0" BorderThickness="0">
|
||||
<Border.Style>
|
||||
<Style BasedOn="{StaticResource SettingGroupBox}" TargetType="Border">
|
||||
<Setter Property="Visibility" Value="Visible" />
|
||||
|
|
@ -786,8 +801,7 @@
|
|||
FontSize="14"
|
||||
ItemsSource="{Binding SearchWindowAligns}"
|
||||
SelectedValue="{Binding Settings.SearchWindowAlign}"
|
||||
SelectedValuePath="Value">
|
||||
</ComboBox>
|
||||
SelectedValuePath="Value" />
|
||||
<StackPanel Margin="0,0,18,0" Orientation="Horizontal">
|
||||
<StackPanel.Style>
|
||||
<Style TargetType="StackPanel">
|
||||
|
|
@ -817,7 +831,7 @@
|
|||
</StackPanel>
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource Glyph}">
|
||||

|
||||

|
||||
</TextBlock>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
|
@ -2446,8 +2460,7 @@
|
|||
FontSize="14"
|
||||
ItemsSource="{Binding AnimationSpeeds}"
|
||||
SelectedValue="{Binding Settings.AnimationSpeed}"
|
||||
SelectedValuePath="Value">
|
||||
</ComboBox>
|
||||
SelectedValuePath="Value" />
|
||||
<StackPanel Margin="0,0,18,0" Orientation="Horizontal">
|
||||
<StackPanel.Style>
|
||||
<Style TargetType="StackPanel">
|
||||
|
|
@ -2474,27 +2487,81 @@
|
|||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
<Border
|
||||
Margin="0"
|
||||
BorderThickness="0"
|
||||
Margin="0,12,0,12"
|
||||
Padding="0"
|
||||
CornerRadius="5"
|
||||
Style="{DynamicResource SettingGroupBox}">
|
||||
<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
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Border
|
||||
Margin="0"
|
||||
BorderThickness="0"
|
||||
Style="{DynamicResource SettingGroupBox}">
|
||||
<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.Column="2"
|
||||
IsOn="{Binding UseSound, Mode=TwoWay}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}"
|
||||
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>
|
||||
</ItemsControl>
|
||||
</TextBlock>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<Border Margin="0,12,0,12" Style="{DynamicResource SettingGroupBox}">
|
||||
|
|
@ -2581,63 +2648,39 @@
|
|||
<StackPanel Margin="5,18,18,10">
|
||||
<TextBlock
|
||||
Grid.Row="0"
|
||||
Margin="0,5,0,2"
|
||||
Margin="0,5,0,6"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource hotkeys}"
|
||||
TextAlignment="left" />
|
||||
|
||||
<StackPanel Grid.Row="1">
|
||||
<Border Margin="0,8,0,0" Style="{DynamicResource SettingGroupBox}">
|
||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||
<StackPanel Style="{StaticResource TextPanel}">
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource flowlauncherHotkey}" />
|
||||
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource flowlauncherHotkeyToolTip}" />
|
||||
</StackPanel>
|
||||
<flowlauncher:HotkeyControl
|
||||
x:Name="HotkeyControl"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Width="300"
|
||||
Height="35"
|
||||
Margin="0,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalContentAlignment="Right"
|
||||
GotFocus="OnHotkeyControlFocused"
|
||||
Loaded="OnHotkeyControlLoaded"
|
||||
LostFocus="OnHotkeyControlFocusLost" />
|
||||
|
||||
<TextBlock Style="{StaticResource Glyph}">
|
||||

|
||||
</TextBlock>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<cc:Card
|
||||
Title="{DynamicResource flowlauncherHotkey}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource flowlauncherHotkeyToolTip}">
|
||||
<flowlauncher:HotkeyControl
|
||||
ChangeHotkey="{Binding SetTogglingHotkeyCommand}"
|
||||
DefaultHotkey="Alt+Space"
|
||||
Hotkey="{Binding Settings.Hotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="True"
|
||||
WindowTitle="{DynamicResource flowlauncherHotkey}" />
|
||||
</cc:Card>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="2">
|
||||
<Border Margin="0,8,0,0" Style="{DynamicResource SettingGroupBox}">
|
||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||
<StackPanel Style="{StaticResource TextPanel}">
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource previewHotkey}" />
|
||||
<TextBlock Style="{DynamicResource SettingSubTitleLabel}" Text="{DynamicResource previewHotkeyToolTip}" />
|
||||
</StackPanel>
|
||||
<flowlauncher:HotkeyControl
|
||||
x:Name="PreviewHotkeyControl"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Width="300"
|
||||
Height="35"
|
||||
Margin="0,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalContentAlignment="Right"
|
||||
Loaded="OnPreviewHotkeyControlLoaded"
|
||||
LostFocus="OnPreviewHotkeyControlFocusLost"
|
||||
ValidateKeyGesture="True" />
|
||||
<TextBlock Style="{StaticResource Glyph}">
|
||||

|
||||
</TextBlock>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
<cc:Card
|
||||
Title="{DynamicResource previewHotkey}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource previewHotkeyToolTip}">
|
||||
<flowlauncher:HotkeyControl
|
||||
DefaultHotkey="F1"
|
||||
Hotkey="{Binding Settings.PreviewHotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="False"
|
||||
WindowTitle="{DynamicResource previewHotkey}" />
|
||||
</cc:Card>
|
||||
</StackPanel>
|
||||
|
||||
<Border
|
||||
|
|
@ -2697,163 +2740,374 @@
|
|||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<TextBlock
|
||||
Grid.Row="4"
|
||||
Margin="0,10,12,10"
|
||||
Padding="0,12,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{DynamicResource customQueryHotkey}" />
|
||||
<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 Grid.Row="2">
|
||||
<cc:ExCard
|
||||
Title="{DynamicResource hotkeyPresets}"
|
||||
Margin="0,14,0,0"
|
||||
Icon=""
|
||||
Sub="{DynamicResource hotkeyPresetsToolTip}">
|
||||
<StackPanel>
|
||||
<cc:Card
|
||||
Title="{DynamicResource OpenContainFolderHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<cc:HotkeyDisplay Keys="Ctrl+Enter" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource RunAsAdminHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<cc:HotkeyDisplay Keys="Ctrl+Shift+Enter" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource ToggleHistoryHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<cc:HotkeyDisplay Keys="Ctrl+H" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource CopyFilePathHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<cc:HotkeyDisplay Keys="Ctrl+Shift+C" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource OpenContextMenuHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<flowlauncher:HotkeyControl
|
||||
DefaultHotkey="Ctrl+I"
|
||||
Hotkey="{Binding Settings.OpenContextMenuHotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource OpenContextMenuHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<cc:HotkeyDisplay Keys="Shift+Enter" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource SettingWindowHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<flowlauncher:HotkeyControl
|
||||
DefaultHotkey="Ctrl+I"
|
||||
Hotkey="{Binding Settings.SettingWindowHotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="False" />
|
||||
</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>
|
||||
|
||||
<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>
|
||||
</Border>
|
||||
</ScrollViewer>
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ using System.Windows.Forms;
|
|||
using System.Windows.Input;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Navigation;
|
||||
using NHotkey;
|
||||
using Button = System.Windows.Controls.Button;
|
||||
using Control = System.Windows.Controls.Control;
|
||||
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
|
||||
|
|
@ -110,41 +111,9 @@ namespace Flow.Launcher
|
|||
|
||||
#region Hotkey
|
||||
|
||||
private void OnHotkeyControlLoaded(object sender, RoutedEventArgs e)
|
||||
private void OnToggleHotkey(object sender, HotkeyEventArgs e)
|
||||
{
|
||||
_ = HotkeyControl.SetHotkeyAsync(viewModel.Settings.Hotkey, false);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
HotKeyMapper.OnToggleHotkey(sender, e);
|
||||
}
|
||||
|
||||
private void OnDeleteCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
|
|
@ -391,7 +360,7 @@ namespace Flow.Launcher
|
|||
{
|
||||
if (viewModel.EditSelectedCustomShortcut())
|
||||
{
|
||||
customShortcutView.Items.Refresh();
|
||||
//customShortcutView.Items.Refresh(); Should Fix
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -80,6 +80,36 @@ namespace Flow.Launcher.ViewModel
|
|||
case nameof(Settings.PreviewHotkey):
|
||||
OnPropertyChanged(nameof(PreviewHotkey));
|
||||
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]
|
||||
private void ReQuery()
|
||||
public void ReQuery()
|
||||
{
|
||||
if (SelectedIsFromQueryResults())
|
||||
{
|
||||
|
|
@ -218,6 +248,14 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
public void ReQuery(bool reselect)
|
||||
{
|
||||
if (SelectedIsFromQueryResults())
|
||||
{
|
||||
QueryResults(isReQuery: true, reSelect: reselect);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void LoadContextMenu()
|
||||
{
|
||||
|
|
@ -334,6 +372,13 @@ namespace Flow.Launcher.ViewModel
|
|||
SelectedResults.SelectFirstResult();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectLastResult()
|
||||
{
|
||||
SelectedResults.SelectLastResult();
|
||||
}
|
||||
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectPrevPage()
|
||||
{
|
||||
|
|
@ -619,25 +664,33 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
public string OpenResultCommandModifiers => Settings.OpenResultModifiers;
|
||||
|
||||
public string PreviewHotkey
|
||||
public string VerifyOrSetDefaultHotkey(string hotkey, string defaultHotkey)
|
||||
{
|
||||
get
|
||||
try
|
||||
{
|
||||
// TODO try to patch issue #1755
|
||||
// Added in v1.14.0, remove after v1.16.0.
|
||||
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;
|
||||
var converter = new KeyGestureConverter();
|
||||
var key = (KeyGesture)converter.ConvertFromString(hotkey);
|
||||
}
|
||||
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;
|
||||
|
||||
|
|
@ -680,20 +733,7 @@ namespace Flow.Launcher.ViewModel
|
|||
List<Result> results;
|
||||
if (selected == lastContextMenuResult)
|
||||
{
|
||||
// Use copy to keep the original results unchanged
|
||||
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,
|
||||
});
|
||||
results = lastContextMenuResults;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -707,7 +747,7 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
if (!string.IsNullOrEmpty(query))
|
||||
{
|
||||
var filtered = results.Where
|
||||
var filtered = results.Select(x => x.Clone()).Where
|
||||
(
|
||||
r =>
|
||||
{
|
||||
|
|
@ -775,7 +815,7 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
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();
|
||||
|
||||
|
|
@ -850,7 +890,7 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
var tasks = plugins.Select(plugin => plugin.Metadata.Disabled switch
|
||||
{
|
||||
false => QueryTask(plugin),
|
||||
false => QueryTask(plugin, reSelect),
|
||||
true => Task.CompletedTask
|
||||
}).ToArray();
|
||||
|
||||
|
|
@ -878,7 +918,7 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
|
||||
// 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
|
||||
// Task.Yield will force it to run in ThreadPool
|
||||
|
|
@ -892,7 +932,7 @@ namespace Flow.Launcher.ViewModel
|
|||
results ??= _emptyResult;
|
||||
|
||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, plugin.Metadata, query,
|
||||
currentCancellationToken)))
|
||||
currentCancellationToken, reSelect)))
|
||||
{
|
||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||
}
|
||||
|
|
@ -1133,7 +1173,7 @@ namespace Flow.Launcher.ViewModel
|
|||
/// <summary>
|
||||
/// To avoid deadlock, this method should not called from main thread
|
||||
/// </summary>
|
||||
public void UpdateResultView(IEnumerable<ResultsForUpdate> resultsForUpdates)
|
||||
public void UpdateResultView(ICollection<ResultsForUpdate> resultsForUpdates)
|
||||
{
|
||||
if (!resultsForUpdates.Any())
|
||||
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
|
||||
|
|
|
|||
|
|
@ -4,23 +4,13 @@ using System.Threading;
|
|||
|
||||
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 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;
|
||||
}
|
||||
public string ID { get; } = Metadata.ID;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,11 @@ namespace Flow.Launcher.ViewModel
|
|||
SelectedIndex = NewIndex(0);
|
||||
}
|
||||
|
||||
public void SelectLastResult()
|
||||
{
|
||||
SelectedIndex = NewIndex(Results.Count - 1);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_collectionLock)
|
||||
|
|
@ -147,23 +152,23 @@ namespace Flow.Launcher.ViewModel
|
|||
/// <summary>
|
||||
/// To avoid deadlock, this method should not called from main thread
|
||||
/// </summary>
|
||||
public void AddResults(IEnumerable<ResultsForUpdate> resultsForUpdates, CancellationToken token)
|
||||
public void AddResults(IEnumerable<ResultsForUpdate> resultsForUpdates, CancellationToken token, bool reselect = true)
|
||||
{
|
||||
var newResults = NewResults(resultsForUpdates);
|
||||
|
||||
if (token.IsCancellationRequested)
|
||||
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)
|
||||
{
|
||||
// update UI in one run, so it can avoid UI flickering
|
||||
Results.Update(newResults, token);
|
||||
if (Results.Any())
|
||||
if (reselect && Results.Any())
|
||||
SelectedItem = Results[0];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ using Flow.Launcher.Plugin.SharedModels;
|
|||
using System.Collections.ObjectModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
|
||||
namespace Flow.Launcher.ViewModel
|
||||
{
|
||||
|
|
@ -63,9 +65,17 @@ namespace Flow.Launcher.ViewModel
|
|||
case nameof(Settings.PreviewHotkey):
|
||||
OnPropertyChanged(nameof(AlwaysPreviewToolTip));
|
||||
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; }
|
||||
|
|
@ -107,13 +117,15 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
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
|
||||
private bool _portableMode = DataLocation.PortableDataLocationInUse();
|
||||
|
||||
public bool PortableMode
|
||||
{
|
||||
get => _portableMode;
|
||||
|
|
@ -182,6 +194,7 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
|
||||
private List<LastQueryMode> _lastQueryModes = new List<LastQueryMode>();
|
||||
|
||||
public List<LastQueryMode> LastQueryModes
|
||||
{
|
||||
get
|
||||
|
|
@ -190,6 +203,7 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
_lastQueryModes = InitLastQueryModes();
|
||||
}
|
||||
|
||||
return _lastQueryModes;
|
||||
}
|
||||
}
|
||||
|
|
@ -197,17 +211,16 @@ namespace Flow.Launcher.ViewModel
|
|||
private List<LastQueryMode> InitLastQueryModes()
|
||||
{
|
||||
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)
|
||||
{
|
||||
var key = $"LastQuery{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new LastQueryMode
|
||||
{
|
||||
Display = display, Value = e,
|
||||
};
|
||||
var m = new LastQueryMode { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
|
||||
|
|
@ -264,15 +277,15 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
public List<string> OpenResultModifiersList => new List<string>
|
||||
{
|
||||
KeyConstant.Alt,
|
||||
KeyConstant.Ctrl,
|
||||
$"{KeyConstant.Ctrl}+{KeyConstant.Alt}"
|
||||
KeyConstant.Alt, KeyConstant.Ctrl, $"{KeyConstant.Ctrl}+{KeyConstant.Alt}"
|
||||
};
|
||||
|
||||
private Internationalization _translater => InternationalizationManager.Instance;
|
||||
public List<Language> Languages => _translater.LoadAvailableLanguages();
|
||||
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()
|
||||
{
|
||||
|
|
@ -282,6 +295,7 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("serverCantBeEmpty");
|
||||
}
|
||||
|
||||
if (Settings.Proxy.Port <= 0)
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation("portCantBeEmpty");
|
||||
|
|
@ -300,6 +314,7 @@ namespace Flow.Launcher.ViewModel
|
|||
Credentials = new NetworkCredential(proxyUserName, Settings.Proxy.Password)
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
|
|
@ -330,10 +345,7 @@ namespace Flow.Launcher.ViewModel
|
|||
get => PluginManager.AllPlugins
|
||||
.OrderBy(x => x.Metadata.Disabled)
|
||||
.ThenBy(y => y.Metadata.Name)
|
||||
.Select(p => new PluginViewModel
|
||||
{
|
||||
PluginPair = p
|
||||
})
|
||||
.Select(p => new PluginViewModel { PluginPair = p })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
|
@ -380,8 +392,7 @@ namespace Flow.Launcher.ViewModel
|
|||
await PluginsManifest.UpdateManifestAsync();
|
||||
OnPropertyChanged(nameof(ExternalPlugins));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
internal void DisplayPluginQuery(string queryToDisplay, PluginPair plugin, int actionKeywordPosition = 0)
|
||||
{
|
||||
|
|
@ -455,12 +466,10 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
var key = $"ColorScheme{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new ColorScheme
|
||||
{
|
||||
Display = display, Value = e,
|
||||
};
|
||||
var m = new ColorScheme { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
|
@ -481,13 +490,10 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
var key = $"SearchWindowScreen{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new SearchWindowScreen
|
||||
{
|
||||
Display = display,
|
||||
Value = e,
|
||||
};
|
||||
var m = new SearchWindowScreen { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
|
@ -508,12 +514,10 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
var key = $"SearchWindowAlign{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new SearchWindowAlign
|
||||
{
|
||||
Display = display, Value = e,
|
||||
};
|
||||
var m = new SearchWindowAlign { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
|
@ -528,6 +532,7 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
screenNumbers.Add(i);
|
||||
}
|
||||
|
||||
return screenNumbers;
|
||||
}
|
||||
}
|
||||
|
|
@ -614,13 +619,10 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
var key = $"AnimationSpeed{e}";
|
||||
var display = _translater.GetTranslation(key);
|
||||
var m = new AnimationSpeed
|
||||
{
|
||||
Display = display,
|
||||
Value = e,
|
||||
};
|
||||
var m = new AnimationSpeed { Display = display, Value = e, };
|
||||
speeds.Add(m);
|
||||
}
|
||||
|
||||
return speeds;
|
||||
}
|
||||
}
|
||||
|
|
@ -631,6 +633,12 @@ namespace Flow.Launcher.ViewModel
|
|||
set => Settings.UseSound = value;
|
||||
}
|
||||
|
||||
public double SoundEffectVolume
|
||||
{
|
||||
get => Settings.SoundVolume;
|
||||
set => Settings.SoundVolume = value;
|
||||
}
|
||||
|
||||
public bool UseClock
|
||||
{
|
||||
get => Settings.UseClock;
|
||||
|
|
@ -681,10 +689,7 @@ namespace Flow.Launcher.ViewModel
|
|||
bitmap.DecodePixelWidth = 800;
|
||||
bitmap.DecodePixelHeight = 600;
|
||||
bitmap.EndInit();
|
||||
var brush = new ImageBrush(bitmap)
|
||||
{
|
||||
Stretch = Stretch.UniformToFill
|
||||
};
|
||||
var brush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
|
||||
return brush;
|
||||
}
|
||||
else
|
||||
|
|
@ -705,26 +710,36 @@ namespace Flow.Launcher.ViewModel
|
|||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
|
||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
|
||||
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png")
|
||||
SubTitle =
|
||||
InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
|
||||
IcoPath =
|
||||
Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png")
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
|
||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
|
||||
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
||||
SubTitle =
|
||||
InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
|
||||
IcoPath =
|
||||
Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
|
||||
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
|
||||
{
|
||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
|
||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
|
||||
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
||||
SubTitle =
|
||||
InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
|
||||
IcoPath = Path.Combine(Constant.ProgramDirectory,
|
||||
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
|
||||
}
|
||||
};
|
||||
var vm = new ResultsViewModel(Settings);
|
||||
|
|
@ -880,6 +895,7 @@ namespace Flow.Launcher.ViewModel
|
|||
SelectedCustomShortcut = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -908,6 +924,7 @@ namespace Flow.Launcher.ViewModel
|
|||
public string Documentation => Constant.Documentation;
|
||||
public string Docs => Constant.Docs;
|
||||
public string Github => Constant.GitHub;
|
||||
|
||||
public string Version
|
||||
{
|
||||
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
|
||||
{
|
||||
|
|
@ -930,7 +949,8 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
var logFiles = GetLogFiles();
|
||||
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)
|
||||
{
|
||||
const int scale = 1024;
|
||||
string[] orders = new string[]
|
||||
{
|
||||
"GB", "MB", "KB", "B"
|
||||
};
|
||||
string[] orders = new string[] { "GB", "MB", "KB", "B" };
|
||||
long max = (long)Math.Pow(scale, orders.Length - 1);
|
||||
|
||||
foreach (string order in orders)
|
||||
|
|
@ -980,6 +997,7 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
max /= scale;
|
||||
}
|
||||
|
||||
return "0 B";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@
|
|||
Title="{DynamicResource Welcome_Page1_Title}"
|
||||
Width="550"
|
||||
Height="650"
|
||||
MinWidth="550"
|
||||
MinHeight="650"
|
||||
MaxWidth="550"
|
||||
MaxHeight="650"
|
||||
Activated="OnActivated"
|
||||
Background="{DynamicResource Color00B}"
|
||||
Foreground="{DynamicResource PopupTextColor}"
|
||||
|
|
|
|||
|
|
@ -3,23 +3,22 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||
{
|
||||
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return LoadChromeBookmarks();
|
||||
}
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
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;
|
||||
}
|
||||
public class ChromeBookmarkLoader : ChromiumBookmarkLoader
|
||||
{
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return LoadChromeBookmarks();
|
||||
}
|
||||
}
|
||||
|
||||
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 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>();
|
||||
if (!Directory.Exists(browserDataPath)) return bookmarks;
|
||||
var paths = Directory.GetDirectories(browserDataPath);
|
||||
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
||||
if (!File.Exists(bookmarkPath))
|
||||
continue;
|
||||
|
||||
foreach (var profile in paths)
|
||||
{
|
||||
var bookmarkPath = Path.Combine(profile, "Bookmarks");
|
||||
if (!File.Exists(bookmarkPath))
|
||||
continue;
|
||||
Main.RegisterBookmarkFile(bookmarkPath);
|
||||
|
||||
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)})");
|
||||
bookmarks.AddRange(LoadBookmarksFromFile(bookmarkPath, source));
|
||||
}
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
||||
{
|
||||
var bookmarks = new List<Bookmark>();
|
||||
|
||||
if (!File.Exists(path))
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
protected List<Bookmark> LoadBookmarksFromFile(string path, string source)
|
||||
{
|
||||
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);
|
||||
using var jsonDocument = JsonDocument.Parse(File.ReadAllText(path));
|
||||
if (!jsonDocument.RootElement.TryGetProperty("roots", out var rootElement))
|
||||
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.
|
||||
// If various exceptions start to build up here consider splitting this Loader into multiple separate ones.
|
||||
if (folder.Name == "custom_root")
|
||||
EnumerateRoot(folder.Value, bookmarks, source);
|
||||
else
|
||||
EnumerateFolderBookmark(folder.Value, bookmarks, source);
|
||||
// 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 (folder.Name == "custom_root")
|
||||
EnumerateRoot(folder.Value, bookmarks, source);
|
||||
else
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnumerateFolderBookmark(JsonElement folderElement, ICollection<Bookmark> bookmarks,
|
||||
string source)
|
||||
{
|
||||
if (!folderElement.TryGetProperty("children", out var childrenElement))
|
||||
return;
|
||||
foreach (var subElement in childrenElement.EnumerateArray())
|
||||
else
|
||||
{
|
||||
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
|
||||
{
|
||||
Log.Error(
|
||||
$"ChromiumBookmarkLoader: EnumerateFolderBookmark: type property not found for {subElement.GetString()}");
|
||||
}
|
||||
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.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())
|
||||
return match;
|
||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||
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>();
|
||||
|
||||
if (setting.LoadChromeBookmark)
|
||||
{
|
||||
// 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();
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
using System.Collections.Generic;
|
||||
|
||||
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; }
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
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 Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
|
||||
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; }
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
{
|
||||
return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite"));
|
||||
}
|
||||
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()
|
||||
{
|
||||
return GetBookmarksFromPath(Path.Combine(BrowserDataPath, "places.sqlite"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,21 +3,20 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
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"));
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark;
|
||||
|
||||
return bookmarks;
|
||||
}
|
||||
|
||||
public override List<Bookmark> GetBookmarks() => LoadEdgeBookmarks();
|
||||
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 override List<Bookmark> GetBookmarks() => LoadEdgeBookmarks();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,140 +5,133 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
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
|
||||
FROM moz_places
|
||||
INNER JOIN moz_bookmarks ON (
|
||||
private const string QueryAllBookmarks = """
|
||||
SELECT moz_places.url, moz_bookmarks.title
|
||||
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
|
||||
)
|
||||
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)
|
||||
{
|
||||
// Return empty list if the places.sqlite file cannot be found
|
||||
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
||||
return new List<Bookmark>();
|
||||
protected static List<Bookmark> GetBookmarksFromPath(string placesPath)
|
||||
{
|
||||
// Return empty list if the places.sqlite file cannot be found
|
||||
if (string.IsNullOrEmpty(placesPath) || !File.Exists(placesPath))
|
||||
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
|
||||
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();
|
||||
|
||||
// return results in List<Bookmark> format
|
||||
bookmarkList = reader.Select(
|
||||
x => new Bookmark(x["title"] is DBNull ? string.Empty : x["title"].ToString(),
|
||||
x["url"].ToString())
|
||||
).ToList();
|
||||
// return results in List<Bookmark> format
|
||||
return reader
|
||||
.Select(
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase
|
||||
/// <summary>
|
||||
/// Path to places.sqlite
|
||||
/// </summary>
|
||||
private string PlacesPath
|
||||
{
|
||||
/// <summary>
|
||||
/// Searches the places.sqlite db and returns all bookmarks
|
||||
/// </summary>
|
||||
public override List<Bookmark> GetBookmarks()
|
||||
get
|
||||
{
|
||||
return GetBookmarksFromPath(PlacesPath);
|
||||
}
|
||||
|
||||
/// <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");
|
||||
var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox");
|
||||
var profileIni = Path.Combine(profileFolderPath, @"profiles.ini");
|
||||
|
||||
if (!File.Exists(profileIni))
|
||||
return string.Empty;
|
||||
if (!File.Exists(profileIni))
|
||||
return string.Empty;
|
||||
|
||||
// get firefox default profile directory from profiles.ini
|
||||
string ini;
|
||||
using (var sReader = new StreamReader(profileIni))
|
||||
{
|
||||
ini = sReader.ReadToEnd();
|
||||
}
|
||||
// get firefox default profile directory from profiles.ini
|
||||
using var sReader = new StreamReader(profileIni);
|
||||
var ini = sReader.ReadToEnd();
|
||||
|
||||
/*
|
||||
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
|
||||
/*
|
||||
Current profiles.ini structure example as of Firefox version 69.0.1
|
||||
|
||||
[Profile2]
|
||||
Name=newblahprofile
|
||||
IsRelative=0
|
||||
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.
|
||||
[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
|
||||
|
||||
[Profile1]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=Profiles/cydum7q4.default
|
||||
Default=1
|
||||
[Profile2]
|
||||
Name=newblahprofile
|
||||
IsRelative=0
|
||||
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.
|
||||
|
||||
[Profile0]
|
||||
Name=default-release
|
||||
IsRelative=1
|
||||
Path=Profiles/7789f565.default-release
|
||||
[Profile1]
|
||||
Name=default
|
||||
IsRelative=1
|
||||
Path=Profiles/cydum7q4.default
|
||||
Default=1
|
||||
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
Version=2
|
||||
*/
|
||||
[Profile0]
|
||||
Name=default-release
|
||||
IsRelative=1
|
||||
Path=Profiles/7789f565.default-release
|
||||
|
||||
var lines = ini.Split(new string[]
|
||||
{
|
||||
"\r\n"
|
||||
}, StringSplitOptions.None).ToList();
|
||||
[General]
|
||||
StartWithLastProfile=1
|
||||
Version=2
|
||||
*/
|
||||
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))
|
||||
return string.Empty;
|
||||
if (string.IsNullOrEmpty(defaultProfileFolderNameRaw))
|
||||
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
|
||||
var relativeAttribute = lines[indexOfDefaultProfileAtttributePath - 1];
|
||||
// Seen in the example above, the IsRelative attribute is always above the Path attribute
|
||||
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
|
||||
? defaultProfileFolderName + @"\places.sqlite"
|
||||
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static IEnumerable<T> Select<T>(this SqliteDataReader reader, Func<SqliteDataReader, T> projection)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return projection(reader);
|
||||
}
|
||||
return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0
|
||||
? defaultProfileFolderName + @"\places.sqlite"
|
||||
: Path.Combine(profileFolderPath, defaultProfileFolderName) + @"\places.sqlite";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Extensions
|
||||
{
|
||||
public static IEnumerable<T> Select<T>(this SqliteDataReader reader, Func<SqliteDataReader, T> projection)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return projection(reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="8.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Plugin.BrowserBookmark.Commands;
|
||||
|
|
@ -12,233 +11,234 @@ using System.Threading.Channels;
|
|||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
private static void LoadBookmarksIfEnabled()
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
// Don't load or monitor files if disabled
|
||||
return;
|
||||
}
|
||||
|
||||
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 = _ =>
|
||||
// Since we mixed chrome and firefox bookmarks, we should order them again
|
||||
return _cachedBookmarks
|
||||
.Select(
|
||||
c => new Result
|
||||
{
|
||||
context.API.OpenUrl(c.Url);
|
||||
|
||||
return true;
|
||||
},
|
||||
ContextData = new BookmarkAttributes
|
||||
{
|
||||
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
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = BookmarkLoader.MatchProgram(c, param).Score,
|
||||
Action = _ =>
|
||||
{
|
||||
context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url);
|
||||
_context.API.OpenUrl(c.Url);
|
||||
|
||||
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";
|
||||
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();
|
||||
_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);
|
||||
|
||||
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;
|
||||
|
||||
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 record Bookmark(string Name, string Url, string Source = "")
|
||||
public override int GetHashCode()
|
||||
{
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashName = Name?.GetHashCode() ?? 0;
|
||||
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();
|
||||
var hashName = Name?.GetHashCode() ?? 0;
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +1,44 @@
|
|||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models
|
||||
{
|
||||
public class CustomBrowser : BaseModel
|
||||
{
|
||||
private string _name;
|
||||
private string _dataDirectoryPath;
|
||||
private BrowserType browserType = BrowserType.Chromium;
|
||||
namespace Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||
|
||||
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;
|
||||
set
|
||||
{
|
||||
_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));
|
||||
}
|
||||
_name = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public enum BrowserType
|
||||
public string DataDirectoryPath
|
||||
{
|
||||
Chromium,
|
||||
Firefox,
|
||||
get => _dataDirectoryPath;
|
||||
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;
|
||||
|
||||
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 LoadFirefoxBookmark { get; set; } = true;
|
||||
public bool LoadEdgeBookmark { get; set; } = true;
|
||||
public bool LoadChromeBookmark { get; set; } = true;
|
||||
public bool LoadFirefoxBookmark { 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