Merge remote-tracking branch 'origin/dev' into add_nodejs_env

This commit is contained in:
Jeremy Wu 2022-11-20 10:25:53 +11:00
commit c01371393e
99 changed files with 5065 additions and 1983 deletions

View file

@ -1,4 +1,6 @@
namespace Flow.Launcher.Core.ExternalPlugins
using System;
namespace Flow.Launcher.Core.ExternalPlugins
{
public record UserPlugin
{
@ -12,5 +14,8 @@
public string UrlDownload { get; set; }
public string UrlSourceCode { get; set; }
public string IcoPath { get; set; }
public DateTime LatestReleaseDate { get; set; }
public DateTime DateAdded { get; set; }
}
}

View file

@ -21,6 +21,7 @@ namespace Flow.Launcher.Infrastructure
public static readonly string PreinstalledDirectory = Path.Combine(ProgramDirectory, Plugins);
public const string Issue = "https://github.com/Flow-Launcher/Flow.Launcher/issues/new";
public static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location.NonNull()).ProductVersion;
public static readonly string Dev = "Dev";
public const string Documentation = "https://flowlauncher.com/docs/#/usage-tips";
public static readonly int ThumbnailSize = 64;

View file

@ -58,7 +58,7 @@
<PackageReference Include="NLog.Schema" Version="4.7.10" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.13.0" />
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
<PackageReference Include="System.Drawing.Common" Version="5.0.3" />
<!--ToolGood.Words.Pinyin v3.0.2.6 results in high memory usage when search with pinyin is enabled-->
<!--Bumping to it or higher needs to test and ensure this is no longer a problem-->
<PackageReference Include="ToolGood.Words.Pinyin" Version="3.0.1.4" />

View file

@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using NLog;

View file

@ -202,7 +202,11 @@ namespace Flow.Launcher.Infrastructure
if (allQuerySubstringsMatched)
{
var nearestSpaceIndex = CalculateClosestSpaceIndex(spaceIndices, firstMatchIndex);
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1,
// firstMatchIndex - nearestSpaceIndex - 1 is to set the firstIndex as the index of the first matched char
// preceded by a space e.g. 'world' matching 'hello world' firstIndex would be 0 not 6
// giving more weight than 'we or donald' by allowing the distance calculation to treat the starting position at after the space.
var score = CalculateSearchScore(query, stringToCompare, firstMatchIndex - nearestSpaceIndex - 1, spaceIndices,
lastMatchIndex - firstMatchIndex, allSubstringsContainedInCompareString);
var resultList = indexList.Select(x => translationMapping?.MapToOriginalIndex(x) ?? x).Distinct().ToList();
@ -296,7 +300,7 @@ namespace Flow.Launcher.Infrastructure
return currentQuerySubstringIndex >= querySubstringsLength;
}
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, int matchLen,
private static int CalculateSearchScore(string query, string stringToCompare, int firstIndex, List<int> spaceIndices, int matchLen,
bool allSubstringsContainedInCompareString)
{
// A match found near the beginning of a string is scored more than a match found near the end
@ -304,6 +308,14 @@ namespace Flow.Launcher.Infrastructure
// while the score is lower if they are more spread out
var score = 100 * (query.Length + 1) / ((1 + firstIndex) + (matchLen + 1));
// Give more weight to a match that is closer to the start of the string.
// if the first matched char is immediately before space and all strings are contained in the compare string e.g. 'world' matching 'hello world'
// and 'world hello', because both have 'world' immediately preceded by space, their firstIndex will be 0 when distance is calculated,
// to prevent them scoring the same, we adjust the score by deducting the number of spaces it has from the start of the string, so 'world hello'
// will score slightly higher than 'hello world' because 'hello world' has one additional space.
if (firstIndex == 0 && allSubstringsContainedInCompareString)
score -= spaceIndices.Count;
// A match with less characters assigning more weights
if (stringToCompare.Length - query.Length < 5)
{

View file

@ -0,0 +1,65 @@
using System;
using System.Text.Json.Serialization;
namespace Flow.Launcher.Infrastructure.UserSettings
{
public abstract class ShortcutBaseModel
{
public string Key { get; set; }
[JsonIgnore]
public Func<string> Expand { get; set; } = () => { return ""; };
public override bool Equals(object obj)
{
return obj is ShortcutBaseModel other &&
Key == other.Key;
}
public override int GetHashCode()
{
return Key.GetHashCode();
}
}
public class CustomShortcutModel : ShortcutBaseModel
{
public string Value { get; set; }
[JsonConstructorAttribute]
public CustomShortcutModel(string key, string value)
{
Key = key;
Value = value;
Expand = () => { return Value; };
}
public void Deconstruct(out string key, out string value)
{
key = Key;
value = Value;
}
public static implicit operator (string Key, string Value)(CustomShortcutModel shortcut)
{
return (shortcut.Key, shortcut.Value);
}
public static implicit operator CustomShortcutModel((string Key, string Value) shortcut)
{
return new CustomShortcutModel(shortcut.Key, shortcut.Value);
}
}
public class BuiltinShortcutModel : ShortcutBaseModel
{
public string Description { get; set; }
public BuiltinShortcutModel(string key, string description, Func<string> expand)
{
Key = key;
Description = description;
Expand = expand ?? (() => { return ""; });
}
}
}

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Text.Json.Serialization;
using System.Windows;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher;
@ -41,12 +42,17 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public bool UseGlyphIcons { get; set; } = true;
public bool UseAnimation { get; set; } = true;
public bool UseSound { get; set; } = true;
public bool UseClock { get; set; } = true;
public bool UseDate { get; set; } = false;
public string TimeFormat { get; set; } = "hh:mm tt";
public string DateFormat { get; set; } = "MM'/'dd ddd";
public bool FirstLaunch { get; set; } = true;
public double SettingWindowWidth { get; set; } = 1000;
public double SettingWindowHeight { get; set; } = 700;
public double SettingWindowTop { get; set; }
public double SettingWindowLeft { get; set; }
public System.Windows.WindowState SettingWindowState { get; set; } = WindowState.Normal;
public int CustomExplorerIndex { get; set; } = 0;
@ -125,8 +131,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
PrivateArg = "-private",
EnablePrivate = false,
Editable = false
}
,
},
new()
{
Name = "MS Edge",
@ -182,6 +187,13 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public ObservableCollection<CustomPluginHotkey> CustomPluginHotkeys { get; set; } = new ObservableCollection<CustomPluginHotkey>();
public ObservableCollection<CustomShortcutModel> CustomShortcuts { get; set; } = new ObservableCollection<CustomShortcutModel>();
[JsonIgnore]
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts { get; set; } = new ObservableCollection<BuiltinShortcutModel>() {
new BuiltinShortcutModel("{clipboard}", "shortcut_clipboard_description", Clipboard.GetText)
};
public bool DontPromptUpdateMsg { get; set; }
public bool EnableUpdateLog { get; set; }

View file

@ -37,7 +37,11 @@ namespace Flow.Launcher.Plugin
/// user's clipboard when Ctrl + C is pressed on a result. If the text is a file/directory path
/// flow will copy the actual file/folder instead of just the path text.
/// </summary>
public string CopyText { get; set; } = string.Empty;
public string CopyText
{
get => string.IsNullOrEmpty(_copyText) ? SubTitle : _copyText;
set => _copyText = value;
}
/// <summary>
/// This holds the text which can be provided by plugin to help Flow autocomplete text
@ -81,6 +85,7 @@ namespace Flow.Launcher.Plugin
/// Delegate to Get Image Source
/// </summary>
public IconDelegate Icon;
private string _copyText = string.Empty;
/// <summary>
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)

View file

@ -129,14 +129,20 @@ namespace Flow.Launcher.Test
}
}
/// <summary>
/// These are standard match scenarios
/// The intention of this test is provide a bench mark for how much the score has increased from a change.
/// Usually the increase in scoring should not be drastic, increase of less than 10 is acceptable.
/// </summary>
[TestCase(Chrome, Chrome, 157)]
[TestCase(Chrome, LastIsChrome, 147)]
[TestCase(Chrome, LastIsChrome, 145)]
[TestCase("chro", HelpCureHopeRaiseOnMindEntityChrome, 50)]
[TestCase("chr", HelpCureHopeRaiseOnMindEntityChrome, 30)]
[TestCase(Chrome, UninstallOrChangeProgramsOnYourComputer, 21)]
[TestCase(Chrome, CandyCrushSagaFromKing, 0)]
[TestCase("sql", MicrosoftSqlServerManagementStudio, 110)]
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 121)] //double spacing intended
[TestCase("sql", MicrosoftSqlServerManagementStudio, 109)]
[TestCase("sql manag", MicrosoftSqlServerManagementStudio, 120)] //double spacing intended
public void WhenGivenQueryString_ThenShouldReturn_TheDesiredScoring(
string queryString, string compareString, int expectedScore)
{
@ -275,7 +281,40 @@ namespace Flow.Launcher.Test
$"Query: \"{queryString}\"{Environment.NewLine} " +
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
$"Should be greater than{Environment.NewLine}" +
$"CompareString2: \"{compareString2}\", Score: {compareString1Result.Score}{Environment.NewLine}");
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
}
[TestCase("red", "red colour", "metro red")]
[TestCase("red", "this red colour", "this colour red")]
[TestCase("red", "this red colour", "this colour is very red")]
[TestCase("red", "this red colour", "this colour is surprisingly super awesome red and cool")]
[TestCase("red", "this colour is surprisingly super red very and cool", "this colour is surprisingly super very red and cool")]
public void WhenGivenTwoStrings_Scoring_ShouldGiveMoreWeightToTheStringCloserToIndexZero(
string queryString, string compareString1, string compareString2)
{
// When
var matcher = new StringMatcher { UserSettingSearchPrecision = SearchPrecisionScore.Regular };
// Given
var compareString1Result = matcher.FuzzyMatch(queryString, compareString1);
var compareString2Result = matcher.FuzzyMatch(queryString, compareString2);
Debug.WriteLine("");
Debug.WriteLine("###############################################");
Debug.WriteLine($"QueryString: \"{queryString}\"{Environment.NewLine}");
Debug.WriteLine(
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}");
Debug.WriteLine(
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
Debug.WriteLine("###############################################");
Debug.WriteLine("");
// Should
Assert.True(compareString1Result.Score > compareString2Result.Score,
$"Query: \"{queryString}\"{Environment.NewLine} " +
$"CompareString1: \"{compareString1}\", Score: {compareString1Result.Score}{Environment.NewLine}" +
$"Should be greater than{Environment.NewLine}" +
$"CompareString2: \"{compareString2}\", Score: {compareString2Result.Score}{Environment.NewLine}");
}
[TestCase("vim", "Vim", "ignoreDescription", "ignore.exe", "Vim Diff", "ignoreDescription", "ignore.exe")]

View file

@ -19,7 +19,7 @@ namespace Flow.Launcher.Test.Plugins
var app = new UWP.Application();
// Act
var result = app.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
var result = UWP.Application.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
// Assert
Assert.IsTrue(result == expectedFormat,

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Flow.Launcher.Converters
{
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
{
if (parameter != null)
{
if (value is true)
{
return Visibility.Collapsed;
}
else
{
return Visibility.Visible;
}
}
else {
if (value is true)
{
return Visibility.Visible;
}
else {
return Visibility.Collapsed;
}
}
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
}
}

View file

@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher.Converters
{
public class TextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var ID = value.ToString();
switch(ID)
{
case PluginStoreItemViewModel.NewRelease:
return InternationalizationManager.Instance.GetTranslation("pluginStore_NewRelease");
case PluginStoreItemViewModel.RecentlyUpdated:
return InternationalizationManager.Instance.GetTranslation("pluginStore_RecentlyUpdated");
case PluginStoreItemViewModel.None:
return InternationalizationManager.Instance.GetTranslation("pluginStore_None");
case PluginStoreItemViewModel.Installed:
return InternationalizationManager.Instance.GetTranslation("pluginStore_Installed");
default:
return ID;
}
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
}
}

View file

@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows.Data;
using Flow.Launcher.Core.Resource;
namespace Flow.Launcher.Converters
{
public class TranlationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var key = value.ToString();
if (String.IsNullOrEmpty(key))
return key;
return InternationalizationManager.Instance.GetTranslation(key);
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
}
}

View file

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

View file

@ -0,0 +1,73 @@
using Flow.Launcher.Core.Resource;
using Flow.Launcher.ViewModel;
using System;
using System.Windows;
using System.Windows.Input;
namespace Flow.Launcher
{
public partial class CustomShortcutSetting : Window
{
private SettingWindowViewModel viewModel;
public string Key { get; set; } = String.Empty;
public string Value { get; set; } = String.Empty;
private string originalKey { get; init; } = null;
private string originalValue { get; init; } = null;
private bool update { get; init; } = false;
public CustomShortcutSetting(SettingWindowViewModel vm)
{
viewModel = vm;
InitializeComponent();
}
public CustomShortcutSetting(string key, string value, SettingWindowViewModel vm)
{
viewModel = vm;
Key = key;
Value = value;
originalKey = key;
originalValue = value;
update = true;
InitializeComponent();
}
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
{
if (String.IsNullOrEmpty(Key) || String.IsNullOrEmpty(Value))
{
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("emptyShortcut"));
return;
}
// Check if key is modified or adding a new one
if (((update && originalKey != Key) || !update)
&& viewModel.ShortcutExists(Key))
{
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("duplicateShortcut"));
return;
}
DialogResult = !update || originalKey != Key || originalValue != Value;
Close();
}
private void cmdEsc_OnPress(object sender, ExecutedRoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void BtnTestShortcut_OnClick(object sender, RoutedEventArgs e)
{
App.API.ChangeQuery(tbExpand.Text);
Application.Current.MainWindow.Show();
Application.Current.MainWindow.Opacity = 1;
Application.Current.MainWindow.Focus();
}
}
}

View file

@ -89,7 +89,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="InputSimulator" Version="1.0.4" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
<PackageReference Include="NHotkey.Wpf" Version="2.1.0" />
<PackageReference Include="NuGet.CommandLine" Version="5.7.2">
@ -98,6 +98,7 @@
</PackageReference>
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
<PackageReference Include="SharpVectors" Version="1.7.6" />
<PackageReference Include="VirtualizingWrapPanel" Version="1.5.7" />
</ItemGroup>
<ItemGroup>
@ -115,12 +116,12 @@
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command="taskkill /f /fi &quot;IMAGENAME eq Flow.Launcher.exe&quot;" />
</Target>
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
<ItemGroup>
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
<FilteredAnalyzer Include="@(Analyzer-&gt;Distinct())" />
<Analyzer Remove="@(Analyzer)" />
<Analyzer Include="@(FilteredAnalyzer)" />
</ItemGroup>

View file

@ -17,7 +17,7 @@ namespace Flow.Launcher.Helper
internal static void Initialize(MainViewModel mainVM)
{
mainViewModel = mainVM;
settings = mainViewModel._settings;
settings = mainViewModel.Settings;
SetHotkey(settings.Hotkey, OnToggleHotkey);
LoadCustomPluginHotkey();

View file

@ -38,9 +38,8 @@
FontSize="13"
FontWeight="SemiBold"
Foreground="{DynamicResource Color05B}"
Visibility="Visible">
Press key
</TextBlock>
Text="{DynamicResource flowlauncherPressHotkey}"
Visibility="Visible" />
</Border>
</Popup>
@ -49,8 +48,8 @@
Margin="0,0,18,0"
VerticalContentAlignment="Center"
input:InputMethod.IsInputMethodEnabled="False"
LostFocus="tbHotkey_LostFocus"
PreviewKeyDown="TbHotkey_OnPreviewKeyDown"
TabIndex="100"
LostFocus="tbHotkey_LostFocus"/>
TabIndex="100" />
</Grid>
</UserControl>

View file

@ -9,6 +9,7 @@ using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin;
using System.Threading;
using System.Windows.Interop;
namespace Flow.Launcher
{
@ -113,7 +114,7 @@ namespace Flow.Launcher
private void tbHotkey_LostFocus(object sender, RoutedEventArgs e)
{
tbMsg.Text = tbMsgTextOriginal;
tbMsg.Foreground = tbMsgForegroundColorOriginal;
tbMsg.SetResourceReference(TextBox.ForegroundProperty, "Color05B");
}
}
}

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Søgetid:</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Tema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Abfragezeit:</system:String>
<system:String x:Key="plugin_query_version">Version</system:String>
<system:String x:Key="plugin_query_web">Webseite</system:String>
<system:String x:Key="plugin_uninstall">Deinstallieren</system:String>
<system:String x:Key="uninstallbtn">Deinstallieren</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Erweiterungen laden</system:String>
<system:String x:Key="refresh">Aktualisieren</system:String>
<system:String x:Key="install">Installieren</system:String>
<system:String x:Key="installbtn">Installieren</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Design</system:String>

View file

@ -27,7 +27,7 @@
<system:String x:Key="PositionResetToolTip">Reset search window position</system:String>
<!-- Setting General -->
<system:String x:Key="flowlauncher_settings">Flow Launcher Settings</system:String>
<system:String x:Key="flowlauncher_settings">Settings</system:String>
<system:String x:Key="general">General</system:String>
<system:String x:Key="portableMode">Portable Mode</system:String>
<system:String x:Key="portableModeToolTIp">Store all settings and user data in one folder (Useful when used with removable drives or cloud services).</system:String>
@ -100,8 +100,20 @@
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="pluginStore_NewRelease">New Release</system:String>
<system:String x:Key="pluginStore_RecentlyUpdated">Recently Updated</system:String>
<system:String x:Key="pluginStore_None">Plugins</system:String>
<system:String x:Key="pluginStore_Installed">Installed</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<system:String x:Key="updatebtn">Update</system:String>
<system:String x:Key="LabelInstalledToolTip">Plugin already installed</system:String>
<system:String x:Key="LabelNew">New Version</system:String>
<system:String x:Key="LabelNewToolTip">This plugin has been updated within the last 7 days</system:String>
<system:String x:Key="LabelUpdateToolTip">New Update is Available</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Theme</system:String>
@ -124,6 +136,8 @@
<system:String x:Key="SoundEffectTip">Play a small sound when the search window opens</system:String>
<system:String x:Key="Animation">Animation</system:String>
<system:String x:Key="AnimationTip">Use Animation in UI</system:String>
<system:String x:Key="Clock">Clock</system:String>
<system:String x:Key="Date">Date</system:String>
<!-- Setting Hotkey -->
<system:String x:Key="hotkey">Hotkey</system:String>
@ -134,18 +148,26 @@
<system:String x:Key="showOpenResultHotkey">Show Hotkey</system:String>
<system:String x:Key="showOpenResultHotkeyToolTip">Show result selection hotkey with results.</system:String>
<system:String x:Key="customQueryHotkey">Custom Query Hotkey</system:String>
<system:String x:Key="customQueryShortcut">Custom Query Shortcut</system:String>
<system:String x:Key="builtinShortcuts">Built-in Shortcuts</system:String>
<system:String x:Key="customQuery">Query</system:String>
<system:String x:Key="customShortcut">Shortcut</system:String>
<system:String x:Key="customShortcutExpansion">Expanded</system:String>
<system:String x:Key="builtinShortcutDescription">Description</system:String>
<system:String x:Key="delete">Delete</system:String>
<system:String x:Key="edit">Edit</system:String>
<system:String x:Key="add">Add</system:String>
<system:String x:Key="pleaseSelectAnItem">Please select an item</system:String>
<system:String x:Key="deleteCustomHotkeyWarning">Are you sure you want to delete {0} plugin hotkey?</system:String>
<system:String x:Key="deleteCustomShortcutWarning">Are you sure you want to delete shortcut: {0} with expansion {1}?</system:String>
<system:String x:Key="shortcut_clipboard_description">Get text from clipboard.</system:String>
<system:String x:Key="queryWindowShadowEffect">Query window shadow effect</system:String>
<system:String x:Key="shadowEffectCPUUsage">Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited.</system:String>
<system:String x:Key="windowWidthSize">Window Width Size</system:String>
<system:String x:Key="windowWidthSizeToolTip">You can also quickly adjust this by using Ctrl+[ and Ctrl+].</system:String>
<system:String x:Key="useGlyphUI">Use Segoe Fluent Icons</system:String>
<system:String x:Key="useGlyphUIEffect">Use Segoe Fluent Icons for query results where supported</system:String>
<system:String x:Key="flowlauncherPressHotkey">Press Key</system:String>
<!-- Setting Proxy -->
<system:String x:Key="proxy">HTTP Proxy</system:String>
@ -169,6 +191,7 @@
<system:String x:Key="github">Github</system:String>
<system:String x:Key="docs">Docs</system:String>
<system:String x:Key="version">Version</system:String>
<system:String x:Key="icons">Icons</system:String>
<system:String x:Key="about_activate_times">You have activated Flow Launcher {0} times</system:String>
<system:String x:Key="checkUpdates">Check for Updates</system:String>
<system:String x:Key="newVersionTips">New version {0} is available, would you like to restart Flow Launcher to use the update?</system:String>
@ -231,6 +254,12 @@
<system:String x:Key="invalidPluginHotkey">Invalid plugin hotkey</system:String>
<system:String x:Key="update">Update</system:String>
<!-- Custom Query Shortcut Dialog -->
<system:String x:Key="customeQueryShortcutTitle">Custom Query Shortcut</system:String>
<system:String x:Key="customeQueryShortcutTips">Enter a shortcut that automatically expands to the specified query.</system:String>
<system:String x:Key="duplicateShortcut">Shortcut already exists, please enter a new Shortcut or edit the existing one.</system:String>
<system:String x:Key="emptyShortcut">Shortcut and/or its expansion is empty.</system:String>
<!-- Hotkey Control -->
<system:String x:Key="hotkeyUnavailable">Hotkey Unavailable</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Tiempo de consulta:</system:String>
<system:String x:Key="plugin_query_version">| Versión</system:String>
<system:String x:Key="plugin_query_web">Sitio web</system:String>
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Tienda de Plugins</system:String>
<system:String x:Key="refresh">Recargar</system:String>
<system:String x:Key="install">Instalar</system:String>
<system:String x:Key="installbtn">Instalar</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Tema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Utilisation :</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Désinstaller</system:String>
<system:String x:Key="uninstallbtn">Désinstaller</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Thèmes</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Tempo ricerca:</system:String>
<system:String x:Key="plugin_query_version">| Versione</system:String>
<system:String x:Key="plugin_query_web">Sito Web</system:String>
<system:String x:Key="plugin_uninstall">Disinstalla</system:String>
<system:String x:Key="uninstallbtn">Disinstalla</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Negozio dei Plugin</system:String>
<system:String x:Key="refresh">Aggiorna</system:String>
<system:String x:Key="install">Installa</system:String>
<system:String x:Key="installbtn">Installa</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Tema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">クエリ時間:</system:String>
<system:String x:Key="plugin_query_version">| バージョン</system:String>
<system:String x:Key="plugin_query_web">ウェブサイト</system:String>
<system:String x:Key="plugin_uninstall">アンインストール</system:String>
<system:String x:Key="uninstallbtn">アンインストール</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">プラグインストア</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">テーマ</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">쿼리 시간:</system:String>
<system:String x:Key="plugin_query_version">| 버전</system:String>
<system:String x:Key="plugin_query_web">웹사이트</system:String>
<system:String x:Key="plugin_uninstall">제거</system:String>
<system:String x:Key="uninstallbtn">제거</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">플러그인 스토어</system:String>
<system:String x:Key="refresh">새로고침</system:String>
<system:String x:Key="install">설치</system:String>
<system:String x:Key="installbtn">설치</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">테마</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Query time:</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Theme</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Query tijd:</system:String>
<system:String x:Key="plugin_query_version">| Versie</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Winkel</system:String>
<system:String x:Key="refresh">Vernieuwen</system:String>
<system:String x:Key="install">Installeren</system:String>
<system:String x:Key="installbtn">Installeren</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Thema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Czas zapytania:</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Odinstalowywanie</system:String>
<system:String x:Key="uninstallbtn">Odinstalowywanie</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Skórka</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Tempo de consulta:</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Desinstalar</system:String>
<system:String x:Key="uninstallbtn">Desinstalar</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Tema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Tempo de consulta:</system:String>
<system:String x:Key="plugin_query_version">| Versão</system:String>
<system:String x:Key="plugin_query_web">Site</system:String>
<system:String x:Key="plugin_uninstall">Desinstalar</system:String>
<system:String x:Key="uninstallbtn">Desinstalar</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Loja de plugins</system:String>
<system:String x:Key="refresh">Recarregar</system:String>
<system:String x:Key="install">Instalar</system:String>
<system:String x:Key="installbtn">Instalar</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Tema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Запрос:</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Удалить</system:String>
<system:String x:Key="uninstallbtn">Удалить</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Тема</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Trvanie dopytu:</system:String>
<system:String x:Key="plugin_query_version">| Verzia</system:String>
<system:String x:Key="plugin_query_web">Webstránka</system:String>
<system:String x:Key="plugin_uninstall">Odinštalovať</system:String>
<system:String x:Key="uninstallbtn">Odinštalovať</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Repozitár pluginov</system:String>
<system:String x:Key="refresh">Obnoviť</system:String>
<system:String x:Key="install">Inštalovať</system:String>
<system:String x:Key="installbtn">Inštalovať</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Motív</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Vreme upita:</system:String>
<system:String x:Key="plugin_query_version">| Version</system:String>
<system:String x:Key="plugin_query_web">Website</system:String>
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String>
<system:String x:Key="refresh">Refresh</system:String>
<system:String x:Key="install">Install</system:String>
<system:String x:Key="installbtn">Install</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Tema</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Sorgu Süresi:</system:String>
<system:String x:Key="plugin_query_version">Sürüm</system:String>
<system:String x:Key="plugin_query_web">İnternet Sitesi</system:String>
<system:String x:Key="plugin_uninstall">Kaldır</system:String>
<system:String x:Key="uninstallbtn">Kaldır</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Eklenti Mağazası</system:String>
<system:String x:Key="refresh">Yenile</system:String>
<system:String x:Key="install">İndir</system:String>
<system:String x:Key="installbtn">İndir</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Temalar</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">Запит:</system:String>
<system:String x:Key="plugin_query_version">| Версія</system:String>
<system:String x:Key="plugin_query_web">Сайт</system:String>
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
<system:String x:Key="uninstallbtn">Uninstall</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Магазин плагінів</system:String>
<system:String x:Key="refresh">Оновити</system:String>
<system:String x:Key="install">Встановити</system:String>
<system:String x:Key="installbtn">Встановити</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">Тема</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">查询耗时:</system:String>
<system:String x:Key="plugin_query_version">| 版本</system:String>
<system:String x:Key="plugin_query_web">官方网站</system:String>
<system:String x:Key="plugin_uninstall">卸载</system:String>
<system:String x:Key="uninstallbtn">卸载</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">插件商店</system:String>
<system:String x:Key="refresh">刷新</system:String>
<system:String x:Key="install">安装</system:String>
<system:String x:Key="installbtn">安装</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">主题</system:String>

