Merge Upstream
6
.gitignore
vendored
|
|
@ -300,4 +300,8 @@ migrateToAutomaticPackageRestore.ps1
|
|||
*.pyc
|
||||
*.diagsession
|
||||
Output-Performance.txt
|
||||
*.diff
|
||||
*.diff
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
.history
|
||||
15
Directory.Build.targets
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<Project>
|
||||
<Target Name="ExcludePluginProjectReferenceOutput"
|
||||
AfterTargets="AssignProjectConfiguration"
|
||||
BeforeTargets="ResolveProjectReferences"
|
||||
Condition="'$(OutputType)' == 'Library' and '$(CopyLocalLockFileAssemblies)' == 'true' and $(AssemblyName.EndsWith('Tests')) == 'false' ">
|
||||
<ItemGroup>
|
||||
<ProjectReferenceWithConfiguration Update="@(ProjectReferenceWithConfiguration)" >
|
||||
<Private>false</Private>
|
||||
</ProjectReferenceWithConfiguration>
|
||||
<ProjectReference Update="@(ProjectReference)" >
|
||||
<Private>false</Private>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
BIN
Doc/Default Icons/app_missing_img.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
Doc/Default Icons/app_missing_img_01.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
44
Doc/Default Icons/app_missing_img_01.svg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
Doc/Default Icons/app_missing_img_02.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
44
Doc/Default Icons/app_missing_img_02.svg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
Doc/Default Icons/app_missing_img_03.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
44
Doc/Default Icons/app_missing_img_03.svg
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
Doc/Default Icons/app_missing_img_buttons.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
48
Doc/Default Icons/app_missing_img_buttons.svg
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
Doc/Default Icons/app_missing_img_fluent.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
49
Doc/Default Icons/app_missing_img_fluent.svg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
Doc/Default Icons/app_missing_img_huge.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
42
Doc/Default Icons/app_missing_img_huge.svg
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
Doc/Default Icons/app_missing_img_lightblue.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
38
Doc/Default Icons/app_missing_img_lightblue.svg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
Doc/Default Icons/app_missing_img_lightblue_buttons.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
42
Doc/Default Icons/app_missing_img_lightblue_buttons.svg
Normal file
|
After Width: | Height: | Size: 52 KiB |
BIN
Doc/Default Icons/app_missing_img_minimal.png
Normal file
|
After Width: | Height: | Size: 45 KiB |
40
Doc/Default Icons/app_missing_img_minimal.svg
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
Doc/Default Icons/app_missing_img_minimal_buttons.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
42
Doc/Default Icons/app_missing_img_minimal_buttons.svg
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
Doc/app_missing_img.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -95,7 +95,7 @@ namespace Flow.Launcher.Core.Configuration
|
|||
|
||||
public void MoveUserDataFolder(string fromLocation, string toLocation)
|
||||
{
|
||||
FilesFolders.Copy(fromLocation, toLocation);
|
||||
FilesFolders.CopyAll(fromLocation, toLocation);
|
||||
VerifyUserDataAfterMove(fromLocation, toLocation);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,12 +54,7 @@
|
|||
|
||||
<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.5.13" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.2.0" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
57
Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using Flow.Launcher.Infrastructure;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
internal class PluginAssemblyLoader : AssemblyLoadContext
|
||||
{
|
||||
private readonly AssemblyDependencyResolver dependencyResolver;
|
||||
|
||||
private readonly AssemblyDependencyResolver referencedPluginPackageDependencyResolver;
|
||||
|
||||
private readonly AssemblyName assemblyName;
|
||||
|
||||
internal PluginAssemblyLoader(string assemblyFilePath)
|
||||
{
|
||||
dependencyResolver = new AssemblyDependencyResolver(assemblyFilePath);
|
||||
assemblyName = new AssemblyName(Path.GetFileNameWithoutExtension(assemblyFilePath));
|
||||
|
||||
referencedPluginPackageDependencyResolver =
|
||||
new AssemblyDependencyResolver(Path.Combine(Constant.ProgramDirectory, "Flow.Launcher.Plugin.dll"));
|
||||
}
|
||||
|
||||
internal Assembly LoadAssemblyAndDependencies()
|
||||
{
|
||||
return LoadFromAssemblyName(assemblyName);
|
||||
}
|
||||
|
||||
protected override Assembly Load(AssemblyName assemblyName)
|
||||
{
|
||||
string assemblyPath = dependencyResolver.ResolveAssemblyToPath(assemblyName);
|
||||
|
||||
// When resolving dependencies, ignore assembly depenedencies that already exits with Flow.Launcher.Plugin
|
||||
// Otherwise will get unexpected behaviour with plugins, e.g. JsonIgnore attribute not honored in WebSearch or other plugins
|
||||
// that use Newtonsoft.Json
|
||||
if (assemblyPath == null || ExistsInReferencedPluginPackage(assemblyName))
|
||||
return null;
|
||||
|
||||
return LoadFromAssemblyPath(assemblyPath);
|
||||
}
|
||||
|
||||
internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, Type type)
|
||||
{
|
||||
var allTypes = assembly.ExportedTypes;
|
||||
|
||||
return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(type));
|
||||
}
|
||||
|
||||
internal bool ExistsInReferencedPluginPackage(AssemblyName assemblyName)
|
||||
{
|
||||
return referencedPluginPackageDependencyResolver.ResolveAssemblyToPath(assemblyName) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using Newtonsoft.Json;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
internal class PluginInstaller
|
||||
{
|
||||
internal static void Install(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
string tempFolder = Path.Combine(Path.GetTempPath(), "flowlauncher", "plugins");
|
||||
if (Directory.Exists(tempFolder))
|
||||
{
|
||||
Directory.Delete(tempFolder, true);
|
||||
}
|
||||
UnZip(path, tempFolder, true);
|
||||
|
||||
string jsonPath = Path.Combine(tempFolder, Constant.PluginMetadataFileName);
|
||||
if (!File.Exists(jsonPath))
|
||||
{
|
||||
MessageBox.Show("Install failed: plugin config is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
PluginMetadata plugin = GetMetadataFromJson(tempFolder);
|
||||
if (plugin == null || plugin.Name == null)
|
||||
{
|
||||
MessageBox.Show("Install failed: plugin config is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
string pluginFolderPath = Infrastructure.UserSettings.DataLocation.PluginsDirectory;
|
||||
|
||||
string newPluginName = plugin.Name
|
||||
.Replace("/", "_")
|
||||
.Replace("\\", "_")
|
||||
.Replace(":", "_")
|
||||
.Replace("<", "_")
|
||||
.Replace(">", "_")
|
||||
.Replace("?", "_")
|
||||
.Replace("*", "_")
|
||||
.Replace("|", "_")
|
||||
+ "-" + Guid.NewGuid();
|
||||
|
||||
string newPluginPath = Path.Combine(pluginFolderPath, newPluginName);
|
||||
|
||||
string content = $"Do you want to install following plugin?{Environment.NewLine}{Environment.NewLine}" +
|
||||
$"Name: {plugin.Name}{Environment.NewLine}" +
|
||||
$"Version: {plugin.Version}{Environment.NewLine}" +
|
||||
$"Author: {plugin.Author}";
|
||||
PluginPair existingPlugin = PluginManager.GetPluginForId(plugin.ID);
|
||||
|
||||
if (existingPlugin != null)
|
||||
{
|
||||
content = $"Do you want to update following plugin?{Environment.NewLine}{Environment.NewLine}" +
|
||||
$"Name: {plugin.Name}{Environment.NewLine}" +
|
||||
$"Old Version: {existingPlugin.Metadata.Version}" +
|
||||
$"{Environment.NewLine}New Version: {plugin.Version}" +
|
||||
$"{Environment.NewLine}Author: {plugin.Author}";
|
||||
}
|
||||
|
||||
var result = MessageBox.Show(content, "Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory))
|
||||
{
|
||||
//when plugin is in use, we can't delete them. That's why we need to make plugin folder a random name
|
||||
File.Create(Path.Combine(existingPlugin.Metadata.PluginDirectory, "NeedDelete.txt")).Close();
|
||||
}
|
||||
|
||||
Directory.Move(tempFolder, newPluginPath);
|
||||
|
||||
//exsiting plugins may be has loaded by application,
|
||||
//if we try to delelte those kind of plugins, we will get a error that indicate the
|
||||
//file is been used now.
|
||||
//current solution is to restart Flow Launcher. Ugly.
|
||||
//if (MainWindow.Initialized)
|
||||
//{
|
||||
// Plugins.Initialize();
|
||||
//}
|
||||
if (MessageBox.Show($"You have installed plugin {plugin.Name} successfully.{Environment.NewLine}" +
|
||||
"Restart Flow Launcher to take effect?",
|
||||
"Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
|
||||
{
|
||||
PluginManager.API.RestartApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static PluginMetadata GetMetadataFromJson(string pluginDirectory)
|
||||
{
|
||||
string configPath = Path.Combine(pluginDirectory, Constant.PluginMetadataFileName);
|
||||
PluginMetadata metadata;
|
||||
|
||||
if (!File.Exists(configPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
metadata = JsonConvert.DeserializeObject<PluginMetadata>(File.ReadAllText(configPath));
|
||||
metadata.PluginDirectory = pluginDirectory;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid json format", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!AllowedLanguage.IsAllowed(metadata.Language))
|
||||
{
|
||||
Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: invalid language {metadata.Language}");
|
||||
return null;
|
||||
}
|
||||
if (!File.Exists(metadata.ExecuteFilePath))
|
||||
{
|
||||
Log.Error($"|PluginInstaller.GetMetadataFromJson|plugin config {configPath} failed: file {metadata.ExecuteFilePath} doesn't exist");
|
||||
return null;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// unzip plugin contents to the given directory.
|
||||
/// </summary>
|
||||
/// <param name="zipFile">The path to the zip file.</param>
|
||||
/// <param name="strDirectory">The output directory.</param>
|
||||
/// <param name="overWrite">overwirte</param>
|
||||
private static void UnZip(string zipFile, string strDirectory, bool overWrite)
|
||||
{
|
||||
if (strDirectory == "")
|
||||
strDirectory = Directory.GetCurrentDirectory();
|
||||
|
||||
using (ZipInputStream zipStream = new ZipInputStream(File.OpenRead(zipFile)))
|
||||
{
|
||||
ZipEntry theEntry;
|
||||
|
||||
while ((theEntry = zipStream.GetNextEntry()) != null)
|
||||
{
|
||||
var pathToZip = theEntry.Name;
|
||||
var directoryName = String.IsNullOrEmpty(pathToZip) ? "" : Path.GetDirectoryName(pathToZip);
|
||||
var fileName = Path.GetFileName(pathToZip);
|
||||
var destinationDir = Path.Combine(strDirectory, directoryName);
|
||||
var destinationFile = Path.Combine(destinationDir, fileName);
|
||||
|
||||
Directory.CreateDirectory(destinationDir);
|
||||
|
||||
if (String.IsNullOrEmpty(fileName) || (File.Exists(destinationFile) && !overWrite))
|
||||
continue;
|
||||
|
||||
using (FileStream streamWriter = File.Create(destinationFile))
|
||||
{
|
||||
zipStream.CopyTo(streamWriter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -133,11 +133,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
}
|
||||
}
|
||||
|
||||
public static void InstallPlugin(string path)
|
||||
{
|
||||
PluginInstaller.Install(path);
|
||||
}
|
||||
|
||||
public static List<PluginPair> ValidPluginsForQuery(Query query)
|
||||
{
|
||||
if (NonGlobalPlugins.ContainsKey(query.ActionKeyword))
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
|
||||
#if DEBUG
|
||||
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(metadata.ExecuteFilePath);
|
||||
var types = assembly.GetTypes();
|
||||
var type = types.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(typeof(IPlugin)));
|
||||
var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
|
||||
var assembly = assemblyLoader.LoadAssemblyAndDependencies();
|
||||
var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly, typeof(IPlugin));
|
||||
var plugin = (IPlugin)Activator.CreateInstance(type);
|
||||
#else
|
||||
Assembly assembly = null;
|
||||
|
|
@ -51,10 +51,10 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
try
|
||||
{
|
||||
assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(metadata.ExecuteFilePath);
|
||||
var assemblyLoader = new PluginAssemblyLoader(metadata.ExecuteFilePath);
|
||||
assembly = assemblyLoader.LoadAssemblyAndDependencies();
|
||||
|
||||
var types = assembly.GetTypes();
|
||||
var type = types.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Contains(typeof(IPlugin)));
|
||||
var type = assemblyLoader.FromAssemblyGetTypeOfInterface(assembly, typeof(IPlugin));
|
||||
|
||||
plugin = (IPlugin)Activator.CreateInstance(type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,7 +88,6 @@ namespace Flow.Launcher.Core.Resource
|
|||
{
|
||||
language = language.NonNull();
|
||||
|
||||
Settings.Language = language.LanguageCode;
|
||||
|
||||
RemoveOldLanguageFiles();
|
||||
if (language != AvailableLanguages.English)
|
||||
|
|
@ -96,6 +95,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
LoadLanguage(language);
|
||||
}
|
||||
UpdatePluginMetadataTranslations();
|
||||
Settings.Language = language.LanguageCode;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Flow.Launcher.Core.Resource
|
|||
private ResourceDictionary _oldResource;
|
||||
private string _oldTheme;
|
||||
public Settings Settings { get; set; }
|
||||
private const string Folder = "Themes";
|
||||
private const string Folder = Constant.Themes;
|
||||
private const string Extension = ".xaml";
|
||||
private string DirectoryPath => Path.Combine(Constant.ProgramDirectory, Folder);
|
||||
private string UserDirectoryPath => Path.Combine(DataLocation.DataDirectory(), Folder);
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ namespace Flow.Launcher.Core
|
|||
if (DataLocation.PortableDataLocationInUse())
|
||||
{
|
||||
var targetDestination = updateManager.RootAppDirectory + $"\\app-{newReleaseVersion.ToString()}\\{DataLocation.PortableFolderName}";
|
||||
FilesFolders.Copy(DataLocation.PortableDataPath, targetDestination);
|
||||
FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination);
|
||||
if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination))
|
||||
MessageBox.Show("Flow Launcher was not able to move your user profile data to the new update version. Please manually " +
|
||||
$"move your profile data folder from {DataLocation.PortableDataPath} to {targetDestination}");
|
||||
|
|
|
|||
|
|
@ -1,178 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using hyjiacan.util.p4n;
|
||||
using hyjiacan.util.p4n.format;
|
||||
using JetBrains.Annotations;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure
|
||||
{
|
||||
public interface IAlphabet
|
||||
{
|
||||
string Translate(string stringToTranslate);
|
||||
}
|
||||
|
||||
public class Alphabet : IAlphabet
|
||||
{
|
||||
private readonly HanyuPinyinOutputFormat Format = new HanyuPinyinOutputFormat();
|
||||
private ConcurrentDictionary<string, string[][]> PinyinCache;
|
||||
private BinaryStorage<Dictionary<string, string[][]>> _pinyinStorage;
|
||||
private Settings _settings;
|
||||
|
||||
public void Initialize([NotNull] Settings settings)
|
||||
{
|
||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||
InitializePinyinHelpers();
|
||||
}
|
||||
|
||||
private void InitializePinyinHelpers()
|
||||
{
|
||||
Format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
|
||||
|
||||
Stopwatch.Normal("|Flow Launcher.Infrastructure.Alphabet.Initialize|Preload pinyin cache", () =>
|
||||
{
|
||||
_pinyinStorage = new BinaryStorage<Dictionary<string, string[][]>>("Pinyin");
|
||||
|
||||
lock(_pinyinStorage)
|
||||
{
|
||||
var loaded = _pinyinStorage.TryLoad(new Dictionary<string, string[][]>());
|
||||
|
||||
PinyinCache = new ConcurrentDictionary<string, string[][]>(loaded);
|
||||
}
|
||||
|
||||
// force pinyin library static constructor initialize
|
||||
PinyinHelper.toHanyuPinyinStringArray('T', Format);
|
||||
});
|
||||
Log.Info($"|Flow Launcher.Infrastructure.Alphabet.Initialize|Number of preload pinyin combination<{PinyinCache.Count}>");
|
||||
}
|
||||
|
||||
public string Translate(string str)
|
||||
{
|
||||
return ConvertChineseCharactersToPinyin(str);
|
||||
}
|
||||
|
||||
public string ConvertChineseCharactersToPinyin(string source)
|
||||
{
|
||||
if (!_settings.ShouldUsePinyin)
|
||||
return source;
|
||||
|
||||
if (string.IsNullOrEmpty(source))
|
||||
return source;
|
||||
|
||||
if (!ContainsChinese(source))
|
||||
return source;
|
||||
|
||||
var combination = PinyinCombination(source);
|
||||
|
||||
var pinyinArray=combination.Select(x => string.Join("", x));
|
||||
var acronymArray = combination.Select(Acronym).Distinct();
|
||||
|
||||
var joinedSingleStringCombination = new StringBuilder();
|
||||
var all = acronymArray.Concat(pinyinArray);
|
||||
all.ToList().ForEach(x => joinedSingleStringCombination.Append(x));
|
||||
|
||||
return joinedSingleStringCombination.ToString();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
if (!_settings.ShouldUsePinyin)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock(_pinyinStorage)
|
||||
{
|
||||
_pinyinStorage.Save(PinyinCache.ToDictionary(i => i.Key, i => i.Value));
|
||||
}
|
||||
}
|
||||
|
||||
private static string[] EmptyStringArray = new string[0];
|
||||
private static string[][] Empty2DStringArray = new string[0][];
|
||||
|
||||
/// <summmary>
|
||||
/// replace chinese character with pinyin, non chinese character won't be modified
|
||||
/// Because we don't have words dictionary, so we can only return all possiblie pinyin combination
|
||||
/// e.g. 音乐 will return yinyue and yinle
|
||||
/// <param name="characters"> should be word or sentence, instead of single character. e.g. 微软 </param>
|
||||
/// </summmary>
|
||||
public string[][] PinyinCombination(string characters)
|
||||
{
|
||||
if (!_settings.ShouldUsePinyin || string.IsNullOrEmpty(characters))
|
||||
{
|
||||
return Empty2DStringArray;
|
||||
}
|
||||
|
||||
if (!PinyinCache.ContainsKey(characters))
|
||||
{
|
||||
var allPinyins = new List<string[]>();
|
||||
foreach (var c in characters)
|
||||
{
|
||||
var pinyins = PinyinHelper.toHanyuPinyinStringArray(c, Format);
|
||||
if (pinyins != null)
|
||||
{
|
||||
var r = pinyins.Distinct().ToArray();
|
||||
allPinyins.Add(r);
|
||||
}
|
||||
else
|
||||
{
|
||||
var r = new[] { c.ToString() };
|
||||
allPinyins.Add(r);
|
||||
}
|
||||
}
|
||||
|
||||
var combination = allPinyins.Aggregate(Combination).Select(c => c.Split(';')).ToArray();
|
||||
PinyinCache[characters] = combination;
|
||||
return combination;
|
||||
}
|
||||
else
|
||||
{
|
||||
return PinyinCache[characters];
|
||||
}
|
||||
}
|
||||
|
||||
public string Acronym(string[] pinyin)
|
||||
{
|
||||
var acronym = string.Join("", pinyin.Select(p => p[0]));
|
||||
return acronym;
|
||||
}
|
||||
|
||||
public bool ContainsChinese(string word)
|
||||
{
|
||||
if (!_settings.ShouldUsePinyin)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (word.Length > 40)
|
||||
{
|
||||
//Skip strings that are too long string for Pinyin conversion.
|
||||
return false;
|
||||
}
|
||||
|
||||
var chinese = word.Select(PinyinHelper.toHanyuPinyinStringArray)
|
||||
.Any(p => p != null);
|
||||
return chinese;
|
||||
}
|
||||
|
||||
private string[] Combination(string[] array1, string[] array2)
|
||||
{
|
||||
if (!_settings.ShouldUsePinyin)
|
||||
{
|
||||
return EmptyStringArray;
|
||||
}
|
||||
|
||||
var combination = (
|
||||
from a1 in array1
|
||||
from a2 in array2
|
||||
select $"{a1};{a2}"
|
||||
).ToArray();
|
||||
return combination;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,13 +23,17 @@ namespace Flow.Launcher.Infrastructure
|
|||
public static readonly string Version = FileVersionInfo.GetVersionInfo(Assembly.Location.NonNull()).ProductVersion;
|
||||
|
||||
public static readonly int ThumbnailSize = 64;
|
||||
public static readonly string DefaultIcon = Path.Combine(ProgramDirectory, "Images", "app.png");
|
||||
public static readonly string ErrorIcon = Path.Combine(ProgramDirectory, "Images", "app_error.png");
|
||||
private static readonly string ImagesDirectory = Path.Combine(ProgramDirectory, "Images");
|
||||
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 string PythonPath;
|
||||
|
||||
public static readonly string QueryTextBoxIconImagePath = $"{ProgramDirectory}\\Images\\mainsearch.png";
|
||||
|
||||
public const string DefaultTheme = "Darker";
|
||||
|
||||
public const string Themes = "Themes";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,14 +49,11 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NLog.Schema" Version="4.7.0-rc1" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
|
||||
<PackageReference Include="Pinyin4DotNet" Version="2016.4.23.4" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="2.5.13" />
|
||||
<PackageReference Include="ToolGood.Words.Pinyin" Version="3.0.1.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
|
|
@ -2,44 +2,84 @@ using System;
|
|||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Image
|
||||
{
|
||||
[Serializable]
|
||||
public class ImageUsage
|
||||
{
|
||||
|
||||
public int usage;
|
||||
public ImageSource imageSource;
|
||||
|
||||
public ImageUsage(int usage, ImageSource image)
|
||||
{
|
||||
this.usage = usage;
|
||||
imageSource = image;
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageCache
|
||||
{
|
||||
private const int MaxCached = 5000;
|
||||
public ConcurrentDictionary<string, int> Usage = new ConcurrentDictionary<string, int>();
|
||||
private readonly ConcurrentDictionary<string, ImageSource> _data = new ConcurrentDictionary<string, ImageSource>();
|
||||
|
||||
private const int MaxCached = 50;
|
||||
public ConcurrentDictionary<string, ImageUsage> Data { get; private set; } = new ConcurrentDictionary<string, ImageUsage>();
|
||||
private const int permissibleFactor = 2;
|
||||
|
||||
public void Initialization(Dictionary<string, int> usage)
|
||||
{
|
||||
foreach (var key in usage.Keys)
|
||||
{
|
||||
Data[key] = new ImageUsage(usage[key], null);
|
||||
}
|
||||
}
|
||||
|
||||
public ImageSource this[string path]
|
||||
{
|
||||
get
|
||||
{
|
||||
Usage.AddOrUpdate(path, 1, (k, v) => v + 1);
|
||||
var i = _data[path];
|
||||
return i;
|
||||
}
|
||||
set { _data[path] = value; }
|
||||
}
|
||||
if (Data.TryGetValue(path, out var value))
|
||||
{
|
||||
value.usage++;
|
||||
return value.imageSource;
|
||||
}
|
||||
|
||||
public Dictionary<string, int> CleanupAndToDictionary()
|
||||
=> Usage
|
||||
.OrderByDescending(o => o.Value)
|
||||
.Take(MaxCached)
|
||||
.ToDictionary(i => i.Key, i => i.Value);
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
Data.AddOrUpdate(
|
||||
path,
|
||||
new ImageUsage(0, value),
|
||||
(k, v) =>
|
||||
{
|
||||
v.imageSource = value;
|
||||
v.usage++;
|
||||
return v;
|
||||
}
|
||||
);
|
||||
|
||||
// To prevent the dictionary from drastically increasing in size by caching images, the dictionary size is not allowed to grow more than the permissibleFactor * maxCached size
|
||||
// This is done so that we don't constantly perform this resizing operation and also maintain the image cache size at the same time
|
||||
if (Data.Count > permissibleFactor * MaxCached)
|
||||
{
|
||||
// To delete the images from the data dictionary based on the resizing of the Usage Dictionary.
|
||||
foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key))
|
||||
Data.TryRemove(key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
var contains = _data.ContainsKey(key);
|
||||
var contains = Data.ContainsKey(key) && Data[key] != null;
|
||||
return contains;
|
||||
}
|
||||
|
||||
public int CacheSize()
|
||||
{
|
||||
return _data.Count;
|
||||
return Data.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -47,8 +87,7 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
/// </summary>
|
||||
public int UniqueImagesInCache()
|
||||
{
|
||||
return _data.Values.Distinct().Count();
|
||||
return Data.Values.Select(x => x.imageSource).Distinct().Count();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -13,12 +13,13 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
{
|
||||
public static class ImageLoader
|
||||
{
|
||||
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 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 bool EnableImageHash = true;
|
||||
public static ImageSource DefaultImage { get; } = new BitmapImage(new Uri(Constant.MissingImgIcon));
|
||||
|
||||
|
||||
private static readonly string[] ImageExtensions =
|
||||
{
|
||||
|
|
@ -36,25 +37,25 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
_storage = new BinaryStorage<Dictionary<string, int>>("Image");
|
||||
_hashGenerator = new ImageHashGenerator();
|
||||
|
||||
_imageCache.Usage = LoadStorageToConcurrentDictionary();
|
||||
var usage = LoadStorageToConcurrentDictionary();
|
||||
|
||||
foreach (var icon in new[] { Constant.DefaultIcon, Constant.ErrorIcon })
|
||||
foreach (var icon in new[] { Constant.DefaultIcon, Constant.MissingImgIcon })
|
||||
{
|
||||
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.Data.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.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -62,13 +63,13 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
{
|
||||
lock (_storage)
|
||||
{
|
||||
_storage.Save(_imageCache.CleanupAndToDictionary());
|
||||
_storage.Save(ImageCache.Data.Select(x => (x.Key, x.Value.usage)).ToDictionary(x => x.Key, x => x.usage));
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentDictionary<string, int> LoadStorageToConcurrentDictionary()
|
||||
{
|
||||
lock(_storage)
|
||||
lock (_storage)
|
||||
{
|
||||
var loaded = _storage.TryLoad(new Dictionary<string, int>());
|
||||
|
||||
|
|
@ -106,11 +107,11 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
{
|
||||
if (string.IsNullOrEmpty(path))
|
||||
{
|
||||
return new ImageResult(_imageCache[Constant.ErrorIcon], ImageType.Error);
|
||||
return new ImageResult(ImageCache[Constant.MissingImgIcon], 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))
|
||||
|
|
@ -139,8 +140,8 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
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;
|
||||
ImageSource image = ImageCache[Constant.MissingImgIcon];
|
||||
ImageCache[path] = image;
|
||||
imageResult = new ImageResult(image, ImageType.Error);
|
||||
}
|
||||
}
|
||||
|
|
@ -191,8 +192,8 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
}
|
||||
else
|
||||
{
|
||||
image = _imageCache[Constant.ErrorIcon];
|
||||
path = Constant.ErrorIcon;
|
||||
image = ImageCache[Constant.MissingImgIcon];
|
||||
path = Constant.MissingImgIcon;
|
||||
}
|
||||
|
||||
if (type != ImageType.Error)
|
||||
|
|
@ -212,33 +213,37 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
option);
|
||||
}
|
||||
|
||||
public static bool CacheContainImage(string path)
|
||||
{
|
||||
return ImageCache.ContainsKey(path) && ImageCache[path] != null;
|
||||
}
|
||||
|
||||
public static ImageSource Load(string path, bool loadFullImage = false)
|
||||
{
|
||||
var imageResult = LoadInternal(path, loadFullImage);
|
||||
|
||||
var img = imageResult.ImageSource;
|
||||
if (imageResult.ImageType != ImageType.Error && imageResult.ImageType != ImageType.Cache)
|
||||
{
|
||||
// we need to get image hash
|
||||
string hash = _enableHashImage ? _hashGenerator.GetHashFromImage(img) : null;
|
||||
{ // we need to get image hash
|
||||
string hash = EnableImageHash ? _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] ?? img;
|
||||
}
|
||||
else
|
||||
{
|
||||
// new guid
|
||||
_guidToKey[hash] = path;
|
||||
{ // new guid
|
||||
GuidToKey[hash] = path;
|
||||
}
|
||||
}
|
||||
|
||||
// update cache
|
||||
_imageCache[path] = img;
|
||||
ImageCache[path] = img;
|
||||
}
|
||||
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
|
|
|
|||
85
Flow.Launcher.Infrastructure/PinyinAlphabet.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using ToolGood.Words.Pinyin;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure
|
||||
{
|
||||
public interface IAlphabet
|
||||
{
|
||||
string Translate(string stringToTranslate);
|
||||
}
|
||||
|
||||
public class PinyinAlphabet : IAlphabet
|
||||
{
|
||||
private ConcurrentDictionary<string, string> _pinyinCache = new ConcurrentDictionary<string, string>();
|
||||
private Settings _settings;
|
||||
|
||||
public void Initialize([NotNull] Settings settings)
|
||||
{
|
||||
_settings = settings ?? throw new ArgumentNullException(nameof(settings));
|
||||
}
|
||||
|
||||
public string Translate(string content)
|
||||
{
|
||||
if (_settings.ShouldUsePinyin)
|
||||
{
|
||||
if (!_pinyinCache.ContainsKey(content))
|
||||
{
|
||||
if (WordsHelper.HasChinese(content))
|
||||
{
|
||||
var resultList = WordsHelper.GetPinyinList(content);
|
||||
|
||||
StringBuilder resultBuilder = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < resultList.Length; i++)
|
||||
{
|
||||
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
|
||||
resultBuilder.Append(resultList[i].First());
|
||||
}
|
||||
|
||||
resultBuilder.Append(' ');
|
||||
|
||||
bool pre = false;
|
||||
|
||||
for (int i = 0; i < resultList.Length; i++)
|
||||
{
|
||||
if (content[i] >= 0x3400 && content[i] <= 0x9FD5)
|
||||
{
|
||||
resultBuilder.Append(' ');
|
||||
resultBuilder.Append(resultList[i]);
|
||||
pre = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pre)
|
||||
{
|
||||
pre = false;
|
||||
resultBuilder.Append(' ');
|
||||
}
|
||||
resultBuilder.Append(resultList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return _pinyinCache[content] = resultBuilder.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
return content;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _pinyinCache[content];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,10 +9,18 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
{
|
||||
public class Settings : BaseModel
|
||||
{
|
||||
private string language = "en";
|
||||
|
||||
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 Language
|
||||
{
|
||||
get => language; set {
|
||||
language = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
public string Theme { get; set; } = Constant.DefaultTheme;
|
||||
public bool UseDropShadowEffect { get; set; } = false;
|
||||
public string QueryBoxFont { get; set; } = FontFamily.GenericSansSerif.Name;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.2.0</Version>
|
||||
<PackageVersion>1.2.0</PackageVersion>
|
||||
<AssemblyVersion>1.2.0</AssemblyVersion>
|
||||
<FileVersion>1.2.0</FileVersion>
|
||||
<Version>1.3.1</Version>
|
||||
<PackageVersion>1.3.1</PackageVersion>
|
||||
<AssemblyVersion>1.3.1</AssemblyVersion>
|
||||
<FileVersion>1.3.1</FileVersion>
|
||||
<PackageId>Flow.Launcher.Plugin</PackageId>
|
||||
<Authors>Flow-Launcher</Authors>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
|
@ -60,12 +60,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
|
||||
<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.5.13" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -63,12 +63,6 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
void OpenSettingDialog();
|
||||
|
||||
/// <summary>
|
||||
/// Install Flow Launcher plugin
|
||||
/// </summary>
|
||||
/// <param name="path">Plugin path (ends with .flowlauncher)</param>
|
||||
void InstallPlugin(string path);
|
||||
|
||||
/// <summary>
|
||||
/// Get translation of current language
|
||||
/// You need to implement IPluginI18n if you want to support multiple languages for your plugin
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
/// </summary>
|
||||
/// <param name="sourcePath"></param>
|
||||
/// <param name="targetPath"></param>
|
||||
public static void Copy(this string sourcePath, string targetPath)
|
||||
public static void CopyAll(this string sourcePath, string targetPath)
|
||||
{
|
||||
// Get the subdirectories for the specified directory.
|
||||
DirectoryInfo dir = new DirectoryInfo(sourcePath);
|
||||
|
|
@ -50,7 +50,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
foreach (DirectoryInfo subdir in dirs)
|
||||
{
|
||||
string temppath = Path.Combine(targetPath, subdir.Name);
|
||||
Copy(subdir.FullName, temppath);
|
||||
CopyAll(subdir.FullName, temppath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -114,7 +114,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
return Directory.Exists(path);
|
||||
}
|
||||
|
||||
public static bool FileExits(this string filePath)
|
||||
public static bool FileExists(this string filePath)
|
||||
{
|
||||
return File.Exists(filePath);
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
var psi = new ProcessStartInfo { FileName = FileExplorerProgramName, UseShellExecute = true, Arguments = fileOrFolderPath };
|
||||
try
|
||||
{
|
||||
if (LocationExists(fileOrFolderPath) || FileExits(fileOrFolderPath))
|
||||
if (LocationExists(fileOrFolderPath) || FileExists(fileOrFolderPath))
|
||||
Process.Start(psi);
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
|
@ -7,12 +8,37 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
{
|
||||
public static class SearchWeb
|
||||
{
|
||||
private static string GetDefaultBrowserPath()
|
||||
{
|
||||
string name = string.Empty;
|
||||
try
|
||||
{
|
||||
using var regDefault = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice", false);
|
||||
var stringDefault = regDefault.GetValue("ProgId");
|
||||
|
||||
using var regKey = Registry.ClassesRoot.OpenSubKey(stringDefault + "\\shell\\open\\command", false);
|
||||
name = regKey.GetValue(null).ToString().ToLower().Replace("\"", "");
|
||||
|
||||
if (!name.EndsWith("exe"))
|
||||
name = name.Substring(0, name.LastIndexOf(".exe") + 4);
|
||||
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens search in a new browser. If no browser path is passed in then Chrome is used.
|
||||
/// Leave browser path blank to use Chrome.
|
||||
/// </summary>
|
||||
public static void NewBrowserWindow(this string url, string browserPath = "")
|
||||
{
|
||||
browserPath = string.IsNullOrEmpty(browserPath) ? GetDefaultBrowserPath() : browserPath;
|
||||
|
||||
var browserExecutableName = browserPath?
|
||||
.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.None)
|
||||
.Last();
|
||||
|
|
@ -44,7 +70,9 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
/// </summary>
|
||||
public static void NewTabInBrowser(this string url, string browserPath = "")
|
||||
{
|
||||
var psi = new ProcessStartInfo() { UseShellExecute = true};
|
||||
browserPath = string.IsNullOrEmpty(browserPath) ? GetDefaultBrowserPath() : browserPath;
|
||||
|
||||
var psi = new ProcessStartInfo() { UseShellExecute = true };
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrEmpty(browserPath))
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc
|
|||
ProjectSection(ProjectDependencies) = postProject
|
||||
{1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {1EE20B48-82FB-48A2-8086-675D6DDAB4F0}
|
||||
{0B9DE348-9361-4940-ADB6-F5953BFFCCEC} = {0B9DE348-9361-4940-ADB6-F5953BFFCCEC}
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217} = {4792A74A-0CEA-4173-A8B2-30E6764C6217}
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {FDB3555B-58EF-4AE6-B5F1-904719637AB4}
|
||||
{F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}
|
||||
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {59BD9891-3837-438A-958D-ADC7F91F6F7E}
|
||||
|
|
@ -23,15 +24,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher", "Flow.Launc
|
|||
{9B130CC5-14FB-41FF-B310-0A95B6894C37} = {9B130CC5-14FB-41FF-B310-0A95B6894C37}
|
||||
{FDED22C8-B637-42E8-824A-63B5B6E05A3A} = {FDED22C8-B637-42E8-824A-63B5B6E05A3A}
|
||||
{A3DCCBCA-ACC1-421D-B16E-210896234C26} = {A3DCCBCA-ACC1-421D-B16E-210896234C26}
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE} = {049490F0-ECD2-4148-9B39-2135EC346EBE}
|
||||
{403B57F2-1856-4FC7-8A24-36AB346B763E} = {403B57F2-1856-4FC7-8A24-36AB346B763E}
|
||||
{588088F4-3262-4F9F-9663-A05DE12534C3} = {588088F4-3262-4F9F-9663-A05DE12534C3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Infrastructure", "Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj", "{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.PluginManagement", "Plugins\Flow.Launcher.Plugin.PluginManagement\Flow.Launcher.Plugin.PluginManagement.csproj", "{049490F0-ECD2-4148-9B39-2135EC346EBE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Core", "Flow.Launcher.Core\Flow.Launcher.Core.csproj", "{B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Program", "Plugins\Flow.Launcher.Plugin.Program\Flow.Launcher.Plugin.Program.csproj", "{FDB3555B-58EF-4AE6-B5F1-904719637AB4}"
|
||||
|
|
@ -53,6 +51,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
.gitattributes = .gitattributes
|
||||
.gitignore = .gitignore
|
||||
appveyor.yml = appveyor.yml
|
||||
Directory.Build.targets = Directory.Build.targets
|
||||
Scripts\flowlauncher.nuspec = Scripts\flowlauncher.nuspec
|
||||
LICENSE = LICENSE
|
||||
Scripts\post_build.ps1 = Scripts\post_build.ps1
|
||||
|
|
@ -70,6 +69,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Explor
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.ProcessKiller", "Plugins\Flow.Launcher.Plugin.ProcessKiller\Flow.Launcher.Plugin.ProcessKiller.csproj", "{588088F4-3262-4F9F-9663-A05DE12534C3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.PluginsManager", "Plugins\Flow.Launcher.Plugin.PluginsManager\Flow.Launcher.Plugin.PluginsManager.csproj", "{4792A74A-0CEA-4173-A8B2-30E6764C6217}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -128,18 +129,6 @@ Global
|
|||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4FD29318-A8AB-4D8F-AA47-60BC241B8DA3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x64.Build.0 = Release|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE}.Release|x86.Build.0 = Release|Any CPU
|
||||
{B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B749F0DB-8E75-47DB-9E5E-265D16D0C0D2}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
|
|
@ -297,12 +286,23 @@ Global
|
|||
{588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x64.Build.0 = Release|Any CPU
|
||||
{588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.Build.0 = Release|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x64.Build.0 = Release|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{049490F0-ECD2-4148-9B39-2135EC346EBE} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
{FDB3555B-58EF-4AE6-B5F1-904719637AB4} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
{403B57F2-1856-4FC7-8A24-36AB346B763E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
{1EE20B48-82FB-48A2-8086-675D6DDAB4F0} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
|
|
@ -315,6 +315,7 @@ Global
|
|||
{59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
{F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
{588088F4-3262-4F9F-9663-A05DE12534C3} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
{4792A74A-0CEA-4173-A8B2-30E6764C6217} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows;
|
||||
|
|
@ -28,7 +29,7 @@ namespace Flow.Launcher
|
|||
private SettingWindowViewModel _settingsVM;
|
||||
private readonly Updater _updater = new Updater(Flow.Launcher.Properties.Settings.Default.GithubRepo);
|
||||
private readonly Portable _portable = new Portable();
|
||||
private readonly Alphabet _alphabet = new Alphabet();
|
||||
private readonly PinyinAlphabet _alphabet = new PinyinAlphabet();
|
||||
private StringMatcher _stringMatcher;
|
||||
|
||||
[STAThread]
|
||||
|
|
@ -85,6 +86,8 @@ namespace Flow.Launcher
|
|||
|
||||
Http.Proxy = _settings.Proxy;
|
||||
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
|
||||
RegisterExitEvents();
|
||||
|
||||
AutoStartup();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
|
|
@ -72,23 +72,13 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="InputSimulator" Version="1.0.4" />
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="Mages" Version="1.6.0" />
|
||||
<PackageReference Include="ModernWpfUI" Version="0.8.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="NHotkey.Wpf" Version="1.2.1" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.9.0" />
|
||||
<PackageReference Include="NuGet.CommandLine" Version="5.4.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="2.5.13" />
|
||||
<PackageReference Include="System.Data.OleDb" Version="4.7.1" />
|
||||
<PackageReference Include="System.Data.SQLite" Version="1.0.112" />
|
||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.112" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
<PackageReference Include="tlbimp-Microsoft.Search.Interop" Version="1.0.0" />
|
||||
<PackageReference Include="UnidecodeSharp" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
BIN
Flow.Launcher/Images/app_missing_img.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -1,12 +1,12 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
<!--MainWindow-->
|
||||
<system:String x:Key="registerHotkeyFailed">Nepodarilo sa registrovať klávesovú skratku {0}</system:String>
|
||||
<system:String x:Key="couldnotStartCmd">Nepodarilo sa spustiť {0}</system:String>
|
||||
<system:String x:Key="invalidFlowLauncherPluginFileFormat">Neplatný formát súboru pre plugin Flow Launcher</system:String>
|
||||
<system:String x:Key="setAsTopMostInThisQuery">Pri tomto dopyte umiestniť navrchu</system:String>
|
||||
<system:String x:Key="cancelTopMostInThisQuery">Zrušiť umiestnenie navrchu pri tomto dopyte</system:String>
|
||||
<system:String x:Key="invalidFlowLauncherPluginFileFormat">Neplatný formát súboru pre plugin Flow Launchera</system:String>
|
||||
<system:String x:Key="setAsTopMostInThisQuery">Pri tomto zadaní umiestniť navrchu</system:String>
|
||||
<system:String x:Key="cancelTopMostInThisQuery">Zrušiť umiestnenie navrchu pri tomto zadaní</system:String>
|
||||
<system:String x:Key="executeQuery">Spustiť dopyt: {0}</system:String>
|
||||
<system:String x:Key="lastExecuteTime">Posledný čas realizácie: {0}</system:String>
|
||||
<system:String x:Key="iconTrayOpen">Otvoriť</system:String>
|
||||
|
|
@ -15,61 +15,71 @@
|
|||
<system:String x:Key="iconTrayExit">Ukončiť</system:String>
|
||||
|
||||
<!--Setting General-->
|
||||
<system:String x:Key="flowlauncher_settings">Nastavenia Flow Launcher</system:String>
|
||||
<system:String x:Key="flowlauncher_settings">Nastavenia Flow Launchera</system:String>
|
||||
<system:String x:Key="general">Všeobecné</system:String>
|
||||
<system:String x:Key="startFlowLauncherOnSystemStartup">Spustiť Flow Launcher po štarte systému</system:String>
|
||||
<system:String x:Key="hideFlowLauncherWhenLoseFocus">Schovať Flow Launcher po strate fokusu</system:String>
|
||||
<system:String x:Key="dontPromptUpdateMsg">Nezobrazovať upozornenia na novú verziu</system:String>
|
||||
<system:String x:Key="rememberLastLocation">Zapamätať si posledné umiestnenie</system:String>
|
||||
<system:String x:Key="language">Jazyk</system:String>
|
||||
<system:String x:Key="lastQueryMode">Posledný dopyt</system:String>
|
||||
<system:String x:Key="lastQueryMode">Posledné vyhľadávanie</system:String>
|
||||
<system:String x:Key="LastQueryPreserved">Ponechať</system:String>
|
||||
<system:String x:Key="LastQuerySelected">Označiť posledný dopyt</system:String>
|
||||
<system:String x:Key="LastQueryEmpty">Prázdne</system:String>
|
||||
<system:String x:Key="LastQuerySelected">Označiť</system:String>
|
||||
<system:String x:Key="LastQueryEmpty">Vymazať</system:String>
|
||||
<system:String x:Key="maxShowResults">Max. výsledkov</system:String>
|
||||
<system:String x:Key="ignoreHotkeysOnFullscreen">Ignorovať klávesové skraty v režime na celú obrazovku</system:String>
|
||||
<system:String x:Key="ignoreHotkeysOnFullscreen">Ignorovať klávesové skratky v režime na celú obrazovku</system:String>
|
||||
<system:String x:Key="pythonDirectory">Priečinok s Pythonom</system:String>
|
||||
<system:String x:Key="autoUpdates">Automatická aktualizácia</system:String>
|
||||
<system:String x:Key="selectPythonDirectory">Vybrať</system:String>
|
||||
<system:String x:Key="hideOnStartup">Schovať Flow Launcher po spustení</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Schovať ikonu v oblasti oznámení</system:String>
|
||||
<system:String x:Key="hideNotifyIcon">Schovať ikonu z oblasti oznámení</system:String>
|
||||
<system:String x:Key="querySearchPrecision">Presnosť vyhľadávania</system:String>
|
||||
<system:String x:Key="ShouldUsePinyin">Použiť Pinyin</system:String>
|
||||
|
||||
<!--Setting Plugin-->
|
||||
<system:String x:Key="plugin">Plugin</system:String>
|
||||
<system:String x:Key="browserMorePlugins">Nájsť ďalšie pluginy</system:String>
|
||||
<system:String x:Key="disable">Zakázať</system:String>
|
||||
<system:String x:Key="actionKeywords">Skratka akcie</system:String>
|
||||
<system:String x:Key="pluginDirectory">Priečinok s pluginmy</system:String>
|
||||
<system:String x:Key="currentActionKeywords">Aktuálna akcia skratky:</system:String>
|
||||
<system:String x:Key="newActionKeyword">Nová akcia skratky:</system:String>
|
||||
<system:String x:Key="pluginDirectory">Priečinok s pluginmi</system:String>
|
||||
<system:String x:Key="author">Autor</system:String>
|
||||
<system:String x:Key="plugin_init_time">Čas inic.:</system:String>
|
||||
<system:String x:Key="plugin_query_time">Čas dopytu:</system:String>
|
||||
<system:String x:Key="plugin_init_time">Príprava: {0}ms</system:String>
|
||||
<system:String x:Key="plugin_query_time">Čas dopytu: {0}ms</system:String>
|
||||
|
||||
<!--Setting Theme-->
|
||||
<system:String x:Key="theme">Motív</system:String>
|
||||
<system:String x:Key="browserMoreThemes">Prehliadať viac motívov</system:String>
|
||||
<system:String x:Key="queryBoxFont">Písmo poľa pre dopyt</system:String>
|
||||
<system:String x:Key="hiThere">Ahojte</system:String>
|
||||
<system:String x:Key="queryBoxFont">Písmo vyhľadávacieho poľa</system:String>
|
||||
<system:String x:Key="resultItemFont">Písmo výsledkov</system:String>
|
||||
<system:String x:Key="windowMode">Režim okno</system:String>
|
||||
<system:String x:Key="opacity">Nepriehľadnosť</system:String>
|
||||
<system:String x:Key="theme_load_failure_path_not_exists">Motív {0} neexistuje, návrat na predvolený motív</system:String>
|
||||
<system:String x:Key="theme_load_failure_parse_error">Nepodarilo sa nečítať motív {0}, návrat na predvolený motív</system:String>
|
||||
|
||||
<!--Setting Hotkey-->
|
||||
<system:String x:Key="hotkey">Klávesová skratka</system:String>
|
||||
<system:String x:Key="hotkey">Klávesové skratky</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="openResultModifiers">Modifikáčné klávesy na otvorenie výsledkov</system:String>
|
||||
<system:String x:Key="showOpenResultHotkey">Zobraziť klávesovú skratku</system:String>
|
||||
<system:String x:Key="customQueryHotkey">Vlastná klávesová skratka na vyhľadávanie</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>
|
||||
<system:String x:Key="pleaseSelectAnItem">Vyberte položku, prosím</system:String>
|
||||
<system:String x:Key="deleteCustomHotkeyWarning">Ste si istý, že chcete odstrániť klávesovú skratku {0} pre plugin?</system:String>
|
||||
<system:String x:Key="queryWindowShadowEffect">Tieňový efekt v poli vyhľadávania</system:String>
|
||||
<system:String x:Key="shadowEffectCPUUsage">Tieňový efekt významne využíva GPU.</system:String>
|
||||
<system:String x:Key="shadowEffectPerformance">Neodporúča sa, ak je výkon počítača obmedzený.</system:String>
|
||||
|
||||
<!--Setting Proxy-->
|
||||
<system:String x:Key="proxy">HTTP Proxy</system:String>
|
||||
<system:String x:Key="enableProxy">Povoliť HTTP Proxy</system:String>
|
||||
<system:String x:Key="server">HTTP Server</system:String>
|
||||
<system:String x:Key="port">Port</system:String>
|
||||
<system:String x:Key="userName">Používateľské meno</system:String>
|
||||
<system:String x:Key="userName">Použív. meno</system:String>
|
||||
<system:String x:Key="password">Heslo</system:String>
|
||||
<system:String x:Key="testProxy">Test Proxy</system:String>
|
||||
<system:String x:Key="save">Uložiť</system:String>
|
||||
|
|
@ -86,13 +96,13 @@
|
|||
<system:String x:Key="version">Verzia</system:String>
|
||||
<system:String x:Key="about_activate_times">Flow Launcher bol aktivovaný {0}-krát</system:String>
|
||||
<system:String x:Key="checkUpdates">Skontrolovať aktualizácie</system:String>
|
||||
<system:String x:Key="newVersionTips">Je dostupná nová verzia {0}, prosím, reštartujte Flow Launcher.</system:String>
|
||||
<system:String x:Key="newVersionTips">Je dostupná nová verzia {0}, chcete reštartovať Flow Launcher, aby sa mohol aktualizovať?</system:String>
|
||||
<system:String x:Key="checkUpdatesFailed">Kontrola aktualizácií zlyhala, prosím, skontrolujte pripojenie na internet a nastavenie proxy k api.github.com.</system:String>
|
||||
<system:String x:Key="downloadUpdatesFailed">
|
||||
Sťahovanie aktualizácií zlyhalo, skontrolujte pripojenie na internet a nastavenie proxy k github-cloud.s3.amazonaws.com,
|
||||
alebo prejdite na https://github.com/Flow-Launcher/Flow.Launcher/releases pre manuálne stiahnutie aktualizácií.
|
||||
alebo prejdite na https://github.com/Flow-Launcher/Flow.Launcher/releases pre manuálne stiahnutie aktualizácie.
|
||||
</system:String>
|
||||
<system:String x:Key="releaseNotes">Poznámky k vydaniu:</system:String>
|
||||
<system:String x:Key="releaseNotes">Poznámky k vydaniu</system:String>
|
||||
|
||||
<!--Action Keyword Setting Dialog-->
|
||||
<system:String x:Key="oldActionKeywords">Stará skratka akcie</system:String>
|
||||
|
|
@ -131,7 +141,7 @@
|
|||
<system:String x:Key="reportWindow_flowlauncher_got_an_error">Flow Launcher zaznamenal chybu</system:String>
|
||||
|
||||
<!--update-->
|
||||
<system:String x:Key="update_flowlauncher_update_new_version_available">Je dostupné nové vydanie Flow Launcher {0}</system:String>
|
||||
<system:String x:Key="update_flowlauncher_update_new_version_available">Je dostupná nová verzia Flow Launcher {0}</system:String>
|
||||
<system:String x:Key="update_flowlauncher_update_error">Počas inštalácie aktualizácií došlo k chybe</system:String>
|
||||
<system:String x:Key="update_flowlauncher_update">Aktualizovať</system:String>
|
||||
<system:String x:Key="update_flowlauncher_update_cancel">Zrušiť</system:String>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
Loaded="OnLoaded"
|
||||
Initialized="OnInitialized"
|
||||
Closing="OnClosing"
|
||||
Drop="OnDrop"
|
||||
LocationChanged="OnLocationChanged"
|
||||
Deactivated="OnDeactivated"
|
||||
PreviewKeyDown="OnKeyDown"
|
||||
|
|
|
|||
|
|
@ -52,12 +52,14 @@ namespace Flow.Launcher
|
|||
|
||||
private void OnInitialized(object sender, EventArgs e)
|
||||
{
|
||||
// show notify icon when flowlauncher is hided
|
||||
InitializeNotifyIcon();
|
||||
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs _)
|
||||
{
|
||||
// show notify icon when flowlauncher is hidden
|
||||
InitializeNotifyIcon();
|
||||
|
||||
// todo is there a way to set blur only once?
|
||||
ThemeManager.Instance.SetBlurForWindow();
|
||||
WindowsInteropHelper.DisableControlBox(this);
|
||||
|
|
@ -87,11 +89,17 @@ namespace Flow.Launcher
|
|||
};
|
||||
_settings.PropertyChanged += (o, e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(Settings.HideNotifyIcon))
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
_notifyIcon.Visible = !_settings.HideNotifyIcon;
|
||||
case nameof(Settings.HideNotifyIcon):
|
||||
_notifyIcon.Visible = !_settings.HideNotifyIcon;
|
||||
break;
|
||||
case nameof(Settings.Language):
|
||||
UpdateNotifyIconText();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
InitializePosition();
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +111,18 @@ namespace Flow.Launcher
|
|||
_settings.WindowLeft = Left;
|
||||
}
|
||||
|
||||
private void UpdateNotifyIconText()
|
||||
{
|
||||
var menu = _notifyIcon.ContextMenuStrip;
|
||||
var open = menu.Items[0];
|
||||
var setting = menu.Items[1];
|
||||
var exit = menu.Items[2];
|
||||
|
||||
open.Text = InternationalizationManager.Instance.GetTranslation("iconTrayOpen");
|
||||
setting.Text = InternationalizationManager.Instance.GetTranslation("iconTraySettings");
|
||||
exit.Text = InternationalizationManager.Instance.GetTranslation("iconTrayExit");
|
||||
}
|
||||
|
||||
private void InitializeNotifyIcon()
|
||||
{
|
||||
_notifyIcon = new NotifyIcon
|
||||
|
|
@ -179,25 +199,6 @@ namespace Flow.Launcher
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnDrop(object sender, DragEventArgs e)
|
||||
{
|
||||
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
||||
{
|
||||
// Note that you can have more than one file.
|
||||
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
||||
if (files[0].ToLower().EndsWith(".flowlauncher"))
|
||||
{
|
||||
PluginManager.InstallPlugin(files[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show(InternationalizationManager.Instance.GetTranslation("invalidFlowLauncherPluginFileFormat"));
|
||||
}
|
||||
}
|
||||
e.Handled = false;
|
||||
}
|
||||
|
||||
private void OnPreviewDragOver(object sender, DragEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
|
|
@ -294,7 +295,5 @@ namespace Flow.Launcher
|
|||
_viewModel.QueryTextCursorMovedToEnd = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -21,11 +21,11 @@ namespace Flow.Launcher
|
|||
{
|
||||
private readonly SettingWindowViewModel _settingsVM;
|
||||
private readonly MainViewModel _mainVM;
|
||||
private readonly Alphabet _alphabet;
|
||||
private readonly PinyinAlphabet _alphabet;
|
||||
|
||||
#region Constructor
|
||||
|
||||
public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, Alphabet alphabet)
|
||||
public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, PinyinAlphabet alphabet)
|
||||
{
|
||||
_settingsVM = settingsVM;
|
||||
_mainVM = mainVM;
|
||||
|
|
@ -76,7 +76,6 @@ namespace Flow.Launcher
|
|||
_settingsVM.Save();
|
||||
PluginManager.Save();
|
||||
ImageLoader.Save();
|
||||
_alphabet.Save();
|
||||
}
|
||||
|
||||
public void ReloadAllPluginData()
|
||||
|
|
@ -116,11 +115,6 @@ namespace Flow.Launcher
|
|||
_mainVM.ProgressBarVisibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public void InstallPlugin(string path)
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() => PluginManager.InstallPlugin(path));
|
||||
}
|
||||
|
||||
public string GetTranslation(string key)
|
||||
{
|
||||
return InternationalizationManager.Instance.GetTranslation(key);
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ namespace Flow.Launcher
|
|||
var link = new Hyperlink { IsEnabled = true };
|
||||
link.Inlines.Add(url);
|
||||
link.NavigateUri = new Uri(url);
|
||||
link.RequestNavigate += (s, e) => SearchWeb.NewBrowserWindow(e.Uri.ToString());
|
||||
link.Click += (s, e) => SearchWeb.NewBrowserWindow(url);
|
||||
link.RequestNavigate += (s, e) => SearchWeb.NewTabInBrowser(e.Uri.ToString());
|
||||
link.Click += (s, e) => SearchWeb.NewTabInBrowser(url);
|
||||
|
||||
paragraph.Inlines.Add(textBeforeUrl);
|
||||
paragraph.Inlines.Add(link);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
<ColumnDefinition Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="ImageIcon" Width="32" Height="32" HorizontalAlignment="Left"
|
||||
Source="{Binding Image ,IsAsync=True}" />
|
||||
Source="{Binding Image.Value}" />
|
||||
<Grid Margin="5 0 5 0" Grid.Column="1" HorizontalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@
|
|||
<TextBlock Text="{Binding PluginPair.Metadata.Description}"
|
||||
Grid.Row="1" Opacity="0.5" />
|
||||
<DockPanel Grid.Row="2" Margin="0 10 0 8" HorizontalAlignment="Right">
|
||||
|
||||
|
||||
<TextBlock Text="{DynamicResource actionKeywords}"
|
||||
Visibility="{Binding ActionKeywordsVisibility}"
|
||||
Margin="20 0 0 0"/>
|
||||
|
|
@ -211,10 +211,10 @@
|
|||
<Run Text="{DynamicResource browserMoreThemes}" />
|
||||
</Hyperlink>
|
||||
</TextBlock>
|
||||
<Button DockPanel.Dock="Top" Margin="0,10,0,0" Width="180" HorizontalAlignment="Center" Click="OpenPluginFolder">Open Theme Folder</Button>
|
||||
<ListBox DockPanel.Dock="Top" SelectedItem="{Binding SelectedTheme}" ItemsSource="{Binding Themes}"
|
||||
Margin="10, 0, 10, 10" Width="180" Height="394" />
|
||||
|
||||
<ListBox SelectedItem="{Binding SelectedTheme}" ItemsSource="{Binding Themes}"
|
||||
Margin="10, 0, 10, 10" Width="180"
|
||||
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
|
||||
</DockPanel>
|
||||
<Grid Margin="0" Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using NHotkey;
|
|||
using NHotkey.Wpf;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Core.Resource;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Hotkey;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
|
@ -228,7 +229,7 @@ namespace Flow.Launcher
|
|||
var uri = new Uri(website);
|
||||
if (Uri.CheckSchemeName(uri.Scheme))
|
||||
{
|
||||
SearchWeb.NewBrowserWindow(website);
|
||||
SearchWeb.NewTabInBrowser(website);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -262,7 +263,7 @@ namespace Flow.Launcher
|
|||
|
||||
private void OnRequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||
{
|
||||
SearchWeb.NewBrowserWindow(e.Uri.AbsoluteUri);
|
||||
SearchWeb.NewTabInBrowser(e.Uri.AbsoluteUri);
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
|
|
@ -275,5 +276,10 @@ namespace Flow.Launcher
|
|||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void OpenPluginFolder(object sender, RoutedEventArgs e)
|
||||
{
|
||||
FilesFolders.OpenPath(Path.Combine(DataLocation.DataDirectory(), Constant.Themes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
StartHelpCommand = new RelayCommand(_ =>
|
||||
{
|
||||
SearchWeb.NewBrowserWindow("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/");
|
||||
SearchWeb.NewTabInBrowser("https://github.com/Flow-Launcher/Flow.Launcher/wiki/Flow-Launcher/");
|
||||
});
|
||||
|
||||
OpenResultCommand = new RelayCommand(index =>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,66 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
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;
|
||||
|
||||
|
||||
namespace Flow.Launcher.ViewModel
|
||||
{
|
||||
public class ResultViewModel : BaseModel
|
||||
{
|
||||
public class LazyAsync<T> : Lazy<Task<T>>
|
||||
{
|
||||
private T defaultValue;
|
||||
|
||||
private readonly Action _updateCallback;
|
||||
public new T Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValueCreated)
|
||||
{
|
||||
base.Value.ContinueWith(_ =>
|
||||
{
|
||||
_updateCallback();
|
||||
});
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (!base.Value.IsCompleted || base.Value.IsFaulted)
|
||||
return defaultValue;
|
||||
|
||||
return base.Value.Result;
|
||||
}
|
||||
}
|
||||
public LazyAsync(Func<Task<T>> factory, T defaultValue, Action updateCallback) : base(factory)
|
||||
{
|
||||
if (defaultValue != null)
|
||||
{
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
_updateCallback = updateCallback;
|
||||
}
|
||||
}
|
||||
|
||||
public ResultViewModel(Result result, Settings settings)
|
||||
{
|
||||
if (result != null)
|
||||
{
|
||||
Result = result;
|
||||
|
||||
Image = new LazyAsync<ImageSource>(
|
||||
SetImage,
|
||||
ImageLoader.DefaultImage,
|
||||
() =>
|
||||
{
|
||||
OnPropertyChanged(nameof(Image));
|
||||
});
|
||||
}
|
||||
|
||||
Settings = settings;
|
||||
|
|
@ -25,39 +68,45 @@ namespace Flow.Launcher.ViewModel
|
|||
|
||||
public Settings Settings { get; private set; }
|
||||
|
||||
public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden;
|
||||
public Visibility ShowOpenResultHotkey => Settings.ShowOpenResultHotkey ? Visibility.Visible : Visibility.Hidden;
|
||||
|
||||
public string OpenResultModifiers => Settings.OpenResultModifiers;
|
||||
|
||||
public string ShowTitleToolTip => string.IsNullOrEmpty(Result.TitleToolTip)
|
||||
? Result.Title
|
||||
? Result.Title
|
||||
: Result.TitleToolTip;
|
||||
|
||||
public string ShowSubTitleToolTip => string.IsNullOrEmpty(Result.SubTitleToolTip)
|
||||
? Result.SubTitle
|
||||
? Result.SubTitle
|
||||
: Result.SubTitleToolTip;
|
||||
|
||||
public ImageSource Image
|
||||
public LazyAsync<ImageSource> Image { get; set; }
|
||||
|
||||
private async Task<ImageSource> SetImage()
|
||||
{
|
||||
get
|
||||
var imagePath = Result.IcoPath;
|
||||
if (string.IsNullOrEmpty(imagePath) && Result.Icon != null)
|
||||
{
|
||||
var imagePath = Result.IcoPath;
|
||||
if (string.IsNullOrEmpty(imagePath) && Result.Icon != null)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return Result.Icon();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e);
|
||||
imagePath = Constant.ErrorIcon;
|
||||
}
|
||||
return Result.Icon();
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception($"|ResultViewModel.Image|IcoPath is empty and exception when calling Icon() for result <{Result.Title}> of plugin <{Result.PluginDirectory}>", e);
|
||||
imagePath = Constant.MissingImgIcon;
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageLoader.CacheContainImage(imagePath))
|
||||
{
|
||||
// will get here either when icoPath has value\icon delegate is null\when had exception in delegate
|
||||
return ImageLoader.Load(imagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
return await Task.Run(() => ImageLoader.Load(imagePath));
|
||||
}
|
||||
}
|
||||
|
||||
public Result Result { get; }
|
||||
|
|
@ -84,6 +133,5 @@ namespace Flow.Launcher.ViewModel
|
|||
{
|
||||
return Result.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
115
JsonRPC/wox.py
|
|
@ -1,115 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import print_function
|
||||
import json
|
||||
import sys
|
||||
import inspect
|
||||
|
||||
class FlowLauncher(object):
|
||||
"""
|
||||
Flow.Launcher python plugin base
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
rpc_request = json.loads(sys.argv[1])
|
||||
# proxy is not working now
|
||||
self.proxy = rpc_request.get("proxy",{})
|
||||
request_method_name = rpc_request.get("method")
|
||||
request_parameters = rpc_request.get("parameters")
|
||||
methods = inspect.getmembers(self, predicate=inspect.ismethod)
|
||||
|
||||
request_method = dict(methods)[request_method_name]
|
||||
results = request_method(*request_parameters)
|
||||
|
||||
if request_method_name == "query" or request_method_name == "context_menu":
|
||||
print(json.dumps({"result": results}))
|
||||
|
||||
def query(self,query):
|
||||
"""
|
||||
sub class need to override this method
|
||||
"""
|
||||
return []
|
||||
|
||||
def context_menu(self, data):
|
||||
"""
|
||||
optional context menu entries for a result
|
||||
"""
|
||||
return []
|
||||
|
||||
def debug(self,msg):
|
||||
"""
|
||||
alert msg
|
||||
"""
|
||||
print("DEBUG:{}".format(msg))
|
||||
sys.exit()
|
||||
|
||||
class FlowLauncherAPI(object):
|
||||
|
||||
@classmethod
|
||||
def change_query(cls,query,requery = False):
|
||||
"""
|
||||
change flowlauncher query
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.ChangeQuery","parameters":[query,requery]}))
|
||||
|
||||
@classmethod
|
||||
def shell_run(cls,cmd):
|
||||
"""
|
||||
run shell commands
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.ShellRun","parameters":[cmd]}))
|
||||
|
||||
@classmethod
|
||||
def close_app(cls):
|
||||
"""
|
||||
close flowlauncher
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.CloseApp","parameters":[]}))
|
||||
|
||||
@classmethod
|
||||
def hide_app(cls):
|
||||
"""
|
||||
hide flowlauncher
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.HideApp","parameters":[]}))
|
||||
|
||||
@classmethod
|
||||
def show_app(cls):
|
||||
"""
|
||||
show flowlauncher
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.ShowApp","parameters":[]}))
|
||||
|
||||
@classmethod
|
||||
def show_msg(cls,title,sub_title,ico_path=""):
|
||||
"""
|
||||
show messagebox
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.ShowMsg","parameters":[title,sub_title,ico_path]}))
|
||||
|
||||
@classmethod
|
||||
def open_setting_dialog(cls):
|
||||
"""
|
||||
open setting dialog
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.OpenSettingDialog","parameters":[]}))
|
||||
|
||||
@classmethod
|
||||
def start_loadingbar(cls):
|
||||
"""
|
||||
start loading animation in flowlauncher
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.StartLoadingBar","parameters":[]}))
|
||||
|
||||
@classmethod
|
||||
def stop_loadingbar(cls):
|
||||
"""
|
||||
stop loading animation in flowlauncher
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.StopLoadingBar","parameters":[]}))
|
||||
|
||||
@classmethod
|
||||
def reload_plugins(cls):
|
||||
"""
|
||||
reload all flowlauncher plugins
|
||||
"""
|
||||
print(json.dumps({"method": "Flow.Launcher.ReloadPlugins","parameters":[]}))
|
||||
1
LICENSE
|
|
@ -1,5 +1,6 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 Flow-Launcher
|
||||
Copyright (c) 2015 Wox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
|
|
|
|||
|
|
@ -19,10 +19,8 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
set
|
||||
{
|
||||
m_Name = value;
|
||||
PinyinName = m_Name.Unidecode();
|
||||
}
|
||||
}
|
||||
public string PinyinName { get; private set; }
|
||||
public string Url { get; set; }
|
||||
public string Source { get; set; }
|
||||
public int Score { get; set; }
|
||||
|
|
|
|||
|
|
@ -6,19 +6,19 @@ namespace Flow.Launcher.Plugin.BrowserBookmark.Commands
|
|||
{
|
||||
internal static class Bookmarks
|
||||
{
|
||||
internal static bool MatchProgram(Bookmark bookmark, string queryString)
|
||||
internal static MatchResult MatchProgram(Bookmark bookmark, string queryString)
|
||||
{
|
||||
if (StringMatcher.FuzzySearch(queryString, bookmark.Name).IsSearchPrecisionScoreMet()) return true;
|
||||
if (StringMatcher.FuzzySearch(queryString, bookmark.PinyinName).IsSearchPrecisionScoreMet()) return true;
|
||||
if (StringMatcher.FuzzySearch(queryString, bookmark.Url).IsSearchPrecisionScoreMet()) return true;
|
||||
var match = StringMatcher.FuzzySearch(queryString, bookmark.Name);
|
||||
if (match.IsSearchPrecisionScoreMet())
|
||||
return match;
|
||||
|
||||
return false;
|
||||
return StringMatcher.FuzzySearch(queryString, bookmark.Url);
|
||||
}
|
||||
|
||||
internal static List<Bookmark> LoadAllBookmarks()
|
||||
{
|
||||
var allbookmarks = new List<Bookmark>();
|
||||
|
||||
|
||||
var chromeBookmarks = new ChromeBookmarks();
|
||||
var mozBookmarks = new FirefoxBookmarks();
|
||||
var edgeBookmarks = new EdgeBookmarks();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
return bookmarks;
|
||||
}
|
||||
|
||||
private void ParseEdgeBookmarks(String path, string source)
|
||||
private void ParseEdgeBookmarks(string path, string source)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
|
||||
|
|
@ -72,12 +72,13 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
|
||||
private void LoadEdgeBookmarks()
|
||||
{
|
||||
String platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
string platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge\User Data"), "Microsoft Edge");
|
||||
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge Dev\User Data"), "Microsoft Edge Dev");
|
||||
LoadEdgeBookmarks(Path.Combine(platformPath, @"Microsoft\Edge SxS\User Data"), "Microsoft Edge Canary");
|
||||
}
|
||||
|
||||
private String DecodeUnicode(String dataStr)
|
||||
private string DecodeUnicode(string dataStr)
|
||||
{
|
||||
Regex reg = new Regex(@"(?i)\\[uU]([0-9a-f]{4})");
|
||||
return reg.Replace(dataStr, m => ((char)Convert.ToInt32(m.Groups[1].Value, 16)).ToString());
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectGuid>{9B130CC5-14FB-41FF-B310-0A95B6894C37}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Flow.Launcher.Plugin.BrowserBookmark</RootNamespace>
|
||||
<AssemblyName>Flow.Launcher.Plugin.BrowserBookmark</AssemblyName>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<!--Plugin Info-->
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_plugin_name">Prehliadač záložiek</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_plugin_description">Vyhľadáva záložky prehliadača</system:String>
|
||||
|
||||
<!--Settings-->
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_openBookmarks">Otvoriť záložky v:</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_newWindow">Nové okno</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_newTab">Nová karta</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_setBrowserFromPath">Nastaviť cestu k prehliadaču:</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_browserbookmark_settings_choose">Prehliadať</system:String>
|
||||
</ResourceDictionary>
|
||||
|
|
@ -12,7 +12,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, ISavable
|
||||
{
|
||||
private PluginInitContext context;
|
||||
|
||||
|
||||
private List<Bookmark> cachedBookmarks = new List<Bookmark>();
|
||||
|
||||
private readonly Settings _settings;
|
||||
|
|
@ -37,36 +37,56 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
|
||||
// Should top results be returned? (true if no search parameters have been passed)
|
||||
var topResults = string.IsNullOrEmpty(param);
|
||||
|
||||
var returnList = cachedBookmarks;
|
||||
|
||||
|
||||
if (!topResults)
|
||||
{
|
||||
// Since we mixed chrome and firefox bookmarks, we should order them again
|
||||
returnList = cachedBookmarks.Where(o => Bookmarks.MatchProgram(o, param)).ToList();
|
||||
returnList = returnList.OrderByDescending(o => o.Score).ToList();
|
||||
}
|
||||
|
||||
return returnList.Select(c => new Result()
|
||||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = 5,
|
||||
Action = (e) =>
|
||||
var returnList = cachedBookmarks.Select(c => new Result()
|
||||
{
|
||||
if (_settings.OpenInNewBrowserWindow)
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = Bookmarks.MatchProgram(c, param).Score,
|
||||
Action = _ =>
|
||||
{
|
||||
c.Url.NewBrowserWindow(_settings.BrowserPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.Url.NewTabInBrowser(_settings.BrowserPath);
|
||||
}
|
||||
if (_settings.OpenInNewBrowserWindow)
|
||||
{
|
||||
c.Url.NewBrowserWindow(_settings.BrowserPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.Url.NewTabInBrowser(_settings.BrowserPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}).ToList();
|
||||
return true;
|
||||
}
|
||||
}).Where(r => r.Score > 0);
|
||||
return returnList.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return cachedBookmarks.Select(c => new Result()
|
||||
{
|
||||
Title = c.Name,
|
||||
SubTitle = c.Url,
|
||||
IcoPath = @"Images\bookmark.png",
|
||||
Score = 5,
|
||||
Action = _ =>
|
||||
{
|
||||
if (_settings.OpenInNewBrowserWindow)
|
||||
{
|
||||
c.Url.NewBrowserWindow(_settings.BrowserPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
c.Url.NewTabInBrowser(_settings.BrowserPath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReloadData()
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
"Name": "Browser Bookmarks",
|
||||
"Description": "Search your browser bookmarks",
|
||||
"Author": "qianlifeng, Ioannis G.",
|
||||
"Version": "1.2.0",
|
||||
"Version": "1.3.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.browserBookmark.dll",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
|
||||
"IcoPath": "Images\\bookmark.png"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectGuid>{59BD9891-3837-438A-958D-ADC7F91F6F7E}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Flow.Launcher.Plugin.Caculator</RootNamespace>
|
||||
<AssemblyName>Flow.Launcher.Plugin.Caculator</AssemblyName>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWPF>true</UseWPF>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
|
@ -102,9 +104,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="Mages" Version="1.6.0" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
16
Plugins/Flow.Launcher.Plugin.Calculator/Languages/sk.xaml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_caculator_plugin_name">Kalkulačka</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_caculator_plugin_description">Spracúva matematické operácie.(Skúste 5*3-2 vo flowlauncheri)</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_not_a_number">Nie je číslo (NaN)</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_expression_not_complete">Nesprávny alebo neúplný výraz (Nezabudli ste na zátvorky?)</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_copy_number_to_clipboard">Kopírovať toto číslo do schránky</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_output_decimal_seperator">Oddeľovač des. miest</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_output_decimal_seperator_help">Oddeľovač desatinných miest použitý vo výsledku.</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_decimal_seperator_use_system_locale">Použiť podľa systému</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_decimal_seperator_comma">Čiarka (,)</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_decimal_seperator_dot">Bodka (.)</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_calculator_max_decimal_places">Desatinné miesta</system:String>
|
||||
</ResourceDictionary>
|
||||
|
|
@ -34,7 +34,7 @@ namespace Flow.Launcher.Plugin.Caculator
|
|||
{
|
||||
MagesEngine = new Engine();
|
||||
}
|
||||
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
Context = context;
|
||||
|
|
@ -78,16 +78,16 @@ namespace Flow.Launcher.Plugin.Caculator
|
|||
{
|
||||
try
|
||||
{
|
||||
Clipboard.SetText(newResult);
|
||||
Clipboard.SetDataObject(newResult);
|
||||
return true;
|
||||
}
|
||||
catch (ExternalException)
|
||||
catch (ExternalException e)
|
||||
{
|
||||
MessageBox.Show("Copy failed, please try later");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ namespace Flow.Launcher.Plugin.Caculator
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (!IsBracketComplete(query.Search))
|
||||
{
|
||||
return false;
|
||||
|
|
@ -164,7 +164,7 @@ namespace Flow.Launcher.Plugin.Caculator
|
|||
|
||||
return leftBracketCount == 0;
|
||||
}
|
||||
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return Context.API.GetTranslation("flowlauncher_plugin_caculator_plugin_name");
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Calculator",
|
||||
"Description": "Provide mathematical calculations.(Try 5*3-2 in Flow Launcher)",
|
||||
"Author": "cxfksword",
|
||||
"Version": "1.0.0",
|
||||
"Version": "1.1.3",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Caculator.dll",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectGuid>{F35190AA-4758-4D9E-A193-E3BDF6AD3567}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Flow.Launcher.Plugin.Color</RootNamespace>
|
||||
<AssemblyName>Flow.Launcher.Plugin.Color</AssemblyName>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
|
@ -96,9 +98,4 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_name">Plugin Management</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_description">Install, remove or update Flow Launcher plugins</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_color_plugin_name">Farby</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_color_plugin_description">Zobrazuje náhľad farieb v HEX formáte. (Skúste #000 vo Flow Launcheri)</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Colors",
|
||||
"Description": "Provide hex color preview.(Try #000 in Flow Launcher)",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "1.0.0",
|
||||
"Version": "1.1.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Color.dll",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectGuid>{1EE20B48-82FB-48A2-8086-675D6DDAB4F0}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Flow.Launcher.Plugin.ControlPanel</RootNamespace>
|
||||
<AssemblyName>Flow.Launcher.Plugin.ControlPanel</AssemblyName>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
|
@ -96,9 +98,4 @@
|
|||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_name">Flow Launcher插件管理</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_description">安装/卸载/更新Flow Launcher插件</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_controlpanel_plugin_name">Ovládací panel</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_controlpanel_plugin_description">Vyhľadáva položky Ovládacieho panela</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Control Panel",
|
||||
"Description": "Search within the Control Panel.",
|
||||
"Author": "CoenraadS",
|
||||
"Version": "1.0.0",
|
||||
"Version": "1.1.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.ControlPanel.dll",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<ApplicationIcon />
|
||||
<StartupObject />
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
<system:String x:Key="plugin_explorer_deletefilefolderconfirm">Are you sure you want to permanently delete this {0}?</system:String>
|
||||
<system:String x:Key="plugin_explorer_deletefilefoldersuccess">Deletion successful</system:String>
|
||||
<system:String x:Key="plugin_explorer_deletefilefoldersuccess_detail">Successfully deleted the {0}</system:String>
|
||||
<system:String x:Key="plugin_explorer_globalActionKeywordInvalid">Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword</system:String>
|
||||
|
||||
<!--Controls-->
|
||||
<system:String x:Key="plugin_explorer_delete">Delete</system:String>
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
internal const char AllFilesFolderSearchWildcard = '>';
|
||||
|
||||
internal const string DefaultContentSearchActionKeyword = "doc:";
|
||||
|
||||
internal const char DirectorySeperator = '\\';
|
||||
|
||||
internal const string WindowsIndexingOptions = "srchadmin.dll";
|
||||
|
|
|
|||
|
|
@ -6,14 +6,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.FolderLinks
|
|||
{
|
||||
public class QuickFolderAccess
|
||||
{
|
||||
internal List<Result> FolderList(Query query, List<FolderLink> folderLinks, PluginInitContext context)
|
||||
internal List<Result> FolderListMatched(Query query, List<FolderLink> folderLinks, PluginInitContext context)
|
||||
{
|
||||
if (string.IsNullOrEmpty(query.Search))
|
||||
return folderLinks
|
||||
.Select(item =>
|
||||
new ResultManager(context)
|
||||
.CreateFolderResult(item.Nickname, item.Path, item.Path, query))
|
||||
.ToList();
|
||||
return new List<Result>();
|
||||
|
||||
string search = query.Search.ToLower();
|
||||
|
||||
|
|
@ -24,5 +20,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search.FolderLinks
|
|||
.CreateFolderResult(item.Nickname, item.Path, item.Path, query))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
internal List<Result> FolderListAll(Query query, List<FolderLink> folderLinks, PluginInitContext context)
|
||||
=> folderLinks
|
||||
.Select(item =>
|
||||
new ResultManager(context).CreateFolderResult(item.Nickname, item.Path, item.Path, query))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,17 +34,20 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
var querySearch = query.Search;
|
||||
|
||||
var quickFolderLinks = quickFolderAccess.FolderList(query, settings.QuickFolderAccessLinks, context);
|
||||
|
||||
if (quickFolderLinks.Count > 0 && query.ActionKeyword == settings.SearchActionKeyword)
|
||||
return quickFolderLinks;
|
||||
|
||||
if (string.IsNullOrEmpty(querySearch))
|
||||
return results;
|
||||
|
||||
if (IsFileContentSearch(query.ActionKeyword))
|
||||
return WindowsIndexFileContentSearch(query, querySearch);
|
||||
|
||||
// This allows the user to type the assigned action keyword and only see the list of quick folder links
|
||||
if (settings.QuickFolderAccessLinks.Count > 0
|
||||
&& query.ActionKeyword == settings.SearchActionKeyword
|
||||
&& string.IsNullOrEmpty(query.Search))
|
||||
return quickFolderAccess.FolderListAll(query, settings.QuickFolderAccessLinks, context);
|
||||
|
||||
var quickFolderLinks = quickFolderAccess.FolderListMatched(query, settings.QuickFolderAccessLinks, context);
|
||||
|
||||
if (quickFolderLinks.Count > 0)
|
||||
results.AddRange(quickFolderLinks);
|
||||
|
||||
var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch);
|
||||
|
||||
if (isEnvironmentVariable)
|
||||
|
|
@ -54,7 +57,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
var isEnvironmentVariablePath = querySearch.Substring(1).Contains("%\\");
|
||||
|
||||
if (!FilesFolders.IsLocationPathString(querySearch) && !isEnvironmentVariablePath)
|
||||
return WindowsIndexFilesAndFoldersSearch(query, querySearch);
|
||||
{
|
||||
results.AddRange(WindowsIndexFilesAndFoldersSearch(query, querySearch));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
var locationPath = querySearch;
|
||||
|
||||
|
|
@ -137,15 +144,17 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
private bool UseWindowsIndexForDirectorySearch(string locationPath)
|
||||
{
|
||||
var pathToDirectory = FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath);
|
||||
|
||||
if (!settings.UseWindowsIndexForDirectorySearch)
|
||||
return false;
|
||||
|
||||
if (settings.IndexSearchExcludedSubdirectoryPaths
|
||||
.Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(locationPath)
|
||||
.Any(x => FilesFolders.ReturnPreviousDirectoryIfIncompleteString(pathToDirectory)
|
||||
.StartsWith(x.Path, StringComparison.OrdinalIgnoreCase)))
|
||||
return false;
|
||||
|
||||
return indexSearch.PathIsIndexed(locationPath);
|
||||
return indexSearch.PathIsIndexed(pathToDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
private readonly ResultManager resultManager;
|
||||
|
||||
// Reserved keywords in oleDB
|
||||
private readonly string reservedStringPattern = @"^[\/\\\$\%]+$";
|
||||
private readonly string reservedStringPattern = @"^[\/\\\$\%_]+$";
|
||||
|
||||
internal IndexSearch(PluginInitContext context)
|
||||
{
|
||||
|
|
@ -51,7 +51,12 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
{
|
||||
if (dataReaderResults.GetValue(0) != DBNull.Value && dataReaderResults.GetValue(1) != DBNull.Value)
|
||||
{
|
||||
var path = new Uri(dataReaderResults.GetString(1)).LocalPath;
|
||||
// # 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")
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
|
@ -22,6 +23,6 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
|
||||
|
||||
[JsonProperty]
|
||||
public string FileContentSearchActionKeyword { get; set; } = "doc:";
|
||||
public string FileContentSearchActionKeyword { get; set; } = Constants.DefaultContentSearchActionKeyword;
|
||||
}
|
||||
}
|
||||
|
|
@ -54,5 +54,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
}
|
||||
|
||||
internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
|
||||
|
||||
internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,8 +51,17 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
if (settingsViewModel.IsNewActionKeywordGlobal(newActionKeyword)
|
||||
&& currentActionKeyword.Description
|
||||
== settingsViewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_filecontentsearch"))
|
||||
{
|
||||
MessageBox.Show(settingsViewModel.Context.API.GetTranslation("plugin_explorer_globalActionKeywordInvalid"));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!settingsViewModel.IsActionKeywordAlreadyAssigned(newActionKeyword))
|
||||
if (!settingsViewModel.IsActionKeywordAlreadyAssigned(newActionKeyword))
|
||||
{
|
||||
settingsViewModel.UpdateActionKeyword(newActionKeyword, currentActionKeyword.Keyword);
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"Name": "Explorer",
|
||||
"Description": "Search and manage files and folders. Explorer utilises Windows Index Search",
|
||||
"Author": "Jeremy Wu",
|
||||
"Version": "1.2.2",
|
||||
"Version": "1.2.5",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectGuid>{FDED22C8-B637-42E8-824A-63B5B6E05A3A}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Flow.Launcher.Plugin.PluginIndicator</RootNamespace>
|
||||
<AssemblyName>Flow.Launcher.Plugin.PluginIndicator</AssemblyName>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
|
@ -96,10 +98,5 @@
|
|||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_name">Plugin Indicator</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_pluginindicator_plugin_description">Ponúka návrhy pre akcie pluginov</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Plugin Indicator",
|
||||
"Description": "Provide plugin actionword suggestion",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "1.0.0",
|
||||
"Version": "1.1.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.PluginIndicator.dll",
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ProjectGuid>{049490F0-ECD2-4148-9B39-2135EC346EBE}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Flow.Launcher.Plugin.PluginManagement</RootNamespace>
|
||||
<AssemblyName>Flow.Launcher.Plugin.PluginManagement</AssemblyName>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.PluginManagement\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>..\..\Output\Release\Plugins\Flow.Launcher.Plugin.PluginManagement\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="plugin.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Images\plugin.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Languages\en.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Languages\zh-cn.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Languages\zh-tw.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Languages\de.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Languages\pl.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Languages\tr.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="JetBrains.Annotations" Version="2019.1.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="System.Runtime" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
namespace Flow.Launcher.Plugin.PluginManagement
|
||||
{
|
||||
public class FlowLauncherPluginResult
|
||||
{
|
||||
public string plugin_file;
|
||||
public string description;
|
||||
public int liked_count;
|
||||
public string name;
|
||||
public string version;
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 269 B |
|
|
@ -1,8 +0,0 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_name">Flow Launcher Plugin Verwaltung</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_description">Installiere/Entferne/Aktualisiere Flow Launcher Plugins</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_name">Zarządzanie wtyczkami Flow Launcher</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_description">Pozwala na instalacje, usuwanie i aktualizacje wtyczek</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_name">Flow Launcher Eklenti Yöneticisi</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_description">Flow Launcher eklentilerini kurun, kaldırın ya da güncelleyin</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_name">Flow Launcher 外掛管理</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_plugin_management_plugin_description">安裝/解除安裝/更新 Flow Launcher 外掛</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Newtonsoft.Json;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Http;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
|
||||
namespace Flow.Launcher.Plugin.PluginManagement
|
||||
{
|
||||
public class Main : IPlugin, IPluginI18n
|
||||
{
|
||||
private static string APIBASE = "http://api.wox.one";
|
||||
private static string pluginSearchUrl = APIBASE + "/plugin/search/";
|
||||
private const string ListCommand = "list";
|
||||
private const string InstallCommand = "install";
|
||||
private const string UninstallCommand = "uninstall";
|
||||
private PluginInitContext context;
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
List<Result> results = new List<Result>();
|
||||
|
||||
if (string.IsNullOrEmpty(query.Search))
|
||||
{
|
||||
results.Add(ResultForListCommandAutoComplete(query));
|
||||
results.Add(ResultForInstallCommandAutoComplete(query));
|
||||
results.Add(ResultForUninstallCommandAutoComplete(query));
|
||||
return results;
|
||||
}
|
||||
|
||||
string command = query.FirstSearch.ToLower();
|
||||
if (string.IsNullOrEmpty(command)) return results;
|
||||
|
||||
if (command == ListCommand)
|
||||
{
|
||||
return ResultForListInstalledPlugins();
|
||||
}
|
||||
if (command == UninstallCommand)
|
||||
{
|
||||
return ResultForUnInstallPlugin(query);
|
||||
}
|
||||
if (command == InstallCommand)
|
||||
{
|
||||
return ResultForInstallPlugin(query);
|
||||
}
|
||||
|
||||
if (InstallCommand.Contains(command))
|
||||
{
|
||||
results.Add(ResultForInstallCommandAutoComplete(query));
|
||||
}
|
||||
if (UninstallCommand.Contains(command))
|
||||
{
|
||||
results.Add(ResultForUninstallCommandAutoComplete(query));
|
||||
}
|
||||
if (ListCommand.Contains(command))
|
||||
{
|
||||
results.Add(ResultForListCommandAutoComplete(query));
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private Result ResultForListCommandAutoComplete(Query query)
|
||||
{
|
||||
string title = ListCommand;
|
||||
string subtitle = "list installed plugins";
|
||||
return ResultForCommand(query, ListCommand, title, subtitle);
|
||||
}
|
||||
|
||||
private Result ResultForInstallCommandAutoComplete(Query query)
|
||||
{
|
||||
string title = $"{InstallCommand} <Package Name>";
|
||||
string subtitle = "list installed plugins";
|
||||
return ResultForCommand(query, InstallCommand, title, subtitle);
|
||||
}
|
||||
|
||||
private Result ResultForUninstallCommandAutoComplete(Query query)
|
||||
{
|
||||
string title = $"{UninstallCommand} <Package Name>";
|
||||
string subtitle = "list installed plugins";
|
||||
return ResultForCommand(query, UninstallCommand, title, subtitle);
|
||||
}
|
||||
|
||||
private Result ResultForCommand(Query query, string command, string title, string subtitle)
|
||||
{
|
||||
const string seperater = Plugin.Query.TermSeperater;
|
||||
var result = new Result
|
||||
{
|
||||
Title = title,
|
||||
IcoPath = "Images\\plugin.png",
|
||||
SubTitle = subtitle,
|
||||
Action = e =>
|
||||
{
|
||||
context.API.ChangeQuery($"{query.ActionKeyword}{seperater}{command}{seperater}");
|
||||
return false;
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<Result> ResultForInstallPlugin(Query query)
|
||||
{
|
||||
List<Result> results = new List<Result>();
|
||||
string pluginName = query.SecondSearch;
|
||||
if (string.IsNullOrEmpty(pluginName)) return results;
|
||||
string json;
|
||||
try
|
||||
{
|
||||
json = Http.Get(pluginSearchUrl + pluginName).Result;
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
//todo happlebao add option in log to decide give user prompt or not
|
||||
context.API.ShowMsg("PluginManagement.ResultForInstallPlugin: Can't connect to Wox plugin website, check your conenction");
|
||||
Log.Exception("|PluginManagement.ResultForInstallPlugin|Can't connect to Wox plugin website, check your conenction", e);
|
||||
return new List<Result>();
|
||||
}
|
||||
List<FlowLauncherPluginResult> searchedPlugins;
|
||||
try
|
||||
{
|
||||
searchedPlugins = JsonConvert.DeserializeObject<List<FlowLauncherPluginResult>>(json);
|
||||
}
|
||||
catch (JsonSerializationException e)
|
||||
{
|
||||
context.API.ShowMsg("PluginManagement.ResultForInstallPlugin: Coundn't parse api search results, Please update your Flow Launcher!");
|
||||
Log.Exception("|PluginManagement.ResultForInstallPlugin|Coundn't parse api search results, Please update your Flow Launcher!", e);
|
||||
return results;
|
||||
}
|
||||
|
||||
foreach (FlowLauncherPluginResult r in searchedPlugins)
|
||||
{
|
||||
FlowLauncherPluginResult r1 = r;
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = r.name,
|
||||
SubTitle = r.description,
|
||||
IcoPath = "Images\\plugin.png",
|
||||
TitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.name).MatchData,
|
||||
SubTitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, r.description).MatchData,
|
||||
Action = _ =>
|
||||
{
|
||||
MessageBoxResult result = MessageBox.Show("Are you sure you wish to install the \'" + r.name + "\' plugin",
|
||||
"Install plugin", MessageBoxButton.YesNo);
|
||||
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
string folder = Path.Combine(Path.GetTempPath(), "FlowLauncherPluginDownload");
|
||||
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
|
||||
string filePath = Path.Combine(folder, Guid.NewGuid().ToString() + ".flowlauncher");
|
||||
|
||||
string pluginUrl = APIBASE + "/media/" + r1.plugin_file;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await Http.Download(pluginUrl, filePath);
|
||||
context.API.InstallPlugin(filePath);
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
context.API.ShowMsg($"PluginManagement.ResultForInstallPlugin: download failed for <{r.name}>");
|
||||
Log.Exception($"|PluginManagement.ResultForInstallPlugin|download failed for <{r.name}>", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private List<Result> ResultForUnInstallPlugin(Query query)
|
||||
{
|
||||
List<Result> results = new List<Result>();
|
||||
List<PluginMetadata> allInstalledPlugins = context.API.GetAllPlugins().Select(o => o.Metadata).ToList();
|
||||
if (!string.IsNullOrEmpty(query.SecondSearch))
|
||||
{
|
||||
allInstalledPlugins =
|
||||
allInstalledPlugins.Where(o => o.Name.ToLower().Contains(query.SecondSearch.ToLower())).ToList();
|
||||
}
|
||||
|
||||
foreach (PluginMetadata plugin in allInstalledPlugins)
|
||||
{
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = plugin.Name,
|
||||
SubTitle = plugin.Description,
|
||||
IcoPath = plugin.IcoPath,
|
||||
TitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, plugin.Name).MatchData,
|
||||
SubTitleHighlightData = StringMatcher.FuzzySearch(query.SecondSearch, plugin.Description).MatchData,
|
||||
Action = e =>
|
||||
{
|
||||
UnInstallPlugin(plugin);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private void UnInstallPlugin(PluginMetadata plugin)
|
||||
{
|
||||
string content = $"Do you want to uninstall following plugin?{Environment.NewLine}{Environment.NewLine}" +
|
||||
$"Name: {plugin.Name}{Environment.NewLine}" +
|
||||
$"Version: {plugin.Version}{Environment.NewLine}" +
|
||||
$"Author: {plugin.Author}";
|
||||
if (MessageBox.Show(content, "Flow Launcher", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||
{
|
||||
File.Create(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt")).Close();
|
||||
var result = MessageBox.Show($"You have uninstalled plugin {plugin.Name} successfully.{Environment.NewLine}" +
|
||||
"Restart Flow Launcher to take effect?",
|
||||
"Install plugin", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
context.API.RestartApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<Result> ResultForListInstalledPlugins()
|
||||
{
|
||||
List<Result> results = new List<Result>();
|
||||
foreach (PluginMetadata plugin in context.API.GetAllPlugins().Select(o => o.Metadata))
|
||||
{
|
||||
string actionKeywordString = string.Join(" or ", plugin.ActionKeywords.ToArray());
|
||||
results.Add(new Result
|
||||
{
|
||||
Title = $"{plugin.Name} - Action Keywords: {actionKeywordString}",
|
||||
SubTitle = plugin.Description,
|
||||
IcoPath = plugin.IcoPath
|
||||
});
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginTitle()
|
||||
{
|
||||
return context.API.GetTranslation("flowlauncher_plugin_plugin_management_plugin_name");
|
||||
}
|
||||
|
||||
public string GetTranslatedPluginDescription()
|
||||
{
|
||||
return context.API.GetTranslation("flowlauncher_plugin_plugin_management_plugin_description");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"ID": "D2D2C23B084D422DB66FE0C79D6C2A6A",
|
||||
"ActionKeyword": "wpm",
|
||||
"Name": "Plugin Management",
|
||||
"Description": "Install/Remove/Update Flow Launcher plugins",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "1.0",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.PluginManagement.dll",
|
||||
"IcoPath": "Images\\plugin.png"
|
||||
}
|
||||
79
Plugins/Flow.Launcher.Plugin.PluginsManager/ContextMenu.cs
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.PluginsManager.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Flow.Launcher.Plugin.PluginsManager
|
||||
{
|
||||
internal class ContextMenu : IContextMenu
|
||||
{
|
||||
private PluginInitContext Context { get; set; }
|
||||
|
||||
private Settings Settings { get; set; }
|
||||
|
||||
public ContextMenu(PluginInitContext context, Settings settings)
|
||||
{
|
||||
Context = context;
|
||||
Settings = settings;
|
||||
}
|
||||
|
||||
public List<Result> LoadContextMenus(Result selectedResult)
|
||||
{
|
||||
var pluginManifestInfo = selectedResult.ContextData as UserPlugin;
|
||||
|
||||
return new List<Result>
|
||||
{
|
||||
new Result
|
||||
{
|
||||
Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_openwebsite_title"),
|
||||
SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_openwebsite_subtitle"),
|
||||
IcoPath = "Images\\website.png",
|
||||
Action = _ =>
|
||||
{
|
||||
SharedCommands.SearchWeb.NewTabInBrowser(pluginManifestInfo.Website);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_gotosourcecode_title"),
|
||||
SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_gotosourcecode_subtitle"),
|
||||
IcoPath = "Images\\sourcecode.png",
|
||||
Action = _ =>
|
||||
{
|
||||
SharedCommands.SearchWeb.NewTabInBrowser(pluginManifestInfo.UrlSourceCode);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_newissue_title"),
|
||||
SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_newissue_subtitle"),
|
||||
IcoPath = "Images\\request.png",
|
||||
Action = _ =>
|
||||
{
|
||||
// standard UrlSourceCode format in PluginsManifest's plugins.json file: https://github.com/jjw24/WoxDictionary/tree/master
|
||||
var link = pluginManifestInfo.UrlSourceCode.StartsWith("https://github.com")
|
||||
? pluginManifestInfo.UrlSourceCode.Replace("/tree/master", "/issues/new/choose")
|
||||
: pluginManifestInfo.UrlSourceCode;
|
||||
|
||||
SharedCommands.SearchWeb.NewBrowserWindow(link);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
new Result
|
||||
{
|
||||
Title = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_title"),
|
||||
SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_plugin_contextmenu_pluginsmanifest_subtitle"),
|
||||
IcoPath = selectedResult.IcoPath,
|
||||
Action = _ =>
|
||||
{
|
||||
SharedCommands.SearchWeb.NewBrowserWindow("https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||