- Merge Split Setting
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
|
||||
namespace Flow.Launcher.Core.ExternalPlugins
|
||||
{
|
||||
|
|
@ -13,9 +13,11 @@ namespace Flow.Launcher.Core.ExternalPlugins
|
|||
public string Website { get; set; }
|
||||
public string UrlDownload { get; set; }
|
||||
public string UrlSourceCode { get; set; }
|
||||
public string LocalInstallPath { get; set; }
|
||||
public string IcoPath { get; set; }
|
||||
public DateTime? LatestReleaseDate { get; set; }
|
||||
public DateTime? DateAdded { get; set; }
|
||||
|
||||
public bool IsFromLocalInstallPath => !string.IsNullOrEmpty(LocalInstallPath);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -380,7 +380,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// Update a plugin to new version, from a zip file. Will Delete zip after updating.
|
||||
/// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url,
|
||||
/// unless it's a local path installation
|
||||
/// </summary>
|
||||
public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath)
|
||||
{
|
||||
|
|
@ -390,11 +391,11 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Install a plugin. Will Delete zip after updating.
|
||||
/// Install a plugin. By default will remove the zip file if installation is from url, unless it's a local path installation
|
||||
/// </summary>
|
||||
public static void InstallPlugin(UserPlugin plugin, string zipFilePath)
|
||||
{
|
||||
InstallPlugin(plugin, zipFilePath, true);
|
||||
InstallPlugin(plugin, zipFilePath, checkModified: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -420,7 +421,9 @@ namespace Flow.Launcher.Core.Plugin
|
|||
// Unzip plugin files to temp folder
|
||||
var tempFolderPluginPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempFolderPluginPath);
|
||||
File.Delete(zipFilePath);
|
||||
|
||||
if(!plugin.IsFromLocalInstallPath)
|
||||
File.Delete(zipFilePath);
|
||||
|
||||
var pluginFolderPath = GetContainingFolderPathAfterUnzip(tempFolderPluginPath);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
public string SelectPrevPageHotkey { get; set; } = $"PageDown";
|
||||
public string OpenContextMenuHotkey { get; set; } = $"Ctrl+O";
|
||||
public string SettingWindowHotkey { get; set; } = $"Ctrl+I";
|
||||
public string CycleHistoryUpHotkey { get; set; } = $"{KeyConstant.Alt} + Up";
|
||||
public string CycleHistoryDownHotkey { get; set; } = $"{KeyConstant.Alt} + Down";
|
||||
|
||||
public string Language
|
||||
{
|
||||
|
|
@ -283,42 +285,9 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
{
|
||||
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)
|
||||
};
|
||||
var list = FixedHotkeys();
|
||||
|
||||
// Customizeable hotkeys
|
||||
if(!string.IsNullOrEmpty(Hotkey))
|
||||
list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = ""));
|
||||
if(!string.IsNullOrEmpty(PreviewHotkey))
|
||||
|
|
@ -343,7 +312,12 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = ""));
|
||||
if(!string.IsNullOrEmpty(SelectPrevPageHotkey))
|
||||
list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = ""));
|
||||
if (!string.IsNullOrEmpty(CycleHistoryUpHotkey))
|
||||
list.Add(new(CycleHistoryUpHotkey, "CycleHistoryUpHotkey", () => CycleHistoryUpHotkey = ""));
|
||||
if (!string.IsNullOrEmpty(CycleHistoryDownHotkey))
|
||||
list.Add(new(CycleHistoryDownHotkey, "CycleHistoryDownHotkey", () => CycleHistoryDownHotkey = ""));
|
||||
|
||||
// Custom Query Hotkeys
|
||||
foreach (var customPluginHotkey in CustomPluginHotkeys)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(customPluginHotkey.Hotkey))
|
||||
|
|
@ -353,6 +327,45 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private List<RegisteredHotkeyData> FixedHotkeys()
|
||||
{
|
||||
return 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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public enum LastQueryMode
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
#pragma warning disable IDE0005
|
||||
using System.Windows;
|
||||
#pragma warning restore IDE0005
|
||||
|
|
@ -200,6 +201,24 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
}
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// This checks whether a given string is a zip file path.
|
||||
/// By default does not check if the zip file actually exist on disk, can do so by
|
||||
/// setting checkFileExists = true.
|
||||
///</summary>
|
||||
public static bool IsZipFilePath(string querySearchString, bool checkFileExists = false)
|
||||
{
|
||||
if (IsLocationPathString(querySearchString) && querySearchString.Split('.').Last() == "zip")
|
||||
{
|
||||
if (checkFileExists)
|
||||
return FileExists(querySearchString);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// This checks whether a given string is a directory path or network location string.
|
||||
/// It does not check if location actually exists.
|
||||
|
|
|
|||
|
|
@ -191,11 +191,15 @@ namespace Flow.Launcher.Test.Plugins
|
|||
[TestCase(@"\c:\", false)]
|
||||
[TestCase(@"cc:\", false)]
|
||||
[TestCase(@"\\\SomeNetworkLocation\", false)]
|
||||
[TestCase(@"\\SomeNetworkLocation\", true)]
|
||||
[TestCase("RandomFile", false)]
|
||||
[TestCase(@"c:\>*", true)]
|
||||
[TestCase(@"c:\>", true)]
|
||||
[TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)]
|
||||
[TestCase(@"c:\SomeLocation\SomeOtherLocation", true)]
|
||||
[TestCase(@"c:\SomeLocation\SomeOtherLocation\SomeFile.exe", true)]
|
||||
[TestCase(@"\\SomeNetworkLocation\SomeFile.exe", true)]
|
||||
|
||||
public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult)
|
||||
{
|
||||
// When, Given
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
</ui:ThemeResources>
|
||||
<ui:XamlControlsResources />
|
||||
<ResourceDictionary Source="pack://application:,,,/Resources/CustomControlTemplate.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/Resources/SettingWindowStyle.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/Themes/Win11System.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/Languages/en.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ namespace Flow.Launcher
|
|||
{
|
||||
public partial class CustomShortcutSetting : Window
|
||||
{
|
||||
private SettingWindowViewModel viewModel;
|
||||
public string Key { get; set; } = String.Empty;
|
||||
public string Value { get; set; } = String.Empty;
|
||||
private string originalKey { get; init; } = null;
|
||||
|
|
@ -17,13 +16,11 @@ namespace Flow.Launcher
|
|||
|
||||
public CustomShortcutSetting(SettingWindowViewModel vm)
|
||||
{
|
||||
viewModel = vm;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public CustomShortcutSetting(string key, string value, SettingWindowViewModel vm)
|
||||
public CustomShortcutSetting(string key, string value)
|
||||
{
|
||||
viewModel = vm;
|
||||
Key = key;
|
||||
Value = value;
|
||||
originalKey = key;
|
||||
|
|
@ -46,8 +43,7 @@ namespace Flow.Launcher
|
|||
return;
|
||||
}
|
||||
// Check if key is modified or adding a new one
|
||||
if (((update && originalKey != Key) || !update)
|
||||
&& viewModel.ShortcutExists(Key))
|
||||
if ((update && originalKey != Key) || !update)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("duplicateShortcut"));
|
||||
return;
|
||||
|
|
|
|||
BIN
Flow.Launcher/Images/info.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Flow.Launcher/Images/keyboard.png
Normal file
|
After Width: | Height: | Size: 873 B |
BIN
Flow.Launcher/Images/plugins.png
Normal file
|
After Width: | Height: | Size: 804 B |
BIN
Flow.Launcher/Images/proxy.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Flow.Launcher/Images/store.png
Normal file
|
After Width: | Height: | Size: 763 B |
BIN
Flow.Launcher/Images/theme.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
|
|
@ -189,6 +189,8 @@
|
|||
<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="CycleHistoryUpHotkey">Cycle Previous Query</system:String>
|
||||
<system:String x:Key="CycleHistoryDownHotkey">Cycle Next Query</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>
|
||||
|
|
|
|||
|
|
@ -198,6 +198,14 @@
|
|||
Key="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||
Command="{Binding SelectPrevPageCommand}"
|
||||
Modifiers="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||
<KeyBinding
|
||||
Key="{Binding CycleHistoryUpHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||
Command="{Binding ReverseHistoryCommand}"
|
||||
Modifiers="{Binding CycleHistoryUpHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||
<KeyBinding
|
||||
Key="{Binding CycleHistoryDownHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}"
|
||||
Command="{Binding ForwardHistoryCommand}"
|
||||
Modifiers="{Binding CycleHistoryDownHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" />
|
||||
</Window.InputBindings>
|
||||
<Grid>
|
||||
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
<Setter Property="MinHeight" Value="68" />
|
||||
<Setter Property="Padding" Value="0,15,0,15" />
|
||||
<Setter Property="Margin" Value="0,4,0,0" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Style.Triggers>
|
||||
|
|
@ -36,6 +37,27 @@
|
|||
<Setter Property="Padding" Value="38,0,26,0" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</DataTrigger>
|
||||
|
||||
<DataTrigger Binding="{Binding (local:CardGroup.Position), RelativeSource={RelativeSource AncestorType=local:Card}}" Value="First">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
</DataTrigger>
|
||||
|
||||
<DataTrigger Binding="{Binding (local:CardGroup.Position), RelativeSource={RelativeSource AncestorType=local:Card}}" Value="Middle">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0 1 0 0" />
|
||||
</DataTrigger>
|
||||
|
||||
<DataTrigger Binding="{Binding (local:CardGroup.Position), RelativeSource={RelativeSource AncestorType=local:Card}}" Value="Last">
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="CornerRadius" Value="0" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="0 1 0 0" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Flow.Launcher.Resources.Controls
|
|||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get { return (string)GetValue(TitleProperty); }
|
||||
|
|
|
|||
32
Flow.Launcher/Resources/Controls/CardGroup.xaml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<UserControl x:Class="Flow.Launcher.Resources.Controls.CardGroup"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance cc:CardGroup}"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<UserControl.Resources>
|
||||
<Style TargetType="cc:Card" x:Key="FirstStyle">
|
||||
<Setter Property="cc:CardGroup.Position" Value="First" />
|
||||
</Style>
|
||||
<Style TargetType="cc:Card" x:Key="MiddleStyle">
|
||||
<Setter Property="cc:CardGroup.Position" Value="Middle" />
|
||||
</Style>
|
||||
<Style TargetType="cc:Card" x:Key="LastStyle">
|
||||
<Setter Property="cc:CardGroup.Position" Value="Last" />
|
||||
</Style>
|
||||
|
||||
<cc:CardGroupCardStyleSelector
|
||||
x:Key="CardStyleSelector"
|
||||
FirstStyle="{StaticResource FirstStyle}"
|
||||
MiddleStyle="{StaticResource MiddleStyle}"
|
||||
LastStyle="{StaticResource LastStyle}" />
|
||||
</UserControl.Resources>
|
||||
<Border Background="{DynamicResource Color00B}" BorderBrush="{DynamicResource Color03B}" BorderThickness="1"
|
||||
CornerRadius="5">
|
||||
<ItemsControl ItemsSource="{Binding Content, RelativeSource={RelativeSource AncestorType=cc:CardGroup}}"
|
||||
ItemContainerStyleSelector="{StaticResource CardStyleSelector}" />
|
||||
</Border>
|
||||
</UserControl>
|
||||
47
Flow.Launcher/Resources/Controls/CardGroup.xaml.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Flow.Launcher.Resources.Controls;
|
||||
|
||||
public partial class CardGroup : UserControl
|
||||
{
|
||||
public enum CardGroupPosition
|
||||
{
|
||||
NotInGroup,
|
||||
First,
|
||||
Middle,
|
||||
Last
|
||||
}
|
||||
|
||||
public new ObservableCollection<Card> Content
|
||||
{
|
||||
get { return (ObservableCollection<Card>)GetValue(ContentProperty); }
|
||||
set { SetValue(ContentProperty, value); }
|
||||
}
|
||||
|
||||
public static new readonly DependencyProperty ContentProperty =
|
||||
DependencyProperty.Register(nameof(Content), typeof(ObservableCollection<Card>), typeof(CardGroup));
|
||||
|
||||
public static readonly DependencyProperty PositionProperty = DependencyProperty.RegisterAttached(
|
||||
"Position", typeof(CardGroupPosition), typeof(CardGroup),
|
||||
new FrameworkPropertyMetadata(CardGroupPosition.NotInGroup, FrameworkPropertyMetadataOptions.AffectsRender)
|
||||
);
|
||||
|
||||
public static void SetPosition(UIElement element, CardGroupPosition value)
|
||||
{
|
||||
element.SetValue(PositionProperty, value);
|
||||
}
|
||||
|
||||
public static CardGroupPosition GetPosition(UIElement element)
|
||||
{
|
||||
return (CardGroupPosition)element.GetValue(PositionProperty);
|
||||
}
|
||||
|
||||
public CardGroup()
|
||||
{
|
||||
InitializeComponent();
|
||||
Content = new ObservableCollection<Card>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Flow.Launcher.Resources.Controls;
|
||||
|
||||
public class CardGroupCardStyleSelector : StyleSelector
|
||||
{
|
||||
public Style FirstStyle { get; set; }
|
||||
public Style MiddleStyle { get; set; }
|
||||
public Style LastStyle { get; set; }
|
||||
|
||||
public override Style SelectStyle(object item, DependencyObject container)
|
||||
{
|
||||
var itemsControl = ItemsControl.ItemsControlFromItemContainer(container);
|
||||
var index = itemsControl.ItemContainerGenerator.IndexFromContainer(container);
|
||||
|
||||
if (index == 0) return FirstStyle;
|
||||
if (index == itemsControl.Items.Count - 1) return LastStyle;
|
||||
return MiddleStyle;
|
||||
}
|
||||
}
|
||||
14
Flow.Launcher/Resources/Controls/HyperLink.xaml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<UserControl x:Class="Flow.Launcher.Resources.Controls.HyperLink"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<TextBlock>
|
||||
<Hyperlink NavigateUri="{Binding Uri, RelativeSource={RelativeSource AncestorType=UserControl}}"
|
||||
RequestNavigate="Hyperlink_OnRequestNavigate">
|
||||
<Run Text="{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
</UserControl>
|
||||
39
Flow.Launcher/Resources/Controls/HyperLink.xaml.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
namespace Flow.Launcher.Resources.Controls;
|
||||
|
||||
public partial class HyperLink : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty UriProperty = DependencyProperty.Register(
|
||||
nameof(Uri), typeof(string), typeof(HyperLink), new PropertyMetadata(default(string))
|
||||
);
|
||||
|
||||
public string Uri
|
||||
{
|
||||
get => (string)GetValue(UriProperty);
|
||||
set => SetValue(UriProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
nameof(Text), typeof(string), typeof(HyperLink), new PropertyMetadata(default(string))
|
||||
);
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public HyperLink()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
App.API.OpenUrl(e.Uri);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
224
Flow.Launcher/Resources/Controls/InstalledPluginDisplay.xaml
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
<UserControl x:Class="Flow.Launcher.Resources.Controls.InstalledPluginDisplay"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:viewModel="clr-namespace:Flow.Launcher.ViewModel"
|
||||
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DataContext="{d:DesignInstance viewModel:PluginViewModel}"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Expander
|
||||
Padding="0"
|
||||
BorderThickness="0"
|
||||
ClipToBounds="True"
|
||||
IsExpanded="{Binding Mode=TwoWay, Path=IsExpanded}"
|
||||
SnapsToDevicePixels="True"
|
||||
Style="{StaticResource ExpanderStyle1}">
|
||||
<Expander.Header>
|
||||
<Border Padding="0 12">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="36" MinWidth="36" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.Column="0"
|
||||
Width="32"
|
||||
Height="32"
|
||||
Source="{Binding Image, IsAsync=True}" />
|
||||
<StackPanel Grid.Column="1" Margin="16 0 14 0">
|
||||
<TextBlock
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding PluginPair.Metadata.Name}"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip="{Binding PluginPair.Metadata.Version}" />
|
||||
<TextBlock
|
||||
Margin="0 2 0 0"
|
||||
Foreground="{DynamicResource Color04B}"
|
||||
FontSize="12"
|
||||
Text="{Binding PluginPair.Metadata.Description}"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<TextBlock
|
||||
Margin="0 0 8 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource Color08B}"
|
||||
Text="{DynamicResource priority}" />
|
||||
<Button
|
||||
x:Name="PriorityButton"
|
||||
Margin="0 0 22 0"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding EditPluginPriorityCommand}"
|
||||
Content="{Binding Priority}"
|
||||
Cursor="Hand"
|
||||
ToolTip="{DynamicResource priorityToolTip}">
|
||||
<!--#region Priority Button Style-->
|
||||
<Button.Resources>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="CornerRadius" Value="2" />
|
||||
</Style>
|
||||
</Button.Resources>
|
||||
<Button.Style>
|
||||
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="Button">
|
||||
<Setter Property="Padding" Value="12 8" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="FontWeight" Value="DemiBold" />
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger
|
||||
Binding="{Binding ElementName=PriorityButton, UpdateSourceTrigger=PropertyChanged, Path=Content}"
|
||||
Value="0">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color08B}" />
|
||||
<Setter Property="FontWeight" Value="Normal" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
<!--#endregion-->
|
||||
</Button>
|
||||
|
||||
<ui:ToggleSwitch
|
||||
Margin="0 0 8 0"
|
||||
IsOn="{Binding PluginState}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Expander.Header>
|
||||
|
||||
<StackPanel>
|
||||
<Border
|
||||
Width="Auto"
|
||||
Height="52"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
BorderThickness="0 1 0 0"
|
||||
CornerRadius="0"
|
||||
Style="{DynamicResource SettingGroupBox}"
|
||||
Visibility="{Binding ActionKeywordsVisibility}">
|
||||
<DockPanel Margin="22 0 18 0" VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
Margin="48 0 10 0"
|
||||
DockPanel.Dock="Left"
|
||||
Style="{StaticResource Glyph}">
|
||||

|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
DockPanel.Dock="Left"
|
||||
Style="{DynamicResource SettingTitleLabel}"
|
||||
Text="{DynamicResource actionKeywords}" />
|
||||
<Button
|
||||
Width="100"
|
||||
Height="34"
|
||||
Margin="5 0 0 0"
|
||||
HorizontalAlignment="Right"
|
||||
Command="{Binding SetActionKeywordsCommand}"
|
||||
Content="{Binding ActionKeywordsText}"
|
||||
Cursor="Hand"
|
||||
DockPanel.Dock="Right"
|
||||
FontWeight="Bold"
|
||||
ToolTip="{DynamicResource actionKeywordsTooltip}"
|
||||
Visibility="{Binding ActionKeywordsVisibility}" />
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
BorderThickness="0 1 0 0"
|
||||
BorderBrush="{DynamicResource Color03B}"
|
||||
Background="{DynamicResource Color00B}">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasSettingControl}" Value="False">
|
||||
<Setter Property="Visibility" Value="Collapsed" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<ContentControl
|
||||
Margin="0"
|
||||
Padding="1"
|
||||
VerticalAlignment="Stretch"
|
||||
Content="{Binding SettingControl}" />
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Margin="0"
|
||||
Padding="15 10"
|
||||
VerticalAlignment="Center"
|
||||
BorderThickness="0 1 0 0"
|
||||
CornerRadius="0 0 5 5"
|
||||
Style="{DynamicResource SettingGroupBox}">
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="10 0 0 0"
|
||||
VerticalAlignment="center"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource PluginInfoColor}"
|
||||
Text="{DynamicResource author}" />
|
||||
<TextBlock
|
||||
Margin="5 0 0 0"
|
||||
VerticalAlignment="center"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource PluginInfoColor}"
|
||||
Text="{Binding PluginPair.Metadata.Author}" />
|
||||
<TextBlock
|
||||
Margin="10 0 0 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource PluginInfoColor}"
|
||||
Text="|" />
|
||||
<TextBlock
|
||||
Margin="10 0 5 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource PluginInfoColor}"
|
||||
Text="{Binding Version}"
|
||||
ToolTip="{Binding InitAndQueryTime}"
|
||||
ToolTipService.InitialShowDelay="500" />
|
||||
<TextBlock
|
||||
Margin="5 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="11"
|
||||
Foreground="{DynamicResource PluginInfoColor}"
|
||||
Text="|" />
|
||||
<TextBlock
|
||||
Margin="5 0 0 0"
|
||||
Style="{DynamicResource LinkBtnStyle}"
|
||||
Text=""
|
||||
ToolTip="{DynamicResource plugin_query_web}">
|
||||
<TextBlock.InputBindings>
|
||||
<MouseBinding Command="{Binding OpenSourceCodeLinkCommand}" MouseAction="LeftClick" />
|
||||
</TextBlock.InputBindings>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Margin="10 0 0 0"
|
||||
Style="{DynamicResource LinkBtnStyle}"
|
||||
Text=""
|
||||
ToolTip="{DynamicResource plugin_uninstall}">
|
||||
<TextBlock.InputBindings>
|
||||
<MouseBinding Command="{Binding OpenDeletePluginWindowCommand}" MouseAction="LeftClick" />
|
||||
</TextBlock.InputBindings>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Margin="10 0 5 0"
|
||||
Style="{DynamicResource LinkBtnStyle}"
|
||||
Text=""
|
||||
ToolTip="{DynamicResource pluginDirectory}">
|
||||
<TextBlock.InputBindings>
|
||||
<MouseBinding Command="{Binding OpenPluginDirectoryCommand}" MouseAction="LeftClick" />
|
||||
</TextBlock.InputBindings>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Expander>
|
||||
</UserControl>
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
namespace Flow.Launcher.Resources.Controls;
|
||||
|
||||
public partial class InstalledPluginDisplay
|
||||
{
|
||||
public InstalledPluginDisplay()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace Flow.Launcher.Resources.MarkupExtensions;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class CollapsedWhenExtension : MarkupExtension {
|
||||
private Binding? When { get; set; }
|
||||
public object? IsEqualTo { get; set; }
|
||||
|
||||
public bool? IsEqualToBool
|
||||
{
|
||||
get => IsEqualTo switch
|
||||
{
|
||||
bool b => b,
|
||||
_ => null
|
||||
};
|
||||
set => IsEqualTo = value;
|
||||
}
|
||||
|
||||
public int? IsEqualToInt
|
||||
{
|
||||
get => IsEqualTo switch
|
||||
{
|
||||
int i => i,
|
||||
_ => null
|
||||
};
|
||||
set => IsEqualTo = value;
|
||||
}
|
||||
|
||||
protected virtual Visibility DefaultVisibility => Visibility.Visible;
|
||||
protected virtual Visibility InvertedVisibility => Visibility.Collapsed;
|
||||
|
||||
public CollapsedWhenExtension(Binding when)
|
||||
{
|
||||
When = when;
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider) {
|
||||
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is not IProvideValueTarget provideValueTarget)
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
if (provideValueTarget is not { TargetObject: not null, TargetProperty: not null })
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
|
||||
if (When is null)
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
if (IsEqualTo is Binding isEqualToBinding)
|
||||
{
|
||||
var multiBinding = new MultiBinding
|
||||
{
|
||||
Converter = new HideableVisibilityConverter
|
||||
{
|
||||
DefaultVisibility = DefaultVisibility,
|
||||
InvertedVisibility = InvertedVisibility
|
||||
},
|
||||
Bindings = { When, isEqualToBinding }
|
||||
};
|
||||
|
||||
return multiBinding.ProvideValue(serviceProvider);
|
||||
}
|
||||
|
||||
When.Converter = new HideableVisibilityConverter
|
||||
{
|
||||
DefaultVisibility = DefaultVisibility,
|
||||
InvertedVisibility = InvertedVisibility,
|
||||
IsEqualTo = IsEqualTo
|
||||
};
|
||||
return When.ProvideValue(serviceProvider);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Flow.Launcher.Resources.MarkupExtensions;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class HideableVisibilityConverter : IMultiValueConverter, IValueConverter {
|
||||
public Visibility DefaultVisibility { get; init; } = Visibility.Visible;
|
||||
public Visibility InvertedVisibility { get; init; } = Visibility.Collapsed;
|
||||
|
||||
public object? IsEqualTo { get; set; }
|
||||
|
||||
public object Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture) {
|
||||
if (values is not { Length: 2 })
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
var value1 = values[0];
|
||||
var value2 = values[1];
|
||||
if (value1 is Enum enum1 && value2 is Enum enum2)
|
||||
{
|
||||
value1 = System.Convert.ToInt32(enum1);
|
||||
value2 = System.Convert.ToInt32(enum2);
|
||||
}
|
||||
|
||||
return Equals(value1, value2) ? InvertedVisibility : DefaultVisibility;
|
||||
}
|
||||
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
return Equals(value, IsEqualTo) ? InvertedVisibility : DefaultVisibility;
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture) {
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Flow.Launcher.Resources.MarkupExtensions;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class VisibleWhenExtension : CollapsedWhenExtension
|
||||
{
|
||||
protected override Visibility DefaultVisibility => Visibility.Collapsed;
|
||||
protected override Visibility InvertedVisibility => Visibility.Visible;
|
||||
|
||||
public VisibleWhenExtension(Binding when) : base(when) { }
|
||||
}
|
||||
413
Flow.Launcher/Resources/SettingWindowStyle.xaml
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="clr-namespace:Flow.Launcher.Converters"
|
||||
xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core">
|
||||
<converters:BorderClipConverter x:Key="BorderClipConverter" />
|
||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
||||
<converters:TextConverter x:Key="TextConverter" />
|
||||
<core:TranslationConverter x:Key="TranslationConverter" />
|
||||
|
||||
<Style x:Key="StoreItemFocusVisualStyleKey">
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Rectangle
|
||||
Margin="0"
|
||||
Stroke="Black"
|
||||
StrokeThickness="2" />
|
||||
</ControlTemplate>
|
||||
</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" />
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition
|
||||
Width="auto"
|
||||
MinWidth="20"
|
||||
MaxWidth="60" />
|
||||
<ColumnDefinition Width="8*" />
|
||||
<ColumnDefinition Width="Auto" MinWidth="30" />
|
||||
</Grid.ColumnDefinitions>
|
||||
</Grid>
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="SettingGroupBox" 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="Margin" Value="0,5,0,0" />
|
||||
<Setter Property="Padding" Value="0,15,0,15" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
</Style>
|
||||
<Style x:Key="SettingTitleLabel" TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
|
||||
<Setter Property="Margin" Value="0,0,0,0" />
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SettingSubTitleLabel" TargetType="{x:Type TextBlock}">
|
||||
<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>
|
||||
<Style x:Key="TextPanel" TargetType="{x:Type StackPanel}">
|
||||
<Setter Property="Grid.Column" Value="1" />
|
||||
<Setter Property="Margin" Value="0,0,0,0" />
|
||||
<Setter Property="Width" Value="Auto" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
</Style>
|
||||
<Style
|
||||
x:Key="SideControlCheckBox"
|
||||
BasedOn="{StaticResource DefaultCheckBoxStyle}"
|
||||
TargetType="{x:Type CheckBox}">
|
||||
<Setter Property="Width" Value="24" />
|
||||
<Setter Property="Grid.Column" Value="2" />
|
||||
<Setter Property="Margin" Value="0,4,10,4" />
|
||||
<Setter Property="LayoutTransform">
|
||||
<Setter.Value>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1" />
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="SideTextAbout" TargetType="{x:Type TextBlock}">
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="Grid.Column" Value="1" />
|
||||
<Setter Property="Margin" Value="0,0,-18,0" />
|
||||
</Style>
|
||||
|
||||
|
||||
<Style x:Key="logo" TargetType="{x:Type TabItem}">
|
||||
<!--#region Logo Style-->
|
||||
<Setter Property="Margin" Value="0" />
|
||||
<Setter Property="HorizontalAlignment" Value="center" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="Foreground" Value="black" />
|
||||
<Setter Property="BorderThickness" Value="0" />
|
||||
<Setter Property="Focusable" Value="false" />
|
||||
<Setter Property="Cursor" Value="Arrow" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TabItem}">
|
||||
<Border>
|
||||
<Grid>
|
||||
<Grid>
|
||||
<Border
|
||||
x:Name="Spacer"
|
||||
Width="Auto"
|
||||
Height="Auto"
|
||||
Margin="0,10,5,0"
|
||||
Padding="0,0,0,0"
|
||||
BorderBrush="Transparent"
|
||||
BorderThickness="0">
|
||||
<Border
|
||||
x:Name="border"
|
||||
Background="Transparent"
|
||||
CornerRadius="5">
|
||||
<ContentPresenter
|
||||
x:Name="ContentSite"
|
||||
Margin="12,12,0,12"
|
||||
HorizontalAlignment="LEFT"
|
||||
VerticalAlignment="Center"
|
||||
ContentSource="Header"
|
||||
TextBlock.Foreground="#000" />
|
||||
</Border>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="Transparent" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="transparent" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<!--#endregion-->
|
||||
</Style>
|
||||
<Style x:Key="NavTabItem" TargetType="{x:Type TabItem}">
|
||||
<Setter Property="DockPanel.Dock" Value="Top" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TabItem}">
|
||||
<Grid>
|
||||
<Border
|
||||
x:Name="border"
|
||||
Height="40"
|
||||
Margin="14,4,8,4"
|
||||
Padding="0,0,0,0"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{DynamicResource Color01B}"
|
||||
CornerRadius="5">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="4" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Rectangle
|
||||
x:Name="Bullet"
|
||||
Grid.Column="0"
|
||||
Width="4"
|
||||
Height="18"
|
||||
Margin="0,11,0,11"
|
||||
Fill="{DynamicResource ToggleSwitchFillOn}"
|
||||
RadiusX="2"
|
||||
RadiusY="2"
|
||||
Visibility="Hidden" />
|
||||
<ContentPresenter
|
||||
x:Name="ContentSite"
|
||||
Grid.Column="1"
|
||||
Margin="12,11,18,11"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
ContentSource="Header"
|
||||
TextBlock.Foreground="#000" />
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="{DynamicResource Color06B}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="True">
|
||||
<Setter TargetName="border" Property="Background" Value="{DynamicResource Color06B}" />
|
||||
<Setter TargetName="Bullet" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style x:Key="PluginList" TargetType="ListBoxItem">
|
||||
<Setter Property="Background" Value="{DynamicResource Color00B}" />
|
||||
<Setter Property="Padding" Value="0,0,0,0" />
|
||||
<Setter Property="UseLayoutRounding" Value="True" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Margin" Value="0,0,18,5" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||
<!--#region Template for blue highlight win10-->
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ListBoxItem}">
|
||||
<Border
|
||||
x:Name="Bd"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="5"
|
||||
UseLayoutRounding="True">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentStringFormat="{TemplateBinding ContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="IsMouseOver" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Color07B}" />
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||
<Setter TargetName="Bd" Property="CornerRadius" Value="5" />
|
||||
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="Selector.IsSelectionActive" Value="False" />
|
||||
<Condition Property="IsSelected" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Color00B}" />
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||
<Setter TargetName="Bd" Property="Margin" Value="0,0,0,0" />
|
||||
|
||||
|
||||
</MultiTrigger>
|
||||
<MultiTrigger>
|
||||
<MultiTrigger.Conditions>
|
||||
<Condition Property="Selector.IsSelectionActive" Value="True" />
|
||||
<Condition Property="IsSelected" Value="True" />
|
||||
</MultiTrigger.Conditions>
|
||||
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource Color00B}" />
|
||||
<Setter TargetName="Bd" Property="BorderBrush" Value="{DynamicResource Color03B}" />
|
||||
<Setter TargetName="Bd" Property="CornerRadius" Value="5" />
|
||||
<Setter TargetName="Bd" Property="Margin" Value="0,0,0,0" />
|
||||
|
||||
|
||||
</MultiTrigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter TargetName="Bd" Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<!--#endregion-->
|
||||
<Setter Property="Height" Value="Auto" />
|
||||
</Style>
|
||||
|
||||
<!--#region PluginStore Style-->
|
||||
<Style x:Key="StoreList" TargetType="ListViewItem">
|
||||
<Setter Property="Padding" Value="0,0,0,0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
<Setter Property="Margin" Value="0,0,8,8" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Stretch" />
|
||||
<!--#region Template for blue highlight win10-->
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ListBoxItem}">
|
||||
<Border
|
||||
x:Name="Bd"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
CornerRadius="5"
|
||||
SnapsToDevicePixels="True"
|
||||
UseLayoutRounding="True">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentStringFormat="{TemplateBinding ContentStringFormat}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<!--#endregion-->
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="PluginListStyle"
|
||||
BasedOn="{StaticResource {x:Type ListBox}}"
|
||||
TargetType="ListBox">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=Items.Count}" Value="0">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid Margin="20,0,0,0">
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="0,20,0,4"
|
||||
FontWeight="Bold"
|
||||
Text="{DynamicResource searchplugin_Noresult_Title}" />
|
||||
<TextBlock Text="{DynamicResource searchplugin_Noresult_Subtitle}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<Style
|
||||
x:Key="StoreListStyle"
|
||||
BasedOn="{StaticResource {x:Type ListBox}}"
|
||||
TargetType="ListBox">
|
||||
<Setter Property="Background" Value="{DynamicResource Color01B}" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding RelativeSource={x:Static RelativeSource.Self}, Path=Items.Count}" Value="0">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid Margin="20,0,0,0">
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="0,20,0,4"
|
||||
FontWeight="Bold"
|
||||
Text="{DynamicResource searchplugin_Noresult_Title}" />
|
||||
<TextBlock Text="{DynamicResource searchplugin_Noresult}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<!-- For Tab Header responsive Width -->
|
||||
<Style x:Key="NavTabControl" TargetType="{x:Type TabControl}">
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Top" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="BorderBrush" Value="Transparent" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Setter Property="FontSize" Value="14" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type TabControl}">
|
||||
<Grid
|
||||
x:Name="templateRoot"
|
||||
ClipToBounds="true"
|
||||
SnapsToDevicePixels="true">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition
|
||||
x:Name="ColumnDefinition0"
|
||||
Width="Auto"
|
||||
MinWidth="230" />
|
||||
<ColumnDefinition x:Name="ColumnDefinition1" Width="7.5*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<!-- here is the edit -->
|
||||
<DockPanel
|
||||
x:Name="headerPanel"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="2,2,2,0"
|
||||
Panel.ZIndex="1"
|
||||
Background="Transparent"
|
||||
IsItemsHost="true"
|
||||
LastChildFill="False" />
|
||||
<Border Grid.Column="1">
|
||||
<ContentPresenter
|
||||
x:Name="PART_SelectedContentHost"
|
||||
Grid.Column="1"
|
||||
ContentSource="SelectedContent" />
|
||||
</Border>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
27
Flow.Launcher/SettingPages/ViewModels/DropdownDataGeneric.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public class DropdownDataGeneric<TValue> : BaseModel where TValue : Enum
|
||||
{
|
||||
public string Display { get; set; }
|
||||
public TValue Value { get; set; }
|
||||
|
||||
public static List<TR> GetValues<TR>(string keyPrefix) where TR : DropdownDataGeneric<TValue>, new()
|
||||
{
|
||||
var data = new List<TR>();
|
||||
var enumValues = (TValue[])Enum.GetValues(typeof(TValue));
|
||||
|
||||
foreach (var value in enumValues)
|
||||
{
|
||||
var key = keyPrefix + value;
|
||||
var display = InternationalizationManager.Instance.GetTranslation(key);
|
||||
data.Add(new TR { Display = display, Value = value });
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPaneAboutViewModel : BaseModel
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
private readonly Updater _updater;
|
||||
|
||||
public string LogFolderSize
|
||||
{
|
||||
get
|
||||
{
|
||||
var size = GetLogFiles().Sum(file => file.Length);
|
||||
return $"{InternationalizationManager.Instance.GetTranslation("clearlogfolder")} ({BytesToReadableString(size)})";
|
||||
}
|
||||
}
|
||||
|
||||
public string Website => Constant.Website;
|
||||
public string SponsorPage => Constant.SponsorPage;
|
||||
public string ReleaseNotes => _updater.GitHubRepository + "/releases/latest";
|
||||
public string Documentation => Constant.Documentation;
|
||||
public string Docs => Constant.Docs;
|
||||
public string Github => Constant.GitHub;
|
||||
|
||||
public string Version => Constant.Version switch
|
||||
{
|
||||
"1.0.0" => Constant.Dev,
|
||||
_ => Constant.Version
|
||||
};
|
||||
|
||||
public string ActivatedTimes => string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("about_activate_times"),
|
||||
_settings.ActivateTimes
|
||||
);
|
||||
|
||||
public SettingsPaneAboutViewModel(Settings settings, Updater updater)
|
||||
{
|
||||
_settings = settings;
|
||||
_updater = updater;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenWelcomeWindow()
|
||||
{
|
||||
var window = new WelcomeWindow(_settings);
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void AskClearLogFolderConfirmation()
|
||||
{
|
||||
var confirmResult = MessageBox.Show(
|
||||
InternationalizationManager.Instance.GetTranslation("clearlogfolderMessage"),
|
||||
InternationalizationManager.Instance.GetTranslation("clearlogfolder"),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
if (confirmResult == MessageBoxResult.Yes)
|
||||
{
|
||||
ClearLogFolder();
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenSettingsFolder()
|
||||
{
|
||||
PluginManager.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Settings));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenLogsFolder()
|
||||
{
|
||||
App.API.OpenDirectory(GetLogDir(Constant.Version).FullName);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private Task UpdateApp() => _updater.UpdateAppAsync(App.API, false);
|
||||
|
||||
private void ClearLogFolder()
|
||||
{
|
||||
var logDirectory = GetLogDir();
|
||||
var logFiles = GetLogFiles();
|
||||
|
||||
logFiles.ForEach(f => f.Delete());
|
||||
|
||||
logDirectory.EnumerateDirectories("*", SearchOption.TopDirectoryOnly)
|
||||
.Where(dir => !Constant.Version.Equals(dir.Name))
|
||||
.ToList()
|
||||
.ForEach(dir => dir.Delete());
|
||||
|
||||
OnPropertyChanged(nameof(LogFolderSize));
|
||||
}
|
||||
|
||||
private static DirectoryInfo GetLogDir(string version = "")
|
||||
{
|
||||
return new DirectoryInfo(Path.Combine(DataLocation.DataDirectory(), Constant.Logs, version));
|
||||
}
|
||||
|
||||
private static List<FileInfo> GetLogFiles(string version = "")
|
||||
{
|
||||
return GetLogDir(version).EnumerateFiles("*", SearchOption.AllDirectories).ToList();
|
||||
}
|
||||
|
||||
private static string BytesToReadableString(long bytes)
|
||||
{
|
||||
const int scale = 1024;
|
||||
string[] orders = { "GB", "MB", "KB", "B" };
|
||||
long max = (long)Math.Pow(scale, orders.Length - 1);
|
||||
|
||||
foreach (string order in orders)
|
||||
{
|
||||
if (bytes > max)
|
||||
return $"{decimal.Divide(bytes, max):##.##} {order}";
|
||||
|
||||
max /= scale;
|
||||
}
|
||||
|
||||
return "0 B";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Forms;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Configuration;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Plugin.SharedModels;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPaneGeneralViewModel : BaseModel
|
||||
{
|
||||
public Settings Settings { get; }
|
||||
private readonly Updater _updater;
|
||||
private readonly IPortable _portable;
|
||||
|
||||
public SettingsPaneGeneralViewModel(Settings settings, Updater updater, IPortable portable)
|
||||
{
|
||||
Settings = settings;
|
||||
_updater = updater;
|
||||
_portable = portable;
|
||||
UpdateLastQueryModeDisplay();
|
||||
}
|
||||
|
||||
public class SearchWindowScreen : DropdownDataGeneric<SearchWindowScreens> { }
|
||||
public class SearchWindowAlign : DropdownDataGeneric<SearchWindowAligns> { }
|
||||
// todo a better name?
|
||||
public class LastQueryMode : DropdownDataGeneric<Infrastructure.UserSettings.LastQueryMode> { }
|
||||
|
||||
public bool StartFlowLauncherOnSystemStartup
|
||||
{
|
||||
get => Settings.StartFlowLauncherOnSystemStartup;
|
||||
set
|
||||
{
|
||||
Settings.StartFlowLauncherOnSystemStartup = value;
|
||||
|
||||
try
|
||||
{
|
||||
if (value)
|
||||
AutoStartup.Enable();
|
||||
else
|
||||
AutoStartup.Disable();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"),
|
||||
e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<SearchWindowScreen> SearchWindowScreens =>
|
||||
DropdownDataGeneric<SearchWindowScreens>.GetValues<SearchWindowScreen>("SearchWindowScreen");
|
||||
|
||||
public List<SearchWindowAlign> SearchWindowAligns =>
|
||||
DropdownDataGeneric<SearchWindowAligns>.GetValues<SearchWindowAlign>("SearchWindowAlign");
|
||||
|
||||
public List<int> ScreenNumbers
|
||||
{
|
||||
get
|
||||
{
|
||||
var screens = Screen.AllScreens;
|
||||
var screenNumbers = new List<int>();
|
||||
for (int i = 1; i <= screens.Length; i++)
|
||||
{
|
||||
screenNumbers.Add(i);
|
||||
}
|
||||
|
||||
return screenNumbers;
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
set
|
||||
{
|
||||
if (!_portable.CanUpdatePortability())
|
||||
return;
|
||||
|
||||
if (DataLocation.PortableDataLocationInUse())
|
||||
{
|
||||
_portable.DisablePortableMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
_portable.EnablePortableMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<LastQueryMode> _lastQueryModes = new();
|
||||
|
||||
public List<LastQueryMode> LastQueryModes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_lastQueryModes.Count == 0)
|
||||
{
|
||||
_lastQueryModes =
|
||||
DropdownDataGeneric<Infrastructure.UserSettings.LastQueryMode>
|
||||
.GetValues<LastQueryMode>("LastQuery");
|
||||
}
|
||||
|
||||
return _lastQueryModes;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLastQueryModeDisplay()
|
||||
{
|
||||
foreach (var item in LastQueryModes)
|
||||
{
|
||||
item.Display = InternationalizationManager.Instance.GetTranslation($"LastQuery{item.Value}");
|
||||
}
|
||||
}
|
||||
|
||||
public string Language
|
||||
{
|
||||
get => Settings.Language;
|
||||
set
|
||||
{
|
||||
InternationalizationManager.Instance.ChangeLanguage(value);
|
||||
|
||||
if (InternationalizationManager.Instance.PromptShouldUsePinyin(value))
|
||||
ShouldUsePinyin = true;
|
||||
|
||||
UpdateLastQueryModeDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShouldUsePinyin
|
||||
{
|
||||
get => Settings.ShouldUsePinyin;
|
||||
set => Settings.ShouldUsePinyin = value;
|
||||
}
|
||||
|
||||
public List<string> QuerySearchPrecisionStrings => Enum
|
||||
.GetValues(typeof(SearchPrecisionScore))
|
||||
.Cast<SearchPrecisionScore>()
|
||||
.Select(v => v.ToString())
|
||||
.ToList();
|
||||
|
||||
public List<Language> Languages => InternationalizationManager.Instance.LoadAvailableLanguages();
|
||||
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);
|
||||
|
||||
public string AlwaysPreviewToolTip => string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("AlwaysPreviewToolTip"),
|
||||
Settings.PreviewHotkey
|
||||
);
|
||||
|
||||
private string GetFileFromDialog(string title, string filter = "")
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
|
||||
Multiselect = false,
|
||||
CheckFileExists = true,
|
||||
CheckPathExists = true,
|
||||
Title = title,
|
||||
Filter = filter
|
||||
};
|
||||
|
||||
return dlg.ShowDialog() switch
|
||||
{
|
||||
DialogResult.OK => dlg.FileName,
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private void UpdateApp()
|
||||
{
|
||||
_ = _updater.UpdateAppAsync(App.API, false);
|
||||
}
|
||||
|
||||
public bool AutoUpdates
|
||||
{
|
||||
get => Settings.AutoUpdates;
|
||||
set
|
||||
{
|
||||
Settings.AutoUpdates = value;
|
||||
|
||||
if (value)
|
||||
{
|
||||
UpdateApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectPython()
|
||||
{
|
||||
var selectedFile = GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectPythonExecutable"),
|
||||
"Python|pythonw.exe"
|
||||
);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
Settings.PluginSettings.PythonExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectNode()
|
||||
{
|
||||
var selectedFile = GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectNodeExecutable"),
|
||||
"*.exe"
|
||||
);
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
Settings.PluginSettings.NodeExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectFileManager()
|
||||
{
|
||||
var fileManagerChangeWindow = new SelectFileManagerWindow(Settings);
|
||||
fileManagerChangeWindow.ShowDialog();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SelectBrowser()
|
||||
{
|
||||
var browserWindow = new SelectBrowserWindow(Settings);
|
||||
browserWindow.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPaneHotkeyViewModel : BaseModel
|
||||
{
|
||||
public Settings Settings { get; }
|
||||
|
||||
public CustomPluginHotkey SelectedCustomPluginHotkey { get; set; }
|
||||
public CustomShortcutModel SelectedCustomShortcut { get; set; }
|
||||
|
||||
public string[] OpenResultModifiersList => new[]
|
||||
{
|
||||
KeyConstant.Alt,
|
||||
KeyConstant.Ctrl,
|
||||
$"{KeyConstant.Ctrl}+{KeyConstant.Alt}"
|
||||
};
|
||||
|
||||
public SettingsPaneHotkeyViewModel(Settings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void SetTogglingHotkey(HotkeyModel hotkey)
|
||||
{
|
||||
HotKeyMapper.SetHotkey(hotkey, HotKeyMapper.OnToggleHotkey);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CustomHotkeyDelete()
|
||||
{
|
||||
var item = SelectedCustomPluginHotkey;
|
||||
if (item is null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MessageBox.Show(
|
||||
string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("deleteCustomHotkeyWarning"), item.Hotkey
|
||||
),
|
||||
InternationalizationManager.Instance.GetTranslation("delete"),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
if (result is MessageBoxResult.Yes)
|
||||
{
|
||||
Settings.CustomPluginHotkeys.Remove(item);
|
||||
HotKeyMapper.RemoveHotkey(item.Hotkey);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CustomHotkeyEdit()
|
||||
{
|
||||
var item = SelectedCustomPluginHotkey;
|
||||
if (item is null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
var window = new CustomQueryHotkeySetting(null, Settings);
|
||||
window.UpdateItem(item);
|
||||
window.ShowDialog();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CustomHotkeyAdd()
|
||||
{
|
||||
new CustomQueryHotkeySetting(null, Settings).ShowDialog();
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CustomShortcutDelete()
|
||||
{
|
||||
var item = SelectedCustomShortcut;
|
||||
if (item is null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
var result = MessageBox.Show(
|
||||
string.Format(
|
||||
InternationalizationManager.Instance.GetTranslation("deleteCustomShortcutWarning"), item.Key, item.Value
|
||||
),
|
||||
InternationalizationManager.Instance.GetTranslation("delete"),
|
||||
MessageBoxButton.YesNo
|
||||
);
|
||||
|
||||
if (result is MessageBoxResult.Yes)
|
||||
{
|
||||
Settings.CustomShortcuts.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CustomShortcutEdit()
|
||||
{
|
||||
var item = SelectedCustomShortcut;
|
||||
if (item is null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
var window = new CustomShortcutSetting(item.Key, item.Value);
|
||||
if (window.ShowDialog() is not true) return;
|
||||
|
||||
var index = Settings.CustomShortcuts.IndexOf(item);
|
||||
Settings.CustomShortcuts[index] = new CustomShortcutModel(window.Key, window.Value);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void CustomShortcutAdd()
|
||||
{
|
||||
var window = new CustomShortcutSetting(null);
|
||||
if (window.ShowDialog() is true)
|
||||
{
|
||||
var shortcut = new CustomShortcutModel(window.Key, window.Value);
|
||||
Settings.CustomShortcuts.Add(shortcut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.ViewModel;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPanePluginStoreViewModel : BaseModel
|
||||
{
|
||||
public string FilterText { get; set; } = string.Empty;
|
||||
|
||||
public IList<PluginStoreItemViewModel> ExternalPlugins => PluginsManifest.UserPlugins
|
||||
.Select(p => new PluginStoreItemViewModel(p))
|
||||
.OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.None)
|
||||
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.Installed)
|
||||
.ToList();
|
||||
|
||||
[RelayCommand]
|
||||
private async Task RefreshExternalPluginsAsync()
|
||||
{
|
||||
await PluginsManifest.UpdateManifestAsync();
|
||||
OnPropertyChanged(nameof(ExternalPlugins));
|
||||
}
|
||||
|
||||
public bool SatisfiesFilter(PluginStoreItemViewModel plugin)
|
||||
{
|
||||
return string.IsNullOrEmpty(FilterText) ||
|
||||
StringMatcher.FuzzySearch(FilterText, plugin.Name).IsSearchPrecisionScoreMet() ||
|
||||
StringMatcher.FuzzySearch(FilterText, plugin.Description).IsSearchPrecisionScoreMet();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.ViewModel;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public class SettingsPanePluginsViewModel : BaseModel
|
||||
{
|
||||
private readonly Settings _settings;
|
||||
|
||||
public SettingsPanePluginsViewModel(Settings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
}
|
||||
|
||||
public string FilterText { get; set; } = string.Empty;
|
||||
|
||||
public PluginViewModel? SelectedPlugin { get; set; }
|
||||
|
||||
private IEnumerable<PluginViewModel>? _pluginViewModels;
|
||||
private IEnumerable<PluginViewModel> PluginViewModels => _pluginViewModels ??= PluginManager.AllPlugins
|
||||
.OrderBy(plugin => plugin.Metadata.Disabled)
|
||||
.ThenBy(plugin => plugin.Metadata.Name)
|
||||
.Select(plugin => new PluginViewModel
|
||||
{
|
||||
PluginPair = plugin,
|
||||
PluginSettingsObject = _settings.PluginSettings.Plugins[plugin.Metadata.ID]
|
||||
})
|
||||
.ToList();
|
||||
|
||||
public List<PluginViewModel> FilteredPluginViewModels => PluginViewModels
|
||||
.Where(v =>
|
||||
string.IsNullOrEmpty(FilterText) ||
|
||||
StringMatcher.FuzzySearch(FilterText, v.PluginPair.Metadata.Name).IsSearchPrecisionScoreMet() ||
|
||||
StringMatcher.FuzzySearch(FilterText, v.PluginPair.Metadata.Description).IsSearchPrecisionScoreMet()
|
||||
)
|
||||
.ToList();
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
using System.Net;
|
||||
using System.Windows;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPaneProxyViewModel : BaseModel
|
||||
{
|
||||
private readonly Updater _updater;
|
||||
public Settings Settings { get; }
|
||||
|
||||
public SettingsPaneProxyViewModel(Settings settings, Updater updater)
|
||||
{
|
||||
_updater = updater;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OnTestProxyClicked()
|
||||
{
|
||||
var message = TestProxy();
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation(message));
|
||||
}
|
||||
|
||||
private string TestProxy()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Settings.Proxy.Server)) return "serverCantBeEmpty";
|
||||
if (Settings.Proxy.Port <= 0) return "portCantBeEmpty";
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(_updater.GitHubRepository);
|
||||
|
||||
if (string.IsNullOrEmpty(Settings.Proxy.UserName) || string.IsNullOrEmpty(Settings.Proxy.Password))
|
||||
{
|
||||
request.Proxy = new WebProxy(Settings.Proxy.Server, Settings.Proxy.Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.Proxy = new WebProxy(Settings.Proxy.Server, Settings.Proxy.Port)
|
||||
{
|
||||
Credentials = new NetworkCredential(Settings.Proxy.UserName, Settings.Proxy.Password)
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var response = (HttpWebResponse)request.GetResponse();
|
||||
return response.StatusCode switch
|
||||
{
|
||||
HttpStatusCode.OK => "proxyIsCorrect",
|
||||
_ => "proxyConnectFailed"
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "proxyConnectFailed";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,392 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.ViewModel;
|
||||
using ModernWpf;
|
||||
using ThemeManager = Flow.Launcher.Core.Resource.ThemeManager;
|
||||
using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
public partial class SettingsPaneThemeViewModel : BaseModel
|
||||
{
|
||||
private CultureInfo Culture => CultureInfo.DefaultThreadCurrentCulture;
|
||||
|
||||
public Settings Settings { get; }
|
||||
|
||||
public static string LinkHowToCreateTheme => @"https://flowlauncher.com/docs/#/how-to-create-a-theme";
|
||||
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
|
||||
|
||||
public string SelectedTheme
|
||||
{
|
||||
get => Settings.Theme;
|
||||
set
|
||||
{
|
||||
ThemeManager.Instance.ChangeTheme(value);
|
||||
|
||||
if (ThemeManager.Instance.BlurEnabled && Settings.UseDropShadowEffect)
|
||||
DropShadowEffect = false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool DropShadowEffect
|
||||
{
|
||||
get => Settings.UseDropShadowEffect;
|
||||
set
|
||||
{
|
||||
if (ThemeManager.Instance.BlurEnabled && value)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("shadowEffectNotAllowed"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (value)
|
||||
{
|
||||
ThemeManager.Instance.AddDropShadowEffectToCurrentTheme();
|
||||
}
|
||||
else
|
||||
{
|
||||
ThemeManager.Instance.RemoveDropShadowEffectFromCurrentTheme();
|
||||
}
|
||||
|
||||
Settings.UseDropShadowEffect = value;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> Themes =>
|
||||
ThemeManager.Instance.LoadAvailableThemes().Select(Path.GetFileNameWithoutExtension).ToList();
|
||||
|
||||
|
||||
public class ColorScheme
|
||||
{
|
||||
public string Display { get; set; }
|
||||
public ColorSchemes Value { get; set; }
|
||||
}
|
||||
|
||||
public List<ColorScheme> ColorSchemes
|
||||
{
|
||||
get
|
||||
{
|
||||
List<ColorScheme> modes = new List<ColorScheme>();
|
||||
var enums = (ColorSchemes[])Enum.GetValues(typeof(ColorSchemes));
|
||||
foreach (var e in enums)
|
||||
{
|
||||
var key = $"ColorScheme{e}";
|
||||
var display = InternationalizationManager.Instance.GetTranslation(key);
|
||||
var m = new ColorScheme { Display = display, Value = e, };
|
||||
modes.Add(m);
|
||||
}
|
||||
|
||||
return modes;
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> TimeFormatList { get; } = new()
|
||||
{
|
||||
"h:mm",
|
||||
"hh:mm",
|
||||
"H:mm",
|
||||
"HH:mm",
|
||||
"tt h:mm",
|
||||
"tt hh:mm",
|
||||
"h:mm tt",
|
||||
"hh:mm tt",
|
||||
"hh:mm:ss tt",
|
||||
"HH:mm:ss"
|
||||
};
|
||||
|
||||
public List<string> DateFormatList { get; } = new()
|
||||
{
|
||||
"MM'/'dd dddd",
|
||||
"MM'/'dd ddd",
|
||||
"MM'/'dd",
|
||||
"MM'-'dd",
|
||||
"MMMM', 'dd",
|
||||
"dd'/'MM",
|
||||
"dd'-'MM",
|
||||
"ddd MM'/'dd",
|
||||
"dddd MM'/'dd",
|
||||
"dddd",
|
||||
"ddd dd'/'MM",
|
||||
"dddd dd'/'MM",
|
||||
"dddd dd', 'MMMM",
|
||||
"dd', 'MMMM"
|
||||
};
|
||||
|
||||
public string TimeFormat
|
||||
{
|
||||
get => Settings.TimeFormat;
|
||||
set => Settings.TimeFormat = value;
|
||||
}
|
||||
|
||||
public string DateFormat
|
||||
{
|
||||
get => Settings.DateFormat;
|
||||
set => Settings.DateFormat = value;
|
||||
}
|
||||
|
||||
public string ClockText => DateTime.Now.ToString(TimeFormat, Culture);
|
||||
|
||||
public string DateText => DateTime.Now.ToString(DateFormat, Culture);
|
||||
|
||||
public double WindowWidthSize
|
||||
{
|
||||
get => Settings.WindowSize;
|
||||
set => Settings.WindowSize = value;
|
||||
}
|
||||
|
||||
public bool UseGlyphIcons
|
||||
{
|
||||
get => Settings.UseGlyphIcons;
|
||||
set => Settings.UseGlyphIcons = value;
|
||||
}
|
||||
|
||||
public bool UseAnimation
|
||||
{
|
||||
get => Settings.UseAnimation;
|
||||
set => Settings.UseAnimation = value;
|
||||
}
|
||||
|
||||
public class AnimationSpeed
|
||||
{
|
||||
public string Display { get; set; }
|
||||
public AnimationSpeeds Value { get; set; }
|
||||
}
|
||||
|
||||
public List<AnimationSpeed> AnimationSpeeds
|
||||
{
|
||||
get
|
||||
{
|
||||
List<AnimationSpeed> speeds = new List<AnimationSpeed>();
|
||||
var enums = (AnimationSpeeds[])Enum.GetValues(typeof(AnimationSpeeds));
|
||||
foreach (var e in enums)
|
||||
{
|
||||
var key = $"AnimationSpeed{e}";
|
||||
var display = InternationalizationManager.Instance.GetTranslation(key);
|
||||
var m = new AnimationSpeed { Display = display, Value = e, };
|
||||
speeds.Add(m);
|
||||
}
|
||||
|
||||
return speeds;
|
||||
}
|
||||
}
|
||||
|
||||
public bool UseSound
|
||||
{
|
||||
get => Settings.UseSound;
|
||||
set => Settings.UseSound = value;
|
||||
}
|
||||
|
||||
public double SoundEffectVolume
|
||||
{
|
||||
get => Settings.SoundVolume;
|
||||
set => Settings.SoundVolume = value;
|
||||
}
|
||||
|
||||
public bool UseClock
|
||||
{
|
||||
get => Settings.UseClock;
|
||||
set => Settings.UseClock = value;
|
||||
}
|
||||
|
||||
public bool UseDate
|
||||
{
|
||||
get => Settings.UseDate;
|
||||
set => Settings.UseDate = value;
|
||||
}
|
||||
|
||||
public Brush PreviewBackground
|
||||
{
|
||||
get
|
||||
{
|
||||
var wallpaper = WallpaperPathRetrieval.GetWallpaperPath();
|
||||
if (wallpaper is not null && File.Exists(wallpaper))
|
||||
{
|
||||
var memStream = new MemoryStream(File.ReadAllBytes(wallpaper));
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.StreamSource = memStream;
|
||||
bitmap.DecodePixelWidth = 800;
|
||||
bitmap.DecodePixelHeight = 600;
|
||||
bitmap.EndInit();
|
||||
return new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
|
||||
}
|
||||
|
||||
var wallpaperColor = WallpaperPathRetrieval.GetWallpaperColor();
|
||||
return new SolidColorBrush(wallpaperColor);
|
||||
}
|
||||
}
|
||||
|
||||
public ResultsViewModel PreviewResults
|
||||
{
|
||||
get
|
||||
{
|
||||
var results = new List<Result>
|
||||
{
|
||||
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"
|
||||
)
|
||||
},
|
||||
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"
|
||||
)
|
||||
},
|
||||
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"
|
||||
)
|
||||
},
|
||||
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"
|
||||
)
|
||||
}
|
||||
};
|
||||
var vm = new ResultsViewModel(Settings);
|
||||
vm.AddResults(results, "PREVIEW");
|
||||
return vm;
|
||||
}
|
||||
}
|
||||
|
||||
public FontFamily SelectedQueryBoxFont
|
||||
{
|
||||
get
|
||||
{
|
||||
var fontExists = Fonts.SystemFontFamilies.Any(
|
||||
fontFamily =>
|
||||
fontFamily.FamilyNames.Values != null &&
|
||||
fontFamily.FamilyNames.Values.Contains(Settings.QueryBoxFont)
|
||||
);
|
||||
|
||||
return fontExists switch
|
||||
{
|
||||
true => new FontFamily(Settings.QueryBoxFont),
|
||||
_ => new FontFamily("Segoe UI")
|
||||
};
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.QueryBoxFont = value.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public FamilyTypeface SelectedQueryBoxFontFaces
|
||||
{
|
||||
get
|
||||
{
|
||||
var typeface = SyntaxSugars.CallOrRescueDefault(
|
||||
() => SelectedQueryBoxFont.ConvertFromInvariantStringsOrNormal(
|
||||
Settings.QueryBoxFontStyle,
|
||||
Settings.QueryBoxFontWeight,
|
||||
Settings.QueryBoxFontStretch
|
||||
)
|
||||
);
|
||||
return typeface;
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.QueryBoxFontStretch = value.Stretch.ToString();
|
||||
Settings.QueryBoxFontWeight = value.Weight.ToString();
|
||||
Settings.QueryBoxFontStyle = value.Style.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public FontFamily SelectedResultFont
|
||||
{
|
||||
get
|
||||
{
|
||||
var fontExists = Fonts.SystemFontFamilies.Any(
|
||||
fontFamily =>
|
||||
fontFamily.FamilyNames.Values != null &&
|
||||
fontFamily.FamilyNames.Values.Contains(Settings.ResultFont)
|
||||
);
|
||||
return fontExists switch
|
||||
{
|
||||
true => new FontFamily(Settings.ResultFont),
|
||||
_ => new FontFamily("Segoe UI")
|
||||
};
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.ResultFont = value.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public FamilyTypeface SelectedResultFontFaces
|
||||
{
|
||||
get
|
||||
{
|
||||
var typeface = SyntaxSugars.CallOrRescueDefault(
|
||||
() => SelectedResultFont.ConvertFromInvariantStringsOrNormal(
|
||||
Settings.ResultFontStyle,
|
||||
Settings.ResultFontWeight,
|
||||
Settings.ResultFontStretch
|
||||
)
|
||||
);
|
||||
return typeface;
|
||||
}
|
||||
set
|
||||
{
|
||||
Settings.ResultFontStretch = value.Stretch.ToString();
|
||||
Settings.ResultFontWeight = value.Weight.ToString();
|
||||
Settings.ResultFontStyle = value.Style.ToString();
|
||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
||||
}
|
||||
}
|
||||
|
||||
public string ThemeImage => Constant.QueryTextBoxIconImagePath;
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenThemesFolder()
|
||||
{
|
||||
App.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
|
||||
}
|
||||
|
||||
public void UpdateColorScheme()
|
||||
{
|
||||
ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme = Settings.ColorScheme switch
|
||||
{
|
||||
Constant.Light => ApplicationTheme.Light,
|
||||
Constant.Dark => ApplicationTheme.Dark,
|
||||
Constant.System => null,
|
||||
_ => ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme
|
||||
};
|
||||
}
|
||||
|
||||
public SettingsPaneThemeViewModel(Settings settings)
|
||||
{
|
||||
Settings = settings;
|
||||
}
|
||||
}
|
||||
127
Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPaneAbout"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:settingsVm="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
Title="About"
|
||||
d:DataContext="{d:DesignInstance Type=settingsVm:SettingsPaneAboutViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer
|
||||
Margin="0"
|
||||
CanContentScroll="True"
|
||||
FontSize="14"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.ScrollUnit="Pixel">
|
||||
<StackPanel Margin="5 14 25 30" Orientation="Vertical">
|
||||
<TextBlock
|
||||
Margin="0 5"
|
||||
FontSize="30"
|
||||
Style="{DynamicResource PageTitle}"
|
||||
Text="{DynamicResource about}"
|
||||
TextAlignment="left" />
|
||||
|
||||
|
||||
<cc:Card
|
||||
Title="{Binding Version}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource version}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button
|
||||
Margin="0 0 10 0"
|
||||
Command="{Binding UpdateAppCommand}"
|
||||
Content="{DynamicResource checkUpdates}" />
|
||||
<Button Padding="0" Style="{StaticResource AccentButtonStyle}">
|
||||
<Hyperlink
|
||||
NavigateUri="{Binding SponsorPage}"
|
||||
RequestNavigate="OnRequestNavigate"
|
||||
TextDecorations="None">
|
||||
<TextBlock
|
||||
Padding="10 5"
|
||||
Foreground="White"
|
||||
Text="{DynamicResource BecomeASponsor}" />
|
||||
</Hyperlink>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource releaseNotes}" Icon="">
|
||||
<cc:HyperLink Uri="{Binding ReleaseNotes}" Text="{DynamicResource releaseNotes}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource website}"
|
||||
Margin="0 14 0 0"
|
||||
Icon="">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<cc:HyperLink Margin="0 0 12 0" Uri="{Binding Website}" Text="{DynamicResource website}" />
|
||||
<cc:HyperLink Uri="{Binding Github}" Text="{DynamicResource github}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource documentation}" Icon="">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<cc:HyperLink Margin="0 0 12 0" Uri="{Binding Documentation}" Text="{DynamicResource documentation}" />
|
||||
<cc:HyperLink Uri="{Binding Website}" Text="{DynamicResource website}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource icons}"
|
||||
Margin="0 14 0 0"
|
||||
Icon="">
|
||||
<cc:HyperLink Uri="https://icons8.com/" Text="icons8.com" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource devtool}" Icon="">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button
|
||||
Margin="0 0 12 0"
|
||||
Command="{Binding AskClearLogFolderConfirmationCommand}"
|
||||
Content="{Binding LogFolderSize, Mode=OneWay}" />
|
||||
<Button
|
||||
Content=""
|
||||
FontFamily="/Resources/#Segoe Fluent Icons"
|
||||
FontSize="20">
|
||||
<ui:FlyoutService.Flyout>
|
||||
<ui:MenuFlyout>
|
||||
<MenuItem Command="{Binding OpenWelcomeWindowCommand}" Header="{DynamicResource welcomewindow}">
|
||||
<MenuItem.Icon>
|
||||
<ui:FontIcon Glyph="" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Command="{Binding OpenSettingsFolderCommand}" Header="{DynamicResource settingfolder}">
|
||||
<MenuItem.Icon>
|
||||
<ui:FontIcon Glyph="" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
|
||||
<MenuItem Command="{Binding OpenLogsFolderCommand}" Header="{DynamicResource logfolder}">
|
||||
<MenuItem.Icon>
|
||||
<ui:FontIcon Glyph="" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
</ui:MenuFlyout>
|
||||
</ui:FlyoutService.Flyout>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<TextBlock
|
||||
Margin="14 20 0 0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Bottom"
|
||||
DockPanel.Dock="Bottom"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource Color15B}"
|
||||
Text="{Binding ActivatedTimes}"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
29
Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPaneAbout
|
||||
{
|
||||
private SettingsPaneAboutViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings, Updater: { } updater })
|
||||
throw new ArgumentException("Settings are required for SettingsPaneAbout.");
|
||||
_viewModel = new SettingsPaneAboutViewModel(settings, updater);
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
|
||||
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
App.API.OpenUrl(e.Uri.AbsoluteUri);
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
244
Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPaneGeneral"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:settingsViewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
|
||||
xmlns:ext="clr-namespace:Flow.Launcher.Resources.MarkupExtensions"
|
||||
Title="General"
|
||||
d:DataContext="{d:DesignInstance settingsViewModels:SettingsPaneGeneralViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer
|
||||
Margin="0"
|
||||
CanContentScroll="False"
|
||||
FontSize="14"
|
||||
VirtualizingPanel.ScrollUnit="Pixel"
|
||||
VirtualizingStackPanel.IsVirtualizing="True">
|
||||
<VirtualizingStackPanel Margin="5 18 25 30" Orientation="Vertical">
|
||||
<TextBlock
|
||||
Grid.Row="2"
|
||||
Margin="0 5"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource general}"
|
||||
TextAlignment="left" />
|
||||
|
||||
<cc:Card Title="{DynamicResource startFlowLauncherOnSystemStartup}" Icon="">
|
||||
<ui:ToggleSwitch IsOn="{Binding StartFlowLauncherOnSystemStartup}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource hideOnStartup}" Icon="">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.HideOnStartup}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource hideFlowLauncherWhenLoseFocus}" Margin="0 30 0 0">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.HideWhenDeactivated}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource hideNotifyIcon}" Sub="{DynamicResource hideNotifyIconToolTip}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.HideNotifyIcon}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:CardGroup Margin="0 30 0 0">
|
||||
<cc:Card Icon="" Title="{DynamicResource SearchWindowPosition}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ComboBox
|
||||
MinWidth="220"
|
||||
DisplayMemberPath="Display"
|
||||
SelectedValuePath="Value"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding SearchWindowScreens}"
|
||||
SelectedValue="{Binding Settings.SearchWindowScreen}" />
|
||||
<ComboBox
|
||||
MinWidth="160"
|
||||
Margin="18 0 0 0"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding ScreenNumbers}"
|
||||
SelectedValue="{Binding Settings.CustomScreenNumber}"
|
||||
Visibility="{ext:VisibleWhen
|
||||
{Binding Settings.SearchWindowScreen},
|
||||
IsEqualTo={x:Static userSettings:SearchWindowScreens.Custom}}"
|
||||
/>
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Icon=""
|
||||
Title="{DynamicResource SearchWindowAlign}"
|
||||
Visibility="{ext:CollapsedWhen
|
||||
{Binding Settings.SearchWindowScreen},
|
||||
IsEqualTo={x:Static userSettings:SearchWindowScreens.RememberLastLaunchLocation}}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ComboBox
|
||||
MinWidth="160"
|
||||
DisplayMemberPath="Display"
|
||||
SelectedValuePath="Value"
|
||||
FontSize="14"
|
||||
VerticalAlignment="Center"
|
||||
ItemsSource="{Binding SearchWindowAligns}"
|
||||
SelectedValue="{Binding Settings.SearchWindowAlign}" />
|
||||
|
||||
<StackPanel
|
||||
Margin="18 0 0 0"
|
||||
Orientation="Horizontal"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{ext:VisibleWhen
|
||||
{Binding Settings.SearchWindowAlign},
|
||||
IsEqualTo={x:Static userSettings:SearchWindowAligns.Custom}}">
|
||||
<TextBox VerticalAlignment="Center" MinWidth="80"
|
||||
Text="{Binding Settings.CustomWindowLeft}" />
|
||||
<TextBlock VerticalAlignment="Center" Margin="10" Text="x" />
|
||||
<TextBox VerticalAlignment="Center" MinWidth="80" Text="{Binding Settings.CustomWindowTop}"
|
||||
TextWrapping="NoWrap" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource ignoreHotkeysOnFullscreen}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource ignoreHotkeysOnFullscreenToolTip}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.IgnoreHotkeysOnFullscreen}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource AlwaysPreview}"
|
||||
Margin="0 30 0 0"
|
||||
Icon=""
|
||||
Sub="{DynamicResource AlwaysPreviewToolTip}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.AlwaysPreview}" ToolTip="{Binding AlwaysPreviewToolTip}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource autoUpdates}"
|
||||
Margin="0 30 0 0"
|
||||
Icon="">
|
||||
<ui:ToggleSwitch IsOn="{Binding AutoUpdates}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource portableMode}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource portableModeToolTIp}">
|
||||
<ui:ToggleSwitch IsOn="{Binding PortableMode}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:CardGroup Margin="0 30 0 0">
|
||||
<cc:Card Title="{DynamicResource querySearchPrecision}"
|
||||
Sub="{DynamicResource querySearchPrecisionToolTip}">
|
||||
<ComboBox
|
||||
MaxWidth="200"
|
||||
ItemsSource="{Binding QuerySearchPrecisionStrings}"
|
||||
SelectedItem="{Binding Settings.QuerySearchPrecisionString}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource lastQueryMode}" Sub="{DynamicResource lastQueryModeToolTip}">
|
||||
<ComboBox
|
||||
DisplayMemberPath="Display"
|
||||
SelectedValuePath="Value"
|
||||
ItemsSource="{Binding LastQueryModes}"
|
||||
SelectedValue="{Binding Settings.LastQueryMode}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Icon="" Title="{DynamicResource maxShowResults}"
|
||||
Sub="{DynamicResource maxShowResultsToolTip}">
|
||||
<ComboBox
|
||||
Width="100"
|
||||
ItemsSource="{Binding MaxResultsRange}"
|
||||
SelectedItem="{Binding Settings.MaxResultsToShow}" />
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource defaultFileManager}"
|
||||
Margin="0 30 0 0"
|
||||
Icon=""
|
||||
Sub="{DynamicResource defaultFileManagerToolTip}">
|
||||
<Button
|
||||
Width="160"
|
||||
MaxWidth="250"
|
||||
Margin="10 0 0 0"
|
||||
Command="{Binding SelectFileManagerCommand}"
|
||||
Content="{Binding Settings.CustomExplorer.Name}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource defaultBrowser}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource defaultBrowserToolTip}">
|
||||
<Button
|
||||
Width="160"
|
||||
MaxWidth="250"
|
||||
Margin="10 0 0 0"
|
||||
Command="{Binding SelectBrowserCommand}"
|
||||
Content="{Binding Settings.CustomBrowser.Name}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource pythonFilePath}" Margin="0 30 0 0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="300"
|
||||
Height="34"
|
||||
Text="{Binding Settings.PluginSettings.PythonExecutablePath, TargetNullValue='None'}" />
|
||||
<Button
|
||||
Height="34"
|
||||
Margin="10 0 0 0"
|
||||
Command="{Binding SelectPythonCommand}"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource nodeFilePath}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox
|
||||
Width="300"
|
||||
Height="34"
|
||||
Text="{Binding Settings.PluginSettings.NodeExecutablePath, TargetNullValue='None'}" />
|
||||
<Button
|
||||
Height="34"
|
||||
Margin="10 0 0 0"
|
||||
Command="{Binding SelectNodeCommand}"
|
||||
Content="{DynamicResource select}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource typingStartEn}"
|
||||
Margin="0 30 0 0"
|
||||
Icon=""
|
||||
Sub="{DynamicResource typingStartEnTooltip}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.AlwaysStartEn}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource ShouldUsePinyin}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource ShouldUsePinyinToolTip}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.ShouldUsePinyin}"
|
||||
ToolTip="{DynamicResource ShouldUsePinyinToolTip}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource language}"
|
||||
Margin="0 30 0 0"
|
||||
Icon="">
|
||||
<ComboBox
|
||||
MaxWidth="200"
|
||||
Margin="10 0 0 0"
|
||||
DisplayMemberPath="Display"
|
||||
ItemsSource="{Binding Languages}"
|
||||
SelectedValue="{Binding Language}"
|
||||
SelectedValuePath="LanguageCode" />
|
||||
</cc:Card>
|
||||
</VirtualizingStackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
24
Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPaneGeneral
|
||||
{
|
||||
private SettingsPaneGeneralViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings, Updater: {} updater, Portable: {} portable })
|
||||
throw new ArgumentException("Settings, Updater and Portable are required for SettingsPaneGeneral.");
|
||||
_viewModel = new SettingsPaneGeneralViewModel(settings, updater, portable);
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
}
|
||||
452
Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml
Normal file
|
|
@ -0,0 +1,452 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPaneHotkey"
|
||||
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:flowlauncher="clr-namespace:Flow.Launcher"
|
||||
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
Title="Hotkey"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsPaneHotkeyViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ScrollViewer
|
||||
Padding="0 0 6 0"
|
||||
FontSize="14"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.ScrollUnit="Pixel">
|
||||
<StackPanel Margin="5 18 18 10">
|
||||
<TextBlock
|
||||
Margin="0 5 0 6"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource hotkeys}"
|
||||
TextAlignment="left" />
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource flowlauncherHotkey}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource flowlauncherHotkeyToolTip}">
|
||||
<flowlauncher:HotkeyControl
|
||||
ChangeHotkey="{Binding SetTogglingHotkeyCommand}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="Alt+Space"
|
||||
Hotkey="{Binding Settings.Hotkey}"
|
||||
ValidateKeyGesture="True"
|
||||
WindowTitle="{DynamicResource flowlauncherHotkey}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource previewHotkey}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource previewHotkeyToolTip}">
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="F1"
|
||||
Hotkey="{Binding Settings.PreviewHotkey}"
|
||||
ValidateKeyGesture="False"
|
||||
WindowTitle="{DynamicResource previewHotkey}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:CardGroup Margin="0 12 0 0">
|
||||
<cc:Card
|
||||
Title="{DynamicResource openResultModifiers}"
|
||||
Sub="{DynamicResource openResultModifiersToolTip}">
|
||||
<ComboBox
|
||||
Width="120"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding OpenResultModifiersList}"
|
||||
SelectedValue="{Binding Settings.OpenResultModifiers}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card
|
||||
Title="{DynamicResource showOpenResultHotkey}"
|
||||
Sub="{DynamicResource showOpenResultHotkeyToolTip}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.ShowOpenResultHotkey}" />
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<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
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="Ctrl+I"
|
||||
Hotkey="{Binding Settings.OpenContextMenuHotkey}"
|
||||
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
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="Ctrl+I"
|
||||
Hotkey="{Binding Settings.SettingWindowHotkey}"
|
||||
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 CycleHistoryUpHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<flowlauncher:HotkeyControl
|
||||
DefaultHotkey="Alt+Up"
|
||||
Hotkey="{Binding Settings.CycleHistoryUpHotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource CycleHistoryDownHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<flowlauncher:HotkeyControl
|
||||
DefaultHotkey="Alt+Down"
|
||||
Hotkey="{Binding Settings.CycleHistoryDownHotkey}"
|
||||
HotkeySettings="{Binding Settings}"
|
||||
ValidateKeyGesture="False" />
|
||||
</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
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey=""
|
||||
Hotkey="{Binding Settings.SelectPrevPageHotkey}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Title="{DynamicResource SelectNextPageHotkey}"
|
||||
Icon=""
|
||||
Type="Inside">
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey=""
|
||||
Hotkey="{Binding Settings.SelectNextPageHotkey}"
|
||||
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
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="Ctrl+Tab"
|
||||
Hotkey="{Binding Settings.AutoCompleteHotkey}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:ExCard.SideContent>
|
||||
<cc:Card
|
||||
Title="{DynamicResource autoCompleteHotkey}"
|
||||
Sub="{DynamicResource AdditionalHotkeyToolTip}"
|
||||
Type="InsideFit">
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey=""
|
||||
Hotkey="{Binding Settings.AutoCompleteHotkey2}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:Card>
|
||||
</cc:ExCard>
|
||||
|
||||
<cc:ExCard
|
||||
Title="{DynamicResource SelectPrevItemHotkey}"
|
||||
Margin="0 4 0 0"
|
||||
Icon="">
|
||||
<cc:ExCard.SideContent>
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="Shift+Tab"
|
||||
Hotkey="{Binding Settings.SelectPrevItemHotkey}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:ExCard.SideContent>
|
||||
<cc:Card
|
||||
Title="{DynamicResource SelectPrevItemHotkey}"
|
||||
Sub="{DynamicResource AdditionalHotkeyToolTip}"
|
||||
Type="InsideFit">
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey=""
|
||||
Hotkey="{Binding Settings.SelectPrevItemHotkey2}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:Card>
|
||||
</cc:ExCard>
|
||||
|
||||
<cc:ExCard
|
||||
Title="{DynamicResource SelectNextItemHotkey}"
|
||||
Margin="0 4 0 0"
|
||||
Icon="">
|
||||
<cc:ExCard.SideContent>
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey="Tab"
|
||||
Hotkey="{Binding Settings.SelectNextItemHotkey}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:ExCard.SideContent>
|
||||
<cc:Card
|
||||
Title="{DynamicResource SelectNextItemHotkey}"
|
||||
Sub="{DynamicResource AdditionalHotkeyToolTip}"
|
||||
Type="InsideFit">
|
||||
<flowlauncher:HotkeyControl
|
||||
HotkeySettings="{Binding Settings}"
|
||||
DefaultHotkey=""
|
||||
Hotkey="{Binding Settings.SelectNextItemHotkey2}"
|
||||
ValidateKeyGesture="False" />
|
||||
</cc:Card>
|
||||
</cc:ExCard>
|
||||
|
||||
<cc:ExCard
|
||||
Title="{DynamicResource customQueryHotkey}"
|
||||
Margin="0 20 0 0"
|
||||
Icon="">
|
||||
<StackPanel>
|
||||
<Separator
|
||||
Width="Auto"
|
||||
Margin="0"
|
||||
BorderThickness="1"
|
||||
Style="{StaticResource SettingSeparatorStyle}" />
|
||||
<StackPanel Margin="18 18 18 0">
|
||||
<ListView
|
||||
MinHeight="160"
|
||||
Margin="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 HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding CustomHotkeyDeleteCommand}"
|
||||
Content="{DynamicResource delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding CustomHotkeyEditCommand}"
|
||||
Content="{DynamicResource edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10 10 0 10"
|
||||
Command="{Binding CustomHotkeyAddCommand}"
|
||||
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
|
||||
MinHeight="160"
|
||||
Margin="0 6 0 0"
|
||||
Background="{DynamicResource Color02B}"
|
||||
BorderBrush="DarkGray"
|
||||
BorderThickness="1"
|
||||
ItemsSource="{Binding Settings.CustomShortcuts}"
|
||||
SelectedItem="{Binding SelectedCustomShortcut}"
|
||||
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Width="180" Header="{DynamicResource customShortcut}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate DataType="{x:Type userSettings:CustomShortcutModel}">
|
||||
<TextBlock Text="{Binding Key}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Width="430" Header="{DynamicResource customShortcutExpansion}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate DataType="{x:Type userSettings:CustomShortcutModel}">
|
||||
<TextBlock Text="{Binding Value}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<StackPanel
|
||||
Margin="0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding CustomShortcutDeleteCommand}"
|
||||
Content="{DynamicResource delete}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10"
|
||||
Command="{Binding CustomShortcutEditCommand}"
|
||||
Content="{DynamicResource edit}" />
|
||||
<Button
|
||||
MinWidth="100"
|
||||
Margin="10 10 0 10"
|
||||
Command="{Binding CustomShortcutAddCommand}"
|
||||
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
|
||||
MinHeight="160"
|
||||
Margin="0 6 0 16"
|
||||
Background="{DynamicResource Color02B}"
|
||||
BorderBrush="DarkGray"
|
||||
BorderThickness="1"
|
||||
ItemsSource="{Binding Settings.BuiltinShortcuts}"
|
||||
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
||||
<ListView.View>
|
||||
<GridView>
|
||||
<GridViewColumn Width="180" Header="{DynamicResource customShortcut}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate DataType="{x:Type userSettings:BuiltinShortcutModel}">
|
||||
<TextBlock Text="{Binding Key}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Width="430" Header="{DynamicResource builtinShortcutDescription}">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate DataType="{x:Type userSettings:BuiltinShortcutModel}">
|
||||
<TextBlock
|
||||
Text="{Binding Description, Converter={StaticResource TranslationConverter}}" />
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</cc:ExCard>
|
||||
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
23
Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPaneHotkey
|
||||
{
|
||||
private SettingsPaneHotkeyViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings })
|
||||
throw new ArgumentException("Settings are required for SettingsPaneHotkey.");
|
||||
_viewModel = new SettingsPaneHotkeyViewModel(settings);
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
}
|
||||
352
Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPanePluginStore"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:wpftk="clr-namespace:WpfToolkit.Controls;assembly=VirtualizingWrapPanel"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
Title="PluginStore"
|
||||
FocusManager.FocusedElement="{Binding ElementName=PluginStoreFilterTextbox}"
|
||||
KeyDown="SettingsPanePlugins_OnKeyDown"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsPanePluginStoreViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ui:Page.Resources>
|
||||
<CollectionViewSource x:Key="PluginStoreCollectionView" Source="{Binding ExternalPlugins}" Filter="PluginStoreCollectionView_OnFilter">
|
||||
<CollectionViewSource.GroupDescriptions>
|
||||
<PropertyGroupDescription PropertyName="Category" />
|
||||
</CollectionViewSource.GroupDescriptions>
|
||||
</CollectionViewSource>
|
||||
</ui:Page.Resources>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="72" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Border
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Padding="5 18 0 0">
|
||||
<TextBlock
|
||||
Margin="0 5"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource pluginStore}"
|
||||
TextAlignment="Left" />
|
||||
</Border>
|
||||
|
||||
<DockPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Margin="5 24 0 0">
|
||||
|
||||
<TextBox
|
||||
Name="PluginStoreFilterTextbox"
|
||||
Width="150"
|
||||
Height="34"
|
||||
Margin="0 0 26 0"
|
||||
HorizontalAlignment="Right"
|
||||
ContextMenu="{StaticResource TextBoxContextMenu}"
|
||||
DockPanel.Dock="Right"
|
||||
FontSize="14"
|
||||
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextAlignment="Left"
|
||||
ToolTip="{DynamicResource searchpluginToolTip}"
|
||||
ToolTipService.InitialShowDelay="200"
|
||||
ToolTipService.Placement="Top">
|
||||
<TextBox.Style>
|
||||
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
|
||||
<Style.Resources>
|
||||
<VisualBrush
|
||||
x:Key="CueBannerBrush"
|
||||
AlignmentX="Left"
|
||||
AlignmentY="Center"
|
||||
Stretch="None">
|
||||
<VisualBrush.Visual>
|
||||
<Label
|
||||
Padding="10 0 0 0"
|
||||
Content="{DynamicResource searchplugin}"
|
||||
Foreground="{DynamicResource CustomContextDisabled}" />
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Style.Resources>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
|
||||
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Text" Value="{x:Null}">
|
||||
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsKeyboardFocused" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource Color02B}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
<Button
|
||||
Height="34"
|
||||
Margin="0 5 10 5"
|
||||
Padding="12 4"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Command="{Binding RefreshExternalPluginsCommand}"
|
||||
Content="{DynamicResource refresh}"
|
||||
DockPanel.Dock="Right"
|
||||
FontSize="13" />
|
||||
</DockPanel>
|
||||
<ListView
|
||||
x:Name="StoreListBox"
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="2"
|
||||
Margin="4 0 0 0"
|
||||
Padding="0 0 18 0"
|
||||
FontSize="14"
|
||||
ItemContainerStyle="{StaticResource StoreList}"
|
||||
ItemsSource="{Binding Source={StaticResource PluginStoreCollectionView}}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
SelectionMode="Single"
|
||||
Style="{DynamicResource StoreListStyle}"
|
||||
VirtualizingPanel.CacheLength="1,1"
|
||||
VirtualizingPanel.CacheLengthUnit="Page"
|
||||
VirtualizingPanel.IsVirtualizingWhenGrouping="True"
|
||||
VirtualizingPanel.ScrollUnit="Pixel">
|
||||
<ListView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<wpftk:VirtualizingWrapPanel
|
||||
x:Name="ItemWrapPanel"
|
||||
Margin="0 0 0 10"
|
||||
ItemSize="216,184"
|
||||
MouseWheelDelta="48"
|
||||
Orientation="Vertical"
|
||||
ScrollLineDelta="16"
|
||||
SpacingMode="None"
|
||||
StretchItems="True" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListView.ItemsPanel>
|
||||
<ListView.GroupStyle>
|
||||
<GroupStyle HidesIfEmpty="True">
|
||||
<GroupStyle.ContainerStyle>
|
||||
<Style TargetType="{x:Type GroupItem}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Grid>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock
|
||||
Margin="2 0 0 10"
|
||||
VerticalAlignment="Top"
|
||||
FontSize="16"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding Name, Converter={StaticResource TextConverter}}" />
|
||||
<ItemsPresenter />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</GroupStyle.ContainerStyle>
|
||||
<GroupStyle.Panel>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel Orientation="{Binding Orientation, Mode=OneWay}" />
|
||||
</ItemsPanelTemplate>
|
||||
</GroupStyle.Panel>
|
||||
</GroupStyle>
|
||||
</ListView.GroupStyle>
|
||||
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<DataTemplate.Resources>
|
||||
<Style x:Key="StoreListItemBtnStyle" TargetType="Button">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border
|
||||
x:Name="Background"
|
||||
Background="{DynamicResource Color00B}"
|
||||
BorderBrush="{DynamicResource Color03B}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4"
|
||||
SnapsToDevicePixels="True">
|
||||
<Border
|
||||
x:Name="Border"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="4">
|
||||
<ContentPresenter
|
||||
x:Name="ContentPresenter"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Focusable="False"
|
||||
RecognizesAccessKey="True"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="Background" Property="Background" Value="{DynamicResource Color07B}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="Background" Property="Background" Value="{DynamicResource Color07B}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</DataTemplate.Resources>
|
||||
<Button
|
||||
Name="StoreListItem"
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
BorderThickness="0"
|
||||
FocusVisualStyle="{StaticResource StoreItemFocusVisualStyleKey}"
|
||||
Style="{DynamicResource StoreListItemBtnStyle}">
|
||||
<ui:FlyoutService.Flyout>
|
||||
<ui:Flyout x:Name="InstallFlyout" Placement="Bottom">
|
||||
<Grid MinWidth="200">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<VirtualizingStackPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Margin="5 0 0 0"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="0 0 5 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
FontWeight="Bold"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding Name}"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip="{Binding Name}" />
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding Version}"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip="{Binding Version}" />
|
||||
</VirtualizingStackPanel>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Margin="5 4 0 0"
|
||||
TextWrapping="Wrap">
|
||||
<Hyperlink Foreground="{DynamicResource Color04B}" NavigateUri="{Binding Website}" RequestNavigate="Hyperlink_OnRequestNavigate">
|
||||
<Run FontSize="12" Text="{Binding Author, Mode=OneWay}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
|
||||
<VirtualizingStackPanel
|
||||
Grid.Row="0"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
Margin="20 0 0 0"
|
||||
HorizontalAlignment="Right"
|
||||
Orientation="Horizontal">
|
||||
<Button
|
||||
MinHeight="42"
|
||||
Margin="5 0"
|
||||
Padding="15 5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Content="{DynamicResource installbtn}"
|
||||
Visibility="{Binding LabelInstalled, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter='!'}"
|
||||
Command="{Binding ShowCommandQueryCommand}"
|
||||
CommandParameter="install" />
|
||||
<Button
|
||||
MinHeight="42"
|
||||
Margin="5 0"
|
||||
Padding="15 5"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Content="{DynamicResource uninstallbtn}"
|
||||
Visibility="{Binding LabelInstalled, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Command="{Binding ShowCommandQueryCommand}"
|
||||
CommandParameter="uninstall" />
|
||||
<Button
|
||||
MinHeight="42"
|
||||
Margin="5 0"
|
||||
Padding="15 5"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Content="{DynamicResource updatebtn}"
|
||||
Style="{DynamicResource AccentButtonStyle}"
|
||||
Visibility="{Binding LabelUpdate, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||
Command="{Binding ShowCommandQueryCommand}"
|
||||
CommandParameter="update" />
|
||||
</VirtualizingStackPanel>
|
||||
</Grid>
|
||||
</ui:Flyout>
|
||||
</ui:FlyoutService.Flyout>
|
||||
<Grid>
|
||||
<StackPanel Width="200">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image
|
||||
Width="32"
|
||||
Height="32"
|
||||
Margin="18 24 0 0"
|
||||
HorizontalAlignment="Left"
|
||||
RenderOptions.BitmapScalingMode="Fant"
|
||||
Source="{Binding IcoPath, IsAsync=True}" />
|
||||
<Border
|
||||
x:Name="LabelUpdate"
|
||||
Height="12"
|
||||
Margin="10 24 0 0"
|
||||
Padding="6 2"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
Background="#45BD59"
|
||||
CornerRadius="36"
|
||||
ToolTip="{DynamicResource LabelUpdateToolTip}"
|
||||
Visibility="{Binding LabelUpdate, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
<TextBlock
|
||||
Margin="18 10 18 0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding Name}"
|
||||
TextWrapping="Wrap"
|
||||
ToolTip="{Binding Version}" />
|
||||
<TextBlock
|
||||
Height="60"
|
||||
Margin="18 6 18 0"
|
||||
Padding="0 0 0 10"
|
||||
FontSize="12"
|
||||
Foreground="{DynamicResource Color04B}"
|
||||
Text="{Binding Description, Mode=OneWay}"
|
||||
TextTrimming="WordEllipsis"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</ui:Page>
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
using Flow.Launcher.ViewModel;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPanePluginStore
|
||||
{
|
||||
private SettingsPanePluginStoreViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings })
|
||||
throw new ArgumentException($"Settings are required for {nameof(SettingsPanePluginStore)}.");
|
||||
_viewModel = new SettingsPanePluginStoreViewModel();
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
_viewModel.PropertyChanged += ViewModel_PropertyChanged;
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
|
||||
private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(SettingsPanePluginStoreViewModel.FilterText))
|
||||
{
|
||||
((CollectionViewSource)FindResource("PluginStoreCollectionView")).View.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
|
||||
{
|
||||
_viewModel.PropertyChanged -= ViewModel_PropertyChanged;
|
||||
base.OnNavigatingFrom(e);
|
||||
}
|
||||
|
||||
private void SettingsPanePlugins_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key is not Key.F || Keyboard.Modifiers is not ModifierKeys.Control) return;
|
||||
PluginStoreFilterTextbox.Focus();
|
||||
}
|
||||
|
||||
private void Hyperlink_OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
PluginManager.API.OpenUrl(e.Uri.AbsoluteUri);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void PluginStoreCollectionView_OnFilter(object sender, FilterEventArgs e)
|
||||
{
|
||||
if (e.Item is not PluginStoreItemViewModel plugin)
|
||||
{
|
||||
e.Accepted = false;
|
||||
return;
|
||||
}
|
||||
|
||||
e.Accepted = _viewModel.SatisfiesFilter(plugin);
|
||||
}
|
||||
}
|
||||
102
Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPanePlugins"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||
Title="Plugins"
|
||||
FocusManager.FocusedElement="{Binding ElementName=PluginFilterTextbox}"
|
||||
KeyDown="SettingsPanePlugins_OnKeyDown"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsPanePluginsViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<ui:Page.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
</ui:Page.Resources>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="73" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<DockPanel Grid.Row="0" Margin="5 18 0 0">
|
||||
<TextBlock
|
||||
Margin="0 5 0 0"
|
||||
DockPanel.Dock="Left"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource plugins}"
|
||||
TextAlignment="Left" />
|
||||
<TextBox
|
||||
Name="PluginFilterTextbox"
|
||||
Width="150"
|
||||
Height="34"
|
||||
Margin="0 5 26 0"
|
||||
HorizontalAlignment="Right"
|
||||
ContextMenu="{StaticResource TextBoxContextMenu}"
|
||||
DockPanel.Dock="Right"
|
||||
FontSize="14"
|
||||
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextAlignment="Left"
|
||||
ToolTip="{DynamicResource searchpluginToolTip}"
|
||||
ToolTipService.InitialShowDelay="200"
|
||||
ToolTipService.Placement="Top">
|
||||
<TextBox.Style>
|
||||
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
|
||||
<Style.Resources>
|
||||
<VisualBrush
|
||||
x:Key="CueBannerBrush"
|
||||
AlignmentX="Left"
|
||||
AlignmentY="Center"
|
||||
Stretch="None">
|
||||
<VisualBrush.Visual>
|
||||
<Label
|
||||
Padding="10 0 0 0"
|
||||
Content="{DynamicResource searchplugin}"
|
||||
Foreground="{DynamicResource CustomContextDisabled}" />
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Style.Resources>
|
||||
<Style.Triggers>
|
||||
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
|
||||
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="Text" Value="{x:Null}">
|
||||
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsKeyboardFocused" Value="True">
|
||||
<Setter Property="Background" Value="{DynamicResource Color02B}" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
</DockPanel>
|
||||
<Border Grid.Row="1" Grid.Column="0" Background="{DynamicResource Color01B}">
|
||||
<ListBox
|
||||
Margin="5 0 7 10"
|
||||
Background="{DynamicResource Color01B}"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding FilteredPluginViewModels}"
|
||||
ItemContainerStyle="{StaticResource PluginList}"
|
||||
ScrollViewer.CanContentScroll="False"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
SelectedItem="{Binding SelectedPlugin}"
|
||||
SnapsToDevicePixels="True"
|
||||
Style="{DynamicResource PluginListStyle}"
|
||||
VirtualizingPanel.ScrollUnit="Pixel"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.VirtualizationMode="Recycling">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<cc:InstalledPluginDisplay />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Border>
|
||||
</Grid>
|
||||
</ui:Page>
|
||||
30
Flow.Launcher/SettingPages/Views/SettingsPanePlugins.xaml.cs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPanePlugins
|
||||
{
|
||||
private SettingsPanePluginsViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings })
|
||||
throw new ArgumentException("Settings are required for SettingsPaneHotkey.");
|
||||
_viewModel = new SettingsPanePluginsViewModel(settings);
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
|
||||
private void SettingsPanePlugins_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key is not Key.F || Keyboard.Modifiers is not ModifierKeys.Control) return;
|
||||
PluginFilterTextbox.Focus();
|
||||
}
|
||||
}
|
||||
77
Flow.Launcher/SettingPages/Views/SettingsPaneProxy.xaml
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPaneProxy"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:cc="clr-namespace:Flow.Launcher.Resources.Controls"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
Title="Proxy"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsPaneProxyViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
<Page.Resources>
|
||||
<ResourceDictionary Source="pack://application:,,,/Resources/SettingWindowStyle.xaml" />
|
||||
</Page.Resources>
|
||||
<ScrollViewer
|
||||
Padding="5 0 24 0"
|
||||
FontSize="14"
|
||||
CanContentScroll="True"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.ScrollUnit="Pixel">
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock
|
||||
Margin="0 23 0 10"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource proxy}"
|
||||
TextAlignment="left" />
|
||||
|
||||
<cc:CardGroup>
|
||||
<cc:Card Title="{DynamicResource enableProxy}">
|
||||
<ui:ToggleSwitch IsOn="{Binding Settings.Proxy.Enabled}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource server}">
|
||||
<TextBox
|
||||
Width="300"
|
||||
IsEnabled="{Binding Settings.Proxy.Enabled}"
|
||||
Text="{Binding Settings.Proxy.Server}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource port}">
|
||||
<TextBox
|
||||
Width="100"
|
||||
IsEnabled="{Binding Settings.Proxy.Enabled}"
|
||||
Text="{Binding Settings.Proxy.Port, TargetNullValue={x:Static sys:String.Empty}}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource userName}">
|
||||
<TextBox
|
||||
Width="200"
|
||||
IsEnabled="{Binding Settings.Proxy.Enabled}"
|
||||
Text="{Binding Settings.Proxy.UserName}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Title="{DynamicResource password}">
|
||||
<TextBox
|
||||
Width="200"
|
||||
IsEnabled="{Binding Settings.Proxy.Enabled}"
|
||||
Text="{Binding Settings.Proxy.Password}" />
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<cc:Card Title="{DynamicResource testProxy}" Margin="0 8 0 0">
|
||||
<Button
|
||||
Width="150"
|
||||
Content="{DynamicResource testProxy}"
|
||||
IsEnabled="{Binding Settings.Proxy.Enabled}"
|
||||
Command="{Binding TestProxyClickedCommand}"/>
|
||||
</cc:Card>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
24
Flow.Launcher/SettingPages/Views/SettingsPaneProxy.xaml.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPaneProxy
|
||||
{
|
||||
private SettingsPaneProxyViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings, Updater: { } updater })
|
||||
throw new ArgumentException($"Settings are required for {nameof(SettingsPaneProxy)}.");
|
||||
_viewModel = new SettingsPaneProxyViewModel(settings, updater);
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
}
|
||||
492
Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
<ui:Page
|
||||
x:Class="Flow.Launcher.SettingPages.Views.SettingsPaneTheme"
|
||||
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:flowlauncher="clr-namespace:Flow.Launcher"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure"
|
||||
xmlns:viewModels="clr-namespace:Flow.Launcher.SettingPages.ViewModels"
|
||||
xmlns:ext="clr-namespace:Flow.Launcher.Resources.MarkupExtensions"
|
||||
Title="Theme"
|
||||
d:DataContext="{d:DesignInstance viewModels:SettingsPaneThemeViewModel}"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
Style="{DynamicResource SettingPageBasic}"
|
||||
mc:Ignorable="d">
|
||||
<ui:Page.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/Resources/SettingWindowStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<CollectionViewSource x:Key="SortedFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}" />
|
||||
</ResourceDictionary>
|
||||
</ui:Page.Resources>
|
||||
<ScrollViewer
|
||||
Padding="6 0 24 0"
|
||||
CanContentScroll="True"
|
||||
FontSize="14"
|
||||
VirtualizingStackPanel.IsVirtualizing="True"
|
||||
VirtualizingStackPanel.ScrollUnit="Pixel">
|
||||
<StackPanel>
|
||||
<!-- Page title -->
|
||||
<TextBlock
|
||||
Margin="5 23 0 5"
|
||||
FontSize="30"
|
||||
Style="{StaticResource PageTitle}"
|
||||
Text="{DynamicResource appearance}"
|
||||
TextAlignment="left"
|
||||
Visibility="Collapsed" />
|
||||
|
||||
<!-- Theme preview -->
|
||||
<StackPanel
|
||||
Height="350"
|
||||
Margin="0"
|
||||
Background="{Binding PreviewBackground}"
|
||||
IsHitTestVisible="False">
|
||||
<StackPanel
|
||||
Margin="0,30,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Border
|
||||
Width="{Binding WindowWidthSize}"
|
||||
Margin="0"
|
||||
SnapsToDevicePixels="True"
|
||||
Style="{DynamicResource WindowBorderStyle}"
|
||||
UseLayoutRounding="True">
|
||||
<Border Style="{DynamicResource WindowRadius}">
|
||||
<Border.Clip>
|
||||
<MultiBinding Converter="{StaticResource BorderClipConverter}">
|
||||
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}" />
|
||||
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}" />
|
||||
<Binding Path="CornerRadius" RelativeSource="{RelativeSource Self}" />
|
||||
</MultiBinding>
|
||||
</Border.Clip>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<!-- Query TextBox -->
|
||||
<TextBox
|
||||
x:Name="QueryTextBox"
|
||||
Grid.Row="0"
|
||||
IsReadOnly="True"
|
||||
Style="{DynamicResource QueryBoxStyle}"
|
||||
Text="{DynamicResource hiThere}" />
|
||||
<!-- Clock panel -->
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
Style="{DynamicResource ClockPanel}"
|
||||
Visibility="Visible">
|
||||
<!-- Clock TextBox -->
|
||||
<TextBlock
|
||||
x:Name="ClockBox"
|
||||
Style="{DynamicResource ClockBox}"
|
||||
Text="{Binding ClockText}"
|
||||
Visibility="{Binding Settings.UseClock, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
<!-- Date TextBox -->
|
||||
<TextBlock
|
||||
x:Name="DateBox"
|
||||
Style="{DynamicResource DateBox}"
|
||||
Text="{Binding DateText}"
|
||||
Visibility="{Binding Settings.UseDate, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
<Canvas Grid.Row="0" Style="{DynamicResource SearchIconPosition}">
|
||||
<Path
|
||||
Margin="0"
|
||||
Data="{DynamicResource SearchIconImg}"
|
||||
Stretch="Fill"
|
||||
Style="{DynamicResource SearchIconStyle}" />
|
||||
</Canvas>
|
||||
|
||||
<Rectangle
|
||||
Grid.Row="1"
|
||||
Width="Auto"
|
||||
HorizontalAlignment="Stretch"
|
||||
Style="{DynamicResource SeparatorStyle}"
|
||||
Visibility="Visible" />
|
||||
|
||||
<flowlauncher:ResultListBox
|
||||
Grid.Row="2"
|
||||
DataContext="{Binding PreviewResults, Mode=OneTime}"
|
||||
Visibility="Visible" />
|
||||
|
||||
</Grid>
|
||||
</Border>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Drop shadow effect -->
|
||||
<cc:Card
|
||||
Icon=""
|
||||
Title="{DynamicResource queryWindowShadowEffect}"
|
||||
Sub="{DynamicResource shadowEffectCPUUsage}"
|
||||
Margin="0 4 0 0">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding DropShadowEffect}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
<!-- Window width size -->
|
||||
<cc:Card
|
||||
Title="{DynamicResource windowWidthSize}"
|
||||
Icon=""
|
||||
Sub="{DynamicResource windowWidthSizeToolTip}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Width="Auto"
|
||||
Margin="0 0 8 2"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{DynamicResource Color05B}"
|
||||
Text="{Binding WindowWidthSize}"
|
||||
TextAlignment="Right" />
|
||||
<Slider
|
||||
Width="250"
|
||||
VerticalAlignment="Center"
|
||||
IsMoveToPointEnabled="True"
|
||||
IsSnapToTickEnabled="True"
|
||||
Maximum="1920"
|
||||
Minimum="400"
|
||||
TickFrequency="10"
|
||||
Value="{Binding WindowWidthSize}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<!-- Theme -->
|
||||
<Border
|
||||
Height="64"
|
||||
Margin="0 8 0 0"
|
||||
CornerRadius="5 5 0 0"
|
||||
Style="{DynamicResource SettingGroupBox}">
|
||||
<ItemsControl Style="{StaticResource SettingGrid}">
|
||||
<StackPanel Style="{StaticResource TextPanel}">
|
||||
<TextBlock Style="{DynamicResource SettingTitleLabel}" Text="{DynamicResource theme}" />
|
||||
</StackPanel>
|
||||
<TextBlock Style="{StaticResource Glyph}">
|
||||

|
||||
</TextBlock>
|
||||
</ItemsControl>
|
||||
</Border>
|
||||
|
||||
<Border
|
||||
Margin="0"
|
||||
Padding="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderThickness="1 0 1 1"
|
||||
CornerRadius="0 0 5 5"
|
||||
Style="{DynamicResource SettingGroupBox}">
|
||||
<ListBox
|
||||
Margin="12"
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalContentAlignment="Center"
|
||||
ui:ScrollViewerHelper.AutoHideScrollBars="True"
|
||||
Background="#ffffff"
|
||||
ItemsSource="{Binding Themes}"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Disabled"
|
||||
SelectedItem="{Binding SelectedTheme}">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
<Setter Property="HorizontalContentAlignment"
|
||||
Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
|
||||
<Setter Property="VerticalContentAlignment"
|
||||
Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
|
||||
<Setter Property="Padding" Value="0" />
|
||||
<Setter Property="Margin" Value="4" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ListBoxItem}">
|
||||
<Border
|
||||
x:Name="Bd"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Background="{DynamicResource Color12B}"
|
||||
BorderBrush="{DynamicResource Color03B}"
|
||||
BorderThickness="1 1 1 0"
|
||||
CornerRadius="4"
|
||||
SnapsToDevicePixels="true">
|
||||
<Border
|
||||
x:Name="Bd2"
|
||||
BorderBrush="{DynamicResource Color14B}"
|
||||
BorderThickness="0 0 0 2"
|
||||
CornerRadius="4">
|
||||
<ContentPresenter
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
||||
</Border>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="true">
|
||||
<Setter TargetName="Bd" Property="Background"
|
||||
Value="{DynamicResource ThemeHoverButton}" />
|
||||
</Trigger>
|
||||
<Trigger Property="IsSelected" Value="true">
|
||||
<Setter TargetName="Bd" Property="Background"
|
||||
Value="{DynamicResource ToggleSwitchFillOn}" />
|
||||
<Setter TargetName="Bd2" Property="BorderThickness" Value="0" />
|
||||
<Setter TargetName="Bd2" Property="TextElement.Foreground"
|
||||
Value="{DynamicResource Color02B}" />
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
<ListBox.Template>
|
||||
<!-- For Scroll Wheel inside listbox area -->
|
||||
<ControlTemplate>
|
||||
<ItemsPresenter />
|
||||
</ControlTemplate>
|
||||
</ListBox.Template>
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid
|
||||
Width="Auto"
|
||||
Height="34"
|
||||
Margin="0">
|
||||
<TextBlock
|
||||
x:Name="ThemeName"
|
||||
Margin="0"
|
||||
Padding="14 12"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Focusable="True"
|
||||
FontSize="12"
|
||||
Text="{Binding}"
|
||||
TextWrapping="Wrap" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
</ListBox>
|
||||
|
||||
</Border>
|
||||
|
||||
<cc:HyperLink
|
||||
Margin="10"
|
||||
HorizontalAlignment="Right"
|
||||
Uri="{Binding LinkThemeGallery}"
|
||||
Text="{DynamicResource browserMoreThemes}" />
|
||||
|
||||
|
||||
<!-- Fonts and icons -->
|
||||
<cc:CardGroup Margin="0 30 0 0">
|
||||
<cc:Card Icon="" Title="{DynamicResource useGlyphUI}"
|
||||
Sub="{DynamicResource useGlyphUIEffect}">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding UseGlyphIcons}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Icon="" Title="{DynamicResource queryBoxFont}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ComboBox
|
||||
Width="180"
|
||||
IsSynchronizedWithCurrentItem="False"
|
||||
ItemsSource="{Binding Source={StaticResource SortedFonts}}"
|
||||
SelectedItem="{Binding SelectedQueryBoxFont}" />
|
||||
<ComboBox
|
||||
Width="130"
|
||||
Margin="10 0 0 0"
|
||||
ItemsSource="{Binding SelectedQueryBoxFont.FamilyTypefaces}"
|
||||
SelectedItem="{Binding SelectedQueryBoxFontFaces}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ItemsControl ItemsSource="{Binding AdjustedFaceNames}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Value}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Icon="" Title="{DynamicResource resultItemFont}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ComboBox
|
||||
Width="180"
|
||||
IsSynchronizedWithCurrentItem="False"
|
||||
ItemsSource="{Binding Source={StaticResource SortedFonts}}"
|
||||
SelectedItem="{Binding SelectedResultFont}" />
|
||||
<ComboBox
|
||||
Width="130"
|
||||
Margin="10 0 0 0"
|
||||
ItemsSource="{Binding SelectedResultFont.FamilyTypefaces}"
|
||||
SelectedItem="{Binding SelectedResultFontFaces}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ItemsControl ItemsSource="{Binding AdjustedFaceNames}">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Value}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<!-- Time and date -->
|
||||
<cc:CardGroup Margin="0 24 0 0">
|
||||
<cc:Card Icon="" Title="{DynamicResource Clock}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource Color04B}"
|
||||
Text="{Binding ClockText}" />
|
||||
<ComboBox
|
||||
MinWidth="180"
|
||||
Margin="10 0 18 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding TimeFormatList}"
|
||||
SelectedItem="{Binding TimeFormat}" />
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding UseClock}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
|
||||
<cc:Card Icon="" Title="{DynamicResource Date}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Foreground="{DynamicResource Color04B}"
|
||||
Text="{Binding DateText}" />
|
||||
<ComboBox
|
||||
MinWidth="180"
|
||||
Margin="10 0 18 0"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding DateFormatList}"
|
||||
SelectedItem="{Binding DateFormat}" />
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding UseDate}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<!-- Animation -->
|
||||
<cc:CardGroup Margin="0 11 0 0">
|
||||
<cc:Card
|
||||
Icon=""
|
||||
Title="{DynamicResource Animation}"
|
||||
Sub="{DynamicResource AnimationTip}">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding UseAnimation}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
<cc:Card
|
||||
Icon=""
|
||||
Title="{DynamicResource AnimationSpeed}"
|
||||
Sub="{DynamicResource AnimationSpeedTip}"
|
||||
Visibility="{Binding UseAnimation, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<ComboBox
|
||||
MinWidth="160"
|
||||
VerticalAlignment="Center"
|
||||
DisplayMemberPath="Display"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding AnimationSpeeds}"
|
||||
SelectedValue="{Binding Settings.AnimationSpeed}"
|
||||
SelectedValuePath="Value" />
|
||||
|
||||
<TextBox
|
||||
Margin="18 0 0 0"
|
||||
MinWidth="80"
|
||||
Text="{Binding Settings.CustomAnimationLength}"
|
||||
TextWrapping="NoWrap"
|
||||
Visibility="{ext:VisibleWhen
|
||||
{Binding Settings.AnimationSpeed},
|
||||
IsEqualTo={x:Static userSettings:AnimationSpeeds.Custom}}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<!-- SFX -->
|
||||
<cc:CardGroup Margin="0 11 0 0">
|
||||
<cc:Card Icon="" Title="{DynamicResource SoundEffect}"
|
||||
Sub="{DynamicResource SoundEffectTip}">
|
||||
<ui:ToggleSwitch
|
||||
IsOn="{Binding UseSound}"
|
||||
OffContent="{DynamicResource disable}"
|
||||
OnContent="{DynamicResource enable}" />
|
||||
</cc:Card>
|
||||
<cc:Card Icon="" Title="{DynamicResource SoundEffectVolume}"
|
||||
Sub="{DynamicResource SoundEffectVolumeTip}"
|
||||
Visibility="{Binding UseSound, Converter={StaticResource BoolToVisibilityConverter}}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock
|
||||
Margin="0 0 8 0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding SoundEffectVolume}" />
|
||||
|
||||
<Slider
|
||||
Width="250"
|
||||
VerticalAlignment="Center"
|
||||
IsMoveToPointEnabled="True"
|
||||
IsSnapToTickEnabled="True"
|
||||
Maximum="100"
|
||||
Minimum="0"
|
||||
TickFrequency="1"
|
||||
Value="{Binding SoundEffectVolume}" />
|
||||
</StackPanel>
|
||||
</cc:Card>
|
||||
</cc:CardGroup>
|
||||
|
||||
<!-- Settings color scheme -->
|
||||
<cc:Card Icon="" Title="{DynamicResource ColorScheme}" Margin="0 11 0 0">
|
||||
<ComboBox
|
||||
MinWidth="180"
|
||||
DisplayMemberPath="Display"
|
||||
FontSize="14"
|
||||
ItemsSource="{Binding ColorSchemes}"
|
||||
SelectedValue="{Binding Settings.ColorScheme}"
|
||||
SelectedValuePath="Value"
|
||||
SelectionChanged="Selector_OnSelectionChanged"/>
|
||||
</cc:Card>
|
||||
|
||||
<!-- Theme folder -->
|
||||
<cc:Card Icon="" Title="{DynamicResource ThemeFolder}">
|
||||
<Button
|
||||
MinWidth="180"
|
||||
Command="{Binding OpenThemesFolderCommand}"
|
||||
Content="{DynamicResource OpenThemeFolder}" />
|
||||
</cc:Card>
|
||||
|
||||
<!-- How to create theme link -->
|
||||
<cc:HyperLink
|
||||
Margin="10 10 10 28"
|
||||
HorizontalAlignment="Right"
|
||||
Uri="{Binding LinkHowToCreateTheme}"
|
||||
Text="{DynamicResource howToCreateTheme}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</ui:Page>
|
||||
31
Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Navigation;
|
||||
using Flow.Launcher.SettingPages.ViewModels;
|
||||
using Page = ModernWpf.Controls.Page;
|
||||
|
||||
namespace Flow.Launcher.SettingPages.Views;
|
||||
|
||||
public partial class SettingsPaneTheme : Page
|
||||
{
|
||||
private SettingsPaneThemeViewModel _viewModel = null!;
|
||||
|
||||
protected override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
if (e.ExtraData is not SettingWindow.PaneData { Settings: { } settings })
|
||||
throw new ArgumentException($"Settings are required for {nameof(SettingsPaneTheme)}.");
|
||||
_viewModel = new SettingsPaneThemeViewModel(settings);
|
||||
DataContext = _viewModel;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
base.OnNavigatedTo(e);
|
||||
}
|
||||
|
||||
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
_viewModel.UpdateColorScheme();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,515 +1,172 @@
|
|||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.ViewModel;
|
||||
using ModernWpf;
|
||||
using ModernWpf.Controls;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
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;
|
||||
using MessageBox = System.Windows.MessageBox;
|
||||
using Flow.Launcher.Core;
|
||||
using Flow.Launcher.Core.Configuration;
|
||||
using Flow.Launcher.Helper;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.SettingPages.Views;
|
||||
using Flow.Launcher.ViewModel;
|
||||
using ModernWpf.Controls;
|
||||
using TextBox = System.Windows.Controls.TextBox;
|
||||
using ThemeManager = ModernWpf.ThemeManager;
|
||||
|
||||
namespace Flow.Launcher
|
||||
namespace Flow.Launcher;
|
||||
|
||||
public partial class SettingWindow
|
||||
{
|
||||
public partial class SettingWindow
|
||||
private readonly IPublicAPI _api;
|
||||
private readonly Settings _settings;
|
||||
private readonly SettingWindowViewModel _viewModel;
|
||||
|
||||
public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)
|
||||
{
|
||||
public readonly IPublicAPI API;
|
||||
private Settings settings;
|
||||
private SettingWindowViewModel viewModel;
|
||||
_settings = viewModel.Settings;
|
||||
DataContext = viewModel;
|
||||
_viewModel = viewModel;
|
||||
_api = api;
|
||||
InitializePosition();
|
||||
InitializeComponent();
|
||||
NavView.SelectedItem = NavView.MenuItems[0]; /* Set First Page */
|
||||
}
|
||||
|
||||
public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
// Fix (workaround) for the window freezes after lock screen (Win+L)
|
||||
// https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf
|
||||
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
|
||||
HwndTarget hwndTarget = hwndSource.CompositionTarget;
|
||||
hwndTarget.RenderMode = RenderMode.Default;
|
||||
|
||||
InitializePosition();
|
||||
}
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
_settings.SettingWindowState = WindowState;
|
||||
_settings.SettingWindowTop = Top;
|
||||
_settings.SettingWindowLeft = Left;
|
||||
_viewModel.Save();
|
||||
_api.SavePluginSettings();
|
||||
}
|
||||
|
||||
private void OnCloseExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
|
||||
{
|
||||
if (Keyboard.FocusedElement is not TextBox textBox)
|
||||
{
|
||||
settings = viewModel.Settings;
|
||||
DataContext = viewModel;
|
||||
this.viewModel = viewModel;
|
||||
API = api;
|
||||
InitializePosition();
|
||||
InitializeComponent();
|
||||
return;
|
||||
}
|
||||
var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
textBox.MoveFocus(tRequest);
|
||||
}
|
||||
|
||||
#region General
|
||||
/* Custom TitleBar */
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
private void OnMinimizeButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void OnMaximizeRestoreButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState switch
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
// Fix (workaround) for the window freezes after lock screen (Win+L)
|
||||
// https://stackoverflow.com/questions/4951058/software-rendering-mode-wpf
|
||||
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
|
||||
HwndTarget hwndTarget = hwndSource.CompositionTarget;
|
||||
hwndTarget.RenderMode = RenderMode.SoftwareOnly;
|
||||
WindowState.Maximized => WindowState.Normal,
|
||||
_ => WindowState.Maximized
|
||||
};
|
||||
}
|
||||
|
||||
pluginListView = (CollectionView)CollectionViewSource.GetDefaultView(Plugins.ItemsSource);
|
||||
pluginListView.Filter = PluginListFilter;
|
||||
private void OnCloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
pluginStoreView = (CollectionView)CollectionViewSource.GetDefaultView(StoreListBox.ItemsSource);
|
||||
pluginStoreView.Filter = PluginStoreFilter;
|
||||
|
||||
viewModel.PropertyChanged += new PropertyChangedEventHandler(SettingsWindowViewModelChanged);
|
||||
|
||||
CheckMediaPlayer();
|
||||
InitializePosition();
|
||||
}
|
||||
|
||||
private void CheckMediaPlayer()
|
||||
private void RefreshMaximizeRestoreButton()
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
if (settings.WMPInstalled)
|
||||
{
|
||||
WMPWarning.Visibility = Visibility.Visible;
|
||||
VolumeAdjustCard.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
MaximizeButton.Visibility = Visibility.Collapsed;
|
||||
RestoreButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
private void SettingsWindowViewModelChanged(object sender, PropertyChangedEventArgs e)
|
||||
else
|
||||
{
|
||||
if (e.PropertyName == nameof(viewModel.ExternalPlugins))
|
||||
{
|
||||
pluginStoreView = (CollectionView)CollectionViewSource.GetDefaultView(StoreListBox.ItemsSource);
|
||||
pluginStoreView.Filter = PluginStoreFilter;
|
||||
pluginStoreView.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectPythonPathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedFile = viewModel.GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectPythonExecutable"),
|
||||
"Python|pythonw.exe");
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
settings.PluginSettings.PythonExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
private void OnSelectNodePathClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedFile = viewModel.GetFileFromDialog(
|
||||
InternationalizationManager.Instance.GetTranslation("selectNodeExecutable"));
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedFile))
|
||||
settings.PluginSettings.NodeExecutablePath = selectedFile;
|
||||
}
|
||||
|
||||
private void OnSelectFileManagerClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SelectFileManagerWindow fileManagerChangeWindow = new SelectFileManagerWindow(settings);
|
||||
fileManagerChangeWindow.ShowDialog();
|
||||
}
|
||||
|
||||
private void OnSelectDefaultBrowserClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var browserWindow = new SelectBrowserWindow(settings);
|
||||
browserWindow.ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Hotkey
|
||||
|
||||
private void OnToggleHotkey(object sender, HotkeyEventArgs e)
|
||||
{
|
||||
HotKeyMapper.OnToggleHotkey(sender, e);
|
||||
}
|
||||
|
||||
private void OnDeleteCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = viewModel.SelectedCustomPluginHotkey;
|
||||
if (item == null)
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
return;
|
||||
}
|
||||
|
||||
string deleteWarning =
|
||||
string.Format(InternationalizationManager.Instance.GetTranslation("deleteCustomHotkeyWarning"),
|
||||
item.Hotkey);
|
||||
if (
|
||||
MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
settings.CustomPluginHotkeys.Remove(item);
|
||||
HotKeyMapper.RemoveHotkey(item.Hotkey);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var item = viewModel.SelectedCustomPluginHotkey;
|
||||
if (item != null)
|
||||
{
|
||||
CustomQueryHotkeySetting window = new CustomQueryHotkeySetting(this, settings);
|
||||
window.UpdateItem(item);
|
||||
window.ShowDialog();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddCustomHotkeyClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
new CustomQueryHotkeySetting(this, settings).ShowDialog();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Plugin
|
||||
|
||||
private void OnPluginToggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var id = viewModel.SelectedPlugin.PluginPair.Metadata.ID;
|
||||
// used to sync the current status from the plugin manager into the setting to keep consistency after save
|
||||
settings.PluginSettings.Plugins[id].Disabled = viewModel.SelectedPlugin.PluginPair.Metadata.Disabled;
|
||||
}
|
||||
|
||||
private void OnPluginPriorityClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is Control { DataContext: PluginViewModel pluginViewModel })
|
||||
{
|
||||
PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(pluginViewModel.PluginPair.Metadata.ID, pluginViewModel);
|
||||
priorityChangeWindow.ShowDialog();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Proxy
|
||||
|
||||
private void OnTestProxyClick(object sender, RoutedEventArgs e)
|
||||
{ // TODO: change to command
|
||||
var msg = viewModel.TestProxy();
|
||||
MessageBox.Show(msg); // TODO: add message box service
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void OnCheckUpdates(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.UpdateApp(); // TODO: change to command
|
||||
}
|
||||
|
||||
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
API.OpenUrl(e.Uri.AbsoluteUri);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void OnClosed(object sender, EventArgs e)
|
||||
{
|
||||
settings.SettingWindowState = WindowState;
|
||||
settings.SettingWindowTop = Top;
|
||||
settings.SettingWindowLeft = Left;
|
||||
viewModel.Save();
|
||||
API.SavePluginSettings();
|
||||
}
|
||||
|
||||
private void OnCloseExecuted(object sender, ExecutedRoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OpenThemeFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PluginManager.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
|
||||
}
|
||||
|
||||
private void OpenSettingFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
PluginManager.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Settings));
|
||||
}
|
||||
|
||||
private void OpenWelcomeWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var WelcomeWindow = new WelcomeWindow(settings);
|
||||
WelcomeWindow.ShowDialog();
|
||||
}
|
||||
private void OpenLogFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.OpenLogFolder();
|
||||
}
|
||||
private void ClearLogFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var confirmResult = MessageBox.Show(
|
||||
InternationalizationManager.Instance.GetTranslation("clearlogfolderMessage"),
|
||||
InternationalizationManager.Instance.GetTranslation("clearlogfolder"),
|
||||
MessageBoxButton.YesNo);
|
||||
|
||||
if (confirmResult == MessageBoxResult.Yes)
|
||||
{
|
||||
viewModel.ClearLogFolder();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExternalPluginInstallClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button { DataContext: PluginStoreItemViewModel plugin } button)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (storeClickedButton != null)
|
||||
{
|
||||
FlyoutService.GetFlyout(storeClickedButton).Hide();
|
||||
}
|
||||
|
||||
viewModel.DisplayPluginQuery($"install {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
}
|
||||
|
||||
private void OnExternalPluginUninstallClick(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
{
|
||||
var name = viewModel.SelectedPlugin.PluginPair.Metadata.Name;
|
||||
viewModel.DisplayPluginQuery($"uninstall {name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExternalPluginUninstallClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (storeClickedButton != null)
|
||||
{
|
||||
FlyoutService.GetFlyout(storeClickedButton).Hide();
|
||||
}
|
||||
|
||||
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
|
||||
viewModel.DisplayPluginQuery($"uninstall {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
|
||||
}
|
||||
|
||||
private void OnExternalPluginUpdateClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (storeClickedButton != null)
|
||||
{
|
||||
FlyoutService.GetFlyout(storeClickedButton).Hide();
|
||||
}
|
||||
if (sender is Button { DataContext: PluginStoreItemViewModel plugin })
|
||||
viewModel.DisplayPluginQuery($"update {plugin.Name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
|
||||
|
||||
}
|
||||
|
||||
private void window_MouseDown(object sender, MouseButtonEventArgs e) /* for close hotkey popup */
|
||||
{
|
||||
if (Keyboard.FocusedElement is not TextBox textBox)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
|
||||
textBox.MoveFocus(tRequest);
|
||||
}
|
||||
|
||||
private void ColorSchemeSelectedIndexChanged(object sender, EventArgs e)
|
||||
=> ThemeManager.Current.ApplicationTheme = settings.ColorScheme switch
|
||||
{
|
||||
Constant.Light => ApplicationTheme.Light,
|
||||
Constant.Dark => ApplicationTheme.Dark,
|
||||
Constant.System => null,
|
||||
_ => ThemeManager.Current.ApplicationTheme
|
||||
};
|
||||
|
||||
/* Custom TitleBar */
|
||||
|
||||
private void OnMinimizeButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void OnMaximizeRestoreButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
|
||||
}
|
||||
|
||||
private void OnCloseButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
private void RefreshMaximizeRestoreButton()
|
||||
{
|
||||
if (WindowState == WindowState.Maximized)
|
||||
{
|
||||
maximizeButton.Visibility = Visibility.Collapsed;
|
||||
restoreButton.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
maximizeButton.Visibility = Visibility.Visible;
|
||||
restoreButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
}
|
||||
|
||||
#region Shortcut
|
||||
|
||||
private void OnDeleteCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.DeleteSelectedCustomShortcut();
|
||||
}
|
||||
|
||||
private void OnEditCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (viewModel.EditSelectedCustomShortcut())
|
||||
{
|
||||
//customShortcutView.Items.Refresh(); Should Fix
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddCustomShortCutClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
viewModel.AddCustomShortcut();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private CollectionView pluginListView;
|
||||
private CollectionView pluginStoreView;
|
||||
|
||||
private bool PluginListFilter(object item)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pluginFilterTxb.Text))
|
||||
return true;
|
||||
if (item is PluginViewModel model)
|
||||
{
|
||||
return StringMatcher.FuzzySearch(pluginFilterTxb.Text, model.PluginPair.Metadata.Name).IsSearchPrecisionScoreMet();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool PluginStoreFilter(object item)
|
||||
{
|
||||
if (string.IsNullOrEmpty(pluginStoreFilterTxb.Text))
|
||||
return true;
|
||||
if (item is PluginStoreItemViewModel model)
|
||||
{
|
||||
return StringMatcher.FuzzySearch(pluginStoreFilterTxb.Text, model.Name).IsSearchPrecisionScoreMet()
|
||||
|| StringMatcher.FuzzySearch(pluginStoreFilterTxb.Text, model.Description).IsSearchPrecisionScoreMet();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private string lastPluginListSearch = "";
|
||||
private string lastPluginStoreSearch = "";
|
||||
|
||||
private void RefreshPluginListEventHandler(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (pluginFilterTxb.Text != lastPluginListSearch)
|
||||
{
|
||||
lastPluginListSearch = pluginFilterTxb.Text;
|
||||
pluginListView.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshPluginStoreEventHandler(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (pluginStoreFilterTxb.Text != lastPluginStoreSearch)
|
||||
{
|
||||
lastPluginStoreSearch = pluginStoreFilterTxb.Text;
|
||||
pluginStoreView.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private void PluginFilterTxb_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
RefreshPluginListEventHandler(sender, e);
|
||||
}
|
||||
|
||||
private void PluginStoreFilterTxb_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
RefreshPluginStoreEventHandler(sender, e);
|
||||
}
|
||||
|
||||
private void OnPluginSettingKeydown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control && e.Key == Key.F)
|
||||
pluginFilterTxb.Focus();
|
||||
}
|
||||
|
||||
private void PluginStore_OnKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.F && (Keyboard.Modifiers & ModifierKeys.Control) != 0)
|
||||
{
|
||||
pluginStoreFilterTxb.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
public void InitializePosition()
|
||||
{
|
||||
if (settings.SettingWindowTop >= 0 && settings.SettingWindowLeft >= 0)
|
||||
{
|
||||
Top = settings.SettingWindowTop;
|
||||
Left = settings.SettingWindowLeft;
|
||||
}
|
||||
else
|
||||
{
|
||||
Top = WindowTop();
|
||||
Left = WindowLeft();
|
||||
}
|
||||
WindowState = settings.SettingWindowState;
|
||||
}
|
||||
|
||||
public double WindowLeft()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
|
||||
var left = (dip2.X - this.ActualWidth) / 2 + dip1.X;
|
||||
return left;
|
||||
}
|
||||
|
||||
public double WindowTop()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
|
||||
var top = (dip2.Y - this.ActualHeight) / 2 + dip1.Y - 20;
|
||||
return top;
|
||||
}
|
||||
|
||||
private Button storeClickedButton;
|
||||
|
||||
private void StoreListItem_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button button)
|
||||
return;
|
||||
|
||||
storeClickedButton = button;
|
||||
|
||||
var flyout = FlyoutService.GetFlyout(button);
|
||||
flyout.Closed += (_, _) =>
|
||||
{
|
||||
storeClickedButton = null;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private void PluginStore_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Keyboard.Focus(pluginStoreFilterTxb);
|
||||
}
|
||||
|
||||
private void Plugin_GotFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Keyboard.Focus(pluginFilterTxb);
|
||||
MaximizeButton.Visibility = Visibility.Visible;
|
||||
RestoreButton.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_StateChanged(object sender, EventArgs e)
|
||||
{
|
||||
RefreshMaximizeRestoreButton();
|
||||
}
|
||||
|
||||
public void InitializePosition()
|
||||
{
|
||||
if (_settings.SettingWindowTop == null)
|
||||
{
|
||||
Top = WindowTop();
|
||||
Left = WindowLeft();
|
||||
}
|
||||
else
|
||||
{
|
||||
Top = _settings.SettingWindowTop;
|
||||
Left = _settings.SettingWindowLeft;
|
||||
}
|
||||
WindowState = _settings.SettingWindowState;
|
||||
}
|
||||
|
||||
private double WindowLeft()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
|
||||
var left = (dip2.X - this.ActualWidth) / 2 + dip1.X;
|
||||
return left;
|
||||
}
|
||||
|
||||
private double WindowTop()
|
||||
{
|
||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
|
||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
|
||||
var top = (dip2.Y - this.ActualHeight) / 2 + dip1.Y - 20;
|
||||
return top;
|
||||
}
|
||||
|
||||
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
|
||||
{
|
||||
var paneData = new PaneData(_settings, _viewModel.Updater, _viewModel.Portable);
|
||||
if (args.IsSettingsSelected)
|
||||
{
|
||||
ContentFrame.Navigate(typeof(SettingsPaneGeneral), paneData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedItem = (NavigationViewItem)args.SelectedItem;
|
||||
if (selectedItem == null) return;
|
||||
|
||||
var pageType = selectedItem.Name switch
|
||||
{
|
||||
nameof(General) => typeof(SettingsPaneGeneral),
|
||||
nameof(Plugins) => typeof(SettingsPanePlugins),
|
||||
nameof(PluginStore) => typeof(SettingsPanePluginStore),
|
||||
nameof(Theme) => typeof(SettingsPaneTheme),
|
||||
nameof(Hotkey) => typeof(SettingsPaneHotkey),
|
||||
nameof(Proxy) => typeof(SettingsPaneProxy),
|
||||
nameof(About) => typeof(SettingsPaneAbout),
|
||||
_ => typeof(SettingsPaneGeneral)
|
||||
};
|
||||
ContentFrame.Navigate(pageType, paneData);
|
||||
}
|
||||
}
|
||||
|
||||
public record PaneData(Settings Settings, Updater Updater, IPortable Portable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ namespace Flow.Launcher.ViewModel
|
|||
private readonly FlowLauncherJsonStorage<UserSelectedRecord> _userSelectedRecordStorage;
|
||||
private readonly FlowLauncherJsonStorage<TopMostRecord> _topMostRecordStorage;
|
||||
private readonly History _history;
|
||||
private int lastHistoryIndex = 1;
|
||||
private readonly UserSelectedRecord _userSelectedRecord;
|
||||
private readonly TopMostRecord _topMostRecord;
|
||||
|
||||
|
|
@ -83,6 +84,12 @@ namespace Flow.Launcher.ViewModel
|
|||
case nameof(Settings.AutoCompleteHotkey):
|
||||
OnPropertyChanged(nameof(AutoCompleteHotkey));
|
||||
break;
|
||||
case nameof(Settings.CycleHistoryUpHotkey):
|
||||
OnPropertyChanged(nameof(CycleHistoryUpHotkey));
|
||||
break;
|
||||
case nameof(Settings.CycleHistoryDownHotkey):
|
||||
OnPropertyChanged(nameof(CycleHistoryDownHotkey));
|
||||
break;
|
||||
case nameof(Settings.AutoCompleteHotkey2):
|
||||
OnPropertyChanged(nameof(AutoCompleteHotkey2));
|
||||
break;
|
||||
|
|
@ -256,6 +263,32 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void ReverseHistory()
|
||||
{
|
||||
if (_history.Items.Count > 0)
|
||||
{
|
||||
ChangeQueryText(_history.Items[_history.Items.Count - lastHistoryIndex].Query.ToString());
|
||||
if (lastHistoryIndex < _history.Items.Count)
|
||||
{
|
||||
lastHistoryIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
public void ForwardHistory()
|
||||
{
|
||||
if (_history.Items.Count > 0)
|
||||
{
|
||||
ChangeQueryText(_history.Items[_history.Items.Count - lastHistoryIndex].Query.ToString());
|
||||
if (lastHistoryIndex > 1)
|
||||
{
|
||||
lastHistoryIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void LoadContextMenu()
|
||||
{
|
||||
|
|
@ -346,6 +379,7 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
_userSelectedRecord.Add(result);
|
||||
_history.Add(result.OriginQuery.RawQuery);
|
||||
lastHistoryIndex = 1;
|
||||
}
|
||||
|
||||
if (hideWindow)
|
||||
|
|
@ -394,7 +428,18 @@ namespace Flow.Launcher.ViewModel
|
|||
[RelayCommand]
|
||||
private void SelectPrevItem()
|
||||
{
|
||||
SelectedResults.SelectPrevResult();
|
||||
if (_history.Items.Count > 0
|
||||
&& QueryText == string.Empty
|
||||
&& SelectedIsFromQueryResults())
|
||||
{
|
||||
lastHistoryIndex = 1;
|
||||
ReverseHistory();
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedResults.SelectPrevResult();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
|
|
@ -690,6 +735,8 @@ namespace Flow.Launcher.ViewModel
|
|||
public string SelectPrevPageHotkey => VerifyOrSetDefaultHotkey(Settings.SelectPrevPageHotkey, "");
|
||||
public string OpenContextMenuHotkey => VerifyOrSetDefaultHotkey(Settings.OpenContextMenuHotkey, "Ctrl+O");
|
||||
public string SettingWindowHotkey => VerifyOrSetDefaultHotkey(Settings.SettingWindowHotkey, "Ctrl+I");
|
||||
public string CycleHistoryUpHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryUpHotkey, "Alt+Up");
|
||||
public string CycleHistoryDownHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryDownHotkey, "Alt+Down");
|
||||
|
||||
|
||||
public string Image => Constant.QueryTextBoxIconImagePath;
|
||||
|
|
@ -1116,6 +1163,7 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
public async void Hide()
|
||||
{
|
||||
lastHistoryIndex = 1;
|
||||
// Trick for no delay
|
||||
MainWindowOpacity = 0;
|
||||
lastContextMenuResult = new Result();
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.ViewModel
|
||||
{
|
||||
public class PluginStoreItemViewModel : BaseModel
|
||||
public partial class PluginStoreItemViewModel : BaseModel
|
||||
{
|
||||
private PluginPair PluginManagerData => PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7");
|
||||
public PluginStoreItemViewModel(UserPlugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
|
|
@ -26,19 +29,13 @@ namespace Flow.Launcher.ViewModel
|
|||
public string IcoPath => _plugin.IcoPath;
|
||||
|
||||
public bool LabelInstalled => PluginManager.GetPluginForId(_plugin.ID) != null;
|
||||
public bool LabelUpdate => LabelInstalled && VersionConvertor(_plugin.Version) > VersionConvertor(PluginManager.GetPluginForId(_plugin.ID).Metadata.Version);
|
||||
public bool LabelUpdate => LabelInstalled && new Version(_plugin.Version) > new Version(PluginManager.GetPluginForId(_plugin.ID).Metadata.Version);
|
||||
|
||||
internal const string None = "None";
|
||||
internal const string RecentlyUpdated = "RecentlyUpdated";
|
||||
internal const string NewRelease = "NewRelease";
|
||||
internal const string Installed = "Installed";
|
||||
|
||||
public Version VersionConvertor(string version)
|
||||
{
|
||||
Version ResultVersion = new Version(version);
|
||||
return ResultVersion;
|
||||
}
|
||||
|
||||
public string Category
|
||||
{
|
||||
get
|
||||
|
|
@ -60,5 +57,13 @@ namespace Flow.Launcher.ViewModel
|
|||
return category;
|
||||
}
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void ShowCommandQuery(string action)
|
||||
{
|
||||
var actionKeyword = PluginManagerData.Metadata.ActionKeywords.Any() ? PluginManagerData.Metadata.ActionKeywords[0] + " " : String.Empty;
|
||||
App.API.ChangeQuery($"{actionKeyword}{action} {_plugin.Name}");
|
||||
App.API.ShowMainWindow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Windows;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Infrastructure.Image;
|
||||
|
|
@ -26,6 +27,21 @@ namespace Flow.Launcher.ViewModel
|
|||
}
|
||||
}
|
||||
|
||||
private string PluginManagerActionKeyword
|
||||
{
|
||||
get
|
||||
{
|
||||
var keyword = PluginManager
|
||||
.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7")
|
||||
.Metadata.ActionKeywords.FirstOrDefault();
|
||||
return keyword switch
|
||||
{
|
||||
null or "*" => string.Empty,
|
||||
_ => keyword
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async void LoadIconAsync()
|
||||
{
|
||||
|
|
@ -46,7 +62,11 @@ namespace Flow.Launcher.ViewModel
|
|||
public bool PluginState
|
||||
{
|
||||
get => !PluginPair.Metadata.Disabled;
|
||||
set => PluginPair.Metadata.Disabled = !value;
|
||||
set
|
||||
{
|
||||
PluginPair.Metadata.Disabled = !value;
|
||||
PluginSettingsObject.Disabled = !value;
|
||||
}
|
||||
}
|
||||
public bool IsExpanded
|
||||
{
|
||||
|
|
@ -62,11 +82,13 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
private Control _settingControl;
|
||||
private bool _isExpanded;
|
||||
|
||||
public bool HasSettingControl => PluginPair.Plugin is ISettingProvider;
|
||||
public Control SettingControl
|
||||
=> IsExpanded
|
||||
? _settingControl
|
||||
??= PluginPair.Plugin is not ISettingProvider settingProvider
|
||||
? new Control()
|
||||
? null
|
||||
: settingProvider.CreateSettingPanel()
|
||||
: null;
|
||||
private ImageSource _image = ImageLoader.MissingImage;
|
||||
|
|
@ -78,6 +100,7 @@ namespace Flow.Launcher.ViewModel
|
|||
public string InitAndQueryTime => InternationalizationManager.Instance.GetTranslation("plugin_init_time") + " " + PluginPair.Metadata.InitTime + "ms, " + InternationalizationManager.Instance.GetTranslation("plugin_query_time") + " " + PluginPair.Metadata.AvgQueryTime + "ms";
|
||||
public string ActionKeywordsText => string.Join(Query.ActionKeywordSeparator, PluginPair.Metadata.ActionKeywords);
|
||||
public int Priority => PluginPair.Metadata.Priority;
|
||||
public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; }
|
||||
|
||||
public void ChangeActionKeyword(string newActionKeyword, string oldActionKeyword)
|
||||
{
|
||||
|
|
@ -88,13 +111,14 @@ namespace Flow.Launcher.ViewModel
|
|||
public void ChangePriority(int newPriority)
|
||||
{
|
||||
PluginPair.Metadata.Priority = newPriority;
|
||||
PluginSettingsObject.Priority = newPriority;
|
||||
OnPropertyChanged(nameof(Priority));
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void EditPluginPriority()
|
||||
{
|
||||
PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(PluginPair.Metadata.ID, this);
|
||||
PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(PluginPair. Metadata.ID, this);
|
||||
priorityChangeWindow.ShowDialog();
|
||||
}
|
||||
|
||||
|
|
@ -106,6 +130,19 @@ namespace Flow.Launcher.ViewModel
|
|||
PluginManager.API.OpenDirectory(directory);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenSourceCodeLink()
|
||||
{
|
||||
PluginManager.API.OpenUrl(PluginPair.Metadata.Website);
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
private void OpenDeletePluginWindow()
|
||||
{
|
||||
PluginManager.API.ChangeQuery($"{PluginManagerActionKeyword} uninstall {PluginPair.Metadata.Name}".Trim(), true);
|
||||
PluginManager.API.ShowMainWindow();
|
||||
}
|
||||
|
||||
public static bool IsActionKeywordRegistered(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
|
||||
|
||||
[RelayCommand]
|
||||
|
|
|
|||
BIN
Plugins/Flow.Launcher.Plugin.PluginsManager/Images/zipfolder.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
|
|
@ -26,7 +26,6 @@
|
|||
<system:String x:Key="plugin_pluginsmanager_update_prompt">{0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart.</system:String>
|
||||
<system:String x:Key="plugin_pluginsmanager_update_prompt_no_restart">{0} by {1} {2}{2}Would you like to update this plugin?</system:String>
|
||||
<system:String x:Key="plugin_pluginsmanager_update_title">Plugin Update</system:String>
|
||||
<system:String x:Key="plugin_pluginsmanager_update_exists">This plugin has an update, would you like to see it?</system:String>
|
||||
<system:String x:Key="plugin_pluginsmanager_update_alreadyexists">This plugin is already installed</system:String>
|
||||
<system:String x:Key="plugin_pluginsmanager_update_failed_title">Plugin Manifest Download Failed</system:String>
|
||||
<system:String x:Key="plugin_pluginsmanager_update_failed_subtitle">Please check if you can connect to github.com. This error means you may not be able to install or update plugins.</system:String>
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ using Flow.Launcher.Core.Plugin;
|
|||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Http;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
|
|
@ -99,13 +97,12 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
if (Context.API.GetAllPlugins()
|
||||
.Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version.CompareTo(plugin.Version) < 0))
|
||||
{
|
||||
if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"),
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
Context
|
||||
.API
|
||||
.ChangeQuery(
|
||||
$"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UpdateCommand} {plugin.Name}");
|
||||
var updateDetail = !plugin.IsFromLocalInstallPath ? plugin.Name : plugin.LocalInstallPath;
|
||||
|
||||
Context
|
||||
.API
|
||||
.ChangeQuery(
|
||||
$"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UpdateCommand} {updateDetail}");
|
||||
|
||||
var mainWindow = Application.Current.MainWindow;
|
||||
mainWindow.Show();
|
||||
|
|
@ -147,12 +144,17 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
try
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
if (!plugin.IsFromLocalInstallPath)
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
if (File.Exists(filePath))
|
||||
File.Delete(filePath);
|
||||
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
|
||||
await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = plugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
Install(plugin, filePath);
|
||||
}
|
||||
|
|
@ -193,24 +195,38 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
{
|
||||
await PluginsManifest.UpdateManifestAsync(token, usePrimaryUrlOnly);
|
||||
|
||||
var pluginFromLocalPath = null as UserPlugin;
|
||||
var updateFromLocalPath = false;
|
||||
|
||||
if (FilesFolders.IsZipFilePath(search, checkFileExists: true))
|
||||
{
|
||||
pluginFromLocalPath = Utilities.GetPluginInfoFromZip(search);
|
||||
pluginFromLocalPath.LocalInstallPath = search;
|
||||
updateFromLocalPath = true;
|
||||
}
|
||||
|
||||
var updateSource = !updateFromLocalPath
|
||||
? PluginsManifest.UserPlugins
|
||||
: new List<UserPlugin> { pluginFromLocalPath };
|
||||
|
||||
var resultsForUpdate = (
|
||||
from existingPlugin in Context.API.GetAllPlugins()
|
||||
join pluginFromManifest in PluginsManifest.UserPlugins
|
||||
on existingPlugin.Metadata.ID equals pluginFromManifest.ID
|
||||
where String.Compare(existingPlugin.Metadata.Version, pluginFromManifest.Version,
|
||||
join pluginUpdateSource in updateSource
|
||||
on existingPlugin.Metadata.ID equals pluginUpdateSource.ID
|
||||
where string.Compare(existingPlugin.Metadata.Version, pluginUpdateSource.Version,
|
||||
StringComparison.InvariantCulture) <
|
||||
0 // if current version precedes manifest version
|
||||
0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest)
|
||||
&& !PluginManager.PluginModified(existingPlugin.Metadata.ID)
|
||||
select
|
||||
new
|
||||
{
|
||||
pluginFromManifest.Name,
|
||||
pluginFromManifest.Author,
|
||||
pluginUpdateSource.Name,
|
||||
pluginUpdateSource.Author,
|
||||
CurrentVersion = existingPlugin.Metadata.Version,
|
||||
NewVersion = pluginFromManifest.Version,
|
||||
NewVersion = pluginUpdateSource.Version,
|
||||
existingPlugin.Metadata.IcoPath,
|
||||
PluginExistingMetadata = existingPlugin.Metadata,
|
||||
PluginNewUserPlugin = pluginFromManifest
|
||||
PluginNewUserPlugin = pluginUpdateSource
|
||||
}).ToList();
|
||||
|
||||
if (!resultsForUpdate.Any())
|
||||
|
|
@ -261,13 +277,21 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
_ = Task.Run(async delegate
|
||||
{
|
||||
if (File.Exists(downloadToFilePath))
|
||||
if (!x.PluginNewUserPlugin.IsFromLocalInstallPath)
|
||||
{
|
||||
File.Delete(downloadToFilePath);
|
||||
}
|
||||
if (File.Exists(downloadToFilePath))
|
||||
{
|
||||
File.Delete(downloadToFilePath);
|
||||
}
|
||||
|
||||
await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath)
|
||||
.ConfigureAwait(false);
|
||||
await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
downloadToFilePath = x.PluginNewUserPlugin.LocalInstallPath;
|
||||
}
|
||||
|
||||
|
||||
PluginManager.UpdatePlugin(x.PluginExistingMetadata, x.PluginNewUserPlugin,
|
||||
downloadToFilePath);
|
||||
|
|
@ -396,7 +420,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
results = results.Prepend(updateAllResult);
|
||||
}
|
||||
|
||||
return Search(results, search);
|
||||
return !updateFromLocalPath ? Search(results, search) : results.ToList();
|
||||
}
|
||||
|
||||
internal bool PluginExists(string id)
|
||||
|
|
@ -470,6 +494,42 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
return new List<Result> { result };
|
||||
}
|
||||
|
||||
internal List<Result> InstallFromLocalPath(string localPath)
|
||||
{
|
||||
var plugin = Utilities.GetPluginInfoFromZip(localPath);
|
||||
|
||||
plugin.LocalInstallPath = localPath;
|
||||
|
||||
return new List<Result>
|
||||
{
|
||||
new Result
|
||||
{
|
||||
Title = $"{plugin.Name} by {plugin.Author}",
|
||||
SubTitle = plugin.Description,
|
||||
IcoPath = plugin.IcoPath,
|
||||
Action = e =>
|
||||
{
|
||||
if (Settings.WarnFromUnknownSource)
|
||||
{
|
||||
if (!InstallSourceKnown(plugin.Website)
|
||||
&& MessageBox.Show(string.Format(
|
||||
Context.API.GetTranslation("plugin_pluginsmanager_install_unknown_source_warning"),
|
||||
Environment.NewLine),
|
||||
Context.API.GetTranslation(
|
||||
"plugin_pluginsmanager_install_unknown_source_warning_title"),
|
||||
MessageBoxButton.YesNo) == MessageBoxResult.No)
|
||||
return false;
|
||||
}
|
||||
|
||||
Application.Current.MainWindow.Hide();
|
||||
_ = InstallOrUpdateAsync(plugin);
|
||||
|
||||
return ShouldHideWindow;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private bool InstallSourceKnown(string url)
|
||||
{
|
||||
var author = url.Split('/')[3];
|
||||
|
|
@ -489,6 +549,9 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
&& search.Split('.').Last() == zip)
|
||||
return InstallFromWeb(search);
|
||||
|
||||
if (FilesFolders.IsZipFilePath(search, checkFileExists: true))
|
||||
return InstallFromLocalPath(search);
|
||||
|
||||
var results =
|
||||
PluginsManifest
|
||||
.UserPlugins
|
||||
|
|
@ -522,10 +585,13 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
if (!File.Exists(downloadedFilePath))
|
||||
throw new FileNotFoundException($"Plugin {plugin.ID} zip file not found at {downloadedFilePath}",
|
||||
downloadedFilePath);
|
||||
|
||||
try
|
||||
{
|
||||
PluginManager.InstallPlugin(plugin, downloadedFilePath);
|
||||
File.Delete(downloadedFilePath);
|
||||
|
||||
if (!plugin.IsFromLocalInstallPath)
|
||||
File.Delete(downloadedFilePath);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Flow.Launcher.Core.ExternalPlugins;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
|
||||
namespace Flow.Launcher.Plugin.PluginsManager
|
||||
{
|
||||
|
|
@ -55,5 +60,28 @@ namespace Flow.Launcher.Plugin.PluginsManager
|
|||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
internal static UserPlugin GetPluginInfoFromZip(string filePath)
|
||||
{
|
||||
var plugin = null as UserPlugin;
|
||||
|
||||
using (ZipArchive archive = System.IO.Compression.ZipFile.OpenRead(filePath))
|
||||
{
|
||||
var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json").ToString();
|
||||
ZipArchiveEntry pluginJsonEntry = archive.GetEntry(pluginJsonPath);
|
||||
|
||||
if (pluginJsonEntry != null)
|
||||
{
|
||||
using (StreamReader reader = new StreamReader(pluginJsonEntry.Open()))
|
||||
{
|
||||
string pluginJsonContent = reader.ReadToEnd();
|
||||
plugin = JsonConvert.DeserializeObject<UserPlugin>(pluginJsonContent);
|
||||
plugin.IcoPath = "Images\\zipfolder.png";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||