View file

@ -76,13 +76,13 @@
<system:String x:Key="plugin_query_time">查詢耗時:</system:String>
<system:String x:Key="plugin_query_version">| 版本</system:String>
<system:String x:Key="plugin_query_web">官方網站</system:String>
<system:String x:Key="plugin_uninstall">解除安裝</system:String>
<system:String x:Key="uninstallbtn">解除安裝</system:String>
<!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">外掛商店</system:String>
<system:String x:Key="refresh">重新整理</system:String>
<system:String x:Key="install">安裝</system:String>
<system:String x:Key="installbtn">安裝</system:String>
<!-- Setting Theme -->
<system:String x:Key="theme">主題</system:String>

View file

@ -1,5 +1,4 @@
<Window
x:Class="Flow.Launcher.MainWindow"
<Window x:Class="Flow.Launcher.MainWindow"
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"
@ -7,6 +6,7 @@
xmlns:flowlauncher="clr-namespace:Flow.Launcher"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:ui="http://schemas.modernwpf.com/2019"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
Name="FlowMainWindow"
Title="Flow Launcher"
@ -36,160 +36,148 @@
<Window.Resources>
<converters:QuerySuggestionBoxConverter x:Key="QuerySuggestionBoxConverter" />
<converters:BorderClipConverter x:Key="BorderClipConverter" />
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Window.InputBindings>
<KeyBinding Key="Escape" Command="{Binding EscCommand}" />
<KeyBinding Key="F1" Command="{Binding StartHelpCommand}" />
<KeyBinding Key="F5" Command="{Binding ReloadPluginDataCommand}" />
<KeyBinding Key="Tab" Command="{Binding AutocompleteQueryCommand}" />
<KeyBinding
Key="Tab"
<KeyBinding Key="Escape"
Command="{Binding EscCommand}" />
<KeyBinding Key="F1"
Command="{Binding StartHelpCommand}" />
<KeyBinding Key="F5"
Command="{Binding ReloadPluginDataCommand}" />
<KeyBinding Key="Tab"
Command="{Binding AutocompleteQueryCommand}" />
<KeyBinding Key="Tab"
Command="{Binding AutocompleteQueryCommand}"
Modifiers="Shift" />
<KeyBinding
Key="I"
<KeyBinding Key="I"
Command="{Binding OpenSettingCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="N"
<KeyBinding Key="N"
Command="{Binding SelectNextItemCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="J"
<KeyBinding Key="J"
Command="{Binding SelectNextItemCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="D"
<KeyBinding Key="D"
Command="{Binding SelectNextPageCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="P"
<KeyBinding Key="P"
Command="{Binding SelectPrevItemCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="K"
<KeyBinding Key="K"
Command="{Binding SelectPrevItemCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="U"
<KeyBinding Key="U"
Command="{Binding SelectPrevPageCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="Home"
<KeyBinding Key="Home"
Command="{Binding SelectFirstResultCommand}"
Modifiers="Alt" />
<KeyBinding
Key="O"
<KeyBinding Key="O"
Command="{Binding LoadContextMenuCommand}"
Modifiers="Ctrl" />
<KeyBinding Key="Right" Command="{Binding LoadContextMenuCommand}" />
<KeyBinding Key="Left" Command="{Binding EscCommand}" />
<KeyBinding
Key="OemCloseBrackets"
Command="{Binding IncreaseWidthCommand}"
Modifiers="Control" />
<KeyBinding
Key="OemOpenBrackets"
Command="{Binding DecreaseWidthCommand}"
Modifiers="Control" />
<KeyBinding
Key="OemPlus"
Command="{Binding IncreaseMaxResultCommand}"
Modifiers="Control" />
<KeyBinding
Key="OemMinus"
Command="{Binding DecreaseMaxResultCommand}"
Modifiers="Control" />
<KeyBinding
Key="H"
<KeyBinding Key="Right"
Command="{Binding LoadContextMenuCommand}" />
<KeyBinding Key="Left"
Command="{Binding EscCommand}" />
<KeyBinding Key="H"
Command="{Binding LoadHistoryCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="Enter"
<KeyBinding Key="Right"
Command="{Binding LoadContextMenuCommand}" />
<KeyBinding Key="Left"
Command="{Binding EscCommand}" />
<KeyBinding Key="OemCloseBrackets"
Command="{Binding IncreaseWidthCommand}"
Modifiers="Control" />
<KeyBinding Key="OemOpenBrackets"
Command="{Binding DecreaseWidthCommand}"
Modifiers="Control" />
<KeyBinding Key="OemPlus"
Command="{Binding IncreaseMaxResultCommand}"
Modifiers="Control" />
<KeyBinding Key="OemMinus"
Command="{Binding DecreaseMaxResultCommand}"
Modifiers="Control" />
<KeyBinding Key="H"
Command="{Binding LoadHistoryCommand}"
Modifiers="Ctrl" />
<KeyBinding Key="Enter"
Command="{Binding OpenResultCommand}"
Modifiers="Ctrl+Shift" />
<KeyBinding
Key="Enter"
<KeyBinding Key="Enter"
Command="{Binding LoadContextMenuCommand}"
Modifiers="Shift" />
<KeyBinding Key="Enter" Command="{Binding OpenResultCommand}" />
<KeyBinding
Key="Enter"
<KeyBinding Key="Enter"
Command="{Binding OpenResultCommand}" />
<KeyBinding Key="Enter"
Command="{Binding OpenResultCommand}"
Modifiers="Ctrl" />
<KeyBinding
Key="Enter"
<KeyBinding Key="Enter"
Command="{Binding OpenResultCommand}"
Modifiers="Alt" />
<KeyBinding
Key="D1"
<KeyBinding Key="D1"
Command="{Binding OpenResultCommand}"
CommandParameter="0"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D2"
<KeyBinding Key="D2"
Command="{Binding OpenResultCommand}"
CommandParameter="1"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D3"
<KeyBinding Key="D3"
Command="{Binding OpenResultCommand}"
CommandParameter="2"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D4"
<KeyBinding Key="D4"
Command="{Binding OpenResultCommand}"
CommandParameter="3"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D5"
<KeyBinding Key="D5"
Command="{Binding OpenResultCommand}"
CommandParameter="4"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D6"
<KeyBinding Key="D6"
Command="{Binding OpenResultCommand}"
CommandParameter="5"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D7"
<KeyBinding Key="D7"
Command="{Binding OpenResultCommand}"
CommandParameter="6"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D8"
<KeyBinding Key="D8"
Command="{Binding OpenResultCommand}"
CommandParameter="7"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D9"
<KeyBinding Key="D9"
Command="{Binding OpenResultCommand}"
CommandParameter="8"
Modifiers="{Binding OpenResultCommandModifiers}" />
<KeyBinding
Key="D0"
<KeyBinding Key="D0"
Command="{Binding OpenResultCommand}"
CommandParameter="9"
Modifiers="{Binding OpenResultCommandModifiers}" />
</Window.InputBindings>
<Grid>
<Border MouseDown="OnMouseDown" Style="{DynamicResource WindowBorderStyle}">
<Border MouseDown="OnMouseDown"
Style="{DynamicResource WindowBorderStyle}">
<StackPanel Orientation="Vertical">
<Grid>
<TextBox
x:Name="QueryTextSuggestionBox"
<TextBox x:Name="QueryTextSuggestionBox"
IsEnabled="False"
Style="{DynamicResource QuerySuggestionBoxStyle}">
<TextBox.Text>
<MultiBinding Converter="{StaticResource QuerySuggestionBoxConverter}">
<Binding ElementName="QueryTextBox" Mode="OneTime" />
<Binding ElementName="ResultListBox" Path="SelectedItem" />
<Binding ElementName="QueryTextBox" Path="Text" />
<Binding ElementName="QueryTextBox"
Mode="OneTime" />
<Binding ElementName="ResultListBox"
Path="SelectedItem" />
<Binding ElementName="QueryTextBox"
Path="Text" />
</MultiBinding>
</TextBox.Text>
</TextBox>
<TextBox
x:Name="QueryTextBox"
<TextBox x:Name="QueryTextBox"
AllowDrop="True"
Background="Transparent"
PreviewDragOver="OnPreviewDragOver"
@ -198,25 +186,61 @@
Text="{Binding QueryText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="Visible">
<TextBox.CommandBindings>
<CommandBinding Command="ApplicationCommands.Copy" Executed="OnCopy" />
<CommandBinding Command="ApplicationCommands.Copy"
Executed="OnCopy" />
</TextBox.CommandBindings>
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Command="ApplicationCommands.Cut" Header="{DynamicResource cut}" />
<MenuItem Command="ApplicationCommands.Copy" Header="{DynamicResource copy}" />
<MenuItem Command="ApplicationCommands.Paste" Header="{DynamicResource paste}" />
<Separator
Margin="0"
<MenuItem Command="ApplicationCommands.Cut"
Header="{DynamicResource cut}">
<MenuItem.Icon>
<ui:FontIcon Glyph="&#xe8c6;" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="ApplicationCommands.Copy"
Header="{DynamicResource copy}">
<MenuItem.Icon>
<ui:FontIcon Glyph="&#xe8c8;" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="ApplicationCommands.Paste"
Header="{DynamicResource paste}">
<MenuItem.Icon>
<ui:FontIcon Glyph="&#xe77f;" />
</MenuItem.Icon>
</MenuItem>
<Separator Margin="0"
Padding="0,4,0,4"
Background="{DynamicResource ContextSeparator}" />
<MenuItem Click="OnContextMenusForSettingsClick" Header="{DynamicResource flowlauncher_settings}" />
<MenuItem Command="{Binding EscCommand}" Header="{DynamicResource closeWindow}" />
<MenuItem Click="OnContextMenusForSettingsClick"
Header="{DynamicResource flowlauncher_settings}">
<MenuItem.Icon>
<ui:FontIcon Glyph="&#xe713;" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Command="{Binding EscCommand}"
Header="{DynamicResource closeWindow}">
<MenuItem.Icon>
<ui:FontIcon Glyph="&#xe711;" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
<StackPanel x:Name="ClockPanel"
IsHitTestVisible="False"
Style="{DynamicResource ClockPanel}">
<TextBlock Style="{DynamicResource DateBox}"
Text="{Binding DateText}"
Visibility="{Binding Settings.UseDate, Converter={StaticResource BooleanToVisibilityConverter}}" />
<TextBlock Style="{DynamicResource ClockBox}"
Text="{Binding ClockText}"
Visibility="{Binding Settings.UseClock, Converter={StaticResource BooleanToVisibilityConverter}}" />
</StackPanel>
<Canvas Style="{DynamicResource SearchIconPosition}">
<Image
x:Name="PluginActivationIcon"
<Image x:Name="PluginActivationIcon"
Width="32"
Height="32"
Margin="0,0,0,0"
@ -227,8 +251,7 @@
Source="{Binding PluginIconPath}"
Stretch="Uniform"
Style="{DynamicResource PluginActivationIcon}" />
<Path
Name="SearchIcon"
<Path Name="SearchIcon"
Margin="0"
Data="{DynamicResource SearchIconImg}"
Stretch="Fill"
@ -241,27 +264,32 @@
<ContentControl>
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Visibility"
Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ResultListBox, Path=Visibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible" />
<DataTrigger Binding="{Binding ElementName=ResultListBox, Path=Visibility}"
Value="Visible">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible" />
<DataTrigger Binding="{Binding ElementName=ContextMenu, Path=Visibility}"
Value="Visible">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=History, Path=Visibility}" Value="Visible">
<Setter Property="Visibility" Value="Visible" />
<DataTrigger Binding="{Binding ElementName=History, Path=Visibility}"
Value="Visible">
<Setter Property="Visibility"
Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
<Rectangle
Width="Auto"
<Rectangle Width="Auto"
HorizontalAlignment="Stretch"
Style="{DynamicResource SeparatorStyle}" />
</ContentControl>
<Line
x:Name="ProgressBar"
<Line x:Name="ProgressBar"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}, Path=ActualWidth}"
Height="2"
HorizontalAlignment="Right"
@ -277,49 +305,58 @@
<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}" />
<Binding Path="ActualWidth"
RelativeSource="{RelativeSource Self}" />
<Binding Path="ActualHeight"
RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius"
RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Border.Clip>
<ContentControl>
<flowlauncher:ResultListBox
x:Name="ResultListBox"
<flowlauncher:ResultListBox x:Name="ResultListBox"
DataContext="{Binding Results}"
PreviewMouseDown="OnPreviewMouseButtonDown" />
LeftClickResultCommand="{Binding LeftClickResultCommand}"
RightClickResultCommand="{Binding RightClickResultCommand}" />
</ContentControl>
</Border>
<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}" />
<Binding Path="ActualWidth"
RelativeSource="{RelativeSource Self}" />
<Binding Path="ActualHeight"
RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius"
RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Border.Clip>
<ContentControl>
<flowlauncher:ResultListBox
x:Name="ContextMenu"
<flowlauncher:ResultListBox x:Name="ContextMenu"
DataContext="{Binding ContextMenu}"
PreviewMouseDown="OnPreviewMouseButtonDown" />
LeftClickResultCommand="{Binding LeftClickResultCommand}"
RightClickResultCommand="{Binding RightClickResultCommand}" />
</ContentControl>
</Border>
<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}" />
<Binding Path="ActualWidth"
RelativeSource="{RelativeSource Self}" />
<Binding Path="ActualHeight"
RelativeSource="{RelativeSource Self}" />
<Binding Path="CornerRadius"
RelativeSource="{RelativeSource Self}" />
</MultiBinding>
</Border.Clip>
<ContentControl>
<flowlauncher:ResultListBox
x:Name="History"
<flowlauncher:ResultListBox x:Name="History"
DataContext="{Binding History}"
PreviewMouseDown="OnPreviewMouseButtonDown" />
LeftClickResultCommand="{Binding LeftClickResultCommand}"
RightClickResultCommand="{Binding RightClickResultCommand}" />
</ContentControl>
</Border>
</StackPanel>
</Border>
</Grid>
</Window>
</Window>

View file

