mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into search_delay
This commit is contained in:
commit
1e0118604c
63 changed files with 3358 additions and 2475 deletions
|
|
@ -1,18 +1,14 @@
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Forms;
|
|
||||||
using Flow.Launcher.Infrastructure.Storage;
|
using Flow.Launcher.Infrastructure.Storage;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using CheckBox = System.Windows.Controls.CheckBox;
|
|
||||||
using ComboBox = System.Windows.Controls.ComboBox;
|
#nullable enable
|
||||||
using Control = System.Windows.Controls.Control;
|
|
||||||
using Orientation = System.Windows.Controls.Orientation;
|
|
||||||
using TextBox = System.Windows.Controls.TextBox;
|
|
||||||
using UserControl = System.Windows.Controls.UserControl;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Core.Plugin
|
namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
|
|
@ -23,51 +19,72 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
public required string SettingPath { get; init; }
|
public required string SettingPath { get; init; }
|
||||||
public Dictionary<string, FrameworkElement> SettingControls { get; } = new();
|
public Dictionary<string, FrameworkElement> SettingControls { get; } = new();
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, object> Inner => Settings;
|
public IReadOnlyDictionary<string, object?> Inner => Settings;
|
||||||
protected ConcurrentDictionary<string, object> Settings { get; set; }
|
protected ConcurrentDictionary<string, object?> Settings { get; set; } = null!;
|
||||||
public required IPublicAPI API { get; init; }
|
public required IPublicAPI API { get; init; }
|
||||||
|
|
||||||
private JsonStorage<ConcurrentDictionary<string, object>> _storage;
|
private JsonStorage<ConcurrentDictionary<string, object?>> _storage = null!;
|
||||||
|
|
||||||
// maybe move to resource?
|
private static readonly Thickness SettingPanelMargin = (Thickness)Application.Current.FindResource("SettingPanelMargin");
|
||||||
private static readonly Thickness settingControlMargin = new(0, 9, 18, 9);
|
private static readonly Thickness SettingPanelItemLeftMargin = (Thickness)Application.Current.FindResource("SettingPanelItemLeftMargin");
|
||||||
private static readonly Thickness settingCheckboxMargin = new(0, 9, 9, 9);
|
private static readonly Thickness SettingPanelItemTopBottomMargin = (Thickness)Application.Current.FindResource("SettingPanelItemTopBottomMargin");
|
||||||
private static readonly Thickness settingPanelMargin = new(0, 0, 0, 0);
|
private static readonly Thickness SettingPanelItemLeftTopBottomMargin = (Thickness)Application.Current.FindResource("SettingPanelItemLeftTopBottomMargin");
|
||||||
private static readonly Thickness settingTextBlockMargin = new(70, 9, 18, 9);
|
private static readonly double SettingPanelTextBoxMinWidth = (double)Application.Current.FindResource("SettingPanelTextBoxMinWidth");
|
||||||
private static readonly Thickness settingLabelPanelMargin = new(70, 9, 18, 9);
|
private static readonly double SettingPanelPathTextBoxWidth = (double)Application.Current.FindResource("SettingPanelPathTextBoxWidth");
|
||||||
private static readonly Thickness settingLabelMargin = new(0, 0, 0, 0);
|
private static readonly double SettingPanelAreaTextBoxMinHeight = (double)Application.Current.FindResource("SettingPanelAreaTextBoxMinHeight");
|
||||||
private static readonly Thickness settingDescMargin = new(0, 2, 0, 0);
|
|
||||||
private static readonly Thickness settingSepMargin = new(0, 0, 0, 2);
|
|
||||||
|
|
||||||
public async Task InitializeAsync()
|
public async Task InitializeAsync()
|
||||||
{
|
{
|
||||||
_storage = new JsonStorage<ConcurrentDictionary<string, object>>(SettingPath);
|
if (Settings == null)
|
||||||
Settings = await _storage.LoadAsync();
|
|
||||||
|
|
||||||
if (Configuration == null)
|
|
||||||
{
|
{
|
||||||
return;
|
_storage = new JsonStorage<ConcurrentDictionary<string, object?>>(SettingPath);
|
||||||
|
Settings = await _storage.LoadAsync();
|
||||||
|
|
||||||
|
// Because value type of settings dictionary is object which causes them to be JsonElement when loading from json files,
|
||||||
|
// we need to convert it to the correct type
|
||||||
|
foreach (var (key, value) in Settings)
|
||||||
|
{
|
||||||
|
if (value is not JsonElement jsonElement) continue;
|
||||||
|
|
||||||
|
Settings[key] = jsonElement.ValueKind switch
|
||||||
|
{
|
||||||
|
JsonValueKind.String => jsonElement.GetString() ?? value,
|
||||||
|
JsonValueKind.True => jsonElement.GetBoolean(),
|
||||||
|
JsonValueKind.False => jsonElement.GetBoolean(),
|
||||||
|
JsonValueKind.Null => null,
|
||||||
|
_ => value
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Configuration == null) return;
|
||||||
|
|
||||||
foreach (var (type, attributes) in Configuration.Body)
|
foreach (var (type, attributes) in Configuration.Body)
|
||||||
{
|
{
|
||||||
if (attributes.Name == null)
|
// Skip if the setting does not have attributes or name
|
||||||
{
|
if (attributes?.Name == null) continue;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Settings.ContainsKey(attributes.Name))
|
// Skip if the setting does not have attributes or name
|
||||||
|
if (!NeedSaveInSettings(type)) continue;
|
||||||
|
|
||||||
|
// If need save in settings, we need to make sure the setting exists in the settings file
|
||||||
|
if (Settings.ContainsKey(attributes.Name)) continue;
|
||||||
|
|
||||||
|
if (type == "checkbox")
|
||||||
|
{
|
||||||
|
// If can parse the default value to bool, use it, otherwise use false
|
||||||
|
Settings[attributes.Name] = bool.TryParse(attributes.DefaultValue, out var value) && value;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Settings[attributes.Name] = attributes.DefaultValue;
|
Settings[attributes.Name] = attributes.DefaultValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void UpdateSettings(IReadOnlyDictionary<string, object> settings)
|
public void UpdateSettings(IReadOnlyDictionary<string, object> settings)
|
||||||
{
|
{
|
||||||
if (settings == null || settings.Count == 0)
|
if (settings == null || settings.Count == 0) return;
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var (key, value) in settings)
|
foreach (var (key, value) in settings)
|
||||||
{
|
{
|
||||||
|
|
@ -78,19 +95,23 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
switch (control)
|
switch (control)
|
||||||
{
|
{
|
||||||
case TextBox textBox:
|
case TextBox textBox:
|
||||||
textBox.Dispatcher.Invoke(() => textBox.Text = value as string ?? string.Empty);
|
var text = value as string ?? string.Empty;
|
||||||
|
textBox.Dispatcher.Invoke(() => textBox.Text = text);
|
||||||
break;
|
break;
|
||||||
case PasswordBox passwordBox:
|
case PasswordBox passwordBox:
|
||||||
passwordBox.Dispatcher.Invoke(() => passwordBox.Password = value as string ?? string.Empty);
|
var password = value as string ?? string.Empty;
|
||||||
|
passwordBox.Dispatcher.Invoke(() => passwordBox.Password = password);
|
||||||
break;
|
break;
|
||||||
case ComboBox comboBox:
|
case ComboBox comboBox:
|
||||||
comboBox.Dispatcher.Invoke(() => comboBox.SelectedItem = value);
|
comboBox.Dispatcher.Invoke(() => comboBox.SelectedItem = value);
|
||||||
break;
|
break;
|
||||||
case CheckBox checkBox:
|
case CheckBox checkBox:
|
||||||
checkBox.Dispatcher.Invoke(() =>
|
var isChecked = value is bool boolValue
|
||||||
checkBox.IsChecked = value is bool isChecked
|
? boolValue
|
||||||
? isChecked
|
// If can parse the default value to bool, use it, otherwise use false
|
||||||
: bool.Parse(value as string ?? string.Empty));
|
: value is string stringValue && bool.TryParse(stringValue, out var boolValueFromString)
|
||||||
|
&& boolValueFromString;
|
||||||
|
checkBox.Dispatcher.Invoke(() =>checkBox.IsChecked = isChecked);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +129,7 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
{
|
{
|
||||||
_storage.Save();
|
_storage.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool NeedCreateSettingPanel()
|
public bool NeedCreateSettingPanel()
|
||||||
{
|
{
|
||||||
// If there are no settings or the settings configuration is empty, return null
|
// If there are no settings or the settings configuration is empty, return null
|
||||||
|
|
@ -118,329 +139,350 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
public Control CreateSettingPanel()
|
public Control CreateSettingPanel()
|
||||||
{
|
{
|
||||||
// No need to check if NeedCreateSettingPanel is true because CreateSettingPanel will only be called if it's true
|
// No need to check if NeedCreateSettingPanel is true because CreateSettingPanel will only be called if it's true
|
||||||
|
// if (!NeedCreateSettingPanel()) return null;
|
||||||
|
|
||||||
var settingWindow = new UserControl();
|
// Create main grid with two columns (Column 1: Auto, Column 2: *)
|
||||||
var mainPanel = new Grid { Margin = settingPanelMargin, VerticalAlignment = VerticalAlignment.Center };
|
var mainPanel = new Grid { Margin = SettingPanelMargin, VerticalAlignment = VerticalAlignment.Center };
|
||||||
|
mainPanel.ColumnDefinitions.Add(new ColumnDefinition()
|
||||||
ColumnDefinition gridCol1 = new ColumnDefinition();
|
|
||||||
ColumnDefinition gridCol2 = new ColumnDefinition();
|
|
||||||
|
|
||||||
gridCol1.Width = new GridLength(70, GridUnitType.Star);
|
|
||||||
gridCol2.Width = new GridLength(30, GridUnitType.Star);
|
|
||||||
mainPanel.ColumnDefinitions.Add(gridCol1);
|
|
||||||
mainPanel.ColumnDefinitions.Add(gridCol2);
|
|
||||||
settingWindow.Content = mainPanel;
|
|
||||||
int rowCount = 0;
|
|
||||||
|
|
||||||
foreach (var (type, attribute) in Configuration.Body)
|
|
||||||
{
|
{
|
||||||
Separator sep = new Separator();
|
Width = new GridLength(0, GridUnitType.Auto)
|
||||||
sep.VerticalAlignment = VerticalAlignment.Top;
|
});
|
||||||
sep.Margin = settingSepMargin;
|
mainPanel.ColumnDefinitions.Add(new ColumnDefinition()
|
||||||
sep.SetResourceReference(Separator.BackgroundProperty, "Color03B"); /* for theme change */
|
{
|
||||||
var panel = new StackPanel
|
Width = new GridLength(1, GridUnitType.Star)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Iterate over each setting and create one row for it
|
||||||
|
var rowCount = 0;
|
||||||
|
foreach (var (type, attributes) in Configuration!.Body)
|
||||||
|
{
|
||||||
|
// Skip if the setting does not have attributes or name
|
||||||
|
if (attributes?.Name == null) continue;
|
||||||
|
|
||||||
|
// Add a new row to the main grid
|
||||||
|
mainPanel.RowDefinitions.Add(new RowDefinition()
|
||||||
{
|
{
|
||||||
Orientation = Orientation.Vertical,
|
Height = new GridLength(0, GridUnitType.Auto)
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
});
|
||||||
Margin = settingLabelPanelMargin
|
|
||||||
};
|
|
||||||
|
|
||||||
RowDefinition gridRow = new RowDefinition();
|
|
||||||
mainPanel.RowDefinitions.Add(gridRow);
|
|
||||||
var name = new TextBlock()
|
|
||||||
{
|
|
||||||
Text = attribute.Label,
|
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
|
||||||
Margin = settingLabelMargin,
|
|
||||||
TextWrapping = TextWrapping.WrapWithOverflow
|
|
||||||
};
|
|
||||||
|
|
||||||
var desc = new TextBlock()
|
|
||||||
{
|
|
||||||
Text = attribute.Description,
|
|
||||||
FontSize = 12,
|
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
|
||||||
Margin = settingDescMargin,
|
|
||||||
TextWrapping = TextWrapping.WrapWithOverflow
|
|
||||||
};
|
|
||||||
|
|
||||||
desc.SetResourceReference(TextBlock.ForegroundProperty, "Color04B");
|
|
||||||
|
|
||||||
if (attribute.Description == null) /* if no description, hide */
|
|
||||||
desc.Visibility = Visibility.Collapsed;
|
|
||||||
|
|
||||||
|
|
||||||
if (type != "textBlock") /* if textBlock, hide desc */
|
|
||||||
{
|
|
||||||
panel.Children.Add(name);
|
|
||||||
panel.Children.Add(desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Grid.SetColumn(panel, 0);
|
|
||||||
Grid.SetRow(panel, rowCount);
|
|
||||||
|
|
||||||
|
// State controls for column 0 and 1
|
||||||
|
StackPanel? panel = null;
|
||||||
FrameworkElement contentControl;
|
FrameworkElement contentControl;
|
||||||
|
|
||||||
|
// If the type is textBlock, separator, or checkbox, we do not need to create a panel
|
||||||
|
if (type != "textBlock" && type != "separator" && type != "checkbox")
|
||||||
|
{
|
||||||
|
// Create a panel to hold the label and description
|
||||||
|
panel = new StackPanel
|
||||||
|
{
|
||||||
|
Margin = SettingPanelItemTopBottomMargin,
|
||||||
|
Orientation = Orientation.Vertical,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a text block for name
|
||||||
|
var name = new TextBlock()
|
||||||
|
{
|
||||||
|
Text = attributes.Label,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
TextWrapping = TextWrapping.WrapWithOverflow
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a text block for description
|
||||||
|
TextBlock? desc = null;
|
||||||
|
if (attributes.Description != null)
|
||||||
|
{
|
||||||
|
desc = new TextBlock()
|
||||||
|
{
|
||||||
|
Text = attributes.Description,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
TextWrapping = TextWrapping.WrapWithOverflow
|
||||||
|
};
|
||||||
|
|
||||||
|
desc.SetResourceReference(TextBlock.StyleProperty, "SettingPanelTextBlockDescriptionStyle"); // for theme change
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the name and description to the panel
|
||||||
|
panel.Children.Add(name);
|
||||||
|
if (desc != null) panel.Children.Add(desc);
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case "textBlock":
|
case "textBlock":
|
||||||
{
|
|
||||||
contentControl = new TextBlock
|
|
||||||
{
|
{
|
||||||
Text = attribute.Description.Replace("\\r\\n", "\r\n"),
|
contentControl = new TextBlock
|
||||||
Margin = settingTextBlockMargin,
|
{
|
||||||
Padding = new Thickness(0, 0, 0, 0),
|
Text = attributes.Description?.Replace("\\r\\n", "\r\n") ?? string.Empty,
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
TextAlignment = TextAlignment.Left,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
TextWrapping = TextWrapping.Wrap
|
Margin = SettingPanelItemTopBottomMargin,
|
||||||
};
|
TextAlignment = TextAlignment.Left,
|
||||||
|
TextWrapping = TextWrapping.Wrap
|
||||||
|
};
|
||||||
|
|
||||||
Grid.SetColumn(contentControl, 0);
|
break;
|
||||||
Grid.SetColumnSpan(contentControl, 2);
|
}
|
||||||
Grid.SetRow(contentControl, rowCount);
|
|
||||||
if (rowCount != 0)
|
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
|
||||||
Grid.SetColumn(sep, 0);
|
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "input":
|
case "input":
|
||||||
{
|
|
||||||
var textBox = new TextBox()
|
|
||||||
{
|
{
|
||||||
Text = Settings[attribute.Name] as string ?? string.Empty,
|
var textBox = new TextBox()
|
||||||
Margin = settingControlMargin,
|
{
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
|
MinWidth = SettingPanelTextBoxMinWidth,
|
||||||
ToolTip = attribute.Description
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
};
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Margin = SettingPanelItemLeftTopBottomMargin,
|
||||||
|
Text = Settings[attributes.Name] as string ?? string.Empty,
|
||||||
|
ToolTip = attributes.Description
|
||||||
|
};
|
||||||
|
|
||||||
textBox.TextChanged += (_, _) =>
|
textBox.TextChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
Settings[attribute.Name] = textBox.Text;
|
Settings[attributes.Name] = textBox.Text;
|
||||||
};
|
};
|
||||||
|
|
||||||
contentControl = textBox;
|
contentControl = textBox;
|
||||||
Grid.SetColumn(contentControl, 1);
|
|
||||||
Grid.SetRow(contentControl, rowCount);
|
|
||||||
if (rowCount != 0)
|
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
break;
|
||||||
Grid.SetColumn(sep, 0);
|
}
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "inputWithFileBtn":
|
case "inputWithFileBtn":
|
||||||
case "inputWithFolderBtn":
|
case "inputWithFolderBtn":
|
||||||
{
|
|
||||||
var textBox = new TextBox()
|
|
||||||
{
|
{
|
||||||
Margin = new Thickness(10, 0, 0, 0),
|
var textBox = new TextBox()
|
||||||
Text = Settings[attribute.Name] as string ?? string.Empty,
|
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
|
|
||||||
ToolTip = attribute.Description
|
|
||||||
};
|
|
||||||
|
|
||||||
textBox.TextChanged += (_, _) =>
|
|
||||||
{
|
|
||||||
Settings[attribute.Name] = textBox.Text;
|
|
||||||
};
|
|
||||||
|
|
||||||
var Btn = new System.Windows.Controls.Button()
|
|
||||||
{
|
|
||||||
Margin = new Thickness(10, 0, 0, 0), Content = "Browse"
|
|
||||||
};
|
|
||||||
|
|
||||||
Btn.Click += (_, _) =>
|
|
||||||
{
|
|
||||||
using CommonDialog dialog = type switch
|
|
||||||
{
|
{
|
||||||
"inputWithFolderBtn" => new FolderBrowserDialog(),
|
Width = SettingPanelPathTextBoxWidth,
|
||||||
_ => new OpenFileDialog(),
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Margin = SettingPanelItemLeftMargin,
|
||||||
|
Text = Settings[attributes.Name] as string ?? string.Empty,
|
||||||
|
ToolTip = attributes.Description
|
||||||
};
|
};
|
||||||
if (dialog.ShowDialog() != DialogResult.OK) return;
|
|
||||||
|
|
||||||
var path = dialog switch
|
textBox.TextChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
FolderBrowserDialog folderDialog => folderDialog.SelectedPath,
|
Settings[attributes.Name] = textBox.Text;
|
||||||
OpenFileDialog fileDialog => fileDialog.FileName,
|
|
||||||
};
|
};
|
||||||
textBox.Text = path;
|
|
||||||
Settings[attribute.Name] = path;
|
|
||||||
};
|
|
||||||
|
|
||||||
var dockPanel = new DockPanel() { Margin = settingControlMargin };
|
var Btn = new Button()
|
||||||
|
{
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Margin = SettingPanelItemLeftMargin,
|
||||||
|
Content = API.GetTranslation("select")
|
||||||
|
};
|
||||||
|
|
||||||
DockPanel.SetDock(Btn, Dock.Right);
|
Btn.Click += (_, _) =>
|
||||||
dockPanel.Children.Add(Btn);
|
{
|
||||||
dockPanel.Children.Add(textBox);
|
using System.Windows.Forms.CommonDialog dialog = type switch
|
||||||
contentControl = dockPanel;
|
{
|
||||||
Grid.SetColumn(contentControl, 1);
|
"inputWithFolderBtn" => new System.Windows.Forms.FolderBrowserDialog(),
|
||||||
Grid.SetRow(contentControl, rowCount);
|
_ => new System.Windows.Forms.OpenFileDialog(),
|
||||||
if (rowCount != 0)
|
};
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
if (dialog.ShowDialog() != System.Windows.Forms.DialogResult.OK)
|
||||||
Grid.SetColumn(sep, 0);
|
{
|
||||||
Grid.SetColumnSpan(sep, 2);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
var path = dialog switch
|
||||||
}
|
{
|
||||||
|
System.Windows.Forms.FolderBrowserDialog folderDialog => folderDialog.SelectedPath,
|
||||||
|
System.Windows.Forms.OpenFileDialog fileDialog => fileDialog.FileName,
|
||||||
|
_ => throw new System.NotImplementedException()
|
||||||
|
};
|
||||||
|
|
||||||
|
textBox.Text = path;
|
||||||
|
Settings[attributes.Name] = path;
|
||||||
|
};
|
||||||
|
|
||||||
|
var stackPanel = new StackPanel()
|
||||||
|
{
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Margin = SettingPanelItemTopBottomMargin,
|
||||||
|
Orientation = Orientation.Horizontal
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a stack panel to wrap the button and text box
|
||||||
|
stackPanel.Children.Add(textBox);
|
||||||
|
stackPanel.Children.Add(Btn);
|
||||||
|
|
||||||
|
contentControl = stackPanel;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
case "textarea":
|
case "textarea":
|
||||||
{
|
|
||||||
var textBox = new TextBox()
|
|
||||||
{
|
{
|
||||||
Height = 120,
|
var textBox = new TextBox()
|
||||||
Margin = settingControlMargin,
|
{
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
MinHeight = SettingPanelAreaTextBoxMinHeight,
|
||||||
TextWrapping = TextWrapping.WrapWithOverflow,
|
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||||
AcceptsReturn = true,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
|
Margin = SettingPanelItemLeftTopBottomMargin,
|
||||||
Text = Settings[attribute.Name] as string ?? string.Empty,
|
TextWrapping = TextWrapping.WrapWithOverflow,
|
||||||
ToolTip = attribute.Description
|
AcceptsReturn = true,
|
||||||
};
|
Text = Settings[attributes.Name] as string ?? string.Empty,
|
||||||
|
ToolTip = attributes.Description
|
||||||
|
};
|
||||||
|
|
||||||
textBox.TextChanged += (sender, _) =>
|
textBox.TextChanged += (sender, _) =>
|
||||||
{
|
{
|
||||||
Settings[attribute.Name] = ((TextBox)sender).Text;
|
Settings[attributes.Name] = ((TextBox)sender).Text;
|
||||||
};
|
};
|
||||||
|
|
||||||
contentControl = textBox;
|
contentControl = textBox;
|
||||||
Grid.SetColumn(contentControl, 1);
|
|
||||||
Grid.SetRow(contentControl, rowCount);
|
|
||||||
if (rowCount != 0)
|
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
break;
|
||||||
Grid.SetColumn(sep, 0);
|
}
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "passwordBox":
|
case "passwordBox":
|
||||||
{
|
|
||||||
var passwordBox = new PasswordBox()
|
|
||||||
{
|
{
|
||||||
Margin = settingControlMargin,
|
var passwordBox = new PasswordBox()
|
||||||
Password = Settings[attribute.Name] as string ?? string.Empty,
|
{
|
||||||
PasswordChar = attribute.passwordChar == default ? '*' : attribute.passwordChar,
|
MinWidth = SettingPanelTextBoxMinWidth,
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
ToolTip = attribute.Description
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
};
|
Margin = SettingPanelItemLeftTopBottomMargin,
|
||||||
|
Password = Settings[attributes.Name] as string ?? string.Empty,
|
||||||
|
PasswordChar = attributes.passwordChar == default ? '*' : attributes.passwordChar,
|
||||||
|
ToolTip = attributes.Description,
|
||||||
|
};
|
||||||
|
|
||||||
passwordBox.PasswordChanged += (sender, _) =>
|
passwordBox.PasswordChanged += (sender, _) =>
|
||||||
{
|
{
|
||||||
Settings[attribute.Name] = ((PasswordBox)sender).Password;
|
Settings[attributes.Name] = ((PasswordBox)sender).Password;
|
||||||
};
|
};
|
||||||
|
|
||||||
contentControl = passwordBox;
|
contentControl = passwordBox;
|
||||||
Grid.SetColumn(contentControl, 1);
|
|
||||||
Grid.SetRow(contentControl, rowCount);
|
|
||||||
if (rowCount != 0)
|
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
break;
|
||||||
Grid.SetColumn(sep, 0);
|
}
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "dropdown":
|
case "dropdown":
|
||||||
{
|
|
||||||
var comboBox = new System.Windows.Controls.ComboBox()
|
|
||||||
{
|
{
|
||||||
ItemsSource = attribute.Options,
|
var comboBox = new ComboBox()
|
||||||
SelectedItem = Settings[attribute.Name],
|
{
|
||||||
Margin = settingControlMargin,
|
ItemsSource = attributes.Options,
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
|
SelectedItem = Settings[attributes.Name],
|
||||||
ToolTip = attribute.Description
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
};
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Margin = SettingPanelItemLeftTopBottomMargin,
|
||||||
|
ToolTip = attributes.Description
|
||||||
|
};
|
||||||
|
|
||||||
comboBox.SelectionChanged += (sender, _) =>
|
comboBox.SelectionChanged += (sender, _) =>
|
||||||
{
|
{
|
||||||
Settings[attribute.Name] = (string)((System.Windows.Controls.ComboBox)sender).SelectedItem;
|
Settings[attributes.Name] = (string)((ComboBox)sender).SelectedItem;
|
||||||
};
|
};
|
||||||
|
|
||||||
contentControl = comboBox;
|
contentControl = comboBox;
|
||||||
Grid.SetColumn(contentControl, 1);
|
|
||||||
Grid.SetRow(contentControl, rowCount);
|
|
||||||
if (rowCount != 0)
|
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
break;
|
||||||
Grid.SetColumn(sep, 0);
|
}
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "checkbox":
|
case "checkbox":
|
||||||
var checkBox = new CheckBox
|
|
||||||
{
|
{
|
||||||
IsChecked =
|
// If can parse the default value to bool, use it, otherwise use false
|
||||||
Settings[attribute.Name] is bool isChecked
|
var defaultValue = bool.TryParse(attributes.DefaultValue, out var value) && value;
|
||||||
|
var checkBox = new CheckBox
|
||||||
|
{
|
||||||
|
IsChecked =
|
||||||
|
Settings[attributes.Name] is bool isChecked
|
||||||
? isChecked
|
? isChecked
|
||||||
: bool.Parse(attribute.DefaultValue),
|
: defaultValue,
|
||||||
Margin = settingCheckboxMargin,
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
ToolTip = attribute.Description
|
Margin = SettingPanelItemTopBottomMargin,
|
||||||
};
|
Content = attributes.Label,
|
||||||
|
ToolTip = attributes.Description
|
||||||
|
};
|
||||||
|
|
||||||
checkBox.Click += (sender, _) =>
|
checkBox.Click += (sender, _) =>
|
||||||
{
|
{
|
||||||
Settings[attribute.Name] = ((CheckBox)sender).IsChecked;
|
Settings[attributes.Name] = ((CheckBox)sender).IsChecked ?? defaultValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
contentControl = checkBox;
|
contentControl = checkBox;
|
||||||
Grid.SetColumn(contentControl, 1);
|
|
||||||
Grid.SetRow(contentControl, rowCount);
|
|
||||||
if (rowCount != 0)
|
|
||||||
mainPanel.Children.Add(sep);
|
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
break;
|
||||||
Grid.SetColumn(sep, 0);
|
}
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
|
||||||
case "hyperlink":
|
case "hyperlink":
|
||||||
var hyperlink = new Hyperlink { ToolTip = attribute.Description, NavigateUri = attribute.url };
|
|
||||||
|
|
||||||
var linkbtn = new System.Windows.Controls.Button
|
|
||||||
{
|
{
|
||||||
HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
|
var hyperlink = new Hyperlink
|
||||||
Margin = settingControlMargin
|
{
|
||||||
};
|
ToolTip = attributes.Description,
|
||||||
|
NavigateUri = attributes.url
|
||||||
|
};
|
||||||
|
|
||||||
linkbtn.Content = attribute.urlLabel;
|
hyperlink.Inlines.Add(attributes.urlLabel);
|
||||||
|
hyperlink.RequestNavigate += (sender, e) =>
|
||||||
|
{
|
||||||
|
API.OpenUrl(e.Uri);
|
||||||
|
e.Handled = true;
|
||||||
|
};
|
||||||
|
|
||||||
contentControl = linkbtn;
|
var textBlock = new TextBlock()
|
||||||
Grid.SetColumn(contentControl, 1);
|
{
|
||||||
Grid.SetRow(contentControl, rowCount);
|
HorizontalAlignment = HorizontalAlignment.Left,
|
||||||
if (rowCount != 0)
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
mainPanel.Children.Add(sep);
|
Margin = SettingPanelItemLeftTopBottomMargin,
|
||||||
|
TextAlignment = TextAlignment.Left,
|
||||||
|
TextWrapping = TextWrapping.Wrap
|
||||||
|
};
|
||||||
|
textBlock.Inlines.Add(hyperlink);
|
||||||
|
|
||||||
Grid.SetRow(sep, rowCount);
|
contentControl = textBlock;
|
||||||
Grid.SetColumn(sep, 0);
|
|
||||||
Grid.SetColumnSpan(sep, 2);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
case "separator":
|
||||||
|
{
|
||||||
|
var sep = new Separator();
|
||||||
|
|
||||||
|
sep.SetResourceReference(Separator.StyleProperty, "SettingPanelSeparatorStyle");
|
||||||
|
|
||||||
|
contentControl = sep;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type != "textBlock")
|
// If type is textBlock or separator, we just add the content control to the main grid
|
||||||
SettingControls[attribute.Name] = contentControl;
|
if (panel == null)
|
||||||
|
{
|
||||||
|
// Add the content control to the column 0, row rowCount and columnSpan 2 of the main grid
|
||||||
|
mainPanel.Children.Add(contentControl);
|
||||||
|
Grid.SetColumn(contentControl, 0);
|
||||||
|
Grid.SetColumnSpan(contentControl, 2);
|
||||||
|
Grid.SetRow(contentControl, rowCount);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Add the panel to the column 0 and row rowCount of the main grid
|
||||||
|
mainPanel.Children.Add(panel);
|
||||||
|
Grid.SetColumn(panel, 0);
|
||||||
|
Grid.SetRow(panel, rowCount);
|
||||||
|
|
||||||
|
// Add the content control to the column 1 and row rowCount of the main grid
|
||||||
|
mainPanel.Children.Add(contentControl);
|
||||||
|
Grid.SetColumn(contentControl, 1);
|
||||||
|
Grid.SetRow(contentControl, rowCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add into SettingControls for settings storage if need
|
||||||
|
if (NeedSaveInSettings(type)) SettingControls[attributes.Name] = contentControl;
|
||||||
|
|
||||||
mainPanel.Children.Add(panel);
|
|
||||||
mainPanel.Children.Add(contentControl);
|
|
||||||
rowCount++;
|
rowCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return settingWindow;
|
// Wrap the main grid in a user control
|
||||||
|
return new UserControl()
|
||||||
|
{
|
||||||
|
Content = mainPanel
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool NeedSaveInSettings(string type)
|
||||||
|
{
|
||||||
|
return type != "textBlock" && type != "separator" && type != "hyperlink";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -231,7 +231,6 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
if (!NonGlobalPlugins.ContainsKey(query.ActionKeyword))
|
if (!NonGlobalPlugins.ContainsKey(query.ActionKeyword))
|
||||||
return GlobalPlugins;
|
return GlobalPlugins;
|
||||||
|
|
||||||
|
|
||||||
var plugin = NonGlobalPlugins[query.ActionKeyword];
|
var plugin = NonGlobalPlugins[query.ActionKeyword];
|
||||||
return new List<PluginPair>
|
return new List<PluginPair>
|
||||||
{
|
{
|
||||||
|
|
@ -367,7 +366,16 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
NonGlobalPlugins[newActionKeyword] = plugin;
|
NonGlobalPlugins[newActionKeyword] = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update action keywords and action keyword in plugin metadata
|
||||||
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
|
plugin.Metadata.ActionKeywords.Add(newActionKeyword);
|
||||||
|
if (plugin.Metadata.ActionKeywords.Count > 0)
|
||||||
|
{
|
||||||
|
plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plugin.Metadata.ActionKeyword = string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -388,16 +396,15 @@ namespace Flow.Launcher.Core.Plugin
|
||||||
if (oldActionkeyword != Query.GlobalPluginWildcardSign)
|
if (oldActionkeyword != Query.GlobalPluginWildcardSign)
|
||||||
NonGlobalPlugins.Remove(oldActionkeyword);
|
NonGlobalPlugins.Remove(oldActionkeyword);
|
||||||
|
|
||||||
|
// Update action keywords and action keyword in plugin metadata
|
||||||
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
|
plugin.Metadata.ActionKeywords.Remove(oldActionkeyword);
|
||||||
}
|
if (plugin.Metadata.ActionKeywords.Count > 0)
|
||||||
|
|
||||||
public static void ReplaceActionKeyword(string id, string oldActionKeyword, string newActionKeyword)
|
|
||||||
{
|
|
||||||
if (oldActionKeyword != newActionKeyword)
|
|
||||||
{
|
{
|
||||||
AddActionKeyword(id, newActionKeyword);
|
plugin.Metadata.ActionKeyword = plugin.Metadata.ActionKeywords[0];
|
||||||
RemoveActionKeyword(id, oldActionKeyword);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plugin.Metadata.ActionKeyword = string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,29 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Effects;
|
using System.Windows.Media.Effects;
|
||||||
using System.Windows.Shell;
|
using System.Windows.Shell;
|
||||||
|
using System.Windows.Threading;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using TextBox = System.Windows.Controls.TextBox;
|
||||||
|
|
||||||
namespace Flow.Launcher.Core.Resource
|
namespace Flow.Launcher.Core.Resource
|
||||||
{
|
{
|
||||||
public class Theme
|
public class Theme
|
||||||
{
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public bool BlurEnabled { get; set; }
|
||||||
|
|
||||||
private const string ThemeMetadataNamePrefix = "Name:";
|
private const string ThemeMetadataNamePrefix = "Name:";
|
||||||
private const string ThemeMetadataIsDarkPrefix = "IsDark:";
|
private const string ThemeMetadataIsDarkPrefix = "IsDark:";
|
||||||
private const string ThemeMetadataHasBlurPrefix = "HasBlur:";
|
private const string ThemeMetadataHasBlurPrefix = "HasBlur:";
|
||||||
|
|
@ -31,14 +39,12 @@ namespace Flow.Launcher.Core.Resource
|
||||||
private string _oldTheme;
|
private string _oldTheme;
|
||||||
private const string Folder = Constant.Themes;
|
private const string Folder = Constant.Themes;
|
||||||
private const string Extension = ".xaml";
|
private const string Extension = ".xaml";
|
||||||
private string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder);
|
private static string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder);
|
||||||
private string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder);
|
private static string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder);
|
||||||
|
|
||||||
public string CurrentTheme => _settings.Theme;
|
#endregion
|
||||||
|
|
||||||
public bool BlurEnabled { get; set; }
|
#region Constructor
|
||||||
|
|
||||||
private double mainWindowWidth;
|
|
||||||
|
|
||||||
public Theme(IPublicAPI publicAPI, Settings settings)
|
public Theme(IPublicAPI publicAPI, Settings settings)
|
||||||
{
|
{
|
||||||
|
|
@ -66,6 +72,15 @@ namespace Flow.Launcher.Core.Resource
|
||||||
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
|
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Theme Resources
|
||||||
|
|
||||||
|
public string GetCurrentTheme()
|
||||||
|
{
|
||||||
|
return _settings.Theme;
|
||||||
|
}
|
||||||
|
|
||||||
private void MakeSureThemeDirectoriesExist()
|
private void MakeSureThemeDirectoriesExist()
|
||||||
{
|
{
|
||||||
foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir)))
|
foreach (var dir in _themeDirectories.Where(dir => !Directory.Exists(dir)))
|
||||||
|
|
@ -81,59 +96,6 @@ namespace Flow.Launcher.Core.Resource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ChangeTheme(string theme)
|
|
||||||
{
|
|
||||||
const string defaultTheme = Constant.DefaultTheme;
|
|
||||||
|
|
||||||
string path = GetThemePath(theme);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(path))
|
|
||||||
throw new DirectoryNotFoundException("Theme path can't be found <{path}>");
|
|
||||||
|
|
||||||
// reload all resources even if the theme itself hasn't changed in order to pickup changes
|
|
||||||
// to things like fonts
|
|
||||||
UpdateResourceDictionary(GetResourceDictionary(theme));
|
|
||||||
|
|
||||||
_settings.Theme = theme;
|
|
||||||
|
|
||||||
|
|
||||||
//always allow re-loading default theme, in case of failure of switching to a new theme from default theme
|
|
||||||
if (_oldTheme != theme || theme == defaultTheme)
|
|
||||||
{
|
|
||||||
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
BlurEnabled = Win32Helper.IsBlurTheme();
|
|
||||||
|
|
||||||
if (_settings.UseDropShadowEffect && !BlurEnabled)
|
|
||||||
AddDropShadowEffectToCurrentTheme();
|
|
||||||
|
|
||||||
Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled);
|
|
||||||
}
|
|
||||||
catch (DirectoryNotFoundException)
|
|
||||||
{
|
|
||||||
Log.Error($"|Theme.ChangeTheme|Theme <{theme}> path can't be found");
|
|
||||||
if (theme != defaultTheme)
|
|
||||||
{
|
|
||||||
_api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_path_not_exists"), theme));
|
|
||||||
ChangeTheme(defaultTheme);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (XamlParseException)
|
|
||||||
{
|
|
||||||
Log.Error($"|Theme.ChangeTheme|Theme <{theme}> fail to parse");
|
|
||||||
if (theme != defaultTheme)
|
|
||||||
{
|
|
||||||
_api.ShowMsgBox(string.Format(InternationalizationManager.Instance.GetTranslation("theme_load_failure_parse_error"), theme));
|
|
||||||
ChangeTheme(defaultTheme);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateResourceDictionary(ResourceDictionary dictionaryToUpdate)
|
private void UpdateResourceDictionary(ResourceDictionary dictionaryToUpdate)
|
||||||
{
|
{
|
||||||
var dicts = Application.Current.Resources.MergedDictionaries;
|
var dicts = Application.Current.Resources.MergedDictionaries;
|
||||||
|
|
@ -154,9 +116,7 @@ namespace Flow.Launcher.Core.Resource
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceDictionary CurrentThemeResourceDictionary() => GetThemeResourceDictionary(_settings.Theme);
|
private ResourceDictionary GetResourceDictionary(string theme)
|
||||||
|
|
||||||
public ResourceDictionary GetResourceDictionary(string theme)
|
|
||||||
{
|
{
|
||||||
var dict = GetThemeResourceDictionary(theme);
|
var dict = GetThemeResourceDictionary(theme);
|
||||||
|
|
||||||
|
|
@ -213,7 +173,7 @@ namespace Flow.Launcher.Core.Resource
|
||||||
|
|
||||||
Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch };
|
Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch };
|
||||||
Array.ForEach(
|
Array.ForEach(
|
||||||
new[] { resultSubItemStyle,resultSubItemSelectedStyle}, o
|
new[] { resultSubItemStyle, resultSubItemSelectedStyle }, o
|
||||||
=> Array.ForEach(setters, p => o.Setters.Add(p)));
|
=> Array.ForEach(setters, p => o.Setters.Add(p)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,28 +181,12 @@ namespace Flow.Launcher.Core.Resource
|
||||||
var windowStyle = dict["WindowStyle"] as Style;
|
var windowStyle = dict["WindowStyle"] as Style;
|
||||||
var width = _settings.WindowSize;
|
var width = _settings.WindowSize;
|
||||||
windowStyle.Setters.Add(new Setter(Window.WidthProperty, width));
|
windowStyle.Setters.Add(new Setter(Window.WidthProperty, width));
|
||||||
mainWindowWidth = (double)width;
|
|
||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceDictionary GetCurrentResourceDictionary( )
|
private ResourceDictionary GetCurrentResourceDictionary()
|
||||||
{
|
{
|
||||||
return GetResourceDictionary(_settings.Theme);
|
return GetResourceDictionary(GetCurrentTheme());
|
||||||
}
|
|
||||||
|
|
||||||
public List<ThemeData> LoadAvailableThemes()
|
|
||||||
{
|
|
||||||
List<ThemeData> themes = new List<ThemeData>();
|
|
||||||
foreach (var themeDirectory in _themeDirectories)
|
|
||||||
{
|
|
||||||
var filePaths = Directory
|
|
||||||
.GetFiles(themeDirectory)
|
|
||||||
.Where(filePath => filePath.EndsWith(Extension) && !filePath.EndsWith("Base.xaml"))
|
|
||||||
.Select(GetThemeDataFromPath);
|
|
||||||
themes.AddRange(filePaths);
|
|
||||||
}
|
|
||||||
|
|
||||||
return themes.OrderBy(o => o.Name).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ThemeData GetThemeDataFromPath(string path)
|
private ThemeData GetThemeDataFromPath(string path)
|
||||||
|
|
@ -264,15 +208,15 @@ namespace Flow.Launcher.Core.Resource
|
||||||
{
|
{
|
||||||
if (line.StartsWith(ThemeMetadataNamePrefix, StringComparison.OrdinalIgnoreCase))
|
if (line.StartsWith(ThemeMetadataNamePrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
name = line.Remove(0, ThemeMetadataNamePrefix.Length).Trim();
|
name = line[ThemeMetadataNamePrefix.Length..].Trim();
|
||||||
}
|
}
|
||||||
else if (line.StartsWith(ThemeMetadataIsDarkPrefix, StringComparison.OrdinalIgnoreCase))
|
else if (line.StartsWith(ThemeMetadataIsDarkPrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
isDark = bool.Parse(line.Remove(0, ThemeMetadataIsDarkPrefix.Length).Trim());
|
isDark = bool.Parse(line[ThemeMetadataIsDarkPrefix.Length..].Trim());
|
||||||
}
|
}
|
||||||
else if (line.StartsWith(ThemeMetadataHasBlurPrefix, StringComparison.OrdinalIgnoreCase))
|
else if (line.StartsWith(ThemeMetadataHasBlurPrefix, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
hasBlur = bool.Parse(line.Remove(0, ThemeMetadataHasBlurPrefix.Length).Trim());
|
hasBlur = bool.Parse(line[ThemeMetadataHasBlurPrefix.Length..].Trim());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,6 +237,81 @@ namespace Flow.Launcher.Core.Resource
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Load & Change
|
||||||
|
|
||||||
|
public List<ThemeData> LoadAvailableThemes()
|
||||||
|
{
|
||||||
|
List<ThemeData> themes = new List<ThemeData>();
|
||||||
|
foreach (var themeDirectory in _themeDirectories)
|
||||||
|
{
|
||||||
|
var filePaths = Directory
|
||||||
|
.GetFiles(themeDirectory)
|
||||||
|
.Where(filePath => filePath.EndsWith(Extension) && !filePath.EndsWith("Base.xaml"))
|
||||||
|
.Select(GetThemeDataFromPath);
|
||||||
|
themes.AddRange(filePaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
return themes.OrderBy(o => o.Name).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeTheme(string theme = null)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(theme))
|
||||||
|
theme = GetCurrentTheme();
|
||||||
|
|
||||||
|
string path = GetThemePath(theme);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
throw new DirectoryNotFoundException("Theme path can't be found <{path}>");
|
||||||
|
|
||||||
|
// reload all resources even if the theme itself hasn't changed in order to pickup changes
|
||||||
|
// to things like fonts
|
||||||
|
UpdateResourceDictionary(GetResourceDictionary(theme));
|
||||||
|
|
||||||
|
_settings.Theme = theme;
|
||||||
|
|
||||||
|
//always allow re-loading default theme, in case of failure of switching to a new theme from default theme
|
||||||
|
if (_oldTheme != theme || theme == Constant.DefaultTheme)
|
||||||
|
{
|
||||||
|
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
BlurEnabled = IsBlurTheme();
|
||||||
|
//if (_settings.UseDropShadowEffect)
|
||||||
|
// AddDropShadowEffectToCurrentTheme();
|
||||||
|
//Win32Helper.SetBlurForWindow(Application.Current.MainWindow, BlurEnabled);
|
||||||
|
_ = SetBlurForWindowAsync();
|
||||||
|
}
|
||||||
|
catch (DirectoryNotFoundException)
|
||||||
|
{
|
||||||
|
Log.Error($"|Theme.ChangeTheme|Theme <{theme}> path can't be found");
|
||||||
|
if (theme != Constant.DefaultTheme)
|
||||||
|
{
|
||||||
|
_api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_path_not_exists"), theme));
|
||||||
|
ChangeTheme(Constant.DefaultTheme);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (XamlParseException)
|
||||||
|
{
|
||||||
|
Log.Error($"|Theme.ChangeTheme|Theme <{theme}> fail to parse");
|
||||||
|
if (theme != Constant.DefaultTheme)
|
||||||
|
{
|
||||||
|
_api.ShowMsgBox(string.Format(_api.GetTranslation("theme_load_failure_parse_error"), theme));
|
||||||
|
ChangeTheme(Constant.DefaultTheme);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Shadow Effect
|
||||||
|
|
||||||
public void AddDropShadowEffectToCurrentTheme()
|
public void AddDropShadowEffectToCurrentTheme()
|
||||||
{
|
{
|
||||||
var dict = GetCurrentResourceDictionary();
|
var dict = GetCurrentResourceDictionary();
|
||||||
|
|
@ -311,8 +330,7 @@ namespace Flow.Launcher.Core.Resource
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var marginSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) as Setter;
|
if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) is not Setter marginSetter)
|
||||||
if (marginSetter == null)
|
|
||||||
{
|
{
|
||||||
var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin);
|
var margin = new Thickness(ShadowExtraMargin, 12, ShadowExtraMargin, ShadowExtraMargin);
|
||||||
marginSetter = new Setter()
|
marginSetter = new Setter()
|
||||||
|
|
@ -347,14 +365,12 @@ namespace Flow.Launcher.Core.Resource
|
||||||
var dict = GetCurrentResourceDictionary();
|
var dict = GetCurrentResourceDictionary();
|
||||||
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
|
var windowBorderStyle = dict["WindowBorderStyle"] as Style;
|
||||||
|
|
||||||
var effectSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.EffectProperty) as Setter;
|
if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.EffectProperty) is Setter effectSetter)
|
||||||
var marginSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) as Setter;
|
|
||||||
|
|
||||||
if (effectSetter != null)
|
|
||||||
{
|
{
|
||||||
windowBorderStyle.Setters.Remove(effectSetter);
|
windowBorderStyle.Setters.Remove(effectSetter);
|
||||||
}
|
}
|
||||||
if (marginSetter != null)
|
|
||||||
|
if (windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) is Setter marginSetter)
|
||||||
{
|
{
|
||||||
var currentMargin = (Thickness)marginSetter.Value;
|
var currentMargin = (Thickness)marginSetter.Value;
|
||||||
var newMargin = new Thickness(
|
var newMargin = new Thickness(
|
||||||
|
|
@ -395,6 +411,343 @@ namespace Flow.Launcher.Core.Resource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Blur Handling
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Refreshes the frame to apply the current theme settings.
|
||||||
|
/// </summary>
|
||||||
|
public async Task RefreshFrameAsync()
|
||||||
|
{
|
||||||
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
// Get the actual backdrop type and drop shadow effect settings
|
||||||
|
var (backdropType, useDropShadowEffect) = GetActualValue();
|
||||||
|
|
||||||
|
// Remove OS minimizing/maximizing animation
|
||||||
|
// Methods.SetWindowAttribute(new WindowInteropHelper(mainWindow).Handle, DWMWINDOWATTRIBUTE.DWMWA_TRANSITIONS_FORCEDISABLED, 3);
|
||||||
|
|
||||||
|
// The timing of adding the shadow effect should vary depending on whether the theme is transparent.
|
||||||
|
if (BlurEnabled)
|
||||||
|
{
|
||||||
|
AutoDropShadow(useDropShadowEffect);
|
||||||
|
}
|
||||||
|
SetBlurForWindow(GetCurrentTheme(), backdropType);
|
||||||
|
|
||||||
|
if (!BlurEnabled)
|
||||||
|
{
|
||||||
|
AutoDropShadow(useDropShadowEffect);
|
||||||
|
}
|
||||||
|
}, DispatcherPriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the blur for a window via SetWindowCompositionAttribute
|
||||||
|
/// </summary>
|
||||||
|
public async Task SetBlurForWindowAsync()
|
||||||
|
{
|
||||||
|
await Application.Current.Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
// Get the actual backdrop type and drop shadow effect settings
|
||||||
|
var (backdropType, _) = GetActualValue();
|
||||||
|
|
||||||
|
SetBlurForWindow(GetCurrentTheme(), backdropType);
|
||||||
|
}, DispatcherPriority.Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the actual backdrop type and drop shadow effect settings based on the current theme status.
|
||||||
|
/// </summary>
|
||||||
|
public (BackdropTypes BackdropType, bool UseDropShadowEffect) GetActualValue()
|
||||||
|
{
|
||||||
|
var backdropType = _settings.BackdropType;
|
||||||
|
var useDropShadowEffect = _settings.UseDropShadowEffect;
|
||||||
|
|
||||||
|
// When changed non-blur theme, change to backdrop to none
|
||||||
|
if (!BlurEnabled)
|
||||||
|
{
|
||||||
|
backdropType = BackdropTypes.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dropshadow on and control disabled.(user can't change dropshadow with blur theme)
|
||||||
|
if (BlurEnabled)
|
||||||
|
{
|
||||||
|
useDropShadowEffect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (backdropType, useDropShadowEffect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetBlurForWindow(string theme, BackdropTypes backdropType)
|
||||||
|
{
|
||||||
|
var dict = GetThemeResourceDictionary(theme);
|
||||||
|
if (dict == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var windowBorderStyle = dict.Contains("WindowBorderStyle") ? dict["WindowBorderStyle"] as Style : null;
|
||||||
|
if (windowBorderStyle == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Window mainWindow = Application.Current.MainWindow;
|
||||||
|
if (mainWindow == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if the theme supports blur
|
||||||
|
bool hasBlur = dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool b && b;
|
||||||
|
if (BlurEnabled && hasBlur && Win32Helper.IsBackdropSupported())
|
||||||
|
{
|
||||||
|
// If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent
|
||||||
|
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt)
|
||||||
|
{
|
||||||
|
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background"));
|
||||||
|
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
|
||||||
|
}
|
||||||
|
else if (backdropType == BackdropTypes.Acrylic)
|
||||||
|
{
|
||||||
|
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background"));
|
||||||
|
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the blur effect
|
||||||
|
Win32Helper.DWMSetBackdropForWindow(mainWindow, backdropType);
|
||||||
|
ColorizeWindow(theme, backdropType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply default style when Blur is disabled
|
||||||
|
Win32Helper.DWMSetBackdropForWindow(mainWindow, BackdropTypes.None);
|
||||||
|
ColorizeWindow(theme, backdropType);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateResourceDictionary(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AutoDropShadow(bool useDropShadowEffect)
|
||||||
|
{
|
||||||
|
SetWindowCornerPreference("Default");
|
||||||
|
RemoveDropShadowEffectFromCurrentTheme();
|
||||||
|
if (useDropShadowEffect)
|
||||||
|
{
|
||||||
|
if (BlurEnabled && Win32Helper.IsBackdropSupported())
|
||||||
|
{
|
||||||
|
SetWindowCornerPreference("Round");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetWindowCornerPreference("Default");
|
||||||
|
AddDropShadowEffectToCurrentTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (BlurEnabled && Win32Helper.IsBackdropSupported())
|
||||||
|
{
|
||||||
|
SetWindowCornerPreference("Default");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RemoveDropShadowEffectFromCurrentTheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetWindowCornerPreference(string cornerType)
|
||||||
|
{
|
||||||
|
Window mainWindow = Application.Current.MainWindow;
|
||||||
|
if (mainWindow == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Win32Helper.DWMSetCornerPreferenceForWindow(mainWindow, cornerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get Background Color from WindowBorderStyle when there not color for BG.
|
||||||
|
// for theme has not "LightBG" or "DarkBG" case.
|
||||||
|
private Color GetWindowBorderStyleBackground(string theme)
|
||||||
|
{
|
||||||
|
var Resources = GetThemeResourceDictionary(theme);
|
||||||
|
var windowBorderStyle = (Style)Resources["WindowBorderStyle"];
|
||||||
|
|
||||||
|
var backgroundSetter = windowBorderStyle.Setters
|
||||||
|
.OfType<Setter>()
|
||||||
|
.FirstOrDefault(s => s.Property == Border.BackgroundProperty);
|
||||||
|
|
||||||
|
if (backgroundSetter != null)
|
||||||
|
{
|
||||||
|
// Background's Value is DynamicColor Case
|
||||||
|
var backgroundValue = backgroundSetter.Value;
|
||||||
|
|
||||||
|
if (backgroundValue is SolidColorBrush solidColorBrush)
|
||||||
|
{
|
||||||
|
return solidColorBrush.Color; // Return SolidColorBrush's Color
|
||||||
|
}
|
||||||
|
else if (backgroundValue is DynamicResourceExtension dynamicResource)
|
||||||
|
{
|
||||||
|
// When DynamicResource Extension it is, Key is resource's name.
|
||||||
|
var resourceKey = backgroundSetter.Value.ToString();
|
||||||
|
|
||||||
|
// find key in resource and return color.
|
||||||
|
if (Resources.Contains(resourceKey))
|
||||||
|
{
|
||||||
|
var colorResource = Resources[resourceKey];
|
||||||
|
if (colorResource is SolidColorBrush colorBrush)
|
||||||
|
{
|
||||||
|
return colorBrush.Color;
|
||||||
|
}
|
||||||
|
else if (colorResource is Color color)
|
||||||
|
{
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Colors.Transparent; // Default is transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyPreviewBackground(Color? bgColor = null)
|
||||||
|
{
|
||||||
|
if (bgColor == null) return;
|
||||||
|
|
||||||
|
// Copy the existing WindowBorderStyle
|
||||||
|
var previewStyle = new Style(typeof(Border));
|
||||||
|
if (Application.Current.Resources.Contains("WindowBorderStyle"))
|
||||||
|
{
|
||||||
|
if (Application.Current.Resources["WindowBorderStyle"] is Style originalStyle)
|
||||||
|
{
|
||||||
|
foreach (var setter in originalStyle.Setters.OfType<Setter>())
|
||||||
|
{
|
||||||
|
previewStyle.Setters.Add(new Setter(setter.Property, setter.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply background color (remove transparency in color)
|
||||||
|
// WPF does not allow the use of an acrylic brush within the window's internal area,
|
||||||
|
// so transparency effects are not applied to the preview.
|
||||||
|
Color backgroundColor = Color.FromRgb(bgColor.Value.R, bgColor.Value.G, bgColor.Value.B);
|
||||||
|
previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(backgroundColor)));
|
||||||
|
|
||||||
|
// The blur theme keeps the corner round fixed (applying DWM code to modify it causes rendering issues).
|
||||||
|
// The non-blur theme retains the previously set WindowBorderStyle.
|
||||||
|
if (BlurEnabled)
|
||||||
|
{
|
||||||
|
previewStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(5)));
|
||||||
|
previewStyle.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(1)));
|
||||||
|
}
|
||||||
|
Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ColorizeWindow(string theme, BackdropTypes backdropType)
|
||||||
|
{
|
||||||
|
var dict = GetThemeResourceDictionary(theme);
|
||||||
|
if (dict == null) return;
|
||||||
|
|
||||||
|
var mainWindow = Application.Current.MainWindow;
|
||||||
|
if (mainWindow == null) return;
|
||||||
|
|
||||||
|
// Check if the theme supports blur
|
||||||
|
bool hasBlur = dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool b && b;
|
||||||
|
|
||||||
|
// SystemBG value check (Auto, Light, Dark)
|
||||||
|
string systemBG = dict.Contains("SystemBG") ? dict["SystemBG"] as string : "Auto"; // 기본값 Auto
|
||||||
|
|
||||||
|
// Check the user's ColorScheme setting
|
||||||
|
string colorScheme = _settings.ColorScheme;
|
||||||
|
|
||||||
|
// Check system dark mode setting (read AppsUseLightTheme value)
|
||||||
|
int themeValue = (int)Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
|
||||||
|
bool isSystemDark = themeValue == 0;
|
||||||
|
|
||||||
|
// Final decision on whether to use dark mode
|
||||||
|
bool useDarkMode = false;
|
||||||
|
|
||||||
|
// If systemBG is not "Auto", prioritize it over ColorScheme and set the mode based on systemBG value
|
||||||
|
if (systemBG == "Dark")
|
||||||
|
{
|
||||||
|
useDarkMode = true; // Dark
|
||||||
|
}
|
||||||
|
else if (systemBG == "Light")
|
||||||
|
{
|
||||||
|
useDarkMode = false; // Light
|
||||||
|
}
|
||||||
|
else if (systemBG == "Auto")
|
||||||
|
{
|
||||||
|
// If systemBG is "Auto", decide based on ColorScheme
|
||||||
|
if (colorScheme == "Dark")
|
||||||
|
useDarkMode = true;
|
||||||
|
else if (colorScheme == "Light")
|
||||||
|
useDarkMode = false;
|
||||||
|
else
|
||||||
|
useDarkMode = isSystemDark; // Auto (based on system setting)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply DWM Dark Mode
|
||||||
|
Win32Helper.DWMSetDarkModeForWindow(mainWindow, useDarkMode);
|
||||||
|
|
||||||
|
Color LightBG;
|
||||||
|
Color DarkBG;
|
||||||
|
|
||||||
|
// Retrieve LightBG value (fallback to WindowBorderStyle background color if not found)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
LightBG = dict.Contains("LightBG") ? (Color)dict["LightBG"] : GetWindowBorderStyleBackground(theme);
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
LightBG = GetWindowBorderStyleBackground(theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve DarkBG value (fallback to LightBG if not found)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DarkBG = dict.Contains("DarkBG") ? (Color)dict["DarkBG"] : LightBG;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
DarkBG = LightBG;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select background color based on ColorScheme and SystemBG
|
||||||
|
Color selectedBG = useDarkMode ? DarkBG : LightBG;
|
||||||
|
ApplyPreviewBackground(selectedBG);
|
||||||
|
|
||||||
|
bool isBlurAvailable = hasBlur && Win32Helper.IsBackdropSupported(); // Windows 11 미만이면 hasBlur를 강제 false
|
||||||
|
|
||||||
|
if (!isBlurAvailable)
|
||||||
|
{
|
||||||
|
mainWindow.Background = Brushes.Transparent;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Only set the background to transparent if the theme supports blur
|
||||||
|
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt)
|
||||||
|
{
|
||||||
|
mainWindow.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mainWindow.Background = new SolidColorBrush(selectedBG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsBlurTheme()
|
||||||
|
{
|
||||||
|
if (!Win32Helper.IsBackdropSupported()) // Windows 11 미만이면 무조건 false
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var resource = Application.Current.TryFindResource("ThemeBlurEnabled");
|
||||||
|
|
||||||
|
return resource is bool b && b;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Classes
|
||||||
|
|
||||||
public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null);
|
public record ThemeData(string FileNameWithoutExtension, string Name, bool? IsDark = null, bool? HasBlur = null);
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
123
Flow.Launcher.Infrastructure/MonitorInfo.cs
Normal file
123
Flow.Launcher.Infrastructure/MonitorInfo.cs
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using Windows.Win32;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
|
using Windows.Win32.Graphics.Gdi;
|
||||||
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Infrastructure;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains full information about a display monitor.
|
||||||
|
/// Codes are edited from: <see href="https://github.com/Jack251970/DesktopWidgets3">.
|
||||||
|
/// </summary>
|
||||||
|
internal class MonitorInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display monitors (including invisible pseudo-monitors associated with the mirroring drivers).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A list of display monitors</returns>
|
||||||
|
public static unsafe IList<MonitorInfo> GetDisplayMonitors()
|
||||||
|
{
|
||||||
|
var monitorCount = PInvoke.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CMONITORS);
|
||||||
|
var list = new List<MonitorInfo>(monitorCount);
|
||||||
|
var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
|
||||||
|
{
|
||||||
|
list.Add(new MonitorInfo(monitor, rect));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
var dwData = new LPARAM();
|
||||||
|
var hdc = new HDC();
|
||||||
|
bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display monitor that is nearest to a given window.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hwnd">Window handle</param>
|
||||||
|
/// <returns>The display monitor that is nearest to a given window, or null if no monitor is found.</returns>
|
||||||
|
public static unsafe MonitorInfo GetNearestDisplayMonitor(HWND hwnd)
|
||||||
|
{
|
||||||
|
var nearestMonitor = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
|
||||||
|
MonitorInfo nearestMonitorInfo = null;
|
||||||
|
var callback = new MONITORENUMPROC((HMONITOR monitor, HDC deviceContext, RECT* rect, LPARAM data) =>
|
||||||
|
{
|
||||||
|
if (monitor == nearestMonitor)
|
||||||
|
{
|
||||||
|
nearestMonitorInfo = new MonitorInfo(monitor, rect);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
var dwData = new LPARAM();
|
||||||
|
var hdc = new HDC();
|
||||||
|
bool ok = PInvoke.EnumDisplayMonitors(hdc, (RECT?)null, callback, dwData);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
Marshal.ThrowExceptionForHR(Marshal.GetLastWin32Error());
|
||||||
|
}
|
||||||
|
return nearestMonitorInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly HMONITOR _monitor;
|
||||||
|
|
||||||
|
internal unsafe MonitorInfo(HMONITOR monitor, RECT* rect)
|
||||||
|
{
|
||||||
|
RectMonitor =
|
||||||
|
new Rect(new Point(rect->left, rect->top),
|
||||||
|
new Point(rect->right, rect->bottom));
|
||||||
|
_monitor = monitor;
|
||||||
|
var info = new MONITORINFOEXW() { monitorInfo = new MONITORINFO() { cbSize = (uint)sizeof(MONITORINFOEXW) } };
|
||||||
|
GetMonitorInfo(monitor, ref info);
|
||||||
|
RectWork =
|
||||||
|
new Rect(new Point(info.monitorInfo.rcWork.left, info.monitorInfo.rcWork.top),
|
||||||
|
new Point(info.monitorInfo.rcWork.right, info.monitorInfo.rcWork.bottom));
|
||||||
|
Name = new string(info.szDevice.AsSpan()).Replace("\0", "").Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the display.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the display monitor rectangle, expressed in virtual-screen coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>
|
||||||
|
/// </remarks>
|
||||||
|
public Rect RectMonitor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the work area rectangle of the display monitor, expressed in virtual-screen coordinates.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <note>If the monitor is not the primary display monitor, some of the rectangle's coordinates may be negative values.</note>
|
||||||
|
/// </remarks>
|
||||||
|
public Rect RectWork { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets if the monitor is the the primary display monitor.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsPrimary => _monitor == PInvoke.MonitorFromWindow(new(IntPtr.Zero), MONITOR_FROM_FLAGS.MONITOR_DEFAULTTOPRIMARY);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString() => $"{Name} {RectMonitor.Width}x{RectMonitor.Height}";
|
||||||
|
|
||||||
|
private static unsafe bool GetMonitorInfo(HMONITOR hMonitor, ref MONITORINFOEXW lpmi)
|
||||||
|
{
|
||||||
|
fixed (MONITORINFOEXW* lpmiLocal = &lpmi)
|
||||||
|
{
|
||||||
|
var lpmiBase = (MONITORINFO*)lpmiLocal;
|
||||||
|
var __result = PInvoke.GetMonitorInfo(hMonitor, lpmiBase);
|
||||||
|
return __result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,4 +16,34 @@ WM_KEYUP
|
||||||
WM_SYSKEYDOWN
|
WM_SYSKEYDOWN
|
||||||
WM_SYSKEYUP
|
WM_SYSKEYUP
|
||||||
|
|
||||||
EnumWindows
|
EnumWindows
|
||||||
|
|
||||||
|
DwmSetWindowAttribute
|
||||||
|
DWM_SYSTEMBACKDROP_TYPE
|
||||||
|
DWM_WINDOW_CORNER_PREFERENCE
|
||||||
|
|
||||||
|
MAX_PATH
|
||||||
|
SystemParametersInfo
|
||||||
|
|
||||||
|
SetForegroundWindow
|
||||||
|
|
||||||
|
GetWindowLong
|
||||||
|
GetForegroundWindow
|
||||||
|
GetDesktopWindow
|
||||||
|
GetShellWindow
|
||||||
|
GetWindowRect
|
||||||
|
GetClassName
|
||||||
|
FindWindowEx
|
||||||
|
WINDOW_STYLE
|
||||||
|
|
||||||
|
SetLastError
|
||||||
|
WINDOW_EX_STYLE
|
||||||
|
|
||||||
|
GetSystemMetrics
|
||||||
|
EnumDisplayMonitors
|
||||||
|
MonitorFromWindow
|
||||||
|
GetMonitorInfo
|
||||||
|
MONITORINFOEXW
|
||||||
|
|
||||||
|
WM_ENTERSIZEMOVE
|
||||||
|
WM_EXITSIZEMOVE
|
||||||
25
Flow.Launcher.Infrastructure/PInvokeExtensions.cs
Normal file
25
Flow.Launcher.Infrastructure/PInvokeExtensions.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
|
namespace Windows.Win32;
|
||||||
|
|
||||||
|
// Edited from: https://github.com/files-community/Files
|
||||||
|
internal static partial class PInvoke
|
||||||
|
{
|
||||||
|
[DllImport("User32", EntryPoint = "SetWindowLongW", ExactSpelling = true)]
|
||||||
|
static extern int _SetWindowLong(HWND hWnd, int nIndex, int dwNewLong);
|
||||||
|
|
||||||
|
[DllImport("User32", EntryPoint = "SetWindowLongPtrW", ExactSpelling = true)]
|
||||||
|
static extern nint _SetWindowLongPtr(HWND hWnd, int nIndex, nint dwNewLong);
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// CsWin32 doesn't generate SetWindowLong on other than x86 and vice versa.
|
||||||
|
// For more info, visit https://github.com/microsoft/CsWin32/issues/882
|
||||||
|
public static unsafe nint SetWindowLongPtr(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, nint dwNewLong)
|
||||||
|
{
|
||||||
|
return sizeof(nint) is 4
|
||||||
|
? _SetWindowLong(hWnd, (int)nIndex, (int)dwNewLong)
|
||||||
|
: _SetWindowLongPtr(hWnd, (int)nIndex, dwNewLong);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -76,6 +76,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public bool UseDropShadowEffect { get; set; } = true;
|
public bool UseDropShadowEffect { get; set; } = true;
|
||||||
|
public BackdropTypes BackdropType{ get; set; } = BackdropTypes.None;
|
||||||
|
|
||||||
/* Appearance Settings. It should be separated from the setting later.*/
|
/* Appearance Settings. It should be separated from the setting later.*/
|
||||||
public double WindowHeightSize { get; set; } = 42;
|
public double WindowHeightSize { get; set; } = 42;
|
||||||
|
|
@ -457,4 +458,12 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
Fast,
|
Fast,
|
||||||
Custom
|
Custom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum BackdropTypes
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Acrylic,
|
||||||
|
Mica,
|
||||||
|
MicaAlt
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Windows.Interop;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using Windows.Win32;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
|
using Windows.Win32.Graphics.Dwm;
|
||||||
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
|
|
||||||
namespace Flow.Launcher.Infrastructure
|
namespace Flow.Launcher.Infrastructure
|
||||||
{
|
{
|
||||||
|
|
@ -9,93 +16,306 @@ namespace Flow.Launcher.Infrastructure
|
||||||
{
|
{
|
||||||
#region Blur Handling
|
#region Blur Handling
|
||||||
|
|
||||||
/*
|
public static bool IsBackdropSupported()
|
||||||
Found on https://github.com/riverar/sample-win10-aeroglass
|
|
||||||
*/
|
|
||||||
|
|
||||||
private enum AccentState
|
|
||||||
{
|
{
|
||||||
ACCENT_DISABLED = 0,
|
// Mica and Acrylic only supported Windows 11 22000+
|
||||||
ACCENT_ENABLE_GRADIENT = 1,
|
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
|
||||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
Environment.OSVersion.Version.Build >= 22000;
|
||||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
|
||||||
ACCENT_INVALID_STATE = 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
public static unsafe bool DWMSetCloakForWindow(Window window, bool cloak)
|
||||||
private struct AccentPolicy
|
|
||||||
{
|
{
|
||||||
public AccentState AccentState;
|
var cloaked = cloak ? 1 : 0;
|
||||||
public int AccentFlags;
|
|
||||||
public int GradientColor;
|
return PInvoke.DwmSetWindowAttribute(
|
||||||
public int AnimationId;
|
GetWindowHandle(window),
|
||||||
|
DWMWINDOWATTRIBUTE.DWMWA_CLOAK,
|
||||||
|
&cloaked,
|
||||||
|
(uint)Marshal.SizeOf<int>()).Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
public static unsafe bool DWMSetBackdropForWindow(Window window, BackdropTypes backdrop)
|
||||||
private struct WindowCompositionAttributeData
|
|
||||||
{
|
{
|
||||||
public WindowCompositionAttribute Attribute;
|
var backdropType = backdrop switch
|
||||||
public IntPtr Data;
|
{
|
||||||
public int SizeOfData;
|
BackdropTypes.Acrylic => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TRANSIENTWINDOW,
|
||||||
|
BackdropTypes.Mica => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_MAINWINDOW,
|
||||||
|
BackdropTypes.MicaAlt => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_TABBEDWINDOW,
|
||||||
|
_ => DWM_SYSTEMBACKDROP_TYPE.DWMSBT_AUTO
|
||||||
|
};
|
||||||
|
|
||||||
|
return PInvoke.DwmSetWindowAttribute(
|
||||||
|
GetWindowHandle(window),
|
||||||
|
DWMWINDOWATTRIBUTE.DWMWA_SYSTEMBACKDROP_TYPE,
|
||||||
|
&backdropType,
|
||||||
|
(uint)Marshal.SizeOf<int>()).Succeeded;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum WindowCompositionAttribute
|
public static unsafe bool DWMSetDarkModeForWindow(Window window, bool useDarkMode)
|
||||||
{
|
{
|
||||||
WCA_ACCENT_POLICY = 19
|
var darkMode = useDarkMode ? 1 : 0;
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
return PInvoke.DwmSetWindowAttribute(
|
||||||
private static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
|
GetWindowHandle(window),
|
||||||
|
DWMWINDOWATTRIBUTE.DWMWA_USE_IMMERSIVE_DARK_MODE,
|
||||||
|
&darkMode,
|
||||||
|
(uint)Marshal.SizeOf<int>()).Succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if the blur theme is enabled
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsBlurTheme()
|
/// <param name="window"></param>
|
||||||
|
/// <param name="cornerType">DoNotRound, Round, RoundSmall, Default</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static unsafe bool DWMSetCornerPreferenceForWindow(Window window, string cornerType)
|
||||||
{
|
{
|
||||||
if (Environment.OSVersion.Version >= new Version(6, 2))
|
var preference = cornerType switch
|
||||||
{
|
{
|
||||||
var resource = Application.Current.TryFindResource("ThemeBlurEnabled");
|
"DoNotRound" => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DONOTROUND,
|
||||||
|
"Round" => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUND,
|
||||||
|
"RoundSmall" => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUNDSMALL,
|
||||||
|
"Default" => DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_DEFAULT,
|
||||||
|
_ => throw new InvalidOperationException("Invalid corner type")
|
||||||
|
};
|
||||||
|
|
||||||
if (resource is bool b)
|
return PInvoke.DwmSetWindowAttribute(
|
||||||
return b;
|
GetWindowHandle(window),
|
||||||
|
DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE,
|
||||||
|
&preference,
|
||||||
|
(uint)Marshal.SizeOf<int>()).Succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Wallpaper
|
||||||
|
|
||||||
|
public static unsafe string GetWallpaperPath()
|
||||||
|
{
|
||||||
|
var wallpaperPtr = stackalloc char[(int)PInvoke.MAX_PATH];
|
||||||
|
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, PInvoke.MAX_PATH,
|
||||||
|
wallpaperPtr,
|
||||||
|
0);
|
||||||
|
var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr);
|
||||||
|
|
||||||
|
return wallpaper.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Window Foreground
|
||||||
|
|
||||||
|
public static nint GetForegroundWindow()
|
||||||
|
{
|
||||||
|
return PInvoke.GetForegroundWindow().Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SetForegroundWindow(Window window)
|
||||||
|
{
|
||||||
|
return PInvoke.SetForegroundWindow(GetWindowHandle(window));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool SetForegroundWindow(nint handle)
|
||||||
|
{
|
||||||
|
return PInvoke.SetForegroundWindow(new(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Task Switching
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide windows in the Alt+Tab window list
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">To hide a window</param>
|
||||||
|
public static void HideFromAltTab(Window window)
|
||||||
|
{
|
||||||
|
var hwnd = GetWindowHandle(window);
|
||||||
|
|
||||||
|
var exStyle = GetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||||
|
|
||||||
|
// Add TOOLWINDOW style, remove APPWINDOW style
|
||||||
|
var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
|
||||||
|
|
||||||
|
SetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Restore window display in the Alt+Tab window list.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="window">To restore the displayed window</param>
|
||||||
|
public static void ShowInAltTab(Window window)
|
||||||
|
{
|
||||||
|
var hwnd = GetWindowHandle(window);
|
||||||
|
|
||||||
|
var exStyle = GetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||||
|
|
||||||
|
// Remove the TOOLWINDOW style and add the APPWINDOW style.
|
||||||
|
var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
|
||||||
|
|
||||||
|
SetWindowStyle(GetWindowHandle(window), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disable windows toolbar's control box
|
||||||
|
/// This will also disable system menu with Alt+Space hotkey
|
||||||
|
/// </summary>
|
||||||
|
public static void DisableControlBox(Window window)
|
||||||
|
{
|
||||||
|
var hwnd = GetWindowHandle(window);
|
||||||
|
|
||||||
|
var style = GetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
|
||||||
|
|
||||||
|
style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
|
||||||
|
|
||||||
|
SetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, style);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex)
|
||||||
|
{
|
||||||
|
var style = PInvoke.GetWindowLong(hWnd, nIndex);
|
||||||
|
if (style == 0 && Marshal.GetLastPInvokeError() != 0)
|
||||||
|
{
|
||||||
|
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static nint SetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong)
|
||||||
|
{
|
||||||
|
PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error
|
||||||
|
|
||||||
|
var result = PInvoke.SetWindowLongPtr(hWnd, nIndex, dwNewLong);
|
||||||
|
if (result == 0 && Marshal.GetLastPInvokeError() != 0)
|
||||||
|
{
|
||||||
|
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Window Fullscreen
|
||||||
|
|
||||||
|
private const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
|
||||||
|
private const string WINDOW_CLASS_WINTAB = "Flip3D";
|
||||||
|
private const string WINDOW_CLASS_PROGMAN = "Progman";
|
||||||
|
private const string WINDOW_CLASS_WORKERW = "WorkerW";
|
||||||
|
|
||||||
|
private static HWND _hwnd_shell;
|
||||||
|
private static HWND HWND_SHELL =>
|
||||||
|
_hwnd_shell != HWND.Null ? _hwnd_shell : _hwnd_shell = PInvoke.GetShellWindow();
|
||||||
|
|
||||||
|
private static HWND _hwnd_desktop;
|
||||||
|
private static HWND HWND_DESKTOP =>
|
||||||
|
_hwnd_desktop != HWND.Null ? _hwnd_desktop : _hwnd_desktop = PInvoke.GetDesktopWindow();
|
||||||
|
|
||||||
|
public static unsafe bool IsForegroundWindowFullscreen()
|
||||||
|
{
|
||||||
|
// Get current active window
|
||||||
|
var hWnd = PInvoke.GetForegroundWindow();
|
||||||
|
if (hWnd.Equals(HWND.Null))
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
// If current active window is desktop or shell, exit early
|
||||||
|
if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string windowClass;
|
||||||
|
const int capacity = 256;
|
||||||
|
Span<char> buffer = stackalloc char[capacity];
|
||||||
|
int validLength;
|
||||||
|
fixed (char* pBuffer = buffer)
|
||||||
|
{
|
||||||
|
validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
windowClass = buffer[..validLength].ToString();
|
||||||
|
|
||||||
|
// For Win+Tab (Flip3D)
|
||||||
|
if (windowClass == WINDOW_CLASS_WINTAB)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PInvoke.GetWindowRect(hWnd, out var appBounds);
|
||||||
|
|
||||||
|
// For console (ConsoleWindowClass), we have to check for negative dimensions
|
||||||
|
if (windowClass == WINDOW_CLASS_CONSOLE)
|
||||||
|
{
|
||||||
|
return appBounds.top < 0 && appBounds.bottom < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For desktop (Progman or WorkerW, depends on the system), we have to check
|
||||||
|
if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
|
||||||
|
{
|
||||||
|
var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
|
||||||
|
hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
|
||||||
|
if (hWndDesktop.Value != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var monitorInfo = MonitorInfo.GetNearestDisplayMonitor(hWnd);
|
||||||
|
return (appBounds.bottom - appBounds.top) == monitorInfo.RectMonitor.Height &&
|
||||||
|
(appBounds.right - appBounds.left) == monitorInfo.RectMonitor.Width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Pixel to DIP
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets the blur for a window via SetWindowCompositionAttribute
|
/// Transforms pixels to Device Independent Pixels used by WPF
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void SetBlurForWindow(Window w, bool blur)
|
/// <param name="visual">current window, required to get presentation source</param>
|
||||||
|
/// <param name="unitX">horizontal position in pixels</param>
|
||||||
|
/// <param name="unitY">vertical position in pixels</param>
|
||||||
|
/// <returns>point containing device independent pixels</returns>
|
||||||
|
public static Point TransformPixelsToDIP(Visual visual, double unitX, double unitY)
|
||||||
{
|
{
|
||||||
SetWindowAccent(w, blur ? AccentState.ACCENT_ENABLE_BLURBEHIND : AccentState.ACCENT_DISABLED);
|
Matrix matrix;
|
||||||
}
|
var source = PresentationSource.FromVisual(visual);
|
||||||
|
if (source is not null)
|
||||||
private static void SetWindowAccent(Window w, AccentState state)
|
|
||||||
{
|
|
||||||
var windowHelper = new WindowInteropHelper(w);
|
|
||||||
|
|
||||||
windowHelper.EnsureHandle();
|
|
||||||
|
|
||||||
var accent = new AccentPolicy { AccentState = state };
|
|
||||||
var accentStructSize = Marshal.SizeOf(accent);
|
|
||||||
|
|
||||||
var accentPtr = Marshal.AllocHGlobal(accentStructSize);
|
|
||||||
Marshal.StructureToPtr(accent, accentPtr, false);
|
|
||||||
|
|
||||||
var data = new WindowCompositionAttributeData
|
|
||||||
{
|
{
|
||||||
Attribute = WindowCompositionAttribute.WCA_ACCENT_POLICY,
|
matrix = source.CompositionTarget.TransformFromDevice;
|
||||||
SizeOfData = accentStructSize,
|
}
|
||||||
Data = accentPtr
|
else
|
||||||
};
|
{
|
||||||
|
using var src = new HwndSource(new HwndSourceParameters());
|
||||||
|
matrix = src.CompositionTarget.TransformFromDevice;
|
||||||
|
}
|
||||||
|
|
||||||
SetWindowCompositionAttribute(windowHelper.Handle, ref data);
|
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
|
||||||
|
|
||||||
Marshal.FreeHGlobal(accentPtr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region WndProc
|
||||||
|
|
||||||
|
public const int WM_ENTERSIZEMOVE = (int)PInvoke.WM_ENTERSIZEMOVE;
|
||||||
|
public const int WM_EXITSIZEMOVE = (int)PInvoke.WM_EXITSIZEMOVE;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Window Handle
|
||||||
|
|
||||||
|
internal static HWND GetWindowHandle(Window window, bool ensure = false)
|
||||||
|
{
|
||||||
|
var windowHelper = new WindowInteropHelper(window);
|
||||||
|
if (ensure)
|
||||||
|
{
|
||||||
|
windowHelper.EnsureHandle();
|
||||||
|
}
|
||||||
|
return new(windowHelper.Handle);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,6 @@ namespace Flow.Launcher.Plugin
|
||||||
/// <param name="callback"></param>
|
/// <param name="callback"></param>
|
||||||
public void RemoveGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback);
|
public void RemoveGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fuzzy Search the string with the given query. This is the core search mechanism Flow uses
|
/// Fuzzy Search the string with the given query. This is the core search mechanism Flow uses
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -191,14 +190,15 @@ namespace Flow.Launcher.Plugin
|
||||||
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default);
|
Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null, CancellationToken token = default);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add ActionKeyword for specific plugin
|
/// Add ActionKeyword and update action keyword metadata for specific plugin
|
||||||
|
/// Before adding, please check if action keyword is already assigned by <see cref="ActionKeywordAssigned"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pluginId">ID for plugin that needs to add action keyword</param>
|
/// <param name="pluginId">ID for plugin that needs to add action keyword</param>
|
||||||
/// <param name="newActionKeyword">The actionkeyword that is supposed to be added</param>
|
/// <param name="newActionKeyword">The actionkeyword that is supposed to be added</param>
|
||||||
void AddActionKeyword(string pluginId, string newActionKeyword);
|
void AddActionKeyword(string pluginId, string newActionKeyword);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Remove ActionKeyword for specific plugin
|
/// Remove ActionKeyword and update action keyword metadata for specific plugin
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pluginId">ID for plugin that needs to remove action keyword</param>
|
/// <param name="pluginId">ID for plugin that needs to remove action keyword</param>
|
||||||
/// <param name="oldActionKeyword">The actionkeyword that is supposed to be removed</param>
|
/// <param name="oldActionKeyword">The actionkeyword that is supposed to be removed</param>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ namespace Flow.Launcher.Plugin
|
||||||
public string ActionKeyword { get; set; }
|
public string ActionKeyword { get; set; }
|
||||||
|
|
||||||
public List<string> ActionKeywords { get; set; }
|
public List<string> ActionKeywords { get; set; }
|
||||||
|
|
||||||
|
public bool HideActionKeywordPanel { get; set; }
|
||||||
|
|
||||||
public int SearchDelay { get; set; }
|
public int SearchDelay { get; set; }
|
||||||
|
|
||||||
public string IcoPath { get; set;}
|
public string IcoPath { get; set;}
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,9 @@ namespace Flow.Launcher.Plugin
|
||||||
public const string TermSeparator = " ";
|
public const string TermSeparator = " ";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// User can set multiple action keywords seperated by ';'
|
/// User can set multiple action keywords seperated by whitespace
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ActionKeywordSeparator = ";";
|
public const string ActionKeywordSeparator = TermSeparator;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wildcard action keyword. Plugins using this value will be queried on every search.
|
/// Wildcard action keyword. Plugins using this value will be queried on every search.
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ using Flow.Launcher.Core.Resource;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
using Flow.Launcher.Core;
|
using Flow.Launcher.Core;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Flow.Launcher
|
namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
|
|
@ -32,14 +34,37 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private void btnDone_OnClick(object sender, RoutedEventArgs _)
|
private void btnDone_OnClick(object sender, RoutedEventArgs _)
|
||||||
{
|
{
|
||||||
var oldActionKeyword = plugin.Metadata.ActionKeywords[0];
|
var oldActionKeywords = plugin.Metadata.ActionKeywords;
|
||||||
var newActionKeyword = tbAction.Text.Trim();
|
|
||||||
newActionKeyword = newActionKeyword.Length > 0 ? newActionKeyword : "*";
|
var newActionKeywords = tbAction.Text.Split(Query.ActionKeywordSeparator).ToList();
|
||||||
|
newActionKeywords.RemoveAll(string.IsNullOrEmpty);
|
||||||
if (!PluginViewModel.IsActionKeywordRegistered(newActionKeyword))
|
newActionKeywords = newActionKeywords.Distinct().ToList();
|
||||||
|
|
||||||
|
newActionKeywords = newActionKeywords.Count > 0 ? newActionKeywords : new() { Query.GlobalPluginWildcardSign };
|
||||||
|
|
||||||
|
var addedActionKeywords = newActionKeywords.Except(oldActionKeywords).ToList();
|
||||||
|
var removedActionKeywords = oldActionKeywords.Except(newActionKeywords).ToList();
|
||||||
|
if (!addedActionKeywords.Any(App.API.ActionKeywordAssigned))
|
||||||
{
|
{
|
||||||
pluginViewModel.ChangeActionKeyword(newActionKeyword, oldActionKeyword);
|
if (oldActionKeywords.Count != newActionKeywords.Count)
|
||||||
Close();
|
{
|
||||||
|
ReplaceActionKeyword(plugin.Metadata.ID, removedActionKeywords, addedActionKeywords);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortedOldActionKeywords = oldActionKeywords.OrderBy(s => s).ToList();
|
||||||
|
var sortedNewActionKeywords = newActionKeywords.OrderBy(s => s).ToList();
|
||||||
|
|
||||||
|
if (sortedOldActionKeywords.SequenceEqual(sortedNewActionKeywords))
|
||||||
|
{
|
||||||
|
// User just changes the sequence of action keywords
|
||||||
|
var msg = translater.GetTranslation("newActionKeywordsSameAsOld");
|
||||||
|
MessageBoxEx.Show(msg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReplaceActionKeyword(plugin.Metadata.ID, removedActionKeywords, addedActionKeywords);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -47,5 +72,21 @@ namespace Flow.Launcher
|
||||||
App.API.ShowMsgBox(msg);
|
App.API.ShowMsgBox(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReplaceActionKeyword(string id, IReadOnlyList<string> removedActionKeywords, IReadOnlyList<string> addedActionKeywords)
|
||||||
|
{
|
||||||
|
foreach (var actionKeyword in removedActionKeywords)
|
||||||
|
{
|
||||||
|
App.API.RemoveActionKeyword(id, actionKeyword);
|
||||||
|
}
|
||||||
|
foreach (var actionKeyword in addedActionKeywords)
|
||||||
|
{
|
||||||
|
App.API.AddActionKeyword(id, actionKeyword);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update action keywords text and close window
|
||||||
|
pluginViewModel.OnActionKeywordsChanged();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||||
ShutdownMode="OnMainWindowClose"
|
ShutdownMode="OnMainWindowClose"
|
||||||
Startup="OnStartupAsync">
|
Startup="OnStartup">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
|
|
||||||
|
|
@ -101,15 +101,15 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
|
if (SingleInstance<App>.InitializeAsFirstInstance(Unique))
|
||||||
{
|
{
|
||||||
using (var application = new App())
|
using var application = new App();
|
||||||
{
|
application.InitializeComponent();
|
||||||
application.InitializeComponent();
|
application.Run();
|
||||||
application.Run();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void OnStartupAsync(object sender, StartupEventArgs e)
|
#pragma warning disable VSTHRD100 // Avoid async void methods
|
||||||
|
|
||||||
|
private async void OnStartup(object sender, StartupEventArgs e)
|
||||||
{
|
{
|
||||||
await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
|
await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
|
||||||
{
|
{
|
||||||
|
|
@ -128,7 +128,7 @@ namespace Flow.Launcher
|
||||||
AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings);
|
AbstractPluginEnvironment.PreStartPluginExecutablePathUpdate(_settings);
|
||||||
|
|
||||||
// TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future
|
// TODO: Clean InternationalizationManager.Instance and InternationalizationManager.Instance.GetTranslation in future
|
||||||
InternationalizationManager.Instance.ChangeLanguage(_settings.Language);
|
Ioc.Default.GetRequiredService<Internationalization>().ChangeLanguage(_settings.Language);
|
||||||
|
|
||||||
PluginManager.LoadPlugins(_settings.PluginSettings);
|
PluginManager.LoadPlugins(_settings.PluginSettings);
|
||||||
|
|
||||||
|
|
@ -137,8 +137,7 @@ namespace Flow.Launcher
|
||||||
await PluginManager.InitializePluginsAsync();
|
await PluginManager.InitializePluginsAsync();
|
||||||
await imageLoadertask;
|
await imageLoadertask;
|
||||||
|
|
||||||
var mainVM = Ioc.Default.GetRequiredService<MainViewModel>();
|
var window = new MainWindow();
|
||||||
var window = new MainWindow(_settings, mainVM);
|
|
||||||
|
|
||||||
Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}");
|
Log.Info($"|App.OnStartup|Dependencies Info:{ErrorReporting.DependenciesInfo()}");
|
||||||
|
|
||||||
|
|
@ -149,7 +148,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
// main windows needs initialized before theme change because of blur settings
|
// main windows needs initialized before theme change because of blur settings
|
||||||
// TODO: Clean ThemeManager.Instance in future
|
// TODO: Clean ThemeManager.Instance in future
|
||||||
ThemeManager.Instance.ChangeTheme(_settings.Theme);
|
Ioc.Default.GetRequiredService<Theme>().ChangeTheme();
|
||||||
|
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
|
||||||
|
|
@ -164,6 +163,8 @@ namespace Flow.Launcher
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning restore VSTHRD100 // Avoid async void methods
|
||||||
|
|
||||||
private void AutoStartup()
|
private void AutoStartup()
|
||||||
{
|
{
|
||||||
// we try to enable auto-startup on first launch, or reenable if it was removed
|
// we try to enable auto-startup on first launch, or reenable if it was removed
|
||||||
|
|
@ -186,8 +187,7 @@ namespace Flow.Launcher
|
||||||
// but if it fails (permissions, etc) then don't keep retrying
|
// but if it fails (permissions, etc) then don't keep retrying
|
||||||
// this also gives the user a visual indication in the Settings widget
|
// this also gives the user a visual indication in the Settings widget
|
||||||
_settings.StartFlowLauncherOnSystemStartup = false;
|
_settings.StartFlowLauncherOnSystemStartup = false;
|
||||||
Notification.Show(InternationalizationManager.Instance.GetTranslation("setAutoStartFailed"),
|
API.ShowMsg(API.GetTranslation("setAutoStartFailed"), e.Message);
|
||||||
e.Message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,10 +94,6 @@
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
||||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
<!-- ModernWpfUI v0.9.5 introduced WinRT changes that causes Notification platform unavailable error on some machines -->
|
<!-- ModernWpfUI v0.9.5 introduced WinRT changes that causes Notification platform unavailable error on some machines -->
|
||||||
<!-- https://github.com/Flow-Launcher/Flow.Launcher/issues/1772#issuecomment-1502440801 -->
|
<!-- https://github.com/Flow-Launcher/Flow.Launcher/issues/1772#issuecomment-1502440801 -->
|
||||||
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
|
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
|
||||||
|
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Interop;
|
|
||||||
using Windows.Win32;
|
|
||||||
using Windows.Win32.Foundation;
|
|
||||||
using Windows.Win32.Graphics.Dwm;
|
|
||||||
using Windows.Win32.UI.Controls;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper;
|
|
||||||
|
|
||||||
public class DwmDropShadow
|
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Drops a standard shadow to a WPF Window, even if the window isborderless. Only works with DWM (Vista and Seven).
|
|
||||||
/// This method is much more efficient than setting AllowsTransparency to true and using the DropShadow effect,
|
|
||||||
/// as AllowsTransparency involves a huge permormance issue (hardware acceleration is turned off for all the window).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">Window to which the shadow will be applied</param>
|
|
||||||
public static void DropShadowToWindow(Window window)
|
|
||||||
{
|
|
||||||
if (!DropShadow(window))
|
|
||||||
{
|
|
||||||
window.SourceInitialized += window_SourceInitialized;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void window_SourceInitialized(object sender, EventArgs e) //fixed typo
|
|
||||||
{
|
|
||||||
Window window = (Window)sender;
|
|
||||||
|
|
||||||
DropShadow(window);
|
|
||||||
|
|
||||||
window.SourceInitialized -= window_SourceInitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The actual method that makes API calls to drop the shadow to the window
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">Window to which the shadow will be applied</param>
|
|
||||||
/// <returns>True if the method succeeded, false if not</returns>
|
|
||||||
private static unsafe bool DropShadow(Window window)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WindowInteropHelper helper = new WindowInteropHelper(window);
|
|
||||||
int val = 2;
|
|
||||||
var ret1 = PInvoke.DwmSetWindowAttribute(new (helper.Handle), DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, &val, 4);
|
|
||||||
|
|
||||||
if (ret1 == HRESULT.S_OK)
|
|
||||||
{
|
|
||||||
var m = new MARGINS { cyBottomHeight = 0, cxLeftWidth = 0, cxRightWidth = 0, cyTopHeight = 0 };
|
|
||||||
var ret2 = PInvoke.DwmExtendFrameIntoClientArea(new(helper.Handle), &m);
|
|
||||||
return ret2 == HRESULT.S_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// Probably dwmapi.dll not found (incompatible OS)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -2,19 +2,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
using Flow.Launcher.Infrastructure;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Windows.Win32;
|
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper;
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
public static class WallpaperPathRetrieval
|
public static class WallpaperPathRetrieval
|
||||||
{
|
{
|
||||||
private static readonly int MAX_PATH = 260;
|
|
||||||
private static readonly int MAX_CACHE_SIZE = 3;
|
private static readonly int MAX_CACHE_SIZE = 3;
|
||||||
|
|
||||||
private static readonly Dictionary<(string, DateTime), ImageBrush> wallpaperCache = new();
|
private static readonly Dictionary<(string, DateTime), ImageBrush> wallpaperCache = new();
|
||||||
|
|
@ -29,7 +26,7 @@ public static class WallpaperPathRetrieval
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var wallpaperPath = GetWallpaperPath();
|
var wallpaperPath = Win32Helper.GetWallpaperPath();
|
||||||
if (wallpaperPath is not null && File.Exists(wallpaperPath))
|
if (wallpaperPath is not null && File.Exists(wallpaperPath))
|
||||||
{
|
{
|
||||||
// Since the wallpaper file name can be the same (TranscodedWallpaper),
|
// Since the wallpaper file name can be the same (TranscodedWallpaper),
|
||||||
|
|
@ -78,17 +75,6 @@ public static class WallpaperPathRetrieval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe string GetWallpaperPath()
|
|
||||||
{
|
|
||||||
var wallpaperPtr = stackalloc char[MAX_PATH];
|
|
||||||
PInvoke.SystemParametersInfo(SYSTEM_PARAMETERS_INFO_ACTION.SPI_GETDESKWALLPAPER, (uint)MAX_PATH,
|
|
||||||
wallpaperPtr,
|
|
||||||
0);
|
|
||||||
var wallpaper = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(wallpaperPtr);
|
|
||||||
|
|
||||||
return wallpaper.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color GetWallpaperColor()
|
private static Color GetWallpaperColor()
|
||||||
{
|
{
|
||||||
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", true);
|
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Colors", true);
|
||||||
|
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using System.Windows.Interop;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using Windows.Win32;
|
|
||||||
using Windows.Win32.Foundation;
|
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
|
||||||
using Point = System.Windows.Point;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Helper;
|
|
||||||
|
|
||||||
public class WindowsInteropHelper
|
|
||||||
{
|
|
||||||
private static HWND _hwnd_shell;
|
|
||||||
private static HWND _hwnd_desktop;
|
|
||||||
|
|
||||||
//Accessors for shell and desktop handlers
|
|
||||||
//Will set the variables once and then will return them
|
|
||||||
private static HWND HWND_SHELL
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _hwnd_shell != HWND.Null ? _hwnd_shell : _hwnd_shell = PInvoke.GetShellWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HWND HWND_DESKTOP
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _hwnd_desktop != HWND.Null ? _hwnd_desktop : _hwnd_desktop = PInvoke.GetDesktopWindow();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const string WINDOW_CLASS_CONSOLE = "ConsoleWindowClass";
|
|
||||||
const string WINDOW_CLASS_WINTAB = "Flip3D";
|
|
||||||
const string WINDOW_CLASS_PROGMAN = "Progman";
|
|
||||||
const string WINDOW_CLASS_WORKERW = "WorkerW";
|
|
||||||
|
|
||||||
public unsafe static bool IsWindowFullscreen()
|
|
||||||
{
|
|
||||||
//get current active window
|
|
||||||
var hWnd = PInvoke.GetForegroundWindow();
|
|
||||||
|
|
||||||
if (hWnd.Equals(HWND.Null))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if current active window is desktop or shell, exit early
|
|
||||||
if (hWnd.Equals(HWND_DESKTOP) || hWnd.Equals(HWND_SHELL))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
string windowClass;
|
|
||||||
const int capacity = 256;
|
|
||||||
Span<char> buffer = stackalloc char[capacity];
|
|
||||||
int validLength;
|
|
||||||
fixed (char* pBuffer = buffer)
|
|
||||||
{
|
|
||||||
validLength = PInvoke.GetClassName(hWnd, pBuffer, capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
windowClass = buffer[..validLength].ToString();
|
|
||||||
|
|
||||||
|
|
||||||
//for Win+Tab (Flip3D)
|
|
||||||
if (windowClass == WINDOW_CLASS_WINTAB)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PInvoke.GetWindowRect(hWnd, out var appBounds);
|
|
||||||
|
|
||||||
//for console (ConsoleWindowClass), we have to check for negative dimensions
|
|
||||||
if (windowClass == WINDOW_CLASS_CONSOLE)
|
|
||||||
{
|
|
||||||
return appBounds.top < 0 && appBounds.bottom < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//for desktop (Progman or WorkerW, depends on the system), we have to check
|
|
||||||
if (windowClass is WINDOW_CLASS_PROGMAN or WINDOW_CLASS_WORKERW)
|
|
||||||
{
|
|
||||||
var hWndDesktop = PInvoke.FindWindowEx(hWnd, HWND.Null, "SHELLDLL_DefView", null);
|
|
||||||
hWndDesktop = PInvoke.FindWindowEx(hWndDesktop, HWND.Null, "SysListView32", "FolderView");
|
|
||||||
if (hWndDesktop.Value != (IntPtr.Zero))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle screenBounds = Screen.FromHandle(hWnd).Bounds;
|
|
||||||
return (appBounds.bottom - appBounds.top) == screenBounds.Height &&
|
|
||||||
(appBounds.right - appBounds.left) == screenBounds.Width;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// disable windows toolbar's control box
|
|
||||||
/// this will also disable system menu with Alt+Space hotkey
|
|
||||||
/// </summary>
|
|
||||||
public static void DisableControlBox(Window win)
|
|
||||||
{
|
|
||||||
var hwnd = new HWND(new WindowInteropHelper(win).Handle);
|
|
||||||
|
|
||||||
var style = PInvoke.GetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE);
|
|
||||||
|
|
||||||
if (style == 0)
|
|
||||||
{
|
|
||||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
|
||||||
}
|
|
||||||
|
|
||||||
style &= ~(int)WINDOW_STYLE.WS_SYSMENU;
|
|
||||||
|
|
||||||
var previousStyle = PInvoke.SetWindowLong(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE,
|
|
||||||
style);
|
|
||||||
|
|
||||||
if (previousStyle == 0)
|
|
||||||
{
|
|
||||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Transforms pixels to Device Independent Pixels used by WPF
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="visual">current window, required to get presentation source</param>
|
|
||||||
/// <param name="unitX">horizontal position in pixels</param>
|
|
||||||
/// <param name="unitY">vertical position in pixels</param>
|
|
||||||
/// <returns>point containing device independent pixels</returns>
|
|
||||||
public static Point TransformPixelsToDIP(Visual visual, double unitX, double unitY)
|
|
||||||
{
|
|
||||||
Matrix matrix;
|
|
||||||
var source = PresentationSource.FromVisual(visual);
|
|
||||||
if (source is not null)
|
|
||||||
{
|
|
||||||
matrix = source.CompositionTarget.TransformFromDevice;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
using var src = new HwndSource(new HwndSourceParameters());
|
|
||||||
matrix = src.CompositionTarget.TransformFromDevice;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Point((int)(matrix.M11 * unitX), (int)(matrix.M22 * unitY));
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Alt Tab
|
|
||||||
|
|
||||||
private static int SetWindowLong(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong)
|
|
||||||
{
|
|
||||||
PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error
|
|
||||||
|
|
||||||
var result = PInvoke.SetWindowLong(hWnd, nIndex, dwNewLong);
|
|
||||||
if (result == 0 && Marshal.GetLastPInvokeError() != 0)
|
|
||||||
{
|
|
||||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hide windows in the Alt+Tab window list
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">To hide a window</param>
|
|
||||||
public static void HideFromAltTab(Window window)
|
|
||||||
{
|
|
||||||
var exStyle = GetCurrentWindowStyle(window);
|
|
||||||
|
|
||||||
// Add TOOLWINDOW style, remove APPWINDOW style
|
|
||||||
var newExStyle = ((uint)exStyle | (uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) & ~(uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
|
|
||||||
|
|
||||||
SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Restore window display in the Alt+Tab window list.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">To restore the displayed window</param>
|
|
||||||
public static void ShowInAltTab(Window window)
|
|
||||||
{
|
|
||||||
var exStyle = GetCurrentWindowStyle(window);
|
|
||||||
|
|
||||||
// Remove the TOOLWINDOW style and add the APPWINDOW style.
|
|
||||||
var newExStyle = ((uint)exStyle & ~(uint)WINDOW_EX_STYLE.WS_EX_TOOLWINDOW) | (uint)WINDOW_EX_STYLE.WS_EX_APPWINDOW;
|
|
||||||
|
|
||||||
SetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)newExStyle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// To obtain the current overridden style of a window.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">To obtain the style dialog window</param>
|
|
||||||
/// <returns>current extension style value</returns>
|
|
||||||
private static int GetCurrentWindowStyle(Window window)
|
|
||||||
{
|
|
||||||
var style = PInvoke.GetWindowLong(new(new WindowInteropHelper(window).Handle), WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
|
||||||
if (style == 0 && Marshal.GetLastPInvokeError() != 0)
|
|
||||||
{
|
|
||||||
throw new Win32Exception(Marshal.GetLastPInvokeError());
|
|
||||||
}
|
|
||||||
return style;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
@ -214,13 +214,14 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
HotkeyList.ItemsSource = KeysToDisplay;
|
HotkeyList.ItemsSource = KeysToDisplay;
|
||||||
|
|
||||||
RefreshHotkeyInterface(Hotkey);
|
// We should not call RefreshHotkeyInterface here because DependencyProperty is not set yet
|
||||||
|
// And it will be called in OnHotkeyChanged event or Hotkey setter later
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshHotkeyInterface(string hotkey)
|
private void RefreshHotkeyInterface(string hotkey)
|
||||||
{
|
{
|
||||||
SetKeysToDisplay(new HotkeyModel(Hotkey));
|
SetKeysToDisplay(new HotkeyModel(hotkey));
|
||||||
CurrentHotkey = new HotkeyModel(Hotkey);
|
CurrentHotkey = new HotkeyModel(hotkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
|
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture) =>
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,11 @@
|
||||||
<system:String x:Key="AlwaysPreview">Always Preview</system:String>
|
<system:String x:Key="AlwaysPreview">Always Preview</system:String>
|
||||||
<system:String x:Key="AlwaysPreviewToolTip">Always open preview panel when Flow activates. Press {0} to toggle preview.</system:String>
|
<system:String x:Key="AlwaysPreviewToolTip">Always open preview panel when Flow activates. Press {0} to toggle preview.</system:String>
|
||||||
<system:String x:Key="shadowEffectNotAllowed">Shadow effect is not allowed while current theme has blur effect enabled</system:String>
|
<system:String x:Key="shadowEffectNotAllowed">Shadow effect is not allowed while current theme has blur effect enabled</system:String>
|
||||||
|
<system:String x:Key="BackdropType">Backdrop Type</system:String>
|
||||||
|
<system:String x:Key="BackdropTypesNone">None</system:String>
|
||||||
|
<system:String x:Key="BackdropTypesAcrylic">Acrylic</system:String>
|
||||||
|
<system:String x:Key="BackdropTypesMica">Mica</system:String>
|
||||||
|
<system:String x:Key="BackdropTypesMicaAlt">Mica Alt</system:String>
|
||||||
|
|
||||||
<!-- Setting Plugin -->
|
<!-- Setting Plugin -->
|
||||||
<system:String x:Key="searchplugin">Search Plugin</system:String>
|
<system:String x:Key="searchplugin">Search Plugin</system:String>
|
||||||
|
|
@ -342,9 +347,10 @@
|
||||||
<system:String x:Key="cannotFindSpecifiedPlugin">Can't find specified plugin</system:String>
|
<system:String x:Key="cannotFindSpecifiedPlugin">Can't find specified plugin</system:String>
|
||||||
<system:String x:Key="newActionKeywordsCannotBeEmpty">New Action Keyword can't be empty</system:String>
|
<system:String x:Key="newActionKeywordsCannotBeEmpty">New Action Keyword can't be empty</system:String>
|
||||||
<system:String x:Key="newActionKeywordsHasBeenAssigned">This new Action Keyword is already assigned to another plugin, please choose a different one</system:String>
|
<system:String x:Key="newActionKeywordsHasBeenAssigned">This new Action Keyword is already assigned to another plugin, please choose a different one</system:String>
|
||||||
|
<system:String x:Key="newActionKeywordsSameAsOld">This new Action Keyword is the same as old, please choose a different one</system:String>
|
||||||
<system:String x:Key="success">Success</system:String>
|
<system:String x:Key="success">Success</system:String>
|
||||||
<system:String x:Key="completedSuccessfully">Completed successfully</system:String>
|
<system:String x:Key="completedSuccessfully">Completed successfully</system:String>
|
||||||
<system:String x:Key="actionkeyword_tips">Enter the action keyword you like to use to start the plugin. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords.</system:String>
|
<system:String x:Key="actionkeyword_tips">Enter the action keywords you like to use to start the plugin and use whitespace to divide them. Use * if you don't want to specify any, and the plugin will be triggered without any action keywords.</system:String>
|
||||||
|
|
||||||
<!-- Custom Query Hotkey Dialog -->
|
<!-- Custom Query Hotkey Dialog -->
|
||||||
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>
|
<system:String x:Key="customeQueryHotkeyTitle">Custom Query Hotkey</system:String>
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,17 @@
|
||||||
Closing="OnClosing"
|
Closing="OnClosing"
|
||||||
Deactivated="OnDeactivated"
|
Deactivated="OnDeactivated"
|
||||||
Icon="Images/app.png"
|
Icon="Images/app.png"
|
||||||
SourceInitialized="OnSourceInitialized"
|
|
||||||
Initialized="OnInitialized"
|
|
||||||
Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
Left="{Binding Settings.WindowLeft, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
Loaded="OnLoaded"
|
Loaded="OnLoaded"
|
||||||
LocationChanged="OnLocationChanged"
|
LocationChanged="OnLocationChanged"
|
||||||
Opacity="{Binding MainWindowOpacity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
Opacity="{Binding MainWindowOpacity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
PreviewKeyDown="OnKeyDown"
|
PreviewKeyDown="OnKeyDown"
|
||||||
PreviewKeyUp="OnKeyUp"
|
PreviewKeyUp="OnKeyUp"
|
||||||
|
PreviewMouseMove="OnPreviewMouseMove"
|
||||||
ResizeMode="CanResize"
|
ResizeMode="CanResize"
|
||||||
ShowInTaskbar="False"
|
ShowInTaskbar="False"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
|
SourceInitialized="OnSourceInitialized"
|
||||||
Topmost="True"
|
Topmost="True"
|
||||||
Visibility="{Binding MainWindowVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
Visibility="{Binding MainWindowVisibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
WindowStartupLocation="Manual"
|
WindowStartupLocation="Manual"
|
||||||
|
|
@ -240,14 +240,14 @@
|
||||||
FontSize="{Binding QueryBoxFontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
FontSize="{Binding QueryBoxFontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||||
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
|
InputMethod.PreferredImeConversionMode="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEConversionModeConverter}}"
|
||||||
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
|
InputMethod.PreferredImeState="{Binding StartWithEnglishMode, Converter={StaticResource BoolToIMEStateConverter}}"
|
||||||
PreviewDragOver="OnPreviewDragOver"
|
PreviewDragOver="QueryTextBox_OnPreviewDragOver"
|
||||||
PreviewKeyUp="QueryTextBox_KeyUp"
|
PreviewKeyUp="QueryTextBox_KeyUp"
|
||||||
Style="{DynamicResource QueryBoxStyle}"
|
Style="{DynamicResource QueryBoxStyle}"
|
||||||
Text="{Binding QueryText, Mode=OneWay}"
|
Text="{Binding QueryText, Mode=OneWay}"
|
||||||
Visibility="Visible"
|
Visibility="Visible"
|
||||||
WindowChrome.IsHitTestVisibleInChrome="True">
|
WindowChrome.IsHitTestVisibleInChrome="True">
|
||||||
<TextBox.CommandBindings>
|
<TextBox.CommandBindings>
|
||||||
<CommandBinding Command="ApplicationCommands.Copy" Executed="OnCopy" />
|
<CommandBinding Command="ApplicationCommands.Copy" Executed="QueryTextBox_OnCopy" />
|
||||||
</TextBox.CommandBindings>
|
</TextBox.CommandBindings>
|
||||||
<TextBox.ContextMenu>
|
<TextBox.ContextMenu>
|
||||||
<ContextMenu MinWidth="160">
|
<ContextMenu MinWidth="160">
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media.Animation;
|
using System.Windows.Media.Animation;
|
||||||
using Flow.Launcher.Helper;
|
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Image;
|
using Flow.Launcher.Infrastructure.Image;
|
||||||
|
|
||||||
|
|
@ -12,14 +11,14 @@ namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
public partial class Msg : Window
|
public partial class Msg : Window
|
||||||
{
|
{
|
||||||
Storyboard fadeOutStoryboard = new Storyboard();
|
private readonly Storyboard fadeOutStoryboard = new();
|
||||||
private bool closing;
|
private bool closing;
|
||||||
|
|
||||||
public Msg()
|
public Msg()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||||
var dipWorkingArea = WindowsInteropHelper.TransformPixelsToDIP(this,
|
var dipWorkingArea = Win32Helper.TransformPixelsToDIP(this,
|
||||||
screen.WorkingArea.Width,
|
screen.WorkingArea.Width,
|
||||||
screen.WorkingArea.Height);
|
screen.WorkingArea.Height);
|
||||||
Left = dipWorkingArea.X - Width;
|
Left = dipWorkingArea.X - Width;
|
||||||
|
|
@ -82,13 +81,13 @@ namespace Flow.Launcher
|
||||||
Show();
|
Show();
|
||||||
|
|
||||||
await Dispatcher.InvokeAsync(async () =>
|
await Dispatcher.InvokeAsync(async () =>
|
||||||
{
|
{
|
||||||
if (!closing)
|
if (!closing)
|
||||||
{
|
{
|
||||||
closing = true;
|
closing = true;
|
||||||
await Dispatcher.InvokeAsync(fadeOutStoryboard.Begin);
|
await Dispatcher.InvokeAsync(fadeOutStoryboard.Begin);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
DwmSetWindowAttribute
|
|
||||||
DwmExtendFrameIntoClientArea
|
|
||||||
SystemParametersInfo
|
|
||||||
SetForegroundWindow
|
|
||||||
|
|
||||||
GetWindowLong
|
|
||||||
SetWindowLong
|
|
||||||
GetForegroundWindow
|
|
||||||
GetDesktopWindow
|
|
||||||
GetShellWindow
|
|
||||||
GetWindowRect
|
|
||||||
GetClassName
|
|
||||||
FindWindowEx
|
|
||||||
WINDOW_STYLE
|
|
||||||
|
|
||||||
WM_ENTERSIZEMOVE
|
|
||||||
WM_EXITSIZEMOVE
|
|
||||||
|
|
||||||
SetLastError
|
|
||||||
WINDOW_EX_STYLE
|
|
||||||
|
|
@ -1,46 +1,48 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Squirrel;
|
using Squirrel;
|
||||||
|
using Flow.Launcher.Core;
|
||||||
using Flow.Launcher.Core.Plugin;
|
using Flow.Launcher.Core.Plugin;
|
||||||
using Flow.Launcher.Core.Resource;
|
|
||||||
using Flow.Launcher.Helper;
|
using Flow.Launcher.Helper;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
|
using Flow.Launcher.Infrastructure.Http;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
using Flow.Launcher.Infrastructure.Image;
|
using Flow.Launcher.Infrastructure.Image;
|
||||||
using Flow.Launcher.Plugin;
|
|
||||||
using Flow.Launcher.ViewModel;
|
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
|
||||||
using System.Threading;
|
|
||||||
using System.IO;
|
|
||||||
using Flow.Launcher.Infrastructure.Http;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Infrastructure.Storage;
|
using Flow.Launcher.Infrastructure.Storage;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
|
||||||
using Flow.Launcher.Core;
|
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
|
using Flow.Launcher.Plugin;
|
||||||
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
|
using Flow.Launcher.ViewModel;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Flow.Launcher.Core.Resource;
|
||||||
|
|
||||||
namespace Flow.Launcher
|
namespace Flow.Launcher
|
||||||
{
|
{
|
||||||
public class PublicAPIInstance : IPublicAPI
|
public class PublicAPIInstance : IPublicAPI
|
||||||
{
|
{
|
||||||
private readonly Settings _settings;
|
private readonly Settings _settings;
|
||||||
|
private readonly Internationalization _translater;
|
||||||
private readonly MainViewModel _mainVM;
|
private readonly MainViewModel _mainVM;
|
||||||
|
|
||||||
#region Constructor
|
#region Constructor
|
||||||
|
|
||||||
public PublicAPIInstance(Settings settings, MainViewModel mainVM)
|
public PublicAPIInstance(Settings settings, Internationalization translater, MainViewModel mainVM)
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_translater = translater;
|
||||||
_mainVM = mainVM;
|
_mainVM = mainVM;
|
||||||
GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
|
GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback;
|
||||||
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
|
WebRequest.RegisterPrefix("data", new DataWebRequestFactory());
|
||||||
|
|
@ -153,17 +155,17 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
public void StopLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Collapsed;
|
public void StopLoadingBar() => _mainVM.ProgressBarVisibility = Visibility.Collapsed;
|
||||||
|
|
||||||
public string GetTranslation(string key) => InternationalizationManager.Instance.GetTranslation(key);
|
public string GetTranslation(string key) => _translater.GetTranslation(key);
|
||||||
|
|
||||||
public List<PluginPair> GetAllPlugins() => PluginManager.AllPlugins.ToList();
|
public List<PluginPair> GetAllPlugins() => PluginManager.AllPlugins.ToList();
|
||||||
|
|
||||||
public MatchResult FuzzySearch(string query, string stringToCompare) =>
|
public MatchResult FuzzySearch(string query, string stringToCompare) =>
|
||||||
StringMatcher.FuzzySearch(query, stringToCompare);
|
StringMatcher.FuzzySearch(query, stringToCompare);
|
||||||
|
|
||||||
public Task<string> HttpGetStringAsync(string url, CancellationToken token = default) => Http.GetAsync(url);
|
public Task<string> HttpGetStringAsync(string url, CancellationToken token = default) => Http.GetAsync(url, token);
|
||||||
|
|
||||||
public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) =>
|
public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) =>
|
||||||
Http.GetStreamAsync(url);
|
Http.GetStreamAsync(url, token);
|
||||||
|
|
||||||
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
|
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, Action<double> reportProgress = null,
|
||||||
CancellationToken token = default) => Http.DownloadAsync(url, filePath, reportProgress, token);
|
CancellationToken token = default) => Http.DownloadAsync(url, filePath, reportProgress, token);
|
||||||
|
|
@ -329,7 +331,6 @@ namespace Flow.Launcher
|
||||||
return _mainVM.GameModeStatus;
|
return _mainVM.GameModeStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private readonly List<Func<int, int, SpecialKeyState, bool>> _globalKeyboardHandlers = new();
|
private readonly List<Func<int, int, SpecialKeyState, bool>> _globalKeyboardHandlers = new();
|
||||||
|
|
||||||
public void RegisterGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Add(callback);
|
public void RegisterGlobalKeyboardCallback(Func<int, int, SpecialKeyState, bool> callback) => _globalKeyboardHandlers.Add(callback);
|
||||||
|
|
|
||||||
|
|
@ -11,30 +11,33 @@
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Border
|
<Border
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Height="52"
|
Height="Auto"
|
||||||
Margin="0"
|
Margin="0"
|
||||||
Padding="0"
|
Padding="0"
|
||||||
BorderThickness="0 1 0 0"
|
BorderThickness="0 1 0 0"
|
||||||
CornerRadius="0"
|
CornerRadius="0"
|
||||||
Style="{DynamicResource SettingGroupBox}"
|
Style="{DynamicResource SettingGroupBox}"
|
||||||
Visibility="{Binding ActionKeywordsVisibility}">
|
Visibility="{Binding ActionKeywordsVisibility}">
|
||||||
<DockPanel Margin="22 0 18 0" VerticalAlignment="Center">
|
<DockPanel Margin="{StaticResource SettingPanelMargin}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="48 0 10 0"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
DockPanel.Dock="Left"
|
DockPanel.Dock="Left"
|
||||||
Style="{StaticResource Glyph}">
|
Style="{StaticResource Glyph}">
|
||||||

|

|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
DockPanel.Dock="Left"
|
DockPanel.Dock="Left"
|
||||||
Style="{DynamicResource SettingTitleLabel}"
|
Style="{DynamicResource SettingTitleLabel}"
|
||||||
Text="{DynamicResource actionKeywords}" />
|
Text="{DynamicResource actionKeywords}" />
|
||||||
|
<!-- Here Margin="0 -4.5 0 -4.5" is to remove redundant top bottom margin from Margin="{StaticResource SettingPanelMargin}" -->
|
||||||
<Button
|
<Button
|
||||||
Width="100"
|
Width="100"
|
||||||
Height="34"
|
Margin="0 -4.5 0 -4.5"
|
||||||
Margin="5 0 0 0"
|
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Command="{Binding SetActionKeywordsCommand}"
|
Command="{Binding SetActionKeywordsCommand}"
|
||||||
Content="{Binding ActionKeywordsText}"
|
Content="{Binding ActionKeywordsText}"
|
||||||
|
|
|
||||||
|
|
@ -5585,4 +5585,31 @@
|
||||||
</Setter.Value>
|
</Setter.Value>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<!-- Settings Panel -->
|
||||||
|
<Thickness x:Key="SettingPanelMargin">70,13.5,18,13.5</Thickness>
|
||||||
|
|
||||||
|
<Thickness x:Key="SettingPanelItemLeftMargin">9,0,0,0</Thickness>
|
||||||
|
<Thickness x:Key="SettingPanelItemRightMargin">0,0,9,0</Thickness>
|
||||||
|
<Thickness x:Key="SettingPanelItemTopBottomMargin">0,4.5,0,4.5</Thickness>
|
||||||
|
|
||||||
|
<Thickness x:Key="SettingPanelItemLeftTopBottomMargin">9,4.5,0,4.5</Thickness>
|
||||||
|
<Thickness x:Key="SettingPanelItemRightTopBottomMargin">0,4.5,9,4.5</Thickness>
|
||||||
|
|
||||||
|
<Style x:Key="SettingPanelSeparatorStyle" TargetType="Separator">
|
||||||
|
<Setter Property="Margin" Value="-70 13.5 -18 13.5" />
|
||||||
|
<Setter Property="Height" Value="1" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Top" />
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Color03B}" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<system:Double x:Key="SettingPanelTextBoxMinWidth">180</system:Double>
|
||||||
|
<system:Double x:Key="SettingPanelPathTextBoxWidth">240</system:Double>
|
||||||
|
<system:Double x:Key="SettingPanelAreaTextBoxMinHeight">150</system:Double>
|
||||||
|
|
||||||
|
<Style x:Key="SettingPanelTextBlockDescriptionStyle" TargetType="TextBlock">
|
||||||
|
<Setter Property="FontSize" Value="12" />
|
||||||
|
<Setter Property="Margin" Value="0 2 0 0" />
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Color04B}" />
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,17 @@
|
||||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||||
|
|
||||||
<SolidColorBrush x:Key="SystemThemeBorder" Color="#3f3f3f" />
|
<SolidColorBrush x:Key="SystemThemeBorder" Color="#3f3f3f" />
|
||||||
<SolidColorBrush x:Key="QuerySuggestionBoxForeground" Color="#4d4d4d" />
|
<SolidColorBrush x:Key="QuerySuggestionBoxForeground" Color="#33FFFFFF" />
|
||||||
<SolidColorBrush x:Key="QuerySelectionBrush" Color="#4a5459" />
|
<SolidColorBrush x:Key="QuerySelectionBrush" Color="#4a5459" />
|
||||||
<SolidColorBrush x:Key="SubTitleForeground" Color="#7b7b7b" />
|
<SolidColorBrush x:Key="SubTitleForeground" Color="#33FFFFFF" />
|
||||||
<SolidColorBrush x:Key="SubTitleSelectedForeground" Color="#7b7b7b" />
|
<SolidColorBrush x:Key="SubTitleSelectedForeground" Color="#33FFFFFF" />
|
||||||
<SolidColorBrush x:Key="SearchIconForeground" Color="#4d4d4d" />
|
<SolidColorBrush x:Key="SearchIconForeground" Color="#33FFFFFF" />
|
||||||
<SolidColorBrush x:Key="SeparatorForeground" Color="#14ffffff" />
|
<SolidColorBrush x:Key="SeparatorForeground" Color="#24FFFFFF" />
|
||||||
<SolidColorBrush x:Key="ThumbColor" Color="#9a9a9a" />
|
<SolidColorBrush x:Key="ThumbColor" Color="#9a9a9a" />
|
||||||
<SolidColorBrush x:Key="InlineHighlight" Color="#0078d7" />
|
<SolidColorBrush x:Key="InlineHighlight" Color="#0078d7" />
|
||||||
<SolidColorBrush x:Key="HotkeyForeground" Color="#7b7b7b" />
|
<SolidColorBrush x:Key="HotkeyForeground" Color="#33FFFFFF" />
|
||||||
<SolidColorBrush x:Key="HotkeySelectedForeground" Color="#7b7b7b" />
|
<SolidColorBrush x:Key="HotkeySelectedForeground" Color="#33FFFFFF" />
|
||||||
<SolidColorBrush x:Key="ClockDateForeground" Color="#4d4d4d" />
|
<SolidColorBrush x:Key="ClockDateForeground" Color="#26FFFFFF" />
|
||||||
<Color x:Key="ItemSelectedBackgroundColorBrush">#198F8F8F</Color>
|
<Color x:Key="ItemSelectedBackgroundColorBrush">#198F8F8F</Color>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,18 +7,18 @@
|
||||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
||||||
|
|
||||||
<SolidColorBrush x:Key="SystemThemeBorder" Color="#aaaaaa" />
|
<SolidColorBrush x:Key="SystemThemeBorder" Color="#aaaaaa" />
|
||||||
<SolidColorBrush x:Key="QuerySuggestionBoxForeground" Color="#d8d2d0" />
|
<SolidColorBrush x:Key="QuerySuggestionBoxForeground" Color="#51000000" />
|
||||||
<SolidColorBrush x:Key="QuerySelectionBrush" Color="#0a68d8" />
|
<SolidColorBrush x:Key="QuerySelectionBrush" Color="#0a68d8" />
|
||||||
<SolidColorBrush x:Key="SubTitleForeground" Color="#818181" />
|
<SolidColorBrush x:Key="SubTitleForeground" Color="#818181" />
|
||||||
<SolidColorBrush x:Key="SubTitleSelectedForeground" Color="#72767d" />
|
<SolidColorBrush x:Key="SubTitleSelectedForeground" Color="#72767d" />
|
||||||
<SolidColorBrush x:Key="SearchIconForeground" Color="#d3d3d3" />
|
<SolidColorBrush x:Key="SearchIconForeground" Color="#20000000" />
|
||||||
<SolidColorBrush x:Key="SeparatorForeground" Color="#14000000" />
|
<SolidColorBrush x:Key="SeparatorForeground" Color="#20000000" />
|
||||||
<SolidColorBrush x:Key="ThumbColor" Color="#868686" />
|
<SolidColorBrush x:Key="ThumbColor" Color="#868686" />
|
||||||
<SolidColorBrush x:Key="InlineHighlight" Color="#0078d7" />
|
<SolidColorBrush x:Key="InlineHighlight" Color="#0078d7" />
|
||||||
<SolidColorBrush x:Key="HotkeyForeground" Color="#acacac" />
|
<SolidColorBrush x:Key="HotkeyForeground" Color="#51000000" />
|
||||||
<SolidColorBrush x:Key="HotkeySelectedForeground" Color="#acacac" />
|
<SolidColorBrush x:Key="HotkeySelectedForeground" Color="#51000000" />
|
||||||
<SolidColorBrush x:Key="ClockDateForeground" Color="#d3d3d3" />
|
<SolidColorBrush x:Key="ClockDateForeground" Color="#44000000" />
|
||||||
<Color x:Key="ItemSelectedBackgroundColorBrush">#198F8F8F</Color>
|
<Color x:Key="ItemSelectedBackgroundColorBrush">#0C000000</Color>
|
||||||
|
|
||||||
<SolidColorBrush x:Key="Color00B" Color="#fbfbfb" />
|
<SolidColorBrush x:Key="Color00B" Color="#fbfbfb" />
|
||||||
<SolidColorBrush x:Key="Color01B" Color="#f3f3f3" />
|
<SolidColorBrush x:Key="Color01B" Color="#f3f3f3" />
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Flow.Launcher.Core.Resource;
|
using Flow.Launcher.Core.Resource;
|
||||||
using Flow.Launcher.Helper;
|
using Flow.Launcher.Helper;
|
||||||
|
|
@ -13,7 +14,6 @@ using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.ViewModel;
|
using Flow.Launcher.ViewModel;
|
||||||
using ModernWpf;
|
using ModernWpf;
|
||||||
using ThemeManager = Flow.Launcher.Core.Resource.ThemeManager;
|
|
||||||
using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;
|
using ThemeManagerForColorSchemeSwitch = ModernWpf.ThemeManager;
|
||||||
|
|
||||||
namespace Flow.Launcher.SettingPages.ViewModels;
|
namespace Flow.Launcher.SettingPages.ViewModels;
|
||||||
|
|
@ -22,45 +22,68 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
{
|
{
|
||||||
private const string DefaultFont = "Segoe UI";
|
private const string DefaultFont = "Segoe UI";
|
||||||
public Settings Settings { get; }
|
public Settings Settings { get; }
|
||||||
|
private readonly Theme _theme = Ioc.Default.GetRequiredService<Theme>();
|
||||||
|
|
||||||
public static string LinkHowToCreateTheme => @"https://flowlauncher.com/docs/#/how-to-create-a-theme";
|
public static string LinkHowToCreateTheme => @"https://flowlauncher.com/docs/#/how-to-create-a-theme";
|
||||||
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
|
public static string LinkThemeGallery => "https://github.com/Flow-Launcher/Flow.Launcher/discussions/1438";
|
||||||
|
|
||||||
|
private List<Theme.ThemeData> _themes;
|
||||||
|
public List<Theme.ThemeData> Themes => _themes ??= _theme.LoadAvailableThemes();
|
||||||
|
|
||||||
private Theme.ThemeData _selectedTheme;
|
private Theme.ThemeData _selectedTheme;
|
||||||
public Theme.ThemeData SelectedTheme
|
public Theme.ThemeData SelectedTheme
|
||||||
{
|
{
|
||||||
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == Settings.Theme);
|
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme());
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_selectedTheme = value;
|
_selectedTheme = value;
|
||||||
ThemeManager.Instance.ChangeTheme(value.FileNameWithoutExtension);
|
_theme.ChangeTheme(value.FileNameWithoutExtension);
|
||||||
|
|
||||||
if (ThemeManager.Instance.BlurEnabled && Settings.UseDropShadowEffect)
|
// Update UI state
|
||||||
DropShadowEffect = false;
|
OnPropertyChanged(nameof(BackdropType));
|
||||||
|
OnPropertyChanged(nameof(IsBackdropEnabled));
|
||||||
|
OnPropertyChanged(nameof(IsDropShadowEnabled));
|
||||||
|
OnPropertyChanged(nameof(DropShadowEffect));
|
||||||
|
|
||||||
|
_ = _theme.RefreshFrameAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsBackdropEnabled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!Win32Helper.IsBackdropSupported()) return false;
|
||||||
|
return SelectedTheme?.HasBlur ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDropShadowEnabled => !_theme.BlurEnabled;
|
||||||
|
|
||||||
public bool DropShadowEffect
|
public bool DropShadowEffect
|
||||||
{
|
{
|
||||||
get => Settings.UseDropShadowEffect;
|
get => Settings.UseDropShadowEffect;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (ThemeManager.Instance.BlurEnabled && value)
|
if (_theme.BlurEnabled)
|
||||||
{
|
{
|
||||||
App.API.ShowMsgBox(InternationalizationManager.Instance.GetTranslation("shadowEffectNotAllowed"));
|
// Always DropShadowEffect = true with blur theme
|
||||||
|
Settings.UseDropShadowEffect = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// User can change shadow with non-blur theme.
|
||||||
if (value)
|
if (value)
|
||||||
{
|
{
|
||||||
ThemeManager.Instance.AddDropShadowEffectToCurrentTheme();
|
_theme.AddDropShadowEffectToCurrentTheme();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ThemeManager.Instance.RemoveDropShadowEffectFromCurrentTheme();
|
_theme.RemoveDropShadowEffectFromCurrentTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings.UseDropShadowEffect = value;
|
Settings.UseDropShadowEffect = value;
|
||||||
|
OnPropertyChanged(nameof(DropShadowEffect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,12 +117,25 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
set => Settings.ResultSubItemFontSize = value;
|
set => Settings.ResultSubItemFontSize = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Theme.ThemeData> _themes;
|
|
||||||
public List<Theme.ThemeData> Themes => _themes ??= ThemeManager.Instance.LoadAvailableThemes();
|
|
||||||
|
|
||||||
public class ColorSchemeData : DropdownDataGeneric<ColorSchemes> { }
|
public class ColorSchemeData : DropdownDataGeneric<ColorSchemes> { }
|
||||||
|
|
||||||
public List<ColorSchemeData> ColorSchemes { get; } = DropdownDataGeneric<ColorSchemes>.GetValues<ColorSchemeData>("ColorScheme");
|
public List<ColorSchemeData> ColorSchemes { get; } = DropdownDataGeneric<ColorSchemes>.GetValues<ColorSchemeData>("ColorScheme");
|
||||||
|
public string ColorScheme
|
||||||
|
{
|
||||||
|
get => Settings.ColorScheme;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme = value switch
|
||||||
|
{
|
||||||
|
Constant.Light => ApplicationTheme.Light,
|
||||||
|
Constant.Dark => ApplicationTheme.Dark,
|
||||||
|
Constant.System => null,
|
||||||
|
_ => ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme
|
||||||
|
};
|
||||||
|
Settings.ColorScheme = value;
|
||||||
|
_ = _theme.RefreshFrameAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<string> TimeFormatList { get; } = new()
|
public List<string> TimeFormatList { get; } = new()
|
||||||
{
|
{
|
||||||
|
|
@ -174,6 +210,31 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
public class AnimationSpeedData : DropdownDataGeneric<AnimationSpeeds> { }
|
public class AnimationSpeedData : DropdownDataGeneric<AnimationSpeeds> { }
|
||||||
public List<AnimationSpeedData> AnimationSpeeds { get; } = DropdownDataGeneric<AnimationSpeeds>.GetValues<AnimationSpeedData>("AnimationSpeed");
|
public List<AnimationSpeedData> AnimationSpeeds { get; } = DropdownDataGeneric<AnimationSpeeds>.GetValues<AnimationSpeedData>("AnimationSpeed");
|
||||||
|
|
||||||
|
public class BackdropTypeData : DropdownDataGeneric<BackdropTypes> { }
|
||||||
|
|
||||||
|
public List<BackdropTypeData> BackdropTypesList { get; } =
|
||||||
|
DropdownDataGeneric<BackdropTypes>.GetValues<BackdropTypeData>("BackdropTypes");
|
||||||
|
|
||||||
|
public BackdropTypes BackdropType
|
||||||
|
{
|
||||||
|
get => Enum.IsDefined(typeof(BackdropTypes), Settings.BackdropType)
|
||||||
|
? Settings.BackdropType
|
||||||
|
: BackdropTypes.None;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!Enum.IsDefined(typeof(BackdropTypes), value))
|
||||||
|
{
|
||||||
|
value = BackdropTypes.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings.BackdropType = value;
|
||||||
|
|
||||||
|
_ = _theme.SetBlurForWindowAsync();
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(IsDropShadowEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool UseSound
|
public bool UseSound
|
||||||
{
|
{
|
||||||
get => Settings.UseSound;
|
get => Settings.UseSound;
|
||||||
|
|
@ -219,37 +280,37 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
{
|
{
|
||||||
var results = new List<Result>
|
var results = new List<Result>
|
||||||
{
|
{
|
||||||
new Result
|
new()
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
|
Title = App.API.GetTranslation("SampleTitleExplorer"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
|
SubTitle = App.API.GetTranslation("SampleSubTitleExplorer"),
|
||||||
IcoPath = Path.Combine(
|
IcoPath = Path.Combine(
|
||||||
Constant.ProgramDirectory,
|
Constant.ProgramDirectory,
|
||||||
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png"
|
@"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
new Result
|
new()
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
|
Title = App.API.GetTranslation("SampleTitleWebSearch"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
|
SubTitle = App.API.GetTranslation("SampleSubTitleWebSearch"),
|
||||||
IcoPath = Path.Combine(
|
IcoPath = Path.Combine(
|
||||||
Constant.ProgramDirectory,
|
Constant.ProgramDirectory,
|
||||||
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png"
|
@"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
new Result
|
new()
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
|
Title = App.API.GetTranslation("SampleTitleProgram"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProgram"),
|
SubTitle = App.API.GetTranslation("SampleSubTitleProgram"),
|
||||||
IcoPath = Path.Combine(
|
IcoPath = Path.Combine(
|
||||||
Constant.ProgramDirectory,
|
Constant.ProgramDirectory,
|
||||||
@"Plugins\Flow.Launcher.Plugin.Program\Images\program.png"
|
@"Plugins\Flow.Launcher.Plugin.Program\Images\program.png"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
new Result
|
new()
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
|
Title = App.API.GetTranslation("SampleTitleProcessKiller"),
|
||||||
SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
|
SubTitle = App.API.GetTranslation("SampleSubTitleProcessKiller"),
|
||||||
IcoPath = Path.Combine(
|
IcoPath = Path.Combine(
|
||||||
Constant.ProgramDirectory,
|
Constant.ProgramDirectory,
|
||||||
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png"
|
@"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png"
|
||||||
|
|
@ -281,7 +342,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Settings.QueryBoxFont = value.ToString();
|
Settings.QueryBoxFont = value.ToString();
|
||||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
_theme.ChangeTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -303,7 +364,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
Settings.QueryBoxFontStretch = value.Stretch.ToString();
|
Settings.QueryBoxFontStretch = value.Stretch.ToString();
|
||||||
Settings.QueryBoxFontWeight = value.Weight.ToString();
|
Settings.QueryBoxFontWeight = value.Weight.ToString();
|
||||||
Settings.QueryBoxFontStyle = value.Style.ToString();
|
Settings.QueryBoxFontStyle = value.Style.ToString();
|
||||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
_theme.ChangeTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -325,7 +386,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Settings.ResultFont = value.ToString();
|
Settings.ResultFont = value.ToString();
|
||||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
_theme.ChangeTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -347,7 +408,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
Settings.ResultFontStretch = value.Stretch.ToString();
|
Settings.ResultFontStretch = value.Stretch.ToString();
|
||||||
Settings.ResultFontWeight = value.Weight.ToString();
|
Settings.ResultFontWeight = value.Weight.ToString();
|
||||||
Settings.ResultFontStyle = value.Style.ToString();
|
Settings.ResultFontStyle = value.Style.ToString();
|
||||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
_theme.ChangeTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,9 +416,9 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (Fonts.SystemFontFamilies.Count(o =>
|
if (Fonts.SystemFontFamilies.Any(o =>
|
||||||
o.FamilyNames.Values != null &&
|
o.FamilyNames.Values != null &&
|
||||||
o.FamilyNames.Values.Contains(Settings.ResultSubFont)) > 0)
|
o.FamilyNames.Values.Contains(Settings.ResultSubFont)))
|
||||||
{
|
{
|
||||||
var font = new FontFamily(Settings.ResultSubFont);
|
var font = new FontFamily(Settings.ResultSubFont);
|
||||||
return font;
|
return font;
|
||||||
|
|
@ -371,7 +432,7 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
Settings.ResultSubFont = value.ToString();
|
Settings.ResultSubFont = value.ToString();
|
||||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
_theme.ChangeTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,34 +453,23 @@ public partial class SettingsPaneThemeViewModel : BaseModel
|
||||||
Settings.ResultSubFontStretch = value.Stretch.ToString();
|
Settings.ResultSubFontStretch = value.Stretch.ToString();
|
||||||
Settings.ResultSubFontWeight = value.Weight.ToString();
|
Settings.ResultSubFontWeight = value.Weight.ToString();
|
||||||
Settings.ResultSubFontStyle = value.Style.ToString();
|
Settings.ResultSubFontStyle = value.Style.ToString();
|
||||||
ThemeManager.Instance.ChangeTheme(Settings.Theme);
|
_theme.ChangeTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ThemeImage => Constant.QueryTextBoxIconImagePath;
|
public string ThemeImage => Constant.QueryTextBoxIconImagePath;
|
||||||
|
|
||||||
|
public SettingsPaneThemeViewModel(Settings settings)
|
||||||
|
{
|
||||||
|
Settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void OpenThemesFolder()
|
private void OpenThemesFolder()
|
||||||
{
|
{
|
||||||
App.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
|
App.API.OpenDirectory(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateColorScheme()
|
|
||||||
{
|
|
||||||
ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme = Settings.ColorScheme switch
|
|
||||||
{
|
|
||||||
Constant.Light => ApplicationTheme.Light,
|
|
||||||
Constant.Dark => ApplicationTheme.Dark,
|
|
||||||
Constant.System => null,
|
|
||||||
_ => ThemeManagerForColorSchemeSwitch.Current.ApplicationTheme
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public SettingsPaneThemeViewModel(Settings settings)
|
|
||||||
{
|
|
||||||
Settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@
|
||||||
Width="400"
|
Width="400"
|
||||||
Margin="40 30 0 30"
|
Margin="40 30 0 30"
|
||||||
SnapsToDevicePixels="True"
|
SnapsToDevicePixels="True"
|
||||||
Style="{DynamicResource WindowBorderStyle}">
|
Style="{DynamicResource PreviewWindowBorderStyle}">
|
||||||
<Border BorderThickness="0" Style="{DynamicResource WindowRadius}">
|
<Border BorderThickness="0" Style="{DynamicResource WindowRadius}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
|
@ -370,17 +370,6 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
<!-- Drop shadow effect -->
|
|
||||||
<cc:Card
|
|
||||||
Title="{DynamicResource queryWindowShadowEffect}"
|
|
||||||
Margin="0 8 0 0"
|
|
||||||
Icon=""
|
|
||||||
Sub="{DynamicResource shadowEffectCPUUsage}">
|
|
||||||
<ui:ToggleSwitch
|
|
||||||
IsOn="{Binding DropShadowEffect}"
|
|
||||||
OffContent="{DynamicResource disable}"
|
|
||||||
OnContent="{DynamicResource enable}" />
|
|
||||||
</cc:Card>
|
|
||||||
|
|
||||||
<!-- Theme -->
|
<!-- Theme -->
|
||||||
<cc:ExCard
|
<cc:ExCard
|
||||||
|
|
@ -469,12 +458,46 @@
|
||||||
</ListBox.Template>
|
</ListBox.Template>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
</cc:ExCard>
|
</cc:ExCard>
|
||||||
|
|
||||||
|
<cc:CardGroup Margin="0 10 0 0">
|
||||||
|
<!-- Backdrop effect -->
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource BackdropType}"
|
||||||
|
Margin="0 0 0 0"
|
||||||
|
Icon="">
|
||||||
|
<ComboBox
|
||||||
|
MinWidth="160"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
DisplayMemberPath="Display"
|
||||||
|
FontSize="14"
|
||||||
|
IsEnabled="{Binding IsBackdropEnabled}"
|
||||||
|
ItemsSource="{Binding BackdropTypesList}"
|
||||||
|
SelectedValue="{Binding BackdropType, Mode=TwoWay}"
|
||||||
|
SelectedValuePath="Value" />
|
||||||
|
<!-- ✅ 추가 -->
|
||||||
|
</cc:Card>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Drop shadow effect -->
|
||||||
|
<cc:Card
|
||||||
|
Title="{DynamicResource queryWindowShadowEffect}"
|
||||||
|
Margin="0 0 0 0"
|
||||||
|
Icon="">
|
||||||
|
<ui:ToggleSwitch
|
||||||
|
IsEnabled="{Binding IsDropShadowEnabled}"
|
||||||
|
IsOn="{Binding DropShadowEffect}"
|
||||||
|
OffContent="{DynamicResource disable}"
|
||||||
|
OnContent="{DynamicResource enable}" />
|
||||||
|
</cc:Card>
|
||||||
|
</cc:CardGroup>
|
||||||
<cc:HyperLink
|
<cc:HyperLink
|
||||||
Margin="10"
|
Margin="10"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Text="{DynamicResource browserMoreThemes}"
|
Text="{DynamicResource browserMoreThemes}"
|
||||||
Uri="{Binding LinkThemeGallery}" />
|
Uri="{Binding LinkThemeGallery}" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Fixed Height -->
|
<!-- Fixed Height -->
|
||||||
<cc:CardGroup Margin="0 20 0 0">
|
<cc:CardGroup Margin="0 20 0 0">
|
||||||
<cc:Card
|
<cc:Card
|
||||||
|
|
@ -667,9 +690,8 @@
|
||||||
DisplayMemberPath="Display"
|
DisplayMemberPath="Display"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
ItemsSource="{Binding ColorSchemes}"
|
ItemsSource="{Binding ColorSchemes}"
|
||||||
SelectedValue="{Binding Settings.ColorScheme}"
|
SelectedValue="{Binding ColorScheme, Mode=TwoWay}"
|
||||||
SelectedValuePath="Value"
|
SelectedValuePath="Value" />
|
||||||
SelectionChanged="Selector_OnSelectionChanged" />
|
|
||||||
</cc:Card>
|
</cc:Card>
|
||||||
|
|
||||||
<!-- Theme folder -->
|
<!-- Theme folder -->
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Flow.Launcher.SettingPages.ViewModels;
|
using Flow.Launcher.SettingPages.ViewModels;
|
||||||
|
|
@ -23,9 +22,4 @@ public partial class SettingsPaneTheme : Page
|
||||||
|
|
||||||
base.OnNavigatedTo(e);
|
base.OnNavigatedTo(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
_viewModel.UpdateColorScheme();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ using System.Windows.Forms;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Flow.Launcher.Helper;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.SettingPages.Views;
|
using Flow.Launcher.SettingPages.Views;
|
||||||
|
|
@ -92,13 +92,13 @@ public partial class SettingWindow
|
||||||
{
|
{
|
||||||
if (WindowState == WindowState.Maximized)
|
if (WindowState == WindowState.Maximized)
|
||||||
{
|
{
|
||||||
MaximizeButton.Visibility = Visibility.Collapsed;
|
MaximizeButton.Visibility = Visibility.Hidden;
|
||||||
RestoreButton.Visibility = Visibility.Visible;
|
RestoreButton.Visibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaximizeButton.Visibility = Visibility.Visible;
|
MaximizeButton.Visibility = Visibility.Visible;
|
||||||
RestoreButton.Visibility = Visibility.Collapsed;
|
RestoreButton.Visibility = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,8 +143,8 @@ public partial class SettingWindow
|
||||||
private double WindowLeft()
|
private double WindowLeft()
|
||||||
{
|
{
|
||||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
|
var dip1 = Win32Helper.TransformPixelsToDIP(this, screen.WorkingArea.X, 0);
|
||||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
|
var dip2 = Win32Helper.TransformPixelsToDIP(this, screen.WorkingArea.Width, 0);
|
||||||
var left = (dip2.X - ActualWidth) / 2 + dip1.X;
|
var left = (dip2.X - ActualWidth) / 2 + dip1.X;
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
@ -152,8 +152,8 @@ public partial class SettingWindow
|
||||||
private double WindowTop()
|
private double WindowTop()
|
||||||
{
|
{
|
||||||
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
|
||||||
var dip1 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
|
var dip1 = Win32Helper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Y);
|
||||||
var dip2 = WindowsInteropHelper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
|
var dip2 = Win32Helper.TransformPixelsToDIP(this, 0, screen.WorkingArea.Height);
|
||||||
var top = (dip2.Y - ActualHeight) / 2 + dip1.Y - 20;
|
var top = (dip2.Y - ActualHeight) / 2 + dip1.Y - 20;
|
||||||
return top;
|
return top;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="BasePendingLineStyle" TargetType="{x:Type Line}">
|
<Style x:Key="BasePendingLineStyle" TargetType="{x:Type Line}">
|
||||||
<Setter Property="Stroke" Value="Blue" />
|
<Setter Property="Stroke" Value="{StaticResource SystemAccentColorLight1Brush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style x:Key="BaseClockPanelPosition" TargetType="{x:Type Canvas}" />
|
<Style x:Key="BaseClockPanelPosition" TargetType="{x:Type Canvas}" />
|
||||||
|
|
@ -165,29 +165,6 @@
|
||||||
BasedOn="{StaticResource BaseClockPanel}"
|
BasedOn="{StaticResource BaseClockPanel}"
|
||||||
TargetType="{x:Type StackPanel}">
|
TargetType="{x:Type StackPanel}">
|
||||||
<Setter Property="Orientation" Value="Vertical" />
|
<Setter Property="Orientation" Value="Vertical" />
|
||||||
<Setter Property="Visibility" Value="Collapsed" />
|
|
||||||
<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>
|
|
||||||
<Setter Property="Visibility" Value="Visible" />
|
|
||||||
<MultiDataTrigger.EnterActions>
|
|
||||||
<BeginStoryboard>
|
|
||||||
<Storyboard>
|
|
||||||
<DoubleAnimation
|
|
||||||
Storyboard.TargetProperty="Opacity"
|
|
||||||
From="0.0"
|
|
||||||
To="1"
|
|
||||||
Duration="0:0:0.25" />
|
|
||||||
</Storyboard>
|
|
||||||
</BeginStoryboard>
|
|
||||||
</MultiDataTrigger.EnterActions>
|
|
||||||
</MultiDataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
|
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!-- Item Style -->
|
<!-- Item Style -->
|
||||||
|
|
@ -557,6 +534,14 @@
|
||||||
<Setter Property="TextWrapping" Value="Wrap" />
|
<Setter Property="TextWrapping" Value="Wrap" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="PreviewWindowBorderStyle" TargetType="{x:Type Border}">
|
||||||
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
|
<Setter Property="Background" Value="#2F2F2F" />
|
||||||
|
<Setter Property="Padding" Value="0 0 0 0" />
|
||||||
|
<Setter Property="CornerRadius" Value="5" />
|
||||||
|
<Setter Property="UseLayoutRounding" Value="True" />
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
</Style>
|
||||||
<!-- Style for old version themes -->
|
<!-- Style for old version themes -->
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewItemTitleStyle"
|
x:Key="PreviewItemTitleStyle"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
||||||
|
<system:String x:Key="SystemBG">Dark</system:String>
|
||||||
|
<Color x:Key="LightBG">#C7000000</Color>
|
||||||
|
<Color x:Key="DarkBG">#C7000000</Color>
|
||||||
|
|
||||||
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
|
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
|
||||||
<Setter Property="CornerRadius" Value="0" />
|
<Setter Property="CornerRadius" Value="0" />
|
||||||
|
|
@ -139,8 +142,8 @@
|
||||||
BasedOn="{StaticResource BaseSearchIconStyle}"
|
BasedOn="{StaticResource BaseSearchIconStyle}"
|
||||||
TargetType="{x:Type Path}">
|
TargetType="{x:Type Path}">
|
||||||
<Setter Property="Fill" Value="#ffffff" />
|
<Setter Property="Fill" Value="#ffffff" />
|
||||||
<Setter Property="Width" Value="32" />
|
<Setter Property="Width" Value="30" />
|
||||||
<Setter Property="Height" Value="32" />
|
<Setter Property="Height" Value="30" />
|
||||||
<Setter Property="Opacity" Value="0.2" />
|
<Setter Property="Opacity" Value="0.2" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,11 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
||||||
|
<system:String x:Key="SystemBG">Dark</system:String>
|
||||||
|
<Color x:Key="LightBG">#B0000000</Color>
|
||||||
|
<Color x:Key="DarkBG">#B6000000</Color>
|
||||||
|
|
||||||
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
|
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
|
||||||
<Setter Property="CornerRadius" Value="0" />
|
<Setter Property="CornerRadius" Value="0" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -135,8 +138,8 @@
|
||||||
BasedOn="{StaticResource BaseSearchIconStyle}"
|
BasedOn="{StaticResource BaseSearchIconStyle}"
|
||||||
TargetType="{x:Type Path}">
|
TargetType="{x:Type Path}">
|
||||||
<Setter Property="Fill" Value="#ffffff" />
|
<Setter Property="Fill" Value="#ffffff" />
|
||||||
<Setter Property="Width" Value="32" />
|
<Setter Property="Width" Value="30" />
|
||||||
<Setter Property="Height" Value="32" />
|
<Setter Property="Height" Value="30" />
|
||||||
<Setter Property="Opacity" Value="0.5" />
|
<Setter Property="Opacity" Value="0.5" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,24 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
||||||
|
<system:String x:Key="SystemBG">Light</system:String>
|
||||||
|
<Color x:Key="LightBG">#BFFAFAFA</Color>
|
||||||
|
<Color x:Key="DarkBG">#BFFAFAFA</Color>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemGlyph"
|
x:Key="ItemGlyph"
|
||||||
BasedOn="{StaticResource BaseGlyphStyle}"
|
BasedOn="{StaticResource BaseGlyphStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#FF000000" />
|
<Setter Property="Foreground" Value="#FF000000" />
|
||||||
</Style>
|
</Style>
|
||||||
|
<Style x:Key="ItemGlyphSelectedStyle" TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="Foreground" Value="#FF000000" />
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center" />
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||||
|
<Setter Property="Width" Value="25" />
|
||||||
|
<Setter Property="Height" Value="25" />
|
||||||
|
<Setter Property="FontSize" Value="25" />
|
||||||
|
</Style>
|
||||||
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
|
<Style x:Key="WindowRadius" TargetType="{x:Type Border}">
|
||||||
<Setter Property="CornerRadius" Value="0" />
|
<Setter Property="CornerRadius" Value="0" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -33,7 +43,9 @@
|
||||||
<Style
|
<Style
|
||||||
x:Key="QuerySuggestionBoxStyle"
|
x:Key="QuerySuggestionBoxStyle"
|
||||||
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
|
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
|
||||||
TargetType="{x:Type TextBox}" />
|
TargetType="{x:Type TextBox}">
|
||||||
|
<Setter Property="Foreground" Value="#39000000" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
x:Key="WindowBorderStyle"
|
x:Key="WindowBorderStyle"
|
||||||
|
|
@ -76,7 +88,7 @@
|
||||||
x:Key="ItemSubTitleStyle"
|
x:Key="ItemSubTitleStyle"
|
||||||
BasedOn="{StaticResource BaseItemSubTitleStyle}"
|
BasedOn="{StaticResource BaseItemSubTitleStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#818181" />
|
<Setter Property="Foreground" Value="#85000000" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemTitleSelectedStyle"
|
x:Key="ItemTitleSelectedStyle"
|
||||||
|
|
@ -88,18 +100,18 @@
|
||||||
x:Key="ItemSubTitleSelectedStyle"
|
x:Key="ItemSubTitleSelectedStyle"
|
||||||
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
|
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#72767d" />
|
<Setter Property="Foreground" Value="#85000000" />
|
||||||
</Style>
|
</Style>
|
||||||
<SolidColorBrush
|
<SolidColorBrush
|
||||||
x:Key="ItemSelectedBackgroundColor"
|
x:Key="ItemSelectedBackgroundColor"
|
||||||
Opacity="0.5"
|
Opacity="0.6"
|
||||||
Color="#ccd0d4" />
|
Color="#33000000" />
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
x:Key="SeparatorStyle"
|
x:Key="SeparatorStyle"
|
||||||
BasedOn="{StaticResource BaseSeparatorStyle}"
|
BasedOn="{StaticResource BaseSeparatorStyle}"
|
||||||
TargetType="{x:Type Rectangle}">
|
TargetType="{x:Type Rectangle}">
|
||||||
<Setter Property="Fill" Value="#c6c6c6" />
|
<Setter Property="Fill" Value="#22000000" />
|
||||||
<Setter Property="Height" Value="1" />
|
<Setter Property="Height" Value="1" />
|
||||||
<Setter Property="Margin" Value="12 0 12 8" />
|
<Setter Property="Margin" Value="12 0 12 8" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -112,7 +124,7 @@
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||||
<Border
|
<Border
|
||||||
Background="#bebebe"
|
Background="#3C000000"
|
||||||
BorderBrush="Transparent"
|
BorderBrush="Transparent"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
CornerRadius="2"
|
CornerRadius="2"
|
||||||
|
|
@ -132,8 +144,8 @@
|
||||||
BasedOn="{StaticResource BaseSearchIconStyle}"
|
BasedOn="{StaticResource BaseSearchIconStyle}"
|
||||||
TargetType="{x:Type Path}">
|
TargetType="{x:Type Path}">
|
||||||
<Setter Property="Fill" Value="#000000" />
|
<Setter Property="Fill" Value="#000000" />
|
||||||
<Setter Property="Width" Value="32" />
|
<Setter Property="Width" Value="30" />
|
||||||
<Setter Property="Height" Value="32" />
|
<Setter Property="Height" Value="30" />
|
||||||
<Setter Property="Opacity" Value="0.2" />
|
<Setter Property="Opacity" Value="0.2" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<!--
|
<!--
|
||||||
Name: Circle
|
Name: Circle
|
||||||
IsDark: True
|
IsDark: True
|
||||||
HasBlur: False
|
HasBlur: True
|
||||||
-->
|
-->
|
||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
||||||
|
<system:String x:Key="SystemBG">Auto</system:String>
|
||||||
|
<Color x:Key="LightBG">#E5E6E6E6</Color>
|
||||||
|
<Color x:Key="DarkBG">#DF1F1F1F</Color>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemGlyph"
|
x:Key="ItemGlyph"
|
||||||
BasedOn="{StaticResource BaseGlyphStyle}"
|
BasedOn="{StaticResource BaseGlyphStyle}"
|
||||||
|
|
@ -23,7 +27,7 @@
|
||||||
BasedOn="{StaticResource BaseQueryBoxStyle}"
|
BasedOn="{StaticResource BaseQueryBoxStyle}"
|
||||||
TargetType="{x:Type TextBox}">
|
TargetType="{x:Type TextBox}">
|
||||||
<Setter Property="Padding" Value="0 4 50 0" />
|
<Setter Property="Padding" Value="0 4 50 0" />
|
||||||
<Setter Property="Foreground" Value="{m:DynamicColor SystemControlPageTextBaseHighBrush}" />
|
<Setter Property="Foreground" Value="{m:DynamicColor SystemControlHighlightBaseHighBrush}" />
|
||||||
<Setter Property="FontSize" Value="18" />
|
<Setter Property="FontSize" Value="18" />
|
||||||
<Setter Property="Height" Value="38" />
|
<Setter Property="Height" Value="38" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -75,7 +79,7 @@
|
||||||
x:Key="SeparatorStyle"
|
x:Key="SeparatorStyle"
|
||||||
BasedOn="{StaticResource BaseSeparatorStyle}"
|
BasedOn="{StaticResource BaseSeparatorStyle}"
|
||||||
TargetType="{x:Type Rectangle}">
|
TargetType="{x:Type Rectangle}">
|
||||||
<Setter Property="Fill" Value="{m:DynamicColor SystemControlBackgroundChromeMediumBrush}" />
|
<Setter Property="Fill" Value="{DynamicResource SeparatorForeground}" />
|
||||||
<Setter Property="Height" Value="1" />
|
<Setter Property="Height" Value="1" />
|
||||||
<Setter Property="Margin" Value="0 0 0 8" />
|
<Setter Property="Margin" Value="0 0 0 8" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@
|
||||||
<Style
|
<Style
|
||||||
x:Key="WindowBorderStyle"
|
x:Key="WindowBorderStyle"
|
||||||
BasedOn="{StaticResource BaseWindowBorderStyle}"
|
BasedOn="{StaticResource BaseWindowBorderStyle}"
|
||||||
TargetType="{x:Type Border}" />
|
TargetType="{x:Type Border}">
|
||||||
|
<Setter Property="Background" Value="#2F2F2F" />
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
x:Key="WindowStyle"
|
x:Key="WindowStyle"
|
||||||
|
|
@ -89,7 +91,7 @@
|
||||||
TargetType="{x:Type Rectangle}">
|
TargetType="{x:Type Rectangle}">
|
||||||
<Setter Property="Fill" Value="#3b3b3b" />
|
<Setter Property="Fill" Value="#3b3b3b" />
|
||||||
<Setter Property="Height" Value="1" />
|
<Setter Property="Height" Value="1" />
|
||||||
<Setter Property="Margin" Value="8,0,8,8" />
|
<Setter Property="Margin" Value="8 0 8 8" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewBorderStyle"
|
x:Key="PreviewBorderStyle"
|
||||||
|
|
|
||||||
|
|
@ -2,46 +2,45 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
<Thickness x:Key="ResultMargin">0 0 0 0</Thickness>
|
<Thickness x:Key="ResultMargin">0 0 0 4</Thickness>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemGlyph"
|
x:Key="ItemGlyph"
|
||||||
BasedOn="{StaticResource BaseGlyphStyle}"
|
BasedOn="{StaticResource BaseGlyphStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#0e172c" />
|
<Setter Property="Foreground" Value="#ffffff" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="QueryBoxStyle"
|
x:Key="QueryBoxStyle"
|
||||||
BasedOn="{StaticResource BaseQueryBoxStyle}"
|
BasedOn="{StaticResource BaseQueryBoxStyle}"
|
||||||
TargetType="{x:Type TextBox}">
|
TargetType="{x:Type TextBox}">
|
||||||
<Setter Property="Foreground" Value="#0E172C" />
|
<Setter Property="Foreground" Value="#cc1081" />
|
||||||
<Setter Property="CaretBrush" Value="#0E172C" />
|
<Setter Property="CaretBrush" Value="#cc1081" />
|
||||||
<Setter Property="SelectionBrush" Value="#a786df" />
|
<Setter Property="SelectionBrush" Value="#e564b1" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
x:Key="QuerySuggestionBoxStyle"
|
x:Key="QuerySuggestionBoxStyle"
|
||||||
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
|
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
|
||||||
TargetType="{x:Type TextBox}">
|
TargetType="{x:Type TextBox}">
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="#1f1d1f" />
|
||||||
<Setter Property="Foreground" Value="#E9819F" />
|
<Setter Property="Foreground" Value="#71114b" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<Style
|
<Style
|
||||||
x:Key="WindowBorderStyle"
|
x:Key="WindowBorderStyle"
|
||||||
BasedOn="{StaticResource BaseWindowBorderStyle}"
|
BasedOn="{StaticResource BaseWindowBorderStyle}"
|
||||||
TargetType="{x:Type Border}">
|
TargetType="{x:Type Border}">
|
||||||
<Setter Property="CornerRadius" Value="8" />
|
<Setter Property="Background" Value="#1f1d1f" />
|
||||||
<Setter Property="Background" Value="#fec7d7" />
|
<Setter Property="BorderThickness" Value="2" />
|
||||||
<Setter Property="BorderThickness" Value="3" />
|
<Setter Property="BorderBrush" Value="#000000" />
|
||||||
<Setter Property="BorderBrush" Value="#0e172c" />
|
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="SeparatorStyle"
|
x:Key="SeparatorStyle"
|
||||||
BasedOn="{StaticResource BaseSeparatorStyle}"
|
BasedOn="{StaticResource BaseSeparatorStyle}"
|
||||||
TargetType="{x:Type Rectangle}">
|
TargetType="{x:Type Rectangle}">
|
||||||
<Setter Property="Fill" Value="#0e172c" />
|
<Setter Property="Fill" Value="#000000" />
|
||||||
<Setter Property="Height" Value="3" />
|
<Setter Property="Height" Value="1" />
|
||||||
<Setter Property="Margin" Value="0 0 0 0" />
|
<Setter Property="Margin" Value="12 0 12 4" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="WindowStyle"
|
x:Key="WindowStyle"
|
||||||
|
|
@ -51,33 +50,34 @@
|
||||||
x:Key="PendingLineStyle"
|
x:Key="PendingLineStyle"
|
||||||
BasedOn="{StaticResource BasePendingLineStyle}"
|
BasedOn="{StaticResource BasePendingLineStyle}"
|
||||||
TargetType="{x:Type Line}">
|
TargetType="{x:Type Line}">
|
||||||
<Setter Property="Stroke" Value="#a786df" />
|
<Setter Property="Stroke" Value="#cc1081" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemTitleStyle"
|
x:Key="ItemTitleStyle"
|
||||||
BasedOn="{StaticResource BaseItemTitleStyle}"
|
BasedOn="{StaticResource BaseItemTitleStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#0e172c" />
|
<Setter Property="Foreground" Value="#f5f5f5" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemSubTitleStyle"
|
x:Key="ItemSubTitleStyle"
|
||||||
BasedOn="{StaticResource BaseItemSubTitleStyle}"
|
BasedOn="{StaticResource BaseItemSubTitleStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#0e172c" />
|
<Setter Property="Foreground" Value="#c2c2c2" />
|
||||||
|
<Setter Property="Opacity" Value="0.5" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemTitleSelectedStyle"
|
x:Key="ItemTitleSelectedStyle"
|
||||||
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
|
BasedOn="{StaticResource BaseItemTitleSelectedStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#fffffe" />
|
<Setter Property="Foreground" Value="#f5f5f5" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemSubTitleSelectedStyle"
|
x:Key="ItemSubTitleSelectedStyle"
|
||||||
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
|
BasedOn="{StaticResource BaseItemSubTitleSelectedStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#fffffe" />
|
<Setter Property="Foreground" Value="#ed92c9" />
|
||||||
</Style>
|
</Style>
|
||||||
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#0e172c</SolidColorBrush>
|
<SolidColorBrush x:Key="ItemSelectedBackgroundColor">#cc1081</SolidColorBrush>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ThumbStyle"
|
x:Key="ThumbStyle"
|
||||||
BasedOn="{StaticResource BaseThumbStyle}"
|
BasedOn="{StaticResource BaseThumbStyle}"
|
||||||
|
|
@ -86,7 +86,7 @@
|
||||||
<Setter.Value>
|
<Setter.Value>
|
||||||
<ControlTemplate TargetType="{x:Type Thumb}">
|
<ControlTemplate TargetType="{x:Type Thumb}">
|
||||||
<Border
|
<Border
|
||||||
Background="#E9819F"
|
Background="#e564b1"
|
||||||
BorderBrush="Transparent"
|
BorderBrush="Transparent"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
CornerRadius="2"
|
CornerRadius="2"
|
||||||
|
|
@ -109,56 +109,53 @@
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}">
|
<Style x:Key="SearchIconStyle" TargetType="{x:Type Path}">
|
||||||
<Setter Property="Fill" Value="#E9819F" />
|
<Setter Property="Fill" Value="#cc1081" />
|
||||||
<Setter Property="Width" Value="28" />
|
<Setter Property="Width" Value="28" />
|
||||||
<Setter Property="Height" Value="28" />
|
<Setter Property="Height" Value="28" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
<Style x:Key="ItemHotkeyStyle" TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="FontSize" Value="11" />
|
<Setter Property="FontSize" Value="14" />
|
||||||
<Setter Property="Foreground" Value="#E9819F" />
|
<Setter Property="Foreground" Value="#ed92c9" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="ItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}">
|
<Style x:Key="ItemHotkeySelectedStyle" TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="FontSize" Value="11" />
|
<Setter Property="FontSize" Value="14" />
|
||||||
<Setter Property="Foreground" Value="#E9819F" />
|
<Setter Property="Foreground" Value="#ed92c9" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ClockBox"
|
x:Key="ClockBox"
|
||||||
BasedOn="{StaticResource BaseClockBox}"
|
BasedOn="{StaticResource BaseClockBox}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#E9819F" />
|
<Setter Property="Foreground" Value="#71114b" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="DateBox"
|
x:Key="DateBox"
|
||||||
BasedOn="{StaticResource BaseDateBox}"
|
BasedOn="{StaticResource BaseDateBox}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="FontWeight" Value="Bold" />
|
<Setter Property="FontWeight" Value="Bold" />
|
||||||
<Setter Property="Foreground" Value="#E9819F" />
|
<Setter Property="Foreground" Value="#71114b" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewBorderStyle"
|
x:Key="PreviewBorderStyle"
|
||||||
BasedOn="{StaticResource BasePreviewBorderStyle}"
|
BasedOn="{StaticResource BasePreviewBorderStyle}"
|
||||||
TargetType="{x:Type Border}">
|
TargetType="{x:Type Border}">
|
||||||
<Setter Property="Margin" Value="0 0 10 0" />
|
<Setter Property="BorderBrush" Value="#000000" />
|
||||||
<Setter Property="Width" Value="5" />
|
|
||||||
<Setter Property="BorderThickness" Value="3 0 0 0" />
|
|
||||||
<Setter Property="BorderBrush" Value="#0e172c" />
|
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewItemTitleStyle"
|
x:Key="PreviewItemTitleStyle"
|
||||||
BasedOn="{StaticResource BasePreviewItemTitleStyle}"
|
BasedOn="{StaticResource BasePreviewItemTitleStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#0E172C" />
|
<Setter Property="Foreground" Value="#f5f5f5" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewItemSubTitleStyle"
|
x:Key="PreviewItemSubTitleStyle"
|
||||||
BasedOn="{StaticResource BasePreviewItemSubTitleStyle}"
|
BasedOn="{StaticResource BasePreviewItemSubTitleStyle}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#0E172C" />
|
<Setter Property="Foreground" Value="#c2c2c2" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewGlyph"
|
x:Key="PreviewGlyph"
|
||||||
BasedOn="{StaticResource BasePreviewGlyph}"
|
BasedOn="{StaticResource BasePreviewGlyph}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="#0E172C" />
|
<Setter Property="Foreground" Value="#ffffff" />
|
||||||
</Style>
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
x:Key="QueryBoxStyle"
|
x:Key="QueryBoxStyle"
|
||||||
BasedOn="{StaticResource BaseQueryBoxStyle}"
|
BasedOn="{StaticResource BaseQueryBoxStyle}"
|
||||||
TargetType="{x:Type TextBox}">
|
TargetType="{x:Type TextBox}">
|
||||||
<Setter Property="Padding" Value="0,4,50,0" />
|
<Setter Property="Padding" Value="0 4 50 0" />
|
||||||
<Setter Property="CaretBrush" Value="#fa7941" />
|
<Setter Property="CaretBrush" Value="#fa7941" />
|
||||||
<Setter Property="Foreground" Value="#ffffff" />
|
<Setter Property="Foreground" Value="#ffffff" />
|
||||||
<Setter Property="FontSize" Value="18" />
|
<Setter Property="FontSize" Value="18" />
|
||||||
|
|
@ -43,7 +43,7 @@
|
||||||
x:Key="QuerySuggestionBoxStyle"
|
x:Key="QuerySuggestionBoxStyle"
|
||||||
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
|
BasedOn="{StaticResource BaseQuerySuggestionBoxStyle}"
|
||||||
TargetType="{x:Type TextBox}">
|
TargetType="{x:Type TextBox}">
|
||||||
<Setter Property="Padding" Value="0,4,50,0" />
|
<Setter Property="Padding" Value="0 4 50 0" />
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Setter Property="Height" Value="38" />
|
<Setter Property="Height" Value="38" />
|
||||||
<Setter Property="FontSize" Value="18" />
|
<Setter Property="FontSize" Value="18" />
|
||||||
|
|
@ -56,15 +56,7 @@
|
||||||
TargetType="{x:Type Border}">
|
TargetType="{x:Type Border}">
|
||||||
<Setter Property="BorderThickness" Value="0" />
|
<Setter Property="BorderThickness" Value="0" />
|
||||||
<Setter Property="BorderBrush" Value="#e2e2e2" />
|
<Setter Property="BorderBrush" Value="#e2e2e2" />
|
||||||
<Setter Property="Background">
|
<Setter Property="Background" Value="#2e2e2e" />
|
||||||
<Setter.Value>
|
|
||||||
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
|
|
||||||
<GradientStop Offset="0.0" Color="#383838" />
|
|
||||||
<GradientStop Offset="0.9" Color="#2e2e2e" />
|
|
||||||
<GradientStop Offset="1.0" Color="#2e2e2e" />
|
|
||||||
</LinearGradientBrush>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Setter Property="CornerRadius" Value="8" />
|
<Setter Property="CornerRadius" Value="8" />
|
||||||
<Setter Property="UseLayoutRounding" Value="True" />
|
<Setter Property="UseLayoutRounding" Value="True" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
@ -96,7 +88,7 @@
|
||||||
TargetType="{x:Type Rectangle}">
|
TargetType="{x:Type Rectangle}">
|
||||||
<Setter Property="Fill" Value="#3b3b3b" />
|
<Setter Property="Fill" Value="#3b3b3b" />
|
||||||
<Setter Property="Height" Value="1" />
|
<Setter Property="Height" Value="1" />
|
||||||
<Setter Property="Margin" Value="0,0,0,8" />
|
<Setter Property="Margin" Value="0 0 0 8" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style x:Key="HighlightStyle" />
|
<Style x:Key="HighlightStyle" />
|
||||||
<Style
|
<Style
|
||||||
|
|
@ -147,7 +139,7 @@
|
||||||
<Setter Property="Background" Value="Transparent" />
|
<Setter Property="Background" Value="Transparent" />
|
||||||
<Setter Property="Width" Value="32" />
|
<Setter Property="Width" Value="32" />
|
||||||
<Setter Property="Height" Value="32" />
|
<Setter Property="Height" Value="32" />
|
||||||
<Setter Property="Margin" Value="0,8,8,0" />
|
<Setter Property="Margin" Value="0 8 8 0" />
|
||||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
|
@ -174,7 +166,7 @@
|
||||||
x:Key="ClockPanel"
|
x:Key="ClockPanel"
|
||||||
BasedOn="{StaticResource ClockPanel}"
|
BasedOn="{StaticResource ClockPanel}"
|
||||||
TargetType="{x:Type StackPanel}">
|
TargetType="{x:Type StackPanel}">
|
||||||
<Setter Property="Margin" Value="0,0,54,2" />
|
<Setter Property="Margin" Value="0 0 54 2" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ClockBox"
|
x:Key="ClockBox"
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<system:Boolean x:Key="ThemeBlurEnabled">False</system:Boolean>
|
||||||
|
<system:String x:Key="SystemBG">Auto</system:String>
|
||||||
|
<Color x:Key="LightBG">#FFFAFAFA</Color>
|
||||||
|
<Color x:Key="DarkBG">#FF202020</Color>
|
||||||
<Thickness x:Key="ResultMargin">0 0 0 8</Thickness>
|
<Thickness x:Key="ResultMargin">0 0 0 8</Thickness>
|
||||||
<Style
|
<Style
|
||||||
x:Key="ItemGlyph"
|
x:Key="ItemGlyph"
|
||||||
|
|
@ -175,13 +179,13 @@
|
||||||
x:Key="ClockBox"
|
x:Key="ClockBox"
|
||||||
BasedOn="{StaticResource BaseClockBox}"
|
BasedOn="{StaticResource BaseClockBox}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ClockDateForeground}" />
|
<Setter Property="Foreground" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="DateBox"
|
x:Key="DateBox"
|
||||||
BasedOn="{StaticResource BaseDateBox}"
|
BasedOn="{StaticResource BaseDateBox}"
|
||||||
TargetType="{x:Type TextBlock}">
|
TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource ClockDateForeground}" />
|
<Setter Property="Foreground" Value="{DynamicResource SystemControlBackgroundBaseLowBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
<Style
|
<Style
|
||||||
x:Key="PreviewBorderStyle"
|
x:Key="PreviewBorderStyle"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<!--
|
<!--
|
||||||
Name: Windows 11
|
Name: Windows 11
|
||||||
IsDark: True
|
IsDark: True
|
||||||
HasBlur: False
|
HasBlur: True
|
||||||
-->
|
-->
|
||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
|
@ -12,6 +12,10 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
<ResourceDictionary Source="pack://application:,,,/Themes/Base.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<system:Boolean x:Key="ThemeBlurEnabled">True</system:Boolean>
|
||||||
|
<system:String x:Key="SystemBG">Auto</system:String>
|
||||||
|
<Color x:Key="LightBG">#BFFAFAFA</Color>
|
||||||
|
<Color x:Key="DarkBG">#DD202020</Color>
|
||||||
<Style
|
<Style
|
||||||
x:Key="BulletStyle"
|
x:Key="BulletStyle"
|
||||||
BasedOn="{StaticResource BaseBulletStyle}"
|
BasedOn="{StaticResource BaseBulletStyle}"
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,29 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Input;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
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;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
|
using Flow.Launcher.Infrastructure.Image;
|
||||||
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Infrastructure.Storage;
|
using Flow.Launcher.Infrastructure.Storage;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
using Flow.Launcher.Storage;
|
using Flow.Launcher.Storage;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
|
||||||
using Microsoft.VisualStudio.Threading;
|
using Microsoft.VisualStudio.Threading;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Channels;
|
|
||||||
using ISavable = Flow.Launcher.Plugin.ISavable;
|
|
||||||
using CommunityToolkit.Mvvm.Input;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using Flow.Launcher.Infrastructure.Image;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.ViewModel
|
namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
|
|
@ -48,8 +46,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
private CancellationTokenSource _updateSource;
|
private CancellationTokenSource _updateSource;
|
||||||
private CancellationToken _updateToken;
|
private CancellationToken _updateToken;
|
||||||
|
|
||||||
private readonly Internationalization _translator = InternationalizationManager.Instance;
|
|
||||||
|
|
||||||
private ChannelWriter<ResultsForUpdate> _resultsUpdateChannelWriter;
|
private ChannelWriter<ResultsForUpdate> _resultsUpdateChannelWriter;
|
||||||
private Task _resultsViewUpdateTask;
|
private Task _resultsViewUpdateTask;
|
||||||
|
|
||||||
|
|
@ -141,7 +137,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
_userSelectedRecord = _userSelectedRecordStorage.Load();
|
_userSelectedRecord = _userSelectedRecordStorage.Load();
|
||||||
_topMostRecord = _topMostRecordStorage.Load();
|
_topMostRecord = _topMostRecordStorage.Load();
|
||||||
|
|
||||||
|
|
||||||
ContextMenu = new ResultsViewModel(Settings)
|
ContextMenu = new ResultsViewModel(Settings)
|
||||||
{
|
{
|
||||||
LeftClickResultCommand = OpenResultCommand,
|
LeftClickResultCommand = OpenResultCommand,
|
||||||
|
|
@ -182,9 +177,9 @@ namespace Flow.Launcher.ViewModel
|
||||||
var resultUpdateChannel = Channel.CreateUnbounded<ResultsForUpdate>();
|
var resultUpdateChannel = Channel.CreateUnbounded<ResultsForUpdate>();
|
||||||
_resultsUpdateChannelWriter = resultUpdateChannel.Writer;
|
_resultsUpdateChannelWriter = resultUpdateChannel.Writer;
|
||||||
_resultsViewUpdateTask =
|
_resultsViewUpdateTask =
|
||||||
Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted);
|
Task.Run(UpdateActionAsync).ContinueWith(continueAction, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
|
||||||
|
|
||||||
async Task updateAction()
|
async Task UpdateActionAsync()
|
||||||
{
|
{
|
||||||
var queue = new Dictionary<string, ResultsForUpdate>();
|
var queue = new Dictionary<string, ResultsForUpdate>();
|
||||||
var channelReader = resultUpdateChannel.Reader;
|
var channelReader = resultUpdateChannel.Reader;
|
||||||
|
|
@ -213,7 +208,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
#else
|
#else
|
||||||
Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}");
|
Log.Error($"Error happen in task dealing with viewupdate for results. {t.Exception}");
|
||||||
_resultsViewUpdateTask =
|
_resultsViewUpdateTask =
|
||||||
Task.Run(updateAction).ContinueWith(continueAction, TaskContinuationOptions.OnlyOnFaulted);
|
Task.Run(UpdateActionAsync).ContinueWith(continueAction, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -245,14 +240,27 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, CultureInfo.CurrentCulture);
|
||||||
|
if (Settings.UseDate)
|
||||||
|
DateText = DateTime.Now.ToString(Settings.DateFormat, CultureInfo.CurrentCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task ReloadPluginDataAsync()
|
private async Task ReloadPluginDataAsync()
|
||||||
{
|
{
|
||||||
Hide();
|
Hide();
|
||||||
|
|
||||||
await PluginManager.ReloadDataAsync().ConfigureAwait(false);
|
await PluginManager.ReloadDataAsync().ConfigureAwait(false);
|
||||||
Notification.Show(InternationalizationManager.Instance.GetTranslation("success"),
|
Notification.Show(App.API.GetTranslation("success"),
|
||||||
InternationalizationManager.Instance.GetTranslation("completedSuccessfully"));
|
App.API.GetTranslation("completedSuccessfully"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|
@ -274,14 +282,14 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (SelectedIsFromQueryResults())
|
||||||
{
|
{
|
||||||
QueryResults(null, isReQuery: true);
|
_ = QueryResultsAsync(null, isReQuery: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReQuery(bool reselect)
|
public void ReQuery(bool reselect)
|
||||||
{
|
{
|
||||||
BackToQueryResults();
|
BackToQueryResults();
|
||||||
QueryResults(null, isReQuery: true, reSelect: reselect);
|
_ = QueryResultsAsync(null, isReQuery: true, reSelect: reselect);
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|
@ -289,7 +297,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
if (_history.Items.Count > 0)
|
if (_history.Items.Count > 0)
|
||||||
{
|
{
|
||||||
ChangeQueryText(_history.Items[_history.Items.Count - lastHistoryIndex].Query.ToString());
|
ChangeQueryText(_history.Items[^lastHistoryIndex].Query.ToString());
|
||||||
if (lastHistoryIndex < _history.Items.Count)
|
if (lastHistoryIndex < _history.Items.Count)
|
||||||
{
|
{
|
||||||
lastHistoryIndex++;
|
lastHistoryIndex++;
|
||||||
|
|
@ -302,7 +310,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
if (_history.Items.Count > 0)
|
if (_history.Items.Count > 0)
|
||||||
{
|
{
|
||||||
ChangeQueryText(_history.Items[_history.Items.Count - lastHistoryIndex].Query.ToString());
|
ChangeQueryText(_history.Items[^lastHistoryIndex].Query.ToString());
|
||||||
if (lastHistoryIndex > 1)
|
if (lastHistoryIndex > 1)
|
||||||
{
|
{
|
||||||
lastHistoryIndex--;
|
lastHistoryIndex--;
|
||||||
|
|
@ -353,12 +361,12 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(SelectedResults.SelectedItem?.QuerySuggestionText))
|
else if (!string.IsNullOrEmpty(SelectedResults.SelectedItem?.QuerySuggestionText))
|
||||||
{
|
{
|
||||||
var defaultSuggestion = SelectedResults.SelectedItem.QuerySuggestionText;
|
//var defaultSuggestion = SelectedResults.SelectedItem.QuerySuggestionText;
|
||||||
// check if result.actionkeywordassigned is empty
|
//// check if result.actionkeywordassigned is empty
|
||||||
if (!string.IsNullOrEmpty(result.ActionKeywordAssigned))
|
//if (!string.IsNullOrEmpty(result.ActionKeywordAssigned))
|
||||||
{
|
//{
|
||||||
autoCompleteText = $"{result.ActionKeywordAssigned} {defaultSuggestion}";
|
// autoCompleteText = $"{result.ActionKeywordAssigned} {defaultSuggestion}";
|
||||||
}
|
//}
|
||||||
|
|
||||||
autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText;
|
autoCompleteText = SelectedResults.SelectedItem.QuerySuggestionText;
|
||||||
}
|
}
|
||||||
|
|
@ -389,11 +397,11 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
var hideWindow = await result.ExecuteAsync(new ActionContext
|
var hideWindow = await result.ExecuteAsync(new ActionContext
|
||||||
{
|
{
|
||||||
// not null means pressing modifier key + number, should ignore the modifier key
|
// not null means pressing modifier key + number, should ignore the modifier key
|
||||||
SpecialKeyState = index is not null ? SpecialKeyState.Default : GlobalHotkey.CheckModifiers()
|
SpecialKeyState = index is not null ? SpecialKeyState.Default : GlobalHotkey.CheckModifiers()
|
||||||
})
|
})
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
if (SelectedIsFromQueryResults())
|
if (SelectedIsFromQueryResults())
|
||||||
{
|
{
|
||||||
|
|
@ -457,7 +465,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
SelectedResults.SelectLastResult();
|
SelectedResults.SelectLastResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void SelectPrevPage()
|
private void SelectPrevPage()
|
||||||
{
|
{
|
||||||
|
|
@ -484,7 +491,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
SelectedResults.SelectPrevResult();
|
SelectedResults.SelectPrevResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
|
|
@ -539,19 +545,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
public string ClockText { get; private set; }
|
public string ClockText { get; private set; }
|
||||||
public string DateText { 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, CultureInfo.CurrentCulture);
|
|
||||||
if (Settings.UseDate)
|
|
||||||
DateText = DateTime.Now.ToString(Settings.DateFormat, CultureInfo.CurrentCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResultsViewModel Results { get; private set; }
|
public ResultsViewModel Results { get; private set; }
|
||||||
|
|
||||||
public ResultsViewModel ContextMenu { get; private set; }
|
public ResultsViewModel ContextMenu { get; private set; }
|
||||||
|
|
@ -561,7 +554,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
public bool GameModeStatus { get; set; } = false;
|
public bool GameModeStatus { get; set; } = false;
|
||||||
|
|
||||||
private string _queryText;
|
private string _queryText;
|
||||||
|
|
||||||
public string QueryText
|
public string QueryText
|
||||||
{
|
{
|
||||||
get => _queryText;
|
get => _queryText;
|
||||||
|
|
@ -683,7 +675,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
Results.Visibility = Visibility.Collapsed;
|
Results.Visibility = Visibility.Collapsed;
|
||||||
_queryTextBeforeLeaveResults = QueryText;
|
_queryTextBeforeLeaveResults = QueryText;
|
||||||
|
|
||||||
|
|
||||||
// Because of Fody's optimization
|
// Because of Fody's optimization
|
||||||
// setter won't be called when property value is not changed.
|
// setter won't be called when property value is not changed.
|
||||||
// so we need manually call Query()
|
// so we need manually call Query()
|
||||||
|
|
@ -761,7 +752,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
public string OpenResultCommandModifiers => Settings.OpenResultModifiers;
|
public string OpenResultCommandModifiers => Settings.OpenResultModifiers;
|
||||||
|
|
||||||
public string VerifyOrSetDefaultHotkey(string hotkey, string defaultHotkey)
|
private static string VerifyOrSetDefaultHotkey(string hotkey, string defaultHotkey)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -790,9 +781,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
public string CycleHistoryUpHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryUpHotkey, "Alt+Up");
|
public string CycleHistoryUpHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryUpHotkey, "Alt+Up");
|
||||||
public string CycleHistoryDownHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryDownHotkey, "Alt+Down");
|
public string CycleHistoryDownHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryDownHotkey, "Alt+Down");
|
||||||
|
|
||||||
|
|
||||||
public string Image => Constant.QueryTextBoxIconImagePath;
|
|
||||||
|
|
||||||
public bool StartWithEnglishMode => Settings.AlwaysStartEn;
|
public bool StartWithEnglishMode => Settings.AlwaysStartEn;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
@ -812,8 +800,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
throw new NotImplementedException("ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value");
|
throw new NotImplementedException("ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value");
|
||||||
#else
|
#else
|
||||||
Log.Error("MainViewModel", "ResultAreaColumnPreviewHidden/ResultAreaColumnPreviewShown int value not implemented", "InternalPreviewVisible");
|
Log.Error("MainViewModel", "ResultAreaColumnPreviewHidden/ResultAreaColumnPreviewShown int value not implemented", "InternalPreviewVisible");
|
||||||
#endif
|
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -877,18 +865,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleInternalPreview()
|
|
||||||
{
|
|
||||||
if (!InternalPreviewVisible)
|
|
||||||
{
|
|
||||||
ShowInternalPreview();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
HideInternalPreview();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OpenExternalPreview(string path, bool sendFailToast = true)
|
private void OpenExternalPreview(string path, bool sendFailToast = true)
|
||||||
{
|
{
|
||||||
_ = PluginManager.OpenExternalPreviewAsync(path, sendFailToast).ConfigureAwait(false);
|
_ = PluginManager.OpenExternalPreviewAsync(path, sendFailToast).ConfigureAwait(false);
|
||||||
|
|
@ -901,7 +877,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
ExternalPreviewVisible = false;
|
ExternalPreviewVisible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SwitchExternalPreview(string path, bool sendFailToast = true)
|
private static void SwitchExternalPreview(string path, bool sendFailToast = true)
|
||||||
{
|
{
|
||||||
_ = PluginManager.SwitchExternalPreviewAsync(path,sendFailToast).ConfigureAwait(false);
|
_ = PluginManager.SwitchExternalPreviewAsync(path,sendFailToast).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
@ -983,7 +959,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
if (SelectedIsFromQueryResults())
|
if (SelectedIsFromQueryResults())
|
||||||
{
|
{
|
||||||
QueryResults(searchDelay, isReQuery);
|
_ = QueryResultsAsync(searchDelay, isReQuery);
|
||||||
}
|
}
|
||||||
else if (ContextMenuSelected())
|
else if (ContextMenuSelected())
|
||||||
{
|
{
|
||||||
|
|
@ -1054,8 +1030,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
var results = new List<Result>();
|
var results = new List<Result>();
|
||||||
foreach (var h in _history.Items)
|
foreach (var h in _history.Items)
|
||||||
{
|
{
|
||||||
var title = _translator.GetTranslation("executeQuery");
|
var title = App.API.GetTranslation("executeQuery");
|
||||||
var time = _translator.GetTranslation("lastExecuteTime");
|
var time = App.API.GetTranslation("lastExecuteTime");
|
||||||
var result = new Result
|
var result = new Result
|
||||||
{
|
{
|
||||||
Title = string.Format(title, h.Query),
|
Title = string.Format(title, h.Query),
|
||||||
|
|
@ -1088,8 +1064,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
private readonly IReadOnlyList<Result> _emptyResult = new List<Result>();
|
||||||
|
|
||||||
private async void QueryResults(int? searchDelay, bool isReQuery = false, bool reSelect = true)
|
private async Task QueryResultsAsync(int? searchDelay, bool isReQuery = false, bool reSelect = true)
|
||||||
{
|
{
|
||||||
System.Diagnostics.Debug.WriteLine("!!!QueryResults");
|
System.Diagnostics.Debug.WriteLine("!!!QueryResults");
|
||||||
|
|
||||||
|
|
@ -1111,8 +1087,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
|
|
||||||
var currentUpdateSource = new CancellationTokenSource();
|
var currentUpdateSource = new CancellationTokenSource();
|
||||||
_updateSource = currentUpdateSource;
|
_updateSource = currentUpdateSource;
|
||||||
var currentCancellationToken = _updateSource.Token;
|
_updateToken = _updateSource.Token;
|
||||||
_updateToken = currentCancellationToken;
|
|
||||||
|
|
||||||
ProgressBarVisibility = Visibility.Hidden;
|
ProgressBarVisibility = Visibility.Hidden;
|
||||||
_isQueryRunning = true;
|
_isQueryRunning = true;
|
||||||
|
|
@ -1120,7 +1095,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
// Switch to ThreadPool thread
|
// Switch to ThreadPool thread
|
||||||
await TaskScheduler.Default;
|
await TaskScheduler.Default;
|
||||||
|
|
||||||
if (currentCancellationToken.IsCancellationRequested)
|
if (_updateSource.Token.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Update the query's IsReQuery property to true if this is a re-query
|
// Update the query's IsReQuery property to true if this is a re-query
|
||||||
|
|
@ -1146,24 +1121,23 @@ namespace Flow.Launcher.ViewModel
|
||||||
SearchIconVisibility = Visibility.Visible;
|
SearchIconVisibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign)
|
if (query.ActionKeyword == Plugin.Query.GlobalPluginWildcardSign)
|
||||||
{
|
{
|
||||||
// Wait 45 millisecond for query change in global query
|
// Wait 45 millisecond for query change in global query
|
||||||
// if query changes, return so that it won't be calculated
|
// if query changes, return so that it won't be calculated
|
||||||
await Task.Delay(45, currentCancellationToken);
|
await Task.Delay(45, _updateSource.Token);
|
||||||
if (currentCancellationToken.IsCancellationRequested)
|
if (_updateSource.Token.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = Task.Delay(200, currentCancellationToken).ContinueWith(_ =>
|
_ = Task.Delay(200, _updateSource.Token).ContinueWith(_ =>
|
||||||
{
|
{
|
||||||
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
|
// start the progress bar if query takes more than 200 ms and this is the current running query and it didn't finish yet
|
||||||
if (!currentCancellationToken.IsCancellationRequested && _isQueryRunning)
|
if (!_updateSource.Token.IsCancellationRequested && _isQueryRunning)
|
||||||
{
|
{
|
||||||
ProgressBarVisibility = Visibility.Visible;
|
ProgressBarVisibility = Visibility.Visible;
|
||||||
}
|
}
|
||||||
}, currentCancellationToken, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default);
|
}, _updateSource.Token, TaskContinuationOptions.NotOnCanceled, TaskScheduler.Default);
|
||||||
|
|
||||||
// plugins is ICollection, meaning LINQ will get the Count and preallocate Array
|
// plugins is ICollection, meaning LINQ will get the Count and preallocate Array
|
||||||
|
|
||||||
|
|
@ -1207,7 +1181,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
System.Diagnostics.Debug.Write("\n");
|
System.Diagnostics.Debug.Write("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
|
// Check the code, WhenAll will translate all type of IEnumerable or Collection to Array, so make an array at first
|
||||||
|
|
@ -1218,29 +1192,29 @@ namespace Flow.Launcher.ViewModel
|
||||||
// nothing to do here
|
// nothing to do here
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentCancellationToken.IsCancellationRequested)
|
if (_updateSource.Token.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// this should happen once after all queries are done so progress bar should continue
|
// this should happen once after all queries are done so progress bar should continue
|
||||||
// until the end of all querying
|
// until the end of all querying
|
||||||
_isQueryRunning = false;
|
_isQueryRunning = false;
|
||||||
if (!currentCancellationToken.IsCancellationRequested)
|
if (!_updateSource.Token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
// update to hidden if this is still the current query
|
// update to hidden if this is still the current query
|
||||||
ProgressBarVisibility = Visibility.Hidden;
|
ProgressBarVisibility = Visibility.Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Local function
|
// Local function
|
||||||
async Task QueryTask(PluginPair plugin, bool reSelect = true)
|
async Task QueryTaskAsync(PluginPair plugin, bool reSelect = true)
|
||||||
{
|
{
|
||||||
// Since it is wrapped within a ThreadPool Thread, the synchronous context is null
|
// Since it is wrapped within a ThreadPool Thread, the synchronous context is null
|
||||||
// Task.Yield will force it to run in ThreadPool
|
// Task.Yield will force it to run in ThreadPool
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
|
|
||||||
IReadOnlyList<Result> results =
|
IReadOnlyList<Result> results =
|
||||||
await PluginManager.QueryForPluginAsync(plugin, query, currentCancellationToken);
|
await PluginManager.QueryForPluginAsync(plugin, query, _updateSource.Token);
|
||||||
|
|
||||||
currentCancellationToken.ThrowIfCancellationRequested();
|
_updateSource.Token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
IReadOnlyList<Result> resultsCopy;
|
IReadOnlyList<Result> resultsCopy;
|
||||||
if (results == null)
|
if (results == null)
|
||||||
|
|
@ -1254,7 +1228,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query,
|
if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, plugin.Metadata, query,
|
||||||
currentCancellationToken, reSelect)))
|
_updateSource.Token, reSelect)))
|
||||||
{
|
{
|
||||||
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
Log.Error("MainViewModel", "Unable to add item to Result Update Queue");
|
||||||
}
|
}
|
||||||
|
|
@ -1330,13 +1304,13 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
menu = new Result
|
menu = new Result
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("cancelTopMostInThisQuery"),
|
Title = App.API.GetTranslation("cancelTopMostInThisQuery"),
|
||||||
IcoPath = "Images\\down.png",
|
IcoPath = "Images\\down.png",
|
||||||
PluginDirectory = Constant.ProgramDirectory,
|
PluginDirectory = Constant.ProgramDirectory,
|
||||||
Action = _ =>
|
Action = _ =>
|
||||||
{
|
{
|
||||||
_topMostRecord.Remove(result);
|
_topMostRecord.Remove(result);
|
||||||
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
|
App.API.ShowMsg(App.API.GetTranslation("success"));
|
||||||
App.API.ReQuery();
|
App.API.ReQuery();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1346,14 +1320,14 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
menu = new Result
|
menu = new Result
|
||||||
{
|
{
|
||||||
Title = InternationalizationManager.Instance.GetTranslation("setAsTopMostInThisQuery"),
|
Title = App.API.GetTranslation("setAsTopMostInThisQuery"),
|
||||||
IcoPath = "Images\\up.png",
|
IcoPath = "Images\\up.png",
|
||||||
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xeac2"),
|
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xeac2"),
|
||||||
PluginDirectory = Constant.ProgramDirectory,
|
PluginDirectory = Constant.ProgramDirectory,
|
||||||
Action = _ =>
|
Action = _ =>
|
||||||
{
|
{
|
||||||
_topMostRecord.AddOrUpdate(result);
|
_topMostRecord.AddOrUpdate(result);
|
||||||
App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
|
App.API.ShowMsg(App.API.GetTranslation("success"));
|
||||||
App.API.ReQuery();
|
App.API.ReQuery();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1363,10 +1337,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result ContextMenuPluginInfo(string id)
|
private static Result ContextMenuPluginInfo(string id)
|
||||||
{
|
{
|
||||||
var metadata = PluginManager.GetPluginForId(id).Metadata;
|
var metadata = PluginManager.GetPluginForId(id).Metadata;
|
||||||
var translator = InternationalizationManager.Instance;
|
var translator = App.API;
|
||||||
|
|
||||||
var author = translator.GetTranslation("author");
|
var author = translator.GetTranslation("author");
|
||||||
var website = translator.GetTranslation("website");
|
var website = translator.GetTranslation("website");
|
||||||
|
|
@ -1429,70 +1403,108 @@ namespace Flow.Launcher.ViewModel
|
||||||
{
|
{
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
if (Application.Current.MainWindow is MainWindow mainWindow)
|
||||||
|
{
|
||||||
|
// 📌 Remove DWM Cloak (Make the window visible normally)
|
||||||
|
Win32Helper.DWMSetCloakForWindow(mainWindow, false);
|
||||||
|
|
||||||
|
// 📌 Restore UI elements
|
||||||
|
mainWindow.ClockPanel.Visibility = Visibility.Visible;
|
||||||
|
//mainWindow.SearchIcon.Visibility = Visibility.Visible;
|
||||||
|
SearchIconVisibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update WPF properties
|
||||||
MainWindowVisibility = Visibility.Visible;
|
MainWindowVisibility = Visibility.Visible;
|
||||||
|
|
||||||
MainWindowOpacity = 1;
|
MainWindowOpacity = 1;
|
||||||
|
|
||||||
MainWindowVisibilityStatus = true;
|
MainWindowVisibilityStatus = true;
|
||||||
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true });
|
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning disable VSTHRD100 // Avoid async void methods
|
||||||
|
|
||||||
public async void Hide()
|
public async void Hide()
|
||||||
{
|
{
|
||||||
lastHistoryIndex = 1;
|
lastHistoryIndex = 1;
|
||||||
// Trick for no delay
|
|
||||||
MainWindowOpacity = 0;
|
|
||||||
|
|
||||||
if (ExternalPreviewVisible)
|
if (ExternalPreviewVisible)
|
||||||
|
{
|
||||||
CloseExternalPreview();
|
CloseExternalPreview();
|
||||||
|
}
|
||||||
|
|
||||||
if (!SelectedIsFromQueryResults())
|
if (!SelectedIsFromQueryResults())
|
||||||
{
|
{
|
||||||
SelectedResults = Results;
|
SelectedResults = Results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 📌 Immediately apply text reset + force UI update
|
||||||
|
if (Settings.LastQueryMode == LastQueryMode.Empty)
|
||||||
|
{
|
||||||
|
ChangeQueryText(string.Empty);
|
||||||
|
await Task.Delay(1); // Wait for one frame to ensure UI reflects changes
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
Application.Current.MainWindow.UpdateLayout(); // Force UI update
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
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:
|
case LastQueryMode.Preserved:
|
||||||
if (Settings.UseAnimation)
|
|
||||||
await Task.Delay(100);
|
|
||||||
LastQuerySelected = true;
|
|
||||||
break;
|
|
||||||
case LastQueryMode.Selected:
|
case LastQueryMode.Selected:
|
||||||
if (Settings.UseAnimation)
|
LastQuerySelected = (Settings.LastQueryMode == LastQueryMode.Preserved);
|
||||||
await Task.Delay(100);
|
|
||||||
LastQuerySelected = false;
|
|
||||||
break;
|
break;
|
||||||
case LastQueryMode.ActionKeywordPreserved or LastQueryMode.ActionKeywordSelected:
|
|
||||||
|
case LastQueryMode.ActionKeywordPreserved:
|
||||||
|
case LastQueryMode.ActionKeywordSelected:
|
||||||
var newQuery = _lastQuery.ActionKeyword;
|
var newQuery = _lastQuery.ActionKeyword;
|
||||||
if (!string.IsNullOrEmpty(newQuery))
|
if (!string.IsNullOrEmpty(newQuery))
|
||||||
newQuery += " ";
|
newQuery += " ";
|
||||||
ChangeQueryText(newQuery);
|
ChangeQueryText(newQuery);
|
||||||
if (Settings.UseAnimation)
|
|
||||||
await Task.Delay(100);
|
|
||||||
if (Settings.LastQueryMode == LastQueryMode.ActionKeywordSelected)
|
if (Settings.LastQueryMode == LastQueryMode.ActionKeywordSelected)
|
||||||
LastQuerySelected = false;
|
LastQuerySelected = false;
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
throw new ArgumentException($"wrong LastQueryMode: <{Settings.LastQueryMode}>");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Application.Current.MainWindow is MainWindow mainWindow)
|
||||||
|
{
|
||||||
|
// 📌 Set Opacity of icon and clock to 0 and apply Visibility.Hidden
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
mainWindow.ClockPanel.Opacity = 0;
|
||||||
|
mainWindow.SearchIcon.Opacity = 0;
|
||||||
|
mainWindow.ClockPanel.Visibility = Visibility.Hidden;
|
||||||
|
//mainWindow.SearchIcon.Visibility = Visibility.Hidden;
|
||||||
|
SearchIconVisibility = Visibility.Hidden;
|
||||||
|
|
||||||
|
// Force UI update
|
||||||
|
mainWindow.ClockPanel.UpdateLayout();
|
||||||
|
mainWindow.SearchIcon.UpdateLayout();
|
||||||
|
}, DispatcherPriority.Render);
|
||||||
|
|
||||||
|
// 📌 Apply DWM Cloak (Completely hide the window)
|
||||||
|
Win32Helper.DWMSetCloakForWindow(mainWindow, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(50);
|
||||||
|
|
||||||
|
// Update WPF properties
|
||||||
|
//MainWindowOpacity = 0;
|
||||||
MainWindowVisibilityStatus = false;
|
MainWindowVisibilityStatus = false;
|
||||||
MainWindowVisibility = Visibility.Collapsed;
|
MainWindowVisibility = Visibility.Collapsed;
|
||||||
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = false });
|
VisibilityChanged?.Invoke(this, new VisibilityChangedEventArgs { IsVisible = false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma warning restore VSTHRD100 // Avoid async void methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if Flow Launcher should ignore any hotkeys
|
/// Checks if Flow Launcher should ignore any hotkeys
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShouldIgnoreHotkeys()
|
public bool ShouldIgnoreHotkeys()
|
||||||
{
|
{
|
||||||
return Settings.IgnoreHotkeysOnFullscreen && WindowsInteropHelper.IsWindowFullscreen() || GameModeStatus;
|
return Settings.IgnoreHotkeysOnFullscreen && Win32Helper.IsForegroundWindowFullscreen() || GameModeStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async void LoadIconAsync()
|
private async void LoadIconAsync()
|
||||||
{
|
{
|
||||||
Image = await ImageLoader.LoadAsync(PluginPair.Metadata.IcoPath);
|
Image = await ImageLoader.LoadAsync(PluginPair.Metadata.IcoPath);
|
||||||
|
|
@ -119,7 +118,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
: null;
|
: null;
|
||||||
private ImageSource _image = ImageLoader.MissingImage;
|
private ImageSource _image = ImageLoader.MissingImage;
|
||||||
|
|
||||||
public Visibility ActionKeywordsVisibility => PluginPair.Metadata.ActionKeywords.Count == 1 ? Visibility.Visible : Visibility.Collapsed;
|
public Visibility ActionKeywordsVisibility => PluginPair.Metadata.HideActionKeywordPanel ? Visibility.Collapsed : Visibility.Visible;
|
||||||
public string InitilizaTime => PluginPair.Metadata.InitTime + "ms";
|
public string InitilizaTime => PluginPair.Metadata.InitTime + "ms";
|
||||||
public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms";
|
public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms";
|
||||||
public string Version => InternationalizationManager.Instance.GetTranslation("plugin_query_version") + " " + PluginPair.Metadata.Version;
|
public string Version => InternationalizationManager.Instance.GetTranslation("plugin_query_version") + " " + PluginPair.Metadata.Version;
|
||||||
|
|
@ -128,9 +127,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
public int Priority => PluginPair.Metadata.Priority;
|
public int Priority => PluginPair.Metadata.Priority;
|
||||||
public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; }
|
public Infrastructure.UserSettings.Plugin PluginSettingsObject { get; set; }
|
||||||
|
|
||||||
public void ChangeActionKeyword(string newActionKeyword, string oldActionKeyword)
|
public void OnActionKeywordsChanged()
|
||||||
{
|
{
|
||||||
PluginManager.ReplaceActionKeyword(PluginPair.Metadata.ID, oldActionKeyword, newActionKeyword);
|
|
||||||
OnPropertyChanged(nameof(ActionKeywordsText));
|
OnPropertyChanged(nameof(ActionKeywordsText));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,8 +167,6 @@ namespace Flow.Launcher.ViewModel
|
||||||
App.API.ShowMainWindow();
|
App.API.ShowMainWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsActionKeywordRegistered(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
|
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void SetActionKeywords()
|
private void SetActionKeywords()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8,77 +8,87 @@
|
||||||
d:DesignWidth="500"
|
d:DesignWidth="500"
|
||||||
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
DataContext="{Binding RelativeSource={RelativeSource Self}}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Margin="60,0,10,0">
|
<Grid Margin="{StaticResource SettingPanelMargin}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel Margin="0,10,0,10" Orientation="Vertical">
|
<StackPanel
|
||||||
<StackPanel Orientation="Horizontal">
|
Grid.Row="0"
|
||||||
<TextBlock Margin="10" Text="{DynamicResource flowlauncher_plugin_browserbookmark_loadBrowserFrom}" />
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
<CheckBox
|
Orientation="Horizontal">
|
||||||
Margin="0,0,15,0"
|
<TextBlock
|
||||||
Content="Chrome"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
IsChecked="{Binding LoadChromeBookmark}" />
|
VerticalAlignment="Center"
|
||||||
<CheckBox
|
Text="{DynamicResource flowlauncher_plugin_browserbookmark_loadBrowserFrom}" />
|
||||||
Margin="0,0,15,0"
|
<CheckBox
|
||||||
Content="Edge"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
IsChecked="{Binding LoadEdgeBookmark}" />
|
Content="Chrome"
|
||||||
<CheckBox
|
IsChecked="{Binding LoadChromeBookmark}" />
|
||||||
Margin="0,0,15,0"
|
<CheckBox
|
||||||
Content="Firefox"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
IsChecked="{Binding LoadFirefoxBookmark}" />
|
Content="Edge"
|
||||||
|
IsChecked="{Binding LoadEdgeBookmark}" />
|
||||||
|
<CheckBox
|
||||||
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
|
Content="Firefox"
|
||||||
|
IsChecked="{Binding LoadFirefoxBookmark}" />
|
||||||
|
<Button
|
||||||
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
|
Click="Others_Click"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_browserbookmark_others}" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
Name="CustomBrowsersList"
|
||||||
|
Grid.Row="1"
|
||||||
|
Visibility="Collapsed">
|
||||||
|
<ListView
|
||||||
|
Name="CustomBrowsers"
|
||||||
|
Height="auto"
|
||||||
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
|
BorderBrush="DarkGray"
|
||||||
|
BorderThickness="1"
|
||||||
|
ItemsSource="{Binding Settings.CustomChromiumBrowsers}"
|
||||||
|
MouseDoubleClick="MouseDoubleClickOnSelectedCustomBrowser"
|
||||||
|
SelectedItem="{Binding SelectedCustomBrowser}"
|
||||||
|
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
||||||
|
<ListView.View>
|
||||||
|
<GridView>
|
||||||
|
<GridViewColumn DisplayMemberBinding="{Binding Name, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserName}" />
|
||||||
|
<GridViewColumn DisplayMemberBinding="{Binding DataDirectoryPath, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserBookmarkDataDirectory}" />
|
||||||
|
<GridViewColumn DisplayMemberBinding="{Binding BrowserType, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserEngine}" />
|
||||||
|
</GridView>
|
||||||
|
</ListView.View>
|
||||||
|
</ListView>
|
||||||
|
<StackPanel
|
||||||
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
Margin="0,0,15,0"
|
Width="100"
|
||||||
Click="Others_Click"
|
Click="NewCustomBrowser"
|
||||||
Content="{DynamicResource flowlauncher_plugin_browserbookmark_others}" />
|
Content="{DynamicResource flowlauncher_plugin_browserbookmark_addBrowserBookmark}" />
|
||||||
</StackPanel>
|
<Button
|
||||||
<StackPanel Name="CustomBrowsersList" Visibility="Collapsed">
|
Width="100"
|
||||||
<ListView
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
Name="CustomBrowsers"
|
Click="EditCustomBrowser"
|
||||||
Height="auto"
|
Content="{DynamicResource flowlauncher_plugin_browserbookmark_editBrowserBookmark}">
|
||||||
Margin="10"
|
<Button.Style>
|
||||||
BorderBrush="DarkGray"
|
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="Button">
|
||||||
BorderThickness="1"
|
<Setter Property="IsEnabled" Value="true" />
|
||||||
ItemsSource="{Binding Settings.CustomChromiumBrowsers}"
|
<Style.Triggers>
|
||||||
MouseDoubleClick="MouseDoubleClickOnSelectedCustomBrowser"
|
<DataTrigger Binding="{Binding ElementName=CustomBrowsers, Path=SelectedItems.Count}" Value="0">
|
||||||
SelectedItem="{Binding SelectedCustomBrowser}"
|
<Setter Property="IsEnabled" Value="false" />
|
||||||
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}">
|
</DataTrigger>
|
||||||
<ListView.View>
|
</Style.Triggers>
|
||||||
<GridView>
|
</Style>
|
||||||
<GridViewColumn DisplayMemberBinding="{Binding Name, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserName}" />
|
</Button.Style>
|
||||||
<GridViewColumn DisplayMemberBinding="{Binding DataDirectoryPath, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserBookmarkDataDirectory}" />
|
</Button>
|
||||||
<GridViewColumn DisplayMemberBinding="{Binding BrowserType, Mode=OneWay}" Header="{DynamicResource flowlauncher_plugin_browserbookmark_browserEngine}" />
|
<Button
|
||||||
</GridView>
|
Width="100"
|
||||||
</ListView.View>
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
</ListView>
|
Click="DeleteCustomBrowser"
|
||||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
Content="{DynamicResource flowlauncher_plugin_browserbookmark_removeBrowserBookmark}" />
|
||||||
<Button
|
|
||||||
MinWidth="130"
|
|
||||||
Margin="10"
|
|
||||||
Click="NewCustomBrowser"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_browserbookmark_addBrowserBookmark}" />
|
|
||||||
<Button
|
|
||||||
MinWidth="130"
|
|
||||||
Margin="10"
|
|
||||||
Click="EditCustomBrowser"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_browserbookmark_editBrowserBookmark}">
|
|
||||||
<Button.Style>
|
|
||||||
<Style BasedOn="{StaticResource DefaultButtonStyle}" TargetType="Button">
|
|
||||||
<Setter Property="IsEnabled" Value="true" />
|
|
||||||
<Style.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding ElementName=CustomBrowsers, Path=SelectedItems.Count}" Value="0">
|
|
||||||
<Setter Property="IsEnabled" Value="false" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</Button.Style>
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
MinWidth="120"
|
|
||||||
Margin="10"
|
|
||||||
Click="DeleteCustomBrowser"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_browserbookmark_removeBrowserBookmark}" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -155,16 +155,16 @@ namespace Flow.Launcher.Plugin.Calculator
|
||||||
return value.ToString(numberFormatInfo);
|
return value.ToString(numberFormatInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetDecimalSeparator()
|
private static string GetDecimalSeparator()
|
||||||
{
|
{
|
||||||
string systemDecimalSeperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
|
string systemDecimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
|
||||||
switch (_settings.DecimalSeparator)
|
return _settings.DecimalSeparator switch
|
||||||
{
|
{
|
||||||
case DecimalSeparator.UseSystemLocale: return systemDecimalSeperator;
|
DecimalSeparator.UseSystemLocale => systemDecimalSeparator,
|
||||||
case DecimalSeparator.Dot: return dot;
|
DecimalSeparator.Dot => dot,
|
||||||
case DecimalSeparator.Comma: return comma;
|
DecimalSeparator.Comma => comma,
|
||||||
default: return systemDecimalSeperator;
|
_ => systemDecimalSeparator,
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsBracketComplete(string query)
|
private bool IsBracketComplete(string query)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
<core:LocalizationConverter x:Key="LocalizationConverter" />
|
<core:LocalizationConverter x:Key="LocalizationConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
<Grid Margin="70,14,0,14">
|
<Grid Margin="{StaticResource SettingPanelMargin}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="auto" />
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="auto" />
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="0,0,10,0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
Text="{DynamicResource flowlauncher_plugin_calculator_output_decimal_seperator}" />
|
Text="{DynamicResource flowlauncher_plugin_calculator_output_decimal_seperator}" />
|
||||||
|
|
@ -39,8 +39,9 @@
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
MaxWidth="300"
|
MaxWidth="300"
|
||||||
Margin="10,5,0,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
ItemsSource="{Binding Source={ui:EnumBindingSource {x:Type calculator:DecimalSeparator}}}"
|
ItemsSource="{Binding Source={ui:EnumBindingSource {x:Type calculator:DecimalSeparator}}}"
|
||||||
SelectedItem="{Binding Settings.DecimalSeparator}">
|
SelectedItem="{Binding Settings.DecimalSeparator}">
|
||||||
<ComboBox.ItemTemplate>
|
<ComboBox.ItemTemplate>
|
||||||
|
|
@ -53,7 +54,7 @@
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="0,0,10,0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
Text="{DynamicResource flowlauncher_plugin_calculator_max_decimal_places}" />
|
Text="{DynamicResource flowlauncher_plugin_calculator_max_decimal_places}" />
|
||||||
|
|
@ -61,8 +62,9 @@
|
||||||
x:Name="MaxDecimalPlaces"
|
x:Name="MaxDecimalPlaces"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="10,5,0,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
ItemsSource="{Binding MaxDecimalPlacesRange}"
|
ItemsSource="{Binding MaxDecimalPlacesRange}"
|
||||||
SelectedItem="{Binding Settings.MaxDecimalPlaces}" />
|
SelectedItem="{Binding Settings.MaxDecimalPlaces}" />
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -7,6 +7,7 @@
|
||||||
"*",
|
"*",
|
||||||
"*"
|
"*"
|
||||||
],
|
],
|
||||||
|
"HideActionKeywordPanel": true,
|
||||||
"Name": "Explorer",
|
"Name": "Explorer",
|
||||||
"Description": "Find and manage files and folders via Windows Search or Everything",
|
"Description": "Find and manage files and folders via Windows Search or Everything",
|
||||||
"Author": "Jeremy Wu",
|
"Author": "Jeremy Wu",
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Margin="70 15 18 15">
|
<Grid Margin="{StaticResource SettingPanelMargin}">
|
||||||
<Grid.ColumnDefinitions />
|
<Grid.ColumnDefinitions />
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="auto" />
|
<RowDefinition Height="auto" />
|
||||||
|
|
@ -15,13 +15,12 @@
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Padding="8 0 0 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
Content="{DynamicResource plugin_pluginsmanager_plugin_settings_unknown_source}"
|
Content="{DynamicResource plugin_pluginsmanager_plugin_settings_unknown_source}"
|
||||||
IsChecked="{Binding WarnFromUnknownSource}" />
|
IsChecked="{Binding WarnFromUnknownSource}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Margin="0 10 0 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
Padding="8 0 0 0"
|
|
||||||
Content="{DynamicResource plugin_pluginsmanager_plugin_settings_auto_restart}"
|
Content="{DynamicResource plugin_pluginsmanager_plugin_settings_auto_restart}"
|
||||||
IsChecked="{Binding AutoRestartAfterChanging}" />
|
IsChecked="{Binding AutoRestartAfterChanging}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -10,124 +10,109 @@
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Margin="0">
|
<Grid Margin="{StaticResource SettingPanelMargin}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<DockPanel
|
<DockPanel HorizontalAlignment="Stretch" LastChildFill="True">
|
||||||
Margin="70 10 0 8"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
LastChildFill="True">
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="0 5 10 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="0 0 14 0"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="UWPEnabled"
|
Name="UWPEnabled"
|
||||||
Margin="12 0 12 0"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_uwp}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_uwp}"
|
||||||
IsChecked="{Binding EnableUWP}"
|
IsChecked="{Binding EnableUWP}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}"
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_uwp_tooltip}"
|
||||||
Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
Visibility="{Binding ShowUWPCheckbox, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="StartMenuEnabled"
|
Name="StartMenuEnabled"
|
||||||
Margin="12 0 12 0"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
||||||
IsChecked="{Binding EnableStartMenuSource}"
|
IsChecked="{Binding EnableStartMenuSource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="RegistryEnabled"
|
Name="RegistryEnabled"
|
||||||
Margin="12 0 12 0"
|
Margin="{StaticResource SettingPanelItemRightMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
||||||
IsChecked="{Binding EnableRegistrySource}"
|
IsChecked="{Binding EnableRegistrySource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="PATHEnabled"
|
Name="PATHEnabled"
|
||||||
Margin="12 0 12 0"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
||||||
IsChecked="{Binding EnablePATHSource}"
|
IsChecked="{Binding EnablePATHSource}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Orientation="Vertical">
|
Orientation="Vertical">
|
||||||
<Separator
|
<Separator Style="{StaticResource SettingPanelSeparatorStyle}" />
|
||||||
Height="1"
|
<DockPanel HorizontalAlignment="Stretch" LastChildFill="True">
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
|
||||||
BorderThickness="1" />
|
|
||||||
<DockPanel
|
|
||||||
Margin="70 10 0 8"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
LastChildFill="True">
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="0 5 10 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
||||||
<WrapPanel
|
<WrapPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="0 0 14 0"
|
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
DockPanel.Dock="Right">
|
DockPanel.Dock="Right">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Margin="12 0 12 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
||||||
IsChecked="{Binding HideAppsPath}"
|
IsChecked="{Binding HideAppsPath}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Margin="12 0 12 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers}"
|
||||||
IsChecked="{Binding HideUninstallers}"
|
IsChecked="{Binding HideUninstallers}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideuninstallers_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Margin="12 0 12 0"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
||||||
IsChecked="{Binding EnableDescription}"
|
IsChecked="{Binding EnableDescription}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Margin="12 0 12 0"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp}"
|
||||||
IsChecked="{Binding HideDuplicatedWindowsApp}"
|
IsChecked="{Binding HideDuplicatedWindowsApp}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hideduplicatedwindowsapp_tooltip}" />
|
||||||
</WrapPanel>
|
</WrapPanel>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Separator
|
<Separator Style="{StaticResource SettingPanelSeparatorStyle}" />
|
||||||
Height="1"
|
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
|
||||||
BorderThickness="1" />
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Margin="60 0 0 2"
|
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnLoadAllProgramSource"
|
x:Name="btnLoadAllProgramSource"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="10 10 5 10"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="btnLoadAllProgramSource_OnClick"
|
Click="btnLoadAllProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_all_programs}" />
|
Content="{DynamicResource flowlauncher_plugin_program_all_programs}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnProgramSuffixes"
|
x:Name="btnProgramSuffixes"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="5 10 5 10"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="BtnProgramSuffixes_OnClick"
|
Click="BtnProgramSuffixes_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_suffixes}" />
|
Content="{DynamicResource flowlauncher_plugin_program_suffixes}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnReindex"
|
x:Name="btnReindex"
|
||||||
MinWidth="120"
|
MinWidth="120"
|
||||||
Margin="5 10 5 10"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Click="btnReindex_Click"
|
Click="btnReindex_Click"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_reindex}" />
|
Content="{DynamicResource flowlauncher_plugin_program_reindex}" />
|
||||||
|
|
@ -140,12 +125,13 @@
|
||||||
x:Name="progressBarIndexing"
|
x:Name="progressBarIndexing"
|
||||||
Width="80"
|
Width="80"
|
||||||
Height="20"
|
Height="20"
|
||||||
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
IsIndeterminate="True"
|
IsIndeterminate="True"
|
||||||
Maximum="100"
|
Maximum="100"
|
||||||
Minimum="0" />
|
Minimum="0" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Height="20"
|
Height="20"
|
||||||
Margin="10 0 0 0"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
@ -154,7 +140,7 @@
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="programSourceView"
|
x:Name="programSourceView"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="70 0 20 0"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
|
@ -203,27 +189,24 @@
|
||||||
</GridView>
|
</GridView>
|
||||||
</ListView.View>
|
</ListView.View>
|
||||||
</ListView>
|
</ListView>
|
||||||
<DockPanel
|
<DockPanel Grid.Row="3">
|
||||||
Grid.Row="3"
|
|
||||||
Grid.RowSpan="1"
|
|
||||||
Margin="0 0 20 0">
|
|
||||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnProgramSourceStatus"
|
x:Name="btnProgramSourceStatus"
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
Margin="10"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
Click="btnProgramSourceStatus_OnClick"
|
Click="btnProgramSourceStatus_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_disable}" />
|
Content="{DynamicResource flowlauncher_plugin_program_disable}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnEditProgramSource"
|
x:Name="btnEditProgramSource"
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
Margin="10"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
Click="btnEditProgramSource_OnClick"
|
Click="btnEditProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_edit}" />
|
Content="{DynamicResource flowlauncher_plugin_program_edit}" />
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnAddProgramSource"
|
x:Name="btnAddProgramSource"
|
||||||
MinWidth="100"
|
MinWidth="100"
|
||||||
Margin="10 10 0 10"
|
Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}"
|
||||||
Click="btnAddProgramSource_OnClick"
|
Click="btnAddProgramSource_OnClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_add}" />
|
Content="{DynamicResource flowlauncher_plugin_program_add}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
d:DesignWidth="300"
|
d:DesignWidth="300"
|
||||||
Loaded="CMDSetting_OnLoaded"
|
Loaded="CMDSetting_OnLoaded"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Margin="60,10,10,20" VerticalAlignment="Top">
|
<Grid Margin="{StaticResource SettingPanelMargin}" VerticalAlignment="Top">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
|
|
@ -21,37 +21,37 @@
|
||||||
<CheckBox
|
<CheckBox
|
||||||
x:Name="ReplaceWinR"
|
x:Name="ReplaceWinR"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="10,10,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Content="{DynamicResource flowlauncher_plugin_cmd_relace_winr}" />
|
Content="{DynamicResource flowlauncher_plugin_cmd_relace_winr}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
x:Name="CloseShellAfterPress"
|
x:Name="CloseShellAfterPress"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Content="{DynamicResource flowlauncher_plugin_cmd_close_cmd_after_press}" />
|
Content="{DynamicResource flowlauncher_plugin_cmd_close_cmd_after_press}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
x:Name="LeaveShellOpen"
|
x:Name="LeaveShellOpen"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Content="{DynamicResource flowlauncher_plugin_cmd_leave_cmd_open}" />
|
Content="{DynamicResource flowlauncher_plugin_cmd_leave_cmd_open}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
x:Name="AlwaysRunAsAdministrator"
|
x:Name="AlwaysRunAsAdministrator"
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" />
|
Content="{DynamicResource flowlauncher_plugin_cmd_always_run_as_administrator}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
x:Name="UseWindowsTerminal"
|
x:Name="UseWindowsTerminal"
|
||||||
Grid.Row="4"
|
Grid.Row="4"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Content="{DynamicResource flowlauncher_plugin_cmd_use_windows_terminal}" />
|
Content="{DynamicResource flowlauncher_plugin_cmd_use_windows_terminal}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="ShellComboBox"
|
x:Name="ShellComboBox"
|
||||||
Grid.Row="5"
|
Grid.Row="5"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left">
|
HorizontalAlignment="Left">
|
||||||
<ComboBoxItem>CMD</ComboBoxItem>
|
<ComboBoxItem>CMD</ComboBoxItem>
|
||||||
<ComboBoxItem>PowerShell</ComboBoxItem>
|
<ComboBoxItem>PowerShell</ComboBoxItem>
|
||||||
|
|
@ -61,11 +61,11 @@
|
||||||
<StackPanel Grid.Row="6" Orientation="Horizontal">
|
<StackPanel Grid.Row="6" Orientation="Horizontal">
|
||||||
<CheckBox
|
<CheckBox
|
||||||
x:Name="ShowOnlyMostUsedCMDs"
|
x:Name="ShowOnlyMostUsedCMDs"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
Content="{DynamicResource flowlauncher_plugin_cmd_history}" />
|
Content="{DynamicResource flowlauncher_plugin_cmd_history}" />
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Name="ShowOnlyMostUsedCMDsNumber"
|
x:Name="ShowOnlyMostUsedCMDsNumber"
|
||||||
Margin="10,5,5,5"
|
Margin="{StaticResource SettingPanelItemRightTopBottomMargin}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
d:DesignHeight="300"
|
d:DesignHeight="300"
|
||||||
d:DesignWidth="300"
|
d:DesignWidth="300"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Margin="70 18 18 18">
|
|
||||||
|
<Grid Margin="{StaticResource SettingPanelMargin}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
|
@ -18,7 +19,7 @@
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="lbxCommands"
|
x:Name="lbxCommands"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="0"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
ItemsSource="{Binding Settings.Commands}"
|
ItemsSource="{Binding Settings.Commands}"
|
||||||
|
|
@ -57,11 +58,12 @@
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
Width="100"
|
Width="100"
|
||||||
Margin="10"
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
Click="OnEditCommandKeywordClick"
|
Click="OnEditCommandKeywordClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_sys_edit}" />
|
Content="{DynamicResource flowlauncher_plugin_sys_edit}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Flow.Launcher.Core.Resource;
|
using Flow.Launcher.Core.Resource;
|
||||||
using FLSettings = Flow.Launcher.Infrastructure.UserSettings.Settings;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Sys
|
namespace Flow.Launcher.Plugin.Sys
|
||||||
{
|
{
|
||||||
|
|
@ -10,7 +9,6 @@ namespace Flow.Launcher.Plugin.Sys
|
||||||
{
|
{
|
||||||
public const string Keyword = "fltheme";
|
public const string Keyword = "fltheme";
|
||||||
|
|
||||||
private readonly FLSettings _settings;
|
|
||||||
private readonly Theme _theme;
|
private readonly Theme _theme;
|
||||||
private readonly PluginInitContext _context;
|
private readonly PluginInitContext _context;
|
||||||
|
|
||||||
|
|
@ -19,19 +17,15 @@ namespace Flow.Launcher.Plugin.Sys
|
||||||
// Theme select codes simplified from SettingsPaneThemeViewModel.cs
|
// Theme select codes simplified from SettingsPaneThemeViewModel.cs
|
||||||
|
|
||||||
private Theme.ThemeData _selectedTheme;
|
private Theme.ThemeData _selectedTheme;
|
||||||
private Theme.ThemeData SelectedTheme
|
public Theme.ThemeData SelectedTheme
|
||||||
{
|
{
|
||||||
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.CurrentTheme);
|
get => _selectedTheme ??= Themes.Find(v => v.FileNameWithoutExtension == _theme.GetCurrentTheme());
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_selectedTheme = value;
|
_selectedTheme = value;
|
||||||
_theme.ChangeTheme(value.FileNameWithoutExtension);
|
_theme.ChangeTheme(value.FileNameWithoutExtension);
|
||||||
|
|
||||||
if (_theme.BlurEnabled && _settings.UseDropShadowEffect)
|
_ = _theme.RefreshFrameAsync();
|
||||||
{
|
|
||||||
_theme.RemoveDropShadowEffectFromCurrentTheme();
|
|
||||||
_settings.UseDropShadowEffect = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,7 +37,6 @@ namespace Flow.Launcher.Plugin.Sys
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_theme = Ioc.Default.GetRequiredService<Theme>();
|
_theme = Ioc.Default.GetRequiredService<Theme>();
|
||||||
_settings = Ioc.Default.GetRequiredService<FLSettings>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Result> Query(Query query)
|
public List<Result> Query(Query query)
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
|
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_action_keyword">Action Keyword</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_action_keyword">Action Keyword</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_url">URL</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_url">URL</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_search">Search</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_search">Search</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_enable_suggestion">Use Search Query Autocomplete:</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_enable_suggestion">Use Search Query Autocomplete</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_enable_suggestion_provider">Autocomplete Data from:</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_enable_suggestion_provider">Autocomplete Data from:</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_pls_select_web_search">Please select a web search</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_pls_select_web_search">Please select a web search</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_websearch_delete_warning">Are you sure you want to delete {0}?</system:String>
|
<system:String x:Key="flowlauncher_plugin_websearch_delete_warning">Are you sure you want to delete {0}?</system:String>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Flow.Launcher.Core.Plugin;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.WebSearch
|
namespace Flow.Launcher.Plugin.WebSearch
|
||||||
{
|
{
|
||||||
|
|
@ -16,7 +15,6 @@ namespace Flow.Launcher.Plugin.WebSearch
|
||||||
private SearchSourceViewModel _viewModel;
|
private SearchSourceViewModel _viewModel;
|
||||||
private string selectedNewIconImageFullPath;
|
private string selectedNewIconImageFullPath;
|
||||||
|
|
||||||
|
|
||||||
public SearchSourceSettingWindow(IList<SearchSource> sources, PluginInitContext context, SearchSource old)
|
public SearchSourceSettingWindow(IList<SearchSource> sources, PluginInitContext context, SearchSource old)
|
||||||
{
|
{
|
||||||
_oldSearchSource = old;
|
_oldSearchSource = old;
|
||||||
|
|
@ -80,10 +78,10 @@ namespace Flow.Launcher.Plugin.WebSearch
|
||||||
private void AddSearchSource()
|
private void AddSearchSource()
|
||||||
{
|
{
|
||||||
var keyword = _searchSource.ActionKeyword;
|
var keyword = _searchSource.ActionKeyword;
|
||||||
if (!PluginManager.ActionKeywordRegistered(keyword))
|
if (!_context.API.ActionKeywordAssigned(keyword))
|
||||||
{
|
{
|
||||||
var id = _context.CurrentPluginMetadata.ID;
|
var id = _context.CurrentPluginMetadata.ID;
|
||||||
PluginManager.AddActionKeyword(id, keyword);
|
_context.API.AddActionKeyword(id, keyword);
|
||||||
|
|
||||||
_searchSources.Add(_searchSource);
|
_searchSources.Add(_searchSource);
|
||||||
|
|
||||||
|
|
@ -100,10 +98,11 @@ namespace Flow.Launcher.Plugin.WebSearch
|
||||||
{
|
{
|
||||||
var newKeyword = _searchSource.ActionKeyword;
|
var newKeyword = _searchSource.ActionKeyword;
|
||||||
var oldKeyword = _oldSearchSource.ActionKeyword;
|
var oldKeyword = _oldSearchSource.ActionKeyword;
|
||||||
if (!PluginManager.ActionKeywordRegistered(newKeyword) || oldKeyword == newKeyword)
|
if (!_context.API.ActionKeywordAssigned(newKeyword) || oldKeyword == newKeyword)
|
||||||
{
|
{
|
||||||
var id = _context.CurrentPluginMetadata.ID;
|
var id = _context.CurrentPluginMetadata.ID;
|
||||||
PluginManager.ReplaceActionKeyword(id, oldKeyword, newKeyword);
|
_context.API.RemoveActionKeyword(id, oldKeyword);
|
||||||
|
_context.API.AddActionKeyword(id, newKeyword);
|
||||||
|
|
||||||
var index = _searchSources.IndexOf(_oldSearchSource);
|
var index = _searchSources.IndexOf(_oldSearchSource);
|
||||||
_searchSources[index] = _searchSource;
|
_searchSources[index] = _searchSource;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
d:DesignHeight="300"
|
d:DesignHeight="300"
|
||||||
d:DesignWidth="500"
|
d:DesignWidth="500"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<Style x:Key="BrowserPathBoxStyle" TargetType="TextBox">
|
<Style x:Key="BrowserPathBoxStyle" TargetType="TextBox">
|
||||||
<Setter Property="Height" Value="28" />
|
<Setter Property="Height" Value="28" />
|
||||||
|
|
@ -35,16 +36,19 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Margin="0,4,0,0">
|
|
||||||
|
<Grid Margin="{StaticResource SettingPanelMargin}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition Height="56" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="50" />
|
<RowDefinition />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="SearchSourcesListView"
|
x:Name="SearchSourcesListView"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Margin="18,18,18,0"
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
GridViewColumnHeader.Click="SortByColumn"
|
GridViewColumnHeader.Click="SortByColumn"
|
||||||
|
|
@ -60,7 +64,7 @@
|
||||||
<Image
|
<Image
|
||||||
Width="20"
|
Width="20"
|
||||||
Height="20"
|
Height="20"
|
||||||
Margin="6,0,0,0"
|
Margin="6 0 0 0"
|
||||||
Source="{Binding Path=IconPath}" />
|
Source="{Binding Path=IconPath}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</GridViewColumn.CellTemplate>
|
</GridViewColumn.CellTemplate>
|
||||||
|
|
@ -69,11 +73,11 @@
|
||||||
<GridViewColumn
|
<GridViewColumn
|
||||||
Width="130"
|
Width="130"
|
||||||
DisplayMemberBinding="{Binding ActionKeyword}"
|
DisplayMemberBinding="{Binding ActionKeyword}"
|
||||||
Header="{DynamicResource flowlauncher_plugin_websearch_action_keyword}"/>
|
Header="{DynamicResource flowlauncher_plugin_websearch_action_keyword}" />
|
||||||
<GridViewColumn
|
<GridViewColumn
|
||||||
Width="350"
|
Width="239"
|
||||||
DisplayMemberBinding="{Binding Title}"
|
DisplayMemberBinding="{Binding Title}"
|
||||||
Header="{DynamicResource flowlauncher_plugin_websearch_title}"/>
|
Header="{DynamicResource flowlauncher_plugin_websearch_title}" />
|
||||||
<GridViewColumn Width="140" Header="{DynamicResource flowlauncher_plugin_websearch_enable}">
|
<GridViewColumn Width="140" Header="{DynamicResource flowlauncher_plugin_websearch_enable}">
|
||||||
<GridViewColumn.CellTemplate>
|
<GridViewColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
|
@ -95,59 +99,57 @@
|
||||||
</GridView>
|
</GridView>
|
||||||
</ListView.View>
|
</ListView.View>
|
||||||
</ListView>
|
</ListView>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
Width="100"
|
Width="100"
|
||||||
Margin="10"
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
Click="OnDeleteSearchSearchClick"
|
Click="OnDeleteSearchSearchClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_websearch_delete}" />
|
Content="{DynamicResource flowlauncher_plugin_websearch_delete}" />
|
||||||
<Button
|
<Button
|
||||||
Width="100"
|
Width="100"
|
||||||
Margin="10"
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
Click="OnEditSearchSourceClick"
|
Click="OnEditSearchSourceClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_websearch_edit}" />
|
Content="{DynamicResource flowlauncher_plugin_websearch_edit}" />
|
||||||
<Button
|
<Button
|
||||||
Width="100"
|
Width="100"
|
||||||
Margin="10,10,18,10"
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
Click="OnAddSearchSearchClick"
|
Click="OnAddSearchSearchClick"
|
||||||
Content="{DynamicResource flowlauncher_plugin_websearch_add}" />
|
Content="{DynamicResource flowlauncher_plugin_websearch_add}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Border
|
|
||||||
Grid.Row="2"
|
<Separator Grid.Row="2" Style="{StaticResource SettingPanelSeparatorStyle}" />
|
||||||
Margin="0,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
<DockPanel
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
Grid.Row="3"
|
||||||
BorderThickness="0,1,0,0">
|
Margin="{StaticResource SettingPanelItemTopBottomMargin}"
|
||||||
<DockPanel HorizontalAlignment="Right">
|
HorizontalAlignment="Right">
|
||||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||||
<Label
|
<Label
|
||||||
Margin="14,0,10,0"
|
HorizontalAlignment="Right"
|
||||||
HorizontalAlignment="Right"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
Content="{DynamicResource flowlauncher_plugin_websearch_enable_suggestion_provider}" />
|
||||||
Content="{DynamicResource flowlauncher_plugin_websearch_enable_suggestion_provider}" />
|
<ComboBox
|
||||||
<ComboBox
|
Height="30"
|
||||||
Height="30"
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
Margin="0,0,20,0"
|
VerticalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
FontSize="11"
|
||||||
FontSize="11"
|
IsEnabled="{Binding ElementName=EnableSuggestion, Path=IsChecked}"
|
||||||
IsEnabled="{Binding ElementName=EnableSuggestion, Path=IsChecked}"
|
ItemsSource="{Binding Settings.Suggestions}"
|
||||||
ItemsSource="{Binding Settings.Suggestions}"
|
SelectedItem="{Binding Settings.SelectedSuggestion}" />
|
||||||
SelectedItem="{Binding Settings.SelectedSuggestion}" />
|
<CheckBox
|
||||||
<Label
|
Name="EnableSuggestion"
|
||||||
Margin="0,0,10,0"
|
Margin="{StaticResource SettingPanelItemLeftMargin}"
|
||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Content="{DynamicResource flowlauncher_plugin_websearch_enable_suggestion}" />
|
Content="{DynamicResource flowlauncher_plugin_websearch_enable_suggestion}"
|
||||||
<CheckBox
|
IsChecked="{Binding Settings.EnableSuggestion}" />
|
||||||
Name="EnableSuggestion"
|
</StackPanel>
|
||||||
Margin="0,0,8,0"
|
<!-- Not sure why binding IsEnabled directly to Settings.EnableWebSearchSuggestion is not working -->
|
||||||
IsChecked="{Binding Settings.EnableSuggestion}" />
|
</DockPanel>
|
||||||
</StackPanel>
|
|
||||||
<!-- Not sure why binding IsEnabled directly to Settings.EnableWebSearchSuggestion is not working -->
|
|
||||||
</DockPanel>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using Flow.Launcher.Core.Plugin;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
|
@ -40,7 +39,7 @@ namespace Flow.Launcher.Plugin.WebSearch
|
||||||
if (result == MessageBoxResult.Yes)
|
if (result == MessageBoxResult.Yes)
|
||||||
{
|
{
|
||||||
var id = _context.CurrentPluginMetadata.ID;
|
var id = _context.CurrentPluginMetadata.ID;
|
||||||
PluginManager.RemoveActionKeyword(id, selected.ActionKeyword);
|
_context.API.RemoveActionKeyword(id, selected.ActionKeyword);
|
||||||
_settings.SearchSources.Remove(selected);
|
_settings.SearchSources.Remove(selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
"yahoo",
|
"yahoo",
|
||||||
"bd"
|
"bd"
|
||||||
],
|
],
|
||||||
|
"HideActionKeywordPanel": true,
|
||||||
"Name": "Web Searches",
|
"Name": "Web Searches",
|
||||||
"Description": "Provide the web search ability",
|
"Description": "Provide the web search ability",
|
||||||
"Author": "qianlifeng",
|
"Author": "qianlifeng",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue