Merge branch 'dev' into update_ui

This commit is contained in:
Jeremy Wu 2020-05-08 12:41:57 +10:00
commit 47a69a322d
53 changed files with 511 additions and 128 deletions

View file

@ -172,7 +172,7 @@ namespace Flow.Launcher.Core.Configuration
"would you like to move it to a different location?", string.Empty,
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
FilesFolders.OpenLocationInExporer(Constant.RootDirectory);
FilesFolders.OpenPath(Constant.RootDirectory);
Environment.Exit(0);
}

View file

@ -11,6 +11,7 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -52,10 +53,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FSharp.Core" Version="4.7.1" />
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="squirrel.windows" Version="1.5.2" />
<PackageReference Include="PropertyChanged.Fody" Version="2.2.4">
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -86,7 +86,7 @@ namespace Flow.Launcher.Core.Plugin
"Restart Flow Launcher to take effect?",
"Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
PluginManager.API.RestarApp();
PluginManager.API.RestartApp();
}
}
}

View file

@ -20,21 +20,21 @@ namespace Flow.Launcher.Core.Plugin
public static List<PluginPair> Plugins(List<PluginMetadata> metadatas, PluginsSettings settings)
{
var csharpPlugins = CSharpPlugins(metadatas).ToList();
var dotnetPlugins = DotNetPlugins(metadatas).ToList();
var pythonPlugins = PythonPlugins(metadatas, settings.PythonDirectory);
var executablePlugins = ExecutablePlugins(metadatas);
var plugins = csharpPlugins.Concat(pythonPlugins).Concat(executablePlugins).ToList();
var plugins = dotnetPlugins.Concat(pythonPlugins).Concat(executablePlugins).ToList();
return plugins;
}
public static IEnumerable<PluginPair> CSharpPlugins(List<PluginMetadata> source)
public static IEnumerable<PluginPair> DotNetPlugins(List<PluginMetadata> source)
{
var plugins = new List<PluginPair>();
var metadatas = source.Where(o => o.Language.ToUpper() == AllowedLanguage.CSharp);
var metadatas = source.Where(o => AllowedLanguage.IsDotNet(o.Language));
foreach (var metadata in metadatas)
{
var milliseconds = Stopwatch.Debug($"|PluginsLoader.CSharpPlugins|Constructor init cost for {metadata.Name}", () =>
var milliseconds = Stopwatch.Debug($"|PluginsLoader.DotNetPlugins|Constructor init cost for {metadata.Name}", () =>
{
#if DEBUG
@ -50,7 +50,7 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
Log.Exception($"|PluginsLoader.CSharpPlugins|Couldn't load assembly for {metadata.Name}", e);
Log.Exception($"|PluginsLoader.DotNetPlugins|Couldn't load assembly for {metadata.Name}", e);
return;
}
var types = assembly.GetTypes();
@ -61,7 +61,7 @@ namespace Flow.Launcher.Core.Plugin
}
catch (InvalidOperationException e)
{
Log.Exception($"|PluginsLoader.CSharpPlugins|Can't find class implement IPlugin for <{metadata.Name}>", e);
Log.Exception($"|PluginsLoader.DotNetPlugins|Can't find class implement IPlugin for <{metadata.Name}>", e);
return;
}
IPlugin plugin;
@ -71,7 +71,7 @@ namespace Flow.Launcher.Core.Plugin
}
catch (Exception e)
{
Log.Exception($"|PluginsLoader.CSharpPlugins|Can't create instance for <{metadata.Name}>", e);
Log.Exception($"|PluginsLoader.DotNetPlugins|Can't create instance for <{metadata.Name}>", e);
return;
}
#endif

View file

@ -13,11 +13,12 @@ namespace Flow.Launcher.Infrastructure.Image
{
public static class ImageLoader
{
private static readonly ImageCache ImageCache = new ImageCache();
private static BinaryStorage<Dictionary<string, int>> _storage;
private static readonly ConcurrentDictionary<string, string> GuidToKey = new ConcurrentDictionary<string, string>();
private static IImageHashGenerator _hashGenerator;
private static readonly ImageCache _imageCache = new ImageCache();
private static readonly ConcurrentDictionary<string, string> _guidToKey = new ConcurrentDictionary<string, string>();
private static readonly bool _enableHashImage = true;
private static BinaryStorage<Dictionary<string, int>> _storage;
private static IImageHashGenerator _hashGenerator;
private static readonly string[] ImageExtensions =
{
@ -30,30 +31,30 @@ namespace Flow.Launcher.Infrastructure.Image
".ico"
};
public static void Initialize()
{
_storage = new BinaryStorage<Dictionary<string, int>>("Image");
_hashGenerator = new ImageHashGenerator();
ImageCache.Usage = LoadStorageToConcurrentDictionary();
_imageCache.Usage = LoadStorageToConcurrentDictionary();
foreach (var icon in new[] { Constant.DefaultIcon, Constant.ErrorIcon })
{
ImageSource img = new BitmapImage(new Uri(icon));
img.Freeze();
ImageCache[icon] = img;
_imageCache[icon] = img;
}
Task.Run(() =>
{
Stopwatch.Normal("|ImageLoader.Initialize|Preload images cost", () =>
{
ImageCache.Usage.AsParallel().ForAll(x =>
_imageCache.Usage.AsParallel().ForAll(x =>
{
Load(x.Key);
});
});
Log.Info($"|ImageLoader.Initialize|Number of preload images is <{ImageCache.Usage.Count}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
Log.Info($"|ImageLoader.Initialize|Number of preload images is <{_imageCache.Usage.Count}>, Images Number: {_imageCache.CacheSize()}, Unique Items {_imageCache.UniqueImagesInCache()}");
});
}
@ -61,7 +62,7 @@ namespace Flow.Launcher.Infrastructure.Image
{
lock (_storage)
{
_storage.Save(ImageCache.CleanupAndToDictionary());
_storage.Save(_imageCache.CleanupAndToDictionary());
}
}
@ -99,17 +100,17 @@ namespace Flow.Launcher.Infrastructure.Image
private static ImageResult LoadInternal(string path, bool loadFullImage = false)
{
ImageSource image;
ImageType type = ImageType.Error;
ImageResult imageResult;
try
{
if (string.IsNullOrEmpty(path))
{
return new ImageResult(ImageCache[Constant.ErrorIcon], ImageType.Error);
return new ImageResult(_imageCache[Constant.ErrorIcon], ImageType.Error);
}
if (ImageCache.ContainsKey(path))
if (_imageCache.ContainsKey(path))
{
return new ImageResult(ImageCache[path], ImageType.Cache);
return new ImageResult(_imageCache[path], ImageType.Cache);
}
if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
@ -124,69 +125,93 @@ namespace Flow.Launcher.Infrastructure.Image
path = Path.Combine(Constant.ProgramDirectory, "Images", Path.GetFileName(path));
}
if (Directory.Exists(path))
imageResult = GetThumbnailResult(ref path, loadFullImage);
}
catch (System.Exception e)
{
try
{
/* Directories can also have thumbnails instead of shell icons.
* Generating thumbnails for a bunch of folders while scrolling through
* results from Everything makes a big impact on performance and
* Flow.Launcher responsibility.
* - Solution: just load the icon
*/
type = ImageType.Folder;
image = WindowsThumbnailProvider.GetThumbnail(path, Constant.ThumbnailSize,
Constant.ThumbnailSize, ThumbnailOptions.IconOnly);
// Get thumbnail may fail for certain images on the first try, retry again has proven to work
imageResult = GetThumbnailResult(ref path, loadFullImage);
}
else if (File.Exists(path))
catch (System.Exception e2)
{
var extension = Path.GetExtension(path).ToLower();
if (ImageExtensions.Contains(extension))
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e);
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2);
ImageSource image = _imageCache[Constant.ErrorIcon];
_imageCache[path] = image;
imageResult = new ImageResult(image, ImageType.Error);
}
}
return imageResult;
}
private static ImageResult GetThumbnailResult(ref string path, bool loadFullImage = false)
{
ImageSource image;
ImageType type = ImageType.Error;
if (Directory.Exists(path))
{
/* Directories can also have thumbnails instead of shell icons.
* Generating thumbnails for a bunch of folders while scrolling through
* results from Everything makes a big impact on performance and
* Flow.Launcher responsibility.
* - Solution: just load the icon
*/
type = ImageType.Folder;
image = GetThumbnail(path, ThumbnailOptions.IconOnly);
}
else if (File.Exists(path))
{
var extension = Path.GetExtension(path).ToLower();
if (ImageExtensions.Contains(extension))
{
type = ImageType.ImageFile;
if (loadFullImage)
{
type = ImageType.ImageFile;
if (loadFullImage)
{
image = LoadFullImage(path);
}
else
{
/* Although the documentation for GetImage on MSDN indicates that
* if a thumbnail is available it will return one, this has proved to not
* be the case in many situations while testing.
* - Solution: explicitly pass the ThumbnailOnly flag
*/
image = WindowsThumbnailProvider.GetThumbnail(path, Constant.ThumbnailSize,
Constant.ThumbnailSize, ThumbnailOptions.ThumbnailOnly);
}
image = LoadFullImage(path);
}
else
{
type = ImageType.File;
image = WindowsThumbnailProvider.GetThumbnail(path, Constant.ThumbnailSize,
Constant.ThumbnailSize, ThumbnailOptions.None);
/* Although the documentation for GetImage on MSDN indicates that
* if a thumbnail is available it will return one, this has proved to not
* be the case in many situations while testing.
* - Solution: explicitly pass the ThumbnailOnly flag
*/
image = GetThumbnail(path, ThumbnailOptions.ThumbnailOnly);
}
}
else
{
image = ImageCache[Constant.ErrorIcon];
path = Constant.ErrorIcon;
}
if (type != ImageType.Error)
{
image.Freeze();
type = ImageType.File;
image = GetThumbnail(path, ThumbnailOptions.None);
}
}
catch (System.Exception e)
else
{
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path}", e);
type = ImageType.Error;
image = ImageCache[Constant.ErrorIcon];
ImageCache[path] = image;
image = _imageCache[Constant.ErrorIcon];
path = Constant.ErrorIcon;
}
if (type != ImageType.Error)
{
image.Freeze();
}
return new ImageResult(image, type);
}
private static bool EnableImageHash = true;
private static BitmapSource GetThumbnail(string path, ThumbnailOptions option = ThumbnailOptions.ThumbnailOnly)
{
return WindowsThumbnailProvider.GetThumbnail(
path,
Constant.ThumbnailSize,
Constant.ThumbnailSize,
option);
}
public static ImageSource Load(string path, bool loadFullImage = false)
{
@ -194,25 +219,27 @@ namespace Flow.Launcher.Infrastructure.Image
var img = imageResult.ImageSource;
if (imageResult.ImageType != ImageType.Error && imageResult.ImageType != ImageType.Cache)
{ // we need to get image hash
string hash = EnableImageHash ? _hashGenerator.GetHashFromImage(img) : null;
{
// we need to get image hash
string hash = _enableHashImage ? _hashGenerator.GetHashFromImage(img) : null;
if (hash != null)
{
if (GuidToKey.TryGetValue(hash, out string key))
{ // image already exists
img = ImageCache[key];
if (_guidToKey.TryGetValue(hash, out string key))
{
// image already exists
img = _imageCache[key];
}
else
{ // new guid
GuidToKey[hash] = path;
{
// new guid
_guidToKey[hash] = path;
}
}
// update cache
ImageCache[path] = img;
_imageCache[path] = img;
}
return img;
}

View file

@ -0,0 +1,9 @@
namespace Flow.Launcher.Infrastructure
{
public static class KeyConstant
{
public const string Ctrl = nameof(Ctrl);
public const string Alt = nameof(Alt);
public const string Space = nameof(Space);
}
}

View file

@ -9,7 +9,9 @@ namespace Flow.Launcher.Infrastructure.UserSettings
{
public class Settings : BaseModel
{
public string Hotkey { get; set; } = "Alt + Space";
public string Hotkey { get; set; } = $"{KeyConstant.Alt} + {KeyConstant.Space}";
public string OpenResultModifiers { get; set; } = KeyConstant.Alt;
public bool ShowOpenResultHotkey { get; set; } = true;
public string Language { get; set; } = "en";
public string Theme { get; set; } = Constant.DefaultTheme;
public bool UseDropShadowEffect { get; set; } = false;

View file

@ -12,15 +12,26 @@
get { return "CSHARP"; }
}
public static string FSharp
{
get { return "FSHARP"; }
}
public static string Executable
{
get { return "EXECUTABLE"; }
}
public static bool IsDotNet(string language)
{
return language.ToUpper() == CSharp
|| language.ToUpper() == FSharp;
}
public static bool IsAllowed(string language)
{
return language.ToUpper() == Python.ToUpper()
|| language.ToUpper() == CSharp.ToUpper()
return IsDotNet(language)
|| language.ToUpper() == Python.ToUpper()
|| language.ToUpper() == Executable.ToUpper();
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
@ -55,7 +55,7 @@
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
<PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="PropertyChanged.Fody" Version="2.2.4">
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -43,6 +43,12 @@ namespace Flow.Launcher.Plugin
/// <summary>
/// Restart Flow Launcher
/// </summary>
void RestartApp();
/// <summary>
/// Restart Flow Launcher
/// </summary>
[Obsolete("Use RestartApp instead. This method will be removed in Flow Launcher 1.3")]
void RestarApp();
/// <summary>

View file

@ -110,12 +110,12 @@ namespace Flow.Launcher.Plugin.SharedCommands
return File.Exists(filePath);
}
public static void OpenLocationInExporer(string location)
public static void OpenPath(string fileOrFolderPath)
{
var psi = new ProcessStartInfo { FileName = FileExplorerProgramName, UseShellExecute = true, Arguments = location };
var psi = new ProcessStartInfo { FileName = FileExplorerProgramName, UseShellExecute = true, Arguments = fileOrFolderPath };
try
{
if (LocationExists(location))
if (LocationExists(fileOrFolderPath) || FileExits(fileOrFolderPath))
Process.Start(psi);
}
catch (Exception e)
@ -123,7 +123,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
#if DEBUG
throw e;
#else
MessageBox.Show(string.Format("Unable to open location {0}, please check if it exists", location));
MessageBox.Show(string.Format("Unable to open the path {0}, please check if it exists", fileOrFolderPath));
#endif
}
}

View file

@ -10,6 +10,7 @@
<ApplicationIcon />
<StartupObject />
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
@ -46,10 +47,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Moq" Version="4.13.1" />
<PackageReference Include="Moq" Version="4.14.1" />
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
</ItemGroup>
<ItemGroup>

View file

@ -74,6 +74,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Browse
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Calculator", "Plugins\Flow.Launcher.Plugin.Calculator\Flow.Launcher.Plugin.Calculator.csproj", "{59BD9891-3837-438A-958D-ADC7F91F6F7E}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "HelloWorldFSharp", "Plugins\HelloWorldFSharp\HelloWorldFSharp.fsproj", "{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -313,6 +315,18 @@ Global
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x64.Build.0 = Release|Any CPU
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.ActiveCfg = Release|Any CPU
{59BD9891-3837-438A-958D-ADC7F91F6F7E}.Release|x86.Build.0 = Release|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Debug|x64.ActiveCfg = Debug|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Debug|x64.Build.0 = Debug|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Debug|x86.ActiveCfg = Debug|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Debug|x86.Build.0 = Debug|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Release|Any CPU.Build.0 = Release|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Release|x64.ActiveCfg = Release|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Release|x64.Build.0 = Release|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Release|x86.ActiveCfg = Release|Any CPU
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -332,6 +346,7 @@ Global
{C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{9B130CC5-14FB-41FF-B310-0A95B6894C37} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
{30DDA7D9-3712-44F4-BD18-DC1C05B2DD9E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED}

View file

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Flow.Launcher.Converters
{
[ValueConversion(typeof(bool), typeof(Visibility))]
public class OpenResultHotkeyVisibilityConverter : IValueConverter
{
private const int MaxVisibleHotkeys = 9;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var hotkeyNumber = int.MaxValue;
if (value is ListBoxItem listBoxItem)
{
ListBox listBox = ItemsControl.ItemsControlFromItemContainer(listBoxItem) as ListBox;
hotkeyNumber = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
}
return hotkeyNumber <= MaxVisibleHotkeys ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
}
}

View file

@ -0,0 +1,22 @@
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
namespace Flow.Launcher.Converters
{
public class OrdinalConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture)
{
if (value is ListBoxItem listBoxItem)
{
ListBox listBox = ItemsControl.ItemsControlFromItemContainer(listBoxItem) as ListBox;
return listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1;
}
return 0;
}
public object ConvertBack(object value, System.Type targetType, object parameter, CultureInfo culture) => throw new System.InvalidOperationException();
}
}

View file

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
@ -11,6 +11,7 @@
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@ -65,7 +66,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="PropertyChanged.Fody" Version="2.2.4">
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

View file

@ -50,7 +50,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Genvejstast</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher genvejstast</system:String>
<system:String x:Key="openResultModifiers">Åbn resultatmodifikatorer</system:String>
<system:String x:Key="customQueryHotkey">Tilpasset søgegenvejstast</system:String>
<system:String x:Key="showOpenResultHotkey">Vis hotkey</system:String>
<system:String x:Key="delete">Slet</system:String>
<system:String x:Key="edit">Rediger</system:String>
<system:String x:Key="add">Tilføj</system:String>

View file

@ -50,7 +50,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Tastenkombination</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher Tastenkombination</system:String>
<system:String x:Key="openResultModifiers">Öffnen Sie die Ergebnismodifikatoren</system:String>
<system:String x:Key="customQueryHotkey">Benutzerdefinierte Abfrage Tastenkombination</system:String>
<system:String x:Key="showOpenResultHotkey">Hotkey anzeigen</system:String>
<system:String x:Key="delete">Löschen</system:String>
<system:String x:Key="edit">Bearbeiten</system:String>
<system:String x:Key="add">Hinzufügen</system:String>

View file

@ -60,6 +60,8 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Hotkey</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher Hotkey</system:String>
<system:String x:Key="openResultModifiers">Open Result Modifiers</system:String>
<system:String x:Key="showOpenResultHotkey">Show Hotkey</system:String>
<system:String x:Key="customQueryHotkey">Custom Query Hotkey</system:String>
<system:String x:Key="delete">Delete</system:String>
<system:String x:Key="edit">Edit</system:String>

View file

@ -54,7 +54,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Raccourcis</system:String>
<system:String x:Key="flowlauncherHotkey">Ouvrir Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Modificateurs de résultats ouverts</system:String>
<system:String x:Key="customQueryHotkey">Requêtes personnalisées</system:String>
<system:String x:Key="showOpenResultHotkey">Afficher le raccourci clavier</system:String>
<system:String x:Key="delete">Supprimer</system:String>
<system:String x:Key="edit">Modifier</system:String>
<system:String x:Key="add">Ajouter</system:String>

View file

@ -54,7 +54,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Tasti scelta rapida</system:String>
<system:String x:Key="flowlauncherHotkey">Tasto scelta rapida Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Apri modificatori di risultato</system:String>
<system:String x:Key="customQueryHotkey">Tasti scelta rapida per ricerche personalizzate</system:String>
<system:String x:Key="showOpenResultHotkey">Mostra tasto di scelta rapida</system:String>
<system:String x:Key="delete">Cancella</system:String>
<system:String x:Key="edit">Modifica</system:String>
<system:String x:Key="add">Aggiungi</system:String>

View file

@ -57,7 +57,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">ホットキー</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher ホットキー</system:String>
<system:String x:Key="openResultModifiers">結果修飾子を開く</system:String>
<system:String x:Key="customQueryHotkey">カスタムクエリ ホットキー</system:String>
<system:String x:Key="showOpenResultHotkey">ホットキーを表示</system:String>
<system:String x:Key="delete">削除</system:String>
<system:String x:Key="edit">編集</system:String>
<system:String x:Key="add">追加</system:String>

View file

@ -54,7 +54,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">핫키</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher 핫키</system:String>
<system:String x:Key="openResultModifiers">결과 수정 자 열기</system:String>
<system:String x:Key="customQueryHotkey">사용자지정 쿼리 핫키</system:String>
<system:String x:Key="showOpenResultHotkey">단축키 표시</system:String>
<system:String x:Key="delete">삭제</system:String>
<system:String x:Key="edit">편집</system:String>
<system:String x:Key="add">추가</system:String>

View file

@ -54,7 +54,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Hurtigtast</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher-hurtigtast</system:String>
<system:String x:Key="openResultModifiers">Åpne resultatmodifiserere</system:String>
<system:String x:Key="customQueryHotkey">Egendefinerd spørringshurtigtast</system:String>
<system:String x:Key="showOpenResultHotkey">Vis hurtigtast</system:String>
<system:String x:Key="delete">Slett</system:String>
<system:String x:Key="edit">Rediger</system:String>
<system:String x:Key="add">Legg til</system:String>

View file

@ -50,7 +50,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Sneltoets</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher Sneltoets</system:String>
<system:String x:Key="openResultModifiers">Open resultaatmodificatoren</system:String>
<system:String x:Key="customQueryHotkey">Custom Query Sneltoets</system:String>
<system:String x:Key="showOpenResultHotkey">Sneltoets weergeven</system:String>
<system:String x:Key="delete">Verwijder</system:String>
<system:String x:Key="edit">Bewerken</system:String>
<system:String x:Key="add">Toevoegen</system:String>

View file

@ -50,7 +50,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Skrót klawiszowy</system:String>
<system:String x:Key="flowlauncherHotkey">Skrót klawiszowy Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Modyfikatory klawiszów otwierających wyniki</system:String>
<system:String x:Key="customQueryHotkey">Skrót klawiszowy niestandardowych zapytań</system:String>
<system:String x:Key="showOpenResultHotkey">Pokaż skrót klawiszowy</system:String>
<system:String x:Key="delete">Usuń</system:String>
<system:String x:Key="edit">Edytuj</system:String>
<system:String x:Key="add">Dodaj</system:String>

View file

@ -54,7 +54,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Atalho</system:String>
<system:String x:Key="flowlauncherHotkey">Atalho do Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Modificadores de resultado aberto</system:String>
<system:String x:Key="customQueryHotkey">Atalho de Consulta Personalizada</system:String>
<system:String x:Key="showOpenResultHotkey">Mostrar tecla de atalho</system:String>
<system:String x:Key="delete">Apagar</system:String>
<system:String x:Key="edit">Editar</system:String>
<system:String x:Key="add">Adicionar</system:String>

View file

@ -50,7 +50,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Горячие клавиши</system:String>
<system:String x:Key="flowlauncherHotkey">Горячая клавиша Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Модификаторы открытого результата</system:String>
<system:String x:Key="customQueryHotkey">Задаваемые горячие клавиши для запросов</system:String>
<system:String x:Key="showOpenResultHotkey">Показать Hotkey</system:String>
<system:String x:Key="delete">Удалить</system:String>
<system:String x:Key="edit">Изменить</system:String>
<system:String x:Key="add">Добавить</system:String>

View file

@ -55,7 +55,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Klávesová skratka</system:String>
<system:String x:Key="flowlauncherHotkey">Klávesová skratka pre Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Otvorte modifikátory výsledkov</system:String>
<system:String x:Key="customQueryHotkey">Vlastná klávesová skratka pre dopyt</system:String>
<system:String x:Key="showOpenResultHotkey">Zobraziť klávesovú skratku</system:String>
<system:String x:Key="delete">Odstrániť</system:String>
<system:String x:Key="edit">Upraviť</system:String>
<system:String x:Key="add">Pridať</system:String>

View file

@ -54,6 +54,8 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Prečica</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher prečica</system:String>
<system:String x:Key="openResultModifiers">Отворите модификаторе резултата</system:String>
<system:String x:Key="showOpenResultHotkey">покажи хоткеи</system:String>
<system:String x:Key="customQueryHotkey">prečica za ručno dodat upit</system:String>
<system:String x:Key="delete">Obriši</system:String>
<system:String x:Key="edit">Izmeni</system:String>

View file

@ -58,7 +58,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Kısayol Tuşu</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher Kısayolu</system:String>
<system:String x:Key="openResultModifiers">Açık Sonuç Değiştiricileri</system:String>
<system:String x:Key="customQueryHotkey">Özel Sorgu Kısayolları</system:String>
<system:String x:Key="showOpenResultHotkey">Kısayol Tuşunu Göster</system:String>
<system:String x:Key="delete">Sil</system:String>
<system:String x:Key="edit">Düzenle</system:String>
<system:String x:Key="add">Ekle</system:String>

View file

@ -50,7 +50,9 @@
<!--Setting Hotkey-->
<system:String x:Key="hotkey">Гарячі клавіші</system:String>
<system:String x:Key="flowlauncherHotkey">Гаряча клавіша Flow Launcher</system:String>
<system:String x:Key="openResultModifiers">Відкриті модифікатори результатів</system:String>
<system:String x:Key="customQueryHotkey">Задані гарячі клавіші для запитів</system:String>
<system:String x:Key="showOpenResultHotkey">Показати клавішу швидкого доступу</system:String>
<system:String x:Key="delete">Видалити</system:String>
<system:String x:Key="edit">Змінити</system:String>
<system:String x:Key="add">Додати</system:String>

View file

@ -57,6 +57,8 @@
<!--设置,热键-->
<system:String x:Key="hotkey">热键</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher激活热键</system:String>
<system:String x:Key="openResultModifiers">开放结果修饰符</system:String>
<system:String x:Key="showOpenResultHotkey">显示热键</system:String>
<system:String x:Key="customQueryHotkey">自定义查询热键</system:String>
<system:String x:Key="delete">删除</system:String>
<system:String x:Key="edit">编辑</system:String>

View file

@ -50,7 +50,9 @@
<!--設置,熱鍵-->
<system:String x:Key="hotkey">熱鍵</system:String>
<system:String x:Key="flowlauncherHotkey">Flow Launcher 執行熱鍵</system:String>
<system:String x:Key="openResultModifiers">開放結果修飾符</system:String>
<system:String x:Key="customQueryHotkey">自定義熱鍵查詢</system:String>
<system:String x:Key="showOpenResultHotkey">顯示熱鍵</system:String>
<system:String x:Key="delete">刪除</system:String>
<system:String x:Key="edit">編輯</system:String>
<system:String x:Key="add">新增</system:String>

View file

@ -49,15 +49,15 @@
<KeyBinding Key="Enter" Command="{Binding OpenResultCommand}"></KeyBinding>
<KeyBinding Key="Enter" Modifiers="Ctrl" Command="{Binding OpenResultCommand}"></KeyBinding>
<KeyBinding Key="Enter" Modifiers="Alt" Command="{Binding OpenResultCommand}"></KeyBinding>
<KeyBinding Key="D1" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="0"></KeyBinding>
<KeyBinding Key="D2" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="1"></KeyBinding>
<KeyBinding Key="D3" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="2"></KeyBinding>
<KeyBinding Key="D4" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="3"></KeyBinding>
<KeyBinding Key="D5" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="4"></KeyBinding>
<KeyBinding Key="D6" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="5"></KeyBinding>
<KeyBinding Key="D7" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="6"></KeyBinding>
<KeyBinding Key="D8" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="7"></KeyBinding>
<KeyBinding Key="D9" Modifiers="Alt" Command="{Binding OpenResultCommand}" CommandParameter="8"></KeyBinding>
<KeyBinding Key="D1" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="0"></KeyBinding>
<KeyBinding Key="D2" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="1"></KeyBinding>
<KeyBinding Key="D3" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="2"></KeyBinding>
<KeyBinding Key="D4" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="3"></KeyBinding>
<KeyBinding Key="D5" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="4"></KeyBinding>
<KeyBinding Key="D6" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="5"></KeyBinding>
<KeyBinding Key="D7" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="6"></KeyBinding>
<KeyBinding Key="D8" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="7"></KeyBinding>
<KeyBinding Key="D9" Modifiers="{Binding OpenResultCommandModifiers}" Command="{Binding OpenResultCommand}" CommandParameter="8"></KeyBinding>
</Window.InputBindings>
<Grid Width="750">
<Border Style="{DynamicResource WindowBorderStyle}" MouseDown="OnMouseDown" CornerRadius="5" >

View file

@ -54,7 +54,7 @@ namespace Flow.Launcher
Application.Current.MainWindow.Close();
}
public void RestarApp()
public void RestartApp()
{
_mainVM.MainWindowVisibility = Visibility.Hidden;
@ -66,6 +66,11 @@ namespace Flow.Launcher
UpdateManager.RestartApp(Constant.ApplicationFileName);
}
public void RestarApp()
{
RestartApp();
}
public void CheckForNewUpdate()
{
_settingsVM.UpdateApp();

View file

@ -33,6 +33,8 @@
Cursor="Hand" UseLayoutRounding="False">
<Grid.Resources>
<converter:HighlightTextConverter x:Key="HighlightTextConverter"/>
<converter:OrdinalConverter x:Key="OrdinalConverter" />
<converter:OpenResultHotkeyVisibilityConverter x:Key="OpenResultHotkeyVisibilityConverter" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32" />
@ -46,6 +48,19 @@
<RowDefinition />
<RowDefinition Height="Auto" x:Name="SubTitleRowDefinition" />
</Grid.RowDefinitions>
<StackPanel Visibility="{Binding ShowOpenResultHotkey}">
<TextBlock Margin="0 5 5 0" Style="{DynamicResource ItemSubTitleStyle}" HorizontalAlignment="Right" Opacity="0.8" >
<TextBlock.Visibility>
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}" Converter="{StaticResource ResourceKey=OpenResultHotkeyVisibilityConverter}" />
</TextBlock.Visibility>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}+{1}">
<Binding Path="OpenResultModifiers" />
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}" Converter="{StaticResource ResourceKey=OrdinalConverter}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
<TextBlock Style="{DynamicResource ItemTitleStyle}" DockPanel.Dock="Left"
VerticalAlignment="Center" ToolTip="{Binding Result.Title}" x:Name="Title"
Text="{Binding Result.Title}">

View file

@ -312,8 +312,9 @@
<Grid Margin="30 10 30 10">
<Grid.RowDefinitions>
<RowDefinition Height="80" />
<RowDefinition Height="25" />
<RowDefinition Height="340" />
<RowDefinition Height="35" />
<RowDefinition Height="70" />
<RowDefinition Height="250" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" VerticalAlignment="Center"
@ -322,13 +323,22 @@
<flowlauncher:HotkeyControl x:Name="HotkeyControl" HotkeyChanged="OnHotkeyChanged"
Loaded="OnHotkeyControlLoaded" Height="35"/>
</StackPanel>
<TextBlock VerticalAlignment="Center" Grid.Row="1" Margin="0,3,10,2"
Text="{DynamicResource customQueryHotkey}" FontSize="14" />
<ListView ItemsSource="{Binding Settings.CustomPluginHotkeys}"
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center"
Margin="0,4,0,3">
<TextBlock VerticalAlignment="Center" Margin="0 0 10 0" Text="{DynamicResource openResultModifiers}" FontSize="14" />
<ComboBox Margin="0 0 0 0" Width="120"
ItemsSource="{Binding OpenResultModifiersList}"
SelectedItem="{Binding Settings.OpenResultModifiers}" FontSize="14" />
<CheckBox Margin="30 0 0 0" IsChecked="{Binding Settings.ShowOpenResultHotkey}" VerticalAlignment="Center">
<TextBlock Text="{DynamicResource showOpenResultHotkey}" FontSize="14" />
</CheckBox>
</StackPanel>
<TextBlock Grid.Row="2" VerticalAlignment="Center" Margin="0 23 10 2" Text="{DynamicResource customQueryHotkey}" FontSize="14" />
<ListView Grid.Row="3" ItemsSource="{Binding Settings.CustomPluginHotkeys}"
SelectedItem="{Binding SelectedCustomPluginHotkey}"
Style="{StaticResource {x:Static GridView.GridViewStyleKey}}"
BorderBrush="DarkGray" BorderThickness="1"
Margin="0 5 0 0" Grid.Row="2">
Margin="0 5 0 0">
<ListView.View>
<GridView>
<GridViewColumn Header="{DynamicResource hotkey}" Width="180">
@ -338,7 +348,7 @@
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="{DynamicResource actionKeywords}" Width="500">
<GridViewColumn Header="{DynamicResource actionKeywords}" Width="546">
<GridViewColumn.CellTemplate>
<DataTemplate DataType="userSettings:CustomPluginHotkey">
<TextBlock Text="{Binding ActionKeyword}" />
@ -348,7 +358,7 @@
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Row="3" HorizontalAlignment="Right" VerticalAlignment="Bottom"
<StackPanel Grid.Row="4" HorizontalAlignment="Right" VerticalAlignment="Bottom"
Orientation="Horizontal" Width="360">
<Button Click="OnDeleteCustomHotkeyClick" Width="100"
Margin="10" Content="{DynamicResource delete}" />

View file

@ -241,7 +241,7 @@ namespace Flow.Launcher
{
var directory = _viewModel.SelectedPlugin.PluginPair.Metadata.PluginDirectory;
if (!string.IsNullOrEmpty(directory))
FilesFolders.OpenLocationInExporer(directory);
FilesFolders.OpenPath(directory);
}
}
#endregion