@ -20,8 +20,16 @@ using Flow.Launcher.Infrastructure;
using System.Windows.Media;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Plugin.SharedCommands;
using System.Windows.Data;
using System.Text;
using DataObject = System.Windows.DataObject;
using System.Diagnostics;
using Microsoft.AspNetCore.Http;
using System.IO;
using System.Windows.Threading;
using System.Windows.Data;
using ModernWpf.Controls;
using System.Drawing;
using System.Windows.Forms.Design.Behavior;
namespace Flow.Launcher
{
@ -45,6 +53,7 @@ namespace Flow.Launcher
DataContext = mainVM;
_viewModel = mainVM;
_settings = settings;
InitializeComponent();
InitializePosition();
animationSound.Open(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav"));
@ -54,6 +63,7 @@ namespace Flow.Launcher
{
InitializeComponent();
}
private void OnCopy(object sender, ExecutedRoutedEventArgs e)
{
if (QueryTextBox.SelectionLength == 0)
@ -217,11 +227,12 @@ namespace Flow.Launcher
private void UpdateNotifyIconText()
{
var menu = contextMenu;
((MenuItem)menu.Items[1]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")";
((MenuItem)menu.Items[2]).Header = InternationalizationManager.Instance.GetTranslation("GameMode");
((MenuItem)menu.Items[3]).Header = InternationalizationManager.Instance.GetTranslation("PositionReset");
((MenuItem)menu.Items[4]).Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings");
((MenuItem)menu.Items[5]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit");
((MenuItem)menu.Items[0]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")";
((MenuItem)menu.Items[1]).Header = InternationalizationManager.Instance.GetTranslation("GameMode");
((MenuItem)menu.Items[2]).Header = InternationalizationManager.Instance.GetTranslation("PositionReset");
((MenuItem)menu.Items[3]).Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings");
((MenuItem)menu.Items[4]).Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit");
}
private void InitializeNotifyIcon()
@ -233,31 +244,35 @@ namespace Flow.Launcher
Visible = !_settings.HideNotifyIcon
};
contextMenu = new ContextMenu();
var header = new MenuItem
{
Header = "Flow Launcher",
IsEnabled = false
};
var openIcon = new FontIcon { Glyph = "\ue71e" };
var open = new MenuItem
{
Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" +_settings.Hotkey + ")"
Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")",
Icon = openIcon
};
var gamemodeIcon = new FontIcon { Glyph = "\ue7fc" };
var gamemode = new MenuItem
{
Header = InternationalizationManager.Instance.GetTranslation("GameMode")
Header = InternationalizationManager.Instance.GetTranslation("GameMode"),
Icon = gamemodeIcon
};
var positionresetIcon = new FontIcon { Glyph = "\ue73f" };
var positionreset = new MenuItem
{
Header = InternationalizationManager.Instance.GetTranslation("PositionReset")
Header = InternationalizationManager.Instance.GetTranslation("PositionReset"),
Icon = positionresetIcon
};
var settingsIcon = new FontIcon { Glyph = "\ue713" };
var settings = new MenuItem
{
Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings")
Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"),
Icon = settingsIcon
};
var exitIcon = new FontIcon { Glyph = "\ue7e8" };
var exit = new MenuItem
{
Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit")
Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"),
Icon = exitIcon
};
open.Click += (o, e) => _viewModel.ToggleFlowLauncher();
@ -265,7 +280,6 @@ namespace Flow.Launcher
positionreset.Click += (o, e) => PositionReset();
settings.Click += (o, e) => App.API.OpenSettingDialog();
exit.Click += (o, e) => Close();
contextMenu.Items.Add(header);
contextMenu.Items.Add(open);
gamemode.ToolTip = InternationalizationManager.Instance.GetTranslation("GameModeToolTip");
positionreset.ToolTip = InternationalizationManager.Instance.GetTranslation("PositionResetToolTip");
@ -391,28 +405,6 @@ namespace Flow.Launcher
if (e.ChangedButton == MouseButton.Left) DragMove();
}
private void OnPreviewMouseButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender != null && e.OriginalSource != null)
{
var r = (ResultListBox)sender;
var d = (DependencyObject)e.OriginalSource;
var item = ItemsControl.ContainerFromElement(r, d) as ListBoxItem;
var result = (ResultViewModel)item?.DataContext;
if (result != null)
{
if (e.ChangedButton == MouseButton.Left)
{
_viewModel.OpenResultCommand.Execute(null);
}
else if (e.ChangedButton == MouseButton.Right)
{
_viewModel.LoadContextMenuCommand.Execute(null);
}
}
}
}
private void OnPreviewDragOver(object sender, DragEventArgs e)
{
e.Handled = true;

View file

@ -1407,7 +1407,8 @@
Padding="{TemplateBinding Padding}"
BorderBrush="{DynamicResource ButtonInsideBorder}"
BorderThickness="{DynamicResource CustomButtonInsideBorderThickness}"
CornerRadius="4">
CornerRadius="4"
SnapsToDevicePixels="True">
<ContentPresenter
x:Name="ContentPresenter"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
@ -2044,31 +2045,43 @@
<Border Padding="{TemplateBinding Padding}">
<Grid Background="Transparent" SnapsToDevicePixels="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="19" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Ellipse
x:Name="circle"
Width="19"
Height="19"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stroke="Transparent" />
<Path
x:Name="arrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 1,1.5 L 4.5,5 L 8,1.5"
SnapsToDevicePixels="false"
Stroke="#666"
StrokeThickness="1" />
<ContentPresenter
Grid.Column="1"
Margin="4,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Grid.Column="0"
Margin="0,0,0,0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
RecognizesAccessKey="True"
SnapsToDevicePixels="True" />
<Grid
x:Name="ChevronGrid"
Grid.Column="1"
Margin="0"
VerticalAlignment="Center"
Background="Transparent"
RenderTransformOrigin="0.5, 0.5">
<Grid.RenderTransform>
<RotateTransform Angle="0" />
</Grid.RenderTransform>
<Ellipse
x:Name="circle"
Width="19"
Height="19"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stroke="Transparent" />
<Path
x:Name="arrow"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 1,1.5 L 4.5,5 L 8,1.5"
SnapsToDevicePixels="false"
Stroke="#666"
StrokeThickness="1" />
</Grid>
</Grid>
</Border>
<ControlTemplate.Triggers>
@ -2077,12 +2090,12 @@
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="circle" Property="Stroke" Value="Transparent" />
<Setter TargetName="arrow" Property="Stroke" Value="#222" />
<Setter TargetName="arrow" Property="Stroke" Value="{DynamicResource Color05B}" />
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="circle" Property="Stroke" Value="Transparent" />
<Setter TargetName="circle" Property="StrokeThickness" Value="1.5" />
<Setter TargetName="arrow" Property="Stroke" Value="#FF003366" />
<Setter TargetName="arrow" Property="Stroke" Value="{DynamicResource Color17B}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
@ -2110,7 +2123,7 @@
x:Name="HeaderSite"
MinWidth="0"
MinHeight="0"
Margin="18,0,0,0"
Margin="18,0,18,0"
Padding="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
@ -2127,19 +2140,62 @@
Foreground="{TemplateBinding Foreground}"
IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource ExpanderDownHeaderStyle}" />
<ContentPresenter
x:Name="ExpandSite"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
DockPanel.Dock="Bottom"
Focusable="false"
Visibility="Collapsed" />
<Border x:Name="ContentPresenterBorder">
<ContentPresenter
x:Name="ExpandSite"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
DockPanel.Dock="Bottom"
Focusable="false" />
<Border.LayoutTransform>
<ScaleTransform ScaleY="0" />
</Border.LayoutTransform>
</Border>
</DockPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="true">
<Setter TargetName="ExpandSite" Property="Visibility" Value="Visible" />
<Setter TargetName="ContentPresenterBorder" Property="BorderThickness" Value="0,1,0,0" />
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ContentPresenterBorder"
Storyboard.TargetProperty="(Border.LayoutTransform).(ScaleTransform.ScaleY)"
From="0.0"
To="1.0"
Duration="00:00:00.00" />
<DoubleAnimation
Storyboard.TargetName="ContentPresenterBorder"
Storyboard.TargetProperty="(Border.Opacity)"
From="0.0"
To="1.0"
Duration="00:00:00.00" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ContentPresenterBorder"
Storyboard.TargetProperty="(Border.LayoutTransform).(ScaleTransform.ScaleY)"
From="1.0"
To="0"
Duration="00:00:00.00" />
<!-- Animation 00:00:00.167 -->
<DoubleAnimation
Storyboard.TargetName="ContentPresenterBorder"
Storyboard.TargetProperty="(Border.Opacity)"
From="1.0"
To="0.0"
Duration="00:00:00.00" />
<!-- Animation 00:00:00.167 -->
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="ExpandDirection" Value="Right">
<Setter TargetName="ExpandSite" Property="DockPanel.Dock" Value="Right" />
@ -2672,73 +2728,491 @@
</Style>
<!--#endregion-->
<Style TargetType="{x:Type MenuItem}">
<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="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource Color05B}" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<system:Double x:Key="MenuBarHeight">40</system:Double>
<Thickness x:Key="MenuFlyoutScrollerMargin">4,4,4,4</Thickness>
<Thickness x:Key="MenuFlyoutItemRevealBorderThickness">1</Thickness>
<Thickness x:Key="ToggleMenuFlyoutItemRevealBorderThickness">1</Thickness>
<Thickness x:Key="MenuFlyoutSubItemRevealBorderThickness">1</Thickness>
<ui:SharedSizeGroupConverter x:Key="SharedSizeGroupConverter" />
<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type FrameworkElement}, ResourceId=MenuScrollViewer}" TargetType="ScrollViewer">
<Setter Property="HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="PanningMode" Value="VerticalOnly" />
</Style>
<Style x:Key="DefaultMenuItemSeparatorStyle" TargetType="Separator">
<Setter Property="Background" Value="{DynamicResource MenuFlyoutSeparatorBackground}" />
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutSeparatorThemePadding}" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Border
Name="bdr"
Padding="24,6,24,6"
Background="Transparent">
<TextBlock
Name="Menu"
VerticalAlignment="Center"
FontSize="14"
Foreground="{DynamicResource Color05B}"
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Header}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsVisible" Value="True">
<Setter TargetName="bdr" Property="Background" Value="{DynamicResource CustomContextBackground}" />
<Setter TargetName="Menu" Property="Foreground" Value="{DynamicResource Color05B}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="bdr" Property="Background" Value="{DynamicResource CustomContextHover}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Menu" Property="Foreground" Value="{DynamicResource CustomContextDisabled}" />
</Trigger>
</ControlTemplate.Triggers>
<ControlTemplate TargetType="Separator">
<Rectangle
Height="{DynamicResource MenuFlyoutSeparatorThemeHeight}"
Margin="{TemplateBinding Padding}"
Fill="{TemplateBinding Background}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ContextMenu}">
<Style
x:Key="{x:Static MenuItem.SeparatorStyleKey}"
BasedOn="{StaticResource DefaultMenuItemSeparatorStyle}"
TargetType="Separator" />
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=TopLevelItemTemplateKey}" TargetType="{x:Type MenuItem}">
<Grid
x:Name="ContentRoot"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<Border
x:Name="Background"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<ContentPresenter
Margin="12,0,12,0"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Background" Property="Background" Value="{DynamicResource MenuBarItemBackgroundPointerOver}" />
<Setter TargetName="Background" Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrushPointerOver}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Background" Property="Background" Value="{DynamicResource MenuBarItemBackgroundPressed}" />
<Setter TargetName="Background" Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrushPressed}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=TopLevelHeaderTemplateKey}" TargetType="{x:Type MenuItem}">
<Grid
x:Name="ContentRoot"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<Border
x:Name="Background"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" />
<ContentPresenter
Margin="12,0,12,0"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<ui:MenuPopup
x:Name="PART_Popup"
AllowsTransparency="true"
Focusable="false"
IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Bottom"
PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
<ui:ThemeShadowChrome CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}" IsShadowEnabled="{DynamicResource {x:Static SystemParameters.DropShadowKey}}">
<Border
x:Name="SubMenuRoot"
Background="{DynamicResource MenuFlyoutPresenterBackground}"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}">
<Grid>
<ScrollViewer
x:Name="SubMenuScrollViewer"
MinWidth="{DynamicResource FlyoutThemeMinWidth}"
Margin="{DynamicResource MenuFlyoutPresenterThemePadding}"
Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer,
TypeInTargetAssembly={x:Type FrameworkElement}}}">
<ItemsPresenter
Grid.IsSharedSizeScope="true"
KeyboardNavigation.DirectionalNavigation="Cycle"
KeyboardNavigation.TabNavigation="Cycle"
RenderOptions.ClearTypeHint="Enabled"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
<Border
x:Name="SubMenuBorder"
BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
BorderThickness="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}" />
</Grid>
</Border>
</ui:ThemeShadowChrome>
</ui:MenuPopup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSuspendingPopupAnimation" Value="true">
<Setter TargetName="PART_Popup" Property="PopupAnimation" Value="None" />
</Trigger>
<Trigger SourceName="PART_Popup" Property="IsSuspendingAnimation" Value="true">
<Setter TargetName="PART_Popup" Property="PopupAnimation" Value="None" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Background" Property="Background" Value="{DynamicResource MenuBarItemBackgroundPointerOver}" />
<Setter TargetName="Background" Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrushPointerOver}" />
</Trigger>
<!-- Selected -->
<Trigger Property="IsSubmenuOpen" Value="True">
<Setter TargetName="Background" Property="Background" Value="{DynamicResource MenuBarItemBackgroundSelected}" />
<Setter TargetName="Background" Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrushSelected}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Background" Property="Background" Value="{DynamicResource MenuBarItemBackgroundPressed}" />
<Setter TargetName="Background" Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrushPressed}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- DefaultMenuFlyoutSubItemStyle -->
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=SubmenuItemTemplateKey}" TargetType="{x:Type MenuItem}">
<ControlTemplate.Resources>
<StreamGeometry x:Key="CheckMark">F1 M 17.939453 5.439453 L 7.5 15.888672 L 2.060547 10.439453 L 2.939453 9.560547 L 7.5 14.111328 L 17.060547 4.560547 Z</StreamGeometry>
</ControlTemplate.Resources>
<Border
x:Name="LayoutRoot"
Height="Auto"
Margin="5,2,5,2"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}"
SnapsToDevicePixels="true"
TextElement.Foreground="{DynamicResource Color05B}"
UseLayoutRounding="True">
<Grid x:Name="AnimationRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="{TemplateBinding Visibility, Converter={StaticResource SharedSizeGroupConverter}, ConverterParameter=MenuItemCheckColumnGroup}" />
<ColumnDefinition Width="Auto" SharedSizeGroup="{TemplateBinding Visibility, Converter={StaticResource SharedSizeGroupConverter}, ConverterParameter=MenuItemIconColumnGroup}" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ui:FontIconFallback
x:Name="CheckGlyph"
Margin="0,0,16,0"
Data="{StaticResource CheckMark}"
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="12"
Foreground="{DynamicResource ToggleMenuFlyoutItemCheckGlyphForeground}"
Opacity="0"
Visibility="Collapsed" />
<Viewbox
x:Name="IconRoot"
Grid.Column="1"
Width="16"
Height="16"
Margin="0,1,12,0"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
TextBlock.FontFamily="/Resources/#Segoe Fluent Icons">
<ContentPresenter
x:Name="IconContent"
ContentSource="Icon"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Viewbox>
<ContentPresenter
x:Name="ContentPresenter"
Grid.Column="2"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
TextElement.Foreground="{DynamicResource Color05B}" />
<TextBlock
x:Name="KeyboardAcceleratorTextBlock"
Grid.Column="3"
Margin="24,4,0,0"
HorizontalAlignment="Right"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForeground}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{TemplateBinding InputGestureText}"
Visibility="Collapsed" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsVisible" Value="True">
<Setter TargetName="LayoutRoot" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
</Trigger>
<Trigger Property="Icon" Value="{x:Null}">
<Setter TargetName="IconRoot" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="InputGestureText" Value="">
<Setter TargetName="KeyboardAcceleratorTextBlock" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="CheckGlyph" Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsCheckable" Value="True">
<Setter TargetName="CheckGlyph" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource CustomContextHover}" />
<Setter TargetName="LayoutRoot" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
<Setter TargetName="KeyboardAcceleratorTextBlock" Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPointerOver}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource CustomContextClick}" />
<Setter TargetName="LayoutRoot" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
<Setter TargetName="KeyboardAcceleratorTextBlock" Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundPressed}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource MenuFlyoutItemBackgroundDisabled}" />
<Setter TargetName="LayoutRoot" Property="TextElement.Foreground" Value="{DynamicResource MenuFlyoutItemForegroundDisabled}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource MenuFlyoutItemForegroundDisabled}" />
<Setter TargetName="KeyboardAcceleratorTextBlock" Property="Foreground" Value="{DynamicResource MenuFlyoutItemKeyboardAcceleratorTextForegroundDisabled}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<!-- DefaultMenuFlyoutItemStyle -->
<ControlTemplate x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=SubmenuHeaderTemplateKey}" TargetType="{x:Type MenuItem}">
<ControlTemplate.Resources>
<StreamGeometry x:Key="ChevronRight">M 5.029297 19.091797 L 14.111328 10 L 5.029297 0.908203 L 5.908203 0.029297 L 15.888672 10 L 5.908203 19.970703 Z</StreamGeometry>
</ControlTemplate.Resources>
<Border
x:Name="LayoutRoot"
Margin="{DynamicResource MenuFlyoutItemMargin}"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}"
SnapsToDevicePixels="True">
<Grid x:Name="AnimationRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemCheckColumnGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="MenuItemIconColumnGroup" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Viewbox
x:Name="IconRoot"
Grid.Column="1"
Width="16"
Height="16"
Margin="0,0,12,0"
HorizontalAlignment="Left"
VerticalAlignment="Center">
<ContentPresenter
x:Name="IconContent"
ContentSource="Icon"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Viewbox>
<ContentPresenter
x:Name="ContentPresenter"
Grid.Column="2"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
ContentSource="Header"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
TextElement.Foreground="{TemplateBinding Foreground}" />
<ui:FontIconFallback
x:Name="SubItemChevron"
Grid.Column="3"
Margin="{DynamicResource MenuFlyoutItemChevronMargin}"
Data="{StaticResource ChevronRight}"
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontSize="12"
Foreground="{DynamicResource MenuFlyoutSubItemChevron}">
<UIElement.RenderTransform>
<TranslateTransform Y="1" />
</UIElement.RenderTransform>
</ui:FontIconFallback>
<Popup
x:Name="PART_Popup"
AllowsTransparency="true"
Focusable="false"
IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}"
Placement="Right"
PlacementTarget="{Binding ElementName=LayoutRoot}"
PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}">
<Popup.PlacementRectangle>
<MultiBinding>
<MultiBinding.Converter>
<ui:PlacementRectangleConverter Margin="4,-1" />
</MultiBinding.Converter>
<Binding ElementName="LayoutRoot" Path="ActualWidth" />
<Binding ElementName="LayoutRoot" Path="ActualHeight" />
</MultiBinding>
</Popup.PlacementRectangle>
<ui:ThemeShadowChrome CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}" IsShadowEnabled="{DynamicResource {x:Static SystemParameters.DropShadowKey}}">
<Border
x:Name="SubMenuRoot"
Background="{DynamicResource MenuFlyoutPresenterBackground}"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}">
<Grid>
<ScrollViewer
x:Name="SubMenuScrollViewer"
MinWidth="{DynamicResource FlyoutThemeMinWidth}"
Margin="{DynamicResource MenuFlyoutPresenterThemePadding}"
Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer,
TypeInTargetAssembly={x:Type FrameworkElement}}}">
<ItemsPresenter
Grid.IsSharedSizeScope="true"
KeyboardNavigation.DirectionalNavigation="Cycle"
KeyboardNavigation.TabNavigation="Cycle"
RenderOptions.ClearTypeHint="Enabled"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
<Border
x:Name="SubMenuBorder"
BorderBrush="{DynamicResource MenuFlyoutPresenterBorderBrush}"
BorderThickness="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}" />
</Grid>
</Border>
</ui:ThemeShadowChrome>
</Popup>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsVisible" Value="True">
<Setter TargetName="LayoutRoot" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource Color05B}" />
</Trigger>
<Trigger Property="IsSuspendingPopupAnimation" Value="true">
<Setter TargetName="PART_Popup" Property="PopupAnimation" Value="None" />
</Trigger>
<Trigger Property="Icon" Value="{x:Null}">
<Setter TargetName="IconRoot" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource MenuFlyoutSubItemBackgroundPointerOver}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource MenuFlyoutSubItemForegroundPointerOver}" />
<Setter TargetName="SubItemChevron" Property="Foreground" Value="{DynamicResource MenuFlyoutSubItemChevronPointerOver}" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource MenuFlyoutSubItemBackgroundPressed}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource MenuFlyoutSubItemForegroundPressed}" />
<Setter TargetName="SubItemChevron" Property="Foreground" Value="{DynamicResource MenuFlyoutSubItemChevronPressed}" />
</Trigger>
<Trigger Property="IsSubmenuOpen" Value="True">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource MenuFlyoutSubItemBackgroundSubMenuOpened}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource MenuFlyoutSubItemForegroundSubMenuOpened}" />
<Setter TargetName="SubItemChevron" Property="Foreground" Value="{DynamicResource MenuFlyoutSubItemChevronSubMenuOpened}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="LayoutRoot" Property="Background" Value="{DynamicResource MenuFlyoutSubItemBackgroundDisabled}" />
<Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{DynamicResource MenuFlyoutSubItemForegroundDisabled}" />
<Setter TargetName="SubItemChevron" Property="Foreground" Value="{DynamicResource MenuFlyoutSubItemChevronDisabled}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="DefaultMenuItemStyle" TargetType="{x:Type MenuItem}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Background" Value="{DynamicResource MenuFlyoutItemBackground}" />
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutItemForeground}" />
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutItemThemePaddingNarrow}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="ScrollViewer.PanningMode" Value="Both" />
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="FocusVisualStyle" Value="{DynamicResource {x:Static SystemParameters.FocusVisualStyleKey}}" />
<Setter Property="ui:FocusVisualHelper.UseSystemFocusVisuals" Value="{DynamicResource UseSystemFocusVisuals}" />
<Setter Property="ui:ControlHelper.CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=SubmenuItemTemplateKey}}" />
<Style.Triggers>
<Trigger Property="Role" Value="TopLevelHeader">
<Setter Property="Background" Value="{DynamicResource MenuBarItemBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource MenuBarItemBorderThickness}" />
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=TopLevelHeaderTemplateKey}}" />
<Setter Property="IsTabStop" Value="True" />
<Setter Property="Height" Value="{StaticResource MenuBarHeight}" />
</Trigger>
<Trigger Property="Role" Value="TopLevelItem">
<Setter Property="Background" Value="{DynamicResource MenuBarItemBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource MenuBarItemBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource MenuBarItemBorderThickness}" />
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=TopLevelItemTemplateKey}}" />
<Setter Property="IsTabStop" Value="True" />
<Setter Property="Height" Value="{StaticResource MenuBarHeight}" />
</Trigger>
<Trigger Property="Role" Value="SubmenuHeader">
<Setter Property="Background" Value="{DynamicResource MenuFlyoutSubItemBackground}" />
<Setter Property="Foreground" Value="{DynamicResource MenuFlyoutSubItemForeground}" />
<Setter Property="Template" Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type MenuItem}, ResourceId=SubmenuHeaderTemplateKey}}" />
</Trigger>
<Trigger Property="IsCheckable" Value="True">
<Setter Property="Background" Value="Transparent" />
<Setter Property="ui:FocusVisualHelper.UseSystemFocusVisuals" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
<Style BasedOn="{StaticResource DefaultMenuItemStyle}" TargetType="{x:Type MenuItem}" />
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="{DynamicResource CustomContextBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource CustomContextBorder}" />
<Setter Property="BorderThickness" Value="{DynamicResource MenuFlyoutPresenterBorderThemeThickness}" />
<Setter Property="Padding" Value="{DynamicResource MenuFlyoutPresenterThemePadding}" />
<Setter Property="FontFamily" Value="{DynamicResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="FontStyle" Value="Normal" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="Grid.IsSharedSizeScope" Value="true" />
<Setter Property="HasDropShadow" Value="{DynamicResource {x:Static SystemParameters.DropShadowKey}}" />
<!--<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />-->
<!--<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />-->
<!--<Setter Property="ScrollViewer.PanningMode" Value="VerticalOnly" />-->
<Setter Property="Stylus.IsFlicksEnabled" Value="False" />
<Setter Property="MaxWidth" Value="{DynamicResource FlyoutThemeMaxWidth}" />
<Setter Property="MinHeight" Value="{DynamicResource MenuFlyoutThemeMinHeight}" />
<Setter Property="ui:ControlHelper.CornerRadius" Value="{DynamicResource OverlayCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border
x:Name="Border"
Margin="5,4,5,12"
Padding="0,4,0,4"
Background="{DynamicResource CustomContextBackground}"
BorderBrush="{DynamicResource CustomContextBorder}"
BorderThickness="1"
CornerRadius="8"
UseLayoutRounding="True">
<Border.Effect>
<DropShadowEffect
BlurRadius="12"
Direction="-90"
Opacity=".15"
ShadowDepth="6"
Color="Black" />
</Border.Effect>
<StackPanel
x:Name="Panel"
ClipToBounds="True"
IsItemsHost="True"
Orientation="Vertical" />
</Border>
<ui:ThemeShadowChrome
x:Name="Shdw"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}"
IsShadowEnabled="{TemplateBinding HasDropShadow}"
SnapsToDevicePixels="True">
<Border
x:Name="Border"
Padding="0,4,0,4"
Background="{DynamicResource CustomContextBackground}"
BorderBrush="{DynamicResource CustomContextBorder}"
BorderThickness="1"
CornerRadius="8">
<Grid>
<ScrollViewer
x:Name="ContextMenuScrollViewer"
MinWidth="{DynamicResource FlyoutThemeMinWidth}"
Margin="{TemplateBinding Padding}"
Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer,
TypeInTargetAssembly={x:Type FrameworkElement}}}">
<ItemsPresenter
KeyboardNavigation.DirectionalNavigation="Cycle"
RenderOptions.ClearTypeHint="Enabled"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
<Border
x:Name="ContextMenuBorder"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="0"
CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}" />
</Grid>
</Border>
</ui:ThemeShadowChrome>
<ControlTemplate.Triggers>
<Trigger Property="IsVisible" Value="true">
<Setter TargetName="Border" Property="Background" Value="{DynamicResource CustomContextBackground}" />
@ -2753,4 +3227,7 @@
</Setter.Value>
</Setter>
</Style>
<ui:TextContextMenu x:Key="TextControlContextMenu" x:Shared="False" />
</ResourceDictionary>

View file

@ -65,10 +65,13 @@
<SolidColorBrush x:Key="CustomContextBorder" Color="#1b1b1b" />
<SolidColorBrush x:Key="CustomContextBackground" Color="#2b2b2b" />
<SolidColorBrush x:Key="CustomContextHover" Color="#3c3c3c" />
<SolidColorBrush x:Key="CustomContextHover" Color="#3a3a3a" />
<SolidColorBrush x:Key="CustomContextClick" Color="#353535" />
<SolidColorBrush x:Key="CustomContextDisabled" Color="#868686" />
<SolidColorBrush x:Key="ContextSeparator" Color="#3c3c3c" />
<SolidColorBrush x:Key="HoverStoreGrid2">#272727</SolidColorBrush>
<Color x:Key="Color01">#202020</Color>
<Color x:Key="Color02">#2b2b2b</Color>
<Color x:Key="Color03">#1d1d1d</Color>

View file

@ -58,10 +58,13 @@
<SolidColorBrush x:Key="CustomContextBorder" Color="#dadada" />
<SolidColorBrush x:Key="CustomContextBackground" Color="#f2f2f2" />
<SolidColorBrush x:Key="CustomContextHover" Color="#DBDBDB" />
<SolidColorBrush x:Key="CustomContextHover" Color="#e4e4e4" />
<SolidColorBrush x:Key="CustomContextClick" Color="#ececec" />
<SolidColorBrush x:Key="CustomContextDisabled" Color="#868686" />
<SolidColorBrush x:Key="ContextSeparator" Color="#dadada" />
<SolidColorBrush x:Key="HoverStoreGrid2">#f6f6f6</SolidColorBrush>
<Color x:Key="Color01">#f3f3f3</Color>
<Color x:Key="Color02">#ffffff</Color>
<Color x:Key="Color03">#e5e5e5</Color>

View file

@ -25,12 +25,17 @@
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"
Visibility="{Binding Visbility}"
mc:Ignorable="d">
mc:Ignorable="d"
PreviewMouseMove="ResultList_MouseMove"
PreviewMouseLeftButtonDown="ResultList_PreviewMouseLeftButtonDown"
PreviewMouseLeftButtonUp="ResultListBox_OnPreviewMouseUp"
PreviewMouseRightButtonDown="ResultListBox_OnPreviewMouseRightButtonDown">
<!-- IsSynchronizedWithCurrentItem: http://stackoverflow.com/a/7833798/2833083 -->
<ListBox.ItemTemplate>
<DataTemplate>
<Button HorizontalAlignment="Stretch">
<Button
HorizontalAlignment="Stretch">
<Button.Template>
<ControlTemplate>
<ContentPresenter Content="{TemplateBinding Button.Content}" />
@ -84,7 +89,7 @@
x:Name="ImageIcon"
Width="{Binding IconXY}"
Height="{Binding IconXY}"
Margin="0,0,0,0"
Margin="0,0,0,0" IsHitTestVisible="False"
HorizontalAlignment="Center"
Source="{Binding Image, TargetNullValue={x:Null}}"
Stretch="Uniform"
@ -136,7 +141,9 @@
DockPanel.Dock="Left"
Style="{DynamicResource ItemTitleStyle}"
Text="{Binding Result.Title}"
ToolTip="{Binding ShowTitleToolTip}">
ToolTip="{Binding ShowTitleToolTip}"
ToolTipService.ShowOnDisabled="True"
IsEnabled="False">
<vm:ResultsViewModel.FormattedText>
<MultiBinding Converter="{StaticResource HighlightTextConverter}">
<Binding Path="Result.Title" />
@ -147,10 +154,11 @@
<TextBlock
x:Name="SubTitle"
Grid.Row="1"
IsEnabled="False"
ToolTipService.ShowOnDisabled="True"
Style="{DynamicResource ItemSubTitleStyle}"
Text="{Binding Result.SubTitle}"
ToolTip="{Binding ShowSubTitleToolTip}" />
ToolTip="{Binding ShowSubTitleToolTip}"/>
</Grid>
</Grid>

View file

@ -1,6 +1,9 @@
using System.Windows;
using System;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Flow.Launcher.ViewModel;
namespace Flow.Launcher
{
@ -14,6 +17,36 @@ namespace Flow.Launcher
InitializeComponent();
}
public static readonly DependencyProperty RightClickResultCommandProperty =
DependencyProperty.Register("RightClickResultCommand", typeof(ICommand), typeof(ResultListBox), new UIPropertyMetadata(null));
public ICommand RightClickResultCommand
{
get
{
return (ICommand)GetValue(RightClickResultCommandProperty);
}
set
{
SetValue(RightClickResultCommandProperty, value);
}
}
public static readonly DependencyProperty LeftClickResultCommandProperty =
DependencyProperty.Register("LeftClickResultCommand", typeof(ICommand), typeof(ResultListBox), new UIPropertyMetadata(null));
public ICommand LeftClickResultCommand
{
get
{
return (ICommand)GetValue(LeftClickResultCommandProperty);
}
set
{
SetValue(LeftClickResultCommandProperty, value);
}
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0 && e.AddedItems[0] != null)
@ -24,7 +57,7 @@ namespace Flow.Launcher
private void OnMouseEnter(object sender, MouseEventArgs e)
{
lock(_lock)
lock (_lock)
{
curItem = (ListBoxItem)sender;
var p = e.GetPosition((IInputElement)sender);
@ -34,7 +67,7 @@ namespace Flow.Launcher
private void OnMouseMove(object sender, MouseEventArgs e)
{
lock(_lock)
lock (_lock)
{
var p = e.GetPosition((IInputElement)sender);
if (_lastpos != p)
@ -46,7 +79,7 @@ namespace Flow.Launcher
private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
lock(_lock)
lock (_lock)
{
if (curItem != null)
{
@ -54,5 +87,65 @@ namespace Flow.Launcher
}
}
}
private Point start;
private string path;
private string query;
private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
return;
path = result.Result.CopyText;
query = result.Result.OriginQuery.RawQuery;
start = e.GetPosition(null);
}
private void ResultList_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed)
{
start = default;
path = string.Empty;
query = string.Empty;
return;
}
if (!File.Exists(path) && !Directory.Exists(path))
return;
Point mousePosition = e.GetPosition(null);
Vector diff = this.start - mousePosition;
if (Math.Abs(diff.X) < SystemParameters.MinimumHorizontalDragDistance
|| Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance)
return;
var data = new DataObject(DataFormats.FileDrop, new[]
{
path
});
DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
App.API.ChangeQuery(query, true);
e.Handled = true;
}
private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
return;
RightClickResultCommand?.Execute(result.Result);
}
private void ResultListBox_OnPreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
return;
LeftClickResultCommand?.Execute(null);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,31 +1,28 @@
using Droplex;
using Flow.Launcher.Core.ExternalPlugins;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Core.Resource;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.ViewModel;
using Microsoft.Win32;
using ModernWpf;
using ModernWpf.Controls;
using System;
using System.Drawing.Printing;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Navigation;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;
using Button = System.Windows.Controls.Button;
using Control = System.Windows.Controls.Control;
using ListViewItem = System.Windows.Controls.ListViewItem;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using MessageBox = System.Windows.MessageBox;
using TextBox = System.Windows.Controls.TextBox;
@ -68,6 +65,7 @@ namespace Flow.Launcher
pluginStoreView.Filter = PluginStoreFilter;
InitializePosition();
ClockDisplay();
}
private void OnSelectPythonFilePathClick(object sender, RoutedEventArgs e)
@ -150,7 +148,7 @@ namespace Flow.Launcher
}
}
private void OnnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
private void OnEditCustomHotkeyClick(object sender, RoutedEventArgs e)
{
var item = viewModel.SelectedCustomPluginHotkey;
if (item != null)
@ -248,6 +246,7 @@ namespace Flow.Launcher
private void OnClosed(object sender, EventArgs e)
{
settings.SettingWindowState = WindowState;
settings.SettingWindowTop = Top;
settings.SettingWindowLeft = Left;
viewModel.Save();
@ -292,20 +291,69 @@ namespace Flow.Launcher
}
}
private void OnPluginStoreRefreshClick(object sender, RoutedEventArgs e)
private static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
_ = viewModel.RefreshExternalPluginsAsync();
}
//get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
return parent;
else
return FindParent<T>(parentObject);
}
private void OnExternalPluginInstallClick(object sender, RoutedEventArgs e)
{
if (sender is Button { DataContext: UserPlugin plugin })
if (sender is not Button { DataContext: PluginStoreItemViewModel plugin } button)
{
var pluginsManagerPlugin = PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7");
var actionKeyword = pluginsManagerPlugin.Metadata.ActionKeywords.Count == 0 ? "" : pluginsManagerPlugin.Metadata.ActionKeywords[0];
API.ChangeQuery($"{actionKeyword} install {plugin.Name}");
API.ShowMainWindow();
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 */
@ -358,11 +406,34 @@ namespace Flow.Launcher
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();
}
}
private void OnAddCustomShortCutClick(object sender, RoutedEventArgs e)
{
viewModel.AddCustomShortcut();
}
#endregion
private CollectionView pluginListView;
private CollectionView pluginStoreView;
@ -381,7 +452,7 @@ namespace Flow.Launcher
{
if (string.IsNullOrEmpty(pluginStoreFilterTxb.Text))
return true;
if (item is UserPlugin model)
if (item is PluginStoreItemViewModel model)
{
return StringMatcher.FuzzySearch(pluginStoreFilterTxb.Text, model.Name).IsSearchPrecisionScoreMet()
|| StringMatcher.FuzzySearch(pluginStoreFilterTxb.Text, model.Description).IsSearchPrecisionScoreMet();
@ -436,6 +507,34 @@ namespace Flow.Launcher
}
}
private void PreviewClockAndDate(object sender, RoutedEventArgs e)
{
ClockDisplay();
}
public void ClockDisplay()
{
if (settings.UseClock)
{
ClockBox.Visibility = Visibility.Visible;
ClockBox.Text = DateTime.Now.ToString(settings.TimeFormat);
}
else
{
ClockBox.Visibility = Visibility.Collapsed;
}
if (settings.UseDate)
{
DateBox.Visibility = Visibility.Visible;
DateBox.Text = DateTime.Now.ToString(settings.DateFormat);
}
else
{
DateBox.Visibility = Visibility.Collapsed;
}
}
public void InitializePosition()
{
if (settings.SettingWindowTop >= 0 && settings.SettingWindowLeft >= 0)
@ -448,6 +547,7 @@ namespace Flow.Launcher
Top = WindowTop();
Left = WindowLeft();
}
WindowState = settings.SettingWindowState;
}
public double WindowLeft()
{
@ -466,16 +566,21 @@ namespace Flow.Launcher
var top = (dip2.Y - this.ActualHeight) / 2 + dip1.Y - 20;
return top;
}
private void OnExternalPluginUninstallClick(object sender, MouseButtonEventArgs e)
private Button storeClickedButton;
private void StoreListItem_Click(object sender, RoutedEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
if (sender is not Button button)
return;
storeClickedButton = button;
var flyout = FlyoutService.GetFlyout(button);
flyout.Closed += (_, _) =>
{
var id = viewModel.SelectedPlugin.PluginPair.Metadata.Name;
var pluginsManagerPlugin = PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7");
var actionKeyword = pluginsManagerPlugin.Metadata.ActionKeywords.Count == 0 ? "" : pluginsManagerPlugin.Metadata.ActionKeywords[0];
API.ChangeQuery($"{actionKeyword} uninstall {id}");
API.ShowMainWindow();
}
storeClickedButton = null;
};
}
}

