diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj
index d20fa94dc..beb2925bf 100644
--- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj
+++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj
@@ -55,7 +55,7 @@
-
+
diff --git a/Flow.Launcher.Core/Plugin/JsonRPCConfigurationModel.cs b/Flow.Launcher.Core/Plugin/JsonRPCConfigurationModel.cs
index 1f63f85a8..6dc4be881 100644
--- a/Flow.Launcher.Core/Plugin/JsonRPCConfigurationModel.cs
+++ b/Flow.Launcher.Core/Plugin/JsonRPCConfigurationModel.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
namespace Flow.Launcher.Core.Plugin
{
@@ -26,6 +27,8 @@ namespace Flow.Launcher.Core.Plugin
public string Name { get; set; }
public string Label { get; set; }
public string Description { get; set; }
+ public string urlLabel { get; set; }
+ public Uri url { get; set; }
public bool Validation { get; set; }
public List Options { get; set; }
public string DefaultValue { get; set; }
@@ -40,4 +43,4 @@ namespace Flow.Launcher.Core.Plugin
DefaultValue = this.DefaultValue;
}
}
-}
\ No newline at end of file
+}
diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
index d9ba4dd40..28d57501b 100644
--- a/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
+++ b/Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs
@@ -22,6 +22,10 @@ using Control = System.Windows.Controls.Control;
using Orientation = System.Windows.Controls.Orientation;
using TextBox = System.Windows.Controls.TextBox;
using UserControl = System.Windows.Controls.UserControl;
+using System.Windows.Documents;
+using static System.Windows.Forms.LinkLabel;
+using Droplex;
+using System.Windows.Forms;
namespace Flow.Launcher.Core.Plugin
{
@@ -336,9 +340,14 @@ namespace Flow.Launcher.Core.Plugin
this.context = context;
await InitSettingAsync();
}
- private static readonly Thickness settingControlMargin = new(10, 4, 10, 4);
- private static readonly Thickness settingPanelMargin = new(15, 20, 15, 20);
- private static readonly Thickness settingTextBlockMargin = new(10, 4, 10, 4);
+ private static readonly Thickness settingControlMargin = new(0, 9, 18, 9);
+ private static readonly Thickness settingCheckboxMargin = new(0, 9, 9, 9);
+ private static readonly Thickness settingPanelMargin = new(0, 0, 0, 0);
+ private static readonly Thickness settingTextBlockMargin = new(70, 9, 18, 9);
+ private static readonly Thickness settingLabelPanelMargin = new(70, 9, 18, 9);
+ private static readonly Thickness settingLabelMargin = new(0, 0, 0, 0);
+ private static readonly Thickness settingDescMargin = new(0, 2, 0, 0);
+ private static readonly Thickness settingSepMargin = new(0, 0, 0, 2);
private JsonRpcConfigurationModel _settingsTemplate;
public Control CreateSettingPanel()
@@ -346,26 +355,60 @@ namespace Flow.Launcher.Core.Plugin
if (Settings == null)
return new();
var settingWindow = new UserControl();
- var mainPanel = new StackPanel
+ var mainPanel = new Grid
{
- Margin = settingPanelMargin, Orientation = Orientation.Vertical
+ Margin = settingPanelMargin, VerticalAlignment = VerticalAlignment.Center
};
- settingWindow.Content = mainPanel;
+ 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 _settingsTemplate.Body)
{
+ Separator sep = new Separator();
+ sep.VerticalAlignment = VerticalAlignment.Top;
+ sep.Margin = settingSepMargin;
+ sep.SetResourceReference(Separator.BackgroundProperty, "Color03B"); /* for theme change */
var panel = new StackPanel
{
- Orientation = Orientation.Horizontal, Margin = settingControlMargin
+ Orientation = Orientation.Vertical, VerticalAlignment = VerticalAlignment.Center,
+ Margin = settingLabelPanelMargin
};
+ RowDefinition gridRow = new RowDefinition();
+ mainPanel.RowDefinitions.Add(gridRow);
var name = new TextBlock()
{
Text = attribute.Label,
- Width = 120,
VerticalAlignment = VerticalAlignment.Center,
- Margin = settingControlMargin,
+ 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);
FrameworkElement contentControl;
@@ -377,18 +420,28 @@ namespace Flow.Launcher.Core.Plugin
{
Text = attribute.Description.Replace("\\r\\n", "\r\n"),
Margin = settingTextBlockMargin,
- MaxWidth = 500,
- TextWrapping = TextWrapping.WrapWithOverflow
+ Padding = new Thickness(0,0,0,0),
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
+ TextAlignment = TextAlignment.Left,
+ TextWrapping = TextWrapping.Wrap
};
- break;
+ Grid.SetColumn(contentControl, 0);
+ 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":
{
var textBox = new TextBox()
{
- Width = 300,
Text = Settings[attribute.Name] as string ?? string.Empty,
Margin = settingControlMargin,
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
ToolTip = attribute.Description
};
textBox.TextChanged += (_, _) =>
@@ -396,17 +449,60 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = textBox.Text;
};
contentControl = textBox;
- break;
+ Grid.SetColumn(contentControl, 1);
+ 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 "inputWithFileBtn":
+ {
+ var textBox = new TextBox()
+ {
+ Margin = new Thickness(10, 0, 0, 0),
+ 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"
+ };
+ var dockPanel = new DockPanel()
+ {
+ Margin = settingControlMargin
+ };
+ DockPanel.SetDock(Btn, Dock.Right);
+ dockPanel.Children.Add(Btn);
+ dockPanel.Children.Add(textBox);
+ contentControl = dockPanel;
+ Grid.SetColumn(contentControl, 1);
+ 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 "textarea":
{
var textBox = new TextBox()
{
- Width = 300,
Height = 120,
Margin = settingControlMargin,
+ VerticalAlignment = VerticalAlignment.Center,
TextWrapping = TextWrapping.WrapWithOverflow,
AcceptsReturn = true,
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
Text = Settings[attribute.Name] as string ?? string.Empty,
ToolTip = attribute.Description
};
@@ -415,16 +511,23 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = ((TextBox)sender).Text;
};
contentControl = textBox;
- break;
+ Grid.SetColumn(contentControl, 1);
+ 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 "passwordBox":
{
var passwordBox = new PasswordBox()
{
- Width = 300,
Margin = settingControlMargin,
Password = Settings[attribute.Name] as string ?? string.Empty,
PasswordChar = attribute.passwordChar == default ? '*' : attribute.passwordChar,
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
ToolTip = attribute.Description
};
passwordBox.PasswordChanged += (sender, _) =>
@@ -432,29 +535,45 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = ((PasswordBox)sender).Password;
};
contentControl = passwordBox;
- break;
+ Grid.SetColumn(contentControl, 1);
+ 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 "dropdown":
{
- var comboBox = new ComboBox()
+ var comboBox = new System.Windows.Controls.ComboBox()
{
ItemsSource = attribute.Options,
SelectedItem = Settings[attribute.Name],
Margin = settingControlMargin,
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
ToolTip = attribute.Description
};
comboBox.SelectionChanged += (sender, _) =>
{
- Settings[attribute.Name] = (string)((ComboBox)sender).SelectedItem;
+ Settings[attribute.Name] = (string)((System.Windows.Controls.ComboBox)sender).SelectedItem;
};
contentControl = comboBox;
- break;
+ Grid.SetColumn(contentControl, 1);
+ 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 "checkbox":
var checkBox = new CheckBox
{
IsChecked = Settings[attribute.Name] is bool isChecked ? isChecked : bool.Parse(attribute.DefaultValue),
- Margin = settingControlMargin,
+ Margin = settingCheckboxMargin,
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
ToolTip = attribute.Description
};
checkBox.Click += (sender, _) =>
@@ -462,15 +581,45 @@ namespace Flow.Launcher.Core.Plugin
Settings[attribute.Name] = ((CheckBox)sender).IsChecked;
};
contentControl = checkBox;
+ Grid.SetColumn(contentControl, 1);
+ 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 "hyperlink":
+ var hyperlink = new Hyperlink
+ {
+ ToolTip = attribute.Description,
+ NavigateUri = attribute.url
+ };
+ var linkbtn = new System.Windows.Controls.Button
+ {
+ HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
+ Margin = settingControlMargin
+ };
+ linkbtn.Content = attribute.urlLabel;
+
+ contentControl = linkbtn;
+ Grid.SetColumn(contentControl, 1);
+ Grid.SetRow(contentControl, rowCount);
+ if (rowCount != 0)
+ mainPanel.Children.Add(sep);
+ Grid.SetRow(sep, rowCount);
+ Grid.SetColumn(sep, 0);
+ Grid.SetColumnSpan(sep, 2);
break;
default:
continue;
}
if (type != "textBlock")
_settingControls[attribute.Name] = contentControl;
- panel.Children.Add(name);
- panel.Children.Add(contentControl);
mainPanel.Children.Add(panel);
+ mainPanel.Children.Add(contentControl);
+ rowCount++;
+
}
return settingWindow;
}
@@ -506,7 +655,7 @@ namespace Flow.Launcher.Core.Plugin
case PasswordBox passwordBox:
passwordBox.Dispatcher.Invoke(() => passwordBox.Password = value as string);
break;
- case ComboBox comboBox:
+ case System.Windows.Controls.ComboBox comboBox:
comboBox.Dispatcher.Invoke(() => comboBox.SelectedItem = value);
break;
case CheckBox checkBox:
diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs
index 15a19b210..ab5e4722b 100644
--- a/Flow.Launcher.Infrastructure/Constant.cs
+++ b/Flow.Launcher.Infrastructure/Constant.cs
@@ -29,6 +29,7 @@ namespace Flow.Launcher.Infrastructure
public static readonly string DefaultIcon = Path.Combine(ImagesDirectory, "app.png");
public static readonly string ErrorIcon = Path.Combine(ImagesDirectory, "app_error.png");
public static readonly string MissingImgIcon = Path.Combine(ImagesDirectory, "app_missing_img.png");
+ public static readonly string LoadingImgIcon = Path.Combine(ImagesDirectory, "loading.png");
public static string PythonPath;
public static string NodePath;
diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
index 5a9122e01..fb773f562 100644
--- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
+++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
@@ -58,7 +58,7 @@
-
+
diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs
index 130221379..deb858a79 100644
--- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs
+++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
@@ -21,8 +22,10 @@ namespace Flow.Launcher.Infrastructure.Image
private static readonly ConcurrentDictionary GuidToKey = new();
private static IImageHashGenerator _hashGenerator;
private static readonly bool EnableImageHash = true;
- public static ImageSource DefaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon));
- public const int SmallIconSize = 32;
+ public static ImageSource MissingImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon));
+ public static ImageSource LoadingImage { get; } = new BitmapImage(new Uri(Constant.LoadingImgIcon));
+ public const int SmallIconSize = 64;
+ public const int FullIconSize = 256;
private static readonly string[] ImageExtensions =
@@ -99,6 +102,7 @@ namespace Flow.Launcher.Infrastructure.Image
Folder,
Data,
ImageFile,
+ FullImageFile,
Error,
Cache
}
@@ -111,7 +115,7 @@ namespace Flow.Launcher.Infrastructure.Image
{
if (string.IsNullOrEmpty(path))
{
- return new ImageResult(DefaultImage, ImageType.Error);
+ return new ImageResult(MissingImage, ImageType.Error);
}
if (ImageCache.ContainsKey(path, loadFullImage))
@@ -201,6 +205,7 @@ namespace Flow.Launcher.Infrastructure.Image
if (loadFullImage)
{
image = LoadFullImage(path);
+ type = ImageType.FullImageFile;
}
else
{
@@ -215,7 +220,7 @@ namespace Flow.Launcher.Infrastructure.Image
else
{
type = ImageType.File;
- image = GetThumbnail(path, ThumbnailOptions.None);
+ image = GetThumbnail(path, ThumbnailOptions.None, loadFullImage ? FullIconSize : SmallIconSize);
}
}
else
@@ -232,12 +237,12 @@ namespace Flow.Launcher.Infrastructure.Image
return new ImageResult(image, type);
}
- private static BitmapSource GetThumbnail(string path, ThumbnailOptions option = ThumbnailOptions.ThumbnailOnly)
+ private static BitmapSource GetThumbnail(string path, ThumbnailOptions option = ThumbnailOptions.ThumbnailOnly, int size = SmallIconSize)
{
return WindowsThumbnailProvider.GetThumbnail(
path,
- Constant.ThumbnailSize,
- Constant.ThumbnailSize,
+ size,
+ size,
option);
}
@@ -254,6 +259,10 @@ namespace Flow.Launcher.Infrastructure.Image
if (imageResult.ImageType != ImageType.Error && imageResult.ImageType != ImageType.Cache)
{ // we need to get image hash
string hash = EnableImageHash ? _hashGenerator.GetHashFromImage(img) : null;
+ if (imageResult.ImageType == ImageType.FullImageFile)
+ {
+ path = $"{path}_{ImageType.FullImageFile}";
+ }
if (hash != null)
{
@@ -263,6 +272,7 @@ namespace Flow.Launcher.Infrastructure.Image
}
else
{ // new guid
+
GuidToKey[hash] = path;
}
}
@@ -279,9 +289,33 @@ namespace Flow.Launcher.Infrastructure.Image
BitmapImage image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
- image.UriSource = new Uri(path);
+ image.UriSource = new Uri(path);
image.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
image.EndInit();
+
+ if (image.PixelWidth > 320)
+ {
+ BitmapImage resizedWidth = new BitmapImage();
+ resizedWidth.BeginInit();
+ resizedWidth.CacheOption = BitmapCacheOption.OnLoad;
+ resizedWidth.UriSource = new Uri(path);
+ resizedWidth.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
+ resizedWidth.DecodePixelWidth = 320;
+ resizedWidth.EndInit();
+
+ if (resizedWidth.PixelHeight > 320)
+ {
+ BitmapImage resizedHeight = new BitmapImage();
+ resizedHeight.BeginInit();
+ resizedHeight.CacheOption = BitmapCacheOption.OnLoad;
+ resizedHeight.UriSource = new Uri(path);
+ resizedHeight.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
+ resizedHeight.DecodePixelHeight = 320;
+ resizedHeight.EndInit();
+ return resizedHeight;
+ }
+ return resizedWidth;
+ }
return image;
}
}
diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index 3561c6ffe..09fad990b 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -146,6 +146,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
/// when false Alphabet static service will always return empty results
///
public bool ShouldUsePinyin { get; set; } = false;
+ public bool AlwaysPreview { get; set; } = false;
[JsonInclude, JsonConverter(typeof(JsonStringEnumConverter))]
public SearchPrecisionScore QuerySearchPrecision { get; private set; } = SearchPrecisionScore.Regular;
diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
index 41d062570..79d106ef2 100644
--- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
@@ -183,6 +183,13 @@ namespace Flow.Launcher.Plugin
/// The actionkeyword that is supposed to be removed
void RemoveActionKeyword(string pluginId, string oldActionKeyword);
+ ///
+ /// Check whether specific ActionKeyword is assigned to any of the plugin
+ ///
+ /// The actionkeyword for checking
+ /// True if the actionkeyword is already assigned, False otherwise
+ bool ActionKeywordAssigned(string actionKeyword);
+
///
/// Log debug message
/// Message will only be logged in Debug mode
diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs
index f2d9323ef..912a23a6f 100644
--- a/Flow.Launcher.Plugin/Result.cs
+++ b/Flow.Launcher.Plugin/Result.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
+using System.Windows.Controls;
using System.Windows.Media;
namespace Flow.Launcher.Plugin
@@ -203,6 +204,11 @@ namespace Flow.Launcher.Plugin
///
public string SubTitleToolTip { get; set; }
+ ///
+ /// Customized Preview Panel
+ ///
+ public Lazy PreviewPanel { get; set; }
+
///
/// Run this result, asynchronously
///
@@ -223,5 +229,30 @@ namespace Flow.Launcher.Plugin
///
/// #26a0da (blue)
public string ProgressBarColor { get; set; } = "#26a0da";
+
+ public PreviewInfo Preview { get; set; } = PreviewInfo.Default;
+
+ ///
+ /// Info of the preview image.
+ ///
+ public record PreviewInfo
+ {
+ ///
+ /// Full image used for preview panel
+ ///
+ public string PreviewImagePath { get; set; }
+ ///
+ /// Determines if the preview image should occupy the full width of the preveiw panel.
+ ///
+ public bool IsMedia { get; set; }
+ public string Description { get; set; }
+
+ public static PreviewInfo Default { get; } = new()
+ {
+ PreviewImagePath = null,
+ Description = null,
+ IsMedia = false,
+ };
+ }
}
}
diff --git a/Flow.Launcher.Test/Flow.Launcher.Test.csproj b/Flow.Launcher.Test/Flow.Launcher.Test.csproj
index c4341288f..c67a5cf22 100644
--- a/Flow.Launcher.Test/Flow.Launcher.Test.csproj
+++ b/Flow.Launcher.Test/Flow.Launcher.Test.csproj
@@ -49,7 +49,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
index 78be463e4..e0cc9b4c2 100644
--- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs
+++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
@@ -7,6 +7,7 @@ using Flow.Launcher.Plugin.SharedCommands;
using NUnit.Framework;
using System;
using System.Collections.Generic;
+using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
@@ -32,12 +33,11 @@ namespace Flow.Launcher.Test.Plugins
{
new Result
{
- Title="Result 1"
+ Title = "Result 1"
},
-
new Result
{
- Title="Result 2"
+ Title = "Result 2"
}
};
}
@@ -46,15 +46,13 @@ namespace Flow.Launcher.Test.Plugins
private bool PreviousLocationNotExistReturnsFalse(string dummyString) => false;
+ [SupportedOSPlatform("windows7.0")]
[TestCase("C:\\SomeFolder\\", "directory='file:C:\\SomeFolder\\'")]
public void GivenWindowsIndexSearch_WhenProvidedFolderPath_ThenQueryWhereRestrictionsShouldUseDirectoryString(string path, string expectedString)
{
- // Given
- var queryConstructor = new QueryConstructor(new Settings());
-
// When
var folderPath = path;
- var result = queryConstructor.QueryWhereRestrictionsForTopLevelDirectorySearch(folderPath);
+ var result = QueryConstructor.TopLevelDirectoryConstraint(folderPath);
// Then
Assert.IsTrue(result == expectedString,
@@ -62,6 +60,7 @@ namespace Flow.Launcher.Test.Plugins
$"Actual: {result}{Environment.NewLine}");
}
+ [SupportedOSPlatform("windows7.0")]
[TestCase("C:\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\' ORDER BY System.FileName")]
[TestCase("C:\\SomeFolder\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\SomeFolder\\' ORDER BY System.FileName")]
public void GivenWindowsIndexSearch_WhenSearchTypeIsTopLevelDirectorySearch_ThenQueryShouldUseExpectedString(string folderPath, string expectedString)
@@ -70,130 +69,68 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var queryString = queryConstructor.QueryForTopLevelDirectorySearch(folderPath);
+ var queryString = queryConstructor.Directory(folderPath);
// Then
- Assert.IsTrue(queryString == expectedString,
+ Assert.IsTrue(queryString.Replace(" ", " ") == expectedString.Replace(" ", " "),
$"Expected string: {expectedString}{Environment.NewLine} " +
$"Actual string was: {queryString}{Environment.NewLine}");
}
- [TestCase("C:\\SomeFolder\\flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " +
- "FROM SystemIndex WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
- "OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033))" +
- " AND directory='file:C:\\SomeFolder' ORDER BY System.FileName")]
+ [SupportedOSPlatform("windows7.0")]
+ [TestCase("C:\\SomeFolder", "flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType" +
+ " FROM SystemIndex WHERE directory='file:C:\\SomeFolder'" +
+ " AND (System.FileName LIKE 'flow.launcher.sln%' OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"'))" +
+ " ORDER BY System.FileName")]
public void GivenWindowsIndexSearchTopLevelDirectory_WhenSearchingForSpecificItem_ThenQueryShouldUseExpectedString(
- string userSearchString, string expectedString)
+ string folderPath, string userSearchString, string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
//When
- var queryString = queryConstructor.QueryForTopLevelDirectorySearch(userSearchString);
+ var queryString = queryConstructor.Directory(folderPath, userSearchString);
// Then
- Assert.IsTrue(queryString == expectedString,
- $"Expected string: {expectedString}{Environment.NewLine} " +
- $"Actual string was: {queryString}{Environment.NewLine}");
- }
-
- [TestCase("C:\\SomeFolder\\SomeApp", "(System.FileName LIKE 'SomeApp%' " +
- "OR CONTAINS(System.FileName,'\"SomeApp*\"',1033))" +
- " AND directory='file:C:\\SomeFolder'")]
- public void GivenWindowsIndexSearchTopLevelDirectory_WhenSearchingForSpecificItem_ThenQueryWhereRestrictionsShouldUseDirectoryString(
- string userSearchString, string expectedString)
- {
- // Given
- var queryConstructor = new QueryConstructor(new Settings());
-
- //When
- var queryString = queryConstructor.QueryWhereRestrictionsForTopLevelDirectorySearch(userSearchString);
-
- // Then
- Assert.IsTrue(queryString == expectedString,
- $"Expected string: {expectedString}{Environment.NewLine} " +
- $"Actual string was: {queryString}{Environment.NewLine}");
+ Assert.AreEqual(expectedString, queryString);
}
+ [SupportedOSPlatform("windows7.0")]
[TestCase("scope='file:'")]
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryWhereRestrictionsShouldUseScopeString(string expectedString)
{
//When
- var resultString = QueryConstructor.QueryWhereRestrictionsForAllFilesAndFoldersSearch;
+ const string resultString = QueryConstructor.RestrictionsForAllFilesAndFoldersSearch;
// Then
- Assert.IsTrue(resultString == expectedString,
- $"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
- $"Actual string was: {resultString}{Environment.NewLine}");
+ Assert.AreEqual(expectedString, resultString);
}
+ [SupportedOSPlatform("windows7.0")]
[TestCase("flow.launcher.sln", "SELECT TOP 100 \"System.FileName\", \"System.ItemUrl\", \"System.ItemType\" " +
- "FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
- "OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:' ORDER BY System.FileName")]
+ "FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
+ "OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:' ORDER BY System.FileName")]
+ [TestCase("", "SELECT TOP 100 \"System.FileName\", \"System.ItemUrl\", \"System.ItemType\" FROM \"SystemIndex\" WHERE WorkId IS NOT NULL AND scope='file:' ORDER BY System.FileName")]
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryShouldUseExpectedString(
string userSearchString, string expectedString)
{
// Given
var queryConstructor = new QueryConstructor(new Settings());
- var baseQuery = queryConstructor.CreateBaseQuery();
-
+ var baseQuery = queryConstructor.CreateBaseQuery();
+
// system running this test could have different locale than the hard-coded 1033 LCID en-US.
var queryKeywordLocale = baseQuery.QueryKeywordLocale;
expectedString = expectedString.Replace("1033", queryKeywordLocale.ToString());
-
-
//When
- var resultString = queryConstructor.QueryForAllFilesAndFolders(userSearchString);
+ var resultString = queryConstructor.FilesAndFolders(userSearchString);
// Then
- Assert.IsTrue(resultString == expectedString,
- $"Expected query string: {expectedString}{Environment.NewLine} " +
- $"Actual string was: {resultString}{Environment.NewLine}");
+ Assert.AreEqual(expectedString, resultString);
}
- [TestCase]
- public async Task GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldContinueDirectoryInfoClassSearchAsync()
- {
- // Given
- var searchManager = new SearchManager(new Settings(), new PluginInitContext());
-
- // When
- var results = await searchManager.TopLevelDirectorySearchBehaviourAsync(
- MethodWindowsIndexSearchReturnsZeroResultsAsync,
- MethodDirectoryInfoClassSearchReturnsTwoResults,
- false,
- new Query(),
- "string not used",
- default);
-
- // Then
- Assert.IsTrue(results.Count == 2,
- $"Expected to have 2 results from DirectoryInfoClassSearch {Environment.NewLine} " +
- $"Actual number of results is {results.Count} {Environment.NewLine}");
- }
-
- [TestCase]
- public async Task GivenTopLevelDirectorySearch_WhenIndexSearchNotRequired_ThenSearchMethodShouldNotContinueDirectoryInfoClassSearchAsync()
- {
- // Given
- var searchManager = new SearchManager(new Settings(), new PluginInitContext());
-
- // When
- var results = await searchManager.TopLevelDirectorySearchBehaviourAsync(
- MethodWindowsIndexSearchReturnsZeroResultsAsync,
- MethodDirectoryInfoClassSearchReturnsTwoResults,
- true,
- new Query(),
- "string not used",
- default);
-
- // Then
- Assert.IsTrue(results.Count == 0,
- $"Expected to have 0 results because location is indexed {Environment.NewLine} " +
- $"Actual number of results is {results.Count} {Environment.NewLine}");
- }
+ [SupportedOSPlatform("windows7.0")]
[TestCase(@"some words", @"FREETEXT('some words')")]
public void GivenWindowsIndexSearch_WhenQueryWhereRestrictionsIsForFileContentSearch_ThenShouldReturnFreeTextString(
string querySearchString, string expectedString)
@@ -202,7 +139,7 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var resultString = queryConstructor.QueryWhereRestrictionsForFileContentSearch(querySearchString);
+ var resultString = QueryConstructor.RestrictionsForFileContentSearch(querySearchString);
// Then
Assert.IsTrue(resultString == expectedString,
@@ -210,8 +147,9 @@ namespace Flow.Launcher.Test.Plugins
$"Actual string was: {resultString}{Environment.NewLine}");
}
+ [SupportedOSPlatform("windows7.0")]
[TestCase("some words", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " +
- "FROM SystemIndex WHERE FREETEXT('some words') AND scope='file:' ORDER BY System.FileName")]
+ "FROM SystemIndex WHERE FREETEXT('some words') AND scope='file:' ORDER BY System.FileName")]
public void GivenWindowsIndexSearch_WhenSearchForFileContent_ThenQueryShouldUseExpectedString(
string userSearchString, string expectedString)
{
@@ -219,7 +157,7 @@ namespace Flow.Launcher.Test.Plugins
var queryConstructor = new QueryConstructor(new Settings());
//When
- var resultString = queryConstructor.QueryForFileContentSearch(userSearchString);
+ var resultString = queryConstructor.FileContent(userSearchString);
// Then
Assert.IsTrue(resultString == expectedString,
@@ -230,12 +168,15 @@ namespace Flow.Launcher.Test.Plugins
public void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileContentSearchRequiredShouldReturnTrue()
{
// Given
- var query = new Query { ActionKeyword = "doc:", Search = "search term" };
+ var query = new Query
+ {
+ ActionKeyword = "doc:", Search = "search term"
+ };
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
// When
- var result = searchManager.IsFileContentSearch(query.ActionKeyword);
+ var result = SearchManager.IsFileContentSearch(query.ActionKeyword);
// Then
Assert.IsTrue(result,
@@ -303,24 +244,19 @@ namespace Flow.Launcher.Test.Plugins
$"Actual path string is {returnedPath} {Environment.NewLine}");
}
- [TestCase("c:\\SomeFolder\\>", "scope='file:c:\\SomeFolder'")]
- [TestCase("c:\\SomeFolder\\>SomeName", "(System.FileName LIKE 'SomeName%' "
- + "OR CONTAINS(System.FileName,'\"SomeName*\"',1033)) AND "
- + "scope='file:c:\\SomeFolder'")]
- public void GivenWindowsIndexSearch_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString)
+ [SupportedOSPlatform("windows7.0")]
+ [TestCase("c:\\SomeFolder", "scope='file:c:\\SomeFolder'")]
+ [TestCase("c:\\OtherFolder", "scope='file:c:\\OtherFolder'")]
+ public void GivenFilePath_WhenSearchPatternHotKeyIsSearchAll_ThenQueryWhereRestrictionsShouldUseScopeString(string path, string expectedString)
{
- // Given
- var queryConstructor = new QueryConstructor(new Settings());
-
//When
- var resultString = queryConstructor.QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(path);
+ var resultString = QueryConstructor.RecursiveDirectoryConstraint(path);
// Then
- Assert.IsTrue(resultString == expectedString,
- $"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
- $"Actual string was: {resultString}{Environment.NewLine}");
+ Assert.AreEqual(expectedString, resultString);
}
+ [SupportedOSPlatform("windows7.0")]
[TestCase("c:\\somefolder\\>somefile", "*somefile*")]
[TestCase("c:\\somefolder\\somefile", "somefile*")]
[TestCase("c:\\somefolder\\", "*")]
@@ -331,9 +267,7 @@ namespace Flow.Launcher.Test.Plugins
var resultString = DirectoryInfoSearch.ConstructSearchCriteria(path);
// Then
- Assert.IsTrue(resultString == expectedString,
- $"Expected criteria string: {expectedString}{Environment.NewLine} " +
- $"Actual criteria string was: {resultString}{Environment.NewLine}");
+ Assert.AreEqual(expectedString, resultString);
}
}
}
diff --git a/Flow.Launcher.Test/Plugins/ProgramTest.cs b/Flow.Launcher.Test/Plugins/ProgramTest.cs
deleted file mode 100644
index e3a05f484..000000000
--- a/Flow.Launcher.Test/Plugins/ProgramTest.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using Flow.Launcher.Plugin.Program.Programs;
-using NUnit.Framework;
-using System;
-using Windows.ApplicationModel;
-
-namespace Flow.Launcher.Test.Plugins
-{
- [TestFixture]
- public class ProgramTest
- {
- [TestCase("Microsoft.WindowsCamera", "ms-resource:LensSDK/Resources/AppTitle", "ms-resource://Microsoft.WindowsCamera/LensSDK/Resources/AppTitle")]
- [TestCase("microsoft.windowscommunicationsapps", "ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_MailDesktop_DisplayName",
- "ms-resource://microsoft.windowscommunicationsapps/hxoutlookintl/AppManifest_MailDesktop_DisplayName")]
- [TestCase("windows.immersivecontrolpanel", "ms-resource:DisplayName", "ms-resource://windows.immersivecontrolpanel/Resources/DisplayName")]
- [TestCase("Microsoft.MSPaint", "ms-resource:AppName", "ms-resource://Microsoft.MSPaint/Resources/AppName")]
- public void WhenGivenPriReferenceValueShouldReturnCorrectFormat(string packageName, string rawPriReferenceValue, string expectedFormat)
- {
- // Arrange
- var app = new UWP.Application();
-
- // Act
- var result = UWP.Application.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
-
- // Assert
- Assert.IsTrue(result == expectedFormat,
- $"Expected Pri reference format: {expectedFormat}{Environment.NewLine} " +
- $"Actual: {result}{Environment.NewLine}");
- }
- }
-}
diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln
index f59d3d26f..1d403c5a1 100644
--- a/Flow.Launcher.sln
+++ b/Flow.Launcher.sln
@@ -80,7 +80,7 @@ Global
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.ActiveCfg = Debug|Any CPU
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x64.Build.0 = Debug|Any CPU
{FF742965-9A80-41A5-B042-D6C7D3A21708}.Debug|x86.ActiveCfg = Debug|Any CPU
diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs
index e116e6f4d..012c9ff4e 100644
--- a/Flow.Launcher/ActionKeywords.xaml.cs
+++ b/Flow.Launcher/ActionKeywords.xaml.cs
@@ -8,24 +8,17 @@ using Flow.Launcher.ViewModel;
namespace Flow.Launcher
{
- public partial class ActionKeywords : Window
+ public partial class ActionKeywords
{
private readonly PluginPair plugin;
- private Settings settings;
private readonly Internationalization translater = InternationalizationManager.Instance;
private readonly PluginViewModel pluginViewModel;
- public ActionKeywords(string pluginId, Settings settings, PluginViewModel pluginViewModel)
+ public ActionKeywords(PluginViewModel pluginViewModel)
{
InitializeComponent();
- plugin = PluginManager.GetPluginForId(pluginId);
- this.settings = settings;
+ plugin = pluginViewModel.PluginPair;
this.pluginViewModel = pluginViewModel;
- if (plugin == null)
- {
- MessageBox.Show(translater.GetTranslation("cannotFindSpecifiedPlugin"));
- Close();
- }
}
private void ActionKeyword_OnLoaded(object sender, RoutedEventArgs e)
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index 0857fb55b..43fa0eddb 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -186,7 +186,7 @@ namespace Flow.Launcher
public void OnSecondAppStarted()
{
- Current.MainWindow.Show();
+ _mainVM.Show();
}
}
}
diff --git a/Flow.Launcher/Converters/OrdinalConverter.cs b/Flow.Launcher/Converters/OrdinalConverter.cs
index 0c716ac7e..02b9bdbde 100644
--- a/Flow.Launcher/Converters/OrdinalConverter.cs
+++ b/Flow.Launcher/Converters/OrdinalConverter.cs
@@ -1,4 +1,4 @@
-using System.Globalization;
+using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj
index b1a822fb6..1f74ea8a5 100644
--- a/Flow.Launcher/Flow.Launcher.csproj
+++ b/Flow.Launcher/Flow.Launcher.csproj
@@ -1,4 +1,4 @@
-
+
WinExe
@@ -92,12 +92,12 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/Flow.Launcher/Images/Browser.png b/Flow.Launcher/Images/Browser.png
index 5d475f82e..a5bc848c7 100644
Binary files a/Flow.Launcher/Images/Browser.png and b/Flow.Launcher/Images/Browser.png differ
diff --git a/Flow.Launcher/Images/app_missing_img.png b/Flow.Launcher/Images/app_missing_img.png
index 27e366bbc..0bb16e5d8 100644
Binary files a/Flow.Launcher/Images/app_missing_img.png and b/Flow.Launcher/Images/app_missing_img.png differ
diff --git a/Flow.Launcher/Images/loading.png b/Flow.Launcher/Images/loading.png
new file mode 100644
index 000000000..1600b5967
Binary files /dev/null and b/Flow.Launcher/Images/loading.png differ
diff --git a/Flow.Launcher/Languages/da.xaml b/Flow.Launcher/Languages/da.xaml
index cf69fd853..cc3d9d527 100644
--- a/Flow.Launcher/Languages/da.xaml
+++ b/Flow.Launcher/Languages/da.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
af
Initaliseringstid:
Søgetid:
- | Version
+ Version
Website
Uninstall
@@ -113,6 +115,14 @@
Søg efter flere temaer
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Søgefelt skrifttype
Resultat skrifttype
Vindue mode
diff --git a/Flow.Launcher/Languages/de.xaml b/Flow.Launcher/Languages/de.xaml
index 0853b4b91..dc7d669f4 100644
--- a/Flow.Launcher/Languages/de.xaml
+++ b/Flow.Launcher/Languages/de.xaml
@@ -62,6 +62,8 @@
Erforderliche Suchergebnisse.
Pinyin aktivieren
Ermöglicht die Verwendung von Pinyin für die Suche. Pinyin ist das Standardsystem der romanisierten Schreibweise für die Übersetzung von chinesischen Texten.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Der Schatteneffekt ist nicht zulässig, wenn das aktuelle Thema den Weichzeichneffekt aktiviert hat
@@ -113,6 +115,14 @@
Suche nach weiteren Themes
Wie man ein Design erstellt
Hallo!
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Programm
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Abfragebox Schriftart
Ergebnis Schriftart
Fenstermodus
@@ -163,9 +173,9 @@
Press Key
- HTTP Proxy
+ HTTP-Proxy
Aktiviere HTTP Proxy
- HTTP Server
+ HTTP-Server
Port
Benutzername
Passwort
@@ -180,9 +190,9 @@
Über
- Website
+ Webseite
Github
- Docs
+ Dokumentation
Version
Icons
Sie haben Flow Launcher {0} mal aktiviert
@@ -207,24 +217,24 @@
Select File Manager
Please specify the file location of the file manager you using and add arguments if necessary. The default arguments are "%d", and a path is entered at that location. For example, If a command is required such as "totalcmd.exe /A c:\windows", argument is /A "%d".
"%f" is an argument that represent the file path. It is used to emphasize the file/folder name when opening a specific file location in 3rd party file manager. This argument is only available in the "Arg for File" item. If the file manager does not have that function, you can use "%d".
- File Manager
- Profile Name
+ Datei-Manager
+ Profilname
File Manager Path
Arg For Folder
Arg For File
- Default Web Browser
+ Standard-Webbrowser
The default setting follows the OS default browser setting. If specified separately, flow uses that browser.
Browser
Browser-Name
- Browser Path
+ Browserpfad
New Window
New Tab
- Private Mode
+ Privater Modus
- Change Priority
+ Priorität ändern
Greater the number, the higher the result will be ranked. Try setting it as 5. If you want the results to be lower than any other plugin's, provide a negative number
Please provide an valid integer for Priority!
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index 661c66bf0..fcc364dc2 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -68,6 +68,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -92,7 +94,7 @@
by
Init time:
Query time:
- | Version
+ Version
Website
Uninstall
@@ -119,6 +121,14 @@
Theme Gallery
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Query Box Font
Result Item Font
Window Mode
diff --git a/Flow.Launcher/Languages/es-419.xaml b/Flow.Launcher/Languages/es-419.xaml
index a3f61ef05..3ac0e22d8 100644
--- a/Flow.Launcher/Languages/es-419.xaml
+++ b/Flow.Launcher/Languages/es-419.xaml
@@ -62,6 +62,8 @@
Cambia la puntuación mínima de similitud requerida para resultados.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
El efecto de sombra no está permitido mientras el tema actual tenga el efecto de desenfoque habilitado
@@ -86,7 +88,7 @@
por
Tiempo de inicio:
Tiempo de consulta:
- | Versión
+ Versión
Sitio web
Uninstall
@@ -113,6 +115,14 @@
Galería de Temas
Cómo crear un tema
Hola
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Fuente del cuadro de consulta
Fuente de los resultados
Modo Ventana
diff --git a/Flow.Launcher/Languages/es.xaml b/Flow.Launcher/Languages/es.xaml
index b158dbb57..03fdfb21c 100644
--- a/Flow.Launcher/Languages/es.xaml
+++ b/Flow.Launcher/Languages/es.xaml
@@ -62,6 +62,8 @@
Cambia la puntuación mínima requerida para la coincidencia de los resultados.
Buscar con Pinyin
Permite utilizar Pinyin para la búsqueda. Pinyin es el sistema estándar de ortografía romanizado para traducir chino.
+ Mostrar siempre vista previa
+ Muestra siempre el panel de vista previa al iniciar Flow. Pulse F1 para mostrar/ocultar la vista previa.
El efecto de sombra no está permitido mientras el tema actual tenga el efecto de desenfoque activado
@@ -86,7 +88,7 @@
por
Tiempo de inicio:
Tiempo de consulta:
- | Versión
+ Versión
Sitio web
Desinstalar
@@ -113,6 +115,14 @@
Galería de temas
Cómo crear un tema
Hola
+ Explorador
+ Buscar archivos, carpetas y contenido de archivos
+ Búsqueda Web
+ Buscar en la web con el apoyo de diferentes motores de búsqueda
+ Programa
+ Iniciar programas como administrador o como usuario diferente
+ Eliminar Procesos
+ Terminar procesos no deseados
Fuente del texto del cuadro de consulta
Fuente del texto de los resultados
Modo Ventana
diff --git a/Flow.Launcher/Languages/fr.xaml b/Flow.Launcher/Languages/fr.xaml
index 7f874a334..7ebd158c2 100644
--- a/Flow.Launcher/Languages/fr.xaml
+++ b/Flow.Launcher/Languages/fr.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Devrait utiliser le pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
Chargement :
Utilisation :
- | Version
+ Version
Website
Désinstaller
@@ -113,6 +115,14 @@
Trouver plus de thèmes
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Police (barre de recherche)
Police (liste des résultats)
Mode fenêtré
diff --git a/Flow.Launcher/Languages/it.xaml b/Flow.Launcher/Languages/it.xaml
index 0367cc4ac..1aabba84d 100644
--- a/Flow.Launcher/Languages/it.xaml
+++ b/Flow.Launcher/Languages/it.xaml
@@ -62,6 +62,8 @@
Modifica il punteggio minimo richiesto per i risultati.
Dovrebbe usare il Pinyin
Consente di utilizzare il Pinyin per la ricerca. Il Pinyin è il sistema standard di ortografia romanizzata per la traduzione del cinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
L'effetto ombra non è consentito mentre il tema corrente ha un effetto di sfocatura abilitato
@@ -86,7 +88,7 @@
da
Tempo di avvio:
Tempo ricerca:
- | Versione
+ Versione
Sito Web
Disinstalla
@@ -113,6 +115,14 @@
Sfoglia per altri temi
Come creare un tema
Ciao
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Font campo di ricerca
Font campo risultati
Modalità finestra
diff --git a/Flow.Launcher/Languages/ja.xaml b/Flow.Launcher/Languages/ja.xaml
index 31b33a653..d93021301 100644
--- a/Flow.Launcher/Languages/ja.xaml
+++ b/Flow.Launcher/Languages/ja.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
初期化時間:
クエリ時間:
- | バージョン
+ バージョン
ウェブサイト
アンインストール
@@ -113,6 +115,14 @@
テーマを探す
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
検索ボックスのフォント
検索結果一覧のフォント
ウィンドウモード
diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml
index cd4134c7b..3c79cc045 100644
--- a/Flow.Launcher/Languages/ko.xaml
+++ b/Flow.Launcher/Languages/ko.xaml
@@ -34,7 +34,7 @@
포커스 잃으면 Flow Launcher 숨김
새 버전 알림 끄기
검색 창 위치
- Remember Last Position
+ 마지막 위치 기억
마우스 위치 화면 - 중앙
마우스 위치 화면 - 중앙 상단
마우스 위치 화면 - 좌측 상단
@@ -62,6 +62,8 @@
검색 결과에 필요한 최소 매치 점수를 변경합니다.
항상 Pinyin 사용
Pinyin을 사용하여 검색할 수 있습니다. Pinyin (병음) 은 로마자 중국어 입력 방식입니다.
+ 항상 미리보기
+ 항상 미리보기 패널이 열린 상태로 Flow를 시작합니다. F1키로 미리보기를 on/off 합니다.
반투명 흐림 효과를 사용하는 경우, 그림자 효과를 쓸 수 없습니다.
@@ -86,7 +88,7 @@
제작자
초기화 시간:
쿼리 시간:
- | 버전
+ 버전
웹사이트
제거
@@ -113,6 +115,14 @@
테마 갤러리
테마 제작 안내
안녕하세요!
+ 탐색기
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ 프로그램
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
쿼리 상자 글꼴
결과 항목 글꼴
윈도우 모드
@@ -137,14 +147,14 @@
Flow Launcher 단축키
Flow Launcher를 열 때 사용할 단축키를 입력합니다.
결과 선택 단축키
- 결과 목록을 선택하는 단축키입니다.
+ 결과 항목을 선택하는 단축키입니다.
단축키 표시
결과창에서 결과 선택 단축키를 표시합니다.
사용자지정 쿼리 단축키
- Custom Query Shortcut
+ 사용자 지정 쿼리 단축어
Built-in Shortcut
쿼리
- Shortcut
+ 단축어
확장
설명
삭제
@@ -187,7 +197,7 @@
아이콘
Flow Launcher를 {0}번 실행했습니다.
업데이트 확인
- Become A Sponsor
+ 후원하기
새 버전({0})이 있습니다. Flow Launcher를 재시작하세요.
업데이트 확인을 실패했습니다. api.github.com로의 연결 또는 프록시 설정을 확인해주세요.
@@ -196,7 +206,7 @@
릴리즈 노트
사용 팁
- 개발자도구
+ 개발자 도구
설정 폴더
로그 폴더
로그 삭제
@@ -249,7 +259,7 @@
업데이트
- Custom Query Shortcut
+ 사용자 지정 쿼리 단축어
Enter a shortcut that automatically expands to the specified query.
Shortcut already exists, please enter a new Shortcut or edit the existing one.
Shortcut and/or its expansion is empty.
diff --git a/Flow.Launcher/Languages/nb.xaml b/Flow.Launcher/Languages/nb.xaml
index f7808909b..017a2064a 100644
--- a/Flow.Launcher/Languages/nb.xaml
+++ b/Flow.Launcher/Languages/nb.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
Init time:
Query time:
- | Version
+ Version
Website
Uninstall
@@ -113,6 +115,14 @@
Theme Gallery
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Query Box Font
Result Item Font
Window Mode
diff --git a/Flow.Launcher/Languages/nl.xaml b/Flow.Launcher/Languages/nl.xaml
index b599b293f..19ea7cda6 100644
--- a/Flow.Launcher/Languages/nl.xaml
+++ b/Flow.Launcher/Languages/nl.xaml
@@ -62,6 +62,8 @@
Wijzigt de minimale overeenkomst-score die vereist is voor resultaten.
Zou Pinyin moeten gebruiken
Zorgt ervoor dat Pinyin gebruikt kan worden om te zoeken. Pinyin is het standaard systeem van geromaniseerde spelling voor het vertalen van Chinees.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Schaduw effect is niet toegestaan omdat het huidige thema een vervagingseffect heeft
@@ -86,7 +88,7 @@
door
Init tijd:
Query tijd:
- | Versie
+ Versie
Website
Uninstall
@@ -113,6 +115,14 @@
Zoek meer thema´s
Hoe maak je een thema
Hallo daar
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Query Box lettertype
Resultaat Item lettertype
Venster Modus
diff --git a/Flow.Launcher/Languages/pl.xaml b/Flow.Launcher/Languages/pl.xaml
index 53688b3f5..17ad0fec7 100644
--- a/Flow.Launcher/Languages/pl.xaml
+++ b/Flow.Launcher/Languages/pl.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
Czas ładowania:
Czas zapytania:
- | Version
+ Wersja
Website
Odinstalowywanie
@@ -113,6 +115,14 @@
Znajdź więcej skórek
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Programy
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Czcionka okna zapytania
Czcionka okna wyników
Tryb w oknie
diff --git a/Flow.Launcher/Languages/pt-br.xaml b/Flow.Launcher/Languages/pt-br.xaml
index 99850fdc7..23dfbc561 100644
--- a/Flow.Launcher/Languages/pt-br.xaml
+++ b/Flow.Launcher/Languages/pt-br.xaml
@@ -12,14 +12,14 @@
Configurações
Sobre
Sair
- Close
+ Fechar
Copy
- Cut
- Paste
+ Cortar
+ Colar
File
Folder
Text
- Game Mode
+ Modo Gamer
Suspend the use of Hotkeys.
Position Reset
Reset search window position
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
Tempo de inicialização:
Tempo de consulta:
- | Version
+ Versão
Website
Desinstalar
@@ -113,6 +115,14 @@
Ver mais temas
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Fonte da caixa de Consulta
Fonte do Resultado
Modo Janela
diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml
index 5e05f3741..1590d0896 100644
--- a/Flow.Launcher/Languages/pt-pt.xaml
+++ b/Flow.Launcher/Languages/pt-pt.xaml
@@ -62,6 +62,8 @@
Altera a precisão mínima necessário para obter resultados
Pesquisar com Pinyin
Permite a utilização de Pinyin para pesquisar. Pinyin é um sistema normalizado de ortografia romanizada para tradução de mandarim.
+ Pré-visualizar sempre
+ Abrir painel de pré-visualização ao iniciar a aplicação. Prima F1 para comutar esta opção.
O efeito sombra não é permitido com este tema porque o efeito desfocar está ativo
@@ -86,7 +88,7 @@
de
Tempo de arranque:
Tempo de consulta:
- | Versão
+ Versão
Site
Desinstalar
@@ -113,6 +115,14 @@
Galeria de temas
Como criar um tema
Olá
+ Explorador
+ Pesquisar por ficheiros, pastas e conteúdo dos ficheiros
+ Pesquisa Web
+ Pesquisa na web com suporte a diversos motores de pesquisa
+ Programas
+ Iniciar programas como administrador ou utilizador
+ Terminador de processos
+ Terminar processos indesejados
Tipo de letra da consulta
Tipo de letra dos resultados
Modo da janela
diff --git a/Flow.Launcher/Languages/ru.xaml b/Flow.Launcher/Languages/ru.xaml
index 22d134ef2..d6582c588 100644
--- a/Flow.Launcher/Languages/ru.xaml
+++ b/Flow.Launcher/Languages/ru.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
Инициализация:
Запрос:
- | Version
+ Версия
Website
Удалить
@@ -113,6 +115,14 @@
Найти больше тем
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Шрифт запросов
Шрифт результатов
Оконный режим
diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml
index 9d1e7a9fe..00ce6b7ca 100644
--- a/Flow.Launcher/Languages/sk.xaml
+++ b/Flow.Launcher/Languages/sk.xaml
@@ -62,6 +62,8 @@
Mení minimálne skóre zhody potrebné na zobrazenie výsledkov.
Vyhľadávanie pomocou pchin-jin
Umožňuje vyhľadávanie pomocou pchin-jin. Pchin-jin je systém zápisu čínskeho jazyka pomocou písmen latinky.
+ Vždy zobraziť náhľad
+ Pri spustení Flowu vždy otvoriť panel s náhľadom. Stlačením klávesu F1 prepnete náhľad.
Efekt tieňa nie je povolený, kým má aktuálny motív povolený efekt rozostrenia
@@ -86,7 +88,7 @@
od
Inicializácia:
Trvanie dopytu:
- | Verzia
+ Verzia
Webstránka
Odinštalovať
@@ -113,6 +115,14 @@
Galéria motívov
Ako vytvoriť motív
Ahojte
+ Prieskumník
+ Vyhľadávanie súborov, priečinkov a obsahu súborov
+ Webové vyhľadávanie
+ Vyhľadávanie na webe s podporou rôznych vyhľadávačov
+ Program
+ Spúšťanie programov ako správca alebo iný používateľ
+ ProcessKiller
+ Ukončenie nežiaducich procesov
Písmo vyhľadávacieho poľa
Písmo výsledkov
Režim okno
diff --git a/Flow.Launcher/Languages/sr.xaml b/Flow.Launcher/Languages/sr.xaml
index 2fe9f7e30..f32b44652 100644
--- a/Flow.Launcher/Languages/sr.xaml
+++ b/Flow.Launcher/Languages/sr.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
Search with Pinyin
Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
by
Vreme inicijalizacije:
Vreme upita:
- | Version
+ Verzija
Website
Uninstall
@@ -113,6 +115,14 @@
Pretražite još tema
How to create a theme
Hi There
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Font upita
Font rezultata
Režim prozora
diff --git a/Flow.Launcher/Languages/tr.xaml b/Flow.Launcher/Languages/tr.xaml
index c81eed114..d47f0a740 100644
--- a/Flow.Launcher/Languages/tr.xaml
+++ b/Flow.Launcher/Languages/tr.xaml
@@ -62,6 +62,8 @@
Sonuçlar için gereken minimum maç puanını değiştirir.
Pinyin kullanılmalı
Arama yapmak için Pinyin'in kullanılmasına izin verir. Pinyin, Çince'yi çevirmek için standart romanlaştırılmış yazım sistemidir.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Mevcut temada bulanıklık efekti etkinken gölge efektine izin verilmez
@@ -113,6 +115,14 @@
Daha fazla tema bul
Nasıl bir tema yaratılır
Merhaba
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Pencere Yazı Tipi
Sonuç Yazı Tipi
Pencere Modu
diff --git a/Flow.Launcher/Languages/uk-UA.xaml b/Flow.Launcher/Languages/uk-UA.xaml
index 306abff9e..c31bebe25 100644
--- a/Flow.Launcher/Languages/uk-UA.xaml
+++ b/Flow.Launcher/Languages/uk-UA.xaml
@@ -62,6 +62,8 @@
Змінює мінімальний бал збігів, необхідних для результатів.
Використовувати піньїнь
Дозволяє використовувати пінїнь для пошуку. Піньїнь - це стандартна система написання для перекладу китайської.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Ефект тіні не дозволено, коли поточна тема має ефект розмиття
@@ -86,7 +88,7 @@
за
Ініціалізація:
Запит:
- | Версія
+ Версія
Сайт
Uninstall
@@ -113,6 +115,14 @@
Знайти більше тем
Як створити тему
Привіт усім
+ Explorer
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ Program
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
Шрифт запитів
Шрифт результатів
Віконний режим
diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml
index e586e68ba..d96948951 100644
--- a/Flow.Launcher/Languages/zh-cn.xaml
+++ b/Flow.Launcher/Languages/zh-cn.xaml
@@ -34,7 +34,7 @@
失去焦点时自动隐藏 Flow Launcher
不显示新版本提示
搜索窗口位置
- Remember Last Position
+ 记住上次的位置
鼠标所在的屏幕 - 中央
鼠标所在的屏幕 - 顶部中央
鼠标所在的屏幕 - 左上角
@@ -62,6 +62,8 @@
更改匹配成功所需的最低分数。
使用 Pinyin 搜索
允许使用拼音进行搜索.
+ 始终打开预览
+ Flow 启动时总是打开预览面板。按 F1 以切换预览。
当前主题已启用模糊效果,不允许启用阴影效果
@@ -86,7 +88,7 @@
出自
加载耗时:
查询耗时:
- | 版本
+ 版本
官方网站
卸载
@@ -113,6 +115,14 @@
浏览更多主题
如何创建一个主题
你好!
+ 文件管理器
+ 搜索文件、 文件夹和文件内容
+ 网络搜索
+ 使用多个搜索引擎搜索网络
+ 程序
+ 以管理员或其他用户身份启动程序
+ 进程杀手
+ 终止不需要的进程
查询框字体
结果项字体
窗口模式
@@ -141,18 +151,18 @@
显示热键
显示用于打开结果的快捷键。
自定义查询热键
- Custom Query Shortcut
- Built-in Shortcut
+ 自定义查询捷径
+ 内置捷径
查询
捷径
- Expansion
+ 展开
描述
删除
编辑
增加
请选择一项
你确定要删除插件 {0} 的热键吗?
- Are you sure you want to delete shortcut: {0} with expansion {1}?
+ 你确定要删除捷径 {0} (展开为 {1})?
从剪贴板获取文本。
查询窗口阴影效果
阴影效果将占用大量的GPU资源。 如果您的计算机性能有限,则不建议使用。
@@ -187,7 +197,7 @@
图标
你已经激活了 Flow Launcher {0} 次
检查更新
- Become A Sponsor
+ 成为赞助者
发现新版本 {0}, 请重启 Flow Launcher
下载更新失败,请检查您与 api.github.com 的连接状态或检查代理设置
@@ -242,7 +252,7 @@
自定义查询热键
- Press a custom hotkey to open Flow Laucher and input the specified query automatically.
+ 输入一个自定义的快捷键来打开 Flow Laucher 并自动输入指定的查询。
预览
热键不可用,请选择一个新的热键
插件热键不合法
@@ -250,9 +260,9 @@
自定义查询捷径
- Enter a shortcut that automatically expands to the specified query.
- Shortcut already exists, please enter a new Shortcut or edit the existing one.
- Shortcut and/or its expansion is empty.
+ 输入一个捷径,它将自动展开为一个查询。
+ 捷径已存在,请输入一个新的或者编辑已有的。
+ 捷径及其展开均不能为空。
热键不可用
diff --git a/Flow.Launcher/Languages/zh-tw.xaml b/Flow.Launcher/Languages/zh-tw.xaml
index c3e6f42f6..3757c7d4d 100644
--- a/Flow.Launcher/Languages/zh-tw.xaml
+++ b/Flow.Launcher/Languages/zh-tw.xaml
@@ -62,6 +62,8 @@
Changes minimum match score required for results.
拼音搜索
允許使用拼音來搜索.
+ Always Preview
+ Always open preview panel when Flow starts. Press F1 to toggle preview.
Shadow effect is not allowed while current theme has blur effect enabled
@@ -86,7 +88,7 @@
作者
載入耗時:
查詢耗時:
- | 版本
+ 版本
官方網站
解除安裝
@@ -113,6 +115,14 @@
瀏覽更多主題
如何創建一個主題
你好呀
+ 檔案總管
+ Search for files, folders and file contents
+ WebSearch
+ Search the web with different search engine support
+ 程式
+ Launch programs as admin or a different user
+ ProcessKiller
+ Terminate unwanted processes
查詢框字體
結果項字體
視窗模式
diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml
index 49854ed81..9f8d523e0 100644
--- a/Flow.Launcher/MainWindow.xaml
+++ b/Flow.Launcher/MainWindow.xaml
@@ -13,7 +13,6 @@
Title="Flow Launcher"
MinWidth="{Binding MainWindowWidth, Mode=OneWay}"
MaxWidth="{Binding MainWindowWidth, Mode=OneWay}"
- d:DataContext="{d:DesignInstance vm:MainViewModel}"
AllowDrop="True"
AllowsTransparency="True"
Background="Transparent"
@@ -285,6 +284,20 @@
+
@@ -306,72 +319,158 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs
index 6d6549250..56c45aeb0 100644
--- a/Flow.Launcher/MainWindow.xaml.cs
+++ b/Flow.Launcher/MainWindow.xaml.cs
@@ -57,9 +57,9 @@ namespace Flow.Launcher
DataContext = mainVM;
_viewModel = mainVM;
_settings = settings;
-
+
InitializeComponent();
- InitializePosition();
+ InitializePosition();
animationSound.Open(new Uri(AppDomain.CurrentDomain.BaseDirectory + "Resources\\open.wav"));
}
@@ -67,7 +67,7 @@ namespace Flow.Launcher
{
InitializeComponent();
}
-
+
private void OnCopy(object sender, ExecutedRoutedEventArgs e)
{
if (QueryTextBox.SelectionLength == 0)
@@ -106,6 +106,7 @@ namespace Flow.Launcher
WindowsInteropHelper.DisableControlBox(this);
InitProgressbarAnimation();
InitializePosition();
+ PreviewReset();
// since the default main window visibility is visible
// so we need set focus during startup
QueryTextBox.Focus();
@@ -114,6 +115,8 @@ namespace Flow.Launcher
switch (e.PropertyName)
{
case nameof(MainViewModel.MainWindowVisibilityStatus):
+ {
+ Dispatcher.Invoke(() =>
{
if (_viewModel.MainWindowVisibilityStatus)
{
@@ -123,6 +126,7 @@ namespace Flow.Launcher
animationSound.Play();
}
UpdatePosition();
+ PreviewReset();
Activate();
QueryTextBox.Focus();
_settings.ActivateTimes++;
@@ -138,7 +142,7 @@ namespace Flow.Launcher
isProgressBarStoryboardPaused = false;
}
- if(_settings.UseAnimation)
+ if (_settings.UseAnimation)
WindowAnimator();
}
else if (!isProgressBarStoryboardPaused)
@@ -146,27 +150,27 @@ namespace Flow.Launcher
_progressBarStoryboard.Stop(ProgressBar);
isProgressBarStoryboardPaused = true;
}
-
- break;
- }
+ });
+ break;
+ }
case nameof(MainViewModel.ProgressBarVisibility):
+ {
+ Dispatcher.Invoke(() =>
{
- Dispatcher.Invoke(() =>
+ if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused)
{
- if (_viewModel.ProgressBarVisibility == Visibility.Hidden && !isProgressBarStoryboardPaused)
- {
- _progressBarStoryboard.Stop(ProgressBar);
- isProgressBarStoryboardPaused = true;
- }
- else if (_viewModel.MainWindowVisibilityStatus &&
- isProgressBarStoryboardPaused)
- {
- _progressBarStoryboard.Begin(ProgressBar, true);
- isProgressBarStoryboardPaused = false;
- }
- });
- break;
- }
+ _progressBarStoryboard.Stop(ProgressBar);
+ isProgressBarStoryboardPaused = true;
+ }
+ else if (_viewModel.MainWindowVisibilityStatus &&
+ isProgressBarStoryboardPaused)
+ {
+ _progressBarStoryboard.Begin(ProgressBar, true);
+ isProgressBarStoryboardPaused = false;
+ }
+ });
+ break;
+ }
case nameof(MainViewModel.QueryTextCursorMovedToEnd):
if (_viewModel.QueryTextCursorMovedToEnd)
{
@@ -249,35 +253,45 @@ namespace Flow.Launcher
contextMenu = new ContextMenu();
- var openIcon = new FontIcon { Glyph = "\ue71e" };
+ var openIcon = new FontIcon
+ {
+ Glyph = "\ue71e"
+ };
var open = new MenuItem
{
- Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")",
- Icon = openIcon
+ Header = InternationalizationManager.Instance.GetTranslation("iconTrayOpen") + " (" + _settings.Hotkey + ")", Icon = openIcon
+ };
+ var gamemodeIcon = new FontIcon
+ {
+ Glyph = "\ue7fc"
};
- var gamemodeIcon = new FontIcon { Glyph = "\ue7fc" };
var gamemode = new MenuItem
{
- Header = InternationalizationManager.Instance.GetTranslation("GameMode"),
- Icon = gamemodeIcon
+ Header = InternationalizationManager.Instance.GetTranslation("GameMode"), Icon = gamemodeIcon
+ };
+ var positionresetIcon = new FontIcon
+ {
+ Glyph = "\ue73f"
};
- var positionresetIcon = new FontIcon { Glyph = "\ue73f" };
var positionreset = new MenuItem
{
- Header = InternationalizationManager.Instance.GetTranslation("PositionReset"),
- Icon = positionresetIcon
+ Header = InternationalizationManager.Instance.GetTranslation("PositionReset"), Icon = positionresetIcon
+ };
+ var settingsIcon = new FontIcon
+ {
+ Glyph = "\ue713"
};
- var settingsIcon = new FontIcon { Glyph = "\ue713" };
var settings = new MenuItem
{
- Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"),
- Icon = settingsIcon
+ Header = InternationalizationManager.Instance.GetTranslation("iconTraySettings"), Icon = settingsIcon
+ };
+ var exitIcon = new FontIcon
+ {
+ Glyph = "\ue7e8"
};
- var exitIcon = new FontIcon { Glyph = "\ue7e8" };
var exit = new MenuItem
{
- Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"),
- Icon = exitIcon
+ Header = InternationalizationManager.Instance.GetTranslation("iconTrayExit"), Icon = exitIcon
};
open.Click += (o, e) => _viewModel.ToggleFlowLauncher();
@@ -340,22 +354,20 @@ namespace Flow.Launcher
}
private async void PositionReset()
{
- _viewModel.Show();
- await Task.Delay(300); // If don't give a time, Positioning will be weird.
- Left = HorizonCenter();
- Top = VerticalCenter();
+ _viewModel.Show();
+ await Task.Delay(300); // If don't give a time, Positioning will be weird.
+ Left = HorizonCenter();
+ Top = VerticalCenter();
}
private void InitProgressbarAnimation()
{
- var da = new DoubleAnimation(ProgressBar.X2, ActualWidth + 150,
- new Duration(new TimeSpan(0, 0, 0, 0, 1600)));
- var da1 = new DoubleAnimation(ProgressBar.X1, ActualWidth + 50, new Duration(new TimeSpan(0, 0, 0, 0, 1600)));
+ var da = new DoubleAnimation(ProgressBar.X2, ActualWidth + 100, new Duration(new TimeSpan(0, 0, 0, 0, 1600)));
+ var da1 = new DoubleAnimation(ProgressBar.X1, ActualWidth + 0, new Duration(new TimeSpan(0, 0, 0, 0, 1600)));
Storyboard.SetTargetProperty(da, new PropertyPath("(Line.X2)"));
Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X1)"));
_progressBarStoryboard.Children.Add(da);
_progressBarStoryboard.Children.Add(da1);
_progressBarStoryboard.RepeatBehavior = RepeatBehavior.Forever;
-
_viewModel.ProgressBarVisibility = Visibility.Hidden;
isProgressBarStoryboardPaused = true;
}
@@ -390,11 +402,11 @@ namespace Flow.Launcher
};
var IconMotion = new DoubleAnimation
{
- From = 12,
- To = 0,
- EasingFunction = easing,
- Duration = TimeSpan.FromSeconds(0.36),
- FillBehavior = FillBehavior.Stop
+ From = 12,
+ To = 0,
+ EasingFunction = easing,
+ Duration = TimeSpan.FromSeconds(0.36),
+ FillBehavior = FillBehavior.Stop
};
var ClockOpacity = new DoubleAnimation
@@ -466,10 +478,10 @@ namespace Flow.Launcher
private async void OnContextMenusForSettingsClick(object sender, RoutedEventArgs e)
{
_viewModel.Hide();
-
- if(_settings.UseAnimation)
+
+ if (_settings.UseAnimation)
await Task.Delay(100);
-
+
App.API.OpenSettingDialog();
}
@@ -487,7 +499,7 @@ namespace Flow.Launcher
// and always after Settings window is closed.
if (_settings.UseAnimation)
await Task.Delay(100);
-
+
if (_settings.HideWhenDeactive)
{
_viewModel.Hide();
@@ -525,7 +537,7 @@ namespace Flow.Launcher
_viewModel.Show();
}
}
-
+
public double HorizonCenter()
{
var screen = Screen.FromPoint(System.Windows.Forms.Cursor.Position);
@@ -607,9 +619,9 @@ namespace Flow.Launcher
&& QueryTextBox.Text.Length > 0
&& QueryTextBox.CaretIndex == QueryTextBox.Text.Length)
{
- var queryWithoutActionKeyword =
- QueryBuilder.Build(QueryTextBox.Text.Trim(), PluginManager.NonGlobalPlugins).Search;
-
+ var queryWithoutActionKeyword =
+ QueryBuilder.Build(QueryTextBox.Text.Trim(), PluginManager.NonGlobalPlugins)?.Search;
+
if (FilesFolders.IsLocationPathString(queryWithoutActionKeyword))
{
_viewModel.BackspaceCommand.Execute(null);
@@ -618,17 +630,50 @@ namespace Flow.Launcher
}
}
break;
+ case Key.F1:
+ PreviewToggle();
+ e.Handled = true;
+ break;
+
default:
break;
}
}
+ public void PreviewReset()
+ {
+ if (_settings.AlwaysPreview == true)
+ {
+ ResultArea.SetValue(Grid.ColumnSpanProperty, 1);
+ Preview.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ ResultArea.SetValue(Grid.ColumnSpanProperty, 2);
+ Preview.Visibility = Visibility.Collapsed;
+ }
+ }
+ public void PreviewToggle()
+ {
+
+ if (Preview.Visibility == Visibility.Collapsed)
+ {
+ ResultArea.SetValue(Grid.ColumnSpanProperty, 1);
+ Preview.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ ResultArea.SetValue(Grid.ColumnSpanProperty, 2);
+ Preview.Visibility = Visibility.Collapsed;
+ }
+ }
+
private void MoveQueryTextToEnd()
{
// QueryTextBox seems to be update with a DispatcherPriority as low as ContextIdle.
// To ensure QueryTextBox is up to date with QueryText from the View, we need to Dispatch with such a priority
- Dispatcher.Invoke(() => QueryTextBox.CaretIndex = QueryTextBox.Text.Length, System.Windows.Threading.DispatcherPriority.ContextIdle);
+ Dispatcher.Invoke(() => QueryTextBox.CaretIndex = QueryTextBox.Text.Length);
}
public void InitializeColorScheme()
@@ -645,7 +690,7 @@ namespace Flow.Launcher
private void QueryTextBox_KeyUp(object sender, KeyEventArgs e)
{
- if(_viewModel.QueryText != QueryTextBox.Text)
+ if (_viewModel.QueryText != QueryTextBox.Text)
{
BindingExpression be = QueryTextBox.GetBindingExpression(System.Windows.Controls.TextBox.TextProperty);
be.UpdateSource();
diff --git a/Flow.Launcher/PriorityChangeWindow.xaml.cs b/Flow.Launcher/PriorityChangeWindow.xaml.cs
index fe846e78b..e2fe46adc 100644
--- a/Flow.Launcher/PriorityChangeWindow.xaml.cs
+++ b/Flow.Launcher/PriorityChangeWindow.xaml.cs
@@ -1,6 +1,5 @@
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Core.Resource;
-using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
using Flow.Launcher.ViewModel;
using System;
@@ -23,14 +22,12 @@ namespace Flow.Launcher
public partial class PriorityChangeWindow : Window
{
private readonly PluginPair plugin;
- private Settings settings;
private readonly Internationalization translater = InternationalizationManager.Instance;
private readonly PluginViewModel pluginViewModel;
- public PriorityChangeWindow(string pluginId, Settings settings, PluginViewModel pluginViewModel)
+ public PriorityChangeWindow(string pluginId, PluginViewModel pluginViewModel)
{
InitializeComponent();
plugin = PluginManager.GetPluginForId(pluginId);
- this.settings = settings;
this.pluginViewModel = pluginViewModel;
if (plugin == null)
{
@@ -74,4 +71,4 @@ namespace Flow.Launcher
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index 5fef5499b..927055971 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -141,6 +141,8 @@ namespace Flow.Launcher
public void AddActionKeyword(string pluginId, string newActionKeyword) =>
PluginManager.AddActionKeyword(pluginId, newActionKeyword);
+ public bool ActionKeywordAssigned(string actionKeyword) => PluginManager.ActionKeywordRegistered(actionKeyword);
+
public void RemoveActionKeyword(string pluginId, string oldActionKeyword) =>
PluginManager.RemoveActionKeyword(pluginId, oldActionKeyword);
diff --git a/Flow.Launcher/Resources/CustomControlTemplate.xaml b/Flow.Launcher/Resources/CustomControlTemplate.xaml
index 07897361c..451dc5344 100644
--- a/Flow.Launcher/Resources/CustomControlTemplate.xaml
+++ b/Flow.Launcher/Resources/CustomControlTemplate.xaml
@@ -3230,4 +3230,26 @@
+
+
+
diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml
index d44830f52..8f3238303 100644
--- a/Flow.Launcher/ResultListBox.xaml
+++ b/Flow.Launcher/ResultListBox.xaml
@@ -7,7 +7,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:Flow.Launcher.ViewModel"
MaxHeight="{Binding MaxHeight}"
- Margin="{DynamicResource ResultMargin}"
HorizontalContentAlignment="Stretch"
d:DataContext="{d:DesignInstance vm:ResultsViewModel}"
d:DesignHeight="100"
@@ -58,6 +57,7 @@
diff --git a/Flow.Launcher/ResultListBox.xaml.cs b/Flow.Launcher/ResultListBox.xaml.cs
index 6bd1490c3..78720e86a 100644
--- a/Flow.Launcher/ResultListBox.xaml.cs
+++ b/Flow.Launcher/ResultListBox.xaml.cs
@@ -92,24 +92,36 @@ namespace Flow.Launcher
private Point start;
private string path;
private string query;
+ // this method is called by the UI thread, which is single threaded, so we can be sloppy with locking
+ private bool isDragging;
private void ResultList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
- if (Mouse.DirectlyOver is not FrameworkElement { DataContext: ResultViewModel result })
- return;
+ if (Mouse.DirectlyOver is not FrameworkElement
+ {
+ DataContext: ResultViewModel
+ {
+ Result:
+ {
+ CopyText: { } copyText,
+ OriginQuery.RawQuery: { } rawQuery
+ }
+ }
+ }) return;
- path = result.Result.CopyText;
- query = result.Result.OriginQuery.RawQuery;
+ path = copyText;
+ query = rawQuery;
start = e.GetPosition(null);
+ isDragging = true;
}
-
private void ResultList_MouseMove(object sender, MouseEventArgs e)
{
- if (e.LeftButton != MouseButtonState.Pressed)
+ if (e.LeftButton != MouseButtonState.Pressed || !isDragging)
{
start = default;
path = string.Empty;
query = string.Empty;
+ isDragging = false;
return;
}
@@ -123,15 +135,19 @@ namespace Flow.Launcher
|| Math.Abs(diff.Y) < SystemParameters.MinimumVerticalDragDistance)
return;
+ isDragging = false;
+
var data = new DataObject(DataFormats.FileDrop, new[]
{
path
});
- DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
- App.API.ChangeQuery(query, true);
-
- e.Handled = true;
+ // Reassigning query to a new variable because for some reason
+ // after DragDrop.DoDragDrop call, 'query' loses its content, i.e. becomes empty string
+ var rawQuery = query;
+ var effect = DragDrop.DoDragDrop((DependencyObject)sender, data, DragDropEffects.Move | DragDropEffects.Copy);
+ if (effect == DragDropEffects.Move)
+ App.API.ChangeQuery(rawQuery, true);
}
private void ResultListBox_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml
index 64ed98002..3a15fea8a 100644
--- a/Flow.Launcher/SettingWindow.xaml
+++ b/Flow.Launcher/SettingWindow.xaml
@@ -443,10 +443,9 @@
Margin="2,2,2,0"
Panel.ZIndex="1"
Background="Transparent"
- IsItemsHost="true"
+ IsItemsHost="true"
LastChildFill="False" />
-
+
@@ -732,6 +731,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1022,6 +1037,7 @@
DockPanel.Dock="Right"
FontSize="14"
KeyDown="PluginFilterTxb_OnKeyDown"
+ Loaded="Plugin_GotFocus"
LostFocus="RefreshPluginListEventHandler"
Text=""
TextAlignment="Left"
@@ -1146,7 +1162,7 @@
x:Name="PriorityButton"
Margin="0,0,22,0"
VerticalAlignment="Center"
- Click="OnPluginPriorityClick"
+ Command="{Binding EditPluginPriorityCommand}"
Content="{Binding Priority, UpdateSourceTrigger=PropertyChanged}"
Cursor="Hand"
ToolTip="{DynamicResource priorityToolTip}">
@@ -1224,7 +1240,7 @@
Height="34"
Margin="5,0,0,0"
HorizontalAlignment="Right"
- Click="OnPluginActionKeywordsClick"
+ Command="{Binding SetActionKeywordsCommand}"
Content="{Binding ActionKeywordsText}"
Cursor="Hand"
DockPanel.Dock="Right"
@@ -1274,7 +1290,7 @@
-
-
-
-
-
-
-
-
-
+ FontSize="11"
+ Foreground="{DynamicResource PluginInfoColor}"
+ Text="|" />
+
+
+
-
+ RequestNavigate="OnRequestNavigate"
+ Style="{DynamicResource HyperLinkBtnStyle}"
+ TextDecorations="None">
+
-
-
+ Style="{DynamicResource LinkBtnStyle}"
+ Text=""
+ ToolTip="{DynamicResource plugin_uninstall}" />
+ Margin="10,0,5,0"
+ Style="{DynamicResource LinkBtnStyle}"
+ Text=""
+ ToolTip="{DynamicResource pluginDirectory}">
+
+
+
+
-
-
-
-
@@ -1448,6 +1428,7 @@
DockPanel.Dock="Right"
FontSize="14"
KeyDown="PluginStoreFilterTxb_OnKeyDown"
+ Loaded="PluginStore_GotFocus"
LostFocus="RefreshPluginStoreEventHandler"
Text=""
TextAlignment="Left"
@@ -1798,7 +1779,12 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
-
+
@@ -1816,6 +1802,7 @@
@@ -1853,7 +1840,10 @@
-
+
diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs
index 73926c091..924ee4ae2 100644
--- a/Flow.Launcher/SettingWindow.xaml.cs
+++ b/Flow.Launcher/SettingWindow.xaml.cs
@@ -5,7 +5,6 @@ using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
-using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.ViewModel;
using ModernWpf;
using ModernWpf.Controls;
@@ -18,7 +17,6 @@ using System.Windows.Data;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Interop;
-using System.Windows.Media;
using System.Windows.Navigation;
using Button = System.Windows.Controls.Button;
using Control = System.Windows.Controls.Control;
@@ -181,44 +179,11 @@ namespace Flow.Launcher
{
if (sender is Control { DataContext: PluginViewModel pluginViewModel })
{
- PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(pluginViewModel.PluginPair.Metadata.ID, settings, pluginViewModel);
+ PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(pluginViewModel.PluginPair.Metadata.ID, pluginViewModel);
priorityChangeWindow.ShowDialog();
}
}
- private void OnPluginActionKeywordsClick(object sender, RoutedEventArgs e)
- {
- var id = viewModel.SelectedPlugin.PluginPair.Metadata.ID;
- ActionKeywords changeKeywordsWindow = new ActionKeywords(id, settings, viewModel.SelectedPlugin);
- changeKeywordsWindow.ShowDialog();
- }
-
- private void OnPluginNameClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- {
- var website = viewModel.SelectedPlugin.PluginPair.Metadata.Website;
- if (!string.IsNullOrEmpty(website))
- {
- var uri = new Uri(website);
- if (Uri.CheckSchemeName(uri.Scheme))
- {
- website.OpenInBrowserTab();
- }
- }
- }
- }
-
- private void OnPluginDirecotyClick(object sender, MouseButtonEventArgs e)
- {
- if (e.ChangedButton == MouseButton.Left)
- {
- var directory = viewModel.SelectedPlugin.PluginPair.Metadata.PluginDirectory;
- if (!string.IsNullOrEmpty(directory))
- PluginManager.API.OpenDirectory(directory);
- }
- }
-
#endregion
#region Proxy
@@ -289,22 +254,6 @@ namespace Flow.Launcher
}
}
- private static T FindParent(DependencyObject child) where T : DependencyObject
- {
- //get parent item
- DependencyObject parentObject = VisualTreeHelper.GetParent(child);
-
- //we've reached the end of the tree
- if (parentObject == null) return null;
-
- //check if the parent matches the type we're looking for
- T parent = parentObject as T;
- if (parent != null)
- return parent;
- else
- return FindParent(parentObject);
- }
-
private void OnExternalPluginInstallClick(object sender, RoutedEventArgs e)
{
if (sender is not Button { DataContext: PluginStoreItemViewModel plugin } button)
@@ -327,8 +276,6 @@ namespace Flow.Launcher
var name = viewModel.SelectedPlugin.PluginPair.Metadata.Name;
viewModel.DisplayPluginQuery($"uninstall {name}", PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"));
}
-
-
}
private void OnExternalPluginUninstallClick(object sender, RoutedEventArgs e)
@@ -554,5 +501,15 @@ namespace Flow.Launcher
};
}
+
+ private void PluginStore_GotFocus(object sender, RoutedEventArgs e)
+ {
+ Keyboard.Focus(pluginStoreFilterTxb);
+ }
+
+ private void Plugin_GotFocus(object sender, RoutedEventArgs e)
+ {
+ Keyboard.Focus(pluginFilterTxb);
+ }
}
}
diff --git a/Flow.Launcher/Themes/Base.xaml b/Flow.Launcher/Themes/Base.xaml
index 94740a730..0b4460d46 100644
--- a/Flow.Launcher/Themes/Base.xaml
+++ b/Flow.Launcher/Themes/Base.xaml
@@ -248,8 +248,9 @@
-
+
+
@@ -273,6 +274,11 @@
+
+
+
+
+
@@ -356,7 +362,22 @@
-
+
@@ -384,7 +405,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/BlurBlack Darker.xaml b/Flow.Launcher/Themes/BlurBlack Darker.xaml
index 88c48afee..67a47f4cf 100644
--- a/Flow.Launcher/Themes/BlurBlack Darker.xaml
+++ b/Flow.Launcher/Themes/BlurBlack Darker.xaml
@@ -37,7 +37,6 @@
x:Key="WindowBorderStyle"
BasedOn="{StaticResource BaseWindowBorderStyle}"
TargetType="{x:Type Border}">
-
@@ -48,6 +47,15 @@
+
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/BlurBlack.xaml b/Flow.Launcher/Themes/BlurBlack.xaml
index f74578a74..0f1264292 100644
--- a/Flow.Launcher/Themes/BlurBlack.xaml
+++ b/Flow.Launcher/Themes/BlurBlack.xaml
@@ -45,6 +45,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/BlurWhite.xaml b/Flow.Launcher/Themes/BlurWhite.xaml
index 2d42d49bc..4406724b8 100644
--- a/Flow.Launcher/Themes/BlurWhite.xaml
+++ b/Flow.Launcher/Themes/BlurWhite.xaml
@@ -155,4 +155,28 @@
+
+
+
+
diff --git a/Flow.Launcher/Themes/Bullet Light.xaml b/Flow.Launcher/Themes/Bullet Light.xaml
index 0dc3b33d2..1f776a2ee 100644
--- a/Flow.Launcher/Themes/Bullet Light.xaml
+++ b/Flow.Launcher/Themes/Bullet Light.xaml
@@ -87,7 +87,7 @@
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
-
+
@@ -156,6 +156,7 @@
+
@@ -181,4 +182,28 @@
TargetType="{x:Type TextBlock}">
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/Circle Light.xaml b/Flow.Launcher/Themes/Circle Light.xaml
index 7e14a29a6..e52e3a957 100644
--- a/Flow.Launcher/Themes/Circle Light.xaml
+++ b/Flow.Launcher/Themes/Circle Light.xaml
@@ -69,7 +69,7 @@
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
-
+
@@ -163,4 +163,28 @@
TargetType="{x:Type TextBlock}">
-
\ No newline at end of file
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/Circle System.xaml b/Flow.Launcher/Themes/Circle System.xaml
index b00f03e76..2b2ce7ca3 100644
--- a/Flow.Launcher/Themes/Circle System.xaml
+++ b/Flow.Launcher/Themes/Circle System.xaml
@@ -70,7 +70,7 @@
x:Key="SeparatorStyle"
BasedOn="{StaticResource BaseSeparatorStyle}"
TargetType="{x:Type Rectangle}">
-
+
@@ -164,4 +164,28 @@
TargetType="{x:Type TextBlock}">
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/Cyan Dark.xaml b/Flow.Launcher/Themes/Cyan Dark.xaml
index c79044f00..60bc09002 100644
--- a/Flow.Launcher/Themes/Cyan Dark.xaml
+++ b/Flow.Launcher/Themes/Cyan Dark.xaml
@@ -164,7 +164,7 @@
0
0
- 0 0 0 0
+ 0 0 0 4
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/Darker Glass.xaml b/Flow.Launcher/Themes/Darker Glass.xaml
index a33f98b09..89b6dfa01 100644
--- a/Flow.Launcher/Themes/Darker Glass.xaml
+++ b/Flow.Launcher/Themes/Darker Glass.xaml
@@ -5,7 +5,7 @@
-
+ 0 0 0 8
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/Darker.xaml b/Flow.Launcher/Themes/Darker.xaml
new file mode 100644
index 000000000..d1abbe978
--- /dev/null
+++ b/Flow.Launcher/Themes/Darker.xaml
@@ -0,0 +1,100 @@
+
+
+
+
+ 0 0 0 8
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #4d4d4d
+
+
+
+
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/Discord Dark.xaml b/Flow.Launcher/Themes/Discord Dark.xaml
index 74c1719c4..5315c7644 100644
--- a/Flow.Launcher/Themes/Discord Dark.xaml
+++ b/Flow.Launcher/Themes/Discord Dark.xaml
@@ -5,6 +5,7 @@
+ 0 0 0 6
+
+
+
+
diff --git a/Flow.Launcher/Themes/Dracula.xaml b/Flow.Launcher/Themes/Dracula.xaml
index c01b67c74..ce3350728 100644
--- a/Flow.Launcher/Themes/Dracula.xaml
+++ b/Flow.Launcher/Themes/Dracula.xaml
@@ -5,6 +5,7 @@
+ 0 0 0 6
+
+
+
+
diff --git a/Flow.Launcher/Themes/Gray.xaml b/Flow.Launcher/Themes/Gray.xaml
index eb8b48f43..d8d344e21 100644
--- a/Flow.Launcher/Themes/Gray.xaml
+++ b/Flow.Launcher/Themes/Gray.xaml
@@ -70,7 +70,7 @@
TargetType="{x:Type Rectangle}">
-
+
-
\ No newline at end of file
+
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/League.xaml b/Flow.Launcher/Themes/League.xaml
index 9f4a9a628..7fbe56187 100644
--- a/Flow.Launcher/Themes/League.xaml
+++ b/Flow.Launcher/Themes/League.xaml
@@ -137,4 +137,29 @@
TargetType="{x:Type TextBlock}">
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/Midnight.xaml b/Flow.Launcher/Themes/Midnight.xaml
index b52fe87e1..91ff620d5 100644
--- a/Flow.Launcher/Themes/Midnight.xaml
+++ b/Flow.Launcher/Themes/Midnight.xaml
@@ -163,4 +163,29 @@
TargetType="{x:Type TextBlock}">
-
\ No newline at end of file
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/Nord Darker.xaml b/Flow.Launcher/Themes/Nord Darker.xaml
index 840e44b3c..d9ddb3076 100644
--- a/Flow.Launcher/Themes/Nord Darker.xaml
+++ b/Flow.Launcher/Themes/Nord Darker.xaml
@@ -3,6 +3,7 @@
+ 0 0 0 8
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/Pink.xaml b/Flow.Launcher/Themes/Pink.xaml
index 96dae2545..dc97e4320 100644
--- a/Flow.Launcher/Themes/Pink.xaml
+++ b/Flow.Launcher/Themes/Pink.xaml
@@ -2,6 +2,7 @@
+ 0 0 0 4
+
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/Sublime.xaml b/Flow.Launcher/Themes/Sublime.xaml
index 417bd723e..6df69ad3e 100644
--- a/Flow.Launcher/Themes/Sublime.xaml
+++ b/Flow.Launcher/Themes/Sublime.xaml
@@ -5,6 +5,7 @@
+ 0 0 0 8
+
+
+
+
diff --git a/Flow.Launcher/Themes/Ubuntu.xaml b/Flow.Launcher/Themes/Ubuntu.xaml
index ea10c0e82..33f232699 100644
--- a/Flow.Launcher/Themes/Ubuntu.xaml
+++ b/Flow.Launcher/Themes/Ubuntu.xaml
@@ -169,7 +169,7 @@
0
0 0 0 0
- 0 0 0 0
+ 0 0 0 8
+
+
+
+
\ No newline at end of file
diff --git a/Flow.Launcher/Themes/Win10Light.xaml b/Flow.Launcher/Themes/Win10Light.xaml
index 12ba01f71..eaa66e7fd 100644
--- a/Flow.Launcher/Themes/Win10Light.xaml
+++ b/Flow.Launcher/Themes/Win10Light.xaml
@@ -5,12 +5,19 @@
+ 0 0 0 4
+
+
+
+
+
diff --git a/Flow.Launcher/Themes/Win11Dark.xaml b/Flow.Launcher/Themes/Win11Dark.xaml
index 4660eae8f..5abb96cce 100644
--- a/Flow.Launcher/Themes/Win11Dark.xaml
+++ b/Flow.Launcher/Themes/Win11Dark.xaml
@@ -5,6 +5,7 @@
+ 0 0 0 8
+
+
+
+
diff --git a/Flow.Launcher/Themes/Win11Light.xaml b/Flow.Launcher/Themes/Win11Light.xaml
index 4c0769d4d..e2c37236c 100644
--- a/Flow.Launcher/Themes/Win11Light.xaml
+++ b/Flow.Launcher/Themes/Win11Light.xaml
@@ -5,6 +5,7 @@
+ 0 0 0 8
+
+
+
+
diff --git a/Flow.Launcher/Themes/Win11System.xaml b/Flow.Launcher/Themes/Win11System.xaml
index 42f0579a7..df09249be 100644
--- a/Flow.Launcher/Themes/Win11System.xaml
+++ b/Flow.Launcher/Themes/Win11System.xaml
@@ -6,6 +6,7 @@
+ 0 0 0 8
+
+
+
+
diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index 4db8e3df3..e05e47041 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -24,6 +24,7 @@ using System.IO;
using System.Collections.Specialized;
using CommunityToolkit.Mvvm.Input;
using System.Globalization;
+using System.Windows.Threading;
namespace Flow.Launcher.ViewModel
{
@@ -65,7 +66,8 @@ namespace Flow.Launcher.ViewModel
Settings = settings;
Settings.PropertyChanged += (_, args) =>
{
- switch (args.PropertyName) {
+ switch (args.PropertyName)
+ {
case nameof(Settings.WindowSize):
OnPropertyChanged(nameof(MainWindowWidth));
break;
@@ -365,6 +367,7 @@ namespace Flow.Launcher.ViewModel
set
{
_queryText = value;
+ OnPropertyChanged();
Query();
}
}
@@ -426,19 +429,24 @@ namespace Flow.Launcher.ViewModel
/// Force query even when Query Text doesn't change
public void ChangeQueryText(string queryText, bool reQuery = false)
{
- if (QueryText != queryText)
+ Application.Current.Dispatcher.Invoke(() =>
{
- // re-query is done in QueryText's setter method
- QueryText = queryText;
- // set to false so the subsequent set true triggers
- // PropertyChanged and MoveQueryTextToEnd is called
- QueryTextCursorMovedToEnd = false;
- }
- else if (reQuery)
- {
- Query();
- }
- QueryTextCursorMovedToEnd = true;
+ if (QueryText != queryText)
+ {
+
+ // re-query is done in QueryText's setter method
+ QueryText = queryText;
+ // set to false so the subsequent set true triggers
+ // PropertyChanged and MoveQueryTextToEnd is called
+ QueryTextCursorMovedToEnd = false;
+
+ }
+ else if (reQuery)
+ {
+ Query();
+ }
+ QueryTextCursorMovedToEnd = true;
+ });
}
public bool LastQuerySelected { get; set; }
@@ -752,11 +760,14 @@ namespace Flow.Launcher.ViewModel
queryBuilder.Replace('@' + shortcut.Key, shortcut.Expand());
}
- foreach (var shortcut in builtInShortcuts)
+ Application.Current.Dispatcher.Invoke(() =>
{
- queryBuilder.Replace(shortcut.Key, shortcut.Expand());
- queryBuilderTmp.Replace(shortcut.Key, shortcut.Expand());
- }
+ foreach (var shortcut in builtInShortcuts)
+ {
+ queryBuilder.Replace(shortcut.Key, shortcut.Expand());
+ queryBuilderTmp.Replace(shortcut.Key, shortcut.Expand());
+ }
+ });
// show expanded builtin shortcuts
// use private field to avoid infinite recursion
@@ -803,7 +814,7 @@ namespace Flow.Launcher.ViewModel
Action = _ =>
{
_topMostRecord.AddOrUpdate(result);
- App.API.ShowMsg("Success");
+ App.API.ShowMsg(InternationalizationManager.Instance.GetTranslation("success"));
return false;
}
};
@@ -879,11 +890,14 @@ namespace Flow.Launcher.ViewModel
public void Show()
{
- MainWindowVisibility = Visibility.Visible;
+ Application.Current.Dispatcher.Invoke(() =>
+ {
+ MainWindowVisibility = Visibility.Visible;
- MainWindowVisibilityStatus = true;
+ MainWindowOpacity = 1;
- MainWindowOpacity = 1;
+ MainWindowVisibilityStatus = true;
+ });
}
public async void Hide()
diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs
index 725857e2f..65ba657ba 100644
--- a/Flow.Launcher/ViewModel/PluginViewModel.cs
+++ b/Flow.Launcher/ViewModel/PluginViewModel.cs
@@ -1,14 +1,16 @@
-using System.Threading.Tasks;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using Flow.Launcher.Plugin;
using Flow.Launcher.Infrastructure.Image;
using Flow.Launcher.Core.Plugin;
using System.Windows.Controls;
+using CommunityToolkit.Mvvm.Input;
+using Flow.Launcher.Core.Resource;
namespace Flow.Launcher.ViewModel
{
- public class PluginViewModel : BaseModel
+ public partial class PluginViewModel : BaseModel
{
private readonly PluginPair _pluginPair;
public PluginPair PluginPair
@@ -35,7 +37,7 @@ namespace Flow.Launcher.ViewModel
{
get
{
- if (_image == ImageLoader.DefaultImage)
+ if (_image == ImageLoader.MissingImage)
LoadIconAsync();
return _image;
@@ -53,6 +55,7 @@ namespace Flow.Launcher.ViewModel
set
{
_isExpanded = value;
+
OnPropertyChanged();
OnPropertyChanged(nameof(SettingControl));
}
@@ -60,18 +63,20 @@ namespace Flow.Launcher.ViewModel
private Control _settingControl;
private bool _isExpanded;
- public Control SettingControl
+ public Control SettingControl
=> IsExpanded
? _settingControl
??= PluginPair.Plugin is not ISettingProvider settingProvider
- ? new Control()
- : settingProvider.CreateSettingPanel()
+ ? new Control()
+ : settingProvider.CreateSettingPanel()
: null;
- private ImageSource _image = ImageLoader.DefaultImage;
+ private ImageSource _image = ImageLoader.MissingImage;
public Visibility ActionKeywordsVisibility => PluginPair.Metadata.ActionKeywords.Count == 1 ? Visibility.Visible : Visibility.Collapsed;
public string InitilizaTime => PluginPair.Metadata.InitTime + "ms";
public string QueryTime => PluginPair.Metadata.AvgQueryTime + "ms";
+ public string Version => InternationalizationManager.Instance.GetTranslation("plugin_query_version") + " " + PluginPair.Metadata.Version;
+ public string InitAndQueryTime => InternationalizationManager.Instance.GetTranslation("plugin_init_time") + " " + PluginPair.Metadata.InitTime + "ms, " + InternationalizationManager.Instance.GetTranslation("plugin_query_time") + " " + PluginPair.Metadata.AvgQueryTime + "ms";
public string ActionKeywordsText => string.Join(Query.ActionKeywordSeparator, PluginPair.Metadata.ActionKeywords);
public int Priority => PluginPair.Metadata.Priority;
@@ -87,7 +92,29 @@ namespace Flow.Launcher.ViewModel
OnPropertyChanged(nameof(Priority));
}
+ [RelayCommand]
+ private void EditPluginPriority()
+ {
+ PriorityChangeWindow priorityChangeWindow = new PriorityChangeWindow(PluginPair.Metadata.ID, this);
+ priorityChangeWindow.ShowDialog();
+ }
+
+ [RelayCommand]
+ private void OpenPluginDirectory()
+ {
+ var directory = PluginPair.Metadata.PluginDirectory;
+ if (!string.IsNullOrEmpty(directory))
+ PluginManager.API.OpenDirectory(directory);
+ }
+
public static bool IsActionKeywordRegistered(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
+
+ [RelayCommand]
+ private void SetActionKeywords()
+ {
+ ActionKeywords changeKeywordsWindow = new ActionKeywords(this);
+ changeKeywordsWindow.ShowDialog();
+ }
}
}
diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs
index 2d61f6cab..0fadeccdf 100644
--- a/Flow.Launcher/ViewModel/ResultViewModel.cs
+++ b/Flow.Launcher/ViewModel/ResultViewModel.cs
@@ -19,47 +19,49 @@ namespace Flow.Launcher.ViewModel
public ResultViewModel(Result result, Settings settings)
{
- if (result != null)
+ Settings = settings;
+
+ if (result == null)
{
- Result = result;
+ return;
+ }
+ Result = result;
- if (Result.Glyph is { FontFamily: not null } glyph)
+ if (Result.Glyph is { FontFamily: not null } glyph)
+ {
+ // Checks if it's a system installed font, which does not require path to be provided.
+ if (glyph.FontFamily.EndsWith(".ttf") || glyph.FontFamily.EndsWith(".otf"))
{
- // Checks if it's a system installed font, which does not require path to be provided.
- if (glyph.FontFamily.EndsWith(".ttf") || glyph.FontFamily.EndsWith(".otf"))
+ string fontFamilyPath = glyph.FontFamily;
+
+ if (!Path.IsPathRooted(fontFamilyPath))
{
- string fontFamilyPath = glyph.FontFamily;
+ fontFamilyPath = Path.Combine(Result.PluginDirectory, fontFamilyPath);
+ }
- if (!Path.IsPathRooted(fontFamilyPath))
+ if (fonts.ContainsKey(fontFamilyPath))
+ {
+ Glyph = glyph with
{
- fontFamilyPath = Path.Combine(Result.PluginDirectory, fontFamilyPath);
- }
-
- if (fonts.ContainsKey(fontFamilyPath))
- {
- Glyph = glyph with
- {
- FontFamily = fonts[fontFamilyPath]
- };
- }
- else
- {
- fontCollection.AddFontFile(fontFamilyPath);
- fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}";
- Glyph = glyph with
- {
- FontFamily = fonts[fontFamilyPath]
- };
- }
+ FontFamily = fonts[fontFamilyPath]
+ };
}
else
{
- Glyph = glyph;
+ fontCollection.AddFontFile(fontFamilyPath);
+ fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}";
+ Glyph = glyph with
+ {
+ FontFamily = fonts[fontFamilyPath]
+ };
}
}
+ else
+ {
+ Glyph = glyph;
+ }
}
- Settings = settings;
}
private Settings Settings { get; }
@@ -67,6 +69,10 @@ namespace Flow.Launcher.ViewModel
public Visibility ShowOpenResultHotkey =>
Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Collapsed;
+ public Visibility ShowDefaultPreview => Result.PreviewPanel == null ? Visibility.Visible : Visibility.Collapsed;
+
+ public Visibility ShowCustomizedPreview => Result.PreviewPanel == null ? Visibility.Collapsed : Visibility.Visible;
+
public Visibility ShowIcon
{
get
@@ -106,7 +112,7 @@ namespace Flow.Launcher.ViewModel
if (!Settings.UseGlyphIcons && !ImgIconAvailable && GlyphAvailable)
return Visibility.Visible;
- return Settings.UseGlyphIcons && GlyphAvailable ? Visibility.Visible : Visibility.Hidden;
+ return Settings.UseGlyphIcons && GlyphAvailable ? Visibility.Visible : Visibility.Collapsed;
}
}
@@ -125,8 +131,10 @@ namespace Flow.Launcher.ViewModel
: Result.SubTitleToolTip;
private volatile bool ImageLoaded;
+ private volatile bool PreviewImageLoaded;
- private ImageSource image = ImageLoader.DefaultImage;
+ private ImageSource image = ImageLoader.LoadingImage;
+ private ImageSource previewImage = ImageLoader.LoadingImage;
public ImageSource Image
{
@@ -143,37 +151,76 @@ namespace Flow.Launcher.ViewModel
private set => image = value;
}
+ public ImageSource PreviewImage
+ {
+ get
+ {
+ if (!PreviewImageLoaded)
+ {
+ PreviewImageLoaded = true;
+ _ = LoadPreviewImageAsync();
+ }
+
+ return previewImage;
+ }
+ private set => previewImage = value;
+ }
+
+ ///
+ /// Determines if to use the full width of the preview panel
+ ///
+ public bool UseBigThumbnail => Result.Preview.IsMedia;
+
public GlyphInfo Glyph { get; set; }
- private async Task LoadImageAsync()
+ private async Task LoadImageInternalAsync(string imagePath, Result.IconDelegate icon, bool loadFullImage)
{
- var imagePath = Result.IcoPath;
- if (string.IsNullOrEmpty(imagePath) && Result.Icon != null)
+ if (string.IsNullOrEmpty(imagePath) && icon != null)
{
try
{
- image = Result.Icon();
- return;
+ var image = await Task.Run(() => icon()).ConfigureAwait(false);
+ return image;
}
catch (Exception e)
{
Log.Exception(
- $"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>",
+ $"|ResultViewModel.LoadImageInternalAsync|IcoPath is empty and exception when calling IconDelegate for result <{Result.Title}> of plugin <{Result.PluginDirectory}>",
e);
}
}
- var loadFullImage = (Path.GetExtension(imagePath) ?? "").Equals(".url", StringComparison.OrdinalIgnoreCase);
+ return await ImageLoader.LoadAsync(imagePath, loadFullImage).ConfigureAwait(false);
+ }
- if (ImageLoader.CacheContainImage(imagePath))
+ private async Task LoadImageAsync()
+ {
+ var imagePath = Result.IcoPath;
+ var iconDelegate = Result.Icon;
+ if (ImageLoader.CacheContainImage(imagePath, false))
{
- // will get here either when icoPath has value\icon delegate is null\when had exception in delegate
- image = await ImageLoader.LoadAsync(imagePath, loadFullImage);
- return;
+ image = await LoadImageInternalAsync(imagePath, iconDelegate, false).ConfigureAwait(false);
}
+ else
+ {
+ // We need to modify the property not field here to trigger the OnPropertyChanged event
+ Image = await LoadImageInternalAsync(imagePath, iconDelegate, false).ConfigureAwait(false);
+ }
+ }
- // We need to modify the property not field here to trigger the OnPropertyChanged event
- Image = await ImageLoader.LoadAsync(imagePath, loadFullImage).ConfigureAwait(false);
+ private async Task LoadPreviewImageAsync()
+ {
+ var imagePath = string.IsNullOrEmpty(Result.Preview.PreviewImagePath) ? Result.IcoPath : Result.Preview.PreviewImagePath;
+ var iconDelegate = Result.Icon;
+ if (ImageLoader.CacheContainImage(imagePath, true))
+ {
+ previewImage = await LoadImageInternalAsync(imagePath, iconDelegate, true).ConfigureAwait(false);
+ }
+ else
+ {
+ // We need to modify the property not field here to trigger the OnPropertyChanged event
+ PreviewImage = await LoadImageInternalAsync(imagePath, iconDelegate, true).ConfigureAwait(false);
+ }
}
public Result Result { get; }
diff --git a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
index 5514951b1..4e4de697b 100644
--- a/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
+++ b/Flow.Launcher/ViewModel/SettingWindowViewModel.cs
@@ -379,6 +379,8 @@ namespace Flow.Launcher.ViewModel
await PluginsManifest.UpdateManifestAsync();
OnPropertyChanged(nameof(ExternalPlugins));
}
+
+
internal void DisplayPluginQuery(string queryToDisplay, PluginPair plugin, int actionKeywordPosition = 0)
{
@@ -632,26 +634,26 @@ namespace Flow.Launcher.ViewModel
{
new Result
{
- Title = "Explorer",
- SubTitle = "Search for files, folders and file contents",
+ Title = InternationalizationManager.Instance.GetTranslation("SampleTitleExplorer"),
+ SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleExplorer"),
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Explorer\Images\explorer.png")
},
new Result
{
- Title = "WebSearch",
- SubTitle = "Search the web with different search engine support",
+ Title = InternationalizationManager.Instance.GetTranslation("SampleTitleWebSearch"),
+ SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleWebSearch"),
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.WebSearch\Images\web_search.png")
},
new Result
{
- Title = "Program",
- SubTitle = "Launch programs as admin or a different user",
+ Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProgram"),
+ SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProgram"),
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.Program\Images\program.png")
},
new Result
{
- Title = "ProcessKiller",
- SubTitle = "Terminate unwanted processes",
+ Title = InternationalizationManager.Instance.GetTranslation("SampleTitleProcessKiller"),
+ SubTitle = InternationalizationManager.Instance.GetTranslation("SampleSubTitleProcessKiller"),
IcoPath = Path.Combine(Constant.ProgramDirectory, @"Plugins\Flow.Launcher.Plugin.ProcessKiller\Images\app.png")
}
};
diff --git a/Flow.Launcher/WelcomeWindow.xaml b/Flow.Launcher/WelcomeWindow.xaml
index d797a623b..c7820d436 100644
--- a/Flow.Launcher/WelcomeWindow.xaml
+++ b/Flow.Launcher/WelcomeWindow.xaml
@@ -7,13 +7,13 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.modernwpf.com/2019"
Name="FlowWelcomeWindow"
- Title="Welcome to Flow Launcher"
- Activated="OnActivated"
+ Title="{DynamicResource Welcome_Page1_Title}"
Width="550"
Height="650"
- MouseDown="window_MouseDown"
+ Activated="OnActivated"
Background="{DynamicResource Color00B}"
Foreground="{DynamicResource PopupTextColor}"
+ MouseDown="window_MouseDown"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
@@ -48,7 +48,7 @@
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource Color05B}"
- Text="Welcome to Flow Launcher" />
+ Text="{DynamicResource Welcome_Page1_Title}" />
LoadAllBookmarks(Settings setting)
{
-
- var chromeBookmarks = new ChromeBookmarkLoader();
- var mozBookmarks = new FirefoxBookmarkLoader();
- var edgeBookmarks = new EdgeBookmarkLoader();
-
var allBookmarks = new List();
- // Add Firefox bookmarks
- allBookmarks.AddRange(mozBookmarks.GetBookmarks());
+ if (setting.LoadChromeBookmark)
+ {
+ // Add Chrome bookmarks
+ var chromeBookmarks = new ChromeBookmarkLoader();
+ allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
+ }
- // Add Chrome bookmarks
- allBookmarks.AddRange(chromeBookmarks.GetBookmarks());
+ if (setting.LoadFirefoxBookmark)
+ {
+ // Add Firefox bookmarks
+ var mozBookmarks = new FirefoxBookmarkLoader();
+ allBookmarks.AddRange(mozBookmarks.GetBookmarks());
+ }
- // Add Edge (Chromium) bookmarks
- allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
+ if (setting.LoadEdgeBookmark)
+ {
+ // Add Edge (Chromium) bookmarks
+ var edgeBookmarks = new EdgeBookmarkLoader();
+ allBookmarks.AddRange(edgeBookmarks.GetBookmarks());
+ }
foreach (var browser in setting.CustomChromiumBrowsers)
{
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Images/bookmark.png b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Images/bookmark.png
index d68cecea1..ee2c7388f 100644
Binary files a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Images/bookmark.png and b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Images/bookmark.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/da.xaml
index 86c09730c..e85688988 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/da.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/da.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Tilføj
Slet
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml
index 0f8227530..7c9b6bc97 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/de.xaml
@@ -19,4 +19,5 @@
Pfad zum Datenverzeichnis
Hinzufügen
Löschen
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/en.xaml
index 8f5396dd7..7c88708f5 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/en.xaml
@@ -21,4 +21,5 @@
Data Directory Path
Add
Delete
+ Others
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es-419.xaml
index b22481631..37c1707d3 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es-419.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es-419.xaml
@@ -19,4 +19,5 @@
Ruta del Directorio de Datos
Añadir
Eliminar
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml
index fcb2beef5..9c375cebf 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/es.xaml
@@ -19,4 +19,5 @@
Ruta del directorio de datos
Añadir
Eliminar
+ Otros
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/fr.xaml
index 485092912..d42c0c6c1 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/fr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/fr.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Ajouter
Supprimer
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/it.xaml
index 789738016..07be31f63 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/it.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/it.xaml
@@ -19,4 +19,5 @@
Percorso cartella Data
Aggiungi
Cancella
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ja.xaml
index 232007a4d..63e759299 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ja.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ja.xaml
@@ -19,4 +19,5 @@
Data Directory Path
追
削除
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ko.xaml
index a5e20a930..694167efb 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ko.xaml
@@ -19,4 +19,5 @@
데이터 디렉토리 위치
추가
삭제
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nb.xaml
index c5d6f77a0..6d6f30884 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nb.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nb.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Add
Delete
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nl.xaml
index d1cbaa001..4c45242da 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/nl.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Toevoegen
Verwijder
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pl.xaml
index 024232350..e0076a376 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pl.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Dodaj
Usu
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-br.xaml
index db29166a0..0131d2a73 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-br.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-br.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Adicionar
Apagar
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-pt.xaml
index eefcc1d2e..9b10c6d47 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-pt.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/pt-pt.xaml
@@ -19,4 +19,5 @@
Caminho do diretório de dados
Adicionar
Eliminar
+ Outros
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ru.xaml
index 545ddbf9a..a631f3ca4 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ru.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/ru.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Добавить
Удалить
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sk.xaml
index b45b437a8..aa65967a9 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sk.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sk.xaml
@@ -19,4 +19,5 @@
Umiestnenie priečinku s dátami
Pridať
Odstrániť
+ Iné
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sr.xaml
index d898a834c..b6a367798 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/sr.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Dodaj
Obriši
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/tr.xaml
index 3e18a245e..bf4a59e65 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/tr.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Ekle
Sil
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/uk-UA.xaml
index f8701ed49..52b9f0b12 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/uk-UA.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/uk-UA.xaml
@@ -19,4 +19,5 @@
Data Directory Path
Додати
Видалити
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-cn.xaml
index 81fa84b44..2f8d718d4 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-cn.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-cn.xaml
@@ -19,4 +19,5 @@
数据文件路径
增加
删除
+ 其他
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml
index a847b8704..0a237d6a0 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Languages/zh-tw.xaml
@@ -19,4 +19,5 @@
檔案目錄路徑
新增
刪除
+ Others
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
index f9127cd3c..d072a362d 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
@@ -183,7 +183,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
return false;
}
},
- IcoPath = "Images\\copylink.png"
+ IcoPath = "Images\\copylink.png",
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8")
}
};
}
@@ -200,4 +201,4 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs
index 5080ad301..17b794e03 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/Settings.cs
@@ -10,6 +10,10 @@ namespace Flow.Launcher.Plugin.BrowserBookmark.Models
public string BrowserPath { get; set; }
+ public bool LoadChromeBookmark { get; set; } = true;
+ public bool LoadFirefoxBookmark { get; set; } = true;
+ public bool LoadEdgeBookmark { get; set; } = true;
+
public ObservableCollection CustomChromiumBrowsers { get; set; } = new();
}
}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml
index 09ad2101b..12a84cb5a 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml
@@ -1,47 +1,66 @@
-
+ x:Class="Flow.Launcher.Plugin.BrowserBookmark.Views.SettingsControl"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ d:DesignHeight="300"
+ d:DesignWidth="500"
+ DataContext="{Binding RelativeSource={RelativeSource Self}}"
+ mc:Ignorable="d">
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+ Margin="0,0,15,0"
+ Click="Others_Click"
+ Content="{DynamicResource flowlauncher_plugin_browserbookmark_others}"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs
index 5f5d3246c..e67c73923 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/SettingsControl.xaml.cs
@@ -1,7 +1,8 @@
-using System.Windows;
+using System.Windows;
using Flow.Launcher.Plugin.BrowserBookmark.Models;
using System.Windows.Input;
using System.ComponentModel;
+using System.Windows.Controls;
namespace Flow.Launcher.Plugin.BrowserBookmark.Views
{
@@ -59,5 +60,15 @@ namespace Flow.Launcher.Plugin.BrowserBookmark.Views
var window = new CustomBrowserSettingWindow(SelectedCustomBrowser);
window.ShowDialog();
}
+ private void Others_Click(object sender, RoutedEventArgs e)
+ {
+
+ if (CustomBrowsersList.Visibility == Visibility.Collapsed)
+ {
+ CustomBrowsersList.Visibility = Visibility.Visible;
+ }
+ else
+ CustomBrowsersList.Visibility = Visibility.Collapsed;
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
index b93630c31..b25996af7 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
@@ -4,7 +4,7 @@
"Name": "Browser Bookmarks",
"Description": "Search your browser bookmarks",
"Author": "qianlifeng, Ioannis G.",
- "Version": "1.7.0",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Images/calculator.png b/Plugins/Flow.Launcher.Plugin.Calculator/Images/calculator.png
index 4bdade8b7..81697a8e8 100644
Binary files a/Plugins/Flow.Launcher.Plugin.Calculator/Images/calculator.png and b/Plugins/Flow.Launcher.Plugin.Calculator/Images/calculator.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
index 547268832..7e47e9109 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
@@ -4,7 +4,7 @@
"Name": "Calculator",
"Description": "Provide mathematical calculations.(Try 5*3-2 in Flow Launcher)",
"Author": "cxfksword",
- "Version": "1.1.12",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Caculator.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs
index 4bc6705f4..4733e09e9 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs
@@ -9,6 +9,8 @@ using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Plugin.Explorer.Search;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
using System.Linq;
+using System.Windows.Controls;
+using System.Windows.Input;
using MessageBox = System.Windows.Forms.MessageBox;
using MessageBoxIcon = System.Windows.Forms.MessageBoxIcon;
using MessageBoxButton = System.Windows.Forms.MessageBoxButtons;
@@ -37,25 +39,25 @@ namespace Flow.Launcher.Plugin.Explorer
var contextMenus = new List();
if (selectedResult.ContextData is SearchResult record)
{
- if (record.Type == ResultType.File)
+ if (record.Type == ResultType.File && !string.IsNullOrEmpty(Settings.EditorPath))
contextMenus.Add(CreateOpenWithEditorResult(record));
if (record.Type == ResultType.Folder && record.WindowsIndexed)
+ {
contextMenus.Add(CreateAddToIndexSearchExclusionListResult(record));
-
+ contextMenus.Add(CreateOpenWithShellResult(record));
+ }
contextMenus.Add(CreateOpenContainingFolderResult(record));
- contextMenus.Add(CreateOpenWindowsIndexingOptions());
-
- if (record.ShowIndexState)
- contextMenus.Add(new Result {Title = "From index search: " + (record.WindowsIndexed ? "Yes" : "No"),
- SubTitle = "Location: " + record.FullPath,
- Score = 501, IcoPath = Constants.IndexImagePath});
+ if (record.WindowsIndexed)
+ {
+ contextMenus.Add(CreateOpenWindowsIndexingOptions());
+ }
var icoPath = (record.Type == ResultType.File) ? Constants.FileImagePath : Constants.FolderImagePath;
var fileOrFolder = (record.Type == ResultType.File) ? "file" : "folder";
- if (!Settings.QuickAccessLinks.Any(x => x.Path == record.FullPath))
+ if (Settings.QuickAccessLinks.All(x => !x.Path.Equals(record.FullPath, StringComparison.OrdinalIgnoreCase)))
{
contextMenus.Add(new Result
{
@@ -63,13 +65,16 @@ namespace Flow.Launcher.Plugin.Explorer
SubTitle = string.Format(Context.API.GetTranslation("plugin_explorer_add_to_quickaccess_subtitle"), fileOrFolder),
Action = (context) =>
{
- Settings.QuickAccessLinks.Add(new AccessLink { Path = record.FullPath, Type = record.Type });
+ Settings.QuickAccessLinks.Add(new AccessLink
+ {
+ Path = record.FullPath, Type = record.Type
+ });
Context.API.ShowMsg(Context.API.GetTranslation("plugin_explorer_addfilefoldersuccess"),
- string.Format(
- Context.API.GetTranslation("plugin_explorer_addfilefoldersuccess_detail"),
- fileOrFolder),
- Constants.ExplorerIconImageFullPath);
+ string.Format(
+ Context.API.GetTranslation("plugin_explorer_addfilefoldersuccess_detail"),
+ fileOrFolder),
+ Constants.ExplorerIconImageFullPath);
ViewModel.Save();
@@ -77,7 +82,8 @@ namespace Flow.Launcher.Plugin.Explorer
},
SubTitleToolTip = Context.API.GetTranslation("plugin_explorer_contextmenu_titletooltip"),
TitleToolTip = Context.API.GetTranslation("plugin_explorer_contextmenu_titletooltip"),
- IcoPath = Constants.QuickAccessImagePath
+ IcoPath = Constants.QuickAccessImagePath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue718"),
});
}
else
@@ -91,10 +97,10 @@ namespace Flow.Launcher.Plugin.Explorer
Settings.QuickAccessLinks.Remove(Settings.QuickAccessLinks.FirstOrDefault(x => x.Path == record.FullPath));
Context.API.ShowMsg(Context.API.GetTranslation("plugin_explorer_removefilefoldersuccess"),
- string.Format(
- Context.API.GetTranslation("plugin_explorer_removefilefoldersuccess_detail"),
- fileOrFolder),
- Constants.ExplorerIconImageFullPath);
+ string.Format(
+ Context.API.GetTranslation("plugin_explorer_removefilefoldersuccess_detail"),
+ fileOrFolder),
+ Constants.ExplorerIconImageFullPath);
ViewModel.Save();
@@ -102,15 +108,16 @@ namespace Flow.Launcher.Plugin.Explorer
},
SubTitleToolTip = Context.API.GetTranslation("plugin_explorer_contextmenu_remove_titletooltip"),
TitleToolTip = Context.API.GetTranslation("plugin_explorer_contextmenu_remove_titletooltip"),
- IcoPath = Constants.RemoveQuickAccessImagePath
+ IcoPath = Constants.RemoveQuickAccessImagePath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uecc9")
});
}
-
+
contextMenus.Add(new Result
{
Title = Context.API.GetTranslation("plugin_explorer_copypath"),
SubTitle = $"Copy the current {fileOrFolder} path to clipboard",
- Action = (context) =>
+ Action = _ =>
{
try
{
@@ -125,18 +132,22 @@ namespace Flow.Launcher.Plugin.Explorer
return false;
}
},
- IcoPath = Constants.CopyImagePath
+ IcoPath = Constants.CopyImagePath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8c8")
});
contextMenus.Add(new Result
{
Title = Context.API.GetTranslation("plugin_explorer_copyfilefolder") + $" {fileOrFolder}",
SubTitle = $"Copy the {fileOrFolder} to clipboard",
- Action = (context) =>
+ Action = _ =>
{
try
{
- Clipboard.SetFileDropList(new System.Collections.Specialized.StringCollection { record.FullPath });
+ Clipboard.SetFileDropList(new System.Collections.Specialized.StringCollection
+ {
+ record.FullPath
+ });
return true;
}
catch (Exception e)
@@ -148,10 +159,12 @@ namespace Flow.Launcher.Plugin.Explorer
}
},
- IcoPath = icoPath
+ IcoPath = icoPath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uf12b")
});
- if (record.Type == ResultType.File || record.Type == ResultType.Folder)
+
+ if (record.Type is ResultType.File or ResultType.Folder)
contextMenus.Add(new Result
{
Title = Context.API.GetTranslation("plugin_explorer_deletefilefolder") + $" {fileOrFolder}",
@@ -161,10 +174,10 @@ namespace Flow.Launcher.Plugin.Explorer
try
{
if (MessageBox.Show(
- string.Format(Context.API.GetTranslation("plugin_explorer_deletefilefolderconfirm"),fileOrFolder),
- string.Empty,
- MessageBoxButton.YesNo,
- MessageBoxIcon.Warning)
+ string.Format(Context.API.GetTranslation("plugin_explorer_deletefilefolderconfirm"), fileOrFolder),
+ string.Empty,
+ MessageBoxButton.YesNo,
+ MessageBoxIcon.Warning)
== DialogResult.No)
return false;
@@ -173,11 +186,11 @@ namespace Flow.Launcher.Plugin.Explorer
else
Directory.Delete(record.FullPath, true);
- Task.Run(() =>
+ _ = Task.Run(() =>
{
Context.API.ShowMsg(Context.API.GetTranslation("plugin_explorer_deletefilefoldersuccess"),
- string.Format(Context.API.GetTranslation("plugin_explorer_deletefilefoldersuccess_detail"), fileOrFolder),
- Constants.ExplorerIconImageFullPath);
+ string.Format(Context.API.GetTranslation("plugin_explorer_deletefilefoldersuccess_detail"), fileOrFolder),
+ Constants.ExplorerIconImageFullPath);
});
}
catch (Exception e)
@@ -190,9 +203,56 @@ namespace Flow.Launcher.Plugin.Explorer
return true;
},
- IcoPath = Constants.DeleteFileFolderImagePath
+ IcoPath = Constants.DeleteFileFolderImagePath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue74d")
});
+ if (record.Type is not ResultType.Volume)
+ {
+ contextMenus.Add(new Result()
+ {
+ Title = Context.API.GetTranslation("plugin_explorer_show_contextmenu_title"),
+ IcoPath = Constants.ShowContextMenuImagePath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue700"),
+ Action = _ =>
+ {
+ if (record.Type is ResultType.Volume)
+ return false;
+
+ var screenWithMouseCursor = System.Windows.Forms.Screen.FromPoint(System.Windows.Forms.Cursor.Position);
+ var xOfScreenCenter = screenWithMouseCursor.WorkingArea.Left + screenWithMouseCursor.WorkingArea.Width / 2;
+ var yOfScreenCenter = screenWithMouseCursor.WorkingArea.Top + screenWithMouseCursor.WorkingArea.Height / 2;
+ var showPosition = new System.Drawing.Point(xOfScreenCenter, yOfScreenCenter);
+
+ switch (record.Type)
+ {
+ case ResultType.File:
+ {
+ var fileInfos = new FileInfo[]
+ {
+ new(record.FullPath)
+ };
+
+ new Peter.ShellContextMenu().ShowContextMenu(fileInfos, showPosition);
+ break;
+ }
+ case ResultType.Folder:
+ {
+ var directoryInfos = new DirectoryInfo[]
+ {
+ new(record.FullPath)
+ };
+
+ new Peter.ShellContextMenu().ShowContextMenu(directoryInfos, showPosition);
+ break;
+ }
+ }
+
+ return false;
+ },
+ });
+ }
+
if (record.Type == ResultType.File && CanRunAsDifferentUser(record.FullPath))
contextMenus.Add(new Result
{
@@ -242,16 +302,18 @@ namespace Flow.Launcher.Plugin.Explorer
return true;
},
- IcoPath = Constants.FolderImagePath
+ IcoPath = Constants.FolderImagePath,
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue838")
};
}
+
+
private Result CreateOpenWithEditorResult(SearchResult record)
{
- string editorPath = "Notepad.exe"; // TODO add the ability to create a custom editor
+ string editorPath = Settings.EditorPath;
- var name = Context.API.GetTranslation("plugin_explorer_openwitheditor")
- + " " + Path.GetFileNameWithoutExtension(editorPath);
+ var name = $"{Context.API.GetTranslation("plugin_explorer_openwitheditor")} {Path.GetFileNameWithoutExtension(editorPath)}";
return new Result
{
@@ -260,12 +322,49 @@ namespace Flow.Launcher.Plugin.Explorer
{
try
{
- Process.Start(editorPath, record.FullPath);
+ Process.Start(new ProcessStartInfo()
+ {
+ FileName = editorPath,
+ ArgumentList = { record.FullPath }
+ });
return true;
}
catch (Exception e)
{
- var message = $"Failed to open editor for file at {record.FullPath}";
+ var raw_message = Context.API.GetTranslation("plugin_explorer_openwitheditor_error");
+ var message = string.Format(raw_message, record.FullPath, Path.GetFileNameWithoutExtension(editorPath), editorPath);
+ LogException(message, e);
+ Context.API.ShowMsgError(message);
+ return false;
+ }
+ },
+ IcoPath = Constants.FileImagePath
+ };
+ }
+
+ private Result CreateOpenWithShellResult(SearchResult record)
+ {
+ string shellPath = Settings.ShellPath;
+
+ var name = $"{Context.API.GetTranslation("plugin_explorer_openwithshell")} {Path.GetFileNameWithoutExtension(shellPath)}";
+
+ return new Result
+ {
+ Title = name,
+ Action = _ =>
+ {
+ try
+ {
+ Process.Start(new ProcessStartInfo()
+ {
+ FileName = shellPath, WorkingDirectory = record.FullPath
+ });
+ return true;
+ }
+ catch (Exception e)
+ {
+ var raw_message = Context.API.GetTranslation("plugin_explorer_openwithshell_error");
+ var message = string.Format(raw_message, record.FullPath, Path.GetFileNameWithoutExtension(shellPath), shellPath);
LogException(message, e);
Context.API.ShowMsgError(message);
return false;
@@ -283,14 +382,17 @@ namespace Flow.Launcher.Plugin.Explorer
SubTitle = Context.API.GetTranslation("plugin_explorer_path") + " " + record.FullPath,
Action = _ =>
{
- if(!Settings.IndexSearchExcludedSubdirectoryPaths.Any(x => x.Path == record.FullPath))
- Settings.IndexSearchExcludedSubdirectoryPaths.Add(new AccessLink { Path = record.FullPath });
+ if (!Settings.IndexSearchExcludedSubdirectoryPaths.Any(x => x.Path == record.FullPath))
+ Settings.IndexSearchExcludedSubdirectoryPaths.Add(new AccessLink
+ {
+ Path = record.FullPath
+ });
Task.Run(() =>
{
- Context.API.ShowMsg(Context.API.GetTranslation("plugin_explorer_excludedfromindexsearch_msg"),
- Context.API.GetTranslation("plugin_explorer_path") +
- " " + record.FullPath, Constants.ExplorerIconImageFullPath);
+ Context.API.ShowMsg(Context.API.GetTranslation("plugin_explorer_excludedfromindexsearch_msg"),
+ Context.API.GetTranslation("plugin_explorer_path") +
+ " " + record.FullPath, Constants.ExplorerIconImageFullPath);
// so the new path can be persisted to storage and not wait till next ViewModel save.
Context.API.SaveAppAllSettings();
@@ -313,11 +415,11 @@ namespace Flow.Launcher.Plugin.Explorer
try
{
var psi = new ProcessStartInfo
- {
- FileName = "control.exe",
- UseShellExecute = true,
- Arguments = "srchadmin.dll"
- };
+ {
+ FileName = "control.exe",
+ UseShellExecute = true,
+ Arguments = "srchadmin.dll"
+ };
Process.Start(psi);
return true;
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x64/Everything.dll b/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x64/Everything.dll
new file mode 100644
index 000000000..6d093b793
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x64/Everything.dll differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x86/Everything.dll b/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x86/Everything.dll
new file mode 100644
index 000000000..de73b87d1
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/EverythingSDK/x86/Everything.dll differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs
new file mode 100644
index 000000000..1a48892f5
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/EngineNotAvailableException.cs
@@ -0,0 +1,48 @@
+#nullable enable
+
+using System;
+using System.Threading.Tasks;
+using System.Windows;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
+using JetBrains.Annotations;
+
+namespace Flow.Launcher.Plugin.Explorer.Exceptions;
+
+public class EngineNotAvailableException : Exception
+{
+ public string EngineName { get; }
+ public string Resolution { get; }
+ public Func>? Action { get; }
+
+ public string? ErrorIcon { get; init; }
+
+ public EngineNotAvailableException(
+ string engineName,
+ string resolution,
+ string message,
+ Func> action = null) : base(message)
+ {
+ EngineName = engineName;
+ Resolution = resolution;
+ Action = action ?? (_ =>
+ {
+ Clipboard.SetDataObject(this.ToString());
+ return ValueTask.FromResult(true);
+ });
+ }
+
+ public EngineNotAvailableException(
+ string engineName,
+ string resolution,
+ string message,
+ Exception innerException) : base(message, innerException)
+ {
+ EngineName = engineName;
+ Resolution = resolution;
+ }
+
+ public override string ToString()
+ {
+ return $"Engine {EngineName} is not available.\n Try to {Resolution}\n {base.ToString()}";
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/SearchException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/SearchException.cs
new file mode 100644
index 000000000..eef81a921
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Exceptions/SearchException.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Exceptions
+{
+ public class SearchException : Exception
+ {
+ public string EngineName { get; }
+ public SearchException(string engineName, string message) : base(message)
+ {
+ EngineName = engineName;
+ }
+
+ public SearchException(string engineName, string message, Exception innerException) : base(message, innerException)
+ {
+ EngineName = engineName;
+ }
+
+ public override string ToString()
+ {
+ return $"{EngineName} Search Exception:\n {base.ToString()}";
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
index b4ab89a36..62cb599a1 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
@@ -8,6 +8,7 @@
true
false
en
+ warnings
@@ -24,6 +25,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+
@@ -39,6 +46,7 @@
+
@@ -47,5 +55,5 @@
-
+
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs
new file mode 100644
index 000000000..3870c4876
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/ShellContextMenu.cs
@@ -0,0 +1,1615 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Runtime.InteropServices;
+using System.Drawing;
+using System.Windows.Forms;
+using System.IO;
+using System.Security.Permissions;
+
+namespace Peter
+{
+ // Code from https://www.codeproject.com/Articles/22012/Explorer-Shell-Context-Menu:
+ ///
+ /// "Stand-alone" shell context menu
+ ///
+ /// It isn't really debugged but is mostly working.
+ /// Create an instance and call ShowContextMenu with a list of FileInfo for the files.
+ /// Limitation is that it only handles files in the same directory but it can be fixed
+ /// by changing the way files are translated into PIDLs.
+ ///
+ /// Based on FileBrowser in C# from CodeProject
+ /// http://www.codeproject.com/useritems/FileBrowser.asp
+ ///
+ /// Hooking class taken from MSDN Magazine Cutting Edge column
+ /// http://msdn.microsoft.com/msdnmag/issues/02/10/CuttingEdge/
+ ///
+ /// Andreas Johansson
+ /// afjohansson@hotmail.com
+ /// http://afjohansson.spaces.live.com
+ ///
+ ///
+ /// ShellContextMenu scm = new ShellContextMenu();
+ /// FileInfo[] files = new FileInfo[1];
+ /// files[0] = new FileInfo(@"c:\windows\notepad.exe");
+ /// scm.ShowContextMenu(this.Handle, files, Cursor.Position);
+ ///
+ public class ShellContextMenu : NativeWindow
+ {
+ #region Constructor
+
+ /// Default constructor
+ public ShellContextMenu()
+ {
+ this.CreateHandle(new CreateParams());
+ }
+
+ #endregion
+
+ #region Destructor
+
+ /// Ensure all resources get released
+ ~ShellContextMenu()
+ {
+ ReleaseAll();
+ }
+
+ #endregion
+
+ #region GetContextMenuInterfaces()
+
+ /// Gets the interfaces to the context menu
+ /// Parent folder
+ /// PIDLs
+ /// true if it got the interfaces, otherwise false
+ private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr)
+ {
+ int nResult = oParentFolder.GetUIObjectOf(
+ IntPtr.Zero,
+ (uint)arrPIDLs.Length,
+ arrPIDLs,
+ ref IID_IContextMenu,
+ IntPtr.Zero,
+ out ctxMenuPtr);
+
+ if (S_OK == nResult)
+ {
+ _oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu));
+
+ return true;
+ }
+ else
+ {
+ ctxMenuPtr = IntPtr.Zero;
+ _oContextMenu = null;
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region Override
+
+ ///
+ /// This method receives WindowMessages. It will make the "Open With" and "Send To" work
+ /// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover
+ /// method of Browser when hovering over a ContextMenu item.
+ ///
+ /// the Message of the Browser's WndProc
+ /// true if the message has been handled, false otherwise
+ protected override void WndProc(ref Message m)
+ {
+ #region IContextMenu
+
+ if (_oContextMenu != null &&
+ m.Msg == (int)WM.MENUSELECT &&
+ (ShellHelper.HiWord(m.WParam) & (nint)MFT.SEPARATOR) == 0 &&
+ (ShellHelper.HiWord(m.WParam) & (nint)MFT.POPUP) == 0)
+ {
+ string info = string.Empty;
+
+ if (ShellHelper.LoWord(m.WParam) == (nint)CMD_CUSTOM.ExpandCollapse)
+ info = "Expands or collapses the current selected item";
+ else
+ {
+ info = "";
+ }
+ }
+
+ #endregion
+
+ #region IContextMenu2
+
+ if (_oContextMenu2 != null &&
+ (m.Msg == (int)WM.INITMENUPOPUP ||
+ m.Msg == (int)WM.MEASUREITEM ||
+ m.Msg == (int)WM.DRAWITEM))
+ {
+ if (_oContextMenu2.HandleMenuMsg(
+ (uint)m.Msg, m.WParam, m.LParam) == S_OK)
+ return;
+ }
+
+ #endregion
+
+ #region IContextMenu3
+
+ if (_oContextMenu3 != null &&
+ m.Msg == (int)WM.MENUCHAR)
+ {
+ if (_oContextMenu3.HandleMenuMsg2(
+ (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == S_OK)
+ return;
+ }
+
+ #endregion
+
+ base.WndProc(ref m);
+ }
+
+ #endregion
+
+ #region InvokeCommand
+
+ private void InvokeCommand(IContextMenu oContextMenu, uint nCmd, string strFolder, Point pointInvoke)
+ {
+ CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX();
+ invoke.cbSize = cbInvokeCommand;
+ invoke.lpVerb = (IntPtr)(nCmd - CMD_FIRST);
+ invoke.lpDirectory = strFolder;
+ invoke.lpVerbW = (IntPtr)(nCmd - CMD_FIRST);
+ invoke.lpDirectoryW = strFolder;
+ invoke.fMask = CMIC.UNICODE | CMIC.PTINVOKE |
+ ((Control.ModifierKeys & Keys.Control) != 0 ? CMIC.CONTROL_DOWN : 0) |
+ ((Control.ModifierKeys & Keys.Shift) != 0 ? CMIC.SHIFT_DOWN : 0);
+ invoke.ptInvoke = new POINT(pointInvoke.X, pointInvoke.Y);
+ invoke.nShow = SW.SHOWNORMAL;
+
+ oContextMenu.InvokeCommand(ref invoke);
+ }
+
+ #endregion
+
+ #region ReleaseAll()
+
+ ///
+ /// Release all allocated interfaces, PIDLs
+ ///
+ private void ReleaseAll()
+ {
+ if (null != _oContextMenu)
+ {
+ Marshal.ReleaseComObject(_oContextMenu);
+ _oContextMenu = null;
+ }
+ if (null != _oContextMenu2)
+ {
+ Marshal.ReleaseComObject(_oContextMenu2);
+ _oContextMenu2 = null;
+ }
+ if (null != _oContextMenu3)
+ {
+ Marshal.ReleaseComObject(_oContextMenu3);
+ _oContextMenu3 = null;
+ }
+ if (null != _oDesktopFolder)
+ {
+ Marshal.ReleaseComObject(_oDesktopFolder);
+ _oDesktopFolder = null;
+ }
+ if (null != _oParentFolder)
+ {
+ Marshal.ReleaseComObject(_oParentFolder);
+ _oParentFolder = null;
+ }
+ if (null != _arrPIDLs)
+ {
+ FreePIDLs(_arrPIDLs);
+ _arrPIDLs = null;
+ }
+ }
+
+ #endregion
+
+ #region GetDesktopFolder()
+
+ ///
+ /// Gets the desktop folder
+ ///
+ /// IShellFolder for desktop folder
+ private IShellFolder GetDesktopFolder()
+ {
+ IntPtr pUnkownDesktopFolder = IntPtr.Zero;
+
+ if (null == _oDesktopFolder)
+ {
+ // Get desktop IShellFolder
+ int nResult = SHGetDesktopFolder(out pUnkownDesktopFolder);
+ if (S_OK != nResult)
+ {
+ throw new ShellContextMenuException("Failed to get the desktop shell folder");
+ }
+ _oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder));
+ }
+
+ return _oDesktopFolder;
+ }
+
+ #endregion
+
+ #region GetParentFolder()
+
+ ///
+ /// Gets the parent folder
+ ///
+ /// Folder path
+ /// IShellFolder for the folder (relative from the desktop)
+ private IShellFolder GetParentFolder(string folderName)
+ {
+ if (null == _oParentFolder)
+ {
+ IShellFolder oDesktopFolder = GetDesktopFolder();
+ if (null == oDesktopFolder)
+ {
+ return null;
+ }
+
+ // Get the PIDL for the folder file is in
+ IntPtr pPIDL = IntPtr.Zero;
+ uint pchEaten = 0;
+ SFGAO pdwAttributes = 0;
+ int nResult = oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, ref pchEaten, out pPIDL, ref pdwAttributes);
+ if (S_OK != nResult)
+ {
+ return null;
+ }
+
+ IntPtr pStrRet = Marshal.AllocCoTaskMem(MAX_PATH * 2 + 4);
+ Marshal.WriteInt32(pStrRet, 0, 0);
+ nResult = _oDesktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet);
+ StringBuilder strFolder = new StringBuilder(MAX_PATH);
+ StrRetToBuf(pStrRet, pPIDL, strFolder, MAX_PATH);
+ Marshal.FreeCoTaskMem(pStrRet);
+ pStrRet = IntPtr.Zero;
+ _strParentFolder = strFolder.ToString();
+
+ // Get the IShellFolder for folder
+ IntPtr pUnknownParentFolder = IntPtr.Zero;
+ nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref IID_IShellFolder, out pUnknownParentFolder);
+ // Free the PIDL first
+ Marshal.FreeCoTaskMem(pPIDL);
+ if (S_OK != nResult)
+ {
+ return null;
+ }
+ _oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder));
+ }
+
+ return _oParentFolder;
+ }
+
+ #endregion
+
+ #region GetPIDLs()
+
+ ///
+ /// Get the PIDLs
+ ///
+ /// Array of FileInfo
+ /// Array of PIDLs
+ protected IntPtr[] GetPIDLs(FileInfo[] arrFI)
+ {
+ if (null == arrFI || 0 == arrFI.Length)
+ {
+ return null;
+ }
+
+ IShellFolder oParentFolder = GetParentFolder(arrFI[0].DirectoryName);
+ if (null == oParentFolder)
+ {
+ return null;
+ }
+
+ IntPtr[] arrPIDLs = new IntPtr[arrFI.Length];
+ int n = 0;
+ foreach (FileInfo fi in arrFI)
+ {
+ // Get the file relative to folder
+ uint pchEaten = 0;
+ SFGAO pdwAttributes = 0;
+ IntPtr pPIDL = IntPtr.Zero;
+ int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
+ if (S_OK != nResult)
+ {
+ FreePIDLs(arrPIDLs);
+ return null;
+ }
+ arrPIDLs[n] = pPIDL;
+ n++;
+ }
+
+ return arrPIDLs;
+ }
+
+ ///
+ /// Get the PIDLs
+ ///
+ /// Array of DirectoryInfo
+ /// Array of PIDLs
+ protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI)
+ {
+ if (null == arrFI || 0 == arrFI.Length)
+ {
+ return null;
+ }
+
+ IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName);
+ if (null == oParentFolder)
+ {
+ return null;
+ }
+
+ IntPtr[] arrPIDLs = new IntPtr[arrFI.Length];
+ int n = 0;
+ foreach (DirectoryInfo fi in arrFI)
+ {
+ // Get the file relative to folder
+ uint pchEaten = 0;
+ SFGAO pdwAttributes = 0;
+ IntPtr pPIDL = IntPtr.Zero;
+ int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
+ if (S_OK != nResult)
+ {
+ FreePIDLs(arrPIDLs);
+ return null;
+ }
+ arrPIDLs[n] = pPIDL;
+ n++;
+ }
+
+ return arrPIDLs;
+ }
+
+ #endregion
+
+ #region FreePIDLs()
+
+ ///
+ /// Free the PIDLs
+ ///
+ /// Array of PIDLs (IntPtr)
+ protected void FreePIDLs(IntPtr[] arrPIDLs)
+ {
+ if (null != arrPIDLs)
+ {
+ for (int n = 0; n < arrPIDLs.Length; n++)
+ {
+ if (arrPIDLs[n] != IntPtr.Zero)
+ {
+ Marshal.FreeCoTaskMem(arrPIDLs[n]);
+ arrPIDLs[n] = IntPtr.Zero;
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region InvokeContextMenuDefault
+
+ private void InvokeContextMenuDefault(FileInfo[] arrFI)
+ {
+ // Release all resources first.
+ ReleaseAll();
+
+ IntPtr pMenu = IntPtr.Zero,
+ iContextMenuPtr = IntPtr.Zero;
+
+ try
+ {
+ _arrPIDLs = GetPIDLs(arrFI);
+ if (null == _arrPIDLs)
+ {
+ ReleaseAll();
+ return;
+ }
+
+ if (false == GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr))
+ {
+ ReleaseAll();
+ return;
+ }
+
+ pMenu = CreatePopupMenu();
+
+ int nResult = _oContextMenu.QueryContextMenu(
+ pMenu,
+ 0,
+ CMD_FIRST,
+ CMD_LAST,
+ CMF.DEFAULTONLY |
+ ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0));
+
+ uint nDefaultCmd = (uint)GetMenuDefaultItem(pMenu, false, 0);
+ if (nDefaultCmd >= CMD_FIRST)
+ {
+ InvokeCommand(_oContextMenu, nDefaultCmd, arrFI[0].DirectoryName, Control.MousePosition);
+ }
+
+ DestroyMenu(pMenu);
+ pMenu = IntPtr.Zero;
+ }
+ catch
+ {
+ throw;
+ }
+ finally
+ {
+ if (pMenu != IntPtr.Zero)
+ {
+ DestroyMenu(pMenu);
+ }
+ ReleaseAll();
+ }
+ }
+
+ #endregion
+
+ #region ShowContextMenu()
+
+ ///
+ /// Shows the context menu
+ ///
+ /// FileInfos (should all be in same directory)
+ /// Where to show the menu
+ public void ShowContextMenu(FileInfo[] files, Point pointScreen)
+ {
+ // Release all resources first.
+ ReleaseAll();
+ _arrPIDLs = GetPIDLs(files);
+ this.ShowContextMenu(pointScreen);
+ }
+
+ ///
+ /// Shows the context menu
+ ///
+ /// DirectoryInfos (should all be in same directory)
+ /// Where to show the menu
+ public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen)
+ {
+ // Release all resources first.
+ ReleaseAll();
+ _arrPIDLs = GetPIDLs(dirs);
+ this.ShowContextMenu(pointScreen);
+ }
+
+ ///
+ /// Shows the context menu
+ ///
+ /// FileInfos (should all be in same directory)
+ /// Where to show the menu
+ private void ShowContextMenu(Point pointScreen)
+ {
+ IntPtr pMenu = IntPtr.Zero,
+ iContextMenuPtr = IntPtr.Zero,
+ iContextMenuPtr2 = IntPtr.Zero,
+ iContextMenuPtr3 = IntPtr.Zero;
+
+ try
+ {
+ if (null == _arrPIDLs)
+ {
+ ReleaseAll();
+ return;
+ }
+
+ if (false == GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr))
+ {
+ ReleaseAll();
+ return;
+ }
+
+ pMenu = CreatePopupMenu();
+
+ int nResult = _oContextMenu.QueryContextMenu(
+ pMenu,
+ 0,
+ CMD_FIRST,
+ CMD_LAST,
+ CMF.EXPLORE |
+ CMF.NORMAL |
+ ((Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0));
+
+ Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu2, out iContextMenuPtr2);
+ Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu3, out iContextMenuPtr3);
+
+ _oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2));
+ _oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3));
+
+ uint nSelected = TrackPopupMenuEx(
+ pMenu,
+ TPM.RETURNCMD,
+ pointScreen.X,
+ pointScreen.Y,
+ this.Handle,
+ IntPtr.Zero);
+
+ DestroyMenu(pMenu);
+ pMenu = IntPtr.Zero;
+
+ if (nSelected != 0)
+ {
+ InvokeCommand(_oContextMenu, nSelected, _strParentFolder, pointScreen);
+ }
+ }
+ catch
+ {
+ throw;
+ }
+ finally
+ {
+ //hook.Uninstall();
+ if (pMenu != IntPtr.Zero)
+ {
+ DestroyMenu(pMenu);
+ }
+
+ if (iContextMenuPtr != IntPtr.Zero)
+ Marshal.Release(iContextMenuPtr);
+
+ if (iContextMenuPtr2 != IntPtr.Zero)
+ Marshal.Release(iContextMenuPtr2);
+
+ if (iContextMenuPtr3 != IntPtr.Zero)
+ Marshal.Release(iContextMenuPtr3);
+
+ ReleaseAll();
+ }
+ }
+
+ #endregion
+
+ #region Local variabled
+
+ private IContextMenu _oContextMenu;
+ private IContextMenu2 _oContextMenu2;
+ private IContextMenu3 _oContextMenu3;
+ private IShellFolder _oDesktopFolder;
+ private IShellFolder _oParentFolder;
+ private IntPtr[] _arrPIDLs;
+ private string _strParentFolder;
+
+ #endregion
+
+ #region Variables and Constants
+
+ private const int MAX_PATH = 260;
+ private const uint CMD_FIRST = 1;
+ private const uint CMD_LAST = 30000;
+
+ private const int S_OK = 0;
+ private const int S_FALSE = 1;
+
+ private static int cbMenuItemInfo = Marshal.SizeOf(typeof(MENUITEMINFO));
+ private static int cbInvokeCommand = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
+
+ #endregion
+
+ #region DLL Import
+
+ // Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace.
+ [DllImport("shell32.dll")]
+ private static extern Int32 SHGetDesktopFolder(out IntPtr ppshf);
+
+ // Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer.
+ [DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
+ private static extern Int32 StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf);
+
+ // The TrackPopupMenuEx function displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu. The shortcut menu can appear anywhere on the screen.
+ [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
+ private static extern uint TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm);
+
+ // The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items.
+ [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
+ private static extern IntPtr CreatePopupMenu();
+
+ // The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies.
+ [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
+ private static extern bool DestroyMenu(IntPtr hMenu);
+
+ // Determines the default menu item on the specified menu
+ [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
+ private static extern int GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags);
+
+ #endregion
+
+ #region Shell GUIDs
+
+ private static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");
+ private static Guid IID_IContextMenu = new Guid("{000214e4-0000-0000-c000-000000000046}");
+ private static Guid IID_IContextMenu2 = new Guid("{000214f4-0000-0000-c000-000000000046}");
+ private static Guid IID_IContextMenu3 = new Guid("{bcfce0a0-ec17-11d0-8d10-00a0c90f2719}");
+
+ #endregion
+
+ #region Structs
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct CWPSTRUCT
+ {
+ public IntPtr lparam;
+ public IntPtr wparam;
+ public int message;
+ public IntPtr hwnd;
+ }
+
+ // Contains extended information about a shortcut menu command
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ private struct CMINVOKECOMMANDINFOEX
+ {
+ public int cbSize;
+ public CMIC fMask;
+ public IntPtr hwnd;
+ public IntPtr lpVerb;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string lpParameters;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string lpDirectory;
+ public SW nShow;
+ public int dwHotKey;
+ public IntPtr hIcon;
+ [MarshalAs(UnmanagedType.LPStr)]
+ public string lpTitle;
+ public IntPtr lpVerbW;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string lpParametersW;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string lpDirectoryW;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string lpTitleW;
+ public POINT ptInvoke;
+ }
+
+ // Contains information about a menu item
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ private struct MENUITEMINFO
+ {
+ public MENUITEMINFO(string text)
+ {
+ cbSize = cbMenuItemInfo;
+ dwTypeData = text;
+ cch = text.Length;
+ fMask = 0;
+ fType = 0;
+ fState = 0;
+ wID = 0;
+ hSubMenu = IntPtr.Zero;
+ hbmpChecked = IntPtr.Zero;
+ hbmpUnchecked = IntPtr.Zero;
+ dwItemData = IntPtr.Zero;
+ hbmpItem = IntPtr.Zero;
+ }
+
+ public int cbSize;
+ public MIIM fMask;
+ public MFT fType;
+ public MFS fState;
+ public uint wID;
+ public IntPtr hSubMenu;
+ public IntPtr hbmpChecked;
+ public IntPtr hbmpUnchecked;
+ public IntPtr dwItemData;
+ [MarshalAs(UnmanagedType.LPTStr)]
+ public string dwTypeData;
+ public int cch;
+ public IntPtr hbmpItem;
+ }
+
+ // A generalized global memory handle used for data transfer operations by the
+ // IAdviseSink, IDataObject, and IOleCache interfaces
+ [StructLayout(LayoutKind.Sequential)]
+ private struct STGMEDIUM
+ {
+ public TYMED tymed;
+ public IntPtr hBitmap;
+ public IntPtr hMetaFilePict;
+ public IntPtr hEnhMetaFile;
+ public IntPtr hGlobal;
+ public IntPtr lpszFileName;
+ public IntPtr pstm;
+ public IntPtr pstg;
+ public IntPtr pUnkForRelease;
+ }
+
+ // Defines the x- and y-coordinates of a point
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ private struct POINT
+ {
+ public POINT(int x, int y)
+ {
+ this.x = x;
+ this.y = y;
+ }
+
+ public int x;
+ public int y;
+ }
+
+ #endregion
+
+ #region Enums
+
+ // Defines the values used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf
+ // methods to specify the type of file or folder names used by those methods
+ [Flags]
+ private enum SHGNO
+ {
+ NORMAL = 0x0000,
+ INFOLDER = 0x0001,
+ FOREDITING = 0x1000,
+ FORADDRESSBAR = 0x4000,
+ FORPARSING = 0x8000
+ }
+
+ // The attributes that the caller is requesting, when calling IShellFolder::GetAttributesOf
+ [Flags]
+ private enum SFGAO : uint
+ {
+ BROWSABLE = 0x8000000,
+ CANCOPY = 1,
+ CANDELETE = 0x20,
+ CANLINK = 4,
+ CANMONIKER = 0x400000,
+ CANMOVE = 2,
+ CANRENAME = 0x10,
+ CAPABILITYMASK = 0x177,
+ COMPRESSED = 0x4000000,
+ CONTENTSMASK = 0x80000000,
+ DISPLAYATTRMASK = 0xfc000,
+ DROPTARGET = 0x100,
+ ENCRYPTED = 0x2000,
+ FILESYSANCESTOR = 0x10000000,
+ FILESYSTEM = 0x40000000,
+ FOLDER = 0x20000000,
+ GHOSTED = 0x8000,
+ HASPROPSHEET = 0x40,
+ HASSTORAGE = 0x400000,
+ HASSUBFOLDER = 0x80000000,
+ HIDDEN = 0x80000,
+ ISSLOW = 0x4000,
+ LINK = 0x10000,
+ NEWCONTENT = 0x200000,
+ NONENUMERATED = 0x100000,
+ READONLY = 0x40000,
+ REMOVABLE = 0x2000000,
+ SHARE = 0x20000,
+ STORAGE = 8,
+ STORAGEANCESTOR = 0x800000,
+ STORAGECAPMASK = 0x70c50008,
+ STREAM = 0x400000,
+ VALIDATE = 0x1000000
+ }
+
+ // Determines the type of items included in an enumeration.
+ // These values are used with the IShellFolder::EnumObjects method
+ [Flags]
+ private enum SHCONTF
+ {
+ FOLDERS = 0x0020,
+ NONFOLDERS = 0x0040,
+ INCLUDEHIDDEN = 0x0080,
+ INIT_ON_FIRST_NEXT = 0x0100,
+ NETPRINTERSRCH = 0x0200,
+ SHAREABLE = 0x0400,
+ STORAGE = 0x0800,
+ }
+
+ // Specifies how the shortcut menu can be changed when calling IContextMenu::QueryContextMenu
+ [Flags]
+ private enum CMF : uint
+ {
+ NORMAL = 0x00000000,
+ DEFAULTONLY = 0x00000001,
+ VERBSONLY = 0x00000002,
+ EXPLORE = 0x00000004,
+ NOVERBS = 0x00000008,
+ CANRENAME = 0x00000010,
+ NODEFAULT = 0x00000020,
+ INCLUDESTATIC = 0x00000040,
+ EXTENDEDVERBS = 0x00000100,
+ RESERVED = 0xffff0000
+ }
+
+ // Flags specifying the information to return when calling IContextMenu::GetCommandString
+ [Flags]
+ private enum GCS : uint
+ {
+ VERBA = 0,
+ HELPTEXTA = 1,
+ VALIDATEA = 2,
+ VERBW = 4,
+ HELPTEXTW = 5,
+ VALIDATEW = 6
+ }
+
+ // Specifies how TrackPopupMenuEx positions the shortcut menu horizontally
+ [Flags]
+ private enum TPM : uint
+ {
+ LEFTBUTTON = 0x0000,
+ RIGHTBUTTON = 0x0002,
+ LEFTALIGN = 0x0000,
+ CENTERALIGN = 0x0004,
+ RIGHTALIGN = 0x0008,
+ TOPALIGN = 0x0000,
+ VCENTERALIGN = 0x0010,
+ BOTTOMALIGN = 0x0020,
+ HORIZONTAL = 0x0000,
+ VERTICAL = 0x0040,
+ NONOTIFY = 0x0080,
+ RETURNCMD = 0x0100,
+ RECURSE = 0x0001,
+ HORPOSANIMATION = 0x0400,
+ HORNEGANIMATION = 0x0800,
+ VERPOSANIMATION = 0x1000,
+ VERNEGANIMATION = 0x2000,
+ NOANIMATION = 0x4000,
+ LAYOUTRTL = 0x8000
+ }
+
+ // The cmd for a custom added menu item
+ private enum CMD_CUSTOM
+ {
+ ExpandCollapse = (int)CMD_LAST + 1
+ }
+
+ // Flags used with the CMINVOKECOMMANDINFOEX structure
+ [Flags]
+ private enum CMIC : uint
+ {
+ HOTKEY = 0x00000020,
+ ICON = 0x00000010,
+ FLAG_NO_UI = 0x00000400,
+ UNICODE = 0x00004000,
+ NO_CONSOLE = 0x00008000,
+ ASYNCOK = 0x00100000,
+ NOZONECHECKS = 0x00800000,
+ SHIFT_DOWN = 0x10000000,
+ CONTROL_DOWN = 0x40000000,
+ FLAG_LOG_USAGE = 0x04000000,
+ PTINVOKE = 0x20000000
+ }
+
+ // Specifies how the window is to be shown
+ [Flags]
+ private enum SW
+ {
+ HIDE = 0,
+ SHOWNORMAL = 1,
+ NORMAL = 1,
+ SHOWMINIMIZED = 2,
+ SHOWMAXIMIZED = 3,
+ MAXIMIZE = 3,
+ SHOWNOACTIVATE = 4,
+ SHOW = 5,
+ MINIMIZE = 6,
+ SHOWMINNOACTIVE = 7,
+ SHOWNA = 8,
+ RESTORE = 9,
+ SHOWDEFAULT = 10,
+ }
+
+ // Window message flags
+ [Flags]
+ private enum WM : uint
+ {
+ ACTIVATE = 0x6,
+ ACTIVATEAPP = 0x1C,
+ AFXFIRST = 0x360,
+ AFXLAST = 0x37F,
+ APP = 0x8000,
+ ASKCBFORMATNAME = 0x30C,
+ CANCELJOURNAL = 0x4B,
+ CANCELMODE = 0x1F,
+ CAPTURECHANGED = 0x215,
+ CHANGECBCHAIN = 0x30D,
+ CHAR = 0x102,
+ CHARTOITEM = 0x2F,
+ CHILDACTIVATE = 0x22,
+ CLEAR = 0x303,
+ CLOSE = 0x10,
+ COMMAND = 0x111,
+ COMPACTING = 0x41,
+ COMPAREITEM = 0x39,
+ CONTEXTMENU = 0x7B,
+ COPY = 0x301,
+ COPYDATA = 0x4A,
+ CREATE = 0x1,
+ CTLCOLORBTN = 0x135,
+ CTLCOLORDLG = 0x136,
+ CTLCOLOREDIT = 0x133,
+ CTLCOLORLISTBOX = 0x134,
+ CTLCOLORMSGBOX = 0x132,
+ CTLCOLORSCROLLBAR = 0x137,
+ CTLCOLORSTATIC = 0x138,
+ CUT = 0x300,
+ DEADCHAR = 0x103,
+ DELETEITEM = 0x2D,
+ DESTROY = 0x2,
+ DESTROYCLIPBOARD = 0x307,
+ DEVICECHANGE = 0x219,
+ DEVMODECHANGE = 0x1B,
+ DISPLAYCHANGE = 0x7E,
+ DRAWCLIPBOARD = 0x308,
+ DRAWITEM = 0x2B,
+ DROPFILES = 0x233,
+ ENABLE = 0xA,
+ ENDSESSION = 0x16,
+ ENTERIDLE = 0x121,
+ ENTERMENULOOP = 0x211,
+ ENTERSIZEMOVE = 0x231,
+ ERASEBKGND = 0x14,
+ EXITMENULOOP = 0x212,
+ EXITSIZEMOVE = 0x232,
+ FONTCHANGE = 0x1D,
+ GETDLGCODE = 0x87,
+ GETFONT = 0x31,
+ GETHOTKEY = 0x33,
+ GETICON = 0x7F,
+ GETMINMAXINFO = 0x24,
+ GETOBJECT = 0x3D,
+ GETSYSMENU = 0x313,
+ GETTEXT = 0xD,
+ GETTEXTLENGTH = 0xE,
+ HANDHELDFIRST = 0x358,
+ HANDHELDLAST = 0x35F,
+ HELP = 0x53,
+ HOTKEY = 0x312,
+ HSCROLL = 0x114,
+ HSCROLLCLIPBOARD = 0x30E,
+ ICONERASEBKGND = 0x27,
+ IME_CHAR = 0x286,
+ IME_COMPOSITION = 0x10F,
+ IME_COMPOSITIONFULL = 0x284,
+ IME_CONTROL = 0x283,
+ IME_ENDCOMPOSITION = 0x10E,
+ IME_KEYDOWN = 0x290,
+ IME_KEYLAST = 0x10F,
+ IME_KEYUP = 0x291,
+ IME_NOTIFY = 0x282,
+ IME_REQUEST = 0x288,
+ IME_SELECT = 0x285,
+ IME_SETCONTEXT = 0x281,
+ IME_STARTCOMPOSITION = 0x10D,
+ INITDIALOG = 0x110,
+ INITMENU = 0x116,
+ INITMENUPOPUP = 0x117,
+ INPUTLANGCHANGE = 0x51,
+ INPUTLANGCHANGEREQUEST = 0x50,
+ KEYDOWN = 0x100,
+ KEYFIRST = 0x100,
+ KEYLAST = 0x108,
+ KEYUP = 0x101,
+ KILLFOCUS = 0x8,
+ LBUTTONDBLCLK = 0x203,
+ LBUTTONDOWN = 0x201,
+ LBUTTONUP = 0x202,
+ LVM_GETEDITCONTROL = 0x1018,
+ LVM_SETIMAGELIST = 0x1003,
+ MBUTTONDBLCLK = 0x209,
+ MBUTTONDOWN = 0x207,
+ MBUTTONUP = 0x208,
+ MDIACTIVATE = 0x222,
+ MDICASCADE = 0x227,
+ MDICREATE = 0x220,
+ MDIDESTROY = 0x221,
+ MDIGETACTIVE = 0x229,
+ MDIICONARRANGE = 0x228,
+ MDIMAXIMIZE = 0x225,
+ MDINEXT = 0x224,
+ MDIREFRESHMENU = 0x234,
+ MDIRESTORE = 0x223,
+ MDISETMENU = 0x230,
+ MDITILE = 0x226,
+ MEASUREITEM = 0x2C,
+ MENUCHAR = 0x120,
+ MENUCOMMAND = 0x126,
+ MENUDRAG = 0x123,
+ MENUGETOBJECT = 0x124,
+ MENURBUTTONUP = 0x122,
+ MENUSELECT = 0x11F,
+ MOUSEACTIVATE = 0x21,
+ MOUSEFIRST = 0x200,
+ MOUSEHOVER = 0x2A1,
+ MOUSELAST = 0x20A,
+ MOUSELEAVE = 0x2A3,
+ MOUSEMOVE = 0x200,
+ MOUSEWHEEL = 0x20A,
+ MOVE = 0x3,
+ MOVING = 0x216,
+ NCACTIVATE = 0x86,
+ NCCALCSIZE = 0x83,
+ NCCREATE = 0x81,
+ NCDESTROY = 0x82,
+ NCHITTEST = 0x84,
+ NCLBUTTONDBLCLK = 0xA3,
+ NCLBUTTONDOWN = 0xA1,
+ NCLBUTTONUP = 0xA2,
+ NCMBUTTONDBLCLK = 0xA9,
+ NCMBUTTONDOWN = 0xA7,
+ NCMBUTTONUP = 0xA8,
+ NCMOUSEHOVER = 0x2A0,
+ NCMOUSELEAVE = 0x2A2,
+ NCMOUSEMOVE = 0xA0,
+ NCPAINT = 0x85,
+ NCRBUTTONDBLCLK = 0xA6,
+ NCRBUTTONDOWN = 0xA4,
+ NCRBUTTONUP = 0xA5,
+ NEXTDLGCTL = 0x28,
+ NEXTMENU = 0x213,
+ NOTIFY = 0x4E,
+ NOTIFYFORMAT = 0x55,
+ NULL = 0x0,
+ PAINT = 0xF,
+ PAINTCLIPBOARD = 0x309,
+ PAINTICON = 0x26,
+ PALETTECHANGED = 0x311,
+ PALETTEISCHANGING = 0x310,
+ PARENTNOTIFY = 0x210,
+ PASTE = 0x302,
+ PENWINFIRST = 0x380,
+ PENWINLAST = 0x38F,
+ POWER = 0x48,
+ PRINT = 0x317,
+ PRINTCLIENT = 0x318,
+ QUERYDRAGICON = 0x37,
+ QUERYENDSESSION = 0x11,
+ QUERYNEWPALETTE = 0x30F,
+ QUERYOPEN = 0x13,
+ QUEUESYNC = 0x23,
+ QUIT = 0x12,
+ RBUTTONDBLCLK = 0x206,
+ RBUTTONDOWN = 0x204,
+ RBUTTONUP = 0x205,
+ RENDERALLFORMATS = 0x306,
+ RENDERFORMAT = 0x305,
+ SETCURSOR = 0x20,
+ SETFOCUS = 0x7,
+ SETFONT = 0x30,
+ SETHOTKEY = 0x32,
+ SETICON = 0x80,
+ SETMARGINS = 0xD3,
+ SETREDRAW = 0xB,
+ SETTEXT = 0xC,
+ SETTINGCHANGE = 0x1A,
+ SHOWWINDOW = 0x18,
+ SIZE = 0x5,
+ SIZECLIPBOARD = 0x30B,
+ SIZING = 0x214,
+ SPOOLERSTATUS = 0x2A,
+ STYLECHANGED = 0x7D,
+ STYLECHANGING = 0x7C,
+ SYNCPAINT = 0x88,
+ SYSCHAR = 0x106,
+ SYSCOLORCHANGE = 0x15,
+ SYSCOMMAND = 0x112,
+ SYSDEADCHAR = 0x107,
+ SYSKEYDOWN = 0x104,
+ SYSKEYUP = 0x105,
+ TCARD = 0x52,
+ TIMECHANGE = 0x1E,
+ TIMER = 0x113,
+ TVM_GETEDITCONTROL = 0x110F,
+ TVM_SETIMAGELIST = 0x1109,
+ UNDO = 0x304,
+ UNINITMENUPOPUP = 0x125,
+ USER = 0x400,
+ USERCHANGED = 0x54,
+ VKEYTOITEM = 0x2E,
+ VSCROLL = 0x115,
+ VSCROLLCLIPBOARD = 0x30A,
+ WINDOWPOSCHANGED = 0x47,
+ WINDOWPOSCHANGING = 0x46,
+ WININICHANGE = 0x1A,
+ SH_NOTIFY = 0x0401
+ }
+
+ // Specifies the content of the new menu item
+ [Flags]
+ private enum MFT : uint
+ {
+ GRAYED = 0x00000003,
+ DISABLED = 0x00000003,
+ CHECKED = 0x00000008,
+ SEPARATOR = 0x00000800,
+ RADIOCHECK = 0x00000200,
+ BITMAP = 0x00000004,
+ OWNERDRAW = 0x00000100,
+ MENUBARBREAK = 0x00000020,
+ MENUBREAK = 0x00000040,
+ RIGHTORDER = 0x00002000,
+ BYCOMMAND = 0x00000000,
+ BYPOSITION = 0x00000400,
+ POPUP = 0x00000010
+ }
+
+ // Specifies the state of the new menu item
+ [Flags]
+ private enum MFS : uint
+ {
+ GRAYED = 0x00000003,
+ DISABLED = 0x00000003,
+ CHECKED = 0x00000008,
+ HILITE = 0x00000080,
+ ENABLED = 0x00000000,
+ UNCHECKED = 0x00000000,
+ UNHILITE = 0x00000000,
+ DEFAULT = 0x00001000
+ }
+
+ // Specifies the content of the new menu item
+ [Flags]
+ private enum MIIM : uint
+ {
+ BITMAP = 0x80,
+ CHECKMARKS = 0x08,
+ DATA = 0x20,
+ FTYPE = 0x100,
+ ID = 0x02,
+ STATE = 0x01,
+ STRING = 0x40,
+ SUBMENU = 0x04,
+ TYPE = 0x10
+ }
+
+ // Indicates the type of storage medium being used in a data transfer
+ [Flags]
+ private enum TYMED
+ {
+ ENHMF = 0x40,
+ FILE = 2,
+ GDI = 0x10,
+ HGLOBAL = 1,
+ ISTORAGE = 8,
+ ISTREAM = 4,
+ MFPICT = 0x20,
+ NULL = 0
+ }
+
+ #endregion
+
+ #region IShellFolder
+
+ [ComImport]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [Guid("000214E6-0000-0000-C000-000000000046")]
+ private interface IShellFolder
+ {
+ // Translates a file object's or folder's display name into an item identifier list.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 ParseDisplayName(
+ IntPtr hwnd,
+ IntPtr pbc,
+ [MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName,
+ ref uint pchEaten,
+ out IntPtr ppidl,
+ ref SFGAO pdwAttributes);
+
+ // Allows a client to determine the contents of a folder by creating an item
+ // identifier enumeration object and returning its IEnumIDList interface.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 EnumObjects(
+ IntPtr hwnd,
+ SHCONTF grfFlags,
+ out IntPtr enumIDList);
+
+ // Retrieves an IShellFolder object for a subfolder.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 BindToObject(
+ IntPtr pidl,
+ IntPtr pbc,
+ ref Guid riid,
+ out IntPtr ppv);
+
+ // Requests a pointer to an object's storage interface.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 BindToStorage(
+ IntPtr pidl,
+ IntPtr pbc,
+ ref Guid riid,
+ out IntPtr ppv);
+
+ // Determines the relative order of two file objects or folders, given their
+ // item identifier lists. Return value: If this method is successful, the
+ // CODE field of the HRESULT contains one of the following values (the code
+ // can be retrived using the helper function GetHResultCode): Negative A
+ // negative return value indicates that the first item should precede
+ // the second (pidl1 < pidl2).
+
+ // Positive A positive return value indicates that the first item should
+ // follow the second (pidl1 > pidl2). Zero A return value of zero
+ // indicates that the two items are the same (pidl1 = pidl2).
+ [PreserveSig]
+ Int32 CompareIDs(
+ IntPtr lParam,
+ IntPtr pidl1,
+ IntPtr pidl2);
+
+ // Requests an object that can be used to obtain information from or interact
+ // with a folder object.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 CreateViewObject(
+ IntPtr hwndOwner,
+ Guid riid,
+ out IntPtr ppv);
+
+ // Retrieves the attributes of one or more file objects or subfolders.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 GetAttributesOf(
+ uint cidl,
+ [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
+ ref SFGAO rgfInOut);
+
+ // Retrieves an OLE interface that can be used to carry out actions on the
+ // specified file objects or folders.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 GetUIObjectOf(
+ IntPtr hwndOwner,
+ uint cidl,
+ [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl,
+ ref Guid riid,
+ IntPtr rgfReserved,
+ out IntPtr ppv);
+
+ // Retrieves the display name for the specified file object or subfolder.
+ // Return value: error code, if any
+ [PreserveSig()]
+ Int32 GetDisplayNameOf(
+ IntPtr pidl,
+ SHGNO uFlags,
+ IntPtr lpName);
+
+ // Sets the display name of a file object or subfolder, changing the item
+ // identifier in the process.
+ // Return value: error code, if any
+ [PreserveSig]
+ Int32 SetNameOf(
+ IntPtr hwnd,
+ IntPtr pidl,
+ [MarshalAs(UnmanagedType.LPWStr)] string pszName,
+ SHGNO uFlags,
+ out IntPtr ppidlOut);
+ }
+
+ #endregion
+
+ #region IContextMenu
+
+ [ComImport()]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ [GuidAttribute("000214e4-0000-0000-c000-000000000046")]
+ private interface IContextMenu
+ {
+ // Adds commands to a shortcut menu
+ [PreserveSig()]
+ Int32 QueryContextMenu(
+ IntPtr hmenu,
+ uint iMenu,
+ uint idCmdFirst,
+ uint idCmdLast,
+ CMF uFlags);
+
+ // Carries out the command associated with a shortcut menu item
+ [PreserveSig()]
+ Int32 InvokeCommand(
+ ref CMINVOKECOMMANDINFOEX info);
+
+ // Retrieves information about a shortcut menu command,
+ // including the help string and the language-independent,
+ // or canonical, name for the command
+ [PreserveSig()]
+ Int32 GetCommandString(
+ uint idcmd,
+ GCS uflags,
+ uint reserved,
+ [MarshalAs(UnmanagedType.LPArray)] byte[] commandstring,
+ int cch);
+ }
+
+ [ComImport, Guid("000214f4-0000-0000-c000-000000000046")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ private interface IContextMenu2
+ {
+ // Adds commands to a shortcut menu
+ [PreserveSig()]
+ Int32 QueryContextMenu(
+ IntPtr hmenu,
+ uint iMenu,
+ uint idCmdFirst,
+ uint idCmdLast,
+ CMF uFlags);
+
+ // Carries out the command associated with a shortcut menu item
+ [PreserveSig()]
+ Int32 InvokeCommand(
+ ref CMINVOKECOMMANDINFOEX info);
+
+ // Retrieves information about a shortcut menu command,
+ // including the help string and the language-independent,
+ // or canonical, name for the command
+ [PreserveSig()]
+ Int32 GetCommandString(
+ uint idcmd,
+ GCS uflags,
+ uint reserved,
+ [MarshalAs(UnmanagedType.LPWStr)] StringBuilder commandstring,
+ int cch);
+
+ // Allows client objects of the IContextMenu interface to
+ // handle messages associated with owner-drawn menu items
+ [PreserveSig]
+ Int32 HandleMenuMsg(
+ uint uMsg,
+ IntPtr wParam,
+ IntPtr lParam);
+ }
+
+ [ComImport, Guid("bcfce0a0-ec17-11d0-8d10-00a0c90f2719")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
+ private interface IContextMenu3
+ {
+ // Adds commands to a shortcut menu
+ [PreserveSig()]
+ Int32 QueryContextMenu(
+ IntPtr hmenu,
+ uint iMenu,
+ uint idCmdFirst,
+ uint idCmdLast,
+ CMF uFlags);
+
+ // Carries out the command associated with a shortcut menu item
+ [PreserveSig()]
+ Int32 InvokeCommand(
+ ref CMINVOKECOMMANDINFOEX info);
+
+ // Retrieves information about a shortcut menu command,
+ // including the help string and the language-independent,
+ // or canonical, name for the command
+ [PreserveSig()]
+ Int32 GetCommandString(
+ uint idcmd,
+ GCS uflags,
+ uint reserved,
+ [MarshalAs(UnmanagedType.LPWStr)] StringBuilder commandstring,
+ int cch);
+
+ // Allows client objects of the IContextMenu interface to
+ // handle messages associated with owner-drawn menu items
+ [PreserveSig]
+ Int32 HandleMenuMsg(
+ uint uMsg,
+ IntPtr wParam,
+ IntPtr lParam);
+
+ // Allows client objects of the IContextMenu3 interface to
+ // handle messages associated with owner-drawn menu items
+ [PreserveSig]
+ Int32 HandleMenuMsg2(
+ uint uMsg,
+ IntPtr wParam,
+ IntPtr lParam,
+ IntPtr plResult);
+ }
+
+ #endregion
+ }
+
+ #region ShellContextMenuException
+
+ public class ShellContextMenuException : Exception
+ {
+ /// Default contructor
+ public ShellContextMenuException()
+ {
+ }
+
+ /// Constructor with message
+ /// Message
+ public ShellContextMenuException(string message)
+ : base(message)
+ {
+ }
+ }
+
+ #endregion
+
+ #region Class HookEventArgs
+
+ public class HookEventArgs : EventArgs
+ {
+ public int HookCode; // Hook code
+ public IntPtr wParam; // WPARAM argument
+ public IntPtr lParam; // LPARAM argument
+ }
+
+ #endregion
+
+ #region Enum HookType
+
+ // Hook Types
+ public enum HookType : int
+ {
+ WH_JOURNALRECORD = 0,
+ WH_JOURNALPLAYBACK = 1,
+ WH_KEYBOARD = 2,
+ WH_GETMESSAGE = 3,
+ WH_CALLWNDPROC = 4,
+ WH_CBT = 5,
+ WH_SYSMSGFILTER = 6,
+ WH_MOUSE = 7,
+ WH_HARDWARE = 8,
+ WH_DEBUG = 9,
+ WH_SHELL = 10,
+ WH_FOREGROUNDIDLE = 11,
+ WH_CALLWNDPROCRET = 12,
+ WH_KEYBOARD_LL = 13,
+ WH_MOUSE_LL = 14
+ }
+
+ #endregion
+
+ #region Class LocalWindowsHook
+
+ public class LocalWindowsHook
+ {
+ // ************************************************************************
+ // Filter function delegate
+ public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
+ // ************************************************************************
+
+ // ************************************************************************
+ // Internal properties
+ protected IntPtr m_hhook = IntPtr.Zero;
+ protected HookProc m_filterFunc = null;
+ protected HookType m_hookType;
+ // ************************************************************************
+
+ // ************************************************************************
+ // Event delegate
+ public delegate void HookEventHandler(object sender, HookEventArgs e);
+ // ************************************************************************
+
+ // ************************************************************************
+ // Event: HookInvoked
+ public event HookEventHandler HookInvoked;
+ protected void OnHookInvoked(HookEventArgs e)
+ {
+ if (HookInvoked != null)
+ HookInvoked(this, e);
+ }
+ // ************************************************************************
+
+ // ************************************************************************
+ // Class constructor(s)
+ public LocalWindowsHook(HookType hook)
+ {
+ m_hookType = hook;
+ m_filterFunc = new HookProc(this.CoreHookProc);
+ }
+ public LocalWindowsHook(HookType hook, HookProc func)
+ {
+ m_hookType = hook;
+ m_filterFunc = func;
+ }
+ // ************************************************************************
+
+ // ************************************************************************
+ // Default filter function
+ protected int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
+ {
+ if (code < 0)
+ return CallNextHookEx(m_hhook, code, wParam, lParam);
+
+ // Let clients determine what to do
+ HookEventArgs e = new HookEventArgs();
+ e.HookCode = code;
+ e.wParam = wParam;
+ e.lParam = lParam;
+ OnHookInvoked(e);
+
+ // Yield to the next hook in the chain
+ return CallNextHookEx(m_hhook, code, wParam, lParam);
+ }
+ // ************************************************************************
+
+ // ************************************************************************
+ // Install the hook
+ public void Install()
+ {
+ m_hhook = SetWindowsHookEx(
+ m_hookType,
+ m_filterFunc,
+ IntPtr.Zero,
+ (int)AppDomain.GetCurrentThreadId());
+ }
+ // ************************************************************************
+
+ // ************************************************************************
+ // Uninstall the hook
+ public void Uninstall()
+ {
+ UnhookWindowsHookEx(m_hhook);
+ }
+ // ************************************************************************
+
+
+ #region Win32 Imports
+
+ // ************************************************************************
+ // Win32: SetWindowsHookEx()
+ [DllImport("user32.dll")]
+ protected static extern IntPtr SetWindowsHookEx(HookType code,
+ HookProc func,
+ IntPtr hInstance,
+ int threadID);
+ // ************************************************************************
+
+ // ************************************************************************
+ // Win32: UnhookWindowsHookEx()
+ [DllImport("user32.dll")]
+ protected static extern int UnhookWindowsHookEx(IntPtr hhook);
+ // ************************************************************************
+
+ // ************************************************************************
+ // Win32: CallNextHookEx()
+ [DllImport("user32.dll")]
+ protected static extern int CallNextHookEx(IntPtr hhook,
+ int code, IntPtr wParam, IntPtr lParam);
+ // ************************************************************************
+
+ #endregion
+ }
+
+ #endregion
+
+ #region ShellHelper
+
+ internal static class ShellHelper
+ {
+ #region Low/High Word
+
+ ///
+ /// Retrieves the High Word of a WParam of a WindowMessage
+ ///
+ /// The pointer to the WParam
+ /// The unsigned integer for the High Word
+ public static nint HiWord(IntPtr ptr)
+ {
+ if (((nint)ptr & 0x80000000) == 0x80000000)
+ return ((nint)ptr >> 16);
+ else
+ return (((nint)ptr >> 16) & 0xffff);
+ }
+
+ ///
+ /// Retrieves the Low Word of a WParam of a WindowMessage
+ ///
+ /// The pointer to the WParam
+ /// The unsigned integer for the Low Word
+ public static nint LoWord(IntPtr ptr)
+ {
+ return (nint)ptr & 0xffff;
+ }
+
+ #endregion
+ }
+
+ #endregion
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranlationHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranlationHelper.cs
new file mode 100644
index 000000000..d3a6552d9
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranlationHelper.cs
@@ -0,0 +1,25 @@
+using Flow.Launcher.Plugin.Everything.Everything;
+using JetBrains.Annotations;
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Helper;
+
+public static class SortOptionTranslationHelper
+{
+ [CanBeNull]
+ public static IPublicAPI API { get; internal set; }
+
+ public static string GetTranslatedName(this SortOption sortOption)
+ {
+ const string prefix = "flowlauncher_plugin_everything_sort_by_";
+
+ ArgumentNullException.ThrowIfNull(API);
+
+ var enumName = Enum.GetName(sortOption);
+ var splited = enumName.Split('_');
+ var name = string.Join('_', splited[..^1]);
+ var direction = splited[^1];
+
+ return $"{API.GetTranslation(prefix + name.ToLower())} {API.GetTranslation(prefix + direction.ToLower())}";
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/context_menu.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/context_menu.png
new file mode 100644
index 000000000..c6138b765
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/Images/context_menu.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/error.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/error.png
new file mode 100644
index 000000000..3b17d925b
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/Images/error.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/everything_error.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/everything_error.png
new file mode 100644
index 000000000..ad3eab179
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/Images/everything_error.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/index.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/index.png
deleted file mode 100644
index a671dac21..000000000
Binary files a/Plugins/Flow.Launcher.Plugin.Explorer/Images/index.png and /dev/null differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error.png
new file mode 100644
index 000000000..518d1d75d
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error2.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error2.png
new file mode 100644
index 000000000..13a3d34fe
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/Images/index_error2.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Images/robot_error.png b/Plugins/Flow.Launcher.Plugin.Explorer/Images/robot_error.png
new file mode 100644
index 000000000..6b4f83b42
Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.Explorer/Images/robot_error.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml
index d4b3afb9d..4431e811e 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/da.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Slet
Rediger
Tilføj
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Færdig
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Slet
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Size
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml
index b462a7b92..8ed355b8c 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/de.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Bitte wähle eine Ordnerverknüpfung
Bist du sicher {0} zu löschen?
@@ -16,41 +16,63 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Löschen
Bearbeiten
Hinzufügen
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor pad
+ Shell Path
Index Search Excluded Paths
+ Verwenden Suchergebnis Standort als ausführbare Arbeitsverzeichnis
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
- Search:
- Path Search:
- File Content Search:
- Index Search:
- Quick Access:
+ Suche:
+ Pfad-Suche:
+ Suche nach Dateiinhalten:
+ Index-Suche:
+ Schnellzugriff:
Current Action Keyword
Fertig
- Enabled
+ Aktiviert
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
- Copy path
- Copy
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
+ Pfad kopieren
+ Kopieren
Löschen
- Path:
- Delete the selected
- Run as different user
- Run the selected using a different user account
+ Pfad:
+ Ausgewählte löschen
+ Als anderer Benutzer ausführen
+ Ausgewählte mit einem anderen Benutzerkonto ausführen
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Everything Service läuft nicht
+ Everything Plugin hat einen Fehler (drücke Enter zum kopieren der Fehlernachricht)
+ Sort By
+ Name
+ Path
+ Größe
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
index e703d8545..d44c67bf0 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
@@ -1,8 +1,8 @@
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:system="clr-namespace:System;assembly=mscorlib">
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -17,15 +17,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Delete
Edit
Add
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -36,12 +43,24 @@
Done
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Delete
@@ -52,6 +71,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -67,5 +89,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Size
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml
index b44ffdce6..8b8d26f4c 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es-419.xaml
@@ -1,7 +1,7 @@
-
+
Por favor, seleccione primero
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Eliminar
Editar
Añadir
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Ruta del editor
+ Shell Path
Index Search Excluded Paths
+ Usar la ubicación de los resultados de búsqueda como directorio de trabajo ejecutable
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Hecho
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Eliminar
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Advertencia: El servicio de Everything no se está ejecutando
+ Error al consultar Everything
+ Ordenar por
+ Name
+ Ruta
+ Size
+ Extensión
+ Tipo de nombre
+ Fecha de creación
+ Fecha de modificación
+ Atributos
+ Lista de archivos Nombre del Archivo
+ Ejecutar cuenta
+ Fecha de cambio reciente
+ Fecha de acceso
+ Fecha de ejecución
+ ↑
+ ↓
+ Advertencia: No es una opción de orden rápido, las búsquedas pueden ser lentas
+
+ Click to Launch or Install Everything
+ Instalación de Everything
+ Instalando el servicio de Everything. Por favor, espere...
+ Servicio de Everything instalado correctamente
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Haga clic aquí para iniciarlo
+ No se ha podido encontrar una instalación de Everything, ¿quieres seleccionar manualmente una ubicación?{0}{0}Click no y todo se instalará automáticamente para usted
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml
index abc97f573..04647d44d 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/es.xaml
@@ -1,7 +1,7 @@
-
+
Por favor haga una selección primero
Por favor, seleccione un enlace de carpeta
¿Está seguro que desea eliminar {0}?
@@ -16,15 +16,22 @@
Explorador alternativo
Se ha producido un error durante la búsqueda: {0}
-
+
Eliminar
Editar
Añadir
+ Configuración general
Personalizar palabras clave de acción
Enlaces de acceso rápido
+ Configuración Everything
+ Ordenar por:
+ Ruta de Everything:
+ Iniciar oculto
+ Ruta del editor
+ Ruta del Shell
Rutas excluídas del índice de búsqueda
+ Usar la ubicación de los resultados de búsqueda como directorio de trabajo ejecutable
Usar búsqueda indexada para buscar rutas
- Al activar esta opción, los directorios/archivos indexados se mostrarán más rápidamente, pero si un directorio/archivo no está indexado, no se mostrará. Si se ha agregado un directorio/archivo a la ruta de exclusión del índice de búsqueda se seguirá mostrando incluso si la opción está activada
Opciones de indexación
Buscar:
Ruta de búsqueda:
@@ -35,12 +42,24 @@
Aceptar
Activado
Cuando esté desactivado, Flow no ejecutará esta opción de búsqueda, y además volverá a '*' para liberar la palabra clave de acción
+ Everything
+ Índice de Windows
+ Enumeración directa
-
+ Motor de búsqueda de contenido
+ Motor de búsqueda recursiva de directorio
+ Motor de búsqueda del Índice
+ Abrir opciones de indexación de Windows
+
+
Explorador
Busca y gestiona archivos y carpetas. El explorador utiliza el índice de búsqueda de Windows
-
+
+ Ctrl + Entrar para abrir el directorio
+ Ctrl + Entrar para abrir la carpeta contenedora
+
+
Copiar ruta
Copiar
Eliminar
@@ -51,6 +70,9 @@
Abrir carpeta contenedora
Abre la ubicación que contiene el archivo o carpeta
Abrir con el editor:
+ No se pudo abrir el archivo en {0} con el editor {1} en {2}
+ Abrir con Shell:
+ No se pudo abrir la carpeta {0} con Shell {1} en {2}
Excluir la carpeta actual y sus subcarpetas del índice de búsqueda
Excluido del índice de búsqueda
Abrir opciones de indexación de Windows
@@ -66,5 +88,36 @@
Eliminar del acceso rápido
Eliminar del acceso rápido
Elimina {0} actual del acceso rápido
+ Mostrar menú contextual de Windows
+
+
+ No se ha podido cargar Everything SDK
+ Advertencia: El servicio de Everything no se está ejecutando
+ Error al consultar Everything
+ Ordenar por
+ Nombre
+ Ruta
+ Tamaño
+ Extensión
+ Tipo
+ Fecha de creación
+ Fecha de modificación
+ Atributos
+ Nombre de la lista de archivos
+ Número de ejecuciones
+ Fecha de cambios recientes
+ Fecha de último acceso
+ Fecha de ejecución
+ ↑
+ ↓
+ Advertencia: Esta no es una opción de clasificación rápida, las búsquedas pueden ser lentas
+
+ Hacer clic para lanzar o instalar Everything
+ Instalación de Everything
+ Instalando el servicio de Everything. Por favor, espere...
+ Servicio de Everything instalado correctamente
+ No se ha podido instalar automáticamente el servicio de Everything. Por favor, instálelo manualmente desde https://www.voidtools.com
+ Hacer clic aquí para iniciarlo
+ No se ha podido encontrar una instalación de Everything, ¿desea seleccionar manualmente una ubicación?{0}{0}Si hace click en no, Everything se instalará automáticamente para usted
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml
index b128d8d56..dafe01173 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/fr.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Supprimer
Modifier
Ajouter
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Termin
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Supprimer
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Taille
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml
index 5335d025e..264fadc09 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/it.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Cancella
Modifica
Aggiungi
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Tasto di accesso rapido alla finestra
+ Shell Path
Index Search Excluded Paths
+ Utilizza il percorso ottenuto dalla ricerca come cartella di lavoro
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Conferma
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Tutto
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Cancella
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Attenzione: Il servizio "Everything" non è in esecuzione
+ Errore nell'interrogazione di Everything
+ Ordina per
+ Name
+ Percorso
+ Dimensioni
+ Estensione
+ Tipo
+ Data di creazione
+ Data della modifica
+ Attributi
+ Nome File Lista
+ Esegui Conteggio
+ Data di recente della modifica
+ Data di accesso
+ Data di esecuzione
+ ↑
+ ↓
+ Attenzione: Questa non è un'opzione di ordinamento rapido, le ricerche potrebbero essere lente
+
+ Click to Launch or Install Everything
+ Installazione di Everything
+ Installazione di everything. Si prega di attendere...
+ Everything è stato installato con successo
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Premi per avviare
+ Impossibile trovare l'installazione di Everything, vuoi inserire manualmente un percorso? {0} {0} Premi no per installare automaticamente Everything
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml
index 9d0c00d25..478df4103 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ja.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
削除
編
追
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
完
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
削除
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ サイズ
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml
index 15d6ca4a7..30cc5e1c7 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ko.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
폴더 링크를 선택하세요
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
삭제
편집
- 추
+ 추가
+ General Setting
사용자 지정 액션 키워드
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
색인 옵션
검색:
경로 검색:
@@ -35,12 +42,24 @@
완료
켬
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
탐색기
Window Index Search를 사용하여 파일과 폴더를 검색 및 관리합니다
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
경로 복사
복사하기
삭제
@@ -51,6 +70,9 @@
포함된 폴더 열기
Opens the location that contains the file or folder
편집기에서 열기:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
윈도우 인덱싱 옵션 열기
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ 크기
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml
index 4fb93acb6..c8fd77ac2 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nb.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Delete
Edit
Add
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Done
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Delete
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Size
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml
index 774ba0e32..eeb64b0da 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/nl.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Verwijder
Bewerken
Toevoegen
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Klaar
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Verwijder
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Size
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml
index 21b11e73f..55713796e 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pl.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Musisz wybrać któryś folder z listy
Czy jesteś pewien że chcesz usunąć {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Usuń
Edytuj
Dodaj
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Ścieżka edytora
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Zapisz
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Usu
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Everything Service nie jest uruchomiony
+ Wystąpił błąd podczas pobierania wyników z Everything
+ Sort By
+ Name
+ Path
+ Rozmiar
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml
index 450dd647d..1beae76c3 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Apagar
Editar
Adicionar
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Finalizado
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Apagar
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Tamanho
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml
index 2f09d7f6d..560078ab1 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-pt.xaml
@@ -1,7 +1,7 @@
-
+
Tem que efetuar uma seleção
Selecione a ligação para a pasta
Tem a certeza de que deseja eliminar {0}?
@@ -16,15 +16,22 @@
Alternativa
Ocorreu um erro ao pesquisar: {0}
-
+
Eliminar
Editar
Adicionar
+ Definições gerais
Personalizar palavras-chave
Ligações de acesso rápido
+ Definições Everything
+ Ordenação:
+ Caminho para Everything:
+ Iniciar oculto
+ Caminho do editor
+ Caminho da consola
Caminhos excluídos do índice de pesquisa
+ Utilizar local dos resultados como diretório de trabalho executável
Utilizar índice de pesquisa para o caminho
- Se ativar esta opção, os ficheiros e/ou diretórios indexados serão mostrados mais rapidamente mas, se um ficheiro ou diretório não estiver indexado não será mostrado. Se existirem ficheiros e/ou diretórios que tenham sido adicionados à exclusão do índice de pesquisa, serão mostrados.
Opções de indexação
Pesquisar:
Pesquisa de caminho:
@@ -35,12 +42,24 @@
Feito
Ativo
Se desativar a opção, Flow Launcher não irá executar esta opção de pesquisa e utilizará '*' para libertar a palavra-chave
+ Everything
+ Índice do Windows
+ Enumeração direta
-
+ Mecanismo de pesquisa para conteúdo
+ Mecanismo de pesquisa recursiva de diretórios
+ Mecanismo de pesquisa do índice
+ Abrir opções de índice do Windows
+
+
Explorador
Pesquisar e gerir ficheiros e pastas. O explorador utiliza o índice de pesquisa Windows.
-
+
+ Ctrl+Enter para abrir o diretório
+ Ctrl+Enter para abrir a pasta de destino
+
+
Copiar caminho
Copiar
Eliminar
@@ -51,6 +70,9 @@
Abrir pasta de destino
Abre a localização que contém o ficheiro ou a pasta
Abrir com o editor:
+ Erro ao abrir o ficheiro {0} com o editor {1} em {2}
+ Abrir com a consola:
+ Erro ao abrir a pasta {0} com a consola {1} em {2}
Excluir diretório atual do índice de pesquisas
Excluído do índice de pesquisas
Abrir opções de indexação do Windows
@@ -66,5 +88,36 @@
Remover do acesso rápido
Remover do acesso rápido
Remover {0} do acesso rápido
+ Mostrar menu de contexto do Windows
+
+
+ Falha ao carregar SDK Everything
+ Aviso: o serviço Everything não está em execução
+ Erro ao consultar Everything
+ Ordenar por
+ Nome
+ Caminho
+ Tamanho
+ Extensão
+ Nome do tipo
+ Data de criação
+ Data de modificação
+ Atributos
+ Por nome na lista de ficheiros
+ Número de execuções
+ Data alterada recentemente
+ Data de acesso
+ Data de execução
+ ↑
+ ↓
+ Aviso: esta não é uma opção de ordenação rápida e as pesquisas podem ser demoradas
+
+ Clique para iniciar ou instalar Everything
+ Instalação Everything
+ A instalar o serviço Everything. Por favor aguarde...
+ Serviço Everything instalado com sucesso
+ Não foi possível instalar o serviço Everything. Descarregue a aplicação em https://www.voidtools.com e instale-a manualmente.
+ Clique aqui para iniciar
+ Não foi possível encontrar a instalação de Everything. Deseja especificar manualmente a localização?{0}{0}Clique Não e Everything será instalado automaticamente.
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml
index aaa25d324..45f63fcba 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/ru.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Удалить
Редактировать
Добавить
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Подтвердить
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Удалить
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Размер
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml
index 5842974e2..aa51a07a2 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sk.xaml
@@ -1,7 +1,7 @@
-
+
Najprv vyberte položku
Vyberte odkaz na priečinok
Naozaj chcete odstrániť {0}?
@@ -16,41 +16,63 @@
Alternatíva pre Preskumníka
Počas vyhľadávania došlo k chybe: {0}
-
+
Odstrániť
Upraviť
Pridať
+ Všeobecné nastavenia
Upraviť aktivačný príkaz
Odkazy Rýchleho prístupu
+ Nastavenia Everything
+ Zoradenie:
+ Umiestnenie Everything:
+ Spustiť skryté
+ Cesta k editoru
+ Cesta k príkazovému riadku
Vylúčené umiestnenia indexovania
+ Použiť cestu výsledku vyhľadávania ako pracovný priečinok spustiteľného súboru
Na vyhľadanie cesty použiť vyhľadávanie v indexe
- Zapnutím tejto funkcie sa zrýchli odozva indexovaných priečinkov/súborov, ale ak priečinok/súbor nie je indexovaný, nezobrazí sa. Ak bol priečinok/súbor pridaný do Vylúčené umiestnenia indexovania, zobrazí sa, aj keď je táto možnosť zapnutá
Možnosti indexovania
Vyhľadávanie:
Cesta vyhľadávania:
- Vyhľadávanie v obsahu súborov:
+ Vyhľadávanie obsahu súborov:
Vyhľadávanie v indexe:
Rýchly prístup:
Aktuálny aktivačný príkaz
Hotovo
Povolené
Ak je vypnuté, Flow túto možnosť vyhľadávania nevykoná a následne sa vráti späť na "*", aby sa uvoľnila skratka akcie
+ Everything
+ Index Windowsu
+ Zoznam priečinkov
-
+ Vyhľadávač obsahu
+ Priečinkový rekurzívny vyhľadávač
+ Indexový vyhľadávač
+ Otvoriť možnosti vyhľadávania vo Windowse
+
+
Prieskumník
Vyhľadáva a spravuje súbory a priečinky. Prieskumník používa indexovanie vyhľadávania vo Windowse
-
+
+ Ctrl + Enter na otvorenie priečinka
+ Ctrl + Enter na otvorenie umiestnenia priečinka
+
+
Kopírovať cestu
Kopírovať
Odstrániť
Cesta:
- Odstrániť vybrané
+ Odstrániť vybraný
Spustiť ako iný používateľ
Spustí vybranú položku ako používateľ s iným kontom
Otvoriť umiestnenie priečinka
Otvorí umiestnenie, ktoré obsahuje súbor alebo priečinok
Otvoriť v editore:
+ Nepodarilo sa otvoriť súbor {0} v editore {1} – {2}
+ Otvori v príkazovom riadku:
+ Nepodarilo sa otvoriť priečinok {0} v prostredí {1} – {2}
Vylúčiť položku a jej podpriečinky z indexu vyhľadávania
Vylúčiť z indexu vyhľadávania
Otvoriť možnosti vyhľadávania vo Windowse
@@ -66,5 +88,36 @@
Odstráni z Rýchleho prístupu
Odstráni z Rýchleho prístupu
Odstráni {0} z Rýchleho prístupu
+ Zobraziť kontextovú ponuku Windowsu
+
+
+ Nepodarilo sa načítať Everything SDK
+ Upozornenie: Služba Everything nie je spustená
+ Chyba pri dopytovaní Everything
+ Zoradiť podľa
+ Názov
+ Cesta
+ Veľkosť
+ Prípona
+ Typ
+ Dátum vytvorenia
+ Dátum úpravy
+ Atribúty
+ Zoznam názvov súborov
+ Počet spustení
+ Nedávno zmenený dátum
+ Dátum prístupu
+ Dátum spustenia
+ ↑
+ ↓
+ Upozornenie: Toto nie je voľba Fast Sort, vyhľadávanie môže byť pomalé
+
+ Kliknutím spustíte alebo nainštalujete Everything
+ Inštalácia Everything
+ Inštaluje sa služba Everything. Čakajte, prosím…
+ Služba Everything bola úspešne nainštalovaná
+ Automatická inštalácia služby Everything zlyhala. Prosím, nainštalujte ju manuálne z https://www.voidtools.com
+ Kliknutím sem ju spustíte
+ Nepodarilo sa nájsť inštaláciu Everything, chcete manuálne vybrať jej umiestnenie?{0}{0}Kliknutím na nie sa Everything automaticky nainštaluje
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml
index 8a09b8834..629dbd18c 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/sr.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Obriši
Izmeni
Dodaj
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Gotovo
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Obriši
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Size
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml
index 5a982e19f..28b7712fa 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/tr.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Lütfen bir klasör bağlantısı seçin
{0} bağlantısını silmek istediğinize emin misiniz?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Sil
Düzenle
Ekle
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Düzenleyici Konumu
+ Shell Path
Index Search Excluded Paths
+ Programın çalışma klasörü olarak sonuç klasörünü kullan
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Tamam
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Sil
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Everything Servisi çalışmıyor
+ Sorgu Everything üzerinde çalıştırılırken hata oluştu
+ Sort By
+ Name
+ Path
+ Boyut
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml
index d19c4b33a..11a778fab 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/uk-UA.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
Видалити
Редагувати
Додати
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ Editor Path
+ Shell Path
Index Search Excluded Paths
+ Use search result's location as executable working directory
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
Indexing Options
Search:
Path Search:
@@ -35,12 +42,24 @@
Готово
Enabled
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
Explorer
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
Copy path
Copy
Видалити
@@ -51,6 +70,9 @@
Open containing folder
Opens the location that contains the file or folder
Open With Editor:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Warning: Everything service is not running
+ Error while querying Everything
+ Sort By
+ Name
+ Path
+ Size
+ Extension
+ Type Name
+ Date Created
+ Date Modified
+ Attributes
+ File List FileName
+ Run Count
+ Date Recently Changed
+ Date Accessed
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything Installation
+ Installing Everything service. Please wait...
+ Successfully installed Everything service
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ Click here to start it
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml
index dd32d0ec4..63783d108 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-cn.xaml
@@ -1,7 +1,7 @@
-
+
请先进行选择
请选择一个文件夹链接
您确定要删除 {0} 吗?
@@ -16,15 +16,22 @@
资源管理器选项
搜索时发生错误:{0}
-
+
删除
编辑
增加
+ 通用设置
自定义动作关键字
快速访问链接
+ Everything 设置
+ 排序选项
+ Everything 路径
+ 隐藏启动
+ 编辑器路径
+ Shell 路径
索引搜索排除的路径
+ 使用搜索结果的位置作为应用程序的工作目录
使用索引进行路径搜索
- 启用该选项会更快速地找到已索引的文件夹和文件,但未索引的项目不会出现在结果中。在“索引搜索排除的路径”中文件夹和文件仍会出现在结果中。
索引选项
搜索激活:
路径搜索激活:
@@ -35,12 +42,24 @@
确认
启用
当禁用时,Flow Launcher 将不会执行此搜索选项,并且还会恢复到“*”以释放动作关键字
+ Everything
+ Windows 索引
+ 直接枚举
-
+ 文件内容搜索引擎
+ 目录递归搜索引擎
+ 索引搜索引擎
+ 打开 Windows 索引选项
+
+
文件管理器
利用Windows索引来搜索和管理文件和文件夹。
-
+
+ Ctrl + Enter 以打开目录
+ Ctrl + Enter 以打开所在的文件夹
+
+
复制路径
复制
删除
@@ -51,6 +70,9 @@
打开文件所在文件夹
打开文件或文件夹所在目录
使用编辑器打开:
+ 使用编辑器 {1} ({2}) 打开文件 {0} 时失败
+ 使用 Shell 打开:
+ 使用 Shell {1} ({2}) 打开文件夹 {0} 时失败
从索引搜索中排除当前目录和子目录
从索引搜索中排除
打开Windows索引选项
@@ -66,5 +88,36 @@
从快速访问中删除
从快速访问中删除
从快速访问中删除 {0}
+ 显示 Windows 上下文菜单
+
+
+ Everything SDK 加载失败
+ 警告:Everything 服务未运行
+ Everything 插件发生了一个错误(回车拷贝具体错误信息)
+ 排序依据
+ 名称
+ 路径
+ 大小
+ 扩展名
+ 类型名称
+ 创建日期
+ 修改日期
+ 属性
+ 文件列表名
+ 运行次数
+ 最近更改日期
+ 访问日期
+ 运行日期
+ ↑
+ ↓
+ 警告:这不是一个快速排序选项,搜索可能较慢。
+
+ 单击启动或安装 Everything
+ Everything 安装
+ 正在安装 Everything 服务。请稍后...
+ 成功安装了 Everything 服务
+ 自动安装 Everything 服务失败。请从 https://www.voidtools.com 手动下载并安装。
+ 单击此处开始
+ 无法找到任何 Everything 安装,您想手动选择一个位置吗?{0}{0} 单击 不 将自动为您安装 Everything。
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml
index e399f6ebf..499f659f4 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/zh-tw.xaml
@@ -1,7 +1,7 @@
-
+
Please make a selection first
請選擇一個資料夾
你確認要刪除{0}嗎?
@@ -16,15 +16,22 @@
Explorer Alternative
Error occurred during search: {0}
-
+
刪除
編輯
新增
+ General Setting
Customise Action Keywords
Quick Access Links
+ Everything Setting
+ Sort Option:
+ Everything Path:
+ Launch Hidden
+ 編輯器路
+ Shell Path
Index Search Excluded Paths
+ 使用程式所在目錄作為工作目錄
Use Index Search For Path Search
- Turning this on will return indexed directories/files faster, but if a directory/file is not indexed it will not show up. If a directory/file has been added to Index Search Excluded Path then it will still show up even if this option is on
索引選項
搜尋:
Path Search:
@@ -35,12 +42,24 @@
確
已啟用
When disabled Flow will not execute this search option, and will additionally revert back to '*' to free up the action keyword
+ Everything
+ Windows Index
+ Direct Enumeration
-
+ Content Search Engine
+ Directory Recursive Search Engine
+ Index Search Engine
+ Open Windows Index Option
+
+
檔案總管
Search and manage files and folders. Explorer utilises Windows Index Search
-
+
+ Ctrl + Enter to open the directory
+ Ctrl + Enter to open the containing folder
+
+
複製路徑
複製
刪除
@@ -51,6 +70,9 @@
開啟檔案位置
Opens the location that contains the file or folder
在編輯器中開啟:
+ Failed to open file at {0} with Editor {1} at {2}
+ Open With Shell:
+ Failed to open folder {0} with Shell {1} at {2}
Exclude current and sub-directories from Index Search
Excluded from Index Search
Open Windows Indexing Options
@@ -66,5 +88,36 @@
Remove from Quick Access
Remove from Quick Access
Remove the current {0} from Quick Access
+ Show Windows Context Menu
+
+
+ Everything SDK Loaded Fail
+ Everything Service 尚未啟動
+ Everything 套件發生錯誤(Enter 複製具體錯誤訊息)
+ 排序依據
+ 名稱
+ 路徑
+ 大小
+ 擴展程序
+ 類型
+ 創建日期
+ 修改日期
+ 屬性
+ File List FileName
+ 執行次數
+ 近期變更
+ 存取日期
+ Date Run
+ ↑
+ ↓
+ Warning: This is not a Fast Sort option, searches may be slow
+
+ Click to Launch or Install Everything
+ Everything 安裝程序
+ 正在安裝 Everything 服務,請稍後...
+ 成功安裝 Everything 服務
+ Failed to automatically install Everything service. Please manually install it from https://www.voidtools.com
+ 點此開始
+ Unable to find an Everything installation, would you like to manually select a location?{0}{0}Click no and Everything will be automatically installed for you
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
index 60208759e..82a5d5441 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
@@ -1,19 +1,22 @@
-using Flow.Launcher.Infrastructure.Storage;
+using Flow.Launcher.Plugin.Explorer.Helper;
using Flow.Launcher.Plugin.Explorer.Search;
-using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
+using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.ViewModels;
using Flow.Launcher.Plugin.Explorer.Views;
+using System;
using System.Collections.Generic;
-using System.Linq;
+using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using System.Windows;
using System.Windows.Controls;
+using Flow.Launcher.Plugin.Explorer.Exceptions;
namespace Flow.Launcher.Plugin.Explorer
{
public class Main : ISettingProvider, IAsyncPlugin, IContextMenu, IPluginI18n
{
- internal PluginInitContext Context { get; set; }
+ internal static PluginInitContext Context { get; set; }
internal Settings Settings;
@@ -31,23 +34,19 @@ namespace Flow.Launcher.Plugin.Explorer
public Task InitAsync(PluginInitContext context)
{
Context = context;
-
+
Settings = context.API.LoadSettingJsonStorage();
viewModel = new SettingsViewModel(context, Settings);
-
-
- // as at v1.7.0 this is to maintain backwards compatibility, need to be removed afterwards.
- if (Settings.QuickFolderAccessLinks.Any())
- {
- Settings.QuickAccessLinks = Settings.QuickFolderAccessLinks;
- Settings.QuickFolderAccessLinks = new List();
- }
contextMenu = new ContextMenu(Context, Settings, viewModel);
searchManager = new SearchManager(Settings, Context);
ResultManager.Init(Context, Settings);
+
+ SortOptionTranslationHelper.API = context.API;
+ EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK",
+ Environment.Is64BitProcess ? "x64" : "x86"));
return Task.CompletedTask;
}
@@ -58,7 +57,34 @@ namespace Flow.Launcher.Plugin.Explorer
public async Task> QueryAsync(Query query, CancellationToken token)
{
- return await searchManager.SearchAsync(query, token);
+ try
+ {
+ return await searchManager.SearchAsync(query, token);
+ }
+ catch (Exception e) when (e is SearchException or EngineNotAvailableException)
+ {
+ return new List
+ {
+ new()
+ {
+ Title = e.Message,
+ SubTitle = e is EngineNotAvailableException { Resolution: { } resolution }
+ ? resolution
+ : "Enter to copy the message to clipboard",
+ Score = 501,
+ IcoPath = e is EngineNotAvailableException { ErrorIcon: { } iconPath }
+ ? iconPath
+ : Constants.GeneralSearchErrorImagePath,
+ AsyncAction = e is EngineNotAvailableException {Action: { } action}
+ ? action
+ : _ =>
+ {
+ Clipboard.SetDataObject(e.ToString());
+ return new ValueTask(true);
+ }
+ }
+ };
+ }
}
public string GetTranslatedPluginTitle()
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs
index 78c7c98a5..2918cb61f 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs
@@ -17,6 +17,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search
internal const string IndexingOptionsIconImagePath = "Images\\windowsindexingoptions.png";
internal const string QuickAccessImagePath = "Images\\quickaccess.png";
internal const string RemoveQuickAccessImagePath = "Images\\removequickaccess.png";
+ internal const string ShowContextMenuImagePath = "Images\\context_menu.png";
+ internal const string EverythingErrorImagePath = "Images\\everything_error.png";
+ internal const string IndexSearchWarningImagePath = "Images\\index_error.png";
+ internal const string WindowsIndexErrorImagePath = "Images\\index_error2.png";
+ internal const string GeneralSearchErrorImagePath = "Images\\robot_error.png";
+
internal const string ToolTipOpenDirectory = "Ctrl + Enter to open the directory";
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
index 93b68675f..d24ad8981 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/DirectoryInfo/DirectoryInfoSearch.cs
@@ -10,7 +10,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
{
public static class DirectoryInfoSearch
{
- internal static List TopLevelDirectorySearch(Query query, string search, CancellationToken token)
+ internal static IEnumerable TopLevelDirectorySearch(Query query, string search, CancellationToken token)
{
var criteria = ConstructSearchCriteria(search);
@@ -19,9 +19,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
return DirectorySearch(new EnumerationOptions
{
RecurseSubdirectories = true
- }, query, search, criteria, token);
+ }, search, criteria, token);
- return DirectorySearch(new EnumerationOptions(), query, search, criteria,
+ return DirectorySearch(new EnumerationOptions(), search, criteria,
token); // null will be passed as default
}
@@ -33,10 +33,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
{
var indexOfSeparator = search.LastIndexOf(Constants.DirectorySeperator);
- incompleteName = search.Substring(indexOfSeparator + 1).ToLower();
+ incompleteName = search[(indexOfSeparator + 1)..].ToLower();
if (incompleteName.StartsWith(Constants.AllFilesFolderSearchWildcard))
- incompleteName = "*" + incompleteName.Substring(1);
+ incompleteName = string.Concat("*", incompleteName.AsSpan(1));
}
incompleteName += "*";
@@ -44,54 +44,45 @@ namespace Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo
return incompleteName;
}
- private static List DirectorySearch(EnumerationOptions enumerationOption, Query query, string search,
+ private static IEnumerable DirectorySearch(EnumerationOptions enumerationOption, string search,
string searchCriteria, CancellationToken token)
{
- var results = new List();
+ var results = new List();
var path = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(search);
- var folderList = new List();
- var fileList = new List();
-
try
{
var directoryInfo = new System.IO.DirectoryInfo(path);
foreach (var fileSystemInfo in directoryInfo.EnumerateFileSystemInfos(searchCriteria, enumerationOption))
{
- if (fileSystemInfo is System.IO.DirectoryInfo)
+ results.Add(new SearchResult
{
- folderList.Add(ResultManager.CreateFolderResult(fileSystemInfo.Name, fileSystemInfo.FullName,
- fileSystemInfo.FullName, query, 0, true, false));
- }
- else
- {
- fileList.Add(ResultManager.CreateFileResult(fileSystemInfo.FullName, query, 0, true, false));
- }
+ FullPath = fileSystemInfo.FullName,
+ Type = fileSystemInfo switch
+ {
+ System.IO.DirectoryInfo {Parent: null} => ResultType.Volume,
+ System.IO.DirectoryInfo => ResultType.Folder,
+ FileInfo => ResultType.File,
+ _ => throw new ArgumentOutOfRangeException(nameof(fileSystemInfo))
+ },
+ WindowsIndexed = false
+ });
- token.ThrowIfCancellationRequested();
+ if (token.IsCancellationRequested)
+ return results;
}
}
catch (Exception e)
{
Log.Exception(nameof(DirectoryInfoSearch), "Error occured while searching path", e);
- results.Add(
- new Result
- {
- Title = string.Format(SearchManager.Context.API.GetTranslation(
- "plugin_explorer_directoryinfosearch_error"),
- e.Message),
- Score = 501,
- IcoPath = Constants.ExplorerIconImagePath
- });
-
- return results;
+ throw;
}
// Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
- return results.Concat(folderList.OrderBy(x => x.Title)).Concat(fileList.OrderBy(x => x.Title)).ToList();
+ return results.OrderBy(r=>r.Type).ThenBy(r=>r.FullPath);
}
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs
new file mode 100644
index 000000000..5381d729d
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs
@@ -0,0 +1,216 @@
+using Flow.Launcher.Plugin.Everything.Everything;
+using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms.Design;
+using Flow.Launcher.Plugin.Explorer.Exceptions;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything
+{
+
+ public static class EverythingApi
+ {
+
+ private const int BufferSize = 4096;
+
+ private static SemaphoreSlim _semaphore = new(1, 1);
+ // cached buffer to remove redundant allocations.
+ private static readonly StringBuilder buffer = new(BufferSize);
+
+ public enum StateCode
+ {
+ OK,
+ MemoryError,
+ IPCError,
+ RegisterClassExError,
+ CreateWindowError,
+ CreateThreadError,
+ InvalidIndexError,
+ InvalidCallError
+ }
+
+ ///
+ /// Gets or sets a value indicating whether [match path].
+ ///
+ /// true if [match path]; otherwise, false .
+ public static bool MatchPath
+ {
+ get => EverythingApiDllImport.Everything_GetMatchPath();
+ set => EverythingApiDllImport.Everything_SetMatchPath(value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether [match case].
+ ///
+ /// true if [match case]; otherwise, false .
+ public static bool MatchCase
+ {
+ get => EverythingApiDllImport.Everything_GetMatchCase();
+ set => EverythingApiDllImport.Everything_SetMatchCase(value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether [match whole word].
+ ///
+ /// true if [match whole word]; otherwise, false .
+ public static bool MatchWholeWord
+ {
+ get => EverythingApiDllImport.Everything_GetMatchWholeWord();
+ set => EverythingApiDllImport.Everything_SetMatchWholeWord(value);
+ }
+
+ ///
+ /// Gets or sets a value indicating whether [enable regex].
+ ///
+ /// true if [enable regex]; otherwise, false .
+ public static bool EnableRegex
+ {
+ get => EverythingApiDllImport.Everything_GetRegex();
+ set => EverythingApiDllImport.Everything_SetRegex(value);
+ }
+
+ ///
+ /// Checks whether the sort option is Fast Sort.
+ ///
+ public static bool IsFastSortOption(SortOption sortOption)
+ {
+ var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption);
+
+ // If the Everything service is not running, then this call will incorrectly report
+ // the state as false. This checks for errors thrown by the api and up to the caller to handle.
+ CheckAndThrowExceptionOnError();
+
+ return fastSortOptionEnabled;
+ }
+
+ public static async ValueTask IsEverythingRunningAsync(CancellationToken token = default)
+ {
+ await _semaphore.WaitAsync(token);
+
+ try
+ {
+ EverythingApiDllImport.Everything_GetMajorVersion();
+ var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError;
+ return result;
+ }
+ finally
+ {
+ _semaphore.Release();
+ }
+ }
+
+ ///
+ /// Searches the specified key word and reset the everything API afterwards
+ ///
+ /// Search Criteria
+ /// when cancelled the current search will stop and exit (and would not reset)
+ /// An IAsyncEnumerable that will enumerate all results searched by the specific query and option
+ public static async IAsyncEnumerable SearchAsync(EverythingSearchOption option,
+ [EnumeratorCancellation] CancellationToken token)
+ {
+ if (option.Offset < 0)
+ throw new ArgumentOutOfRangeException(nameof(option.Offset), option.Offset, "Offset must be greater than or equal to 0");
+
+ if (option.MaxCount < 0)
+ throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0");
+
+ await _semaphore.WaitAsync(token);
+
+
+ try
+ {
+ if (token.IsCancellationRequested)
+ yield break;
+
+ if (option.Keyword.StartsWith("@"))
+ {
+ EverythingApiDllImport.Everything_SetRegex(true);
+ option.Keyword = option.Keyword[1..];
+ }
+
+ var builder = new StringBuilder();
+ builder.Append(option.Keyword);
+
+ if (!string.IsNullOrWhiteSpace(option.ParentPath))
+ {
+ builder.Append($" {(option.IsRecursive ? "" : "parent:")}\"{option.ParentPath}\"");
+ }
+
+ if (option.IsContentSearch)
+ {
+ builder.Append($" content:\"{option.ContentSearchKeyword}\"");
+ }
+
+ EverythingApiDllImport.Everything_SetSearchW(builder.ToString());
+ EverythingApiDllImport.Everything_SetOffset(option.Offset);
+ EverythingApiDllImport.Everything_SetMax(option.MaxCount);
+
+ EverythingApiDllImport.Everything_SetSort(option.SortOption);
+
+ if (token.IsCancellationRequested) yield break;
+
+ if (!EverythingApiDllImport.Everything_QueryW(true))
+ {
+ CheckAndThrowExceptionOnError();
+ yield break;
+ }
+
+ for (var idx = 0; idx < EverythingApiDllImport.Everything_GetNumResults(); ++idx)
+ {
+ if (token.IsCancellationRequested)
+ {
+ yield break;
+ }
+
+ EverythingApiDllImport.Everything_GetResultFullPathNameW(idx, buffer, BufferSize);
+
+ var result = new SearchResult
+ {
+ FullPath = buffer.ToString(),
+ Type = EverythingApiDllImport.Everything_IsFolderResult(idx) ? ResultType.Folder :
+ EverythingApiDllImport.Everything_IsFileResult(idx) ? ResultType.File :
+ ResultType.Volume
+ };
+
+ yield return result;
+ }
+ }
+ finally
+ {
+ EverythingApiDllImport.Everything_Reset();
+ _semaphore.Release();
+ }
+ }
+
+ private static void CheckAndThrowExceptionOnError()
+ {
+ switch (EverythingApiDllImport.Everything_GetLastError())
+ {
+ case StateCode.CreateThreadError:
+ throw new CreateThreadException();
+ case StateCode.CreateWindowError:
+ throw new CreateWindowException();
+ case StateCode.InvalidCallError:
+ throw new InvalidCallException();
+ case StateCode.InvalidIndexError:
+ throw new InvalidIndexException();
+ case StateCode.IPCError:
+ throw new IPCErrorException();
+ case StateCode.MemoryError:
+ throw new MemoryErrorException();
+ case StateCode.RegisterClassExError:
+ throw new RegisterClassExException();
+ case StateCode.OK:
+ break;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs
new file mode 100644
index 000000000..5b80819fa
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs
@@ -0,0 +1,163 @@
+using Flow.Launcher.Plugin.Everything.Everything;
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything
+{
+ public static class EverythingApiDllImport
+ {
+ public static void Load(string directory)
+ {
+ var path = Path.Combine(directory, DLL);
+ int code = LoadLibrary(path);
+ if (code == 0)
+ {
+ int err = Marshal.GetLastPInvokeError();
+ Marshal.ThrowExceptionForHR(err);
+ }
+ }
+
+ [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ private static extern int LoadLibrary(string name);
+
+ private const string DLL = "Everything.dll";
+
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ internal static extern int Everything_SetSearchW(string lpSearchString);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SetMatchPath(bool bEnable);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SetMatchCase(bool bEnable);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SetMatchWholeWord(bool bEnable);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SetRegex(bool bEnable);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SetMax(int dwMax);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SetOffset(int dwOffset);
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_GetMatchPath();
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_GetMatchCase();
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_GetMatchWholeWord();
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_GetRegex();
+
+ [DllImport(DLL)]
+ internal static extern uint Everything_GetMax();
+
+ [DllImport(DLL)]
+ internal static extern uint Everything_GetOffset();
+
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ internal static extern string Everything_GetSearchW();
+
+ [DllImport(DLL)]
+ internal static extern EverythingApi.StateCode Everything_GetLastError();
+
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ internal static extern bool Everything_QueryW(bool bWait);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_SortResultsByPath();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetNumFileResults();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetMajorVersion();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetNumFolderResults();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetNumResults();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetTotFileResults();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetTotFolderResults();
+
+ [DllImport(DLL)]
+ internal static extern int Everything_GetTotResults();
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_IsVolumeResult(int nIndex);
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_IsFolderResult(int nIndex);
+
+ [DllImport(DLL)]
+ internal static extern bool Everything_IsFileResult(int nIndex);
+
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ internal static extern void Everything_GetResultFullPathNameW(int nIndex, StringBuilder lpString, int nMaxCount);
+
+ [DllImport(DLL)]
+ internal static extern void Everything_Reset();
+
+ // Everything 1.4
+
+ [DllImport(DLL)]
+ public static extern void Everything_SetSort(SortOption dwSortType);
+ [DllImport(DLL)]
+ public static extern bool Everything_IsFastSort(SortOption dwSortType);
+ [DllImport(DLL)]
+ public static extern SortOption Everything_GetSort();
+ [DllImport(DLL)]
+ public static extern uint Everything_GetResultListSort();
+ [DllImport(DLL)]
+ public static extern void Everything_SetRequestFlags(uint dwRequestFlags);
+ [DllImport(DLL)]
+ public static extern uint Everything_GetRequestFlags();
+ [DllImport(DLL)]
+ public static extern uint Everything_GetResultListRequestFlags();
+ [DllImport("Everything64.dll", CharSet = CharSet.Unicode)]
+ public static extern IntPtr Everything_GetResultExtension(uint nIndex);
+ [DllImport(DLL)]
+ public static extern bool Everything_GetResultSize(uint nIndex, out long lpFileSize);
+ [DllImport(DLL)]
+ public static extern bool Everything_GetResultDateCreated(uint nIndex, out long lpFileTime);
+ [DllImport(DLL)]
+ public static extern bool Everything_GetResultDateModified(uint nIndex, out long lpFileTime);
+ [DllImport(DLL)]
+ public static extern bool Everything_GetResultDateAccessed(uint nIndex, out long lpFileTime);
+ [DllImport(DLL)]
+ public static extern uint Everything_GetResultAttributes(uint nIndex);
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ public static extern IntPtr Everything_GetResultFileListFileName(uint nIndex);
+ [DllImport(DLL)]
+ public static extern uint Everything_GetResultRunCount(uint nIndex);
+ [DllImport(DLL)]
+ public static extern bool Everything_GetResultDateRun(uint nIndex, out long lpFileTime);
+ [DllImport(DLL)]
+ public static extern bool Everything_GetResultDateRecentlyChanged(uint nIndex, out long lpFileTime);
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ public static extern IntPtr Everything_GetResultHighlightedFileName(uint nIndex);
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ public static extern IntPtr Everything_GetResultHighlightedPath(uint nIndex);
+ [DllImport(DLL, CharSet = CharSet.Unicode)]
+ public static extern IntPtr Everything_GetResultHighlightedFullPathAndFileName(uint nIndex);
+ [DllImport(DLL)]
+ public static extern uint Everything_GetRunCountFromFileName(string lpFileName);
+ [DllImport(DLL)]
+ public static extern bool Everything_SetRunCountFromFileName(string lpFileName, uint dwRunCount);
+ [DllImport(DLL)]
+ public static extern uint Everything_IncRunCountFromFileName(string lpFileName);
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingDownloadHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingDownloadHelper.cs
new file mode 100644
index 000000000..ce774281c
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingDownloadHelper.cs
@@ -0,0 +1,88 @@
+using Droplex;
+using Flow.Launcher.Plugin.SharedCommands;
+using Microsoft.Win32;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything;
+
+public static class EverythingDownloadHelper
+{
+ public static async Task PromptDownloadIfNotInstallAsync(string installedLocation, IPublicAPI api)
+ {
+ if (!string.IsNullOrEmpty(installedLocation) && installedLocation.FileExists())
+ return installedLocation;
+
+ installedLocation = GetInstalledPath();
+
+ if (string.IsNullOrEmpty(installedLocation))
+ {
+ if (System.Windows.Forms.MessageBox.Show(
+ string.Format(api.GetTranslation("flowlauncher_plugin_everything_installing_select"), Environment.NewLine),
+ api.GetTranslation("flowlauncher_plugin_everything_installing_title"),
+ System.Windows.Forms.MessageBoxButtons.YesNo) == System.Windows.Forms.DialogResult.Yes)
+ {
+ var dlg = new System.Windows.Forms.OpenFileDialog
+ {
+ InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)
+ };
+
+ var result = dlg.ShowDialog();
+ if (result == System.Windows.Forms.DialogResult.OK && !string.IsNullOrEmpty(dlg.FileName))
+ installedLocation = dlg.FileName;
+ }
+ }
+
+ if (!string.IsNullOrEmpty(installedLocation))
+ {
+ return installedLocation;
+ }
+
+ api.ShowMsg(api.GetTranslation("flowlauncher_plugin_everything_installing_title"),
+ api.GetTranslation("flowlauncher_plugin_everything_installing_subtitle"), "", useMainWindowAsOwner: false);
+
+ await DroplexPackage.Drop(App.Everything1_4_1_1009).ConfigureAwait(false);
+
+ api.ShowMsg(api.GetTranslation("flowlauncher_plugin_everything_installing_title"),
+ api.GetTranslation("flowlauncher_plugin_everything_installationsuccess_subtitle"), "", useMainWindowAsOwner: false);
+
+ installedLocation = "C:\\Program Files\\Everything\\Everything.exe";
+
+ FilesFolders.OpenPath(installedLocation);
+
+ return installedLocation;
+
+ }
+
+ internal static string GetInstalledPath()
+ {
+ using var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
+ if (key is not null)
+ {
+ foreach (var subKey in key.GetSubKeyNames().Select(keyName => key.OpenSubKey(keyName)))
+ {
+ if (subKey?.GetValue("DisplayName") is not string displayName || !displayName.Contains("Everything"))
+ {
+ continue;
+ }
+ if (subKey.GetValue("UninstallString") is not string uninstallString)
+ {
+ continue;
+ }
+
+ if (Path.GetDirectoryName(uninstallString) is not { } uninstallDirectory)
+ {
+ continue;
+ }
+ return Path.Combine(uninstallDirectory, "Everything.exe");
+ }
+ }
+
+ var scoopInstalledPath = Environment.ExpandEnvironmentVariables(@"%userprofile%\scoop\apps\everything\current\Everything.exe");
+ return File.Exists(scoopInstalledPath) ? scoopInstalledPath : string.Empty;
+
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs
new file mode 100644
index 000000000..ffd22d9f5
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchManager.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Flow.Launcher.Plugin.Explorer.Exceptions;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything
+{
+ public class EverythingSearchManager : IIndexProvider, IContentIndexProvider, IPathIndexProvider
+ {
+ private Settings Settings { get; }
+
+ public EverythingSearchManager(Settings settings)
+ {
+ Settings = settings;
+ }
+
+ private async ValueTask ThrowIfEverythingNotAvailableAsync(CancellationToken token = default)
+ {
+ try
+ {
+ if (!await EverythingApi.IsEverythingRunningAsync(token))
+ throw new EngineNotAvailableException(
+ Enum.GetName(Settings.IndexSearchEngineOption.Everything)!,
+ Main.Context.API.GetTranslation("flowlauncher_plugin_everything_click_to_launch_or_install"),
+ Main.Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running"),
+ ClickToInstallEverythingAsync)
+ {
+ ErrorIcon = Constants.EverythingErrorImagePath
+ };
+ }
+ catch (DllNotFoundException)
+ {
+ throw new EngineNotAvailableException(
+ Enum.GetName(Settings.IndexSearchEngineOption.Everything)!,
+ "Please check whether your system is x86 or x64",
+ Main.Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue"))
+ {
+ ErrorIcon = Constants.GeneralSearchErrorImagePath
+ };
+ }
+ }
+ private async ValueTask ClickToInstallEverythingAsync(ActionContext _)
+ {
+ var installedPath = await EverythingDownloadHelper.PromptDownloadIfNotInstallAsync(Settings.EverythingInstalledPath, Main.Context.API);
+ if (installedPath == null)
+ {
+ Main.Context.API.ShowMsgError("Unable to find Everything.exe");
+ return false;
+ }
+ Settings.EverythingInstalledPath = installedPath;
+ Process.Start(installedPath, "-startup");
+ return true;
+ }
+
+ public async IAsyncEnumerable SearchAsync(string search, [EnumeratorCancellation] CancellationToken token)
+ {
+ await ThrowIfEverythingNotAvailableAsync(token);
+ if (token.IsCancellationRequested)
+ yield break;
+ var option = new EverythingSearchOption(search, Settings.SortOption);
+ await foreach (var result in EverythingApi.SearchAsync(option, token))
+ yield return result;
+ }
+ public async IAsyncEnumerable ContentSearchAsync(string plainSearch,
+ string contentSearch, [EnumeratorCancellation] CancellationToken token)
+ {
+ await ThrowIfEverythingNotAvailableAsync(token);
+ if (!Settings.EnableEverythingContentSearch)
+ {
+ throw new EngineNotAvailableException(Enum.GetName(Settings.IndexSearchEngineOption.Everything)!,
+ "Click to Enable Everything Content Search (only applicable to Everything 1.5+ with indexed content)",
+ "Everything Content Search is not enabled.",
+ _ =>
+ {
+ Settings.EnableEverythingContentSearch = true;
+ return ValueTask.FromResult(true);
+ })
+ {
+ ErrorIcon = Constants.EverythingErrorImagePath
+ };
+ }
+ if (token.IsCancellationRequested)
+ yield break;
+
+ var option = new EverythingSearchOption(plainSearch,
+ Settings.SortOption,
+ true,
+ contentSearch);
+
+ await foreach (var result in EverythingApi.SearchAsync(option, token))
+ {
+ yield return result;
+ }
+ }
+ public async IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, [EnumeratorCancellation] CancellationToken token)
+ {
+ await ThrowIfEverythingNotAvailableAsync(token);
+ if (token.IsCancellationRequested)
+ yield break;
+
+ var option = new EverythingSearchOption(search,
+ Settings.SortOption,
+ ParentPath: path,
+ IsRecursive: recursive);
+
+ await foreach (var result in EverythingApi.SearchAsync(option, token))
+ {
+ yield return result;
+ }
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs
new file mode 100644
index 000000000..6839822a4
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs
@@ -0,0 +1,14 @@
+using System;
+using Flow.Launcher.Plugin.Everything.Everything;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything
+{
+ public record struct EverythingSearchOption(string Keyword,
+ SortOption SortOption,
+ bool IsContentSearch = false,
+ string ContentSearchKeyword = default,
+ string ParentPath = default,
+ bool IsRecursive = true,
+ int Offset = 0,
+ int MaxCount = 100);
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/CreateThreadException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/CreateThreadException.cs
new file mode 100644
index 000000000..32163057b
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/CreateThreadException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class CreateThreadException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/CreateWindowException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/CreateWindowException.cs
new file mode 100644
index 000000000..9704226d7
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/CreateWindowException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class CreateWindowException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/IPCErrorException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/IPCErrorException.cs
new file mode 100644
index 000000000..41629d2e4
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/IPCErrorException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class IPCErrorException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/InvalidCallException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/InvalidCallException.cs
new file mode 100644
index 000000000..f84dc1ab8
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/InvalidCallException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class InvalidCallException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/InvalidIndexException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/InvalidIndexException.cs
new file mode 100644
index 000000000..cbf75e5a3
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/InvalidIndexException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class InvalidIndexException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/MemoryErrorException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/MemoryErrorException.cs
new file mode 100644
index 000000000..c632cd530
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/MemoryErrorException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class MemoryErrorException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/RegisterClassExException.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/RegisterClassExException.cs
new file mode 100644
index 000000000..2ebdbb689
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/Exceptions/RegisterClassExException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions
+{
+ ///
+ ///
+ ///
+ public class RegisterClassExException : ApplicationException
+ {
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs
new file mode 100644
index 000000000..434afd1b4
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Flow.Launcher.Plugin.Everything.Everything
+{
+ public enum SortOption : uint
+ {
+ NAME_ASCENDING = 1u,
+ NAME_DESCENDING = 2u,
+ PATH_ASCENDING = 3u,
+ PATH_DESCENDING = 4u,
+ SIZE_ASCENDING = 5u,
+ SIZE_DESCENDING = 6u,
+ EXTENSION_ASCENDING = 7u,
+ EXTENSION_DESCENDING = 8u,
+ TYPE_NAME_ASCENDING = 9u,
+ TYPE_NAME_DESCENDING = 10u,
+ DATE_CREATED_ASCENDING = 11u,
+ DATE_CREATED_DESCENDING = 12u,
+ DATE_MODIFIED_ASCENDING = 13u,
+ DATE_MODIFIED_DESCENDING = 14u,
+ ATTRIBUTES_ASCENDING = 15u,
+ ATTRIBUTES_DESCENDING = 16u,
+ FILE_LIST_FILENAME_ASCENDING = 17u,
+ FILE_LIST_FILENAME_DESCENDING = 18u,
+ RUN_COUNT_ASCENDING = 19u,
+ RUN_COUNT_DESCENDING = 20u,
+ DATE_RECENTLY_CHANGED_ASCENDING = 21u,
+ DATE_RECENTLY_CHANGED_DESCENDING = 22u,
+ DATE_ACCESSED_ASCENDING = 23u,
+ DATE_ACCESSED_DESCENDING = 24u,
+ DATE_RUN_ASCENDING = 25u,
+ DATE_RUN_DESCENDING = 26u
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IContentIndexProvider.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IContentIndexProvider.cs
new file mode 100644
index 000000000..6e036e058
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IContentIndexProvider.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
+{
+ public interface IContentIndexProvider
+ {
+ public IAsyncEnumerable ContentSearchAsync(string plainSearch, string contentSearch, CancellationToken token = default);
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IIndexProvider.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IIndexProvider.cs
new file mode 100644
index 000000000..d43dd7df3
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IIndexProvider.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
+{
+ public interface IIndexProvider
+ {
+ public IAsyncEnumerable SearchAsync(string search, CancellationToken token);
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IPathIndexProvider.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IPathIndexProvider.cs
new file mode 100644
index 000000000..4622df5f9
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/IProvider/IPathIndexProvider.cs
@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.IProvider
+{
+ public interface IPathIndexProvider
+ {
+ public IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, CancellationToken token);
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/QuickAccess.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/QuickAccess.cs
index 55975c2a5..cdd2c93e6 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/QuickAccess.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/QuickAccessLinks/QuickAccess.cs
@@ -8,7 +8,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks
{
private const int quickAccessResultScore = 100;
- internal static List AccessLinkListMatched(Query query, List accessLinks)
+ internal static List AccessLinkListMatched(Query query, IEnumerable accessLinks)
{
if (string.IsNullOrEmpty(query.Search))
return new List();
@@ -17,7 +17,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks
var queriedAccessLinks =
accessLinks
- .Where(x => x.Name.Contains(search, StringComparison.OrdinalIgnoreCase))
+ .Where(x => x.Name.Contains(search, StringComparison.OrdinalIgnoreCase) || x.Path.Contains(search, StringComparison.OrdinalIgnoreCase))
.OrderBy(x => x.Type)
.ThenBy(x => x.Name);
@@ -29,7 +29,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks
}).ToList();
}
- internal static List AccessLinkListAll(Query query, List accessLinks)
+ internal static List AccessLinkListAll(Query query, IEnumerable accessLinks)
=> accessLinks
.OrderBy(x => x.Type)
.ThenBy(x => x.Name)
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
index d6d382e9a..88bfecc14 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
@@ -1,4 +1,5 @@
-using Flow.Launcher.Infrastructure;
+using Flow.Launcher.Core.Resource;
+using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin.SharedCommands;
using System;
using System.Diagnostics;
@@ -20,30 +21,42 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Settings = settings;
}
- private static string GetPathWithActionKeyword(string path, ResultType type)
+ private static string GetPathWithActionKeyword(string path, ResultType type, string actionKeyword)
{
- // one of it is enabled
- var keyword = Settings.SearchActionKeywordEnabled ? Settings.SearchActionKeyword : Settings.PathSearchActionKeyword;
-
- keyword = keyword == Query.GlobalPluginWildcardSign ? string.Empty : keyword + " ";
+ // Query.ActionKeyword is string.Empty when Global Action Keyword ('*') is used
+ var keyword = actionKeyword != string.Empty ? actionKeyword + " " : string.Empty;
var formatted_path = path;
if (type == ResultType.Folder)
+ // the seperator is needed so when navigating the folder structure contents of the folder are listed
formatted_path = path.EndsWith(Constants.DirectorySeperator) ? path : path + Constants.DirectorySeperator;
return $"{keyword}{formatted_path}";
}
- internal static Result CreateFolderResult(string title, string subtitle, string path, Query query, int score = 0, bool showIndexState = false, bool windowsIndexed = false)
+ public static Result CreateResult(Query query, SearchResult result)
+ {
+ return result.Type switch
+ {
+ ResultType.Folder or ResultType.Volume => CreateFolderResult(Path.GetFileName(result.FullPath),
+ result.FullPath, result.FullPath, query, 0, result.WindowsIndexed),
+ ResultType.File => CreateFileResult(
+ result.FullPath, query, 0, result.WindowsIndexed),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ }
+
+ internal static Result CreateFolderResult(string title, string subtitle, string path, Query query, int score = 0, bool windowsIndexed = false)
{
return new Result
{
Title = title,
IcoPath = path,
- SubTitle = subtitle,
- AutoCompleteText = GetPathWithActionKeyword(path, ResultType.Folder),
+ SubTitle = Path.GetDirectoryName(path),
+ AutoCompleteText = GetPathWithActionKeyword(path, ResultType.Folder, query.ActionKeyword),
TitleHighlightData = StringMatcher.FuzzySearch(query.Search, title).MatchData,
+ CopyText = path,
Action = c =>
{
if (c.SpecialKeyState.CtrlPressed || (!Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled))
@@ -60,35 +73,33 @@ namespace Flow.Launcher.Plugin.Explorer.Search
}
}
- Context.API.ChangeQuery(GetPathWithActionKeyword(path, ResultType.Folder));
-
+ Context.API.ChangeQuery(GetPathWithActionKeyword(path, ResultType.Folder, query.ActionKeyword));
+
return false;
},
Score = score,
- TitleToolTip = Constants.ToolTipOpenDirectory,
+ TitleToolTip = InternationalizationManager.Instance.GetTranslation("plugin_explorer_plugin_ToolTipOpenDirectory"),
SubTitleToolTip = path,
ContextData = new SearchResult
{
Type = ResultType.Folder,
FullPath = path,
- ShowIndexState = showIndexState,
WindowsIndexed = windowsIndexed
}
};
}
- internal static Result CreateDriveSpaceDisplayResult(string path, bool windowsIndexed = false)
+ internal static Result CreateDriveSpaceDisplayResult(string path, string actionKeyword, bool windowsIndexed = false)
{
var progressBarColor = "#26a0da";
- int progressValue = 0;
var title = string.Empty; // hide title when use progress bar,
- var driveLetter = path.Substring(0, 1).ToUpper();
+ var driveLetter = path[..1].ToUpper();
var driveName = driveLetter + ":\\";
DriveInfo drv = new DriveInfo(driveLetter);
- var subtitle = toReadableSize(drv.AvailableFreeSpace, 2) + " free of " + toReadableSize(drv.TotalSize, 2);
- double UsingSize = (Convert.ToDouble(drv.TotalSize) - Convert.ToDouble(drv.AvailableFreeSpace)) / Convert.ToDouble(drv.TotalSize) * 100;
+ var subtitle = ToReadableSize(drv.AvailableFreeSpace, 2) + " free of " + ToReadableSize(drv.TotalSize, 2);
+ double usingSize = (Convert.ToDouble(drv.TotalSize) - Convert.ToDouble(drv.AvailableFreeSpace)) / Convert.ToDouble(drv.TotalSize) * 100;
- progressValue = Convert.ToInt32(UsingSize);
+ int? progressValue = Convert.ToInt32(usingSize);
if (progressValue >= 90)
progressBarColor = "#da2626";
@@ -97,7 +108,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
Title = title,
SubTitle = subtitle,
- AutoCompleteText = GetPathWithActionKeyword(path, ResultType.Folder),
+ AutoCompleteText = GetPathWithActionKeyword(path, ResultType.Folder, actionKeyword),
IcoPath = path,
Score = 500,
ProgressBar = progressValue,
@@ -111,15 +122,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search
SubTitleToolTip = path,
ContextData = new SearchResult
{
- Type = ResultType.Folder,
+ Type = ResultType.Volume,
FullPath = path,
- ShowIndexState = true,
WindowsIndexed = windowsIndexed
}
};
}
- private static string toReadableSize(long pDrvSize, int pi)
+ private static string ToReadableSize(long pDrvSize, int pi)
{
int mok = 0;
double drvSize = pDrvSize;
@@ -140,49 +150,33 @@ namespace Flow.Launcher.Plugin.Explorer.Search
else if (mok == 4)
Space = " TB";
- var returnStr = string.Format("{0}{1}", Convert.ToInt32(drvSize), Space);
+ var returnStr = $"{Convert.ToInt32(drvSize)}{Space}";
if (mok != 0)
{
- switch (pi)
+ returnStr = pi switch
{
- case 1:
- returnStr = string.Format("{0:F1}{1}", drvSize, Space);
- break;
- case 2:
- returnStr = string.Format("{0:F2}{1}", drvSize, Space);
- break;
- case 3:
- returnStr = string.Format("{0:F3}{1}", drvSize, Space);
- break;
- default:
- returnStr = string.Format("{0}{1}", Convert.ToInt32(drvSize), Space);
- break;
- }
+ 1 => $"{drvSize:F1}{Space}",
+ 2 => $"{drvSize:F2}{Space}",
+ 3 => $"{drvSize:F3}{Space}",
+ _ => $"{Convert.ToInt32(drvSize)}{Space}"
+ };
}
return returnStr;
}
- internal static Result CreateOpenCurrentFolderResult(string path, bool windowsIndexed = false)
+ internal static Result CreateOpenCurrentFolderResult(string path, string actionKeyword, bool windowsIndexed = false)
{
- var retrievedDirectoryPath = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(path);
-
- var folderName = retrievedDirectoryPath.TrimEnd(Constants.DirectorySeperator).Split(new[]
+ // Path passed from PathSearchAsync ends with Constants.DirectorySeperator ('\'), need to remove the seperator
+ // so it's consistent with folder results returned by index search which does not end with one
+ var folderPath = path.TrimEnd(Constants.DirectorySeperator);
+
+ var folderName = folderPath.TrimEnd(Constants.DirectorySeperator).Split(new[]
{
Path.DirectorySeparatorChar
}, StringSplitOptions.None).Last();
- if (retrievedDirectoryPath.EndsWith(":\\"))
- {
- var driveLetter = path.Substring(0, 1).ToUpper();
- folderName = driveLetter + " drive";
- }
-
- var title = "Open current directory";
-
- if (retrievedDirectoryPath != path)
- title = "Open " + folderName;
-
+ var title = $"Open {folderName}";
var subtitleFolderName = folderName;
@@ -195,43 +189,48 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Title = title,
SubTitle = $"Use > to search within {subtitleFolderName}, " +
$"* to search for file extensions or >* to combine both searches.",
- AutoCompleteText = GetPathWithActionKeyword(retrievedDirectoryPath, ResultType.Folder),
- IcoPath = retrievedDirectoryPath,
+ AutoCompleteText = GetPathWithActionKeyword(folderPath, ResultType.Folder, actionKeyword),
+ IcoPath = folderPath,
Score = 500,
- Action = c =>
+ CopyText = folderPath,
+ Action = _ =>
{
- Context.API.OpenDirectory(retrievedDirectoryPath);
+ Context.API.OpenDirectory(folderPath);
return true;
},
- TitleToolTip = retrievedDirectoryPath,
- SubTitleToolTip = retrievedDirectoryPath,
ContextData = new SearchResult
{
Type = ResultType.Folder,
- FullPath = retrievedDirectoryPath,
- ShowIndexState = true,
+ FullPath = folderPath,
WindowsIndexed = windowsIndexed
}
};
}
- internal static Result CreateFileResult(string filePath, Query query, int score = 0, bool showIndexState = false, bool windowsIndexed = false)
+ internal static Result CreateFileResult(string filePath, Query query, int score = 0, bool windowsIndexed = false)
{
+ Result.PreviewInfo preview = IsMedia(Path.GetExtension(filePath)) ? new Result.PreviewInfo {
+ IsMedia = true,
+ PreviewImagePath = filePath,
+ } : Result.PreviewInfo.Default;
+
var result = new Result
{
Title = Path.GetFileName(filePath),
- SubTitle = filePath,
+ SubTitle = Path.GetDirectoryName(filePath),
IcoPath = filePath,
- AutoCompleteText = GetPathWithActionKeyword(filePath, ResultType.File),
+ Preview = preview,
+ AutoCompleteText = GetPathWithActionKeyword(filePath, ResultType.File, query.ActionKeyword),
TitleHighlightData = StringMatcher.FuzzySearch(query.Search, Path.GetFileName(filePath)).MatchData,
Score = score,
+ CopyText = filePath,
Action = c =>
{
try
{
if (File.Exists(filePath) && c.SpecialKeyState.CtrlPressed && c.SpecialKeyState.ShiftPressed)
{
- Task.Run(() =>
+ _ = Task.Run(() =>
{
try
{
@@ -264,28 +263,31 @@ namespace Flow.Launcher.Plugin.Explorer.Search
return true;
},
- TitleToolTip = Constants.ToolTipOpenContainingFolder,
+ TitleToolTip = InternationalizationManager.Instance.GetTranslation("plugin_explorer_plugin_ToolTipOpenContainingFolder"),
SubTitleToolTip = filePath,
ContextData = new SearchResult
{
Type = ResultType.File,
FullPath = filePath,
- ShowIndexState = showIndexState,
WindowsIndexed = windowsIndexed
}
};
return result;
}
- }
- internal class SearchResult
- {
- public string FullPath { get; set; }
- public ResultType Type { get; set; }
+ public static bool IsMedia(string extension)
+ {
+ if (string.IsNullOrEmpty(extension))
+ {
+ return false;
+ }
+ else
+ {
+ return MediaExtensions.Contains(extension.ToLowerInvariant());
+ }
+ }
- public bool WindowsIndexed { get; set; }
-
- public bool ShowIndexState { get; set; }
+ public static readonly string[] MediaExtensions = { ".jpg", ".png", ".avi", ".mkv", ".bmp", ".gif", ".wmv", ".mp3", ".flac", ".mp4" };
}
public enum ResultType
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
index 4bddbda57..fc4186cb3 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
@@ -1,12 +1,13 @@
using Flow.Launcher.Plugin.Explorer.Search.DirectoryInfo;
+using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
-using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
using Flow.Launcher.Plugin.SharedCommands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Flow.Launcher.Plugin.Explorer.Exceptions;
namespace Flow.Launcher.Plugin.Explorer.Search
{
@@ -29,52 +30,92 @@ namespace Flow.Launcher.Plugin.Explorer.Search
public bool Equals(Result x, Result y)
{
- return x.SubTitle == y.SubTitle;
+ return x.Title == y.Title && x.SubTitle == y.SubTitle;
}
public int GetHashCode(Result obj)
{
- return obj.SubTitle.GetHashCode();
+ return HashCode.Combine(obj.Title.GetHashCode(), obj.SubTitle?.GetHashCode() ?? 0);
}
}
internal async Task> SearchAsync(Query query, CancellationToken token)
{
- var querySearch = query.Search;
-
var results = new HashSet(PathEqualityComparator.Instance);
// This allows the user to type the below action keywords and see/search the list of quick folder links
if (ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)
|| ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword)
- || ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword))
+ || ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
+ || ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword)
+ || ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword))
{
- if (string.IsNullOrEmpty(query.Search))
+ if (string.IsNullOrEmpty(query.Search) && ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword))
return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
- var quickaccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
+ var quickAccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
- results.UnionWith(quickaccessLinks);
+ results.UnionWith(quickAccessLinks);
}
-
- if (IsFileContentSearch(query.ActionKeyword))
- return await WindowsIndexFileContentSearchAsync(query, querySearch, token).ConfigureAwait(false);
-
- if (ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword) ||
- ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword))
+ else
{
- results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false));
+ return new List();
}
- if ((ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword) ||
- ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)) &&
- querySearch.Length > 0 &&
- !querySearch.IsLocationPathString())
+ IAsyncEnumerable searchResults;
+
+ bool isPathSearch = query.Search.IsLocationPathString() || IsEnvironmentVariableSearch(query.Search);
+
+ string engineName;
+
+ switch (isPathSearch)
{
- results.UnionWith(await WindowsIndexFilesAndFoldersSearchAsync(query, querySearch, token)
- .ConfigureAwait(false));
+ case true
+ when ActionKeywordMatch(query, Settings.ActionKeyword.PathSearchActionKeyword)
+ || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword):
+
+ results.UnionWith(await PathSearchAsync(query, token).ConfigureAwait(false));
+
+ return results.ToList();
+
+ case false
+ when ActionKeywordMatch(query, Settings.ActionKeyword.FileContentSearchActionKeyword):
+
+ // Intentionally require enabling of Everything's content search due to its slowness
+ if (Settings.ContentIndexProvider is EverythingSearchManager && !Settings.EnableEverythingContentSearch)
+ return EverythingContentSearchResult(query);
+
+ searchResults = Settings.ContentIndexProvider.ContentSearchAsync("", query.Search, token);
+ engineName = Enum.GetName(Settings.ContentSearchEngine);
+ break;
+
+ case false
+ when ActionKeywordMatch(query, Settings.ActionKeyword.IndexSearchActionKeyword)
+ || ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword):
+
+ searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
+ engineName = Enum.GetName(Settings.IndexSearchEngine);
+ break;
+ default:
+ return results.ToList();
}
+ try
+ {
+ await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false))
+ results.Add(ResultManager.CreateResult(query, search));
+ }
+ catch (Exception e)
+ {
+ if (e is OperationCanceledException)
+ return results.ToList();
+
+ throw new SearchException(engineName, e.Message, e);
+ }
+
+ results.RemoveWhere(r => Settings.IndexSearchExcludedSubdirectoryPaths.Any(
+ excludedPath => r.SubTitle.StartsWith(excludedPath.Path, StringComparison.OrdinalIgnoreCase)));
+
return results.ToList();
}
@@ -93,12 +134,31 @@ namespace Flow.Launcher.Plugin.Explorer.Search
Settings.ActionKeyword.IndexSearchActionKeyword => Settings.IndexSearchKeywordEnabled &&
keyword == Settings.IndexSearchActionKeyword,
Settings.ActionKeyword.QuickAccessActionKeyword => Settings.QuickAccessKeywordEnabled &&
- keyword == Settings.QuickAccessActionKeyword,
- _ => throw new NotImplementedException()
+ keyword == Settings.QuickAccessActionKeyword,
+ _ => throw new ArgumentOutOfRangeException(nameof(allowedActionKeyword), allowedActionKeyword, "actionKeyword out of range")
};
}
- public async Task> PathSearchAsync(Query query, CancellationToken token = default)
+ private static List EverythingContentSearchResult(Query query)
+ {
+ return new List()
+ {
+ new()
+ {
+ Title = "Do you want to enable content search for Everything?",
+ SubTitle = "It can be very slow without index (which is only supported in Everything v1.5+)",
+ IcoPath = "Images/index_error.png",
+ Action = c =>
+ {
+ Settings.EnableEverythingContentSearch = true;
+ Context.API.ChangeQuery(query.RawQuery, true);
+ return false;
+ }
+ }
+ };
+ }
+
+ private async Task> PathSearchAsync(Query query, CancellationToken token = default)
{
var querySearch = query.Search;
@@ -118,118 +178,76 @@ namespace Flow.Launcher.Plugin.Explorer.Search
locationPath = EnvironmentVariables.TranslateEnvironmentVariablePath(locationPath);
// Check that actual location exists, otherwise directory search will throw directory not found exception
- if (!FilesFolders.LocationExists(FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath)))
+ if (!FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath).LocationExists())
return results.ToList();
- var useIndexSearch = UseWindowsIndexForDirectorySearch(locationPath);
+ var useIndexSearch = Settings.IndexSearchEngine is Settings.IndexSearchEngineOption.WindowsIndex
+ && UseWindowsIndexForDirectorySearch(locationPath);
- if (locationPath.EndsWith(":\\"))
+ var retrievedDirectoryPath = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath);
+
+ results.Add(retrievedDirectoryPath.EndsWith(":\\")
+ ? ResultManager.CreateDriveSpaceDisplayResult(retrievedDirectoryPath, query.ActionKeyword, useIndexSearch)
+ : ResultManager.CreateOpenCurrentFolderResult(retrievedDirectoryPath, query.ActionKeyword, useIndexSearch));
+
+ if (token.IsCancellationRequested)
+ return new List();
+
+ IAsyncEnumerable directoryResult;
+
+ var recursiveIndicatorIndex = query.Search.IndexOf('>');
+
+ if (recursiveIndicatorIndex > 0 && Settings.PathEnumerationEngine != Settings.PathEnumerationEngineOption.DirectEnumeration)
{
- results.Add(ResultManager.CreateDriveSpaceDisplayResult(locationPath, useIndexSearch));
+ directoryResult =
+ Settings.PathEnumerator.EnumerateAsync(
+ query.Search[..recursiveIndicatorIndex],
+ query.Search[(recursiveIndicatorIndex + 1)..],
+ true,
+ token);
+
}
else
{
- results.Add(ResultManager.CreateOpenCurrentFolderResult(locationPath, useIndexSearch));
+ directoryResult = DirectoryInfoSearch.TopLevelDirectorySearch(query, query.Search, token).ToAsyncEnumerable();
}
- token.ThrowIfCancellationRequested();
+ if (token.IsCancellationRequested)
+ return new List();
- var directoryResult = await TopLevelDirectorySearchBehaviourAsync(WindowsIndexTopLevelFolderSearchAsync,
- DirectoryInfoClassSearch,
- useIndexSearch,
- query,
- locationPath,
- token).ConfigureAwait(false);
+ try
+ {
+ await foreach (var directory in directoryResult.WithCancellation(token).ConfigureAwait(false))
+ {
+ results.Add(ResultManager.CreateResult(query, directory));
+ }
+ }
+ catch (Exception e)
+ {
+ throw new SearchException(Enum.GetName(Settings.PathEnumerationEngine), e.Message, e);
+ }
- token.ThrowIfCancellationRequested();
-
- results.UnionWith(directoryResult);
return results.ToList();
}
- private async Task> WindowsIndexFileContentSearchAsync(Query query, string querySearchString,
- CancellationToken token)
- {
- var queryConstructor = new QueryConstructor(Settings);
+ public static bool IsFileContentSearch(string actionKeyword) => actionKeyword == Settings.FileContentSearchActionKeyword;
- if (string.IsNullOrEmpty(querySearchString))
- return new List();
-
- return await IndexSearch.WindowsIndexSearchAsync(
- querySearchString,
- queryConstructor.CreateQueryHelper,
- queryConstructor.QueryForFileContentSearch,
- Settings.IndexSearchExcludedSubdirectoryPaths,
- query,
- token).ConfigureAwait(false);
- }
-
- public bool IsFileContentSearch(string actionKeyword)
- {
- return actionKeyword == Settings.FileContentSearchActionKeyword;
- }
-
- private List DirectoryInfoClassSearch(Query query, string querySearch, CancellationToken token)
- {
- return DirectoryInfoSearch.TopLevelDirectorySearch(query, querySearch, token);
- }
-
- public async Task> TopLevelDirectorySearchBehaviourAsync(
- Func>> windowsIndexSearch,
- Func> directoryInfoClassSearch,
- bool useIndexSearch,
- Query query,
- string querySearchString,
- CancellationToken token)
- {
- if (!useIndexSearch)
- return directoryInfoClassSearch(query, querySearchString, token);
-
- return await windowsIndexSearch(query, querySearchString, token);
- }
-
- private async Task> WindowsIndexFilesAndFoldersSearchAsync(Query query, string querySearchString,
- CancellationToken token)
- {
- var queryConstructor = new QueryConstructor(Settings);
-
- return await IndexSearch.WindowsIndexSearchAsync(
- querySearchString,
- queryConstructor.CreateQueryHelper,
- queryConstructor.QueryForAllFilesAndFolders,
- Settings.IndexSearchExcludedSubdirectoryPaths,
- query,
- token).ConfigureAwait(false);
- }
-
- private async Task> WindowsIndexTopLevelFolderSearchAsync(Query query, string path,
- CancellationToken token)
- {
- var queryConstructor = new QueryConstructor(Settings);
-
- return await IndexSearch.WindowsIndexSearchAsync(
- path,
- queryConstructor.CreateQueryHelper,
- queryConstructor.QueryForTopLevelDirectorySearch,
- Settings.IndexSearchExcludedSubdirectoryPaths,
- query,
- token).ConfigureAwait(false);
- }
private bool UseWindowsIndexForDirectorySearch(string locationPath)
{
var pathToDirectory = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath);
- if (!Settings.UseWindowsIndexForDirectorySearch)
- return false;
-
- if (Settings.IndexSearchExcludedSubdirectoryPaths
- .Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory)
- .StartsWith(x.Path, StringComparison.OrdinalIgnoreCase)))
- return false;
-
- return IndexSearch.PathIsIndexed(pathToDirectory);
+ return !Settings.IndexSearchExcludedSubdirectoryPaths.Any(
+ x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory).StartsWith(x.Path, StringComparison.OrdinalIgnoreCase))
+ && WindowsIndex.WindowsIndex.PathIsIndexed(pathToDirectory);
+ }
+
+ internal static bool IsEnvironmentVariableSearch(string search)
+ {
+ return search.StartsWith("%")
+ && search != "%%"
+ && !search.Contains('\\');
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs
new file mode 100644
index 000000000..92c24559d
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchResult.cs
@@ -0,0 +1,13 @@
+using System;
+
+namespace Flow.Launcher.Plugin.Explorer.Search
+{
+ public record struct SearchResult
+ {
+ public string FullPath { get; init; }
+ public ResultType Type { get; init; }
+ public int Score { get; init; }
+
+ public bool WindowsIndexed { get; init; }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
deleted file mode 100644
index 318a9bde9..000000000
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-using Flow.Launcher.Infrastructure.Logger;
-using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
-using Microsoft.Search.Interop;
-using System;
-using System.Collections.Generic;
-using System.Data.OleDb;
-using System.Linq;
-using System.Runtime.InteropServices;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-using System.Windows;
-
-namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
-{
- internal static class IndexSearch
- {
-
- // Reserved keywords in oleDB
- private const string reservedStringPattern = @"^[`\@\@\#\#\*\^,\&\&\/\\\$\%_;\[\]]+$";
-
- internal static async Task> ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, Query query, CancellationToken token)
- {
- var results = new List();
- var fileResults = new List();
-
- try
- {
- await using var conn = new OleDbConnection(connectionString);
- await conn.OpenAsync(token);
- token.ThrowIfCancellationRequested();
-
- await using var command = new OleDbCommand(indexQueryString, conn);
- // Results return as an OleDbDataReader.
- await using var dataReaderResults = await command.ExecuteReaderAsync(token) as OleDbDataReader;
- token.ThrowIfCancellationRequested();
-
- if (dataReaderResults.HasRows)
- {
- while (await dataReaderResults.ReadAsync(token))
- {
- token.ThrowIfCancellationRequested();
- if (dataReaderResults.GetValue(0) != DBNull.Value && dataReaderResults.GetValue(1) != DBNull.Value)
- {
- // # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
- var encodedFragmentPath = dataReaderResults
- .GetString(1)
- .Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
-
- var path = new Uri(encodedFragmentPath).LocalPath;
-
- if (dataReaderResults.GetString(2) == "Directory")
- {
- results.Add(ResultManager.CreateFolderResult(
- dataReaderResults.GetString(0),
- path,
- path,
- query, 0, true, true));
- }
- else
- {
- fileResults.Add(ResultManager.CreateFileResult(path, query, 0, true, true));
- }
- }
- }
- }
- }
- catch (OperationCanceledException)
- {
- // return empty result when cancelled
- return results;
- }
- catch (InvalidOperationException e)
- {
- // Internal error from ExecuteReader(): Connection closed.
- LogException("Internal error from ExecuteReader()", e);
- }
- catch (Exception e)
- {
- LogException("General error from performing index search", e);
- }
-
- results.AddRange(fileResults);
-
- // Intial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
- return results;
- }
-
- internal async static Task> WindowsIndexSearchAsync(
- string searchString,
- Func createQueryHelper,
- Func constructQuery,
- List exclusionList,
- Query query,
- CancellationToken token)
- {
- var regexMatch = Regex.Match(searchString, reservedStringPattern);
-
- if (regexMatch.Success)
- return new List();
-
- try
- {
- var constructedQuery = constructQuery(searchString);
-
- return RemoveResultsInExclusionList(
- await ExecuteWindowsIndexSearchAsync(constructedQuery, createQueryHelper().ConnectionString, query, token).ConfigureAwait(false),
- exclusionList,
- token);
- }
- catch (COMException)
- {
- // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
- if (!SearchManager.Settings.WarnWindowsSearchServiceOff)
- return new List();
-
- return ResultForWindexSearchOff(query.RawQuery);
- }
- }
-
- private static List RemoveResultsInExclusionList(List results, List exclusionList, CancellationToken token)
- {
- var indexExclusionListCount = exclusionList.Count;
-
- if (indexExclusionListCount == 0)
- return results;
-
- var filteredResults = new List();
-
- for (var index = 0; index < results.Count; index++)
- {
- token.ThrowIfCancellationRequested();
-
- var excludeResult = false;
-
- for (var i = 0; i < indexExclusionListCount; i++)
- {
- token.ThrowIfCancellationRequested();
-
- if (results[index].SubTitle.StartsWith(exclusionList[i].Path, StringComparison.OrdinalIgnoreCase))
- {
- excludeResult = true;
- break;
- }
- }
-
- if (!excludeResult)
- filteredResults.Add(results[index]);
- }
-
- return filteredResults;
- }
-
- internal static bool PathIsIndexed(string path)
- {
- try
- {
- var csm = new CSearchManager();
- var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
- return indexManager.IncludedInCrawlScope(path) > 0;
- }
- catch(COMException)
- {
- // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
- return false;
- }
- }
-
- private static List ResultForWindexSearchOff(string rawQuery)
- {
- var api = SearchManager.Context.API;
-
- return new List
- {
- new Result
- {
- Title = api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"),
- SubTitle = api.GetTranslation("plugin_explorer_windowsSearchServiceFix"),
- Action = c =>
- {
- SearchManager.Settings.WarnWindowsSearchServiceOff = false;
-
- var pluginsManagerPlugin= api.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == "9f8f9b14-2518-4907-b211-35ab6290dee7");
-
- var actionKeywordCount = pluginsManagerPlugin.Metadata.ActionKeywords.Count;
-
- if (actionKeywordCount > 1)
- LogException("PluginsManager's action keyword has increased to more than 1, this does not allow for determining the " +
- "right action keyword. Explorer's code for managing Windows Search service not running exception needs to be updated",
- new InvalidOperationException());
-
- if (MessageBox.Show(string.Format(api.GetTranslation("plugin_explorer_alternative"), Environment.NewLine),
- api.GetTranslation("plugin_explorer_alternative_title"),
- MessageBoxButton.YesNo) == MessageBoxResult.Yes
- && actionKeywordCount == 1)
- {
- api.ChangeQuery(string.Format("{0} install everything", pluginsManagerPlugin.Metadata.ActionKeywords[0]));
- }
- else
- {
- // Clears the warning message because same query string will not alter the displayed result list
- api.ChangeQuery(string.Empty);
-
- api.ChangeQuery(rawQuery);
- }
-
- var mainWindow = Application.Current.MainWindow;
- mainWindow.Show();
- mainWindow.Focus();
-
- return false;
- },
- IcoPath = Constants.ExplorerIconImagePath
- }
- };
- }
-
- private static void LogException(string message, Exception e)
- {
-#if DEBUG // Please investigate and handle error from index search
- throw e;
-#else
- Log.Exception($"|Flow.Launcher.Plugin.Explorer.IndexSearch|{message}", e);
-#endif
- }
- }
-}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
index 20e85bbb5..87eca91da 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
@@ -1,10 +1,12 @@
+using System;
+using System.Buffers;
using Microsoft.Search.Interop;
namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
{
public class QueryConstructor
{
- private readonly Settings settings;
+ private Settings settings { get; }
private const string SystemIndex = "SystemIndex";
@@ -35,6 +37,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
internal CSearchQueryHelper CreateQueryHelper()
{
// This uses the Microsoft.Search.Interop assembly
+ // Throws COMException if Windows Search service is not running/disabled, this needs to be caught
var manager = new CSearchManager();
// SystemIndex catalog is the default catalog in Windows
@@ -42,98 +45,67 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
// Get the ISearchQueryHelper which will help us to translate AQS --> SQL necessary to query the indexer
var queryHelper = catalogManager.GetQueryHelper();
-
+
return queryHelper;
}
- ///
- /// Set the required WHERE clause restriction to search on the first level of a specified directory.
- ///
- public string QueryWhereRestrictionsForTopLevelDirectorySearch(string path)
- {
- var searchDepth = $"directory='file:";
-
- return QueryWhereRestrictionsFromLocationPath(path, searchDepth);
- }
-
- ///
- /// Set the required WHERE clause restriction to search all files and subfolders of a specified directory.
- ///
- public string QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(string path)
- {
- var searchDepth = $"scope='file:";
-
- return QueryWhereRestrictionsFromLocationPath(path, searchDepth);
- }
-
- private string QueryWhereRestrictionsFromLocationPath(string path, string searchDepth)
- {
- if (path.EndsWith(Constants.DirectorySeperator))
- return searchDepth + $"{path}'";
-
- var indexOfSeparator = path.LastIndexOf(Constants.DirectorySeperator);
-
- var itemName = path.Substring(indexOfSeparator + 1);
-
- if (itemName.StartsWith(Constants.AllFilesFolderSearchWildcard))
- itemName = itemName.Substring(1);
-
- var previousLevelDirectory = path.Substring(0, indexOfSeparator);
-
- if (string.IsNullOrEmpty(itemName))
- return $"{searchDepth}{previousLevelDirectory}'";
-
- return $"(System.FileName LIKE '{itemName}%' OR CONTAINS(System.FileName,'\"{itemName}*\"',1033)) AND {searchDepth}{previousLevelDirectory}'";
- }
+ public static string TopLevelDirectoryConstraint(ReadOnlySpan path) => $"directory='file:{path}'";
+ public static string RecursiveDirectoryConstraint(ReadOnlySpan path) => $"scope='file:{path}'";
+
///
/// Search will be performed on all folders and files on the first level of a specified directory.
///
- public string QueryForTopLevelDirectorySearch(string path)
+ public string Directory(ReadOnlySpan path, ReadOnlySpan searchString = default, bool recursive = false)
{
- string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
+ var queryConstraint = searchString.IsWhiteSpace() ? "" : $"AND ({FileName} LIKE '{searchString}%' OR CONTAINS({FileName},'\"{searchString}*\"'))";
- if (path.LastIndexOf(Constants.AllFilesFolderSearchWildcard) > path.LastIndexOf(Constants.DirectorySeperator))
- return query + QueryWhereRestrictionsForTopLevelDirectoryAllFilesAndFoldersSearch(path) + QueryOrderByFileNameRestriction;
+ var scopeConstraint = recursive
+ ? RecursiveDirectoryConstraint(path)
+ : TopLevelDirectoryConstraint(path);
- return query + QueryWhereRestrictionsForTopLevelDirectorySearch(path) + QueryOrderByFileNameRestriction;
+ var query = $"SELECT TOP {settings.MaxResult} {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE {scopeConstraint} {queryConstraint} ORDER BY {FileName}";
+
+ return query;
}
///
/// Search will be performed on all folders and files based on user's search keywords.
///
- public string QueryForAllFilesAndFolders(string userSearchString)
+ public string FilesAndFolders(ReadOnlySpan userSearchString)
{
+ if (userSearchString.IsWhiteSpace())
+ userSearchString = "*";
+
// Generate SQL from constructed parameters, converting the userSearchString from AQS->WHERE clause
- return CreateBaseQuery().GenerateSQLFromUserQuery(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
- + QueryOrderByFileNameRestriction;
+ return $"{CreateBaseQuery().GenerateSQLFromUserQuery(userSearchString.ToString())} AND {RestrictionsForAllFilesAndFoldersSearch} ORDER BY {FileName}";
}
///
/// Set the required WHERE clause restriction to search for all files and folders.
///
- public const string QueryWhereRestrictionsForAllFilesAndFoldersSearch = "scope='file:'";
+ public const string RestrictionsForAllFilesAndFoldersSearch = "scope='file:'";
- public const string QueryOrderByFileNameRestriction = " ORDER BY System.FileName";
+ ///
+ /// Order identifier: file name
+ ///
+ public const string FileName = "System.FileName";
///
/// Search will be performed on all indexed file contents for the specified search keywords.
///
- public string QueryForFileContentSearch(string userSearchString)
+ public string FileContent(ReadOnlySpan userSearchString)
{
- string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
+ string query =
+ $"SELECT TOP {settings.MaxResult} {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE {RestrictionsForFileContentSearch(userSearchString)} AND {RestrictionsForAllFilesAndFoldersSearch} ORDER BY {FileName}";
- return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch
- + QueryOrderByFileNameRestriction;
+ return query;
}
///
/// Set the required WHERE clause restriction to search within file content.
///
- public string QueryWhereRestrictionsForFileContentSearch(string searchQuery)
- {
- return $"FREETEXT('{searchQuery}')";
- }
+ public static string RestrictionsForFileContentSearch(ReadOnlySpan searchQuery) => $"FREETEXT('{searchQuery}')";
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs
new file mode 100644
index 000000000..2093508a0
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndex.cs
@@ -0,0 +1,106 @@
+using Flow.Launcher.Infrastructure.Logger;
+using Microsoft.Search.Interop;
+using System;
+using System.Collections.Generic;
+using System.Data.OleDb;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using Flow.Launcher.Plugin.Explorer.Exceptions;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
+{
+ internal static class WindowsIndex
+ {
+
+ // Reserved keywords in oleDB
+ private static Regex _reservedPatternMatcher = new(@"^[`\@\@\#\#\*\^,\&\&\/\\\$\%_;\[\]]+$", RegexOptions.Compiled);
+
+ private static async IAsyncEnumerable ExecuteWindowsIndexSearchAsync(string indexQueryString, string connectionString, [EnumeratorCancellation] CancellationToken token)
+ {
+ await using var conn = new OleDbConnection(connectionString);
+ await conn.OpenAsync(token);
+ token.ThrowIfCancellationRequested();
+
+ await using var command = new OleDbCommand(indexQueryString, conn);
+ // Results return as an OleDbDataReader.
+ OleDbDataReader dataReaderAttempt;
+ try
+ {
+ dataReaderAttempt = await command.ExecuteReaderAsync(token) as OleDbDataReader;
+ }
+ catch (OleDbException e)
+ {
+ Log.Exception($"|WindowsIndex.ExecuteWindowsIndexSearchAsync|Failed to execute windows index search query: {indexQueryString}", e);
+ yield break;
+ }
+ await using var dataReader = dataReaderAttempt;
+ token.ThrowIfCancellationRequested();
+
+ if (dataReader is not { HasRows: true })
+ {
+ yield break;
+ }
+
+ while (await dataReader.ReadAsync(token))
+ {
+ token.ThrowIfCancellationRequested();
+ if (dataReader.GetValue(0) == DBNull.Value || dataReader.GetValue(1) == DBNull.Value)
+ {
+ continue;
+ }
+ // # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
+ var encodedFragmentPath = dataReader
+ .GetString(1)
+ .Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
+
+ var path = new Uri(encodedFragmentPath).LocalPath;
+
+ yield return new SearchResult
+ {
+ FullPath = path,
+ Type = dataReader.GetString(2) == "Directory" ? ResultType.Folder : ResultType.File,
+ WindowsIndexed = true
+ };
+ }
+
+ // Initial ordering, this order can be updated later by UpdateResultView.MainViewModel based on history of user selection.
+ }
+
+ internal static IAsyncEnumerable WindowsIndexSearchAsync(
+ string connectionString,
+ string search,
+ CancellationToken token)
+ {
+ try
+ {
+
+ return _reservedPatternMatcher.IsMatch(search)
+ ? AsyncEnumerable.Empty()
+ : ExecuteWindowsIndexSearchAsync(search, connectionString, token);
+ }
+ catch (InvalidOperationException e)
+ {
+ throw new SearchException("Windows Index", e.Message, e);
+ }
+ }
+
+ internal static bool PathIsIndexed(string path)
+ {
+ try
+ {
+ var csm = new CSearchManager();
+ var indexManager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
+ return indexManager.IncludedInCrawlScope(path) > 0;
+ }
+ catch (COMException)
+ {
+ // Occurs because the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
+ return false;
+ }
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs
new file mode 100644
index 000000000..abb50849d
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/WindowsIndexSearchManager.cs
@@ -0,0 +1,123 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using Flow.Launcher.Plugin.Explorer.Exceptions;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
+
+namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
+{
+ public class WindowsIndexSearchManager : IIndexProvider, IContentIndexProvider, IPathIndexProvider
+ {
+ private Settings Settings { get; }
+
+ private QueryConstructor QueryConstructor { get; }
+
+ public WindowsIndexSearchManager(Settings settings)
+ {
+ Settings = settings;
+ QueryConstructor = new QueryConstructor(Settings);
+ }
+
+ private IAsyncEnumerable WindowsIndexFileContentSearchAsync(
+ ReadOnlySpan querySearchString,
+ CancellationToken token)
+ {
+ if (querySearchString.IsEmpty)
+ return AsyncEnumerable.Empty();
+
+ try
+ {
+ return WindowsIndex.WindowsIndexSearchAsync(
+ QueryConstructor.CreateQueryHelper().ConnectionString,
+ QueryConstructor.FileContent(querySearchString),
+ token);
+ }
+ catch (COMException)
+ {
+ // Occurs when the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
+ // Thrown by QueryConstructor.CreateQueryHelper()
+ return HandledEngineNotAvailableExceptionAsync();
+ }
+ }
+
+ private IAsyncEnumerable WindowsIndexFilesAndFoldersSearchAsync(
+ ReadOnlySpan querySearchString,
+ CancellationToken token = default)
+ {
+ try
+ {
+ return WindowsIndex.WindowsIndexSearchAsync(
+ QueryConstructor.CreateQueryHelper().ConnectionString,
+ QueryConstructor.FilesAndFolders(querySearchString),
+ token);
+ }
+ catch (COMException)
+ {
+ // Occurs when the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
+ // Thrown by QueryConstructor.CreateQueryHelper()
+ return HandledEngineNotAvailableExceptionAsync();
+ }
+ }
+
+ private IAsyncEnumerable WindowsIndexTopLevelFolderSearchAsync(
+ ReadOnlySpan search,
+ ReadOnlySpan path,
+ bool recursive,
+ CancellationToken token)
+ {
+ try
+ {
+ return WindowsIndex.WindowsIndexSearchAsync(
+ QueryConstructor.CreateQueryHelper().ConnectionString,
+ QueryConstructor.Directory(path, search, recursive),
+ token);
+ }
+ catch (COMException)
+ {
+ // Occurs when the Windows Indexing (WSearch) is turned off in services and unable to be used by Explorer plugin
+ // Thrown by QueryConstructor.CreateQueryHelper()
+ return HandledEngineNotAvailableExceptionAsync();
+ }
+ }
+ public IAsyncEnumerable SearchAsync(string search, CancellationToken token)
+ {
+ return WindowsIndexFilesAndFoldersSearchAsync(search, token: token);
+ }
+ public IAsyncEnumerable ContentSearchAsync(string plainSearch, string contentSearch, CancellationToken token)
+ {
+ return WindowsIndexFileContentSearchAsync(contentSearch, token);
+ }
+ public IAsyncEnumerable EnumerateAsync(string path, string search, bool recursive, CancellationToken token)
+ {
+ return WindowsIndexTopLevelFolderSearchAsync(search, path, recursive, token);
+ }
+
+ private IAsyncEnumerable HandledEngineNotAvailableExceptionAsync()
+ {
+ if (!SearchManager.Settings.WarnWindowsSearchServiceOff)
+ return AsyncEnumerable.Empty();
+
+ var api = SearchManager.Context.API;
+
+ throw new EngineNotAvailableException(
+ "Windows Index",
+ api.GetTranslation("plugin_explorer_windowsSearchServiceFix"),
+ api.GetTranslation("plugin_explorer_windowsSearchServiceNotRunning"),
+ c =>
+ {
+ SearchManager.Settings.WarnWindowsSearchServiceOff = false;
+
+ // Clears the warning message so user is not mistaken that it has not worked
+ api.ChangeQuery(string.Empty);
+
+ return ValueTask.FromResult(false);
+ })
+ {
+ ErrorIcon = Constants.WindowsIndexErrorImagePath
+ };
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
index 90b85d187..67c4061d4 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
@@ -1,7 +1,15 @@
+using Flow.Launcher.Plugin.Everything.Everything;
using Flow.Launcher.Plugin.Explorer.Search;
+using Flow.Launcher.Plugin.Explorer.Search.Everything;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
+using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex;
using System;
using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Text.Json.Serialization;
+using Flow.Launcher.Plugin.Explorer.Search.IProvider;
namespace Flow.Launcher.Plugin.Explorer
{
@@ -9,14 +17,19 @@ namespace Flow.Launcher.Plugin.Explorer
{
public int MaxResult { get; set; } = 100;
- public List QuickAccessLinks { get; set; } = new List();
+ public ObservableCollection QuickAccessLinks { get; set; } = new();
- // as at v1.7.0 this is to maintain backwards compatibility, need to be removed afterwards.
- public List QuickFolderAccessLinks { get; set; } = new List();
+ public ObservableCollection IndexSearchExcludedSubdirectoryPaths { get; set; } = new ObservableCollection();
- public bool UseWindowsIndexForDirectorySearch { get; set; } = false;
+ public string EditorPath { get; set; } = "";
+
+ public string ShellPath { get; set; } = "cmd";
+
+
+ public bool UseLocationAsWorkingDir { get; set; } = false;
+
+ public bool ShowWindowsContextMenu { get; set; } = true;
- public List IndexSearchExcludedSubdirectoryPaths { get; set; } = new List();
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
@@ -38,8 +51,92 @@ namespace Flow.Launcher.Plugin.Explorer
public bool QuickAccessKeywordEnabled { get; set; }
+
public bool WarnWindowsSearchServiceOff { get; set; } = true;
+ private EverythingSearchManager _everythingManagerInstance;
+ private WindowsIndexSearchManager _windowsIndexSearchManager;
+
+ #region SearchEngine
+
+ private EverythingSearchManager EverythingManagerInstance => _everythingManagerInstance ??= new EverythingSearchManager(this);
+ private WindowsIndexSearchManager WindowsIndexSearchManager => _windowsIndexSearchManager ??= new WindowsIndexSearchManager(this);
+
+
+ public IndexSearchEngineOption IndexSearchEngine { get; set; } = IndexSearchEngineOption.WindowsIndex;
+ [JsonIgnore]
+ public IIndexProvider IndexProvider => IndexSearchEngine switch
+ {
+ IndexSearchEngineOption.Everything => EverythingManagerInstance,
+ IndexSearchEngineOption.WindowsIndex => WindowsIndexSearchManager,
+ _ => throw new ArgumentOutOfRangeException(nameof(IndexSearchEngine))
+ };
+
+ public PathEnumerationEngineOption PathEnumerationEngine { get; set; } = PathEnumerationEngineOption.WindowsIndex;
+
+ [JsonIgnore]
+ public IPathIndexProvider PathEnumerator => PathEnumerationEngine switch
+ {
+ PathEnumerationEngineOption.Everything => EverythingManagerInstance,
+ PathEnumerationEngineOption.WindowsIndex => WindowsIndexSearchManager,
+ _ => throw new ArgumentOutOfRangeException(nameof(PathEnumerationEngine))
+ };
+
+ public ContentIndexSearchEngineOption ContentSearchEngine { get; set; } = ContentIndexSearchEngineOption.WindowsIndex;
+ [JsonIgnore]
+ public IContentIndexProvider ContentIndexProvider => ContentSearchEngine switch
+ {
+ ContentIndexSearchEngineOption.Everything => EverythingManagerInstance,
+ ContentIndexSearchEngineOption.WindowsIndex => WindowsIndexSearchManager,
+ _ => throw new ArgumentOutOfRangeException(nameof(ContentSearchEngine))
+ };
+
+ public enum PathEnumerationEngineOption
+ {
+ [Description("plugin_explorer_engine_windows_index")]
+ WindowsIndex,
+ [Description("plugin_explorer_engine_everything")]
+ Everything,
+ [Description("plugin_explorer_path_enumeration_engine_none")]
+ DirectEnumeration
+ }
+
+ public enum IndexSearchEngineOption
+ {
+ [Description("plugin_explorer_engine_windows_index")]
+ WindowsIndex,
+ [Description("plugin_explorer_engine_everything")]
+ Everything,
+ }
+
+ public enum ContentIndexSearchEngineOption
+ {
+ [Description("plugin_explorer_engine_windows_index")]
+ WindowsIndex,
+ [Description("plugin_explorer_engine_everything")]
+ Everything,
+ }
+
+ #endregion
+
+
+ #region Everything Settings
+
+ public string EverythingInstalledPath { get; set; }
+
+ [JsonIgnore]
+ public SortOption[] SortOptions { get; set; } = Enum.GetValues();
+
+ public SortOption SortOption { get; set; } = SortOption.NAME_ASCENDING;
+
+ public bool EnableEverythingContentSearch { get; set; } = false;
+
+ public bool EverythingEnabled => IndexSearchEngine == IndexSearchEngineOption.Everything ||
+ PathEnumerationEngine == PathEnumerationEngineOption.Everything ||
+ ContentSearchEngine == ContentIndexSearchEngineOption.Everything;
+
+ #endregion
+
internal enum ActionKeyword
{
SearchActionKeyword,
@@ -89,4 +186,4 @@ namespace Flow.Launcher.Plugin.Explorer
_ => throw new ArgumentOutOfRangeException(nameof(actionKeyword), actionKeyword, "ActionKeyword enabled status not defined")
};
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs
new file mode 100644
index 000000000..2f614ead8
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/ActionKeywordModel.cs
@@ -0,0 +1,57 @@
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+
+namespace Flow.Launcher.Plugin.Explorer.Views
+{
+ public class ActionKeywordModel : INotifyPropertyChanged
+ {
+ private static Settings _settings;
+
+ public event PropertyChangedEventHandler PropertyChanged;
+
+ public static void Init(Settings settings)
+ {
+ _settings = settings;
+ }
+
+ internal ActionKeywordModel(Settings.ActionKeyword actionKeyword, string description)
+ {
+ KeywordProperty = actionKeyword;
+ Description = description;
+ }
+
+ public string Description { get; private init; }
+
+ internal Settings.ActionKeyword KeywordProperty { get; }
+
+ private void OnPropertyChanged([CallerMemberName] string propertyName = "")
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+
+ private string? keyword;
+
+ public string Keyword
+ {
+ get => keyword ??= _settings.GetActionKeyword(KeywordProperty);
+ set
+ {
+ keyword = value;
+ _settings.SetActionKeyword(KeywordProperty, value);
+ OnPropertyChanged();
+ }
+ }
+ private bool? enabled;
+
+ public bool Enabled
+ {
+ get => enabled ??= _settings.GetActionKeywordEnabled(KeywordProperty);
+ set
+ {
+ enabled = value;
+ _settings.SetActionKeywordEnabled(KeywordProperty, value);
+ OnPropertyChanged();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/EnumBindingModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/EnumBindingModel.cs
new file mode 100644
index 000000000..29c81a465
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/EnumBindingModel.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace Flow.Launcher.Plugin.Explorer.ViewModels;
+
+public class EnumBindingModel where T : struct, Enum
+{
+ public static IReadOnlyList> CreateList()
+ {
+ return Enum.GetValues()
+ .Select(value => new EnumBindingModel
+ {
+ Value = value, LocalizationKey = GetDescriptionAttr(value)
+ })
+ .ToArray();
+ }
+
+ public EnumBindingModel From(T value)
+ {
+ var name = value.ToString();
+ var description = GetDescriptionAttr(value);
+
+ return new EnumBindingModel
+ {
+ Name = name,
+ LocalizationKey = description,
+ Value = value
+ };
+ }
+
+ private static string GetDescriptionAttr(T source)
+ {
+ var fi = source.GetType().GetField(source.ToString());
+
+ var attributes = (DescriptionAttribute[])fi?.GetCustomAttributes(
+ typeof(DescriptionAttribute), false);
+
+ return attributes is { Length: > 0 } ? attributes[0].Description : source.ToString();
+
+ }
+
+ public string Name { get; set; }
+ private string LocalizationKey { get; set; }
+ public string Description => Main.Context.API.GetTranslation(LocalizationKey);
+ public T Value { get; set; }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/RelayCommand.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/RelayCommand.cs
new file mode 100644
index 000000000..ff704b679
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/RelayCommand.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Windows.Input;
+
+namespace Flow.Launcher.Plugin.Explorer.ViewModels
+{
+ internal class RelayCommand : ICommand
+ {
+ private Action _action;
+
+ public RelayCommand(Action action)
+ {
+ _action = action;
+ }
+
+ public virtual bool CanExecute(object parameter)
+ {
+ return true;
+ }
+
+ public event EventHandler CanExecuteChanged;
+
+ public virtual void Execute(object parameter)
+ {
+ _action?.Invoke(parameter);
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
index 9167691b4..5975d3f16 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
@@ -1,22 +1,40 @@
-using Flow.Launcher.Core.Plugin;
-using Flow.Launcher.Infrastructure.Storage;
+#nullable enable
using Flow.Launcher.Plugin.Explorer.Search;
+using Flow.Launcher.Plugin.Explorer.Search.Everything;
+using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions;
using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks;
+using Flow.Launcher.Plugin.Explorer.Views;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
using System.Diagnostics;
-using System.Threading.Tasks;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
+using System.Windows;
+using System.Windows.Forms;
+using System.Windows.Input;
+using MessageBox = System.Windows.Forms.MessageBox;
namespace Flow.Launcher.Plugin.Explorer.ViewModels
{
- public class SettingsViewModel
+ public class SettingsViewModel : BaseModel
{
- internal Settings Settings { get; set; }
+ public Settings Settings { get; set; }
internal PluginInitContext Context { get; set; }
+ public IReadOnlyList> IndexSearchEngines { get; set; }
+ public IReadOnlyList> ContentIndexSearchEngines { get; set; }
+ public IReadOnlyList> PathEnumerationEngines { get; set; }
+
public SettingsViewModel(PluginInitContext context, Settings settings)
{
Context = context;
Settings = settings;
+
+ InitializeEngineSelection();
+ InitializeActionKeywordModels();
}
@@ -25,11 +43,267 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
Context.API.SaveSettingJsonStorage();
}
- internal void RemoveLinkFromQuickAccess(AccessLink selectedRow) => Settings.QuickAccessLinks.Remove(selectedRow);
+ #region Engine Selection
- internal void RemoveAccessLinkFromExcludedIndexPaths(AccessLink selectedRow) => Settings.IndexSearchExcludedSubdirectoryPaths.Remove(selectedRow);
+ private EnumBindingModel _selectedIndexSearchEngine;
+ private EnumBindingModel _selectedContentSearchEngine;
+ private EnumBindingModel _selectedPathEnumerationEngine;
- internal void OpenWindowsIndexingOptions()
+
+ public EnumBindingModel SelectedIndexSearchEngine
+ {
+ get => _selectedIndexSearchEngine;
+ set
+ {
+ _selectedIndexSearchEngine = value;
+ Settings.IndexSearchEngine = value.Value;
+ OnPropertyChanged();
+ }
+ }
+
+ public EnumBindingModel SelectedContentSearchEngine
+ {
+ get => _selectedContentSearchEngine;
+ set
+ {
+ _selectedContentSearchEngine = value;
+ Settings.ContentSearchEngine = value.Value;
+ OnPropertyChanged();
+ }
+ }
+
+ public EnumBindingModel SelectedPathEnumerationEngine
+ {
+ get => _selectedPathEnumerationEngine;
+ set
+ {
+ _selectedPathEnumerationEngine = value;
+ Settings.PathEnumerationEngine = value.Value;
+ OnPropertyChanged();
+ }
+ }
+
+ [MemberNotNull(nameof(IndexSearchEngines),
+ nameof(ContentIndexSearchEngines),
+ nameof(PathEnumerationEngines),
+ nameof(_selectedIndexSearchEngine),
+ nameof(_selectedContentSearchEngine),
+ nameof(_selectedPathEnumerationEngine))]
+ private void InitializeEngineSelection()
+ {
+ IndexSearchEngines = EnumBindingModel.CreateList();
+ ContentIndexSearchEngines = EnumBindingModel.CreateList();
+ PathEnumerationEngines = EnumBindingModel.CreateList();
+
+ _selectedIndexSearchEngine = IndexSearchEngines.First(x => x.Value == Settings.IndexSearchEngine);
+ _selectedContentSearchEngine = ContentIndexSearchEngines.First(x => x.Value == Settings.ContentSearchEngine);
+ _selectedPathEnumerationEngine = PathEnumerationEngines.First(x => x.Value == Settings.PathEnumerationEngine);
+ }
+
+ #endregion
+
+
+
+ #region ActionKeyword
+
+ [MemberNotNull(nameof(ActionKeywordsModels))]
+ private void InitializeActionKeywordModels()
+ {
+ ActionKeywordsModels = new List
+ {
+ new(Settings.ActionKeyword.SearchActionKeyword,
+ Context.API.GetTranslation("plugin_explorer_actionkeywordview_search")),
+ new(Settings.ActionKeyword.FileContentSearchActionKeyword,
+ Context.API.GetTranslation("plugin_explorer_actionkeywordview_filecontentsearch")),
+ new(Settings.ActionKeyword.PathSearchActionKeyword,
+ Context.API.GetTranslation("plugin_explorer_actionkeywordview_pathsearch")),
+ new(Settings.ActionKeyword.IndexSearchActionKeyword,
+ Context.API.GetTranslation("plugin_explorer_actionkeywordview_indexsearch")),
+ new(Settings.ActionKeyword.QuickAccessActionKeyword,
+ Context.API.GetTranslation("plugin_explorer_actionkeywordview_quickaccess"))
+ };
+ }
+
+ public IReadOnlyList ActionKeywordsModels { get; set; }
+
+ public ActionKeywordModel? SelectedActionKeyword { get; set; }
+
+ public ICommand EditActionKeywordCommand => new RelayCommand(EditActionKeyword);
+
+ private void EditActionKeyword(object obj)
+ {
+ if (SelectedActionKeyword is not { } actionKeyword)
+ {
+ ShowUnselectedMessage();
+ return;
+ }
+
+ var actionKeywordWindow = new ActionKeywordSetting(actionKeyword, Context.API);
+
+ if (!(actionKeywordWindow.ShowDialog() ?? false))
+ {
+ return;
+ }
+
+ switch (actionKeyword.Enabled, actionKeywordWindow.KeywordEnabled)
+ {
+ case (true, false):
+ Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
+ break;
+ case (true, true):
+ // same keyword will have dialog result false
+ Context.API.RemoveActionKeyword(Context.CurrentPluginMetadata.ID, actionKeyword.Keyword);
+ Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
+ break;
+ case (false, true):
+ Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
+ break;
+ case (false, false):
+ throw new ArgumentException(
+ $"Both false in {nameof(actionKeyword)}.{nameof(actionKeyword.Enabled)} and {nameof(actionKeywordWindow)}.{nameof(actionKeywordWindow.KeywordEnabled)} should suggest that the ShowDialog() result is false");
+ }
+
+ (actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled);
+
+ }
+
+ #endregion
+
+ #region AccessLinks
+
+ public AccessLink? SelectedQuickAccessLink { get; set; }
+ public AccessLink? SelectedIndexSearchExcludedPath { get; set; }
+
+
+
+ public ICommand RemoveLinkCommand => new RelayCommand(RemoveLink);
+ public ICommand EditLinkCommand => new RelayCommand(EditLink);
+ public ICommand AddLinkCommand => new RelayCommand(AddLink);
+
+ public void AppendLink(string containerName, AccessLink link)
+ {
+ var container = containerName switch
+ {
+ "QuickAccessLink" => Settings.QuickAccessLinks,
+ "IndexSearchExcludedPaths" => Settings.IndexSearchExcludedSubdirectoryPaths,
+ _ => throw new ArgumentException($"Unknown container name: {containerName}")
+ };
+ container.Add(link);
+ }
+
+ private void EditLink(object commandParameter)
+ {
+ var (selectedLink, collection) = commandParameter switch
+ {
+ "QuickAccessLink" => (SelectedQuickAccessLink, Settings.QuickAccessLinks),
+ "IndexSearchExcludedPaths" => (SelectedIndexSearchExcludedPath, Settings.IndexSearchExcludedSubdirectoryPaths),
+ _ => throw new ArgumentOutOfRangeException(nameof(commandParameter))
+ };
+
+ if (selectedLink is null)
+ {
+ ShowUnselectedMessage();
+ return;
+ }
+
+ var path = PromptUserSelectPath(selectedLink.Type,
+ selectedLink.Type == ResultType.Folder
+ ? selectedLink.Path
+ : Path.GetDirectoryName(selectedLink.Path));
+
+ if (path is null)
+ return;
+
+ collection.Remove(selectedLink);
+ collection.Add(new AccessLink
+ {
+ Path = path, Type = selectedLink.Type,
+ });
+ }
+
+ private void ShowUnselectedMessage()
+ {
+ var warning = Context.API.GetTranslation("plugin_explorer_make_selection_warning");
+ MessageBox.Show(warning);
+ }
+
+
+ private void AddLink(object commandParameter)
+ {
+ var container = commandParameter switch
+ {
+ "QuickAccessLink" => Settings.QuickAccessLinks,
+ "IndexSearchExcludedPaths" => Settings.IndexSearchExcludedSubdirectoryPaths,
+ _ => throw new ArgumentOutOfRangeException(nameof(commandParameter))
+ };
+
+ ArgumentNullException.ThrowIfNull(container);
+
+ var folderBrowserDialog = new FolderBrowserDialog();
+
+ if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
+ return;
+
+ var newAccessLink = new AccessLink
+ {
+ Path = folderBrowserDialog.SelectedPath
+ };
+
+ container.Add(newAccessLink);
+ }
+
+ private void RemoveLink(object obj)
+ {
+ if (obj is not string container) return;
+
+ switch (container)
+ {
+ case "QuickAccessLink":
+ if (SelectedQuickAccessLink == null) return;
+ Settings.QuickAccessLinks.Remove(SelectedQuickAccessLink);
+ break;
+ case "IndexSearchExcludedPaths":
+ if (SelectedIndexSearchExcludedPath == null) return;
+ Settings.IndexSearchExcludedSubdirectoryPaths.Remove(SelectedIndexSearchExcludedPath);
+ break;
+ }
+ Save();
+ }
+
+ #endregion
+
+ private string? PromptUserSelectPath(ResultType type, string? initialDirectory = null)
+ {
+ string? path = null;
+
+ if (type is ResultType.Folder)
+ {
+ var folderBrowserDialog = new FolderBrowserDialog();
+
+ if (initialDirectory is not null)
+ folderBrowserDialog.InitialDirectory = initialDirectory;
+
+ if (folderBrowserDialog.ShowDialog() != DialogResult.OK)
+ return path;
+
+ path = folderBrowserDialog.SelectedPath;
+ }
+ else if (type is ResultType.File)
+ {
+ var openFileDialog = new OpenFileDialog();
+ if (initialDirectory is not null)
+ openFileDialog.InitialDirectory = initialDirectory;
+
+ if (openFileDialog.ShowDialog() != DialogResult.OK)
+ return path;
+
+ path = openFileDialog.FileName;
+ }
+ return path;
+ }
+
+
+ internal static void OpenWindowsIndexingOptions()
{
var psi = new ProcessStartInfo
{
@@ -41,27 +315,106 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
Process.Start(psi);
}
- internal void UpdateActionKeyword(Settings.ActionKeyword modifiedActionKeyword, string newActionKeyword, string oldActionKeyword)
+ private ICommand? _openEditorPathCommand;
+
+ public ICommand OpenEditorPath => _openEditorPathCommand ??= new RelayCommand(_ =>
{
- PluginManager.ReplaceActionKeyword(Context.CurrentPluginMetadata.ID, oldActionKeyword, newActionKeyword);
- }
+ var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
+ if (path is null)
+ return;
- internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword)
+ EditorPath = path;
+ });
+
+ private ICommand? _openShellPathCommand;
+
+ public ICommand OpenShellPath => _openShellPathCommand ??= new RelayCommand(_ =>
{
- return PluginManager.ActionKeywordRegistered(newActionKeyword);
- }
+ var path = PromptUserSelectPath(ResultType.File, Settings.EditorPath != null ? Path.GetDirectoryName(Settings.EditorPath) : null);
+ if (path is null)
+ return;
- internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign;
+ ShellPath = path;
+ });
- public bool UseWindowsIndexForDirectorySearch {
- get
- {
- return Settings.UseWindowsIndexForDirectorySearch;
- }
+
+ public string EditorPath
+ {
+ get => Settings.EditorPath;
set
{
- Settings.UseWindowsIndexForDirectorySearch = value;
+ Settings.EditorPath = value;
+ OnPropertyChanged();
}
}
+
+ public string ShellPath
+ {
+ get => Settings.ShellPath;
+ set
+ {
+ Settings.ShellPath = value;
+ OnPropertyChanged();
+ }
+ }
+
+
+ #region Everything FastSortWarning
+
+ public Visibility FastSortWarningVisibility
+ {
+ get
+ {
+ try
+ {
+ return EverythingApi.IsFastSortOption(Settings.SortOption) ? Visibility.Collapsed : Visibility.Visible;
+ }
+ catch (IPCErrorException)
+ {
+ // this error occurs if the Everything service is not running, in this instance show the warning and
+ // update the message to let user know in the settings panel.
+ return Visibility.Visible;
+ }
+ catch (DllNotFoundException)
+ {
+ return Visibility.Collapsed;
+ }
+ }
+ }
+ public string SortOptionWarningMessage
+ {
+ get
+ {
+ try
+ {
+ // this method is used to determine if Everything service is running because as at Everything v1.4.1
+ // the sdk does not provide a dedicated interface to determine if it is running.
+ return EverythingApi.IsFastSortOption(Settings.SortOption) ? string.Empty
+ : Context.API.GetTranslation("flowlauncher_plugin_everything_nonfastsort_warning");
+ }
+ catch (IPCErrorException)
+ {
+ return Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running");
+ }
+ catch (DllNotFoundException)
+ {
+ return Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue");
+ }
+ }
+ }
+
+ public string EverythingInstalledPath
+ {
+ get => Settings.EverythingInstalledPath;
+ set
+ {
+ Settings.EverythingInstalledPath = value;
+ OnPropertyChanged();
+ }
+ }
+
+ #endregion
+
+
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml
index 8397145cf..d42505348 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml
@@ -77,8 +77,6 @@
Text="{DynamicResource plugin_explorer_actionkeyword_current}" />
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs
index 27e4a0b9a..6ee4faad8 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs
@@ -2,7 +2,9 @@ using Flow.Launcher.Plugin.Explorer.ViewModels;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;
@@ -11,11 +13,9 @@ namespace Flow.Launcher.Plugin.Explorer.Views
///
/// Interaction logic for ActionKeywordSetting.xaml
///
- public partial class ActionKeywordSetting : Window
+ public partial class ActionKeywordSetting : INotifyPropertyChanged
{
- private SettingsViewModel settingsViewModel;
-
- public ActionKeywordView CurrentActionKeyword { get; set; }
+ private ActionKeywordModel CurrentActionKeyword { get; }
public string ActionKeyword
{
@@ -23,24 +23,27 @@ namespace Flow.Launcher.Plugin.Explorer.Views
set
{
// Set Enable to be true if user change ActionKeyword
- Enabled = true;
- actionKeyword = value;
+ KeywordEnabled = true;
+ _ = SetField(ref actionKeyword, value);
}
}
- public bool Enabled { get; set; }
+ public bool KeywordEnabled
+ {
+ get => _keywordEnabled;
+ set => SetField(ref _keywordEnabled, value);
+ }
private string actionKeyword;
+ private readonly IPublicAPI api;
+ private bool _keywordEnabled;
- public ActionKeywordSetting(SettingsViewModel settingsViewModel,
- ActionKeywordView selectedActionKeyword)
+ public ActionKeywordSetting(ActionKeywordModel selectedActionKeyword, IPublicAPI api)
{
- this.settingsViewModel = settingsViewModel;
-
CurrentActionKeyword = selectedActionKeyword;
-
+ this.api = api;
ActionKeyword = selectedActionKeyword.Keyword;
- Enabled = selectedActionKeyword.Enabled;
+ KeywordEnabled = selectedActionKeyword.Enabled;
InitializeComponent();
@@ -52,56 +55,38 @@ namespace Flow.Launcher.Plugin.Explorer.Views
if (string.IsNullOrEmpty(ActionKeyword))
ActionKeyword = Query.GlobalPluginWildcardSign;
- if (CurrentActionKeyword.Keyword == ActionKeyword && CurrentActionKeyword.Enabled == Enabled)
+ if (CurrentActionKeyword.Keyword == ActionKeyword && CurrentActionKeyword.Enabled == KeywordEnabled)
{
+ DialogResult = false;
Close();
return;
}
-
if (ActionKeyword == Query.GlobalPluginWildcardSign)
- switch (CurrentActionKeyword.KeywordProperty)
+ switch (CurrentActionKeyword.KeywordProperty, KeywordEnabled)
{
- case Settings.ActionKeyword.FileContentSearchActionKeyword:
- MessageBox.Show(settingsViewModel.Context.API.GetTranslation("plugin_explorer_globalActionKeywordInvalid"));
+ case (Settings.ActionKeyword.FileContentSearchActionKeyword, true):
+ MessageBox.Show(api.GetTranslation("plugin_explorer_globalActionKeywordInvalid"));
return;
- case Settings.ActionKeyword.QuickAccessActionKeyword:
- MessageBox.Show(settingsViewModel.Context.API.GetTranslation("plugin_explorer_quickaccess_globalActionKeywordInvalid"));
+ case (Settings.ActionKeyword.QuickAccessActionKeyword, true):
+ MessageBox.Show(api.GetTranslation("plugin_explorer_quickaccess_globalActionKeywordInvalid"));
return;
}
- var oldActionKeyword = CurrentActionKeyword.Keyword;
-
- if (!Enabled || !settingsViewModel.IsActionKeywordAlreadyAssigned(ActionKeyword))
+ if (!KeywordEnabled || !api.ActionKeywordAssigned(ActionKeyword))
{
- // Update View Data
- CurrentActionKeyword.Keyword = Enabled == true ? ActionKeyword : Query.GlobalPluginWildcardSign;
- CurrentActionKeyword.Enabled = Enabled;
-
- switch (Enabled)
- {
- // reset to global so it does not take up an action keyword when disabled
- // not for null Enable plugin
- case false when oldActionKeyword != Query.GlobalPluginWildcardSign:
- settingsViewModel.UpdateActionKeyword(CurrentActionKeyword.KeywordProperty,
- Query.GlobalPluginWildcardSign, oldActionKeyword);
- break;
- default:
- settingsViewModel.UpdateActionKeyword(CurrentActionKeyword.KeywordProperty,
- CurrentActionKeyword.Keyword, oldActionKeyword);
- break;
- }
-
+ DialogResult = true;
Close();
return;
}
// The keyword is not valid, so show message
- MessageBox.Show(settingsViewModel.Context.API.GetTranslation("newActionKeywordsHasBeenAssigned"));
+ MessageBox.Show(api.GetTranslation("newActionKeywordsHasBeenAssigned"));
}
private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
{
+ DialogResult = false;
Close();
}
private void TxtCurrentActionKeyword_OnKeyDown(object sender, KeyEventArgs e)
@@ -113,5 +98,18 @@ namespace Flow.Launcher.Plugin.Explorer.Views
e.Handled = true;
}
}
+ public event PropertyChangedEventHandler PropertyChanged;
+ protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+ }
+ private bool SetField(ref T field, T value, [CallerMemberName] string propertyName = null)
+ {
+ if (EqualityComparer.Default.Equals(field, value))
+ return false;
+ field = value;
+ OnPropertyChanged(propertyName);
+ return true;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs
new file mode 100644
index 000000000..e24b21dcd
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs
@@ -0,0 +1,20 @@
+using Flow.Launcher.Plugin.Everything.Everything;
+using Flow.Launcher.Plugin.Explorer.Helper;
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace Flow.Launcher.Plugin.Explorer.Views.Converters;
+
+public class EnumNameConverter : IValueConverter
+{
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ return value is SortOption option ? option.GetTranslatedName() : value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
index 0be68e257..6b2877bf5 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
@@ -2,20 +2,111 @@
x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:converters="clr-namespace:Flow.Launcher.Plugin.Explorer.Views.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks"
+ xmlns:ui="http://schemas.modernwpf.com/2019"
+ xmlns:viewModels="clr-namespace:Flow.Launcher.Plugin.Explorer.ViewModels"
xmlns:views="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
+ d:DataContext="{d:DesignInstance viewModels:SettingsViewModel}"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
-
+
+
-
-
-
-
+
+ Text="{Binding Keyword}">
+
+
-
+
-
+
@@ -182,7 +189,7 @@
+ Margin="0,0,20,0">
_settings.ProgramSources.Any(y => y.UniqueIdentifier == x.UniqueIdentifier));
}
+
+ private void ListView_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ ListView listView = sender as ListView;
+ GridView gView = listView.View as GridView;
+
+ var workingWidth = listView.ActualWidth - SystemParameters.VerticalScrollBarWidth; // take into account vertical scrollbar
+ var col1 = 0.25;
+ var col2 = 0.15;
+ var col3 = 0.60;
+
+ gView.Columns[0].Width = workingWidth * col1;
+ gView.Columns[1].Width = workingWidth * col2;
+ gView.Columns[2].Width = workingWidth * col3;
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json
index a297cb410..3c719e28b 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Program/plugin.json
@@ -4,7 +4,7 @@
"Name": "Program",
"Description": "Search programs in Flow.Launcher",
"Author": "qianlifeng",
- "Version": "1.9.0",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj
index d1da7327d..c3f63eeb5 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj
@@ -8,6 +8,7 @@
Flow.Launcher.Plugin.Shell
Flow.Launcher.Plugin.Shell
true
+ true
true
false
false
@@ -54,10 +55,6 @@
PreserveNewest
-
- MSBuild:Compile
- Designer
-
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Images/shell.png b/Plugins/Flow.Launcher.Plugin.Shell/Images/shell.png
index 0ec0122d4..c41275d9e 100644
Binary files a/Plugins/Flow.Launcher.Plugin.Shell/Images/shell.png and b/Plugins/Flow.Launcher.Plugin.Shell/Images/shell.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.Shell/Languages/de.xaml
index d305a348c..5c3c1e92e 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Shell/Languages/de.xaml
@@ -4,7 +4,7 @@
Ersetzt Win+R
Schließe die Kommandozeilte nicht nachdem der Befehl ausgeführt wurde
Always run as administrator
- Run as different user
+ Als anderer Benutzer ausführen
Kommandozeile
Bereitstellung der Kommandozeile in Flow Launcher. Befehle müssem mit > starten
Dieser Befehl wurde {0} mal ausgeführt
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs
index 9f822ea47..7ce597b96 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Shell/Main.cs
@@ -61,15 +61,15 @@ namespace Flow.Launcher.Plugin.Shell
if (basedir != null)
{
- var autocomplete =
+ var autocomplete =
Directory.GetFileSystemEntries(basedir)
.Select(o => dir + Path.GetFileName(o))
.Where(o => o.StartsWith(cmd, StringComparison.OrdinalIgnoreCase) &&
- !results.Any(p => o.Equals(p.Title, StringComparison.OrdinalIgnoreCase)) &&
- !results.Any(p => o.Equals(p.Title, StringComparison.OrdinalIgnoreCase))).ToList();
-
+ !results.Any(p => o.Equals(p.Title, StringComparison.OrdinalIgnoreCase)) &&
+ !results.Any(p => o.Equals(p.Title, StringComparison.OrdinalIgnoreCase))).ToList();
+
autocomplete.Sort();
-
+
results.AddRange(autocomplete.ConvertAll(m => new Result
{
Title = m,
@@ -194,72 +194,74 @@ namespace Flow.Launcher.Plugin.Shell
ProcessStartInfo info = new()
{
- Verb = runAsAdministratorArg,
- WorkingDirectory = workingDirectory,
+ Verb = runAsAdministratorArg, WorkingDirectory = workingDirectory,
};
switch (_settings.Shell)
{
case Shell.Cmd:
- {
- info.FileName = "cmd.exe";
- info.Arguments = $"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command}";
+ {
+ info.FileName = "cmd.exe";
+ info.Arguments = $"{(_settings.LeaveShellOpen ? "/k" : "/c")} {command}";
- //// Use info.Arguments instead of info.ArgumentList to enable users better control over the arguments they are writing.
- //// Previous code using ArgumentList, commands needed to be seperated correctly:
- //// Incorrect:
- // info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c");
- // info.ArgumentList.Add(command); //<== info.ArgumentList.Add("mkdir \"c:\\test new\"");
+ //// Use info.Arguments instead of info.ArgumentList to enable users better control over the arguments they are writing.
+ //// Previous code using ArgumentList, commands needed to be seperated correctly:
+ //// Incorrect:
+ // info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c");
+ // info.ArgumentList.Add(command); //<== info.ArgumentList.Add("mkdir \"c:\\test new\"");
- //// Correct version should be:
- //info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c");
- //info.ArgumentList.Add("mkdir");
- //info.ArgumentList.Add(@"c:\test new");
+ //// Correct version should be:
+ //info.ArgumentList.Add(_settings.LeaveShellOpen ? "/k" : "/c");
+ //info.ArgumentList.Add("mkdir");
+ //info.ArgumentList.Add(@"c:\test new");
- //https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0#remarks
+ //https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.processstartinfo.argumentlist?view=net-6.0#remarks
- break;
- }
+ break;
+ }
case Shell.Powershell:
+ {
+ info.FileName = "powershell.exe";
+ if (_settings.LeaveShellOpen)
{
- info.FileName = "powershell.exe";
- if (_settings.LeaveShellOpen)
- {
- info.ArgumentList.Add("-NoExit");
- info.ArgumentList.Add(command);
- }
- else
- {
- info.ArgumentList.Add("-Command");
- info.ArgumentList.Add(command);
- }
- break;
+ info.ArgumentList.Add("-NoExit");
+ info.ArgumentList.Add(command);
}
+ else
+ {
+ info.ArgumentList.Add("-Command");
+ info.ArgumentList.Add(command);
+ }
+ break;
+ }
case Shell.RunCommand:
+ {
+ var parts = command.Split(new[]
{
- var parts = command.Split(new[] { ' ' }, 2);
- if (parts.Length == 2)
+ ' '
+ }, 2);
+ if (parts.Length == 2)
+ {
+ var filename = parts[0];
+ if (ExistInPath(filename))
{
- var filename = parts[0];
- if (ExistInPath(filename))
- {
- var arguments = parts[1];
- info.FileName = filename;
- info.ArgumentList.Add(arguments);
- }
- else
- {
- info.FileName = command;
- }
+ var arguments = parts[1];
+ info.FileName = filename;
+ info.ArgumentList.Add(arguments);
}
else
{
info.FileName = command;
}
-
- break;
}
+ else
+ {
+ info.FileName = command;
+ }
+
+ break;
+ }
default:
throw new NotImplementedException();
}
@@ -350,8 +352,12 @@ namespace Flow.Launcher.Plugin.Shell
private void OnWinRPressed()
{
// show the main window and set focus to the query box
- context.API.ShowMainWindow();
- context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}");
+ Task.Run(() =>
+ {
+ context.API.ShowMainWindow();
+ context.API.ChangeQuery($"{context.CurrentPluginMetadata.ActionKeywords[0]}{Plugin.Query.TermSeparator}");
+ });
+
}
public Control CreateSettingPanel()
@@ -381,7 +387,8 @@ namespace Flow.Launcher.Plugin.Shell
Execute(ShellCommand.RunAsDifferentUser, PrepareProcessStartInfo(selectedResult.Title));
return true;
},
- IcoPath = "Images/user.png"
+ IcoPath = "Images/user.png",
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xe7ee")
},
new Result
{
@@ -391,7 +398,8 @@ namespace Flow.Launcher.Plugin.Shell
Execute(Process.Start, PrepareProcessStartInfo(selectedResult.Title, true));
return true;
},
- IcoPath = "Images/admin.png"
+ IcoPath = "Images/admin.png",
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xe7ef")
},
new Result
{
@@ -401,7 +409,8 @@ namespace Flow.Launcher.Plugin.Shell
Clipboard.SetDataObject(selectedResult.Title);
return true;
},
- IcoPath = "Images/copy.png"
+ IcoPath = "Images/copy.png",
+ Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xe8c8")
}
};
diff --git a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
index 99b8261bb..5885b10d7 100644
--- a/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Shell/plugin.json
@@ -4,7 +4,7 @@
"Name": "Shell",
"Description": "Provide executing commands from Flow Launcher",
"Author": "qianlifeng",
- "Version": "1.4.11",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Shell.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
index 55ab2780e..ce4773908 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
@@ -8,6 +8,7 @@
Flow.Launcher.Plugin.Sys
Flow.Launcher.Plugin.Sys
true
+ true
true
false
false
@@ -48,10 +49,6 @@
PreserveNewest
-
- MSBuild:Compile
- Designer
-
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml
index e379fb14c..4a7910df7 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/es.xaml
@@ -22,7 +22,7 @@
Refresca los datos del complemento con nuevo contenido
Abre la ubicación de los archivos de registro de Flow Launcher
Busca actualizaciones de Flow Launcher
- Visite la documentación de Flow Launcher para más ayuda y consejos de uso
+ Accede a la documentación de Flow Launcher para más ayuda y consejos de uso
Abre la ubicación donde se almacena la configuración de Flow Launcher
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml
index 7b140b41f..069b03ba7 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/Languages/ko.xaml
@@ -5,9 +5,9 @@
명령어
설명
- 컴퓨터 종료
- 컴퓨터 재시작
- 안전 및 디버깅 모드에 대한 고급 부팅 옵션과 기타 옵션을 사용하여 컴퓨터를 다시 시작
+ 시스템 종료
+ 시스템 재시작
+ 안전 및 디버깅 모드에 대한 고급 부팅 옵션과 기타 옵션을 사용하여 시스템을 다시 시작
로그아웃
컴퓨터 잠금
Flow Launcher 닫기
@@ -29,9 +29,9 @@
성공
모든 Flow Launcher 설정을 저장했습니다
적용 가능한 모든 플러그인 데이터를 다시 로드했습니다
- 컴퓨터를 종료하시겠습니까?
- 컴퓨터를 재시작 하시겠습니까?
- 고급 부팅 옵션으로 컴퓨터를 다시 시작하시겠습니까?
+ 시스템을 종료하시겠습니까?
+ 시스템을 재시작 하시겠습니까?
+ 고급 부팅 옵션으로 시스템을 다시 시작하시겠습니까?
시스템 명령어
시스템 종료, 컴퓨터 잠금, 설정 등과 같은 시스템 관련 명령어를 제공합니다
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml b/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml
index 66aa34b2a..f806900de 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml
@@ -1,33 +1,39 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml.cs b/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml.cs
index cdcc977a9..b5f1531c3 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.Sys/SysSettings.xaml.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Windows;
using System.Windows.Controls;
namespace Flow.Launcher.Plugin.Sys
@@ -14,5 +15,17 @@ namespace Flow.Launcher.Plugin.Sys
lbxCommands.Items.Add(Result);
}
}
+ private void ListView_SizeChanged(object sender, SizeChangedEventArgs e)
+ {
+ ListView listView = sender as ListView;
+ GridView gView = listView.View as GridView;
+
+ var workingWidth = listView.ActualWidth - SystemParameters.VerticalScrollBarWidth; // take into account vertical scrollbar
+ var col1 = 0.3;
+ var col2 = 0.7;
+
+ gView.Columns[0].Width = workingWidth * col1;
+ gView.Columns[1].Width = workingWidth * col2;
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json
index ad3a9908d..0ce62c28c 100644
--- a/Plugins/Flow.Launcher.Plugin.Sys/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Sys/plugin.json
@@ -4,7 +4,7 @@
"Name": "System Commands",
"Description": "Provide System related commands. e.g. shutdown,lock, setting etc.",
"Author": "qianlifeng",
- "Version": "1.6.3",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Sys.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Url/Images/url.png b/Plugins/Flow.Launcher.Plugin.Url/Images/url.png
index 5d475f82e..a5bc848c7 100644
Binary files a/Plugins/Flow.Launcher.Plugin.Url/Images/url.png and b/Plugins/Flow.Launcher.Plugin.Url/Images/url.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.Url/plugin.json b/Plugins/Flow.Launcher.Plugin.Url/plugin.json
index 7175f8920..aadaf5d70 100644
--- a/Plugins/Flow.Launcher.Plugin.Url/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Url/plugin.json
@@ -4,7 +4,7 @@
"Name": "URL",
"Description": "Open the typed URL from Flow Launcher",
"Author": "qianlifeng",
- "Version": "1.2.3",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Url.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml
index e36b0a7de..4d32b7bbc 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/da.xaml
@@ -10,6 +10,8 @@
Slet
Rediger
Tilføj
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Annuller
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml
index 887e2e9b5..2e4a0c2a9 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/de.xaml
@@ -10,6 +10,8 @@
Löschen
Bearbeiten
Hinzufügen
+ Aktiviert
+ Disabled
Confirm
Aktionsschlüsselwort
URL
@@ -30,7 +32,7 @@
Titel
- Aktivieren
+ Status
Wähle Symbol
Symbol
Abbrechen
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
index 0906d30f0..0e2b85b93 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
@@ -12,6 +12,8 @@
Delete
Edit
Add
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -32,7 +34,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Cancel
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml
index e058e6e41..f234a180b 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es-419.xaml
@@ -10,6 +10,8 @@
Eliminar
Editar
Añadir
+ Enabled
+ Disabled
Confirmar
Palabra clave
URL
@@ -30,7 +32,7 @@
Título
- Habilitar
+ Status
Seleccionar icono
Ícono
Cancelar
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml
index d9b0c0e32..63fdae4ee 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/es.xaml
@@ -10,6 +10,8 @@
Eliminar
Editar
Añadir
+ Activado
+ Desactivado
Confirmar
Palabra clave de acción
URL
@@ -30,7 +32,7 @@
Título
- Activar
+ Estado
Seleccionar icono
Icono
Cancelar
@@ -40,7 +42,7 @@
Por favor, introduzca una URL
La palabra clave de acción ya está en uso, por favor, introduzca una diferente
Correcto
- Sugerencia: No es necesario copiar imágenes personalizadas en esta carpeta, cuando Flow sea actualizado se perderán. Flow copiará automáticamente cualquier imagen externa a esta carpeta en la ubicación de imágenes personalizada de WebSearch.
+ Sugerencia: No es necesario colocar imágenes personalizadas en esta carpeta, al actualizar Flow se perderán. Flow copiará automáticamente cualquier imagen externa a esta carpeta en la ubicación de imágenes personalizada de WebSearch.
Búsquedas Web
Permite realizar búsquedas web
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml
index da433832e..960aa6d5c 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/fr.xaml
@@ -10,6 +10,8 @@
Supprimer
Modifier
Ajouter
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Annuler
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml
index b7bd18deb..a09f73077 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/it.xaml
@@ -10,6 +10,8 @@
Cancella
Modifica
Aggiungi
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Annulla
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml
index 0658f9f1f..edf26dc35 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ja.xaml
@@ -10,6 +10,8 @@
削除
編集
追加
+ Enabled
+ Disabled
Confirm
キーワード
URL
@@ -30,7 +32,7 @@
タイトル
- 有効
+ Status
アイコンを選択
アイコン
キャンセル
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml
index 706e94365..2b34775c5 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ko.xaml
@@ -10,6 +10,8 @@
삭제
편집
추
+ 켬
+ Disabled
확인
액션 키워드
URL
@@ -30,7 +32,7 @@
이름
- 활성화
+ Status
아이콘 선택
아이콘
취소
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml
index 01dfaf784..d6059c371 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nb.xaml
@@ -10,6 +10,8 @@
Delete
Edit
Add
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Cancel
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml
index b5d303fab..fac64d046 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/nl.xaml
@@ -10,6 +10,8 @@
Verwijder
Bewerken
Toevoegen
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Annuleer
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml
index ae2b7e57f..6860f8aac 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pl.xaml
@@ -10,6 +10,8 @@
Usuń
Edytuj
Dodaj
+ Enabled
+ Disabled
Confirm
Wyzwalacz
Adres URL
@@ -30,7 +32,7 @@
Tytuł
- Aktywne
+ Status
Wybierz ikonę
Ikona
Anuluj
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml
index 4fb45e7df..d1838a4d6 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-br.xaml
@@ -10,6 +10,8 @@
Apagar
Editar
Adicionar
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Cancelar
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml
index 9278b3e0d..4b36dd408 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/pt-pt.xaml
@@ -10,6 +10,8 @@
Eliminar
Editar
Adicionar
+ Ativo
+ Inativo
Confirmar
Palavra-chave de ação
URL
@@ -30,7 +32,7 @@
Título
- Ativar
+ Estado
Selecionar ícone
Ícone
Cancelar
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml
index f185a6dc2..8280c1297 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/ru.xaml
@@ -10,6 +10,8 @@
Удалить
Редактировать
Добавить
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Отменить
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml
index 008b893bb..3ec98073f 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sk.xaml
@@ -10,6 +10,8 @@
Odstrániť
Upraviť
Pridať
+ Povolené
+ Vypnuté
Potvrdiť
Aktivačný príkaz
Adresa URL
@@ -30,7 +32,7 @@
Názov
- Povoliť
+ Stav
Vybrať ikonu
Ikona
Zrušiť
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml
index 9038585b6..8de90c8fb 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/sr.xaml
@@ -10,6 +10,8 @@
Obriši
Izmeni
Dodaj
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Otkaži
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml
index a30da0afe..3d3b0e58e 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/tr.xaml
@@ -10,6 +10,8 @@
Sil
Düzenle
Ekle
+ Enabled
+ Disabled
Onayla
Anahtar Kelime
URL
@@ -30,7 +32,7 @@
Başlık
- Etkin
+ Status
Simge Seç
Simge
İptal
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml
index ca17365b1..352d9d785 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/uk-UA.xaml
@@ -10,6 +10,8 @@
Видалити
Редагувати
Додати
+ Enabled
+ Disabled
Confirm
Action Keyword
URL
@@ -30,7 +32,7 @@
Title
- Enable
+ Status
Select Icon
Icon
Скасувати
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml
index b2bbe38e5..e336e1ffe 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-cn.xaml
@@ -10,6 +10,8 @@
删除
编辑
增加
+ 启用
+ 已禁用
确认
触发关键字
打开链接
@@ -30,7 +32,7 @@
标题
- 启用
+ 状态
选择图标
图标
取消
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml
index 996b19dad..78d07a118 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/zh-tw.xaml
@@ -10,6 +10,8 @@
刪除
編輯
新增
+ 已啟用
+ Disabled
確定
觸發關鍵字
URL
@@ -30,7 +32,7 @@
標題
- 啟用
+ Status
選擇圖示
圖示
取消
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
index b136e3b8b..179745e2d 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
@@ -192,4 +192,4 @@ namespace Flow.Launcher.Plugin.WebSearch
public event ResultUpdatedEventHandler ResultsUpdated;
}
-}
\ No newline at end of file
+}
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
index 07c7a05ba..b9ca47e4f 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SettingsControl.xaml
@@ -35,7 +35,7 @@
-
+
@@ -44,7 +44,7 @@
-
+
-
+
+
+
+
+
@@ -115,7 +123,7 @@
Content="{DynamicResource flowlauncher_plugin_websearch_edit}" />
@@ -123,9 +131,9 @@
Grid.Row="2"
Margin="0,0,0,0"
HorizontalAlignment="Stretch"
- BorderBrush="#cecece"
+ BorderBrush="{DynamicResource Color03B}"
BorderThickness="0,1,0,0">
-
+
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
index d755bf85d..2d9a28c48 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
@@ -26,7 +26,7 @@
"Name": "Web Searches",
"Description": "Provide the web search ability",
"Author": "qianlifeng",
- "Version": "1.5.4",
+ "Version": "2.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/ControlPanel_Small.png b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/ControlPanel_Small.png
index 0897fd788..9fa4a7313 100644
Binary files a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/ControlPanel_Small.png and b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/ControlPanel_Small.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/WindowsSettings.light.png b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/WindowsSettings.light.png
index 79691ed95..0a8bbc924 100644
Binary files a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/WindowsSettings.light.png and b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Images/WindowsSettings.light.png differ
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx
index d1523c239..31443560c 100644
--- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx
+++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.de-DE.resx
@@ -701,7 +701,7 @@
Area Gaming
- Game Mode
+ Spielmodus
Area Gaming
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-BR.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-BR.resx
index b519399ca..e2998402d 100644
--- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-BR.resx
+++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-BR.resx
@@ -701,7 +701,7 @@
Area Gaming
- Game Mode
+ Modo Gamer
Area Gaming
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx
index 7cd57d6b1..af912181c 100644
--- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx
+++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Properties/Resources.pt-PT.resx
@@ -2031,7 +2031,7 @@
Change when the computer sleeps
- Set up a virtual private network (VPN) connection
+ Configurar uma rede privada (VPN)
Accommodate learning abilities
@@ -2055,7 +2055,7 @@
Accommodate low vision
- Manage offline files
+ Gerenciar ficheiros offline
Review your computer's status and resolve issues
@@ -2091,7 +2091,7 @@
Change tablet pen settings
- Change how your mouse works
+ Alterar modo de funcionamento do rato
Show how much RAM is on this computer
diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json
index dcac0857b..a27bc1b74 100644
--- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json
@@ -4,7 +4,7 @@
"Description": "Search settings inside Control Panel and Settings App",
"Name": "Windows Settings",
"Author": "TobiasSekan",
- "Version": "2.1.0",
+ "Version": "3.0.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.WindowsSettings.dll",
diff --git a/README.md b/README.md
index 1441c8b39..dcc1da935 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,9 @@
-
-
-
-
+
+
+
+
-
-
@@ -22,18 +20,63 @@ Dedicated to making your workflow flow more seamless. Search everything from app
Remember to star it, flow will love you more :)
- SOFTPEDIA EDITOR'S PICK
-
-## 🎉 New Features in 1.9
+## 🎅 New Features🤶
+### Preview Panel
+
-
+- Use the F1 key to open/hide the preview panel.
+- Media files will be displayed as large images, otherwise a large icon and entire path will be displayed.
+- Turn on preview permanently via Settings (Always Preview).
+- Use hotkeys (Ctrl+Plus,Minus / Ctrl+],[) to adjust flow's search window width and height quickly if the preview area is too narrow.
+- This feature is currently in its early stages.
-- All New Design. New Themes, New Setting Window. Animation & Sound Effect, Color Scheme aka Dark Mode.
-- New Plugins, Plugin Store, Game Mode, Wizard window
-- Full changelog
+### Everything Plugin Merged Into Explorer
+
+
+- Switch easily between Everything and Windows Search to take advantage of both search engines (remember to remove existing Everything plugin).
+- Use features available to both Everything and Explorer plugins
+
+### Date & Time Display In Search Window
+
+
+
+- Display the date and time when the search window is triggered.
+
+### Drag & Drop
+
+
+- Drag an item to Discord or computer location.
+- The target program determines whether the drop is to copy or move the item (can change via CTRL or Alt), and the operation is displayed on the mouse cursor.
+
+### Custom Shortcut
+
+
+
+
+- New shortcut functionality to set additional action keywords or search terms.
+
+### Improved Program Plugin
+- PATH is now indexed
+- Support for .url files, flow can now search installed steam/epic games.
+- Improved UWP indexing.
+
+### Improved Memory Usage
+- Fixed a memory leak and reduced overall memory usage.
+
+### Improved Plugin / Plugin Store
+- Search plugins in the Plugin Store and existing plugin tab.
+- Categorised sections in Plugin Store to easily see new and updated plugins.
+
+### Improved Non-C# Plugin's Panel Design
+
+
+- The design has been adjusted to align to the overall look and feel of flow.
+- Simplified the information displayed on buttons
+
+🚂Full Changelogs
@@ -84,11 +127,12 @@ And you can download
-
+
+
### Browser Bookmarks
-
+
### System Commands
@@ -99,26 +143,27 @@ And you can download
+
- Do mathematical calculations and copy the result to clipboard.
### Shell Command
-
+
+
- Run batch and PowerShell commands as Administrator or a different user.
- Ctrl+Enter to Run as Administrator.
### Explorer
-
+
- Save file or folder locations for quick access.
### Windows & Control Panel Settings
-
+
- Search for Windows & Control Panel settings.
@@ -127,17 +172,16 @@ And you can download
-
- Prioritise the order of each plugin's results.
### Customizations
-
+
- Window size adjustment, animation, and sound
- Color Scheme (aka Dark Mode)
-
+
- There are various themes and you also can make your own.
@@ -157,9 +201,10 @@ And you can download
+
- Pause hotkey activation when you are playing games.
+- When in search window use Ctrl+F12 to toggle on/off.
@@ -208,8 +253,8 @@ And you can download
### 🛒 Plugin Store
+
-
- You can view the full plugin list or quickly install a plugin via the Plugin Store menu inside Settings
@@ -224,16 +269,21 @@ And you can download
+
+
-
-
- :sparkles:Why I Chose to Support Flow-Launcher :sparkles:
-
+
+
+
+
+### Mentions
+- Why I Chose to Support Flow-Launcher - Appwrite
+- Softpedia Editor's Pick
+
## ❔ Questions/Suggestions
@@ -290,7 +348,7 @@ Yes please, let us know in the [Q&A](https://github.com/Flow-Launcher/Flow.Launc
### New changes
-All changes to flow are captured via pull requests. Some new changes will have been merged but still pending release, this means whilst a change may not exist in the current latest release, it may very well have been accepted and merged into the dev branch and available as a pre-release download. It is therefore a good idea that before you start to make changes, search through the open and closed pull requests to make sure the change you intend to make is not already done.
+All changes to flow are captured via pull requests. Some new changes will have been merged but still pending release, this means whilst a change may not exist in the current release, it may very well have been accepted and merged into the dev branch and available as a pre-release download. It is therefore a good idea that before you start to make changes, search through the open and closed pull requests to make sure the change you intend to make is not already done.
Each of the pull requests will be marked with a milestone indicating the planned release version for the change.
diff --git a/Scripts/flowlauncher.nuspec b/Scripts/flowlauncher.nuspec
index 8c1b16fe5..aeb29d1f1 100644
--- a/Scripts/flowlauncher.nuspec
+++ b/Scripts/flowlauncher.nuspec
@@ -8,9 +8,9 @@
https://github.com/Flow-Launcher/Flow.Launcher
https://raw.githubusercontent.com/Flow-Launcher/Flow.Launcher/master/Flow.Launcher/Images/app.png
false
- Flow Launcher - a launcher for windows
+ Flow Launcher - Quick file search and app launcher for Windows with community-made plugins
-
+
diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1
index fdf2a0349..d937c5732 100644
--- a/Scripts/post_build.ps1
+++ b/Scripts/post_build.ps1
@@ -70,8 +70,8 @@ function Pack-Squirrel-Installer ($path, $version, $output) {
Write-Host "Packing: $spec"
Write-Host "Input path: $input"
- # making version static as multiple versions can exist in the nuget folder and in the case a breaking change is introduced.
- New-Alias Nuget $env:USERPROFILE\.nuget\packages\NuGet.CommandLine\5.7.2\tools\NuGet.exe -Force
+
+ New-Alias Nuget $env:USERPROFILE\.nuget\packages\NuGet.CommandLine\6.3.1\tools\NuGet.exe -Force
# dotnet pack is not used because ran into issues, need to test installation and starting up if to use it.
nuget pack $spec -Version $version -BasePath $input -OutputDirectory $output -Properties Configuration=Release
diff --git a/appveyor.yml b/appveyor.yml
index aa490fd25..4f371e132 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: '1.9.5.{build}'
+version: '1.10.1.{build}'
init:
- ps: |