View file

@ -28,6 +28,8 @@ namespace Flow.Launcher.ViewModel
{
#region Private Fields
private const string DefaultOpenResultModifiers = "Alt";
private bool _isQueryRunning;
private Query _lastQuery;
private string _queryTextBeforeLeaveResults;
@ -76,6 +78,7 @@ namespace Flow.Launcher.ViewModel
SetHotkey(_settings.Hotkey, OnHotkey);
SetCustomPluginHotkey();
SetOpenResultModifiers();
}
private void RegisterResultsUpdatedEvent()
@ -279,6 +282,8 @@ namespace Flow.Launcher.ViewModel
public ICommand LoadHistoryCommand { get; set; }
public ICommand OpenResultCommand { get; set; }
public string OpenResultCommandModifiers { get; private set; }
public ImageSource Image => ImageLoader.Load(Constant.QueryTextBoxIconImagePath);
#endregion
@ -598,6 +603,11 @@ namespace Flow.Launcher.ViewModel
}
}
private void SetOpenResultModifiers()
{
OpenResultCommandModifiers = _settings.OpenResultModifiers ?? DefaultOpenResultModifiers;
}
private void OnHotkey(object sender, HotkeyEventArgs e)
{
if (!ShouldIgnoreHotkeys())

View file

@ -1,9 +1,11 @@
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Image;
using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin;
@ -11,14 +13,22 @@ namespace Flow.Launcher.ViewModel
{
public class ResultViewModel : BaseModel
{
public ResultViewModel(Result result)
public ResultViewModel(Result result, Settings settings)
{
if (result != null)
{
Result = result;
}
Settings = settings;
}
public Settings Settings { get; private set; }
public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden;
public string OpenResultModifiers => Settings.OpenResultModifiers;
public ImageSource Image
{
get

View file

@ -156,7 +156,7 @@ namespace Flow.Launcher.ViewModel
private List<ResultViewModel> NewResults(List<Result> newRawResults, string resultId)
{
var results = Results.ToList();
var newResults = newRawResults.Select(r => new ResultViewModel(r)).ToList();
var newResults = newRawResults.Select(r => new ResultViewModel(r, _settings)).ToList();
var oldResults = results.Where(r => r.Result.PluginID == resultId).ToList();
// Find the same results in A (old results) and B (new newResults)

View file

@ -160,6 +160,7 @@ namespace Flow.Launcher.ViewModel
}
}
public List<string> OpenResultModifiersList => new List<string> { KeyConstant.Alt, KeyConstant.Ctrl, $"{KeyConstant.Ctrl}+{KeyConstant.Alt}" };
private Internationalization _translater => InternationalizationManager.Instance;
public List<Language> Languages => _translater.LoadAvailableLanguages();
public IEnumerable<int> MaxResultsRange => Enumerable.Range(2, 16);

View file

@ -89,7 +89,7 @@ namespace Flow.Launcher.Plugin.Folder
if (record.Type == ResultType.File)
File.Delete(record.FullPath);
else
Directory.Delete(record.FullPath);
Directory.Delete(record.FullPath, true);
}
catch(Exception e)
{

View file

@ -1,6 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
@ -27,6 +27,8 @@ namespace Flow.Launcher.Plugin.Folder
private readonly PluginJsonStorage<Settings> _storage;
private IContextMenu _contextMenuLoader;
private static Dictionary<string, string> _envStringPaths;
public Main()
{
_storage = new PluginJsonStorage<Settings>();
@ -48,6 +50,7 @@ namespace Flow.Launcher.Plugin.Folder
_context = context;
_contextMenuLoader = new ContextMenuLoader(context);
InitialDriverList();
LoadEnvironmentStringPaths();
}
public List<Result> Query(Query query)
@ -55,10 +58,19 @@ namespace Flow.Launcher.Plugin.Folder
var results = GetUserFolderResults(query);
string search = query.Search.ToLower();
if (!IsDriveOrSharedFolder(search))
if (!IsDriveOrSharedFolder(search) && !IsEnvironmentVariableSearch(search))
{
return results;
}
results.AddRange(QueryInternal_Directory_Exists(query));
if (IsEnvironmentVariableSearch(search))
{
results.AddRange(GetEnvironmentStringPathResults(search, query));
}
else
{
results.AddRange(QueryInternal_Directory_Exists(query.Search, query));
}
// todo why was this hack here?
foreach (var result in results)
@ -69,10 +81,15 @@ namespace Flow.Launcher.Plugin.Folder
return results;
}
private static bool IsEnvironmentVariableSearch(string search)
{
return _envStringPaths != null && search.StartsWith("%");
}
private static bool IsDriveOrSharedFolder(string search)
{
if (search.StartsWith(@"\\"))
{ // share folder
{ // shared folder
return true;
}
@ -103,7 +120,7 @@ namespace Flow.Launcher.Plugin.Folder
{
try
{
FilesFolders.OpenLocationInExporer(path);
FilesFolders.OpenPath(path);
return true;
}
catch (Exception ex)
@ -146,14 +163,26 @@ namespace Flow.Launcher.Plugin.Folder
}
}
private void LoadEnvironmentStringPaths()
{
_envStringPaths = new Dictionary<string, string>();
foreach (DictionaryEntry special in Environment.GetEnvironmentVariables())
{
if (Directory.Exists(special.Value.ToString()))
{
_envStringPaths.Add(special.Key.ToString().ToLower(), special.Value.ToString());
}
}
}
private static readonly char[] _specialSearchChars = new char[]
{
'?', '*', '>'
};
private List<Result> QueryInternal_Directory_Exists(Query query)
private List<Result> QueryInternal_Directory_Exists(string search, Query query)
{
var search = query.Search;
var results = new List<Result>();
var hasSpecial = search.IndexOfAny(_specialSearchChars) >= 0;
string incompleteName = "";
@ -243,6 +272,63 @@ namespace Flow.Launcher.Plugin.Folder
return results.Concat(folderList.OrderBy(x => x.Title)).Concat(fileList.OrderBy(x => x.Title)).ToList();
}
private List<Result> GetEnvironmentStringPathSuggestions(string search, Query query)
{
var results = new List<Result>();
foreach (var p in _envStringPaths)
{
if (p.Key.StartsWith(search))
{
results.Add(CreateFolderResult($"%{p.Key}%", p.Value, p.Value, query));
}
}
return results;
}
private List<Result> GetEnvironmentStringPathResults(string envStringSearch, Query query)
{
if (envStringSearch == "%")
{ // return all environment string options as path suggestions
return GetEnvironmentStringPathSuggestions("", query);
}
var results = new List<Result>();
var search = envStringSearch.Substring(1);
if (search.EndsWith("%") && search.Length > 1)
{ // query starts and ends with a %, find an exact match from env-string paths
var exactEnvStringPath = search.Substring(0, search.Length-1);
if (_envStringPaths.ContainsKey(exactEnvStringPath))
{
var expandedPath = _envStringPaths[exactEnvStringPath];
results.Add(CreateFolderResult($"%{exactEnvStringPath}%", expandedPath, expandedPath, query));
}
}
else if (search.Contains("%"))
{ // query starts with a % and contains another % somewhere before the end
var splitSearch = search.Split("%");
var exactEnvStringPath = splitSearch[0];
// if there are more than 2 % characters in the query, don't bother
if (splitSearch.Length == 2 && _envStringPaths.ContainsKey(exactEnvStringPath))
{
var queryPartToReplace = $"%{exactEnvStringPath}%";
var expandedPath = _envStringPaths[exactEnvStringPath];
// replace the %envstring% part of the query with its expanded equivalent
var updatedSearch = envStringSearch.Replace(queryPartToReplace, expandedPath);
results.AddRange(QueryInternal_Directory_Exists(updatedSearch, query));
}
}
else
{ // query simply starts wtih a %, suggest env-string paths that match the rest of the search
results.AddRange(GetEnvironmentStringPathSuggestions(search, query));
}
return results;
}
private static Result CreateFileResult(string filePath, Query query)
{
var result = new Result
@ -255,7 +341,7 @@ namespace Flow.Launcher.Plugin.Folder
{
try
{
FilesFolders.OpenLocationInExporer(filePath);
FilesFolders.OpenPath(filePath);
}
catch (Exception ex)
{
@ -286,7 +372,7 @@ namespace Flow.Launcher.Plugin.Folder
Score = 500,
Action = c =>
{
FilesFolders.OpenLocationInExporer(search);
FilesFolders.OpenPath(search);
return true;
}
};

View file

@ -220,7 +220,7 @@ namespace Flow.Launcher.Plugin.PluginManagement
"Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
context.API.RestarApp();
context.API.RestartApp();
}
}
}

View file

@ -110,7 +110,7 @@
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.18362.2005" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="NLog" Version="4.7.0-rc1" />
<PackageReference Include="NLog" Version="4.7.0" />
<PackageReference Include="System.Runtime" Version="4.3.1" />
</ItemGroup>

View file

@ -205,7 +205,7 @@ namespace Flow.Launcher.Plugin.Sys
IcoPath = "Images\\app.png",
Action = c =>
{
context.API.RestarApp();
context.API.RestartApp();
return false;
}
},

View file

@ -8,6 +8,7 @@
<AssemblyName>Flow.Launcher.Plugin.WebSearch</AssemblyName>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

View file

@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<OutputPath>..\..\Output\Debug\Plugins\HelloWorldFSharp\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<OutputPath>..\..\Output\Release\Plugins\HelloWorldFSharp\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Content Include="Images\app.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="plugin.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Compile Include="Main.fs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.1" />
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -0,0 +1,31 @@
namespace HelloWorldFSharp
open Flow.Launcher.Plugin
open System.Collections.Generic
type HelloWorldFSharpPlugin() =
let mutable initContext = PluginInitContext()
interface IPlugin with
member this.Init (context: PluginInitContext) =
initContext <- context
member this.Query (query: Query) =
List<Result> [
Result (Title = "Hello World from F#",
SubTitle = sprintf "Query: %s" query.Search)
Result (Title = "Browse source code of this plugin",
SubTitle = "click to open in browser",
Action = (fun ctx ->
initContext.CurrentPluginMetadata.Website
|> System.Diagnostics.Process.Start
|> ignore
true))
Result (Title = "Trigger a tray message",
Action = (fun _ ->
initContext.API.ShowMsg ("Sample tray message", "from the F# plugin")
false))
]

View file

@ -0,0 +1,12 @@
{
"ID": "8FF5D5C1F8194958A12E8668FB7ECC04",
"ActionKeyword": "hf",
"Name": "Hello World FSharp",
"Description": "Hello World FSharp",
"Author": "Ioannis G.",
"Version": "1.0.0",
"Language": "fsharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "HelloWorldFSharp.dll",
"IcoPath": "Images\\app.png"
}