diff --git a/Doc/Default Icons/app_missing_img.png b/Doc/Default Icons/app_missing_img.png
new file mode 100644
index 000000000..b07eb4262
Binary files /dev/null and b/Doc/Default Icons/app_missing_img.png differ
diff --git a/Doc/Default Icons/app_missing_img_01.png b/Doc/Default Icons/app_missing_img_01.png
new file mode 100644
index 000000000..2cc466ed0
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_01.png differ
diff --git a/Doc/Default Icons/app_missing_img_01.svg b/Doc/Default Icons/app_missing_img_01.svg
new file mode 100644
index 000000000..88b84858a
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_01.svg
@@ -0,0 +1,44 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_02.png b/Doc/Default Icons/app_missing_img_02.png
new file mode 100644
index 000000000..285a68890
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_02.png differ
diff --git a/Doc/Default Icons/app_missing_img_02.svg b/Doc/Default Icons/app_missing_img_02.svg
new file mode 100644
index 000000000..190ecf469
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_02.svg
@@ -0,0 +1,44 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_03.png b/Doc/Default Icons/app_missing_img_03.png
new file mode 100644
index 000000000..11d5466f0
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_03.png differ
diff --git a/Doc/Default Icons/app_missing_img_03.svg b/Doc/Default Icons/app_missing_img_03.svg
new file mode 100644
index 000000000..904380091
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_03.svg
@@ -0,0 +1,44 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_buttons.png b/Doc/Default Icons/app_missing_img_buttons.png
new file mode 100644
index 000000000..62de71f21
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_buttons.png differ
diff --git a/Doc/Default Icons/app_missing_img_buttons.svg b/Doc/Default Icons/app_missing_img_buttons.svg
new file mode 100644
index 000000000..b9d5e1259
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_buttons.svg
@@ -0,0 +1,48 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_fluent.png b/Doc/Default Icons/app_missing_img_fluent.png
new file mode 100644
index 000000000..eafd1bb35
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_fluent.png differ
diff --git a/Doc/Default Icons/app_missing_img_fluent.svg b/Doc/Default Icons/app_missing_img_fluent.svg
new file mode 100644
index 000000000..7a201cdc3
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_fluent.svg
@@ -0,0 +1,49 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_huge.png b/Doc/Default Icons/app_missing_img_huge.png
new file mode 100644
index 000000000..70aea308d
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_huge.png differ
diff --git a/Doc/Default Icons/app_missing_img_huge.svg b/Doc/Default Icons/app_missing_img_huge.svg
new file mode 100644
index 000000000..874a9a0ca
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_huge.svg
@@ -0,0 +1,42 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_lightblue.png b/Doc/Default Icons/app_missing_img_lightblue.png
new file mode 100644
index 000000000..3b262fc9b
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_lightblue.png differ
diff --git a/Doc/Default Icons/app_missing_img_lightblue.svg b/Doc/Default Icons/app_missing_img_lightblue.svg
new file mode 100644
index 000000000..da713b413
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_lightblue.svg
@@ -0,0 +1,38 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_lightblue_buttons.png b/Doc/Default Icons/app_missing_img_lightblue_buttons.png
new file mode 100644
index 000000000..17de0a6fe
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_lightblue_buttons.png differ
diff --git a/Doc/Default Icons/app_missing_img_lightblue_buttons.svg b/Doc/Default Icons/app_missing_img_lightblue_buttons.svg
new file mode 100644
index 000000000..7251fb9f6
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_lightblue_buttons.svg
@@ -0,0 +1,42 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_minimal.png b/Doc/Default Icons/app_missing_img_minimal.png
new file mode 100644
index 000000000..e66ea6d6e
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_minimal.png differ
diff --git a/Doc/Default Icons/app_missing_img_minimal.svg b/Doc/Default Icons/app_missing_img_minimal.svg
new file mode 100644
index 000000000..d2b6d22fe
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_minimal.svg
@@ -0,0 +1,40 @@
+
+
+
diff --git a/Doc/Default Icons/app_missing_img_minimal_buttons.png b/Doc/Default Icons/app_missing_img_minimal_buttons.png
new file mode 100644
index 000000000..d4f240909
Binary files /dev/null and b/Doc/Default Icons/app_missing_img_minimal_buttons.png differ
diff --git a/Doc/Default Icons/app_missing_img_minimal_buttons.svg b/Doc/Default Icons/app_missing_img_minimal_buttons.svg
new file mode 100644
index 000000000..131ffadf8
--- /dev/null
+++ b/Doc/Default Icons/app_missing_img_minimal_buttons.svg
@@ -0,0 +1,42 @@
+
+
+
diff --git a/Doc/app_missing_img.png b/Doc/app_missing_img.png
new file mode 100644
index 000000000..11d5466f0
Binary files /dev/null and b/Doc/app_missing_img.png differ
diff --git a/Flow.Launcher.Core/Configuration/Portable.cs b/Flow.Launcher.Core/Configuration/Portable.cs
index 44e4434be..5bca087b8 100644
--- a/Flow.Launcher.Core/Configuration/Portable.cs
+++ b/Flow.Launcher.Core/Configuration/Portable.cs
@@ -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);
}
diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs
index 9ad6466e9..df336e14b 100644
--- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs
+++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs
@@ -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;
diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs
index 99d48275a..20df23e40 100644
--- a/Flow.Launcher.Core/Updater.cs
+++ b/Flow.Launcher.Core/Updater.cs
@@ -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}");
diff --git a/Flow.Launcher.Infrastructure/Alphabet.cs b/Flow.Launcher.Infrastructure/Alphabet.cs
deleted file mode 100644
index e0eb60de4..000000000
--- a/Flow.Launcher.Infrastructure/Alphabet.cs
+++ /dev/null
@@ -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 PinyinCache;
- private BinaryStorage> _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>("Pinyin");
-
- lock(_pinyinStorage)
- {
- var loaded = _pinyinStorage.TryLoad(new Dictionary());
-
- PinyinCache = new ConcurrentDictionary(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 ")]
- ///
- /// replace chinese character with pinyin, non chinese character won't be modified
- /// should be word or sentence, instead of single character. e.g. 微软
- ///
- 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;
- }
-
- ///
- /// 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
- /// should be word or sentence, instead of single character. e.g. 微软
- ///
- public string[][] PinyinCombination(string characters)
- {
- if (!_settings.ShouldUsePinyin || string.IsNullOrEmpty(characters))
- {
- return Empty2DStringArray;
- }
-
- if (!PinyinCache.ContainsKey(characters))
- {
- var allPinyins = new List();
- 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;
- }
- }
-}
diff --git a/Flow.Launcher.Infrastructure/Constant.cs b/Flow.Launcher.Infrastructure/Constant.cs
index a8c72fb12..c6a3b48f3 100644
--- a/Flow.Launcher.Infrastructure/Constant.cs
+++ b/Flow.Launcher.Infrastructure/Constant.cs
@@ -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;
diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
index 410d11536..d834bd2d3 100644
--- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
+++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
@@ -53,10 +53,10 @@
-
+
diff --git a/Flow.Launcher.Infrastructure/FuzzyMatcher.cs b/Flow.Launcher.Infrastructure/FuzzyMatcher.cs
deleted file mode 100644
index 3df719b28..000000000
--- a/Flow.Launcher.Infrastructure/FuzzyMatcher.cs
+++ /dev/null
@@ -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);
- }
- }
-}
diff --git a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs
index 29e13a2de..4ae62dacd 100644
--- a/Flow.Launcher.Infrastructure/Image/ImageLoader.cs
+++ b/Flow.Launcher.Infrastructure/Image/ImageLoader.cs
@@ -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)
diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs
new file mode 100644
index 000000000..38f1ab879
--- /dev/null
+++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs
@@ -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 _pinyinCache = new ConcurrentDictionary();
+ 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()));
+ }
+ }
+}
\ No newline at end of file
diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs
index 79ccfd7af..2a4270fb4 100644
--- a/Flow.Launcher.Infrastructure/StringMatcher.cs
+++ b/Flow.Launcher.Infrastructure/StringMatcher.cs
@@ -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
{
- ///
- /// prefix of match char, use for highlight
- ///
- [Obsolete("this is never used")]
- public string Prefix { get; set; } = "";
-
- ///
- /// suffix of match char, use for highlight
- ///
- [Obsolete("this is never used")]
- public string Suffix { get; set; } = "";
-
public bool IgnoreCase { get; set; } = true;
}
}
diff --git a/Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs b/Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs
index 310c1e33a..e93c341dc 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/DataLocation.cs
@@ -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);
}
}
diff --git a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
index 4c47ca425..ccd9beb86 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/PluginSettings.cs
@@ -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 ActionKeywords { get; set; } // a reference of the action keywords from plugin manager
///
diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index 4e1a8d7d8..837fe3b71 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -70,12 +70,6 @@ namespace Flow.Launcher.Infrastructure.UserSettings
public PluginsSettings PluginSettings { get; set; } = new PluginsSettings();
public ObservableCollection CustomPluginHotkeys { get; set; } = new ObservableCollection();
- [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
- }
}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin/Feature.cs b/Flow.Launcher.Plugin/Feature.cs
index 62da96c57..81839d816 100644
--- a/Flow.Launcher.Plugin/Feature.cs
+++ b/Flow.Launcher.Plugin/Feature.cs
@@ -11,23 +11,6 @@ namespace Flow.Launcher.Plugin
List 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);
- }
-
- ///
- /// Represent plugin query will be executed in UI thread directly. Don't do long-running operation in Query method if you implement this interface
- /// This will improve the performance of instant search like websearch or cmd plugin
- ///
- [Obsolete("Flow Launcher is fast enough now, executed on ui thread is no longer needed")]
- public interface IInstantQuery : IFeatures
- {
- bool IsInstantQuery(string query);
- }
-
///
/// Represent plugins that support internationalization
///
diff --git a/Flow.Launcher.Plugin/Features/IContextMenu.cs b/Flow.Launcher.Plugin/Features/IContextMenu.cs
deleted file mode 100644
index f60e02a69..000000000
--- a/Flow.Launcher.Plugin/Features/IContextMenu.cs
+++ /dev/null
@@ -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 { }
-}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin/Features/IExclusiveQuery.cs b/Flow.Launcher.Plugin/Features/IExclusiveQuery.cs
deleted file mode 100644
index 57eddd93e..000000000
--- a/Flow.Launcher.Plugin/Features/IExclusiveQuery.cs
+++ /dev/null
@@ -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 { }
-}
diff --git a/Flow.Launcher.Plugin/Features/IInstantQuery.cs b/Flow.Launcher.Plugin/Features/IInstantQuery.cs
deleted file mode 100644
index 465640ae9..000000000
--- a/Flow.Launcher.Plugin/Features/IInstantQuery.cs
+++ /dev/null
@@ -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 { }
-}
\ No newline at end of file
diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
index 0c69a6b9b..5dda76bc4 100644
--- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
+++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
@@ -14,10 +14,10 @@
- 1.1.0
- 1.1.0
- 1.1.0
- 1.1.0
+ 1.2.1
+ 1.2.1
+ 1.2.1
+ 1.2.1
Flow.Launcher.Plugin
Flow-Launcher
MIT
diff --git a/Flow.Launcher.Plugin/IPublicAPI.cs b/Flow.Launcher.Plugin/IPublicAPI.cs
index 2e754a0ff..681973905 100644
--- a/Flow.Launcher.Plugin/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/IPublicAPI.cs
@@ -8,15 +8,6 @@ namespace Flow.Launcher.Plugin
///
public interface IPublicAPI
{
- ///
- /// Push result to query box
- ///
- ///
- ///
- ///
- [Obsolete("This method will be removed in Flow Launcher 1.3")]
- void PushResults(Query query, PluginMetadata plugin, List results);
-
///
/// Change Flow.Launcher query
///
@@ -27,42 +18,11 @@ namespace Flow.Launcher.Plugin
///
void ChangeQuery(string query, bool requery = false);
- ///
- /// Just change the query text, this won't raise search
- ///
- ///
- [Obsolete]
- void ChangeQueryText(string query, bool selectAll = false);
-
- ///
- /// Close Flow Launcher
- ///
- [Obsolete]
- void CloseApp();
-
///
/// Restart Flow Launcher
///
void RestartApp();
- ///
- /// Restart Flow Launcher
- ///
- [Obsolete("Use RestartApp instead. This method will be removed in Flow Launcher 1.3")]
- void RestarApp();
-
- ///
- /// Hide Flow Launcher
- ///
- [Obsolete]
- void HideApp();
-
- ///
- /// Show Flow Launcher
- ///
- [Obsolete]
- void ShowApp();
-
///
/// Save all Flow Launcher settings
///
@@ -103,18 +63,6 @@ namespace Flow.Launcher.Plugin
///
void OpenSettingDialog();
- ///
- /// Show loading animation
- ///
- [Obsolete("automatically start")]
- void StartLoadingBar();
-
- ///
- /// Stop loading animation
- ///
- [Obsolete("automatically stop")]
- void StopLoadingBar();
-
///
/// Install Flow Launcher plugin
///
diff --git a/Flow.Launcher.Plugin/PluginMetadata.cs b/Flow.Launcher.Plugin/PluginMetadata.cs
index fb615459b..d81b442e2 100644
--- a/Flow.Launcher.Plugin/PluginMetadata.cs
+++ b/Flow.Launcher.Plugin/PluginMetadata.cs
@@ -43,9 +43,6 @@ namespace Flow.Launcher.Plugin
return Name;
}
- [Obsolete("Use IcoPath")]
- public string FullIcoPath => IcoPath;
-
///
/// Init time include both plugin load time and init time
///
diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs
index 33310f2aa..1eb5c9c14 100644
--- a/Flow.Launcher.Plugin/Query.cs
+++ b/Flow.Launcher.Plugin/Query.cs
@@ -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 ActionParameters { get; internal set; }
-
- [Obsolete("Use Search instead, this method will be removed in v1.3.0")]
- public string GetAllRemainingParameter() => Search;
}
}
diff --git a/Flow.Launcher.Plugin/Result.cs b/Flow.Launcher.Plugin/Result.cs
index d210ba1d8..70be1e9dc 100644
--- a/Flow.Launcher.Plugin/Result.cs
+++ b/Flow.Launcher.Plugin/Result.cs
@@ -104,21 +104,6 @@ namespace Flow.Launcher.Plugin
return Title + SubTitle;
}
-
- ///
- /// Context menus associate with this result
- ///
- [Obsolete("Use IContextMenu instead")]
- public List 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() { }
///
diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
index 98cd777aa..27cd1a558 100644
--- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
+++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs
@@ -11,7 +11,13 @@ namespace Flow.Launcher.Plugin.SharedCommands
private const string FileExplorerProgramEXE = "explorer.exe";
- public static void Copy(this string sourcePath, string targetPath)
+ ///
+ /// Copies the folder and all of its files and folders
+ /// including subfolders to the target location
+ ///
+ ///
+ ///
+ 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
///
/// 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
///
public static string GetPreviousExistingDirectory(Func locationExists, string path)
{
diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
index 0a1dece4f..c91144825 100644
--- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs
+++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs
@@ -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)]
diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs
index 985d4da87..59bdbc896 100644
--- a/Flow.Launcher/App.xaml.cs
+++ b/Flow.Launcher/App.xaml.cs
@@ -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();
diff --git a/Flow.Launcher/Images/app_missing_img.png b/Flow.Launcher/Images/app_missing_img.png
new file mode 100644
index 000000000..11d5466f0
Binary files /dev/null and b/Flow.Launcher/Images/app_missing_img.png differ
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index 069071f39..adb49b65d 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -111,7 +111,7 @@
Done
Can't find specified plugin
New Action Keyword can't be empty
- New Action Keywords have been assigned to another plugin, please assign other new action keyword
+ This new Action Keyword is already assigned to another plugin, please choose a different one
Success
Use * if you don't want to specify an action keyword
diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs
index 530e6443c..0cc5a0e5d 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -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 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
diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs
index 4392234eb..a4fe2ede4 100644
--- a/Flow.Launcher/ViewModel/ResultViewModel.cs
+++ b/Flow.Launcher/ViewModel/ResultViewModel.cs
@@ -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;
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Bookmark.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Bookmark.cs
index 1149042dd..790c03686 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Bookmark.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Bookmark.cs
@@ -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; }
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/Bookmarks.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/Bookmarks.cs
index 7c2db8bf9..c7013aa67 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/Bookmarks.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/Bookmarks.cs
@@ -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 LoadAllBookmarks()
{
var allbookmarks = new List();
-
+
var chromeBookmarks = new ChromeBookmarks();
var mozBookmarks = new FirefoxBookmarks();
var edgeBookmarks = new EdgeBookmarks();
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarks.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarks.cs
index 12b80c08a..376808549 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarks.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/EdgeBookmarks.cs
@@ -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());
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
index 5d74ed4ad..47493654f 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
@@ -12,7 +12,7 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, ISavable
{
private PluginInitContext context;
-
+
private List cachedBookmarks = new List();
private readonly Settings _settings;
@@ -33,40 +33,60 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
public List 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()
diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
index 8676a3e5b..7bb662b36 100644
--- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
@@ -4,7 +4,7 @@
"Name": "Browser Bookmarks",
"Description": "Search your browser bookmarks",
"Author": "qianlifeng, Ioannis G.",
- "Version": "1.2.0",
+ "Version": "1.2.1",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.browserBookmark.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
index 1235a18e7..949911229 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
@@ -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");
diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
index 284a2893d..316788884 100644
--- a/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Calculator/plugin.json
@@ -4,7 +4,7 @@
"Name": "Calculator",
"Description": "Provide mathematical calculations.(Try 5*3-2 in Flow Launcher)",
"Author": "cxfksword",
- "Version": "1.0.0",
+ "Version": "1.0.1",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Caculator.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.Everything b/Plugins/Flow.Launcher.Plugin.Everything
new file mode 160000
index 000000000..6d5b687e2
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Everything
@@ -0,0 +1 @@
+Subproject commit 6d5b687e240a6abdc5623d8a8e09501f3994b0d3
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
index bd2a047eb..efa5339b4 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
@@ -104,6 +104,7 @@
+
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
index 01bd1a60f..2fb16e0e1 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml
@@ -1,22 +1,26 @@
-
+ Please make a selection first
Please select a folder link
Are you sure you want to delete {0}?
Are you sure you want to permanently delete this {0}?
Deletion successful
Successfully deleted the {0}
+ Assigning the global action keyword could bring up too many results during search. Please choose a specific action keyword
Delete
Edit
Add
+ Customise Action Keywords
Quick Folder Access Paths
Index Search Excluded Paths
Indexing Options
-
+ Search Activation:
+ File Content Search:
Explorer
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs
index db2eaa722..38939e244 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Constants.cs
@@ -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";
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs
index c576d6ee8..6a870f149 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/EnvironmentVariables.cs
@@ -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);
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs
index ebde039d6..8bd19956e 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/FolderLinks/QuickFolderAccess.cs
@@ -6,14 +6,10 @@ namespace Flow.Launcher.Plugin.Explorer.Search.FolderLinks
{
public class QuickFolderAccess
{
- internal List FolderList(Query query, List folderLinks, PluginInitContext context)
+ internal List FolderListMatched(Query query, List 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();
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 FolderListAll(Query query, List folderLinks, PluginInitContext context)
+ => folderLinks
+ .Select(item =>
+ new ResultManager(context).CreateFolderResult(item.Nickname, item.Path, item.Path, query))
+ .ToList();
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
index f814962ba..5b50b7fad 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
@@ -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 WindowsIndexFileContentSearch(Query query, string querySearchString)
+ {
+ var queryConstructor = new QueryConstructor(settings);
+
+ if (string.IsNullOrEmpty(querySearchString))
+ return new List();
+
+ return indexSearch.WindowsIndexSearch(querySearchString,
+ queryConstructor.CreateQueryHelper().ConnectionString,
+ queryConstructor.QueryForFileContentSearch,
+ query);
+ }
+
+ public bool IsFileContentSearch(string actionKeyword)
+ {
+ return actionKeyword == settings.FileContentSearchActionKeyword;
+ }
+
private List 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);
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
index c1793b42b..4f9325c77 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/IndexSearch.cs
@@ -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));
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
index f4480eea7..5718fdb0a 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/WindowsIndex/QueryConstructor.cs
@@ -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:'";
}
+
+ ///
+ /// Search will be performed on all indexed file contents for the specified search keywords.
+ ///
+ public string QueryForFileContentSearch(string userSearchString)
+ {
+ string query = "SELECT TOP " + settings.MaxResult + $" {CreateBaseQuery().QuerySelectColumns} FROM {SystemIndex} WHERE ";
+
+ return query + QueryWhereRestrictionsForFileContentSearch(userSearchString) + " AND " + QueryWhereRestrictionsForAllFilesAndFoldersSearch();
+ }
+
+ ///
+ /// Set the required WHERE clause restriction to search within file content.
+ ///
+ public string QueryWhereRestrictionsForFileContentSearch(string searchQuery)
+ {
+ return $"FREETEXT('{searchQuery}')";
+ }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
index d4bfdbbfc..5b12870c8 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs
@@ -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 IndexSearchExcludedSubdirectoryPaths { get; set; } = new List();
+
+ [JsonProperty]
+ public string SearchActionKeyword { get; set; } = Query.GlobalPluginWildcardSign;
+
+ [JsonProperty]
+ public string FileContentSearchActionKeyword { get; set; } = Constants.DefaultContentSearchActionKeyword;
}
}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
index a5e81716a..7fcd77f07 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
@@ -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;
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml
new file mode 100644
index 000000000..0e1c7e872
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs
new file mode 100644
index 000000000..2957283ad
--- /dev/null
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ActionKeywordSetting.xaml.cs
@@ -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
+{
+ ///
+ /// Interaction logic for ActionKeywordSetting.xaml
+ ///
+ public partial class ActionKeywordSetting : Window
+ {
+ private SettingsViewModel settingsViewModel;
+
+ private ActionKeywordView currentActionKeyword;
+
+ private List actionKeywordListView;
+
+ public ActionKeywordSetting(SettingsViewModel settingsViewModel, List 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;
+ }
+ }
+}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
index 5ba1a063b..9d6f4976e 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml
@@ -1,4 +1,4 @@
-
+
+
+
+
+
+
@@ -25,8 +35,14 @@
+
+
+
+ Expanded="expFolderLinks_Click" Collapsed="expFolderLinks_Collapsed"
+ Margin="0 10 0 0">
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
+ {
+ 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; }
+ }
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json
index 91b27edb1..7c6ef82b0 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/plugin.json
@@ -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",
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml
index 2eee31745..e7a136114 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Languages/en.xaml
@@ -5,7 +5,8 @@
Process Killer
Kill running processes from Flow Launcher
- kill all "{0}" processes
+ kill all instances of "{0}"
+ kill {0} processes
kill all instances
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs
index 22c84b20f..c3d9d1ab2 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs
@@ -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;
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json
index f2e1eca12..894c49bdf 100644
--- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json
@@ -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",
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
index 579a64718..c266aa6f6 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
@@ -40,7 +40,12 @@
Search programs in Flow Launcher
Invalid Path
-
+
+ Customized Explorer
+ Args
+ 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.
+ 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.
+
Success
Successfully disabled this program from displaying in your query
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs
index b8633f357..def121723 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs
@@ -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
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
index cdea767f3..7f90367ab 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
@@ -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"
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
index fcb4cbf2d..7cb02a852 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
@@ -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";
+
///
/// Contains user added folder location contents as well as all user disabled applications
///
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
index 6051e0579..90fda1756 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
@@ -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">
+
@@ -24,7 +25,7 @@
-
+
@@ -71,9 +72,18 @@
-
+
+
+
+
+
+
+
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs
index a9de5ea71..e4e92b9bc 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml.cs
@@ -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;
+ }
}
}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Program/plugin.json b/Plugins/Flow.Launcher.Plugin.Program/plugin.json
index 0316a2397..3eb4a40e1 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.Program/plugin.json
@@ -4,7 +4,7 @@
"Name": "Program",
"Description": "Search programs in Flow.Launcher",
"Author": "qianlifeng",
- "Version": "1.0.0",
+ "Version": "1.1.0",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.Program.dll",
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
index f1ae5bc35..c2ed7df31 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
@@ -25,6 +25,7 @@
Please enter a URL
Action keyword already exists, please enter a different one
Success
+ 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.
Web Searches
Allows to perform web searches
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
index 3fdb26c93..3c4d4c67d 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs
@@ -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
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs
index 20d0dd5a4..c7ccb4d51 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSource.cs
@@ -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;
///
- /// 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
///
- [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;
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml
index 0f17d21f5..02809be3a 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml
@@ -47,7 +47,7 @@
-
+
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs
index 9ecdda23f..fd0701c01 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceSetting.xaml.cs
@@ -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 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);
}
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs
index 049c50560..f54dbc13c 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SearchSourceViewModel.cs
@@ -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);
+ }
}
}
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
index 9784cfefe..a91e42f45 100644
--- a/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
+++ b/Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json
@@ -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",
diff --git a/README.md b/README.md
index c39c01328..b44628744 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/SolutionAssemblyInfo.cs b/SolutionAssemblyInfo.cs
index 0c45546df..abf7f5e15 100644
--- a/SolutionAssemblyInfo.cs
+++ b/SolutionAssemblyInfo.cs
@@ -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")]
\ No newline at end of file
+[assembly: AssemblyVersion("1.3.1")]
+[assembly: AssemblyFileVersion("1.3.1")]
+[assembly: AssemblyInformationalVersion("1.3.1")]
\ No newline at end of file
diff --git a/appveyor.yml b/appveyor.yml
index 56fa840ab..2b2acc304 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,4 +1,4 @@
-version: '1.1.2.{build}'
+version: '1.3.1.{build}'
init:
- ps: |