View file

@ -1,64 +1,100 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#9fb2bf" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#515a6b"/>
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#515a6b" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Background" Value="#282c34" />
<Setter Property="Foreground" Value="#61afef" />
<Setter Property="CaretBrush" Value="#ffb86c" />
<Setter Property="FontSize" Value="26" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
<Setter Property="Height" Value="42" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#282c34" />
<Setter Property="Foreground" Value="#454e61" />
<Setter Property="FontSize" Value="26" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
<Setter Property="Height" Value="42" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="#44475a" />
<Setter Property="CornerRadius" Value="5" />
<Setter Property="Background" Value="#282c34" />
</Style>
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}">
<Setter Property="Width" Value="576" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
</Style>
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#9fb2bf" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6272a4 " />
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6272a4" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#e5c07b" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#c678dd" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#2c313c</SolidColorBrush>
<Style x:Key="ItemImageSelectedStyle" BasedOn="{StaticResource BaseItemImageSelectedStyle}" TargetType="{x:Type Image}" >
<Style
x:Key="ItemImageSelectedStyle"
BasedOn="{StaticResource BaseItemImageSelectedStyle}"
TargetType="{x:Type Image}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<Style x:Key="HighlightStyle">
@ -68,36 +104,67 @@
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#6272a4" />
</Style>
<Style x:Key="ItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}">
<Style
x:Key="ItemHotkeySelectedStyle"
BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#56b6c2" />
</Style>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Width" Value="2"/>
<Setter Property="Focusable" Value="false"/>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Width" Value="2" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#b4b5b7" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#b4b5b7"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#495162" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="12,0,12,8" />
</Style>
<Style x:Key="SeparatorStyle" BasedOn="{StaticResource BaseSeparatorStyle}" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#495162"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Margin" Value="12 0 12 8"/>
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#495162" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Opacity" Value="0.8" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#495162" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#495162" />
</Style>
</ResourceDictionary>

View file

@ -79,6 +79,83 @@
<Setter Property="Stroke" Value="Blue" />
</Style>
<Style x:Key="BaseClockPosition" TargetType="{x:Type Canvas}" />
<Style x:Key="BaseClockPanel" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Height" Value="Auto" />
<Setter Property="Margin" Value="0,0,14,0" />
<Setter Property="Visibility" Value="Collapsed" />
</Style>
<Style x:Key="BaseClockBox" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="22" />
<Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,2,0" />
</Style>
<Style x:Key="BaseDateBox" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="16" />
<Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,10,0" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#C6C6C6" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#C6C6C6" />
</Style>
<Style
x:Key="ClockPanel"
BasedOn="{StaticResource BaseClockPanel}"
TargetType="{x:Type StackPanel}">
<Setter Property="Margin" Value="0,0,66,0" />
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=QueryTextBox, UpdateSourceTrigger=PropertyChanged, Path=Text.Length}" Value="0" />
<Condition Binding="{Binding ElementName=ContextMenu, Path=Visibility}" Value="Collapsed" />
<Condition Binding="{Binding ElementName=History, Path=Visibility}" Value="Collapsed" />
</MultiDataTrigger.Conditions>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
From="0.0"
To="1.0"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
<MultiDataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="Opacity"
To="0.0"
Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.ExitActions>
</MultiDataTrigger>
</Style.Triggers>
</Style>
<!-- Item Style -->
<Style x:Key="ProgressBarResult" TargetType="{x:Type ProgressBar}">

View file

@ -7,6 +7,7 @@
</ResourceDictionary.MergedDictionaries>
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="0" />
</Style>
@ -36,6 +37,7 @@
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#444444" />
<Setter Property="CornerRadius" Value="0" />
@ -140,4 +142,18 @@
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="Opacity" Value="0.2" />
</Style>
</ResourceDictionary>

View file

@ -50,7 +50,7 @@
TargetType="{x:Type Window}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Opacity="0.5" />
<SolidColorBrush Opacity="0.5" Color="White" />
</Setter.Value>
</Setter>
</Style>
@ -143,4 +143,18 @@
<Setter Property="Foreground" Value="#000000" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#000000" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#000000" />
<Setter Property="Opacity" Value="0.2" />
</Style>
</ResourceDictionary>

View file

@ -1,84 +1,131 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ebebeb" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="#ebebeb" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent" />
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="Transparent" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="5" />
<Setter Property="BorderThickness" Value="1 1 0 0" />
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="5" />
<Setter Property="BorderThickness" Value="1,1,0,0" />
<Setter Property="BorderBrush" Value="#666666" />
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="#333333" Opacity="0.95"/>
<SolidColorBrush Opacity="0.95" Color="#333333" />
</Setter.Value>
</Setter>
</Style>
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="White" Opacity="0.5"/>
<SolidColorBrush Opacity="0.5" Color="White" />
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
</Style>
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="0, -10"/>
<Setter Property="Foreground" Value="#ebebeb"/>
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="0,-10" />
<Setter Property="Foreground" Value="#ebebeb" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Foreground" Value="#787878"/>
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#787878" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Margin" Value="0, -10"/>
<Setter Property="Foreground" Value="#ffffff"/>
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="0,-10" />
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Foreground" Value="#949494"/>
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#949494" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#545454</SolidColorBrush>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#525252" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#525252"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="#a0a0a0"/>
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="#a0a0a0" />
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#FFFFFF" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style x:Key="SeparatorStyle" BasedOn="{StaticResource BaseSeparatorStyle}" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#787878"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Margin" Value="0 0 0 8"/>
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#787878" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="0,0,0,8" />
<Setter Property="Opacity" Value="0.3" />
</Style>
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
@ -91,5 +138,16 @@
<Setter Property="Foreground" Value="#787878" />
<Setter Property="Opacity" Value="0.1" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#787878" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#787878" />
</Style>
</ResourceDictionary>

View file

@ -1,51 +1,97 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#6e6e6e"/>
<Setter Property="SelectionBrush" Value="#4D4D4D"/>
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#6e6e6e" />
<Setter Property="SelectionBrush" Value="#4D4D4D" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="#8f8f8f" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
</Style>
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}" />
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
</Style>
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
</Style>
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}" />
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8f8f8f" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8f8f8f" />
<Setter Property="Cursor" Value="Arrow" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#4d4d4d</SolidColorBrush>
<Style x:Key="ItemImageSelectedStyle" BasedOn="{StaticResource BaseItemImageSelectedStyle}" TargetType="{x:Type Image}" >
<Style
x:Key="ItemImageSelectedStyle"
BasedOn="{StaticResource BaseItemImageSelectedStyle}"
TargetType="{x:Type Image}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
</Style>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}" />
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6e6e6e" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6e6e6e" />
</Style>
</ResourceDictionary>

View file

@ -1,64 +1,101 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="#dcddde" />
<Setter Property="Background" Value="#36393f" />
<Setter Property="CaretBrush" Value="#ffffff" />
<Setter Property="SelectionBrush" Value="#0a68d8"/>
<Setter Property="SelectionBrush" Value="#0a68d8" />
<Setter Property="Height" Value="42" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Padding" Value="0 0 66 0" />
<Setter Property="Padding" Value="0,0,66,0" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="#72767d" />
<Setter Property="Background" Value="#36393f" />
<Setter Property="Height" Value="42" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Padding" Value="0 0 66 0" />
<Setter Property="Padding" Value="0,0,66,0" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="#2f3136" />
<Setter Property="CornerRadius" Value="4" />
<Setter Property="Background" Value="#36393f" />
</Style>
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}">
<Setter Property="Width" Value="576" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="#ffffff" />
<Setter Property="Opacity" Value="0.6" />
</Style>
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#dcddde" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#72767d" />
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#A6A6A6" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#32bd6a" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#72767d" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#49443c</SolidColorBrush>
<Style x:Key="ItemImageSelectedStyle" BasedOn="{StaticResource BaseItemImageSelectedStyle}" TargetType="{x:Type Image}" >
<Style
x:Key="ItemImageSelectedStyle"
BasedOn="{StaticResource BaseItemImageSelectedStyle}"
TargetType="{x:Type Image}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<Style x:Key="HighlightStyle">
@ -74,30 +111,58 @@
<Setter Property="Foreground" Value="#72767d" />
<Setter Property="Opacity" Value="0.8" />
</Style>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="false"/>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#202225" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#202225"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#42454a" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="12,0,12,8" />
</Style>
<Style x:Key="SeparatorStyle" BasedOn="{StaticResource BaseSeparatorStyle}" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#42454a"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Margin" Value="12 0 12 8"/>
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#42454a" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#72767d" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#72767d" />
</Style>
</ResourceDictionary>

View file

@ -1,64 +1,100 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#f8f8f2" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#ff79c6"/>
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#ff79c6" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Background" Value="#282a36" />
<Setter Property="Foreground" Value="#f8f8f2" />
<Setter Property="CaretBrush" Value="#ffb86c" />
<Setter Property="FontSize" Value="26" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
<Setter Property="Height" Value="42" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#282a36" />
<Setter Property="Foreground" Value="#6272a4" />
<Setter Property="FontSize" Value="26" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
<Setter Property="Height" Value="42" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="#44475a" />
<Setter Property="CornerRadius" Value="5" />
<Setter Property="Background" Value="#282a36" />
</Style>
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}">
<Setter Property="Width" Value="576" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
</Style>
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#f8f8f2" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6272a4" />
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6272a4" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#ff79c6" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#6272a4" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#44475a</SolidColorBrush>
<Style x:Key="ItemImageSelectedStyle" BasedOn="{StaticResource BaseItemImageSelectedStyle}" TargetType="{x:Type Image}" >
<Style
x:Key="ItemImageSelectedStyle"
BasedOn="{StaticResource BaseItemImageSelectedStyle}"
TargetType="{x:Type Image}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<Style x:Key="HighlightStyle">
@ -68,36 +104,67 @@
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#6272a4" />
</Style>
<Style x:Key="ItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}">
<Style
x:Key="ItemHotkeySelectedStyle"
BasedOn="{StaticResource BaseItemHotkeySelecetedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#ff79c6" />
</Style>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Width" Value="2"/>
<Setter Property="Focusable" Value="false"/>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Width" Value="2" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#44475a" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#44475a"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#44475a" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="12,0,12,8" />
</Style>
<Style x:Key="SeparatorStyle" BasedOn="{StaticResource BaseSeparatorStyle}" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#44475a"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Margin" Value="12 0 12 8"/>
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#6272a4" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Opacity" Value="0.8" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6272a4" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6272a4" />
</Style>
</ResourceDictionary>

View file

@ -1,61 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Foreground" Value="#222222" />
</Style>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#000000" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Foreground" Value="#b8b8b8" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="LightGray" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Background" Value="LightGray"></Setter>
<Setter Property="Background" Value="LightGray" />
</Style>
<Style x:Key="WindowStyle" TargetType="{x:Type Window}" BasedOn="{StaticResource BaseWindowStyle}" >
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}" />
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#333333" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#A6A6A6" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#818181" />
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="White" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Silver" />
<Setter Property="FontSize" Value="13" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#787878</SolidColorBrush>
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#eeeeee" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#eeeeee"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}" >
<Setter Property="Width" Value="3"/>
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}">
<Setter Property="Width" Value="3" />
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#a4a4a4" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
@ -67,5 +113,17 @@
<Style x:Key="ItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}">
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#a3a3a3" />
</Style>
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#818181" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#818181" />
</Style>
</ResourceDictionary>

View file

@ -118,5 +118,16 @@
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#4bb44b" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#4bb44b" />
</Style>
</ResourceDictionary>

View file

@ -1,48 +1,83 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml"></ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="#FFFFFF" />
<Setter Property="Background" Value="#001e4e"/>
<Setter Property="Padding" Value="0 0 18 0" />
<Setter Property="Background" Value="#001e4e" />
<Setter Property="Padding" Value="0,0,18,0" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="#344c71" />
<Setter Property="Background" Value="#001e4e" />
<Setter Property="Padding" Value="0 0 18 0" />
<Setter Property="Padding" Value="0,0,18,0" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Setter Property="Background" Value="#001e4e"></Setter>
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="Background" Value="#001e4e" />
</Style>
<Style x:Key="WindowStyle" TargetType="{x:Type Window}" BasedOn="{StaticResource BaseWindowStyle}" >
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}" >
</Style>
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Foreground" Value="#f5f5f5"></Setter>
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Foreground" Value="#A5A5A5"></Setter>
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}" />
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#f5f5f5" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#A5A5A5"></Setter>
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#A5A5A5" />
<Setter Property="FontSize" Value="13" />
</Style>
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#f5f5f5" />
</Style>
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#A5A5A5" />
<Setter Property="FontSize" Value="13" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#04152E</SolidColorBrush>
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}" />
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#1d427d" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
@ -56,4 +91,23 @@
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#2C5595" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#2C5595" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#2C5595" />
</Style>
<Style
x:Key="ClockPanel"
BasedOn="{StaticResource BaseClockPanel}"
TargetType="{x:Type StackPanel}">
<Setter Property="Margin" Value="0,0,22,0" />
<Setter Property="Visibility" Value="Visible" />
</Style>
</ResourceDictionary>

View file

@ -1,64 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#2e3440" />
<Setter Property="Foreground" Value="#eceff4" />
<Setter Property="FontSize" Value="30" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#2e3440" />
<Setter Property="Foreground" Value="#50596b" />
<Setter Property="FontSize" Value="30" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="#4c566a" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="#2e3440"></Setter>
<Setter Property="Background" Value="#2e3440" />
</Style>
<Style x:Key="WindowStyle" TargetType="{x:Type Window}" BasedOn="{StaticResource BaseWindowStyle}" >
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="White" />
</Style>
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#e5e9f0" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6F7C95" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#606c83" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#e5e9f0" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8391AB" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#4e586b</SolidColorBrush>
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#B2B6BE" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#B2B6BE"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}" >
<Setter Property="Width" Value="3"/>
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}">
<Setter Property="Width" Value="3" />
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#50596b" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
@ -71,4 +117,16 @@
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#8391AB" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6F7C95" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#6F7C95" />
</Style>
</ResourceDictionary>

View file

@ -1,63 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" ?>
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#4c566a" />
<Setter Property="Foreground" Value="#eceff4" />
<Setter Property="FontSize" Value="25" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#4c566a" />
<Setter Property="Foreground" Value="#eceff4" />
<Setter Property="FontSize" Value="25" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="#2e3440" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value="#4c566a"></Setter>
<Setter Property="Background" Value="#4c566a" />
</Style>
<Style x:Key="WindowStyle" TargetType="{x:Type Window}" BasedOn="{StaticResource BaseWindowStyle}" >
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="White" />
</Style>
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#e5e9f0" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#798090" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#798090" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#FFFFFF" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#9498A0" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#596479</SolidColorBrush>
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#2e3440" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#2e3440"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}" >
<Setter Property="Width" Value="3"/>
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}">
<Setter Property="Width" Value="3" />
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#687693" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
@ -70,4 +116,16 @@
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#687693" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8394B6" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#8394B6" />
</Style>
</ResourceDictionary>

View file

@ -1,63 +1,102 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml"></ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ffffff" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#1f1d1f"/>
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#1f1d1f" />
<Setter Property="Foreground" Value="#cc1081" />
<Setter Property="CaretBrush" Value="#cc1081" />
<Setter Property="SelectionBrush" Value="#e564b1"/>
<Setter Property="SelectionBrush" Value="#e564b1" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#1f1d1f"/>
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#1f1d1f" />
<Setter Property="Foreground" Value="#71114b" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Setter Property="Background" Value="#1f1d1f"></Setter>
<Setter Property="BorderThickness" Value="2"></Setter>
<Setter Property="BorderBrush" Value="#000000"></Setter>
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="Background" Value="#1f1d1f" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="#000000" />
</Style>
<Style x:Key="WindowStyle" TargetType="{x:Type Window}" BasedOn="{StaticResource BaseWindowStyle}" >
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}" />
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="#cc1081" />
</Style>
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Foreground" Value="#f5f5f5"></Setter>
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Setter Property="Foreground" Value="#c2c2c2"></Setter>
<Setter Property="Opacity" Value="0.5"></Setter>
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#f5f5f5" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#c2c2c2" />
<Setter Property="Opacity" Value="0.5" />
</Style>
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#f5f5f5" />
</Style>
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#ed92c9" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#cc1081</SolidColorBrush>
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#e564b1" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#e564b1"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
</Style>
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Geometry x:Key="SearchIconImg">F1 M20,20z M0,0z M14.75,1A5.24,5.24,0,0,0,10,4A5.24,5.24,0,0,0,0,6.25C0,11.75 10,19 10,19 10,19 20,11.75 20,6.25A5.25,5.25,0,0,0,14.75,1z</Geometry>
<Style x:Key="SearchIconPosition" TargetType="{x:Type Canvas}">
<Setter Property="Width" Value="34" />
<Setter Property="Height" Value="34" />
<Setter Property="Margin" Value="0 6 14 0" />
<Setter Property="Margin" Value="0,6,14,0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
@ -74,4 +113,16 @@
<Setter Property="FontSize" Value="14" />
<Setter Property="Foreground" Value="#ed92c9" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#71114b" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#71114b" />
</Style>
</ResourceDictionary>

View file

@ -1,64 +1,101 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#5bafb0" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="24" />
<Setter Property="Background" Value="#303840" />
<Setter Property="Foreground" Value="#d2d8e5" />
<Setter Property="CaretBrush" Value="#FFAA47" />
<Setter Property="FontSize" Value="26" />
<Setter Property="Height" Value="42" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#303840" />
<Setter Property="Foreground" Value="#798189" />
<Setter Property="FontSize" Value="26" />
<Setter Property="Height" Value="42" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="#6c7279" />
<Setter Property="CornerRadius" Value="6" />
<Setter Property="Background" Value="#303840" />
</Style>
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}">
<Setter Property="Width" Value="576" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="#FFAA47" />
</Style>
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#5989b2" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#7b858f" />
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#7b858f" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#5bafb0" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#cc8ec8" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#3c454e</SolidColorBrush>
<Style x:Key="ItemImageSelectedStyle" BasedOn="{StaticResource BaseItemImageSelectedStyle}" TargetType="{x:Type Image}" >
<Style
x:Key="ItemImageSelectedStyle"
BasedOn="{StaticResource BaseItemImageSelectedStyle}"
TargetType="{x:Type Image}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<Style x:Key="HighlightStyle">
@ -72,31 +109,59 @@
<Setter Property="FontSize" Value="13" />
<Setter Property="Foreground" Value="#ea7354" />
</Style>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Width" Value="2"/>
<Setter Property="Focusable" Value="false"/>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Width" Value="2" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#6c7279" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#6c7279"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#3c454e" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="0,0,0,8" />
</Style>
<Style x:Key="SeparatorStyle" BasedOn="{StaticResource BaseSeparatorStyle}" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#3c454e"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Margin" Value="0 0 0 8"/>
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#3c454e" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#5bafb0" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#5bafb0" />
</Style>
</ResourceDictionary>

View file

@ -1,67 +1,104 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ItemGlyph" BasedOn="{StaticResource BaseGlyphStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemGlyph"
BasedOn="{StaticResource BaseGlyphStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#000000" />
</Style>
<Style x:Key="QueryBoxStyle" BasedOn="{StaticResource BaseQueryBoxStyle}" TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#0a68d8"/>
<Style
x:Key="QueryBoxStyle"
BasedOn="{StaticResource BaseQueryBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="SelectionBrush" Value="#0a68d8" />
<Setter Property="FontSize" Value="24" />
<Setter Property="Foreground" Value="#000000" />
<Setter Property="Background" Value="#dddddd" />
<Setter Property="CaretBrush" Value="#000000" />
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FontSize" Value="28" />
<Setter Property="Height" Value="42" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
</Style>
<Style x:Key="QuerySuggestionBoxStyle" BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}" TargetType="{x:Type TextBox}">
<Style
x:Key="QuerySuggestionBoxStyle"
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="#dddddd" />
<Setter Property="Foreground" Value="#c6c6c6" />
<Setter Property="FontSize" Value="28" />
<Setter Property="Padding" Value="0 4 66 0" />
<Setter Property="Padding" Value="0,4,66,0" />
<Setter Property="Height" Value="42" />
</Style>
<Style x:Key="WindowBorderStyle" BasedOn="{StaticResource BaseWindowBorderStyle}" TargetType="{x:Type Border}">
<Style
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="#aaaaaa" />
<Setter Property="CornerRadius" Value="0" />
<Setter Property="Background" Value="#dddddd" />
</Style>
<Style x:Key="WindowStyle" BasedOn="{StaticResource BaseWindowStyle}" TargetType="{x:Type Window}">
<Style
x:Key="WindowStyle"
BasedOn="{StaticResource BaseWindowStyle}"
TargetType="{x:Type Window}">
<Setter Property="Width" Value="576" />
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled" />
</Style>
<Style x:Key="PendingLineStyle" BasedOn="{StaticResource BasePendingLineStyle}" TargetType="{x:Type Line}">
<Style
x:Key="PendingLineStyle"
BasedOn="{StaticResource BasePendingLineStyle}"
TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="#0a68d8" />
</Style>
<!-- Item Style -->
<Style x:Key="ItemTitleStyle" BasedOn="{StaticResource BaseItemTitleStyle}" TargetType="{x:Type TextBlock}">
<!-- Item Style -->
<Style
x:Key="ItemTitleStyle"
BasedOn="{StaticResource BaseItemTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#000000" />
</Style>
<Style x:Key="ItemSubTitleStyle" BasedOn="{StaticResource BaseItemSubTitleStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleStyle"
BasedOn="{StaticResource BaseItemSubTitleStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#818181" />
<Setter Property="FontSize" Value="13" />
</Style>
<Style x:Key="ItemNumberStyle" BasedOn="{StaticResource BaseItemNumberStyle}" TargetType="{x:Type TextBlock}">
<Style
x:Key="ItemNumberStyle"
BasedOn="{StaticResource BaseItemNumberStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#818181" />
</Style>
<Style x:Key="ItemTitleSelectedStyle" BasedOn="{StaticResource BaseItemTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemTitleSelectedStyle"
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#000000" />
</Style>
<Style x:Key="ItemSubTitleSelectedStyle" BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}" TargetType="{x:Type TextBlock}" >
<Style
x:Key="ItemSubTitleSelectedStyle"
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
TargetType="{x:Type TextBlock}">
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Foreground" Value="#72767d" />
</Style>
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#ccd0d4</SolidColorBrush>
<Style x:Key="ItemImageSelectedStyle" BasedOn="{StaticResource BaseItemImageSelectedStyle}" TargetType="{x:Type Image}" >
<Style
x:Key="ItemImageSelectedStyle"
BasedOn="{StaticResource BaseItemImageSelectedStyle}"
TargetType="{x:Type Image}">
<Setter Property="Cursor" Value="Arrow" />
</Style>
<Style x:Key="HighlightStyle">
@ -75,31 +112,59 @@
<Setter Property="FontSize" Value="15" />
<Setter Property="Foreground" Value="#b2b2b2" />
</Style>
<!-- button style in the middle of the scrollbar -->
<Style x:Key="ThumbStyle" BasedOn="{StaticResource BaseThumbStyle}" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="IsTabStop" Value="false"/>
<Setter Property="Focusable" Value="false"/>
<!-- button style in the middle of the scrollbar -->
<Style
x:Key="ThumbStyle"
BasedOn="{StaticResource BaseThumbStyle}"
TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Focusable" Value="false" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="2" DockPanel.Dock="Right" Background="#bebebe" BorderBrush="Transparent" BorderThickness="0" />
<Border
Background="#bebebe"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
DockPanel.Dock="Right" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ScrollBarStyle" BasedOn="{StaticResource BaseScrollBarStyle}" TargetType="{x:Type ScrollBar}">
<Style
x:Key="ScrollBarStyle"
BasedOn="{StaticResource BaseScrollBarStyle}"
TargetType="{x:Type ScrollBar}" />
<Style
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#c6c6c6" />
<Setter Property="Height" Value="1" />
<Setter Property="Margin" Value="12,0,12,8" />
</Style>
<Style x:Key="SeparatorStyle" BasedOn="{StaticResource BaseSeparatorStyle}" TargetType="{x:Type Rectangle}">
<Setter Property="Fill" Value="#c6c6c6"/>
<Setter Property="Height" Value="1"/>
<Setter Property="Margin" Value="12 0 12 8"/>
</Style>
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}" BasedOn="{StaticResource BaseSearchIconStyle}">
<Style
x:Key="SearchIconStyle"
BasedOn="{StaticResource BaseSearchIconStyle}"
TargetType="{x:Type Path}">
<Setter Property="Fill" Value="#555555" />
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#b2b2b2" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#b2b2b2" />
</Style>
</ResourceDictionary>

