Merge branch 'dev' into address_high_memory_issue
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ namespace Flow.Launcher.Core.Plugin
|
|||
else
|
||||
{ // non action keyword
|
||||
actionKeyword = string.Empty;
|
||||
actionParameters = terms.ToList();
|
||||
search = rawQuery;
|
||||
}
|
||||
|
||||
|
|
@ -38,10 +37,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
Terms = terms,
|
||||
RawQuery = rawQuery,
|
||||
ActionKeyword = actionKeyword,
|
||||
Search = search,
|
||||
// Obsolete value initialisation
|
||||
ActionName = actionKeyword,
|
||||
ActionParameters = actionParameters
|
||||
Search = search
|
||||
};
|
||||
|
||||
return query;
|
||||
|
|
|
|||
|
|
@ -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,199 +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][];
|
||||
|
||||
[Obsolete("Not accurate, eg 音乐 will not return yinyue but returns yinle ")]
|
||||
/// <summary>
|
||||
/// replace chinese character with pinyin, non chinese character won't be modified
|
||||
/// <param name="word"> should be word or sentence, instead of single character. e.g. 微软 </param>
|
||||
/// </summary>
|
||||
public string[] Pinyin(string word)
|
||||
{
|
||||
if (!_settings.ShouldUsePinyin)
|
||||
{
|
||||
return EmptyStringArray;
|
||||
}
|
||||
|
||||
var pinyin = word.Select(c =>
|
||||
{
|
||||
var pinyins = PinyinHelper.toHanyuPinyinStringArray(c);
|
||||
var result = pinyins == null ? c.ToString() : pinyins[0];
|
||||
return result;
|
||||
}).ToArray();
|
||||
return pinyin;
|
||||
}
|
||||
|
||||
/// <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,8 +23,10 @@ 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -53,10 +53,10 @@
|
|||
<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>
|
||||
|
|
|
|||
|
|
@ -1,32 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure
|
||||
{
|
||||
[Obsolete("This class is obsolete and should not be used. Please use the static function StringMatcher.FuzzySearch")]
|
||||
public class FuzzyMatcher
|
||||
{
|
||||
private string query;
|
||||
private MatchOption opt;
|
||||
|
||||
private FuzzyMatcher(string query, MatchOption opt)
|
||||
{
|
||||
this.query = query.Trim();
|
||||
this.opt = opt;
|
||||
}
|
||||
|
||||
public static FuzzyMatcher Create(string query)
|
||||
{
|
||||
return new FuzzyMatcher(query, new MatchOption());
|
||||
}
|
||||
|
||||
public static FuzzyMatcher Create(string query, MatchOption opt)
|
||||
{
|
||||
return new FuzzyMatcher(query, opt);
|
||||
}
|
||||
|
||||
public MatchResult Evaluate(string str)
|
||||
{
|
||||
return StringMatcher.Instance.FuzzyMatch(query, str, opt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
|
||||
ImageCache.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();
|
||||
|
|
@ -106,7 +106,7 @@ 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))
|
||||
{
|
||||
|
|
@ -139,8 +139,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 +191,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)
|
||||
|
|
|
|||
65
Flow.Launcher.Infrastructure/PinyinAlphabet.cs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using JetBrains.Annotations;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using ToolGood.Words.Pinyin;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
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 result = WordsHelper.GetPinyin(content, ";");
|
||||
result = GetFirstPinyinChar(result) + result.Replace(";", "");
|
||||
_pinyinCache[content] = result;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return content;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return _pinyinCache[content];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFirstPinyinChar(string content)
|
||||
{
|
||||
return string.Concat(content.Split(';').Select(x => x.First()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,18 +21,6 @@ namespace Flow.Launcher.Infrastructure
|
|||
|
||||
public static StringMatcher Instance { get; internal set; }
|
||||
|
||||
[Obsolete("This method is obsolete and should not be used. Please use the static function StringMatcher.FuzzySearch")]
|
||||
public static int Score(string source, string target)
|
||||
{
|
||||
return FuzzySearch(target, source).Score;
|
||||
}
|
||||
|
||||
[Obsolete("This method is obsolete and should not be used. Please use the static function StringMatcher.FuzzySearch")]
|
||||
public static bool IsMatch(string source, string target)
|
||||
{
|
||||
return Score(source, target) > 0;
|
||||
}
|
||||
|
||||
public static MatchResult FuzzySearch(string query, string stringToCompare)
|
||||
{
|
||||
return Instance.FuzzyMatch(query, stringToCompare);
|
||||
|
|
@ -323,18 +311,6 @@ namespace Flow.Launcher.Infrastructure
|
|||
|
||||
public class MatchOption
|
||||
{
|
||||
/// <summary>
|
||||
/// prefix of match char, use for highlight
|
||||
/// </summary>
|
||||
[Obsolete("this is never used")]
|
||||
public string Prefix { get; set; } = "";
|
||||
|
||||
/// <summary>
|
||||
/// suffix of match char, use for highlight
|
||||
/// </summary>
|
||||
[Obsolete("this is never used")]
|
||||
public string Suffix { get; set; } = "";
|
||||
|
||||
public bool IgnoreCase { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,5 +30,6 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
}
|
||||
|
||||
public static readonly string PluginsDirectory = Path.Combine(DataDirectory(), Constant.Plugins);
|
||||
public static readonly string PluginSettingsDirectory = Path.Combine(DataDirectory(), "Settings", Constant.Plugins);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
if (Plugins.ContainsKey(metadata.ID))
|
||||
{
|
||||
var settings = Plugins[metadata.ID];
|
||||
|
||||
// TODO: Remove. This is one off for 1.2.0 release.
|
||||
// Introduced a new action keyword in Explorer, so need to update plugin setting in the UserData folder.
|
||||
// This kind of plugin meta update should be handled by a dedicated method trigger by version bump.
|
||||
if (metadata.ID == "572be03c74c642baae319fc283e561a8" && metadata.ActionKeywords.Count != settings.ActionKeywords.Count)
|
||||
settings.ActionKeywords = metadata.ActionKeywords;
|
||||
|
||||
if (string.IsNullOrEmpty(settings.Version))
|
||||
settings.Version = metadata.Version;
|
||||
|
||||
if (settings.ActionKeywords?.Count > 0)
|
||||
{
|
||||
metadata.ActionKeywords = settings.ActionKeywords;
|
||||
|
|
@ -28,6 +38,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
{
|
||||
ID = metadata.ID,
|
||||
Name = metadata.Name,
|
||||
Version = metadata.Version,
|
||||
ActionKeywords = metadata.ActionKeywords,
|
||||
Disabled = metadata.Disabled
|
||||
};
|
||||
|
|
@ -39,6 +50,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
{
|
||||
public string ID { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Version { get; set; }
|
||||
public List<string> ActionKeywords { get; set; } // a reference of the action keywords from plugin manager
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -70,12 +70,6 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
|
||||
public ObservableCollection<CustomPluginHotkey> CustomPluginHotkeys { get; set; } = new ObservableCollection<CustomPluginHotkey>();
|
||||
|
||||
[Obsolete]
|
||||
public double Opacity { get; set; } = 1;
|
||||
|
||||
[Obsolete]
|
||||
public OpacityMode OpacityMode { get; set; } = OpacityMode.Normal;
|
||||
|
||||
public bool DontPromptUpdateMsg { get; set; }
|
||||
public bool EnableUpdateLog { get; set; }
|
||||
|
||||
|
|
@ -108,12 +102,4 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
|||
Empty,
|
||||
Preserved
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public enum OpacityMode
|
||||
{
|
||||
Normal = 0,
|
||||
LayeredWindow = 1,
|
||||
DWM = 2
|
||||
}
|
||||
}
|
||||
|
|
@ -11,23 +11,6 @@ namespace Flow.Launcher.Plugin
|
|||
List<Result> LoadContextMenus(Result selectedResult);
|
||||
}
|
||||
|
||||
[Obsolete("If a plugin has a action keyword, then it is exclusive. This interface will be remove in v1.3.0")]
|
||||
public interface IExclusiveQuery : IFeatures
|
||||
{
|
||||
[Obsolete("If a plugin has a action keyword, then it is exclusive. This method will be remove in v1.3.0")]
|
||||
bool IsExclusiveQuery(Query query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represent plugin query will be executed in UI thread directly. Don't do long-running operation in Query method if you implement this interface
|
||||
/// <remarks>This will improve the performance of instant search like websearch or cmd plugin</remarks>
|
||||
/// </summary>
|
||||
[Obsolete("Flow Launcher is fast enough now, executed on ui thread is no longer needed")]
|
||||
public interface IInstantQuery : IFeatures
|
||||
{
|
||||
bool IsInstantQuery(string query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represent plugins that support internationalization
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Features
|
||||
{
|
||||
[Obsolete("Delete Flow.Launcher.Plugin.Features using directive, " +
|
||||
"and use Flow.Launcher.Plugin.Feature.IContextMenu instead, " +
|
||||
"this method will be removed in v1.3.0")]
|
||||
public interface IContextMenu { }
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Features
|
||||
{
|
||||
[Obsolete("Delete Flow.Launcher.Plugin.Features using directive, " +
|
||||
"and use Flow.Launcher.Plugin.Feature.IInstantQuery instead, " +
|
||||
"this method will be removed in v1.3.0")]
|
||||
public interface IExclusiveQuery { }
|
||||
}
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Features
|
||||
{
|
||||
[Obsolete("Delete Flow.Launcher.Plugin.Features using directive, " +
|
||||
"and use Flow.Launcher.Plugin.Feature.IInstantQuery instead, " +
|
||||
"this method will be removed in v1.3.0")]
|
||||
public interface IInstantQuery { }
|
||||
}
|
||||
|
|
@ -14,10 +14,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>1.1.0</Version>
|
||||
<PackageVersion>1.1.0</PackageVersion>
|
||||
<AssemblyVersion>1.1.0</AssemblyVersion>
|
||||
<FileVersion>1.1.0</FileVersion>
|
||||
<Version>1.2.1</Version>
|
||||
<PackageVersion>1.2.1</PackageVersion>
|
||||
<AssemblyVersion>1.2.1</AssemblyVersion>
|
||||
<FileVersion>1.2.1</FileVersion>
|
||||
<PackageId>Flow.Launcher.Plugin</PackageId>
|
||||
<Authors>Flow-Launcher</Authors>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
|
|
|
|||
|
|
@ -8,15 +8,6 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
public interface IPublicAPI
|
||||
{
|
||||
/// <summary>
|
||||
/// Push result to query box
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="plugin"></param>
|
||||
/// <param name="results"></param>
|
||||
[Obsolete("This method will be removed in Flow Launcher 1.3")]
|
||||
void PushResults(Query query, PluginMetadata plugin, List<Result> results);
|
||||
|
||||
/// <summary>
|
||||
/// Change Flow.Launcher query
|
||||
/// </summary>
|
||||
|
|
@ -27,42 +18,11 @@ namespace Flow.Launcher.Plugin
|
|||
/// </param>
|
||||
void ChangeQuery(string query, bool requery = false);
|
||||
|
||||
/// <summary>
|
||||
/// Just change the query text, this won't raise search
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
[Obsolete]
|
||||
void ChangeQueryText(string query, bool selectAll = false);
|
||||
|
||||
/// <summary>
|
||||
/// Close Flow Launcher
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
void CloseApp();
|
||||
|
||||
/// <summary>
|
||||
/// Restart Flow Launcher
|
||||
/// </summary>
|
||||
void RestartApp();
|
||||
|
||||
/// <summary>
|
||||
/// Restart Flow Launcher
|
||||
/// </summary>
|
||||
[Obsolete("Use RestartApp instead. This method will be removed in Flow Launcher 1.3")]
|
||||
void RestarApp();
|
||||
|
||||
/// <summary>
|
||||
/// Hide Flow Launcher
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
void HideApp();
|
||||
|
||||
/// <summary>
|
||||
/// Show Flow Launcher
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
void ShowApp();
|
||||
|
||||
/// <summary>
|
||||
/// Save all Flow Launcher settings
|
||||
/// </summary>
|
||||
|
|
@ -103,18 +63,6 @@ namespace Flow.Launcher.Plugin
|
|||
/// </summary>
|
||||
void OpenSettingDialog();
|
||||
|
||||
/// <summary>
|
||||
/// Show loading animation
|
||||
/// </summary>
|
||||
[Obsolete("automatically start")]
|
||||
void StartLoadingBar();
|
||||
|
||||
/// <summary>
|
||||
/// Stop loading animation
|
||||
/// </summary>
|
||||
[Obsolete("automatically stop")]
|
||||
void StopLoadingBar();
|
||||
|
||||
/// <summary>
|
||||
/// Install Flow Launcher plugin
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -43,9 +43,6 @@ namespace Flow.Launcher.Plugin
|
|||
return Name;
|
||||
}
|
||||
|
||||
[Obsolete("Use IcoPath")]
|
||||
public string FullIcoPath => IcoPath;
|
||||
|
||||
/// <summary>
|
||||
/// Init time include both plugin load time and init time
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -94,14 +94,5 @@ namespace Flow.Launcher.Plugin
|
|||
}
|
||||
|
||||
public override string ToString() => RawQuery;
|
||||
|
||||
[Obsolete("Use ActionKeyword, this property will be removed in v1.3.0")]
|
||||
public string ActionName { get; internal set; }
|
||||
|
||||
[Obsolete("Use Search instead, this property will be removed in v1.3.0")]
|
||||
public List<string> ActionParameters { get; internal set; }
|
||||
|
||||
[Obsolete("Use Search instead, this method will be removed in v1.3.0")]
|
||||
public string GetAllRemainingParameter() => Search;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,21 +104,6 @@ namespace Flow.Launcher.Plugin
|
|||
return Title + SubTitle;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Context menus associate with this result
|
||||
/// </summary>
|
||||
[Obsolete("Use IContextMenu instead")]
|
||||
public List<Result> ContextMenu { get; set; }
|
||||
|
||||
[Obsolete("Use Object initializer instead")]
|
||||
public Result(string Title, string IcoPath, string SubTitle = null)
|
||||
{
|
||||
this.Title = Title;
|
||||
this.IcoPath = IcoPath;
|
||||
this.SubTitle = SubTitle;
|
||||
}
|
||||
|
||||
public Result() { }
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,13 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
|
||||
private const string FileExplorerProgramEXE = "explorer.exe";
|
||||
|
||||
public static void Copy(this string sourcePath, string targetPath)
|
||||
/// <summary>
|
||||
/// Copies the folder and all of its files and folders
|
||||
/// including subfolders to the target location
|
||||
/// </summary>
|
||||
/// <param name="sourcePath"></param>
|
||||
/// <param name="targetPath"></param>
|
||||
public static void CopyAll(this string sourcePath, string targetPath)
|
||||
{
|
||||
// Get the subdirectories for the specified directory.
|
||||
DirectoryInfo dir = new DirectoryInfo(sourcePath);
|
||||
|
|
@ -44,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)
|
||||
|
|
@ -108,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);
|
||||
}
|
||||
|
|
@ -118,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)
|
||||
|
|
@ -172,7 +178,7 @@ namespace Flow.Launcher.Plugin.SharedCommands
|
|||
///<summary>
|
||||
/// Gets the previous level directory from a path string.
|
||||
/// Checks that previous level directory exists and returns it
|
||||
/// as a path string, or empty string if doesn't exit
|
||||
/// as a path string, or empty string if doesn't exist
|
||||
///</summary>
|
||||
public static string GetPreviousExistingDirectory(Func<string, bool> locationExists, string path)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ namespace Flow.Launcher.Test.Plugins
|
|||
$"Actual: {result}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
[TestCase("C:\\", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType FROM SystemIndex WHERE directory='file:C:\\'")]
|
||||
[TestCase("C:\\SomeFolder\\", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType FROM SystemIndex WHERE directory='file:C:\\SomeFolder\\'")]
|
||||
[TestCase("C:\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\'")]
|
||||
[TestCase("C:\\SomeFolder\\", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType FROM SystemIndex WHERE directory='file:C:\\SomeFolder\\'")]
|
||||
public void GivenWindowsIndexSearch_WhenSearchTypeIsTopLevelDirectorySearch_ThenQueryShouldUseExpectedString(string folderPath, string expectedString)
|
||||
{
|
||||
// Given
|
||||
|
|
@ -74,7 +74,7 @@ namespace Flow.Launcher.Test.Plugins
|
|||
$"Actual string was: {queryString}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
[TestCase("C:\\SomeFolder\\flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemPathDisplay, System.ItemType " +
|
||||
[TestCase("C:\\SomeFolder\\flow.launcher.sln", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " +
|
||||
"FROM SystemIndex WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
|
||||
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033))" +
|
||||
" AND directory='file:C:\\SomeFolder'")]
|
||||
|
|
@ -126,7 +126,7 @@ namespace Flow.Launcher.Test.Plugins
|
|||
$"Actual string was: {resultString}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
[TestCase("flow.launcher.sln", "SELECT TOP 100 \"System.FileName\", \"System.ItemPathDisplay\", \"System.ItemType\" " +
|
||||
[TestCase("flow.launcher.sln", "SELECT TOP 100 \"System.FileName\", \"System.ItemUrl\", \"System.ItemType\" " +
|
||||
"FROM \"SystemIndex\" WHERE (System.FileName LIKE 'flow.launcher.sln%' " +
|
||||
"OR CONTAINS(System.FileName,'\"flow.launcher.sln*\"',1033)) AND scope='file:'")]
|
||||
public void GivenWindowsIndexSearch_WhenSearchAllFoldersAndFiles_ThenQueryShouldUseExpectedString(
|
||||
|
|
@ -184,6 +184,55 @@ namespace Flow.Launcher.Test.Plugins
|
|||
$"Actual number of results is {results.Count} {Environment.NewLine}");
|
||||
}
|
||||
|
||||
[TestCase(@"some words", @"FREETEXT('some words')")]
|
||||
public void GivenWindowsIndexSearch_WhenQueryWhereRestrictionsIsForFileContentSearch_ThenShouldReturnFreeTextString(
|
||||
string querySearchString, string expectedString)
|
||||
{
|
||||
// Given
|
||||
var queryConstructor = new QueryConstructor(new Settings());
|
||||
|
||||
//When
|
||||
var resultString = queryConstructor.QueryWhereRestrictionsForFileContentSearch(querySearchString);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(resultString == expectedString,
|
||||
$"Expected QueryWhereRestrictions string: {expectedString}{Environment.NewLine} " +
|
||||
$"Actual string was: {resultString}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
[TestCase("some words", "SELECT TOP 100 System.FileName, System.ItemUrl, System.ItemType " +
|
||||
"FROM SystemIndex WHERE FREETEXT('some words') AND scope='file:'")]
|
||||
public void GivenWindowsIndexSearch_WhenSearchForFileContent_ThenQueryShouldUseExpectedString(
|
||||
string userSearchString, string expectedString)
|
||||
{
|
||||
// Given
|
||||
var queryConstructor = new QueryConstructor(new Settings());
|
||||
|
||||
//When
|
||||
var resultString = queryConstructor.QueryForFileContentSearch(userSearchString);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(resultString == expectedString,
|
||||
$"Expected query string: {expectedString}{Environment.NewLine} " +
|
||||
$"Actual string was: {resultString}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
public void GivenQuery_WhenActionKeywordForFileContentSearchExists_ThenFileContentSearchRequiredShouldReturnTrue()
|
||||
{
|
||||
// Given
|
||||
var query = new Query { ActionKeyword = "doc:", Search = "search term" };
|
||||
|
||||
var searchManager = new SearchManager(new Settings(), new PluginInitContext());
|
||||
|
||||
// When
|
||||
var result = searchManager.IsFileContentSearch(query.ActionKeyword);
|
||||
|
||||
// Then
|
||||
Assert.IsTrue(result,
|
||||
$"Expected True for file content search. {Environment.NewLine} " +
|
||||
$"Actual result was: {result}{Environment.NewLine}");
|
||||
}
|
||||
|
||||
[TestCase(@"c:\\", false)]
|
||||
[TestCase(@"i:\", true)]
|
||||
[TestCase(@"\c:\", false)]
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
BIN
Flow.Launcher/Images/app_missing_img.png
Normal file
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -111,7 +111,7 @@
|
|||
<system:String x:Key="done">Done</system:String>
|
||||
<system:String x:Key="cannotFindSpecifiedPlugin">Can't find specified plugin</system:String>
|
||||
<system:String x:Key="newActionKeywordsCannotBeEmpty">New Action Keyword can't be empty</system:String>
|
||||
<system:String x:Key="newActionKeywordsHasBeenAssigned">New Action Keywords have been assigned to another plugin, please assign other new action keyword</system:String>
|
||||
<system:String x:Key="newActionKeywordsHasBeenAssigned">This new Action Keyword is already assigned to another plugin, please choose a different one</system:String>
|
||||
<system:String x:Key="success">Success</system:String>
|
||||
<system:String x:Key="actionkeyword_tips">Use * if you don't want to specify an action keyword</system:String>
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -48,12 +48,6 @@ namespace Flow.Launcher
|
|||
_mainVM.ChangeQueryText(query);
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public void CloseApp()
|
||||
{
|
||||
Application.Current.MainWindow.Close();
|
||||
}
|
||||
|
||||
public void RestartApp()
|
||||
{
|
||||
_mainVM.MainWindowVisibility = Visibility.Hidden;
|
||||
|
|
@ -82,7 +76,6 @@ namespace Flow.Launcher
|
|||
_settingsVM.Save();
|
||||
PluginManager.Save();
|
||||
ImageLoader.Save();
|
||||
_alphabet.Save();
|
||||
}
|
||||
|
||||
public void ReloadAllPluginData()
|
||||
|
|
@ -90,18 +83,6 @@ namespace Flow.Launcher
|
|||
PluginManager.ReloadData();
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public void HideApp()
|
||||
{
|
||||
_mainVM.MainWindowVisibility = Visibility.Hidden;
|
||||
}
|
||||
|
||||
[Obsolete]
|
||||
public void ShowApp()
|
||||
{
|
||||
_mainVM.MainWindowVisibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
public void ShowMsg(string title, string subTitle = "", string iconPath = "")
|
||||
{
|
||||
ShowMsg(title, subTitle, iconPath, true);
|
||||
|
|
@ -151,21 +132,6 @@ namespace Flow.Launcher
|
|||
|
||||
public event FlowLauncherGlobalKeyboardEventHandler GlobalKeyboardEvent;
|
||||
|
||||
[Obsolete("This will be removed in Flow Launcher 1.3")]
|
||||
public void PushResults(Query query, PluginMetadata plugin, List<Result> results)
|
||||
{
|
||||
results.ForEach(o =>
|
||||
{
|
||||
o.PluginDirectory = plugin.PluginDirectory;
|
||||
o.PluginID = plugin.ID;
|
||||
o.OriginQuery = query;
|
||||
});
|
||||
Task.Run(() =>
|
||||
{
|
||||
_mainVM.UpdateResultView(results, plugin, query);
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ namespace Flow.Launcher.ViewModel
|
|||
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;
|
||||
imagePath = Constant.MissingImgIcon;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -33,40 +33,60 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
|||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
string param = query.GetAllRemainingParameter().TrimStart();
|
||||
string param = query.Search.TrimStart();
|
||||
|
||||
// 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,7 +4,7 @@
|
|||
"Name": "Browser Bookmarks",
|
||||
"Description": "Search your browser bookmarks",
|
||||
"Author": "qianlifeng, Ioannis G.",
|
||||
"Version": "1.2.0",
|
||||
"Version": "1.2.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.browserBookmark.dll",
|
||||
|
|
|
|||
|
|
@ -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.0.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Caculator.dll",
|
||||
|
|
|
|||
1
Plugins/Flow.Launcher.Plugin.Everything
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 6d5b687e240a6abdc5623d8a8e09501f3994b0d3
|
||||
|
|
@ -104,6 +104,7 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Core\Flow.Launcher.Core.csproj" />
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||
<ProjectReference Include="..\..\Flow.Launcher.Plugin\Flow.Launcher.Plugin.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,22 +1,26 @@
|
|||
<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">
|
||||
|
||||
<!--Dialogues-->
|
||||
<system:String x:Key="plugin_explorer_make_selection_warning">Please make a selection first</system:String>
|
||||
<system:String x:Key="plugin_explorer_select_folder_link_warning">Please select a folder link</system:String>
|
||||
<system:String x:Key="plugin_explorer_delete_folder_link">Are you sure you want to delete {0}?</system:String>
|
||||
<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>
|
||||
<system:String x:Key="plugin_explorer_edit">Edit</system:String>
|
||||
<system:String x:Key="plugin_explorer_add">Add</system:String>
|
||||
<system:String x:Key="plugin_explorer_manageactionkeywords_header">Customise Action Keywords</system:String>
|
||||
<system:String x:Key="plugin_explorer_quickfolderaccess_header">Quick Folder Access Paths</system:String>
|
||||
<system:String x:Key="plugin_explorer_indexsearchexcludedpaths_header">Index Search Excluded Paths</system:String>
|
||||
<system:String x:Key="plugin_explorer_manageindexoptions">Indexing Options</system:String>
|
||||
|
||||
<system:String x:Key="plugin_explorer_actionkeywordview_search">Search Activation:</system:String>
|
||||
<system:String x:Key="plugin_explorer_actionkeywordview_filecontentsearch">File Content Search:</system:String>
|
||||
|
||||
<!--Plugin Infos-->
|
||||
<system:String x:Key="plugin_explorer_plugin_name">Explorer</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";
|
||||
|
|
|
|||
|
|
@ -22,11 +22,20 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
foreach (DictionaryEntry special in Environment.GetEnvironmentVariables())
|
||||
{
|
||||
if (Directory.Exists(special.Value.ToString()))
|
||||
var path = special.Value.ToString();
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
// we add a trailing slash to the path to make sure drive paths become valid absolute paths.
|
||||
// for example, if %systemdrive% is C: we turn it to C:\
|
||||
path = path.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
|
||||
|
||||
// if we don't have an absolute path, we use Path.GetFullPath to get one.
|
||||
// for example, if %homepath% is \Users\John we turn it to C:\Users\John
|
||||
path = Path.IsPathFullyQualified(path) ? path : Path.GetFullPath(path);
|
||||
|
||||
// Variables are returned with a mixture of all upper/lower case.
|
||||
// Call ToLower() to make the results look consistent
|
||||
envStringPaths.Add(special.Key.ToString().ToLower(), special.Value.ToString());
|
||||
envStringPaths.Add(special.Key.ToString().ToLower(), path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,13 +34,19 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
|
||||
var querySearch = query.Search;
|
||||
|
||||
var quickFolderLinks = quickFolderAccess.FolderList(query, settings.QuickFolderAccessLinks, context);
|
||||
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)
|
||||
return quickFolderLinks;
|
||||
|
||||
if (string.IsNullOrEmpty(querySearch))
|
||||
return results;
|
||||
results.AddRange(quickFolderLinks);
|
||||
|
||||
var isEnvironmentVariable = EnvironmentVariables.IsEnvironmentVariableSearch(querySearch);
|
||||
|
||||
|
|
@ -51,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;
|
||||
|
||||
|
|
@ -74,6 +84,24 @@ namespace Flow.Launcher.Plugin.Explorer.Search
|
|||
return results;
|
||||
}
|
||||
|
||||
private List<Result> WindowsIndexFileContentSearch(Query query, string querySearchString)
|
||||
{
|
||||
var queryConstructor = new QueryConstructor(settings);
|
||||
|
||||
if (string.IsNullOrEmpty(querySearchString))
|
||||
return new List<Result>();
|
||||
|
||||
return indexSearch.WindowsIndexSearch(querySearchString,
|
||||
queryConstructor.CreateQueryHelper().ConnectionString,
|
||||
queryConstructor.QueryForFileContentSearch,
|
||||
query);
|
||||
}
|
||||
|
||||
public bool IsFileContentSearch(string actionKeyword)
|
||||
{
|
||||
return actionKeyword == settings.FileContentSearchActionKeyword;
|
||||
}
|
||||
|
||||
private List<Result> DirectoryInfoClassSearch(Query query, string querySearch)
|
||||
{
|
||||
var directoryInfoSearch = new DirectoryInfoSearch(context);
|
||||
|
|
@ -116,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,17 +51,24 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
{
|
||||
if (dataReaderResults.GetValue(0) != DBNull.Value && dataReaderResults.GetValue(1) != DBNull.Value)
|
||||
{
|
||||
// # is URI syntax for the fragment component, need to be encoded so LocalPath returns complete path
|
||||
var encodedFragmentPath = dataReaderResults
|
||||
.GetString(1)
|
||||
.Replace("#", "%23", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var path = new Uri(encodedFragmentPath).LocalPath;
|
||||
|
||||
if (dataReaderResults.GetString(2) == "Directory")
|
||||
{
|
||||
folderResults.Add(resultManager.CreateFolderResult(
|
||||
dataReaderResults.GetString(0),
|
||||
dataReaderResults.GetString(1),
|
||||
dataReaderResults.GetString(1),
|
||||
path,
|
||||
path,
|
||||
query, true, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
fileResults.Add(resultManager.CreateFileResult(dataReaderResults.GetString(1), query, true, true));
|
||||
fileResults.Add(resultManager.CreateFileResult(path, query, true, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
baseQuery.QueryMaxResults = settings.MaxResult;
|
||||
|
||||
// Set list of columns we want to display, getting the path presently
|
||||
baseQuery.QuerySelectColumns = "System.FileName, System.ItemPathDisplay, System.ItemType";
|
||||
baseQuery.QuerySelectColumns = "System.FileName, System.ItemUrl, System.ItemType";
|
||||
|
||||
// Filter based on file name
|
||||
baseQuery.QueryContentProperties = "System.FileName";
|
||||
|
|
@ -117,5 +117,23 @@ namespace Flow.Launcher.Plugin.Explorer.Search.WindowsIndex
|
|||
{
|
||||
return $"scope='file:'";
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Search will be performed on all indexed file contents for the specified search keywords.
|
||||
///</summary>
|
||||
public string QueryForFileContentSearch(string userSearchString)
|
||||
{
|
||||
string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
|
||||
|
||||
return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch();
|
||||
}
|
||||
|
||||
///<summary>
|
||||
/// Set the required WHERE clause restriction to search within file content.
|
||||
///</summary>
|
||||
public string QueryWhereRestrictionsForFileContentSearch(string searchQuery)
|
||||
{
|
||||
return $"FREETEXT('{searchQuery}')";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
@ -17,5 +18,11 @@ namespace Flow.Launcher.Plugin.Explorer
|
|||
|
||||
[JsonProperty]
|
||||
public List<FolderLink> IndexSearchExcludedSubdirectoryPaths { get; set; } = new List<FolderLink>();
|
||||
|
||||
[JsonProperty]
|
||||
public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
|
||||
|
||||
[JsonProperty]
|
||||
public string FileContentSearchActionKeyword { get; set; } = Constants.DefaultContentSearchActionKeyword;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Plugin.Explorer.Search;
|
||||
using Flow.Launcher.Plugin.Explorer.Search.FolderLinks;
|
||||
using System.Diagnostics;
|
||||
|
|
@ -40,5 +41,20 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
|
|||
|
||||
Process.Start(psi);
|
||||
}
|
||||
|
||||
internal void UpdateActionKeyword(string newActionKeyword, string oldActionKeyword)
|
||||
{
|
||||
PluginManager.ReplaceActionKeyword(Context.CurrentPluginMetadata.ID, oldActionKeyword, newActionKeyword);
|
||||
|
||||
if (Settings.FileContentSearchActionKeyword == oldActionKeyword)
|
||||
Settings.FileContentSearchActionKeyword = newActionKeyword;
|
||||
|
||||
if (Settings.SearchActionKeyword == oldActionKeyword)
|
||||
Settings.SearchActionKeyword = newActionKeyword;
|
||||
}
|
||||
|
||||
internal bool IsActionKeywordAlreadyAssigned(string newActionKeyword) => PluginManager.ActionKeywordRegistered(newActionKeyword);
|
||||
|
||||
internal bool IsNewActionKeywordGlobal(string newActionKeyword) => newActionKeyword == Query.GlobalPluginWildcardSign;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
<Window x:Class="Flow.Launcher.Plugin.Explorer.Views.ActionKeywordSetting"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Flow.Launcher.Plugin.Explorer.Views"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="NoResize"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Title="Action Keyword Setting" Height="200" Width="500">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="180" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Margin="20 10 10 10" FontSize="14" Grid.Row="0" Grid.Column="0" VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left" Text="Current Action Keyword:" />
|
||||
<TextBox Name="txtCurrentActionKeyword"
|
||||
Margin="10" Grid.Row="0" Width="105" Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Row="1" Grid.Column="1">
|
||||
<Button Click="OnConfirmButtonClick"
|
||||
Margin="10 0 10 0" Width="80" Height="35"
|
||||
Content="OK" />
|
||||
<Button Click="OnCancelButtonClick"
|
||||
Margin="10 0 10 0" Width="80" Height="35"
|
||||
Content="Cancel" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
using Flow.Launcher.Plugin.Explorer.ViewModels;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Explorer.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ActionKeywordSetting.xaml
|
||||
/// </summary>
|
||||
public partial class ActionKeywordSetting : Window
|
||||
{
|
||||
private SettingsViewModel settingsViewModel;
|
||||
|
||||
private ActionKeywordView currentActionKeyword;
|
||||
|
||||
private List<ActionKeywordView> actionKeywordListView;
|
||||
|
||||
public ActionKeywordSetting(SettingsViewModel settingsViewModel, List<ActionKeywordView> actionKeywordListView, ActionKeywordView selectedActionKeyword)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.settingsViewModel = settingsViewModel;
|
||||
|
||||
currentActionKeyword = selectedActionKeyword;
|
||||
|
||||
txtCurrentActionKeyword.Text = selectedActionKeyword.Keyword;
|
||||
|
||||
this.actionKeywordListView = actionKeywordListView;
|
||||
}
|
||||
|
||||
private void OnConfirmButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var newActionKeyword = txtCurrentActionKeyword.Text;
|
||||
|
||||
if (string.IsNullOrEmpty(newActionKeyword))
|
||||
return;
|
||||
|
||||
if (newActionKeyword == currentActionKeyword.Keyword)
|
||||
{
|
||||
Close();
|
||||
|
||||
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))
|
||||
{
|
||||
settingsViewModel.UpdateActionKeyword(newActionKeyword, currentActionKeyword.Keyword);
|
||||
|
||||
actionKeywordListView.Where(x => x.Description == currentActionKeyword.Description).FirstOrDefault().Keyword = newActionKeyword;
|
||||
|
||||
Close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MessageBox.Show(settingsViewModel.Context.API.GetTranslation("newActionKeywordsHasBeenAssigned"));
|
||||
}
|
||||
|
||||
private void OnCancelButtonClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Close();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<UserControl x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings"
|
||||
<UserControl x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
|
|
@ -17,6 +17,16 @@
|
|||
Text="{Binding Nickname, Mode=OneTime}"
|
||||
Margin="0,5,0,5" />
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="ListViewActionKeywords">
|
||||
<Grid>
|
||||
<TextBlock
|
||||
Text="{Binding Description, Mode=OneTime}"
|
||||
Margin="0,5,0,0" />
|
||||
<TextBlock
|
||||
Text="{Binding Keyword, Mode=OneTime}"
|
||||
Margin="150,5,0,0" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
|
|
@ -25,8 +35,14 @@
|
|||
</Grid.RowDefinitions>
|
||||
<ScrollViewer Margin="20 35 0 0" HorizontalScrollBarVisibility="Hidden" Grid.Row="0" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
<Expander Name="expActionKeywords" Header="{DynamicResource plugin_explorer_manageactionkeywords_header}"
|
||||
Expanded="expActionKeywords_Click" Collapsed="expActionKeywords_Collapsed">
|
||||
<ListView x:Name="lbxActionKeywords"
|
||||
ItemTemplate="{StaticResource ListViewActionKeywords}"/>
|
||||
</Expander>
|
||||
<Expander Name="expFolderLinks" Header="{DynamicResource plugin_explorer_quickfolderaccess_header}"
|
||||
Expanded="expFolderLinks_Click" Collapsed="expFolderLinks_Click">
|
||||
Expanded="expFolderLinks_Click" Collapsed="expFolderLinks_Collapsed"
|
||||
Margin="0 10 0 0">
|
||||
<ListView
|
||||
x:Name="lbxFolderLinks" AllowDrop="True"
|
||||
Drop="lbxFolders_Drop"
|
||||
|
|
@ -34,7 +50,7 @@
|
|||
ItemTemplate="{StaticResource ListViewTemplateFolderLinks}"/>
|
||||
</Expander>
|
||||
<Expander x:Name="expExcludedPaths" Header="{DynamicResource plugin_explorer_indexsearchexcludedpaths_header}"
|
||||
Expanded="expExcludedPaths_Click" Collapsed="expExcludedPaths_Click"
|
||||
Expanded="expExcludedPaths_Click"
|
||||
Margin="0 10 0 0">
|
||||
<ListView
|
||||
x:Name="lbxExcludedPaths" AllowDrop="True"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
public partial class ExplorerSettings
|
||||
{
|
||||
private readonly SettingsViewModel viewModel;
|
||||
|
||||
private List<ActionKeywordView> actionKeywordsListView;
|
||||
|
||||
public ExplorerSettings(SettingsViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
|
@ -30,6 +33,22 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
lbxExcludedPaths.ItemsSource = this.viewModel.Settings.IndexSearchExcludedSubdirectoryPaths;
|
||||
|
||||
actionKeywordsListView = new List<ActionKeywordView>
|
||||
{
|
||||
new ActionKeywordView()
|
||||
{
|
||||
Description = viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_search"),
|
||||
Keyword = this.viewModel.Settings.SearchActionKeyword
|
||||
},
|
||||
new ActionKeywordView()
|
||||
{
|
||||
Description = viewModel.Context.API.GetTranslation("plugin_explorer_actionkeywordview_filecontentsearch"),
|
||||
Keyword = this.viewModel.Settings.FileContentSearchActionKeyword
|
||||
}
|
||||
};
|
||||
|
||||
lbxActionKeywords.ItemsSource = actionKeywordsListView;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
|
|
@ -43,9 +62,14 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
btnEdit.Visibility = Visibility.Hidden;
|
||||
btnAdd.Visibility = Visibility.Hidden;
|
||||
|
||||
if (expFolderLinks.IsExpanded || expExcludedPaths.IsExpanded)
|
||||
if (expFolderLinks.IsExpanded || expExcludedPaths.IsExpanded || expActionKeywords.IsExpanded)
|
||||
{
|
||||
btnAdd.Visibility = Visibility.Visible;
|
||||
if (!expActionKeywords.IsExpanded)
|
||||
btnAdd.Visibility = Visibility.Visible;
|
||||
|
||||
if (expActionKeywords.IsExpanded
|
||||
&& btnEdit.Visibility == Visibility.Hidden)
|
||||
btnEdit.Visibility = Visibility.Visible;
|
||||
|
||||
if ((lbxFolderLinks.Items.Count == 0 && lbxExcludedPaths.Items.Count == 0)
|
||||
&& btnDelete.Visibility == Visibility.Visible
|
||||
|
|
@ -77,22 +101,50 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
lbxFolderLinks.Items.Refresh();
|
||||
|
||||
lbxExcludedPaths.Items.Refresh();
|
||||
|
||||
lbxActionKeywords.Items.Refresh();
|
||||
}
|
||||
|
||||
private void expActionKeywords_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.Height = 215;
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expExcludedPaths.IsExpanded = false;
|
||||
|
||||
if (expFolderLinks.IsExpanded)
|
||||
expFolderLinks.IsExpanded = false;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void expActionKeywords_Collapsed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!expActionKeywords.IsExpanded)
|
||||
expActionKeywords.Height = Double.NaN;
|
||||
}
|
||||
|
||||
private void expFolderLinks_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expFolderLinks.IsExpanded)
|
||||
expFolderLinks.Height = 235;
|
||||
|
||||
if (!expFolderLinks.IsExpanded)
|
||||
expFolderLinks.Height = Double.NaN;
|
||||
expFolderLinks.Height = 215;
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
expExcludedPaths.IsExpanded = false;
|
||||
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.IsExpanded = false;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private void expFolderLinks_Collapsed(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!expFolderLinks.IsExpanded)
|
||||
expFolderLinks.Height = Double.NaN;
|
||||
}
|
||||
|
||||
private void expExcludedPaths_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
|
|
@ -101,6 +153,9 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
if (expFolderLinks.IsExpanded)
|
||||
expFolderLinks.IsExpanded = false;
|
||||
|
||||
if (expActionKeywords.IsExpanded)
|
||||
expActionKeywords.IsExpanded = false;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
|
|
@ -132,33 +187,46 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
|
||||
private void btnEdit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var selectedRow = lbxFolderLinks.SelectedItem as FolderLink ?? lbxExcludedPaths.SelectedItem as FolderLink;
|
||||
|
||||
if (selectedRow != null)
|
||||
if (lbxActionKeywords.SelectedItem is ActionKeywordView)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
folderBrowserDialog.SelectedPath = selectedRow.Path;
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (expFolderLinks.IsExpanded)
|
||||
{
|
||||
var link = viewModel.Settings.QuickFolderAccessLinks.First(x => x.Path == selectedRow.Path);
|
||||
link.Path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
var selectedActionKeyword = lbxActionKeywords.SelectedItem as ActionKeywordView;
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
{
|
||||
var link = viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.First(x => x.Path == selectedRow.Path);
|
||||
link.Path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
var actionKeywordWindow = new ActionKeywordSetting(viewModel, actionKeywordsListView, selectedActionKeyword);
|
||||
|
||||
actionKeywordWindow.ShowDialog();
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
else
|
||||
{
|
||||
string warning = viewModel.Context.API.GetTranslation("plugin_explorer_select_folder_link_warning");
|
||||
MessageBox.Show(warning);
|
||||
var selectedRow = lbxFolderLinks.SelectedItem as FolderLink ?? lbxExcludedPaths.SelectedItem as FolderLink;
|
||||
|
||||
if (selectedRow != null)
|
||||
{
|
||||
var folderBrowserDialog = new FolderBrowserDialog();
|
||||
folderBrowserDialog.SelectedPath = selectedRow.Path;
|
||||
if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
if (expFolderLinks.IsExpanded)
|
||||
{
|
||||
var link = viewModel.Settings.QuickFolderAccessLinks.First(x => x.Path == selectedRow.Path);
|
||||
link.Path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
|
||||
if (expExcludedPaths.IsExpanded)
|
||||
{
|
||||
var link = viewModel.Settings.IndexSearchExcludedSubdirectoryPaths.First(x => x.Path == selectedRow.Path);
|
||||
link.Path = folderBrowserDialog.SelectedPath;
|
||||
}
|
||||
}
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
else
|
||||
{
|
||||
string warning = viewModel.Context.API.GetTranslation("plugin_explorer_make_selection_warning");
|
||||
MessageBox.Show(warning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -242,4 +310,11 @@ namespace Flow.Launcher.Plugin.Explorer.Views
|
|||
viewModel.OpenWindowsIndexingOptions();
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionKeywordView
|
||||
{
|
||||
public string Description { get; set; }
|
||||
|
||||
public string Keyword { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
{
|
||||
"ID": "572be03c74c642baae319fc283e561a8",
|
||||
"ActionKeyword": "*",
|
||||
"ActionKeywords": [
|
||||
"*",
|
||||
"doc:"
|
||||
],
|
||||
"Name": "Explorer",
|
||||
"Description": "Search and manage files and folders. Explorer utilises Windows Index Search",
|
||||
"Author": "Jeremy Wu",
|
||||
"Version": "1.1.0",
|
||||
"Version": "1.2.4",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Explorer.dll",
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
<system:String x:Key="flowlauncher_plugin_processkiller_plugin_name">Process Killer</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_processkiller_plugin_description">Kill running processes from Flow Launcher</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_processkiller_kill_all">kill all "{0}" processes</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_processkiller_kill_all">kill all instances of "{0}"</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_processkiller_kill_all_count">kill {0} processes</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_processkiller_kill_instances">kill all instances</system:String>
|
||||
|
||||
</ResourceDictionary>
|
||||
|
|
@ -52,21 +52,24 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
// get all non-system processes whose file path matches that of the given result (processPath)
|
||||
var similarProcesses = processHelper.GetSimilarProcesses(processPath);
|
||||
|
||||
menuOptions.Add(new Result
|
||||
if (similarProcesses.Count() > 0)
|
||||
{
|
||||
Title = _context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_instances"),
|
||||
SubTitle = processPath,
|
||||
Action = _ =>
|
||||
menuOptions.Add(new Result
|
||||
{
|
||||
foreach (var p in similarProcesses)
|
||||
Title = _context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_instances"),
|
||||
SubTitle = processPath,
|
||||
Action = _ =>
|
||||
{
|
||||
processHelper.TryKill(p);
|
||||
}
|
||||
foreach (var p in similarProcesses)
|
||||
{
|
||||
processHelper.TryKill(p);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
IcoPath = processPath
|
||||
});
|
||||
return true;
|
||||
},
|
||||
IcoPath = processPath
|
||||
});
|
||||
}
|
||||
|
||||
return menuOptions;
|
||||
}
|
||||
|
|
@ -86,6 +89,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
SubTitle = path,
|
||||
TitleHighlightData = StringMatcher.FuzzySearch(termToSearch, p.ProcessName).MatchData,
|
||||
Score = pr.Score,
|
||||
ContextData = p.ProcessName,
|
||||
Action = (c) =>
|
||||
{
|
||||
processHelper.TryKill(p);
|
||||
|
|
@ -94,16 +98,18 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
});
|
||||
}
|
||||
|
||||
var sortedResults = results.OrderBy(x => x.Title).ToList();
|
||||
|
||||
// When there are multiple results AND all of them are instances of the same executable
|
||||
// add a quick option to kill them all at the top of the results.
|
||||
var firstResult = results.FirstOrDefault()?.SubTitle;
|
||||
if (processlist.Count > 1 && !string.IsNullOrEmpty(termToSearch) && results.All(r => r.SubTitle == firstResult))
|
||||
var firstResult = sortedResults.FirstOrDefault(x => !string.IsNullOrEmpty(x.SubTitle));
|
||||
if (processlist.Count > 1 && !string.IsNullOrEmpty(termToSearch) && sortedResults.All(r => r.SubTitle == firstResult?.SubTitle))
|
||||
{
|
||||
results.Insert(0, new Result()
|
||||
sortedResults.Insert(1, new Result()
|
||||
{
|
||||
IcoPath = "Images/app.png",
|
||||
Title = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all"), termToSearch),
|
||||
SubTitle = "",
|
||||
IcoPath = firstResult?.IcoPath,
|
||||
Title = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all"), firstResult?.ContextData),
|
||||
SubTitle = string.Format(_context.API.GetTranslation("flowlauncher_plugin_processkiller_kill_all_count"), processlist.Count),
|
||||
Score = 200,
|
||||
Action = (c) =>
|
||||
{
|
||||
|
|
@ -117,7 +123,7 @@ namespace Flow.Launcher.Plugin.ProcessKiller
|
|||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
return sortedResults;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Name":"Process Killer",
|
||||
"Description":"kill running processes from Flow",
|
||||
"Author":"Flow-Launcher",
|
||||
"Version":"1.0.0",
|
||||
"Version":"1.1.0",
|
||||
"Language":"csharp",
|
||||
"Website":"https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller",
|
||||
"IcoPath":"Images\\app.png",
|
||||
|
|
|
|||
|
|
@ -40,7 +40,12 @@
|
|||
<system:String x:Key="flowlauncher_plugin_program_plugin_description">Search programs in Flow Launcher</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_program_invalid_path">Invalid Path</system:String>
|
||||
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_program_customizedexplorer">Customized Explorer</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_program_args">Args</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_program_tooltip_customizedexplorer">You can customized the explorer used for opening the container folder by inputing the Environmental Variable of the explorer you want to use. It will be useful to use CMD to test whether the Environmental Variable is avaliable.</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_program_tooltip_args">Enter the customized args you want to add for your customized explorer. %s for parent directory, %f for full path (which only works for win32). Check the explorer's website for details.</system:String>
|
||||
|
||||
<!--Dialogs-->
|
||||
<system:String x:Key="flowlauncher_plugin_program_disable_dlgtitle_success">Success</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_program_disable_dlgtitle_success_message">Successfully disabled this program from displaying in your query</system:String>
|
||||
|
|
|
|||
|
|
@ -324,7 +324,9 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
Action = _ =>
|
||||
{
|
||||
Main.StartProcess(Process.Start, new ProcessStartInfo(Package.Location));
|
||||
Main.StartProcess(Process.Start, new ProcessStartInfo(
|
||||
!string.IsNullOrEmpty(Main._settings.CustomizedExplorer) ? Main._settings.CustomizedExplorer:Settings.Explorer,
|
||||
Main._settings.CustomizedArgs.Replace("%s",$"\"{Package.Location}\"").Trim()));
|
||||
|
||||
return true;
|
||||
},
|
||||
|
|
@ -536,7 +538,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
ProgramLogger.LogException($"|UWP|ImageFromPath|{path}" +
|
||||
$"|Unable to get logo for {UserModelId} from {path} and" +
|
||||
$" located in {Package.Location}", new FileNotFoundException());
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
return new BitmapImage(new Uri(Constant.MissingImgIcon));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -586,7 +588,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
$"|Unable to convert background string {BackgroundColor} " +
|
||||
$"to color for {Package.Location}", new InvalidOperationException());
|
||||
|
||||
return new BitmapImage(new Uri(Constant.ErrorIcon));
|
||||
return new BitmapImage(new Uri(Constant.MissingImgIcon));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -140,10 +140,19 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
Title = api.GetTranslation("flowlauncher_plugin_program_open_containing_folder"),
|
||||
Action = _ =>
|
||||
{
|
||||
var args = !string.IsNullOrWhiteSpace(Main._settings.CustomizedArgs)
|
||||
?Main._settings.CustomizedArgs
|
||||
.Replace("%s",$"\"{ParentDirectory}\"")
|
||||
.Replace("%f",$"\"{FullPath}\""):
|
||||
Main._settings.CustomizedExplorer==Settings.Explorer
|
||||
? $"/select,\"{FullPath}\""
|
||||
: Settings.ExplorerArgs;
|
||||
|
||||
|
||||
Main.StartProcess(Process.Start, new ProcessStartInfo("explorer", ParentDirectory));
|
||||
|
||||
Main.StartProcess(Process.Start, new ProcessStartInfo(
|
||||
!string.IsNullOrWhiteSpace(Main._settings.CustomizedExplorer)
|
||||
? Main._settings.CustomizedExplorer
|
||||
: Settings.Explorer,
|
||||
args));
|
||||
return true;
|
||||
},
|
||||
IcoPath = "Images/folder.png"
|
||||
|
|
|
|||
|
|
@ -14,9 +14,15 @@ namespace Flow.Launcher.Plugin.Program
|
|||
public bool EnableStartMenuSource { get; set; } = true;
|
||||
|
||||
public bool EnableRegistrySource { get; set; } = true;
|
||||
public string CustomizedExplorer { get; set; } = Explorer;
|
||||
public string CustomizedArgs { get; set; } = ExplorerArgs;
|
||||
|
||||
internal const char SuffixSeperator = ';';
|
||||
|
||||
internal const string Explorer = "explorer";
|
||||
|
||||
internal const string ExplorerArgs = "%s";
|
||||
|
||||
/// <summary>
|
||||
/// Contains user added folder location contents as well as all user disabled applications
|
||||
/// </summary>
|
||||
|
|
|
|||
|
|
@ -5,12 +5,13 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:program="clr-namespace:Flow.Launcher.Plugin.Program"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="600">
|
||||
d:DesignHeight="404.508" d:DesignWidth="600">
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="75"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="50"/>
|
||||
<RowDefinition Height="50"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical" Width="205">
|
||||
|
|
@ -24,7 +25,7 @@
|
|||
</StackPanel>
|
||||
</StackPanel>
|
||||
<ListView x:Name="programSourceView" Grid.Row="1" AllowDrop="True" SelectionMode="Extended" Style="{StaticResource {x:Static GridView.GridViewStyleKey}}"
|
||||
Margin="0 13 0 0"
|
||||
Margin="0,13,0,10"
|
||||
BorderBrush="DarkGray"
|
||||
BorderThickness="1"
|
||||
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"
|
||||
|
|
@ -63,7 +64,7 @@
|
|||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
<DockPanel Grid.Row="2">
|
||||
<DockPanel Grid.Row="2" Margin="0,0,0,0" Grid.RowSpan="1">
|
||||
<StackPanel x:Name="indexingPanel" Visibility="Hidden" HorizontalAlignment="Left" Orientation="Horizontal">
|
||||
<ProgressBar x:Name="progressBarIndexing" Height="20" Width="80" Minimum="0" Maximum="100" IsIndeterminate="True" />
|
||||
<TextBlock Margin="10 0 0 0" Height="20" HorizontalAlignment="Center" Text="{DynamicResource flowlauncher_plugin_program_indexing}" />
|
||||
|
|
@ -71,9 +72,18 @@
|
|||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||
<Button x:Name="btnProgramSourceStatus" Click="btnProgramSourceStatus_OnClick" Width="100" Margin="10" Content="{DynamicResource flowlauncher_plugin_program_disable}" />
|
||||
<Button x:Name="btnEditProgramSource" Click="btnEditProgramSource_OnClick" Width="100" Margin="10" Content="{DynamicResource flowlauncher_plugin_program_edit}"/>
|
||||
<Button x:Name="btnAddProgramSource" Click="btnAddProgramSource_OnClick" Width="100" Margin="10" Content="{DynamicResource flowlauncher_plugin_program_add}"/>
|
||||
<Button x:Name="btnAddProgramSource" Click="btnAddProgramSource_OnClick" Width="100" Margin="10 10 0 10" Content="{DynamicResource flowlauncher_plugin_program_add}"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Stretch">
|
||||
<TextBlock Text="{DynamicResource flowlauncher_plugin_program_customizedexplorer}" VerticalAlignment="Center" FontSize="15"
|
||||
ToolTip= "{DynamicResource flowlauncher_plugin_program_tooltip_customizedexplorer}"/>
|
||||
<TextBox Margin="10,0,10,0" TextWrapping="NoWrap" VerticalAlignment="Center" Width="200" Height="30" FontSize="15"
|
||||
TextChanged="CustomizeExplorer" x:Name="CustomizeExplorerBox"/>
|
||||
<TextBlock Text="{DynamicResource flowlauncher_plugin_program_args}" VerticalAlignment="Center" FontSize="15"
|
||||
ToolTip="{DynamicResource flowlauncher_plugin_program_tooltip_args}" />
|
||||
<TextBox Margin="10,0,0,0" Width="135" Height="30" FontSize="15" x:Name="CustomizeArgsBox" TextChanged="CustomizeExplorerArgs"></TextBox>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,9 @@ namespace Flow.Launcher.Plugin.Program.Views
|
|||
StartMenuEnabled.IsChecked = _settings.EnableStartMenuSource;
|
||||
RegistryEnabled.IsChecked = _settings.EnableRegistrySource;
|
||||
|
||||
CustomizeExplorerBox.Text = _settings.CustomizedExplorer;
|
||||
CustomizeArgsBox.Text = _settings.CustomizedArgs;
|
||||
|
||||
ViewRefresh();
|
||||
}
|
||||
|
||||
|
|
@ -326,5 +329,15 @@ namespace Flow.Launcher.Plugin.Program.Views
|
|||
btnProgramSourceStatus.Content = "Enable";
|
||||
}
|
||||
}
|
||||
|
||||
private void CustomizeExplorer(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
_settings.CustomizedExplorer = CustomizeExplorerBox.Text;
|
||||
}
|
||||
|
||||
private void CustomizeExplorerArgs(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
_settings.CustomizedArgs = CustomizeArgsBox.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
"Name": "Program",
|
||||
"Description": "Search programs in Flow.Launcher",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "1.0.0",
|
||||
"Version": "1.1.0",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
<system:String x:Key="flowlauncher_plugin_websearch_input_url">Please enter a URL</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_websearch_action_keyword_exist">Action keyword already exists, please enter a different one</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_websearch_succeed">Success</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_websearch_iconpath_hint">Hint: You do not need to place custom images in this directory, if Flow's version is updated they will be lost. Flow will automatically copy any images outside of this directory across to WebSearch's custom image location.</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_websearch_plugin_name">Web Searches</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_websearch_plugin_description">Allows to perform web searches</system:String>
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
|
||||
namespace Flow.Launcher.Plugin.WebSearch
|
||||
|
|
@ -21,8 +22,9 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
private CancellationTokenSource _updateSource;
|
||||
private CancellationToken _updateToken;
|
||||
|
||||
public const string Images = "Images";
|
||||
public static string ImagesDirectory;
|
||||
internal const string Images = "Images";
|
||||
internal static string DefaultImagesDirectory;
|
||||
internal static string CustomImagesDirectory;
|
||||
|
||||
private readonly string SearchSourceGlobalPluginWildCardSign = "*";
|
||||
|
||||
|
|
@ -172,8 +174,14 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
_context = context;
|
||||
var pluginDirectory = _context.CurrentPluginMetadata.PluginDirectory;
|
||||
var bundledImagesDirectory = Path.Combine(pluginDirectory, Images);
|
||||
ImagesDirectory = Path.Combine(_context.CurrentPluginMetadata.PluginDirectory, Images);
|
||||
Helper.ValidateDataDirectory(bundledImagesDirectory, ImagesDirectory);
|
||||
|
||||
// Default images directory is in the WebSearch's application folder
|
||||
DefaultImagesDirectory = Path.Combine(pluginDirectory, Images);
|
||||
Helper.ValidateDataDirectory(bundledImagesDirectory, DefaultImagesDirectory);
|
||||
|
||||
// Custom images directory is in the WebSearch's data location folder
|
||||
var name = Path.GetFileNameWithoutExtension(_context.CurrentPluginMetadata.ExecuteFileName);
|
||||
CustomImagesDirectory = Path.Combine(DataLocation.PluginSettingsDirectory, name, "CustomIcons");
|
||||
}
|
||||
|
||||
#region ISettingProvider Members
|
||||
|
|
|
|||
|
|
@ -1,29 +1,38 @@
|
|||
using System.IO;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
using JetBrains.Annotations;
|
||||
using Newtonsoft.Json;
|
||||
using Flow.Launcher.Infrastructure.Image;
|
||||
using Flow.Launcher.Infrastructure;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Flow.Launcher.Plugin.WebSearch
|
||||
{
|
||||
public class SearchSource : BaseModel
|
||||
{
|
||||
public const string DefaultIcon = "web_search.png";
|
||||
public string Title { get; set; }
|
||||
public string ActionKeyword { get; set; }
|
||||
|
||||
[NotNull]
|
||||
public string Icon { get; set; } = DefaultIcon;
|
||||
public string Icon { get; set; } = "web_search.png";
|
||||
|
||||
public bool CustomIcon { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// All icon should be put under Images directory
|
||||
/// Default icons are placed in Images directory in the app location.
|
||||
/// Custom icons are placed in the user data directory
|
||||
/// </summary>
|
||||
[NotNull]
|
||||
[JsonIgnore]
|
||||
internal string IconPath => Path.Combine(Main.ImagesDirectory, Icon);
|
||||
public string IconPath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (CustomIcon)
|
||||
return Path.Combine(Main.CustomImagesDirectory, Icon);
|
||||
|
||||
[JsonIgnore]
|
||||
public ImageSource Image => ImageLoader.Load(IconPath);
|
||||
return Path.Combine(Main.DefaultImagesDirectory, Icon);
|
||||
}
|
||||
}
|
||||
|
||||
public string Url { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
|
|
@ -36,6 +45,7 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
ActionKeyword = string.Copy(ActionKeyword),
|
||||
Url = string.Copy(Url),
|
||||
Icon = string.Copy(Icon),
|
||||
CustomIcon = CustomIcon,
|
||||
Enabled = Enabled
|
||||
};
|
||||
return webSearch;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
<TextBlock Margin="10" FontSize="14" Grid.Row="4" Grid.Column="0" VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right" Text="{DynamicResource flowlauncher_plugin_websearch_icon}" />
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="4" Grid.Column="1" Margin="10">
|
||||
<Image Source="{Binding SearchSource.Image ,IsAsync=True}" Width="24" Height="24" Margin="0 0 20 0" />
|
||||
<Image Name="imgPreviewIcon" Width="24" Height="24" Margin="0 0 20 0" />
|
||||
<Button Click="OnSelectIconClick" Height="35"
|
||||
Content="{DynamicResource flowlauncher_plugin_websearch_select_icon}" />
|
||||
</StackPanel>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using Microsoft.Win32;
|
||||
using Flow.Launcher.Core.Plugin;
|
||||
|
|
@ -15,6 +14,7 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
private PluginInitContext _context;
|
||||
private IPublicAPI _api;
|
||||
private SearchSourceViewModel _viewModel;
|
||||
private string selectedNewIconImageFullPath;
|
||||
|
||||
|
||||
public SearchSourceSettingWindow(IList<SearchSource> sources, PluginInitContext context, SearchSource old)
|
||||
|
|
@ -39,6 +39,10 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
_action = action;
|
||||
_context = context;
|
||||
_api = _context.API;
|
||||
|
||||
_viewModel.SetupCustomImagesDirectory();
|
||||
|
||||
imgPreviewIcon.Source = _viewModel.LoadPreviewIcon(_searchSource.IconPath);
|
||||
}
|
||||
|
||||
private void OnCancelButtonClick(object sender, RoutedEventArgs e)
|
||||
|
|
@ -111,26 +115,32 @@ namespace Flow.Launcher.Plugin.WebSearch
|
|||
var warning = _api.GetTranslation("newActionKeywordsHasBeenAssigned");
|
||||
MessageBox.Show(warning);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedNewIconImageFullPath))
|
||||
{
|
||||
_viewModel.UpdateIconAttributes(_searchSource, selectedNewIconImageFullPath);
|
||||
|
||||
_viewModel.CopyNewImageToUserDataDirectoryIfRequired(
|
||||
_searchSource, selectedNewIconImageFullPath, _oldSearchSource.IconPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectIconClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var directory = Main.ImagesDirectory;
|
||||
const string filter = "Image files (*.jpg, *.jpeg, *.gif, *.png, *.bmp) |*.jpg; *.jpeg; *.gif; *.png; *.bmp";
|
||||
var dialog = new OpenFileDialog {InitialDirectory = directory, Filter = filter};
|
||||
var dialog = new OpenFileDialog {InitialDirectory = Main.CustomImagesDirectory, Filter = filter};
|
||||
|
||||
var result = dialog.ShowDialog();
|
||||
if (result == true)
|
||||
{
|
||||
var fullpath = dialog.FileName;
|
||||
if (!string.IsNullOrEmpty(fullpath))
|
||||
selectedNewIconImageFullPath = dialog.FileName;
|
||||
|
||||
if (!string.IsNullOrEmpty(selectedNewIconImageFullPath))
|
||||
{
|
||||
_searchSource.Icon = Path.GetFileName(fullpath);
|
||||
if (!File.Exists(_searchSource.IconPath))
|
||||
{
|
||||
_searchSource.Icon = SearchSource.DefaultIcon;
|
||||
MessageBox.Show($"The file should be put under {directory}");
|
||||
}
|
||||
if (_viewModel.ShouldProvideHint(selectedNewIconImageFullPath))
|
||||
MessageBox.Show(_api.GetTranslation("flowlauncher_plugin_websearch_iconpath_hint"));
|
||||
|
||||
imgPreviewIcon.Source = _viewModel.LoadPreviewIcon(selectedNewIconImageFullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,65 @@
|
|||
namespace Flow.Launcher.Plugin.WebSearch
|
||||
using Flow.Launcher.Infrastructure.Image;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Flow.Launcher.Plugin.WebSearch
|
||||
{
|
||||
public class SearchSourceViewModel
|
||||
public class SearchSourceViewModel : BaseModel
|
||||
{
|
||||
public SearchSource SearchSource { get; set; }
|
||||
|
||||
public void UpdateIconAttributes(SearchSource selectedSearchSource, string fullpathToSelectedImage)
|
||||
{
|
||||
var parentDirectorySelectedImg = Directory.GetParent(fullpathToSelectedImage).ToString();
|
||||
|
||||
selectedSearchSource.CustomIcon = parentDirectorySelectedImg != Main.DefaultImagesDirectory;
|
||||
|
||||
var iconFileName = Path.GetFileName(fullpathToSelectedImage);
|
||||
selectedSearchSource.Icon = iconFileName;
|
||||
}
|
||||
|
||||
public void CopyNewImageToUserDataDirectoryIfRequired(
|
||||
SearchSource selectedSearchSource, string fullpathToSelectedImage, string fullPathToOriginalImage)
|
||||
{
|
||||
var destinationFileNameFullPath = Path.Combine(Main.CustomImagesDirectory, Path.GetFileName(fullpathToSelectedImage));
|
||||
|
||||
var parentDirectorySelectedImg = Directory.GetParent(fullpathToSelectedImage).ToString();
|
||||
|
||||
if (parentDirectorySelectedImg != Main.CustomImagesDirectory && parentDirectorySelectedImg != Main.DefaultImagesDirectory)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Copy(fullpathToSelectedImage, destinationFileNameFullPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if DEBUG
|
||||
throw e;
|
||||
#else
|
||||
MessageBox.Show(string.Format("Copying the selected image file to {0} has failed, changes will now be reverted", destinationFileNameFullPath));
|
||||
UpdateIconAttributes(selectedSearchSource, fullPathToOriginalImage);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetupCustomImagesDirectory()
|
||||
{
|
||||
if (!Directory.Exists(Main.CustomImagesDirectory))
|
||||
Directory.CreateDirectory(Main.CustomImagesDirectory);
|
||||
}
|
||||
|
||||
internal bool ShouldProvideHint(string fullPathToSelectedImage)
|
||||
{
|
||||
return Directory.GetParent(fullPathToSelectedImage).ToString() == Main.DefaultImagesDirectory;
|
||||
}
|
||||
|
||||
internal ImageSource LoadPreviewIcon(string pathToPreviewIconImage)
|
||||
{
|
||||
return ImageLoader.Load(pathToPreviewIconImage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
"Name": "Web Searches",
|
||||
"Description": "Provide the web search ability",
|
||||
"Author": "qianlifeng",
|
||||
"Version": "1.0.0",
|
||||
"Version": "1.0.1",
|
||||
"Language": "csharp",
|
||||
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
|
||||
"ExecuteFileName": "Flow.Launcher.Plugin.WebSearch.dll",
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
[](https://github.com/Flow-Launcher/Flow.Launcher/releases)
|
||||
[](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest)
|
||||

|
||||
[](https://discord.gg/AvgAQgh)
|
||||
|
||||
Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at being more than an app launcher, it searches, integrates and expands on functionalities. Flow will continue to evolve, designed to be open and built with the community at heart.
|
||||
|
||||
|
|
@ -16,6 +17,7 @@ Flow Launcher. Dedicated to make your workflow flow more seamlessly. Aimed at be
|
|||

|
||||
|
||||
- Search everything from applications, files, bookmarks, YouTube, Twitter and more. All from the comfort of your keyboard without ever touching the mouse.
|
||||
- Search for file contents
|
||||
- Support search using environment variable paths
|
||||
- Run batch and PowerShell commands as Administrator or a different user.
|
||||
- Support languages from Chinese to Italian and more.
|
||||
|
|
@ -58,6 +60,8 @@ Get in touch if you like to join the Flow-Launcher Team and help build this grea
|
|||
|
||||
Yes please, submit an issue to let us know.
|
||||
|
||||
**Join our community on [Discord](https://discord.gg/AvgAQgh)!**
|
||||
|
||||
## Developing/Debugging
|
||||
|
||||
Flow Launcher's target framework is .Net Core 3.1
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: AssemblyVersion("1.1.2")]
|
||||
[assembly: AssemblyFileVersion("1.1.2")]
|
||||
[assembly: AssemblyInformationalVersion("1.1.2")]
|
||||
[assembly: AssemblyVersion("1.3.1")]
|
||||
[assembly: AssemblyFileVersion("1.3.1")]
|
||||
[assembly: AssemblyInformationalVersion("1.3.1")]
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
version: '1.1.2.{build}'
|
||||
version: '1.3.1.{build}'
|
||||
|
||||
init:
|
||||
- ps: |
|
||||
|
|
|
|||