View file

@ -156,4 +156,16 @@
<Setter Property="Width" Value="32" />
<Setter Property="Height" Value="32" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#7b7b7b" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#7b7b7b" />
</Style>
</ResourceDictionary>

View file

@ -164,4 +164,16 @@
<Setter Property="Height" Value="32" />
<Setter Property="Opacity" Value="0.2" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#acacac" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="#acacac" />
</Style>
</ResourceDictionary>

View file

@ -156,4 +156,16 @@
<Setter Property="Height" Value="32" />
<Setter Property="Opacity" Value="1" />
</Style>
<Style
x:Key="ClockBox"
BasedOn="{StaticResource BaseClockBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{DynamicResource HotkeyForeground}" />
</Style>
<Style
x:Key="DateBox"
BasedOn="{StaticResource BaseDateBox}"
TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{DynamicResource HotkeyForeground}" />
</Style>
</ResourceDictionary>

View file

@ -17,6 +17,7 @@ using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Storage;
using Flow.Launcher.Infrastructure.Logger;
using Microsoft.VisualStudio.Threading;
using System.Text;
using System.Threading.Channels;
using ISavable = Flow.Launcher.Plugin.ISavable;
using System.IO;
@ -38,7 +39,6 @@ namespace Flow.Launcher.ViewModel
private readonly FlowLauncherJsonStorage<History> _historyItemsStorage;
private readonly FlowLauncherJsonStorage<UserSelectedRecord> _userSelectedRecordStorage;
private readonly FlowLauncherJsonStorage<TopMostRecord> _topMostRecordStorage;
internal readonly Settings _settings;
private readonly History _history;
private readonly UserSelectedRecord _userSelectedRecord;
private readonly TopMostRecord _topMostRecord;
@ -61,8 +61,8 @@ namespace Flow.Launcher.ViewModel
_queryText = "";
_lastQuery = new Query();
_settings = settings;
_settings.PropertyChanged += (_, args) =>
Settings = settings;
Settings.PropertyChanged += (_, args) =>
{
if (args.PropertyName == nameof(Settings.WindowSize))
{
@ -77,15 +77,26 @@ namespace Flow.Launcher.ViewModel
_userSelectedRecord = _userSelectedRecordStorage.Load();
_topMostRecord = _topMostRecordStorage.Load();
ContextMenu = new ResultsViewModel(_settings);
Results = new ResultsViewModel(_settings);
History = new ResultsViewModel(_settings);
InitializeKeyCommands();
ContextMenu = new ResultsViewModel(Settings)
{
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand
};
Results = new ResultsViewModel(Settings)
{
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand
};
History = new ResultsViewModel(Settings)
{
LeftClickResultCommand = OpenResultCommand, RightClickResultCommand = LoadContextMenuCommand
};
_selectedResults = Results;
InitializeKeyCommands();
RegisterViewUpdate();
RegisterResultsUpdatedEvent();
RegisterClockAndDateUpdateAsync();
SetOpenResultModifiers();
}
@ -198,15 +209,10 @@ namespace Flow.Launcher.ViewModel
PluginManager.API.OpenUrl("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/");
});
OpenSettingCommand = new RelayCommand(_ => { App.API.OpenSettingDialog(); });
OpenResultCommand = new RelayCommand(async index =>
OpenResultCommand = new AsyncRelayCommand(async _ =>
{
var results = SelectedResults;
if (index != null)
{
results.SelectedIndex = int.Parse(index.ToString()!);
}
var result = results.SelectedItem?.Result;
if (result == null)
{
@ -321,6 +327,22 @@ namespace Flow.Launcher.ViewModel
#region ViewModel Properties
public Settings Settings { get; }
public object ClockText { get; private set; }
public string DateText { get; private set; }
private async Task RegisterClockAndDateUpdateAsync()
{
var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
// ReSharper disable once MethodSupportsCancellation
while (await timer.WaitForNextTickAsync().ConfigureAwait(false))
{
if (Settings.UseClock)
ClockText = DateTime.Now.ToString(Settings.TimeFormat);
if (Settings.UseDate)
DateText = DateTime.Now.ToString(Settings.DateFormat);
}
}
public ResultsViewModel Results { get; private set; }
public ResultsViewModel ContextMenu { get; private set; }
@ -344,14 +366,14 @@ namespace Flow.Launcher.ViewModel
[RelayCommand]
private void IncreaseWidth()
{
if (MainWindowWidth + 100 > 1920 || _settings.WindowSize == 1920)
if (MainWindowWidth + 100 > 1920 || Settings.WindowSize == 1920)
{
_settings.WindowSize = 1920;
Settings.WindowSize = 1920;
}
else
{
_settings.WindowSize += 100;
_settings.WindowLeft -= 50;
else
{
Settings.WindowSize += 100;
Settings.WindowLeft -= 50;
}
OnPropertyChanged();
}
@ -359,14 +381,14 @@ namespace Flow.Launcher.ViewModel
[RelayCommand]
private void DecreaseWidth()
{
if (MainWindowWidth - 100 < 400 || _settings.WindowSize == 400)
if (MainWindowWidth - 100 < 400 || Settings.WindowSize == 400)
{
_settings.WindowSize = 400;
Settings.WindowSize = 400;
}
else
{
_settings.WindowLeft += 50;
_settings.WindowSize -= 100;
{
Settings.WindowLeft += 50;
Settings.WindowSize -= 100;
}
OnPropertyChanged();
}
@ -374,19 +396,19 @@ namespace Flow.Launcher.ViewModel
[RelayCommand]
private void IncreaseMaxResult()
{
if (_settings.MaxResultsToShow == 17)
if (Settings.MaxResultsToShow == 17)
return;
_settings.MaxResultsToShow += 1;
Settings.MaxResultsToShow += 1;
}
[RelayCommand]
private void DecreaseMaxResult()
{
if (_settings.MaxResultsToShow == 2)
if (Settings.MaxResultsToShow == 2)
return;
_settings.MaxResultsToShow -= 1;
Settings.MaxResultsToShow -= 1;
}
/// <summary>
@ -466,8 +488,8 @@ namespace Flow.Launcher.ViewModel
public double MainWindowWidth
{
get => _settings.WindowSize;
set => _settings.WindowSize = value;
get => Settings.WindowSize;
set => Settings.WindowSize = value;
}
public string PluginIconPath { get; set; } = null;
@ -605,7 +627,9 @@ namespace Flow.Launcher.ViewModel
{
_updateSource?.Cancel();
if (string.IsNullOrWhiteSpace(QueryText))
var query = ConstructQuery(QueryText, Settings.CustomShortcuts, Settings.BuiltinShortcuts);
if (query == null) // shortcut expanded
{
Results.Clear();
Results.Visbility = Visibility.Collapsed;
@ -630,7 +654,6 @@ namespace Flow.Launcher.ViewModel
if (currentCancellationToken.IsCancellationRequested)
return;
var query = QueryBuilder.Build(QueryText, PluginManager.NonGlobalPlugins);
// handle the exclusiveness of plugin using action keyword
RemoveOldQueryResults(query);
@ -720,6 +743,40 @@ namespace Flow.Launcher.ViewModel
}
}
private Query ConstructQuery(string queryText, IEnumerable<CustomShortcutModel> customShortcuts, IEnumerable<BuiltinShortcutModel> builtInShortcuts)
{
if (string.IsNullOrWhiteSpace(queryText))
{
return null;
}
StringBuilder queryBuilder = new(queryText);
StringBuilder queryBuilderTmp = new(queryText);
foreach (var shortcut in customShortcuts)
{
if (queryBuilder.Equals(shortcut.Key))
{
queryBuilder.Replace(shortcut.Key, shortcut.Expand());
}
queryBuilder.Replace('@' + shortcut.Key, shortcut.Expand());
}
foreach (var shortcut in builtInShortcuts)
{
queryBuilder.Replace(shortcut.Key, shortcut.Expand());
queryBuilderTmp.Replace(shortcut.Key, shortcut.Expand());
}
// show expanded builtin shortcuts
// use private field to avoid infinite recursion
_queryText = queryBuilderTmp.ToString();
var query = QueryBuilder.Build(queryBuilder.ToString().Trim(), PluginManager.NonGlobalPlugins);
return query;
}
private void RemoveOldQueryResults(Query query)
{
if (_lastQuery?.ActionKeyword != query?.ActionKeyword)
@ -816,7 +873,7 @@ namespace Flow.Launcher.ViewModel
private void SetOpenResultModifiers()
{
OpenResultCommandModifiers = _settings.OpenResultModifiers ?? DefaultOpenResultModifiers;
OpenResultCommandModifiers = Settings.OpenResultModifiers ?? DefaultOpenResultModifiers;
}
public void ToggleFlowLauncher()
@ -845,24 +902,24 @@ namespace Flow.Launcher.ViewModel
// Trick for no delay
MainWindowOpacity = 0;
switch (_settings.LastQueryMode)
switch (Settings.LastQueryMode)
{
case LastQueryMode.Empty:
ChangeQueryText(string.Empty);
await Task.Delay(100); //Time for change to opacity
break;
case LastQueryMode.Preserved:
if (_settings.UseAnimation)
if (Settings.UseAnimation)
await Task.Delay(100);
LastQuerySelected = true;
break;
case LastQueryMode.Selected:
if (_settings.UseAnimation)
if (Settings.UseAnimation)
await Task.Delay(100);
LastQuerySelected = false;
break;
default:
throw new ArgumentException($"wrong LastQueryMode: <{_settings.LastQueryMode}>");
throw new ArgumentException($"wrong LastQueryMode: <{Settings.LastQueryMode}>");
}
MainWindowVisibilityStatus = false;
@ -877,7 +934,7 @@ namespace Flow.Launcher.ViewModel
/// </summary>
public bool ShouldIgnoreHotkeys()
{
return _settings.IgnoreHotkeysOnFullscreen && WindowsInteropHelper.IsWindowFullscreen();
return Settings.IgnoreHotkeysOnFullscreen && WindowsInteropHelper.IsWindowFullscreen();
}
@ -950,28 +1007,26 @@ namespace Flow.Launcher.ViewModel
var result = Results.SelectedItem?.Result;
if (result != null)
{
string copyText = string.IsNullOrEmpty(result.CopyText) ? result.SubTitle : result.CopyText;
string copyText = result.CopyText;
var isFile = File.Exists(copyText);
var isFolder = Directory.Exists(copyText);
if (isFile || isFolder)
{
var paths = new StringCollection();
paths.Add(copyText);
var paths = new StringCollection
{
copyText
};
Clipboard.SetFileDropList(paths);
App.API.ShowMsg(
App.API.GetTranslation("copy")
+ " "
+ (isFile ? App.API.GetTranslation("fileTitle") : App.API.GetTranslation("folderTitle")),
$"{App.API.GetTranslation("copy")} {(isFile ? App.API.GetTranslation("fileTitle") : App.API.GetTranslation("folderTitle"))}",
App.API.GetTranslation("completedSuccessfully"));
}
else
{
Clipboard.SetDataObject(copyText.ToString());
Clipboard.SetDataObject(copyText);
App.API.ShowMsg(
App.API.GetTranslation("copy")
+ " "
+ App.API.GetTranslation("textTitle"),
$"{App.API.GetTranslation("copy")} {App.API.GetTranslation("textTitle")}",
App.API.GetTranslation("completedSuccessfully"));
}
}

View file

@ -0,0 +1,58 @@
using System;
using Flow.Launcher.Core.ExternalPlugins;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.ViewModel
{
public class PluginStoreItemViewModel : BaseModel
{
public PluginStoreItemViewModel(UserPlugin plugin)
{
_plugin = plugin;
}
private UserPlugin _plugin;
public string ID => _plugin.ID;
public string Name => _plugin.Name;
public string Description => _plugin.Description;
public string Author => _plugin.Author;
public string Version => _plugin.Version;
public string Language => _plugin.Language;
public string Website => _plugin.Website;
public string UrlDownload => _plugin.UrlDownload;
public string UrlSourceCode => _plugin.UrlSourceCode;
public string IcoPath => _plugin.IcoPath;
public bool LabelInstalled => PluginManager.GetPluginForId(_plugin.ID) != null;
public bool LabelUpdate => LabelInstalled && _plugin.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 string Category
{
get
{
string category = None;
if (DateTime.Now - _plugin.LatestReleaseDate < TimeSpan.FromDays(7))
{
category = RecentlyUpdated;
}
if (DateTime.Now - _plugin.DateAdded < TimeSpan.FromDays(7))
{
category = NewRelease;
}
if (PluginManager.GetPluginForId(_plugin.ID) != null)
{
category = Installed;
}
return category;
}
}
}
}

View file

@ -163,15 +163,17 @@ namespace Flow.Launcher.ViewModel
}
}
var loadFullImage = (Path.GetExtension(imagePath) ?? "").Equals(".url", StringComparison.OrdinalIgnoreCase);
if (ImageLoader.CacheContainImage(imagePath))
{
// will get here either when icoPath has value\icon delegate is null\when had exception in delegate
image = ImageLoader.Load(imagePath);
image = ImageLoader.Load(imagePath, loadFullImage);
return;
}
// We need to modify the property not field here to trigger the OnPropertyChanged event
Image = await Task.Run(() => ImageLoader.Load(imagePath)).ConfigureAwait(false);
Image = await Task.Run(() => ImageLoader.Load(imagePath, loadFullImage)).ConfigureAwait(false);
}
public Result Result { get; }

View file

@ -8,6 +8,8 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using JetBrains.Annotations;
namespace Flow.Launcher.ViewModel
{
@ -49,6 +51,9 @@ namespace Flow.Launcher.ViewModel
public ResultViewModel SelectedItem { get; set; }
public Thickness Margin { get; set; }
public Visibility Visbility { get; set; } = Visibility.Collapsed;
public ICommand RightClickResultCommand { get; init; }
public ICommand LeftClickResultCommand { get; init; }
#endregion

View file

@ -19,10 +19,12 @@ using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedModels;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.Input;
namespace Flow.Launcher.ViewModel
{
public class SettingWindowViewModel : BaseModel
public partial class SettingWindowViewModel : BaseModel
{
private readonly Updater _updater;
private readonly IPortable _portable;
@ -212,11 +214,19 @@ namespace Flow.Launcher.ViewModel
}
}
public List<string> OpenResultModifiersList => new List<string> { KeyConstant.Alt, KeyConstant.Ctrl, $"{KeyConstant.Ctrl}+{KeyConstant.Alt}" };
public List<string> OpenResultModifiersList => new List<string>
{
KeyConstant.Alt,
KeyConstant.Ctrl,
$"{KeyConstant.Ctrl}+{KeyConstant.Alt}"
};
private Internationalization _translater => InternationalizationManager.Instance;
public List<Language> Languages => _translater.LoadAvailableLanguages();
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);
public ObservableCollection<CustomShortcutModel> CustomShortcuts => Settings.CustomShortcuts;
public ObservableCollection<BuiltinShortcutModel> BuiltinShortcuts => Settings.BuiltinShortcuts;
public string TestProxy()
{
var proxyServer = Settings.Proxy.Server;
@ -275,20 +285,33 @@ namespace Flow.Launcher.ViewModel
var metadatas = PluginManager.AllPlugins
.OrderBy(x => x.Metadata.Disabled)
.ThenBy(y => y.Metadata.Name)
.Select(p => new PluginViewModel { PluginPair = p })
.Select(p => new PluginViewModel
{
PluginPair = p
})
.ToList();
return metadatas;
}
}
public IList<UserPlugin> ExternalPlugins
public IList<PluginStoreItemViewModel> ExternalPlugins
{
get
{
return PluginsManifest.UserPlugins;
return LabelMaker(PluginsManifest.UserPlugins);
}
}
private IList<PluginStoreItemViewModel> LabelMaker(IList<UserPlugin> list)
{
return list.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();
}
public Control SettingProvider
{
get
@ -308,12 +331,22 @@ namespace Flow.Launcher.ViewModel
}
}
public async Task RefreshExternalPluginsAsync()
[RelayCommand]
private async Task RefreshExternalPluginsAsync()
{
await PluginsManifest.UpdateManifestAsync();
OnPropertyChanged(nameof(ExternalPlugins));
}
internal void DisplayPluginQuery(string queryToDisplay, PluginPair plugin, int actionKeywordPosition = 0)
{
var actionKeyword = plugin.Metadata.ActionKeywords.Count == 0
? string.Empty
: plugin.Metadata.ActionKeywords[actionKeywordPosition];
App.API.ChangeQuery($"{actionKeyword} {queryToDisplay}");
App.API.ShowMainWindow();
}
#endregion
@ -378,7 +411,11 @@ namespace Flow.Launcher.ViewModel
{
var key = $"ColorScheme{e}";
var display = _translater.GetTranslation(key);
var m = new ColorScheme { Display = display, Value = e, };
var m = new ColorScheme
{
Display = display,
Value = e,
};
modes.Add(m);
}
return modes;
@ -410,7 +447,24 @@ namespace Flow.Launcher.ViewModel
}
}
public List<string> TimeFormatList { get; set; } = new List<string>()
{
"hh:mm",
"HH:mm",
"tt hh:mm",
"hh:mm tt"
};
public List<string> DateFormatList { get; set; } = new List<string>()
{
"MM'/'dd dddd",
"MM'/'dd ddd",
"MM'/'dd",
"dd'/'MM",
"ddd MM'/'dd",
"dddd MM'/'dd",
"dddd"
};
public double WindowWidthSize
{
@ -436,6 +490,18 @@ namespace Flow.Launcher.ViewModel
set => Settings.UseSound = value;
}
public bool UseClock
{
get => Settings.UseClock;
set => Settings.UseClock = value;
}
public bool UseDate
{
get => Settings.UseDate;
set => Settings.UseDate = value;
}
public double SettingWindowWidth
{
get => Settings.SettingWindowWidth;
@ -471,8 +537,13 @@ namespace Flow.Launcher.ViewModel
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = memStream;
bitmap.DecodePixelWidth = 800;
bitmap.DecodePixelHeight = 600;
bitmap.EndInit();
var brush = new ImageBrush(bitmap) { Stretch = Stretch.UniformToFill };
var brush = new ImageBrush(bitmap)
{
Stretch = Stretch.UniformToFill
};
return brush;
}
else
@ -500,19 +571,19 @@ namespace Flow.Launcher.ViewModel
{
Title = "WebSearch",
SubTitle = "Search the web with different search engine support",
IcoPath =Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
},
new Result
{
Title = "Program",
SubTitle = "Launch programs as admin or a different user",
IcoPath =Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Program\Images\program.png")
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Program\Images\program.png")
},
new Result
{
Title = "ProcessKiller",
SubTitle = "Terminate unwanted processes",
IcoPath =Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
}
};
var vm = new ResultsViewModel(Settings);
@ -526,8 +597,8 @@ namespace Flow.Launcher.ViewModel
get
{
if (Fonts.SystemFontFamilies.Count(o =>
o.FamilyNames.Values != null &&
o.FamilyNames.Values.Contains(Settings.QueryBoxFont)) > 0)
o.FamilyNames.Values != null &&
o.FamilyNames.Values.Contains(Settings.QueryBoxFont)) > 0)
{
var font = new FontFamily(Settings.QueryBoxFont);
return font;
@ -554,7 +625,7 @@ namespace Flow.Launcher.ViewModel
Settings.QueryBoxFontStyle,
Settings.QueryBoxFontWeight,
Settings.QueryBoxFontStretch
));
));
return typeface;
}
set
@ -571,8 +642,8 @@ namespace Flow.Launcher.ViewModel
get
{
if (Fonts.SystemFontFamilies.Count(o =>
o.FamilyNames.Values != null &&
o.FamilyNames.Values.Contains(Settings.ResultFont)) > 0)
o.FamilyNames.Values != null &&
o.FamilyNames.Values.Contains(Settings.ResultFont)) > 0)
{
var font = new FontFamily(Settings.ResultFont);
return font;
@ -599,7 +670,7 @@ namespace Flow.Launcher.ViewModel
Settings.ResultFontStyle,
Settings.ResultFontWeight,
Settings.ResultFontStretch
));
));
return typeface;
}
set
@ -621,6 +692,65 @@ namespace Flow.Launcher.ViewModel
#endregion
#region shortcut
public CustomShortcutModel? SelectedCustomShortcut { get; set; }
public void DeleteSelectedCustomShortcut()
{
var item = SelectedCustomShortcut;
if (item == null)
{
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
return;
}
string deleteWarning = string.Format(
InternationalizationManager.Instance.GetTranslation("deleteCustomShortcutWarning"),
item?.Key, item?.Value);
if (MessageBox.Show(deleteWarning, InternationalizationManager.Instance.GetTranslation("delete"),
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
Settings.CustomShortcuts.Remove(item);
}
}
public bool EditSelectedCustomShortcut()
{
var item = SelectedCustomShortcut;
if (item == null)
{
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("pleaseSelectAnItem"));
return false;
}
var shortcutSettingWindow = new CustomShortcutSetting(item.Key, item.Value, this);
if (shortcutSettingWindow.ShowDialog() == true)
{
item.Key = shortcutSettingWindow.Key;
item.Value = shortcutSettingWindow.Value;
return true;
}
return false;
}
public void AddCustomShortcut()
{
var shortcutSettingWindow = new CustomShortcutSetting(this);
if (shortcutSettingWindow.ShowDialog() == true)
{
var shortcut = new CustomShortcutModel(shortcutSettingWindow.Key, shortcutSettingWindow.Value);
Settings.CustomShortcuts.Add(shortcut);
}
}
public bool ShortcutExists(string key)
{
return Settings.CustomShortcuts.Any(x => x.Key == key) || Settings.BuiltinShortcuts.Any(x => x.Key == key);
}
#endregion
#region about
public string Website => Constant.Website;
@ -628,7 +758,20 @@ namespace Flow.Launcher.ViewModel
public string Documentation => Constant.Documentation;
public string Docs => Constant.Docs;
public string Github => Constant.GitHub;
public static string Version => Constant.Version;
public string Version
{
get
{
if (Constant.Version == "1.0.0")
{
return Constant.Dev;
}
else
{
return Constant.Version;
}
}
}
public string ActivatedTimes => string.Format(_translater.GetTranslation("about_activate_times"), Settings.ActivateTimes);
public string CheckLogFolder

View file

@ -1,4 +1,4 @@
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
@ -130,4 +130,4 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
}
}
}
}
}

View file

@ -3,7 +3,7 @@
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWPF>true</UseWPF>
<ProjectGuid>{9B130CC5-14FB-41FF-B310-0A95B6894C37}</ProjectGuid>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Flow.Launcher.Plugin.BrowserBookmark</RootNamespace>
@ -23,7 +23,7 @@
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
@ -39,15 +39,6 @@
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<Content Include="x64\SQLite.Interop.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="x86\SQLite.Interop.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
@ -64,8 +55,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Data.SQLite" Version="1.0.114.4" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.114.3" />
<PackageReference Include="System.Data.SQLite" Version="1.0.116" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.116" />
<PackageReference Include="UnidecodeSharp" Version="1.0.0" />
</ItemGroup>
@ -73,4 +64,19 @@
<Compile Remove="Bookmark.cs" />
</ItemGroup>
<Target Name="CopyDLLs" AfterTargets="Build">
<Message Text="Executing CopyDLLs task" Importance="High" />
<Copy
SourceFiles="$(TargetDir)\runtimes\win-x64\native\SQLite.Interop.dll"
DestinationFolder="$(TargetDir)\x64" />
<Copy
SourceFiles="$(TargetDir)\runtimes\win-x86\native\SQLite.Interop.dll"
DestinationFolder="$(TargetDir)\x86" />
</Target>
<Target Name="DeleteRuntimesFolder" AfterTargets="CopyDLLs">
<Message Text="Deleting runtimes folder" Importance="High" />
<RemoveDir Directories="$(TargetDir)\runtimes" />
</Target>
</Project>

View file

@ -6,12 +6,13 @@
xmlns:local="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="{DynamicResource plugin_explorer_manageactionkeywords_header}"
Width="400"
SizeToContent="Height"
Width="Auto"
Height="255"
Background="{DynamicResource PopuBGColor}"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Foreground="{DynamicResource PopupTextColor}"
ResizeMode="NoResize"
SizeToContent="Width"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<WindowChrome.WindowChrome>
@ -68,7 +69,7 @@
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
<TextBlock
Width="150"
MinWidth="150"
Margin="0,10,15,10"
HorizontalAlignment="Left"
VerticalAlignment="Center"
@ -78,18 +79,19 @@
Name="TxtCurrentActionKeyword"
Grid.Row="0"
Grid.Column="1"
Width="105"
Width="135"
HorizontalAlignment="Left"
VerticalAlignment="Center"
PreviewKeyDown="TxtCurrentActionKeyword_OnKeyDown"
Text="{Binding ActionKeyword}" />
</StackPanel>
<StackPanel Margin="0,10,0,15" Orientation="Horizontal">
<TextBlock Margin="0 0 15 0 "
<TextBlock
MinWidth="150"
Margin="0,0,18,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="14"
Width="150"
Text="{DynamicResource plugin_explorer_actionkeyword_enabled}" />
<CheckBox
Name="ChkActionKeywordEnabled"

View file

@ -37,7 +37,7 @@ namespace Flow.Launcher.Plugin.PluginsManager
contextMenu = new ContextMenu(Context);
pluginManager = new PluginsManager(Context, Settings);
await pluginManager.UpdateManifestAsync();
_ = pluginManager.UpdateManifestAsync();
}
public List<Result> LoadContextMenus(Result selectedResult)
@ -74,4 +74,4 @@ namespace Flow.Launcher.Plugin.PluginsManager
return Context.API.GetTranslation("plugin_pluginsmanager_plugin_description");
}
}
}
}

View file

@ -5,12 +5,13 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="{DynamicResource flowlauncher_plugin_program_directory}"
Width="400"
Width="Auto"
Height="276"
Background="{DynamicResource PopuBGColor}"
Foreground="{DynamicResource PopupTextColor}"
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
ResizeMode="NoResize"
SizeToContent="Width"
WindowStartupLocation="CenterScreen">
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
</WindowChrome.WindowChrome>
@ -19,7 +20,6 @@
<RowDefinition />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<StackPanel>
<Grid>
@ -53,33 +53,80 @@
</Button>
</Grid>
</StackPanel>
<StackPanel Margin="26,12,26,0">
<StackPanel Margin="0,0,0,12">
<StackPanel Margin="26,0,26,0">
<StackPanel Grid.Row="0" Margin="0,0,0,12">
<TextBlock
Grid.Column="0"
Margin="0,0,0,0"
FontSize="20"
FontWeight="SemiBold"
Text="{DynamicResource flowlauncher_plugin_program_directory}"
Text="{DynamicResource flowlauncher_plugin_program_edit_program_source_title}"
TextAlignment="Left" />
</StackPanel>
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<TextBox
Name="Directory"
Width="268"
Margin="0,7"
VerticalAlignment="Center" />
<Button
Width="70"
Margin="10"
HorizontalAlignment="Right"
Click="BrowseButton_Click"
Content="{DynamicResource flowlauncher_plugin_program_browse}" />
<StackPanel>
<TextBlock
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_edit_program_source_tips}"
TextAlignment="Left"
TextWrapping="WrapWithOverflow" />
</StackPanel>
<StackPanel Margin="0,10,10,0" Orientation="Horizontal">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_directory}" />
<DockPanel
Grid.Row="0"
Grid.Column="1"
LastChildFill="True">
<Button
MinWidth="70"
HorizontalAlignment="Stretch"
Click="BrowseButton_Click"
Content="{DynamicResource flowlauncher_plugin_program_browse}"
DockPanel.Dock="Right" />
<TextBox
Name="Directory"
MinWidth="300"
Margin="10"
HorizontalAlignment="Stretch"
VerticalAlignment="Center" />
</DockPanel>
<TextBlock
Grid.Row="1"
Grid.Column="0"
Margin="10"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_enabled}" />
<CheckBox
x:Name="Chkbox"
Grid.Row="1"
Grid.Column="1"
Margin="10,0"
VerticalAlignment="Center" />
</Grid>
</StackPanel>
</StackPanel>
</StackPanel>
<Border
Grid.Row="1"
Margin="0,14,0,0"
Background="{DynamicResource PopupButtonAreaBGColor}"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="0,1,0,0">
@ -87,19 +134,17 @@
<Button
x:Name="btnCancel"
MinWidth="140"
Margin="0,0,5,0"
Margin="10,0,5,0"
Click="BtnCancel_OnClick"
Content="{DynamicResource cancel}" />
<Button
x:Name="btnAdd"
MinWidth="140"
Margin="5,0,0,0"
HorizontalAlignment="Right"
Click="ButtonAdd_OnClick"
Margin="5,0,10,0"
Click="BtnAdd_OnClick"
Content="{DynamicResource flowlauncher_plugin_program_update}"
Style="{DynamicResource AccentButtonStyle}" />
</StackPanel>
</Border>
</Grid>
</Window>
</Window>

View file

@ -9,11 +9,12 @@ namespace Flow.Launcher.Plugin.Program
/// <summary>
/// Interaction logic for AddProgramSource.xaml
/// </summary>
public partial class AddProgramSource
public partial class AddProgramSource : Window
{
private PluginInitContext _context;
private Settings.ProgramSource _editing;
private ProgramSource _editing;
private Settings _settings;
private bool update;
public AddProgramSource(PluginInitContext context, Settings settings)
{
@ -21,14 +22,19 @@ namespace Flow.Launcher.Plugin.Program
_context = context;
_settings = settings;
Directory.Focus();
Chkbox.IsChecked = true;
update = false;
btnAdd.Content = _context.API.GetTranslation("flowlauncher_plugin_program_add");
}
public AddProgramSource(Settings.ProgramSource edit, Settings settings)
public AddProgramSource(PluginInitContext context, Settings settings, ProgramSource source)
{
_editing = edit;
_settings = settings;
InitializeComponent();
_context = context;
_editing = source;
_settings = settings;
update = true;
Chkbox.IsChecked = _editing.Enabled;
Directory.Text = _editing.Location;
}
@ -47,34 +53,54 @@ namespace Flow.Launcher.Plugin.Program
Close();
}
private void ButtonAdd_OnClick(object sender, RoutedEventArgs e)
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
{
string s = Directory.Text;
if (!System.IO.Directory.Exists(s))
string path = Directory.Text;
bool modified = false;
if (!System.IO.Directory.Exists(path))
{
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
return;
}
if (_editing == null)
if (!update)
{
if (!ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == Directory.Text))
if (!ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase)))
{
var source = new ProgramSource
{
Location = Directory.Text,
UniqueIdentifier = Directory.Text
};
var source = new ProgramSource(path);
modified = true;
_settings.ProgramSources.Insert(0, source);
ProgramSetting.ProgramSettingDisplayList.Add(source);
}
else
{
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
return;
}
}
else
{
_editing.Location = Directory.Text;
// Separate checks to avoid changing UniqueIdentifier of UWP
if (!_editing.Location.Equals(path, System.StringComparison.OrdinalIgnoreCase))
{
if (ProgramSetting.ProgramSettingDisplayList
.Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase)))
{
// Check if the new location is used
// No need to check win32 or uwp, just override them
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
return;
}
modified = true;
_editing.Location = path; // Changes UniqueIdentifier internally
}
if (_editing.Enabled != Chkbox.IsChecked)
{
modified = true;
_editing.Enabled = Chkbox.IsChecked ?? true;
}
}
DialogResult = true;
DialogResult = modified;
Close();
}
}

View file

@ -1,58 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Plugin.Program.Programs;
namespace Flow.Launcher.Plugin.Program
{
//internal static class FileChangeWatcher
//{
// private static readonly List<string> WatchedPath = new List<string>();
// // todo remove previous watcher events
// public static void AddAll(List<UnregisteredPrograms> sources, string[] suffixes)
// {
// foreach (var s in sources)
// {
// if (Directory.Exists(s.Location))
// {
// AddWatch(s.Location, suffixes);
// }
// }
// }
// public static void AddWatch(string path, string[] programSuffixes, bool includingSubDirectory = true)
// {
// if (WatchedPath.Contains(path)) return;
// if (!Directory.Exists(path))
// {
// Log.Warn($"|FileChangeWatcher|{path} doesn't exist");
// return;
// }
// WatchedPath.Add(path);
// foreach (string fileType in programSuffixes)
// {
// FileSystemWatcher watcher = new FileSystemWatcher
// {
// Path = path,
// IncludeSubdirectories = includingSubDirectory,
// Filter = $"*.{fileType}",
// EnableRaisingEvents = true
// };
// watcher.Changed += FileChanged;
// watcher.Created += FileChanged;
// watcher.Deleted += FileChanged;
// watcher.Renamed += FileChanged;
// }
// }
// private static void FileChanged(object source, FileSystemEventArgs e)
// {
// Task.Run(() =>
// {
// Main.IndexPrograms();
// });
// }
//}
}

View file

@ -58,6 +58,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ini-parser" Version="2.5.2" />
<PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup>

View file

@ -4,21 +4,27 @@
xmlns:system="clr-namespace:System;assembly=mscorlib">
<!-- Program setting -->
<system:String x:Key="flowlauncher_plugin_program_reset">Reset Default</system:String>
<system:String x:Key="flowlauncher_plugin_program_delete">Delete</system:String>
<system:String x:Key="flowlauncher_plugin_program_edit">Edit</system:String>
<system:String x:Key="flowlauncher_plugin_program_add">Add</system:String>
<system:String x:Key="flowlauncher_plugin_program_name">Name</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable">Enable</system:String>
<system:String x:Key="flowlauncher_plugin_program_enabled">Enabled</system:String>
<system:String x:Key="flowlauncher_plugin_program_disable">Disable</system:String>
<system:String x:Key="flowlauncher_plugin_program_location">Location</system:String>
<system:String x:Key="flowlauncher_plugin_program_all_programs">All Programs</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes">File Suffixes</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes">File Type</system:String>
<system:String x:Key="flowlauncher_plugin_program_reindex">Reindex</system:String>
<system:String x:Key="flowlauncher_plugin_program_indexing">Indexing</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_start">Index Start Menu</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_source">Index Sources</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_option">Options</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_start">Start Menu</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_start_tooltip">When enabled, Flow will load programs from the start menu</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_registry">Index Registry</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_registry">Registry</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_registry_tooltip">When enabled, Flow will load programs from the registry</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_PATH">PATH</system:String>
<system:String x:Key="flowlauncher_plugin_program_index_PATH_tooltip">When enabled, Flow will load programs from the PATH environment variable</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath">Hide app path</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath_tooltip">For executable files such as UWP or lnk, hide the file path from being visible</system:String>
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
@ -33,11 +39,30 @@
<system:String x:Key="flowlauncher_plugin_program_pls_select_program_source">Please select a program source</system:String>
<system:String x:Key="flowlauncher_plugin_program_delete_program_source">Are you sure you want to delete the selected program sources?</system:String>
<system:String x:Key="flowlauncher_plugin_program_duplicate_program_source">Another program source with the same location alreaday exists.</system:String>
<system:String x:Key="flowlauncher_plugin_program_update">OK</system:String>
<system:String x:Key="flowlauncher_plugin_program_only_index_tip">Flow Launcher will only index files that end with the following suffixes. (Each suffix should split by ';' )</system:String>
<system:String x:Key="flowlauncher_plugin_program_edit_program_source_title">Program Source</system:String>
<system:String x:Key="flowlauncher_plugin_program_edit_program_source_tips">Edit directory and status of this program source.</system:String>
<system:String x:Key="flowlauncher_plugin_program_update">Update</system:String>
<system:String x:Key="flowlauncher_plugin_program_only_index_tip">Program Plugin will only index files with selected suffixes and .url files with selected protocols.</system:String>
<system:String x:Key="flowlauncher_plugin_program_update_file_suffixes">Successfully updated file suffixes</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_cannot_empty">File suffixes can't be empty</system:String>
<system:String x:Key="flowlauncher_plugin_protocols_cannot_empty">Protocols can't be empty</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_excutable_types">File Suffixes</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_types">URL Protocols</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_steam">Steam Games</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_epic">Epic Games</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_URL_http">Http/Https</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_custom_urls">Custom URL Protocols</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_custom_file_types">Custom File Suffixes</system:String>
<system:String x:Key="flowlauncher_plugin_program_suffixes_tooltip">
Insert file suffixes you want to index. Suffixes should be separated by ';'. (ex>bat;py)
</system:String>
<system:String x:Key="flowlauncher_plugin_program_protocol_tooltip">
Insert protocols of .url files you want to index. Protocols should be separated by ';', and should end with "://". (ex>ftp://;mailto://)
</system:String>
<system:String x:Key="flowlauncher_plugin_program_run_as_different_user">Run As Different User</system:String>
<system:String x:Key="flowlauncher_plugin_program_run_as_administrator">Run As Administrator</system:String>

View file

@ -1,13 +1,8 @@
using NLog;
using NLog.Config;
using NLog.Targets;
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.UserSettings;
namespace Flow.Launcher.Plugin.Program.Logger
{

View file

@ -1,7 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@ -11,9 +9,8 @@ using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Plugin.Program.Programs;
using Flow.Launcher.Plugin.Program.Views;
using Flow.Launcher.Plugin.Program.Views.Models;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Primitives;
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
namespace Flow.Launcher.Plugin.Program
@ -82,13 +79,9 @@ namespace Flow.Launcher.Plugin.Program
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
{
_win32Storage = new BinaryStorage<Win32[]>("Win32");
_win32s = _win32Storage.TryLoad(new Win32[]
{
});
_win32s = _win32Storage.TryLoad(Array.Empty<Win32>());
_uwpStorage = new BinaryStorage<UWP.Application[]>("UWP");
_uwps = _uwpStorage.TryLoad(new UWP.Application[]
{
});
_uwps = _uwpStorage.TryLoad(Array.Empty<UWP.Application>());
});
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
@ -102,14 +95,14 @@ namespace Flow.Launcher.Plugin.Program
var b = Task.Run(() =>
{
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|UWPPRogram index cost", IndexUwpPrograms);
});
if (cacheEmpty)
await Task.WhenAll(a, b);
Win32.WatchProgramUpdate(_settings);
UWP.WatchPackageChange();
_ = UWP.WatchPackageChange();
}
public static void IndexWin32Programs()
@ -123,18 +116,23 @@ namespace Flow.Launcher.Plugin.Program
{
var windows10 = new Version(10, 0);
var support = Environment.OSVersion.Version.Major >= windows10.Major;
var applications = support ? UWP.All() : new UWP.Application[]
{
};
var applications = support ? UWP.All() : Array.Empty<UWP.Application>();
_uwps = applications;
ResetCache();
}
public static async Task IndexProgramsAsync()
{
var t1 = Task.Run(IndexWin32Programs);
var t2 = Task.Run(IndexUwpPrograms);
await Task.WhenAll(t1, t2).ConfigureAwait(false);
var a = Task.Run(() =>
{
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32Programs);
});
var b = Task.Run(() =>
{
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|UWPProgram index cost", IndexUwpPrograms);
});
await Task.WhenAll(a, b).ConfigureAwait(false);
_settings.LastIndexTime = DateTime.Today;
}
@ -190,29 +188,33 @@ namespace Flow.Launcher.Plugin.Program
return menuOptions;
}
private void DisableProgram(IProgram programToDelete)
private static void DisableProgram(IProgram programToDelete)
{
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
return;
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
_uwps.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
.Enabled = false;
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
_win32s.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
.Enabled = false;
_settings.DisabledProgramSources
.Add(
new Settings.DisabledProgramSource
{
Name = programToDelete.Name,
Location = programToDelete.Location,
UniqueIdentifier = programToDelete.UniqueIdentifier,
Enabled = false
}
);
{
var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
program.Enabled = false;
_settings.DisabledProgramSources.Add(new ProgramSource(program));
_ = Task.Run(() =>
{
IndexUwpPrograms();
_settings.LastIndexTime = DateTime.Today;
});
}
else if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
{
var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
program.Enabled = false;
_settings.DisabledProgramSources.Add(new ProgramSource(program));
_ = Task.Run(() =>
{
IndexWin32Programs();
_settings.LastIndexTime = DateTime.Today;
});
}
}
public static void StartProcess(Func<ProcessStartInfo, Process> runProcess, ProcessStartInfo info)
@ -233,6 +235,7 @@ namespace Flow.Launcher.Plugin.Program
{
await IndexProgramsAsync();
}
public void Dispose()
{
Win32.Dispose();

View file

@ -4,9 +4,11 @@
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:ui="http://schemas.modernwpf.com/2019"
Title="{DynamicResource flowlauncher_plugin_program_suffixes}"
Width="400"
Width="600"
Background="{DynamicResource PopuBGColor}"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Foreground="{DynamicResource PopupTextColor}"
ResizeMode="NoResize"
SizeToContent="Height"
@ -15,9 +17,73 @@
<WindowChrome.WindowChrome>
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
</WindowChrome.WindowChrome>
<Grid>
<Window.Resources>
<Style
x:Key="CustomFileTypeTextBox"
BasedOn="{StaticResource DefaultTextBoxStyle}"
TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CustomFiles, Path=IsChecked}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style
x:Key="CustomURLTypeTextBox"
BasedOn="{StaticResource DefaultTextBoxStyle}"
TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=CustomProtocol, Path=IsChecked}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="SettingGroupBoxSuffixToolTip" TargetType="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="15,15,15,15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbSuffixes, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tbSuffixes, Path=IsFocused}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="SettingGroupBoxURLToolTip" TargetType="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="15,15,15,15" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=tbProtocols, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=tbProtocols, Path=IsFocused}" Value="False">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid x:Name="WindowArea">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="auto" />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
@ -55,7 +121,9 @@
</Grid>
</StackPanel>
<StackPanel Margin="26,12,26,0">
<StackPanel Margin="0,0,0,12">
<TextBlock
Grid.Column="0"
Margin="0,0,0,0"
@ -65,10 +133,104 @@
TextAlignment="Left" />
</StackPanel>
<TextBlock
Margin="0,0,0,10"
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_only_index_tip}"
TextWrapping="Wrap" />
<TextBox x:Name="tbSuffixes" Margin="0,20,0,20" />
<Border Style="{DynamicResource SettingGroupBoxURLToolTip}">
<TextBlock
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_protocol_tooltip}"
TextWrapping="Wrap" />
</Border>
<Border Style="{DynamicResource SettingGroupBoxSuffixToolTip}">
<TextBlock
FontSize="14"
Text="{DynamicResource flowlauncher_plugin_program_suffixes_tooltip}"
TextWrapping="Wrap" />
</Border>
<Grid Margin="0,20,0,12">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250" />
<ColumnDefinition Width="250" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="0,0,0,0">
<TextBlock
Margin="0,0,0,8"
FontSize="16"
FontWeight="SemiBold"
Text="{DynamicResource flowlauncher_plugin_program_suffixes_excutable_types}" />
<CheckBox
Name="apprefMS"
Margin="10,0,0,0"
IsChecked="{Binding SuffixesStatus[appref-ms]}">
appref-ms
</CheckBox>
<CheckBox
Name="exe"
Margin="10,0,0,0"
IsChecked="{Binding SuffixesStatus[exe]}">
exe
</CheckBox>
<CheckBox
Name="lnk"
Margin="10,0,0,0"
IsChecked="{Binding SuffixesStatus[lnk]}">
lnk
</CheckBox>
<CheckBox
Name="CustomFiles"
Margin="10,0,0,0"
Content="{DynamicResource flowlauncher_plugin_program_suffixes_custom_file_types}"
IsChecked="{Binding UseCustomSuffixes}" />
<TextBox
x:Name="tbSuffixes"
Margin="10,4,0,10"
Style="{StaticResource CustomFileTypeTextBox}" />
</StackPanel>
<Border
Grid.Column="1"
Margin="20,0,0,10"
Padding="20,0,0,0"
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
BorderThickness="1,0,0,0">
<StackPanel>
<TextBlock
Margin="0,0,0,8"
FontSize="16"
FontWeight="SemiBold"
Text="{DynamicResource flowlauncher_plugin_program_suffixes_URL_types}" />
<CheckBox
Name="steam"
Margin="10,0,0,0"
Content="{DynamicResource flowlauncher_plugin_program_suffixes_URL_steam}"
IsChecked="{Binding ProtocolsStatus[steam]}" />
<CheckBox
Name="epic"
Margin="10,0,0,0"
Content="{DynamicResource flowlauncher_plugin_program_suffixes_URL_epic}"
IsChecked="{Binding ProtocolsStatus[epic]}" />
<CheckBox
Name="http"
Margin="10,0,0,0"
Content="{DynamicResource flowlauncher_plugin_program_suffixes_URL_http}"
IsChecked="{Binding ProtocolsStatus[http]}" />
<CheckBox
Name="CustomProtocol"
Margin="10,0,0,0"
Content="{DynamicResource flowlauncher_plugin_program_suffixes_custom_urls}"
IsChecked="{Binding UseCustomProtocols}" />
<TextBox
x:Name="tbProtocols"
Margin="10,4,0,0"
Style="{StaticResource CustomURLTypeTextBox}" />
</StackPanel>
</Border>
</Grid>
</StackPanel>
</StackPanel>
<Border
@ -78,10 +240,17 @@
BorderThickness="0,1,0,0">
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
<Button
x:Name="btnCancel"
x:Name="btnReset"
Height="30"
MinWidth="140"
Margin="0,0,5,0"
Click="BtnReset_OnClick"
Content="{DynamicResource flowlauncher_plugin_program_reset}" />
<Button
x:Name="btnCancel"
Height="30"
MinWidth="140"
Margin="5,0,5,0"
Click="BtnCancel_OnClick"
Content="{DynamicResource cancel}" />
@ -90,7 +259,7 @@
MinWidth="140"
Margin="5,0,0,0"
HorizontalAlignment="Right"
Click="ButtonBase_OnClick"
Click="BtnAdd_OnClick"
Content="{DynamicResource flowlauncher_plugin_program_update}"
Style="{DynamicResource AccentButtonStyle}" />
</StackPanel>

View file

@ -1,44 +1,76 @@
using System;
using System.Collections.Generic;
using System.Windows;
namespace Flow.Launcher.Plugin.Program
{
/// <summary>
/// ProgramSuffixes.xaml 的交互逻辑
/// </summary>
public partial class ProgramSuffixes
{
private PluginInitContext context;
private Settings _settings;
public Dictionary<string, bool> SuffixesStatus { get; set; }
public Dictionary<string, bool> ProtocolsStatus { get; set; }
public bool UseCustomSuffixes { get; set; }
public bool UseCustomProtocols { get; set; }
public ProgramSuffixes(PluginInitContext context, Settings settings)
{
this.context = context;
InitializeComponent();
_settings = settings;
tbSuffixes.Text = string.Join(Settings.SuffixSeperator.ToString(), _settings.ProgramSuffixes);
SuffixesStatus = new Dictionary<string, bool>(_settings.BuiltinSuffixesStatus);
ProtocolsStatus = new Dictionary<string, bool>(_settings.BuiltinProtocolsStatus);
UseCustomSuffixes = _settings.UseCustomSuffixes;
UseCustomProtocols = _settings.UseCustomProtocols;
InitializeComponent();
tbSuffixes.Text = string.Join(Settings.SuffixSeparator, _settings.CustomSuffixes);
tbProtocols.Text = string.Join(Settings.SuffixSeparator, _settings.CustomProtocols);
}
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
{
Close();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var suffixes = tbSuffixes.Text.Split(Settings.SuffixSeperator, StringSplitOptions.RemoveEmptyEntries);
if (suffixes.Length == 0)
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
{
var suffixes = tbSuffixes.Text.Split(Settings.SuffixSeparator, StringSplitOptions.RemoveEmptyEntries);
var protocols = tbProtocols.Text.Split(Settings.SuffixSeparator, StringSplitOptions.RemoveEmptyEntries);
if (suffixes.Length == 0 && UseCustomSuffixes)
{
string warning = context.API.GetTranslation("flowlauncher_plugin_program_suffixes_cannot_empty");
MessageBox.Show(warning);
return;
}
_settings.ProgramSuffixes = suffixes;
if (protocols.Length == 0 && UseCustomProtocols)
{
string warning = context.API.GetTranslation("flowlauncher_plugin_protocols_cannot_empty");
MessageBox.Show(warning);
return;
}
string msg = context.API.GetTranslation("flowlauncher_plugin_program_update_file_suffixes");
MessageBox.Show(msg);
_settings.CustomSuffixes = suffixes;
_settings.CustomProtocols = protocols;
_settings.BuiltinSuffixesStatus = new Dictionary<string, bool>(SuffixesStatus);
_settings.BuiltinProtocolsStatus = new Dictionary<string, bool>(ProtocolsStatus);
_settings.UseCustomSuffixes = UseCustomSuffixes;
_settings.UseCustomProtocols = UseCustomProtocols;
DialogResult = true;
}
private void BtnReset_OnClick(object sender, RoutedEventArgs e)
{
apprefMS.IsChecked = true;
exe.IsChecked = true;
lnk.IsChecked = true;
CustomFiles.IsChecked = false;
steam.IsChecked = true;
epic.IsChecked = true;
http.IsChecked = false;
CustomProtocol.IsChecked = false;
}
}
}
}

View file

@ -1,8 +1,6 @@
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
namespace Flow.Launcher.Plugin.Program.Programs
{

View file

@ -1,20 +1,18 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Windows.Storage;
namespace Flow.Launcher.Plugin.Program.Programs
{
public class AppxPackageHelper
{
// This function returns a list of attributes of applications
public List<IAppxManifestApplication> getAppsFromManifest(IStream stream)
public static List<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
{
IAppxFactory appxFactory = (IAppxFactory)new AppxFactory();
List<IAppxManifestApplication> apps = new List<IAppxManifestApplication>();
var appxFactory = new AppxFactory();
var reader = ((IAppxFactory)appxFactory).CreateManifestReader(stream);
var reader = appxFactory.CreateManifestReader(stream);
var manifestApps = reader.GetApplications();
while (manifestApps.GetHasCurrent())
{

View file

@ -1,11 +1,8 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using Accessibility;
using System.Runtime.InteropServices.ComTypes;
using System.Security.Policy;
namespace Flow.Launcher.Plugin.Program.Programs
{

View file

@ -18,7 +18,6 @@ using Flow.Launcher.Plugin.Program.Logger;
using Rect = System.Windows.Rect;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.Infrastructure.Logger;
using System.Runtime.Versioning;
using System.Threading.Channels;
namespace Flow.Launcher.Plugin.Program.Programs
@ -42,39 +41,27 @@ namespace Flow.Launcher.Plugin.Program.Programs
FullName = package.Id.FullName;
FamilyName = package.Id.FamilyName;
InitializeAppInfo();
Apps = Apps.Where(a =>
{
var valid =
!string.IsNullOrEmpty(a.UserModelId) &&
!string.IsNullOrEmpty(a.DisplayName);
return valid;
}).ToArray();
}
private void InitializeAppInfo()
{
AppxPackageHelper _helper = new AppxPackageHelper();
var path = Path.Combine(Location, "AppxManifest.xml");
var namespaces = XmlNamespaces(path);
InitPackageVersion(namespaces);
const uint noAttribute = 0x80;
const Stgm exclusiveRead = Stgm.Read | Stgm.ShareExclusive;
var hResult = SHCreateStreamOnFileEx(path, exclusiveRead, noAttribute, false, null, out IStream stream);
const Stgm nonExclusiveRead = Stgm.Read | Stgm.ShareDenyNone;
var hResult = SHCreateStreamOnFileEx(path, nonExclusiveRead, noAttribute, false, null, out IStream stream);
if (hResult == Hresult.Ok)
{
var apps = new List<Application>();
List<AppxPackageHelper.IAppxManifestApplication> _apps = AppxPackageHelper.GetAppsFromManifest(stream);
List<AppxPackageHelper.IAppxManifestApplication> _apps = _helper.getAppsFromManifest(stream);
foreach (var _app in _apps)
{
var app = new Application(_app, this);
apps.Add(app);
}
Apps = apps.Where(a => a.AppListEntry != "none").ToArray();
Apps = _apps.Select(x => new Application(x, this))
.Where(a => !string.IsNullOrEmpty(a.UserModelId)
&& !string.IsNullOrEmpty(a.DisplayName))
.ToArray();
}
else
{
@ -82,17 +69,17 @@ namespace Flow.Launcher.Plugin.Program.Programs
ProgramLogger.LogException($"|UWP|InitializeAppInfo|{path}" +
"|Error caused while trying to get the details of the UWP program", e);
Apps = new List<Application>().ToArray();
Apps = Array.Empty<Application>();
}
if (Marshal.ReleaseComObject(stream) > 0)
if (stream != null && Marshal.ReleaseComObject(stream) > 0)
{
Log.Error("Flow.Launcher.Plugin.Program.Programs.UWP", "AppxManifest.xml was leaked");
}
}
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
private string[] XmlNamespaces(string path)
private static string[] XmlNamespaces(string path)
{
XDocument z = XDocument.Load(path);
if (z.Root != null)
@ -110,9 +97,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
ProgramLogger.LogException($"|UWP|XmlNamespaces|{path}" +
$"|Error occured while trying to get the XML from {path}", new ArgumentNullException());
return new string[]
{
};
return Array.Empty<string>();
}
}
@ -178,16 +163,13 @@ namespace Flow.Launcher.Plugin.Program.Programs
var updatedListWithoutDisabledApps = applications
.Where(t1 => !Main._settings.DisabledProgramSources
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
.Select(x => x);
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
return updatedListWithoutDisabledApps.ToArray();
}
else
{
return new Application[]
{
};
return Array.Empty<Application>();
}
}
@ -233,9 +215,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
}
else
{
return new Package[]
{
};
return Array.Empty<Package>();
}
}
@ -297,8 +277,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
[Serializable]
public class Application : IProgram
{
public string AppListEntry { get; set; }
public string UniqueIdentifier { get; set; }
private string _uid = string.Empty;
public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); }
public string DisplayName { get; set; }
public string Description { get; set; }
public string UserModelId { get; set; }
@ -317,7 +297,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
public Application() { }
public Result Result(string query, IPublicAPI api)
{
string title;
@ -544,7 +523,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
}
}
public string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue)
public static string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue)
{
const string prefix = "ms-resource:";
@ -601,92 +580,97 @@ namespace Flow.Launcher.Plugin.Program.Programs
// windows 8.1 https://msdn.microsoft.com/en-us/library/windows/apps/hh965372.aspx#target_size
// windows 8 https://msdn.microsoft.com/en-us/library/windows/apps/br211475.aspx
string path;
if (uri.Contains("\\"))
{
path = Path.Combine(Package.Location, uri);
}
else
string path = Path.Combine(Package.Location, uri);
var logoPath = TryToFindLogo(uri, path);
if (String.IsNullOrEmpty(logoPath))
{
// TODO: Don't know why, just keep it at the moment
// Maybe on older version of Windows 10?
// for C:\Windows\MiracastView etc
path = Path.Combine(Package.Location, "Assets", uri);
return TryToFindLogo(uri, Path.Combine(Package.Location, "Assets", uri));
}
return logoPath;
var extension = Path.GetExtension(path);
if (extension != null)
string TryToFindLogo(string uri, string path)
{
var end = path.Length - extension.Length;
var prefix = path.Substring(0, end);
var paths = new List<string>
var extension = Path.GetExtension(path);
if (extension != null)
{
path
};
//if (File.Exists(path))
//{
// return path; // shortcut, avoid enumerating files
//}
var scaleFactors = new Dictionary<PackageVersion, List<int>>
{
// scale factors on win10: https://docs.microsoft.com/en-us/windows/uwp/controls-and-patterns/tiles-and-notifications-app-assets#asset-size-tables,
var logoNamePrefix = Path.GetFileNameWithoutExtension(uri); // e.g Square44x44
var logoDir = Path.GetDirectoryName(path); // e.g ..\..\Assets
if (String.IsNullOrEmpty(logoNamePrefix) || String.IsNullOrEmpty(logoDir) || !Directory.Exists(logoDir))
{
PackageVersion.Windows10, new List<int>
{
100,
125,
150,
200,
400
}
},
// Known issue: Edge always triggers it since logo is not at uri
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
$"|{UserModelId} can't find logo uri for {uri} in package location (logo name or directory not found): {Package.Location}", new FileNotFoundException());
return string.Empty;
}
var files = Directory.EnumerateFiles(logoDir);
// Currently we don't care which one to choose
// Just ignore all qualifiers
// select like logo.[xxx_yyy].png
// https://learn.microsoft.com/en-us/windows/uwp/app-resources/tailor-resources-lang-scale-contrast
var logos = files.Where(file =>
Path.GetFileName(file)?.StartsWith(logoNamePrefix, StringComparison.OrdinalIgnoreCase) ?? false
&& extension.Equals(Path.GetExtension(file), StringComparison.OrdinalIgnoreCase)
);
var selected = logos.FirstOrDefault();
var closest = selected;
int min = int.MaxValue;
foreach(var logo in logos)
{
PackageVersion.Windows81, new List<int>
var imageStream = File.OpenRead(logo);
var decoder = BitmapDecoder.Create(imageStream, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.None);
var height = decoder.Frames[0].PixelHeight;
var width = decoder.Frames[0].PixelWidth;
int pixelCountDiff = Math.Abs(height * width - 1936); // 44*44=1936
if(pixelCountDiff < min)
{
100,
120,
140,
160,
180
}
},
{
PackageVersion.Windows8, new List<int>
{
100
// try to find the closest to 44x44 logo
closest = logo;
if (pixelCountDiff == 0)
break; // found 44x44
min = pixelCountDiff;
}
}
};
if (scaleFactors.ContainsKey(Package.Version))
{
foreach (var factor in scaleFactors[Package.Version])
selected = closest;
if (!string.IsNullOrEmpty(selected))
{
paths.Add($"{prefix}.scale-{factor}{extension}");
return selected;
}
else
{
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
$"|{UserModelId} can't find logo uri for {uri} in package location (can't find specified logo): {Package.Location}", new FileNotFoundException());
return string.Empty;
}
}
var selected = paths.FirstOrDefault(File.Exists);
if (!string.IsNullOrEmpty(selected))
{
return selected;
}
else
{
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
$"|{UserModelId} can't find logo uri for {uri} in package location: {Package.Location}", new FileNotFoundException());
$"|Unable to find extension from {uri} for {UserModelId} " +
$"in package location {Package.Location}", new FileNotFoundException());
return string.Empty;
}
}
else
{
ProgramLogger.LogException($"|UWP|LogoPathFromUri|{Package.Location}" +
$"|Unable to find extension from {uri} for {UserModelId} " +
$"in package location {Package.Location}", new FileNotFoundException());
return string.Empty;
}
}
public ImageSource Logo()
{
var logo = ImageFromPath(LogoPath);
var plated = PlatedImage(logo);
var plated = PlatedImage(logo); // TODO: maybe get plated directly from app package?
// todo magic! temp fix for cross thread object
plated.Freeze();
@ -696,9 +680,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
private BitmapImage ImageFromPath(string path)
{
// TODO: Consider using infrastructure.image.imageloader?
if (File.Exists(path))
{
var image = new BitmapImage(new Uri(path));
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(path);
image.CacheOption = BitmapCacheOption.OnLoad;
image.EndInit();
image.Freeze();
return image;
}
else
@ -770,6 +760,23 @@ namespace Flow.Launcher.Plugin.Program.Programs
{
return $"{DisplayName}: {Description}";
}
public override bool Equals(object obj)
{
if (obj is Application other)
{
return UniqueIdentifier == other.UniqueIdentifier;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return UniqueIdentifier.GetHashCode();
}
}
public enum PackageVersion
@ -785,6 +792,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
{
Read = 0x0,
ShareExclusive = 0x10,
ShareDenyNone = 0x40
}
private enum Hresult : uint

View file

@ -11,12 +11,11 @@ using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin.Program.Logger;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.Infrastructure.Logger;
using System.Collections;
using System.Diagnostics;
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
using System.Diagnostics.CodeAnalysis;
using System.Threading.Channels;
using Flow.Launcher.Plugin.Program.Views.Models;
using IniParser;
namespace Flow.Launcher.Plugin.Program.Programs
{
@ -24,10 +23,21 @@ namespace Flow.Launcher.Plugin.Program.Programs
public class Win32 : IProgram, IEquatable<Win32>
{
public string Name { get; set; }
public string UniqueIdentifier { get; set; }
public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); } // For path comparison
public string IcoPath { get; set; }
/// <summary>
/// Path of the file. It's the path of .lnk or .url for .lnk and .url.
/// </summary>
public string FullPath { get; set; }
/// <summary>
/// Path of the excutable for .lnk, or the URL for .url.
/// </summary>
public string LnkResolvedPath { get; set; }
/// <summary>
/// Path of the actual executable file.
/// </summary>
public string ExecutablePath => LnkResolvedPath ?? FullPath;
public string WorkingDir => Directory.GetParent(ExecutablePath)?.FullName ?? string.Empty;
public string ParentDirectory { get; set; }
public string ExecutableName { get; set; }
public string Description { get; set; }
@ -36,7 +46,9 @@ namespace Flow.Launcher.Plugin.Program.Programs
public string Location => ParentDirectory;
private const string ShortcutExtension = "lnk";
private const string UrlExtension = "url";
private const string ExeExtension = "exe";
private string _uid = string.Empty;
private static readonly Win32 Default = new Win32()
{
@ -96,10 +108,23 @@ namespace Flow.Launcher.Plugin.Program.Programs
matchResult.MatchData = new List<int>();
}
string subtitle = string.Empty;
if (!Main._settings.HideAppsPath)
{
if (Extension(FullPath) == UrlExtension)
{
subtitle = LnkResolvedPath;
}
else
{
subtitle = FullPath;
}
}
var result = new Result
{
Title = title,
SubTitle = Main._settings.HideAppsPath ? string.Empty : LnkResolvedPath ?? FullPath,
SubTitle = subtitle,
IcoPath = IcoPath,
Score = matchResult.Score,
TitleHighlightData = matchResult.MatchData,
@ -115,8 +140,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
var info = new ProcessStartInfo
{
FileName = LnkResolvedPath ?? FullPath,
WorkingDirectory = ParentDirectory,
FileName = ExecutablePath,
WorkingDirectory = WorkingDir,
UseShellExecute = true,
Verb = runAsAdmin ? "runas" : null
};
@ -142,8 +167,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
{
var info = new ProcessStartInfo
{
FileName = FullPath,
WorkingDirectory = ParentDirectory,
FileName = ExecutablePath,
WorkingDirectory = WorkingDir,
UseShellExecute = true
};
@ -161,8 +186,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
{
var info = new ProcessStartInfo
{
FileName = FullPath,
WorkingDirectory = ParentDirectory,
FileName = ExecutablePath,
WorkingDirectory = WorkingDir,
Verb = "runas",
UseShellExecute = true
};
@ -221,11 +246,17 @@ namespace Flow.Launcher.Plugin.Program.Programs
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
$"|Permission denied when trying to load the program from {path}", e);
return new Win32()
{
Valid = false, Enabled = false
};
return Default;
}
#if !DEBUG
catch (Exception e)
{
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
"|An unexpected error occurred in the calling method Win32Program", e);
return Default;
}
#endif
}
private static Win32 LnkProgram(string path)
@ -243,8 +274,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
var extension = Extension(target);
if (extension == ExeExtension && File.Exists(target))
{
program.LnkResolvedPath = program.FullPath;
program.FullPath = Path.GetFullPath(target).ToLower();
program.LnkResolvedPath = Path.GetFullPath(target);
program.ExecutableName = Path.GetFileName(target);
var description = _helper.description;
@ -272,8 +302,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
"|Error caused likely due to trying to get the description of the program",
e);
program.Valid = false;
return program;
return Default;
}
catch (FileNotFoundException e)
{
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
"|An unexpected error occurred in the calling method LnkProgram", e);
return Default;
}
#if !DEBUG //Only do a catch all in production. This is so make developer aware of any unhandled exception and add the exception handling in.
catch (Exception e)
@ -281,12 +317,50 @@ namespace Flow.Launcher.Plugin.Program.Programs
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
"|An unexpected error occurred in the calling method LnkProgram", e);
program.Valid = false;
return program;
return Default;
}
#endif
}
private static Win32 UrlProgram(string path, string[] protocols)
{
var program = Win32Program(path);
program.Valid = false;
try
{
var parser = new FileIniDataParser();
var data = parser.ReadFile(path);
var urlSection = data["InternetShortcut"];
var url = urlSection?["URL"];
if (String.IsNullOrEmpty(url))
{
return program;
}
foreach (var protocol in protocols)
{
if (url.StartsWith(protocol))
{
program.LnkResolvedPath = url;
program.Valid = true;
break;
}
}
var iconPath = urlSection?["IconFile"];
if (!String.IsNullOrEmpty(iconPath))
{
program.IcoPath = iconPath;
}
}
catch (Exception e)
{
// Many files do not have the required fields, so no logging is done.
}
return program;
}
private static Win32 ExeProgram(string path)
{
try
@ -297,35 +371,40 @@ namespace Flow.Launcher.Plugin.Program.Programs
program.Description = info.FileDescription;
return program;
}
catch (FileNotFoundException e)
{
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
$"|File not found when trying to load the program from {path}", e);
return Default;
}
catch (Exception e) when (e is SecurityException || e is UnauthorizedAccessException)
{
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
$"|Permission denied when trying to load the program from {path}", e);
return new Win32()
{
Valid = false, Enabled = false
};
return Default;
}
}
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes)
private static IEnumerable<string> EnumerateProgramsInDir(string directory, string[] suffixes, bool recursive = true)
{
if (!Directory.Exists(directory))
return Enumerable.Empty<string>();
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
{
IgnoreInaccessible = true, RecurseSubdirectories = true
IgnoreInaccessible = true,
RecurseSubdirectories = recursive
}).Where(x => suffixes.Contains(Extension(x)));
}
private static string Extension(string path)
{
var extension = Path.GetExtension(path)?.ToLower();
var extension = Path.GetExtension(path)?.ToLowerInvariant();
if (!string.IsNullOrEmpty(extension))
{
return extension.Substring(1);
return extension.Substring(1); // remove dot
}
else
{
@ -333,44 +412,51 @@ namespace Flow.Launcher.Plugin.Program.Programs
}
}
private static IEnumerable<Win32> UnregisteredPrograms(List<Settings.ProgramSource> sources, string[] suffixes)
private static IEnumerable<Win32> UnregisteredPrograms(List<string> directories, string[] suffixes, string[] protocols)
{
var paths = ExceptDisabledSource(sources.Where(s => Directory.Exists(s.Location) && s.Enabled)
.SelectMany(s => ProgramPaths(s.Location, suffixes)), x => x)
.Distinct();
var programs = paths.Select(x => Extension(x) switch
{
ExeExtension => ExeProgram(x),
ShortcutExtension => LnkProgram(x),
_ => Win32Program(x)
});
// Disabled custom sources are not in DisabledProgramSources
var paths = directories.AsParallel()
.SelectMany(s => EnumerateProgramsInDir(s, suffixes));
// Remove disabled programs in DisabledProgramSources
var programs = ExceptDisabledSource(paths).Select(x => GetProgramFromPath(x, protocols));
return programs;
}
private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes)
private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes, string[] protocols)
{
var disabledProgramsList = Main._settings.DisabledProgramSources;
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
var paths1 = ProgramPaths(directory1, suffixes);
var paths2 = ProgramPaths(directory2, suffixes);
var paths1 = EnumerateProgramsInDir(directory1, suffixes);
var paths2 = EnumerateProgramsInDir(directory2, suffixes);
var toFilter = paths1.Concat(paths2);
var programs = ExceptDisabledSource(toFilter.Distinct())
.Select(x => Extension(x) switch
{
ShortcutExtension => LnkProgram(x),
_ => Win32Program(x)
}).Where(x => x.Valid);
.Select(x => GetProgramFromPath(x, protocols));
return programs;
}
private static IEnumerable<Win32> AppPathsPrograms(string[] suffixes)
private static IEnumerable<Win32> PATHPrograms(string[] suffixes, string[] protocols, List<string> commonParents)
{
var pathEnv = Environment.GetEnvironmentVariable("Path");
if (String.IsNullOrEmpty(pathEnv))
{
return Array.Empty<Win32>();
}
var paths = pathEnv.Split(";", StringSplitOptions.RemoveEmptyEntries).DistinctBy(p => p.ToLowerInvariant());
var toFilter = paths.Where(x => commonParents.All(parent => !IsSubPathOf(x, parent)))
.AsParallel()
.SelectMany(p => EnumerateProgramsInDir(p, suffixes, recursive: false));
var programs = ExceptDisabledSource(toFilter.Distinct())
.Select(x => GetProgramFromPath(x, protocols));
return programs;
}
private static IEnumerable<Win32> AppPathsPrograms(string[] suffixes, string[] protocols)
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
const string appPaths = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
@ -390,12 +476,11 @@ namespace Flow.Launcher.Plugin.Program.Programs
toFilter = toFilter.Concat(GetPathFromRegistry(rootUser));
}
toFilter = toFilter.Distinct().Where(p => suffixes.Contains(Extension(p)));
var filtered = ExceptDisabledSource(toFilter);
return filtered.Select(GetProgramFromPath).ToList(); // ToList due to disposing issue
var programs = ExceptDisabledSource(toFilter)
.Select(x => GetProgramFromPath(x, protocols)).Where(x => x.Valid).ToList(); // ToList due to disposing issue
return programs;
}
private static IEnumerable<string> GetPathFromRegistry(RegistryKey root)
@ -435,24 +520,25 @@ namespace Flow.Launcher.Plugin.Program.Programs
}
}
private static Win32 GetProgramFromPath(string path)
private static Win32 GetProgramFromPath(string path, string[] protocols)
{
if (string.IsNullOrEmpty(path))
return Default;
path = Environment.ExpandEnvironmentVariables(path);
if (!File.Exists(path))
return Default;
var entry = Win32Program(path);
return entry;
return Extension(path) switch
{
ShortcutExtension => LnkProgram(path),
ExeExtension => ExeProgram(path),
UrlExtension => UrlProgram(path, protocols),
_ => Win32Program(path)
}; ;
}
public static IEnumerable<string> ExceptDisabledSource(IEnumerable<string> sources)
public static IEnumerable<string> ExceptDisabledSource(IEnumerable<string> paths)
{
return ExceptDisabledSource(sources, x => x);
return ExceptDisabledSource(paths, x => x.ToLowerInvariant());
}
public static IEnumerable<TSource> ExceptDisabledSource<TSource>(IEnumerable<TSource> sources,
@ -487,14 +573,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
private static IEnumerable<Win32> ProgramsHasher(IEnumerable<Win32> programs)
{
return programs.GroupBy(p => p.FullPath.ToLower())
return programs.GroupBy(p => p.ExecutablePath.ToLowerInvariant())
.AsParallel()
.SelectMany(g =>
{
var temp = g.Where(g => !string.IsNullOrEmpty(g.Description)).ToList();
if (temp.Any())
return DistinctBy(temp, x => x.Description);
return g.Take(1);
}).ToArray();
});
}
@ -503,28 +590,40 @@ namespace Flow.Launcher.Plugin.Program.Programs
try
{
var programs = Enumerable.Empty<Win32>();
var suffixes = settings.GetSuffixes();
var protocols = settings.GetProtocols();
var unregistered = UnregisteredPrograms(settings.ProgramSources, settings.ProgramSuffixes);
// Disabled custom sources are not in DisabledProgramSources
var sources = settings.ProgramSources.Where(s => Directory.Exists(s.Location) && s.Enabled).Distinct();
var commonParents = GetCommonParents(sources);
var unregistered = UnregisteredPrograms(commonParents, suffixes, protocols);
programs = programs.Concat(unregistered);
var autoIndexPrograms = Enumerable.Empty<Win32>();
var autoIndexPrograms = Enumerable.Empty<Win32>(); // for single programs, not folders
if (settings.EnableRegistrySource)
{
var appPaths = AppPathsPrograms(settings.ProgramSuffixes);
var appPaths = AppPathsPrograms(suffixes, protocols);
autoIndexPrograms = autoIndexPrograms.Concat(appPaths);
}
if (settings.EnableStartMenuSource)
{
var startMenu = StartMenuPrograms(settings.ProgramSuffixes);
var startMenu = StartMenuPrograms(suffixes, protocols);
autoIndexPrograms = autoIndexPrograms.Concat(startMenu);
}
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
if (settings.EnablePATHSource)
{
var path = PATHPrograms(settings.GetSuffixes(), protocols, commonParents);
programs = programs.Concat(path);
}
return programs.Concat(autoIndexPrograms).Distinct().ToArray();
autoIndexPrograms = ProgramsHasher(autoIndexPrograms).ToArray();
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();
}
#if DEBUG //This is to make developer aware of any unhandled exception and add in handling.
catch (Exception)
@ -556,6 +655,18 @@ namespace Flow.Launcher.Plugin.Program.Programs
return UniqueIdentifier == other.UniqueIdentifier;
}
public override bool Equals(object obj)
{
if (obj is Win32 other)
{
return UniqueIdentifier == other.UniqueIdentifier;
}
else
{
return false;
}
}
private static IEnumerable<string> GetStartMenuPaths()
{
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
@ -572,11 +683,13 @@ namespace Flow.Launcher.Plugin.Program.Programs
if (settings.EnableStartMenuSource)
paths.AddRange(GetStartMenuPaths());
paths.AddRange(from source in settings.ProgramSources where source.Enabled select source.Location);
var customSources = GetCommonParents(settings.ProgramSources);
paths.AddRange(customSources);
var fileExtensionToWatch = settings.GetSuffixes();
foreach (var directory in from path in paths where Directory.Exists(path) select path)
{
WatchDirectory(directory);
WatchDirectory(directory, fileExtensionToWatch);
}
_ = Task.Run(MonitorDirectoryChangeAsync);
@ -596,8 +709,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
await Task.Run(Main.IndexWin32Programs);
}
}
public static void WatchDirectory(string directory)
public static void WatchDirectory(string directory, string[] extensions)
{
if (!Directory.Exists(directory))
{
@ -609,7 +722,11 @@ namespace Flow.Launcher.Plugin.Program.Programs
watcher.Deleted += static (_, _) => indexQueue.Writer.TryWrite(default);
watcher.EnableRaisingEvents = true;
watcher.IncludeSubdirectories = true;
foreach (var extension in extensions)
{
watcher.Filters.Add($"*.{extension}");
}
Watchers.Add(watcher);
}
@ -620,5 +737,38 @@ namespace Flow.Launcher.Plugin.Program.Programs
fileSystemWatcher.Dispose();
}
}
// https://stackoverflow.com/a/66877016
private static bool IsSubPathOf(string subPath, string basePath)
{
var rel = Path.GetRelativePath(basePath, subPath);
return rel != "."
&& rel != ".."
&& !rel.StartsWith("../")
&& !rel.StartsWith(@"..\")
&& !Path.IsPathRooted(rel);
}
private static List<string> GetCommonParents(IEnumerable<ProgramSource> programSources)
{
// To avoid unnecessary io
// like c:\windows and c:\windows\system32
var grouped = programSources.GroupBy(p => p.Location.ToLowerInvariant()[0]); // group by disk
List<string> result = new();
foreach (var group in grouped)
{
HashSet<ProgramSource> parents = group.ToHashSet();
foreach (var source in group)
{
if (parents.Any(p => IsSubPathOf(source.Location, p.Location) &&
source != p))
{
parents.Remove(source);
}
}
result.AddRange(parents.Select(x => x.Location));
}
return result.DistinctBy(x => x.ToLowerInvariant()).ToList();
}
}
}

View file

@ -1,48 +1,132 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using Flow.Launcher.Plugin.Program.Views.Models;
namespace Flow.Launcher.Plugin.Program
{
public class Settings
{
public DateTime LastIndexTime { get; set; }
/// <summary>
/// User-added program sources' directories
/// </summary>
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
public List<DisabledProgramSource> DisabledProgramSources { get; set; } = new List<DisabledProgramSource>();
public string[] ProgramSuffixes { get; set; } = {"appref-ms", "exe", "lnk"};
/// <summary>
/// Disabled single programs, not including User-added directories
/// </summary>
public List<ProgramSource> DisabledProgramSources { get; set; } = new List<ProgramSource>();
[Obsolete("Should use GetSuffixes() instead."), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string[] ProgramSuffixes { get; set; } = null;
public string[] CustomSuffixes { get; set; } = Array.Empty<string>(); // Custom suffixes only
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
public Dictionary<string, bool> BuiltinSuffixesStatus { get; set; } = new Dictionary<string, bool>{
{ "exe", true }, { "appref-ms", true }, { "lnk", true }
};
public Dictionary<string, bool> BuiltinProtocolsStatus { get; set; } = new Dictionary<string, bool>{
{ "steam", true }, { "epic", true }, { "http", false }
};
[JsonIgnore]
public Dictionary<string, string> BuiltinProtocols { get; set; } = new Dictionary<string, string>{
{ "steam", $"steam://run/{SuffixSeparator}steam://rungameid/" }, { "epic", "com.epicgames.launcher://apps/" }, { "http", $"http://{SuffixSeparator}https://"}
};
public bool UseCustomSuffixes { get; set; } = false;
public bool UseCustomProtocols { get; set; } = false;
public string[] GetSuffixes()
{
RemoveRedundantSuffixes();
List<string> extensions = new List<string>();
foreach (var item in BuiltinSuffixesStatus)
{
if (item.Value)
{
extensions.Add(item.Key);
}
}
if (BuiltinProtocolsStatus.Values.Any(x => x == true) || UseCustomProtocols)
{
extensions.Add("url");
}
if (UseCustomSuffixes)
{
return extensions.Concat(CustomSuffixes).DistinctBy(x => x.ToLower()).ToArray();
}
else
{
return extensions.DistinctBy(x => x.ToLower()).ToArray();
}
}
public string[] GetProtocols()
{
List<string> protocols = new List<string>();
foreach (var item in BuiltinProtocolsStatus)
{
if (item.Value)
{
if (BuiltinProtocols.TryGetValue(item.Key, out string ps))
{
var tmp = ps.Split(SuffixSeparator, StringSplitOptions.RemoveEmptyEntries);
foreach (var protocol in tmp)
{
protocols.Add(protocol);
}
}
}
}
if (UseCustomProtocols)
{
return protocols.Concat(CustomProtocols).DistinctBy(x => x.ToLower()).ToArray();
}
else
{
return protocols.DistinctBy(x => x.ToLower()).ToArray();
}
}
private void RemoveRedundantSuffixes()
{
// Migrate to new settings
// CustomSuffixes no longer contains custom suffixes
// users has tweaked the settings
// or this function has been executed once
if (UseCustomSuffixes == true || ProgramSuffixes == null)
return;
var suffixes = ProgramSuffixes.ToList();
foreach(var item in BuiltinSuffixesStatus)
{
suffixes.Remove(item.Key);
}
CustomSuffixes = suffixes.ToArray(); // Custom suffixes
UseCustomSuffixes = CustomSuffixes.Length != 0; // Search custom suffixes or not
ProgramSuffixes = null;
}
public bool EnableStartMenuSource { get; set; } = true;
public bool EnableDescription { get; set; } = false;
public bool HideAppsPath { get; set; } = true;
public bool EnableRegistrySource { get; set; } = true;
public bool EnablePATHSource { get; set; } = true;
public string CustomizedExplorer { get; set; } = Explorer;
public string CustomizedArgs { get; set; } = ExplorerArgs;
internal const char SuffixSeperator = ';';
internal const char SuffixSeparator = ';';
internal const string Explorer = "explorer";
internal const string ExplorerArgs = "%s";
/// <summary>
/// Contains user added folder location contents as well as all user disabled applications
/// </summary>
/// <remarks>
/// <para>Win32 class applications set UniqueIdentifier using their full file path</para>
/// <para>UWP class applications set UniqueIdentifier using their Application User Model ID</para>
/// <para>Custom user added program sources set UniqueIdentifier using their location</para>
/// </remarks>
public class ProgramSource
{
private string name;
public string Location { get; set; }
public string Name { get => name ?? new DirectoryInfo(Location).Name; set => name = value; }
public bool Enabled { get; set; } = true;
public string UniqueIdentifier { get; set; }
}
public class DisabledProgramSource : ProgramSource { }
}
}

View file

@ -12,7 +12,7 @@ namespace Flow.Launcher.Plugin.Program
var text = value as string[];
if (text != null)
{
return string.Join(";", text);
return string.Join(Settings.SuffixSeparator, text);
}
else
{

View file

@ -1,146 +1,88 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flow.Launcher.Plugin.Program.Views.Models;
namespace Flow.Launcher.Plugin.Program.Views.Commands
{
internal static class ProgramSettingDisplay
{
internal static List<ProgramSource> LoadProgramSources(this List<Settings.ProgramSource> programSources)
internal static List<ProgramSource> LoadProgramSources()
{
var list = new List<ProgramSource>();
programSources.ForEach(x => list
.Add(
new ProgramSource
{
Enabled = x.Enabled,
Location = x.Location,
Name = x.Name,
UniqueIdentifier = x.UniqueIdentifier
}
));
// Even though these are disabled, we still want to display them so users can enable later on
Main._settings
.DisabledProgramSources
.Where(t1 => !Main._settings
.ProgramSources // program sourcces added above already, so exlcude
.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
.Select(x => x)
.ToList()
.ForEach(x => list
.Add(
new ProgramSource
{
Enabled = x.Enabled,
Location = x.Location,
Name = x.Name,
UniqueIdentifier = x.UniqueIdentifier
}
));
return list;
return Main._settings
.DisabledProgramSources
.Union(Main._settings.ProgramSources)
.ToList();
}
internal static void LoadAllApplications(this List<ProgramSource> list)
internal static void DisplayAllPrograms()
{
Main._win32s
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
.ToList()
.ForEach(t1 => ProgramSetting.ProgramSettingDisplayList
.Add(
new ProgramSource
{
Name = t1.Name,
Location = t1.ParentDirectory,
UniqueIdentifier = t1.UniqueIdentifier,
Enabled = t1.Enabled
}
));
var win32 = Main._win32s
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
.Select(x => new ProgramSource(x));
Main._uwps
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
.ToList()
.ForEach(t1 => ProgramSetting.ProgramSettingDisplayList
.Add(
new ProgramSource
{
Name = t1.DisplayName,
Location = t1.Package.Location,
UniqueIdentifier = t1.UniqueIdentifier,
Enabled = t1.Enabled
}
));
var uwp = Main._uwps
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
.Select(x => new ProgramSource(x));
ProgramSetting.ProgramSettingDisplayList.AddRange(win32);
ProgramSetting.ProgramSettingDisplayList.AddRange(uwp);
}
internal static void SetProgramSourcesStatus(this List<ProgramSource> list, List<ProgramSource> selectedProgramSourcesToDisable, bool status)
internal static void SetProgramSourcesStatus(List<ProgramSource> selectedProgramSourcesToDisable, bool status)
{
ProgramSetting.ProgramSettingDisplayList
.Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
.ToList()
.ForEach(t1 => t1.Enabled = status);
foreach(var program in ProgramSetting.ProgramSettingDisplayList)
{
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
{
program.Enabled = status;
}
}
Main._win32s
.Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
.ToList()
.ForEach(t1 => t1.Enabled = status);
foreach(var program in Main._win32s)
{
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
{
program.Enabled = status;
}
}
Main._uwps
.Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
.ToList()
.ForEach(t1 => t1.Enabled = status);
foreach (var program in Main._uwps)
{
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
{
program.Enabled = status;
}
}
}
internal static void StoreDisabledInSettings(this List<ProgramSource> list)
internal static void StoreDisabledInSettings()
{
Main._settings.ProgramSources
.Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && !x.Enabled))
.ToList()
.ForEach(t1 => t1.Enabled = false);
ProgramSetting.ProgramSettingDisplayList
// Disabled, not in DisabledProgramSources or ProgramSources
var tmp = ProgramSetting.ProgramSettingDisplayList
.Where(t1 => !t1.Enabled
&& !Main._settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
.ToList()
.ForEach(x => Main._settings.DisabledProgramSources
.Add(
new Settings.DisabledProgramSource
{
Name = x.Name,
Location = x.Location,
UniqueIdentifier = x.UniqueIdentifier,
Enabled = false
}
));
&& !Main._settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier)
&& !Main._settings.ProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
Main._settings.DisabledProgramSources.AddRange(tmp);
}
internal static void RemoveDisabledFromSettings(this List<ProgramSource> list)
internal static void RemoveDisabledFromSettings()
{
Main._settings.ProgramSources
.Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && x.Enabled))
.ToList()
.ForEach(t1 => t1.Enabled = true);
Main._settings.DisabledProgramSources
.Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && x.Enabled))
.ToList()
.ForEach(x => Main._settings.DisabledProgramSources.Remove(x));
Main._settings.DisabledProgramSources.RemoveAll(t1 => t1.Enabled);
}
internal static bool IsReindexRequired(this List<ProgramSource> selectedItems)
{
if (selectedItems.Where(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0
&& selectedItems.Where(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0)
// Not in cache
if (selectedItems.Any(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
&& selectedItems.Any(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)))
return true;
// ProgramSources holds list of user added directories,
// so when we enable/disable we need to reindex to show/not show the programs
// that are found in those directories.
if (selectedItems.Where(t1 => Main._settings.ProgramSources.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0)
if (selectedItems.Any(t1 => Main._settings.ProgramSources.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)))
return true;
return false;

View file

@ -1,5 +1,89 @@

using System;
using System.IO;
using System.Text.Json.Serialization;
using Flow.Launcher.Plugin.Program.Programs;
namespace Flow.Launcher.Plugin.Program.Views.Models
{
public class ProgramSource : Settings.ProgramSource { }
/// <summary>
/// Contains user added folder location contents as well as all user disabled applications
/// </summary>
/// <remarks>
/// <para>Win32 class applications set UniqueIdentifier using their full file path</para>
/// <para>UWP class applications set UniqueIdentifier using their Application User Model ID</para>
/// <para>Custom user added program sources set UniqueIdentifier using their location</para>
/// </remarks>
public class ProgramSource
{
private string name = string.Empty;
private string loc = string.Empty;
private string uniqueIdentifier = string.Empty;
public string Location
{
get => loc;
set
{
loc = value ?? string.Empty;
UniqueIdentifier = value;
}
}
public string Name { get => name; set => name = value ?? string.Empty; }
public bool Enabled { get; set; } = true;
public string UniqueIdentifier
{
get => uniqueIdentifier;
private set
{
uniqueIdentifier = value == null ? string.Empty : value.ToLowerInvariant();
}
}
[JsonConstructor]
public ProgramSource(string name, string location, bool enabled, string uniqueIdentifier)
{
loc = location ?? string.Empty;
Name = name;
Enabled = enabled;
UniqueIdentifier = uniqueIdentifier;
}
/// <summary>
/// Add source by location
/// </summary>
/// <param name="location">location of program source</param>
/// <param name="enabled">enabled</param>
public ProgramSource(string location, bool enabled = true)
{
loc = location ?? string.Empty;
Enabled = enabled;
UniqueIdentifier = location; // For path comparison
Name = new DirectoryInfo(Location).Name;
}
public ProgramSource(IProgram source)
{
loc = source.Location ?? string.Empty;
Name = source.Name;
Enabled = source.Enabled;
UniqueIdentifier = source.UniqueIdentifier;
}
public override bool Equals(object obj)
{
return obj is ProgramSource other && other.UniqueIdentifier == this.UniqueIdentifier;
}
public bool Equals(IProgram program)
{
return program != null && program.UniqueIdentifier == this.UniqueIdentifier;
}
public override int GetHashCode()
{
return HashCode.Combine(UniqueIdentifier);
}
}
}

View file

@ -10,58 +10,89 @@
mc:Ignorable="d">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="170" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="60" />
</Grid.RowDefinitions>
<DockPanel
Margin="70,10,0,8"
HorizontalAlignment="Stretch"
LastChildFill="True">
<TextBlock
MinWidth="120"
Margin="0,5,10,0"
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
<WrapPanel
Width="Auto"
Margin="0,0,14,0"
HorizontalAlignment="Right"
DockPanel.Dock="Right">
<CheckBox
Name="StartMenuEnabled"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
IsChecked="{Binding EnableStartMenuSource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
<CheckBox
Name="RegistryEnabled"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
IsChecked="{Binding EnableRegistrySource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
<CheckBox
Name="PATHEnabled"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
IsChecked="{Binding EnablePATHSource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
</WrapPanel>
</DockPanel>
<StackPanel
Grid.Row="0"
Grid.Row="1"
HorizontalAlignment="Stretch"
Orientation="Vertical">
<StackPanel Width="Auto" Orientation="Vertical">
<StackPanel Width="Auto" Orientation="Horizontal">
<CheckBox
Name="StartMenuEnabled"
Width="220"
Margin="70,8,10,8"
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
IsChecked="{Binding EnableStartMenuSource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
<CheckBox
Name="RegistryEnabled"
Margin="70,8,10,8"
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
IsChecked="{Binding EnableRegistrySource}"
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
</StackPanel>
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
<StackPanel Width="Auto" Orientation="Horizontal">
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
<DockPanel
Margin="70,10,0,8"
HorizontalAlignment="Stretch"
LastChildFill="True">
<TextBlock
MinWidth="120"
Margin="0,5,10,0"
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
<WrapPanel
Width="Auto"
Margin="0,0,14,0"
HorizontalAlignment="Right"
DockPanel.Dock="Right">
<CheckBox
Name="HideLnkEnabled"
Width="220"
Margin="70,8,10,8"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
IsChecked="{Binding HideAppsPath}"
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
<CheckBox
Name="DescriptionEnabled"
Margin="70,8,10,8"
Margin="12,0,12,0"
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
IsChecked="{Binding EnableDescription}"
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
</StackPanel>
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
</StackPanel>
</WrapPanel>
</DockPanel>
<Separator
Height="1"
BorderBrush="{DynamicResource Color03B}"
BorderThickness="1" />
<StackPanel
Width="Auto"
Margin="10,6,0,0"
Height="55"
Margin="60,6,0,0"
HorizontalAlignment="Left"
Orientation="Horizontal">
<Button
@ -107,15 +138,17 @@
</StackPanel>
<ListView
x:Name="programSourceView"
Grid.Row="1"
Margin="20,0,20,0"
Grid.Row="2"
Margin="70,0,20,0"
AllowDrop="True"
BorderBrush="DarkGray"
BorderThickness="1"
DragEnter="programSourceView_DragEnter"
Drop="programSourceView_Drop"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"
MouseDoubleClick="programSourceView_MouseDoubleClick"
PreviewMouseRightButtonUp="ProgramSourceView_PreviewMouseRightButtonUp"
SelectionChanged="programSourceView_SelectionChanged"
SelectionMode="Extended">
<ListView.View>
<GridView>
@ -126,7 +159,7 @@
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{DynamicResource flowlauncher_plugin_program_enable}">
<GridViewColumn Header="{DynamicResource flowlauncher_plugin_program_enabled}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock
@ -147,7 +180,7 @@
</ListView.View>
</ListView>
<DockPanel
Grid.Row="2"
Grid.Row="3"
Grid.RowSpan="1"
Margin="0,0,20,10">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
@ -173,66 +206,3 @@
</DockPanel>
</Grid>
</UserControl>

View file

@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
@ -36,6 +35,7 @@ namespace Flow.Launcher.Plugin.Program.Views
_settings.EnableDescription = value;
}
}
public bool HideAppsPath
{
get => _settings.HideAppsPath;
@ -66,6 +66,16 @@ namespace Flow.Launcher.Plugin.Program.Views
}
}
public bool EnablePATHSource
{
get => _settings.EnablePATHSource;
set
{
_settings.EnablePATHSource = value;
ReIndexing();
}
}
public string CustomizedExplorerPath
{
get => _settings.CustomizedExplorer;
@ -88,7 +98,7 @@ namespace Flow.Launcher.Plugin.Program.Views
private void Setting_Loaded(object sender, RoutedEventArgs e)
{
ProgramSettingDisplayList = _settings.ProgramSources.LoadProgramSources();
ProgramSettingDisplayList = ProgramSettingDisplay.LoadProgramSources();
programSourceView.ItemsSource = ProgramSettingDisplayList;
ViewRefresh();
@ -147,20 +157,35 @@ namespace Flow.Launcher.Plugin.Program.Views
private void btnEditProgramSource_OnClick(object sender, RoutedEventArgs e)
{
var selectedProgramSource = programSourceView.SelectedItem as Settings.ProgramSource;
if (selectedProgramSource != null)
{
var add = new AddProgramSource(selectedProgramSource, _settings);
if (add.ShowDialog() ?? false)
{
ReIndexing();
}
}
else
var selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
EditProgramSource(selectedProgramSource);
}
private void EditProgramSource(ProgramSource selectedProgramSource)
{
if (selectedProgramSource == null)
{
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
MessageBox.Show(msg);
}
else
{
var add = new AddProgramSource(context, _settings, selectedProgramSource);
if (add.ShowDialog() ?? false)
{
if (selectedProgramSource.Enabled)
{
ProgramSettingDisplay.SetProgramSourcesStatus(new List<ProgramSource> { selectedProgramSource }, true); // sync status in win32, uwp and disabled
ProgramSettingDisplay.RemoveDisabledFromSettings();
}
else
{
ProgramSettingDisplay.SetProgramSourcesStatus(new List<ProgramSource> { selectedProgramSource }, false);
ProgramSettingDisplay.StoreDisabledInSettings();
}
ReIndexing();
}
}
}
private void btnReindex_Click(object sender, RoutedEventArgs e)
@ -199,19 +224,16 @@ namespace Flow.Launcher.Plugin.Program.Views
{
foreach (string directory in directories)
{
if (Directory.Exists(directory) && !ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == directory))
if (Directory.Exists(directory)
&& !ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(directory, System.StringComparison.OrdinalIgnoreCase)))
{
var source = new ProgramSource
{
Location = directory,
UniqueIdentifier = directory
};
var source = new ProgramSource(directory);
directoriesToAdd.Add(source);
}
}
if (directoriesToAdd.Count() > 0)
if (directoriesToAdd.Count > 0)
{
directoriesToAdd.ForEach(x => _settings.ProgramSources.Add(x));
directoriesToAdd.ForEach(x => ProgramSettingDisplayList.Add(x));
@ -224,7 +246,7 @@ namespace Flow.Launcher.Plugin.Program.Views
private void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e)
{
ProgramSettingDisplayList.LoadAllApplications();
ProgramSettingDisplay.DisplayAllPrograms();
ViewRefresh();
}
@ -235,18 +257,14 @@ namespace Flow.Launcher.Plugin.Program.Views
.SelectedItems.Cast<ProgramSource>()
.ToList();
if (selectedItems.Count() == 0)
if (selectedItems.Count == 0)
{
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
MessageBox.Show(msg);
return;
}
if (selectedItems
.Where(t1 => !_settings
.ProgramSources
.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
.Count() == 0)
if (IsAllItemsUserAdded(selectedItems))
{
var msg = string.Format(context.API.GetTranslation("flowlauncher_plugin_program_delete_program_source"));
@ -257,17 +275,17 @@ namespace Flow.Launcher.Plugin.Program.Views
DeleteProgramSources(selectedItems);
}
else if (IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(selectedItems))
else if (HasMoreOrEqualEnabledItems(selectedItems))
{
ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, false);
ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, false);
ProgramSettingDisplayList.StoreDisabledInSettings();
ProgramSettingDisplay.StoreDisabledInSettings();
}
else
{
ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, true);
ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, true);
ProgramSettingDisplayList.RemoveDisabledFromSettings();
ProgramSettingDisplay.RemoveDisabledFromSettings();
}
if (selectedItems.IsReindexRequired())
@ -329,35 +347,41 @@ namespace Flow.Launcher.Plugin.Program.Views
dataView.Refresh();
}
private bool IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(List<ProgramSource> selectedItems)
private static bool HasMoreOrEqualEnabledItems(List<ProgramSource> items)
{
return selectedItems.Where(x => x.Enabled).Count() >= selectedItems.Where(x => !x.Enabled).Count();
var enableCount = items.Where(x => x.Enabled).Count();
return enableCount >= items.Count - enableCount;
}
private void Row_OnClick(object sender, RoutedEventArgs e)
private void programSourceView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItems = programSourceView
.SelectedItems.Cast<ProgramSource>()
.ToList();
.SelectedItems.Cast<ProgramSource>()
.ToList();
if (selectedItems
.Where(t1 => !_settings
.ProgramSources
.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
.Count() == 0)
if (IsAllItemsUserAdded(selectedItems))
{
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_delete");
return;
}
if (IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(selectedItems))
else if (HasMoreOrEqualEnabledItems(selectedItems))
{
btnProgramSourceStatus.Content = "Disable";
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_disable");
}
else
{
btnProgramSourceStatus.Content = "Enable";
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_enable");
}
}
private void programSourceView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
EditProgramSource(selectedProgramSource);
}
private bool IsAllItemsUserAdded(List<ProgramSource> items)
{
return items.All(x => _settings.ProgramSources.Any(y => y.UniqueIdentifier == x.UniqueIdentifier));
}
}
}
}

View file

@ -4,9 +4,17 @@ init:
- ps: |
$version = new-object System.Version $env:APPVEYOR_BUILD_VERSION
$env:flowVersion = "{0}.{1}.{2}" -f $version.Major, $version.Minor, $version.Build
if ($env:APPVEYOR_REPO_BRANCH -eq "dev")
{
$env:prereleaseTag = "{0}.{1}.{2}.{3}" -f $version.Major, $version.Minor, $version.Build, $version.Revision
}
- sc config WSearch start= auto # Starts Windows Search service- Needed for running ExplorerTest
- net start WSearch
cache:
- '%USERPROFILE%\.nuget\packages -> **.sln, **.csproj' # preserve nuget folder (packages) unless the solution or projects change
assembly_info:
patch: true
file: SolutionAssemblyInfo.cs
@ -14,12 +22,6 @@ assembly_info:
assembly_file_version: $(flowVersion)
assembly_informational_version: $(flowVersion)
skip_branch_with_pr: true
skip_commits:
files:
- '*.md'
image: Visual Studio 2022
platform: Any CPU
configuration: Release
@ -28,7 +30,9 @@ before_build:
build:
project: Flow.Launcher.sln
verbosity: minimal
after_build:
test_script:
- dotnet test --no-build -c Release
after_test:
- ps: .\Scripts\post_build.ps1
artifacts:
@ -51,6 +55,17 @@ deploy:
on:
APPVEYOR_REPO_TAG: true
- provider: GitHub
repository: Flow-Launcher/Prereleases
release: v$(prereleaseTag)
description: 'This is the early access build of our upcoming release. All changes contained here are reviewed, tested and stable to use.\n\nSee our [release](https://github.com/Flow-Launcher/Flow.Launcher/pulls?q=is%3Aopen+is%3Apr+label%3Arelease) Pull Request for details.\n\nFor latest production release visit [here](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest)\n\nPlease report any bugs or issues over at the [main repository](https://github.com/Flow-Launcher/Flow.Launcher/issues)'
auth_token:
secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv
artifact: Squirrel Installer, Portable Version, Squirrel nupkg, Squirrel RELEASES
force_update: true
on:
branch: dev
- provider: GitHub
release: v$(flowVersion)
auth_token: