From 3abd05f6b3a687e73fc9e6ab0f09ec2af2f6c06a Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 18 Nov 2023 14:58:16 +0800 Subject: [PATCH 001/545] Implement double pinyin --- .../DoublePinAlphabet.cs | 193 ++++++++++++++++++ .../UserSettings/Settings.cs | 2 + 2 files changed, 195 insertions(+) create mode 100644 Flow.Launcher.Infrastructure/DoublePinAlphabet.cs diff --git a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs new file mode 100644 index 000000000..607582097 --- /dev/null +++ b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs @@ -0,0 +1,193 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using Flow.Launcher.Infrastructure.UserSettings; +using ToolGood.Words.Pinyin; + +namespace Flow.Launcher.Infrastructure +{ + public class DoublePinAlphabet : IAlphabet + { + private ConcurrentDictionary _doublePinCache = + new ConcurrentDictionary(); + + private Settings _settings; + + public void Initialize([NotNull] Settings settings) + { + _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + } + + public bool CanBeTranslated(string stringToTranslate) + { + return WordsHelper.HasChinese(stringToTranslate); + } + + public (string translation, TranslationMapping map) Translate(string content) + { + if (_settings.ShouldUseDoublePin) + { + if (!_doublePinCache.ContainsKey(content)) + { + return BuildCacheFromContent(content); + } + else + { + return _doublePinCache[content]; + } + } + return (content, null); + } + + private (string translation, TranslationMapping map) BuildCacheFromContent(string content) + { + if (WordsHelper.HasChinese(content)) + { + var resultList = WordsHelper.GetPinyinList(content).Select(ToDoublePin).ToArray(); + StringBuilder resultBuilder = new StringBuilder(); + TranslationMapping map = new TranslationMapping(); + + bool pre = false; + + for (int i = 0; i < resultList.Length; i++) + { + if (content[i] >= 0x3400 && content[i] <= 0x9FD5) + { + map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1); + resultBuilder.Append(' '); + resultBuilder.Append(resultList[i]); + pre = true; + } + else + { + if (pre) + { + pre = false; + resultBuilder.Append(' '); + } + + resultBuilder.Append(resultList[i]); + } + } + + map.endConstruct(); + + var key = resultBuilder.ToString(); + map.setKey(key); + + return _doublePinCache[content] = (key, map); + } + else + { + return (content, null); + } + } + + private static readonly ReadOnlyDictionary special = new(new Dictionary(){ + {"a", "aa"}, + {"ai", "ai"}, + {"an", "an"}, + {"ang", "ah"}, + {"ao", "ao"}, + {"e", "ee"}, + {"ei", "ei"}, + {"en", "en"}, + {"er", "er"}, + {"o", "oo"}, + {"ou", "ou"} + }); + + + private static readonly ReadOnlyDictionary first = new(new Dictionary(){ + {"ch", "i"}, + {"sh", "u"}, + {"zh", "v"} + }); + + + private static readonly ReadOnlyDictionary second = new(new Dictionary() + { + {"ua", "x"}, + {"ei", "w"}, + {"e", "e"}, + {"ou", "z"}, + {"iu", "q"}, + {"ve", "t"}, + {"ue", "t"}, + {"u", "u"}, + {"i", "i"}, + {"o", "o"}, + {"uo", "o"}, + {"ie", "p"}, + {"a", "a"}, + {"ong", "s"}, + {"iong", "s"}, + {"ai", "d"}, + {"ing", "k"}, + {"uai", "k"}, + {"ang", "h"}, + {"uan", "r"}, + {"an", "j"}, + {"en", "f"}, + {"ia", "x"}, + {"iang", "l"}, + {"uang", "l"}, + {"eng", "g"}, + {"in", "b"}, + {"ao", "c"}, + {"v", "v"}, + {"ui", "v"}, + {"un", "y"}, + {"iao", "n"}, + {"ian", "m"} + }); + + private static string ToDoublePin(string fullPinyin) + { + // Assuming s is valid + StringBuilder doublePin = new StringBuilder(); + + if (fullPinyin.Length <= 3 && (fullPinyin[0] == 'a' || fullPinyin[0] == 'e' || fullPinyin[0] == 'o')) + { + if (special.ContainsKey(fullPinyin)) + { + return special[fullPinyin]; + } + } + + // zh, ch, sh + if (fullPinyin.Length >= 2 && first.ContainsKey(fullPinyin[..2])) + { + doublePin.Append(first[fullPinyin[..2]]); + + if (second.TryGetValue(fullPinyin[2..], out string tmp)) + { + doublePin.Append(tmp); + } + else + { + doublePin.Append(fullPinyin[2..]); + } + } + else + { + doublePin.Append(fullPinyin[0]); + + if (second.TryGetValue(fullPinyin[1..], out string tmp)) + { + doublePin.Append(tmp); + } + else + { + doublePin.Append(fullPinyin[1..]); + } + } + + return doublePin.ToString(); + } + } +} diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 458846665..8d94cdba5 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -185,6 +185,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings /// when false Alphabet static service will always return empty results /// public bool ShouldUsePinyin { get; set; } = false; + + public bool ShouldUseDoublePin { get; set; } = false; public bool AlwaysPreview { get; set; } = false; public bool AlwaysStartEn { get; set; } = false; From fb6635344b8e5ecae06aadd31a3b112471b48ae2 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 18 Nov 2023 14:58:23 +0800 Subject: [PATCH 002/545] Test double pinyin --- Flow.Launcher/App.xaml.cs | 2 +- Flow.Launcher/PublicAPIInstance.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 765a1a559..d74ea62fb 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -30,7 +30,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 PinyinAlphabet _alphabet = new PinyinAlphabet(); + private readonly DoublePinAlphabet _alphabet = new DoublePinAlphabet(); private StringMatcher _stringMatcher; [STAThread] diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index b49bf39d3..952ce0edb 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -32,11 +32,11 @@ namespace Flow.Launcher { private readonly SettingWindowViewModel _settingsVM; private readonly MainViewModel _mainVM; - private readonly PinyinAlphabet _alphabet; + private readonly DoublePinAlphabet _alphabet; #region Constructor - public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, PinyinAlphabet alphabet) + public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, DoublePinAlphabet alphabet) { _settingsVM = settingsVM; _mainVM = mainVM; From f6ae71a99f838b2237c14c62c6daff5e97e6eec0 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 18 Nov 2023 20:24:13 +0800 Subject: [PATCH 003/545] Only convert to double pinyin when meeting Chinese --- Flow.Launcher.Infrastructure/DoublePinAlphabet.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs index 607582097..e09046410 100644 --- a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs @@ -47,7 +47,7 @@ namespace Flow.Launcher.Infrastructure { if (WordsHelper.HasChinese(content)) { - var resultList = WordsHelper.GetPinyinList(content).Select(ToDoublePin).ToArray(); + var resultList = WordsHelper.GetPinyinList(content); StringBuilder resultBuilder = new StringBuilder(); TranslationMapping map = new TranslationMapping(); @@ -57,9 +57,10 @@ namespace Flow.Launcher.Infrastructure { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { - map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1); + string dp = ToDoublePin(resultList[i].ToLower()); + map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); resultBuilder.Append(' '); - resultBuilder.Append(resultList[i]); + resultBuilder.Append(dp); pre = true; } else From e5285b19921ae2cc49b6f55ebe5772a77f05cd54 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 19 Nov 2023 12:30:17 +0800 Subject: [PATCH 004/545] Temp: compatibility with full pinyin option --- Flow.Launcher.Infrastructure/DoublePinAlphabet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs index e09046410..e6930ad93 100644 --- a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs @@ -29,7 +29,7 @@ namespace Flow.Launcher.Infrastructure public (string translation, TranslationMapping map) Translate(string content) { - if (_settings.ShouldUseDoublePin) + if (_settings.ShouldUsePinyin) { if (!_doublePinCache.ContainsKey(content)) { @@ -57,7 +57,7 @@ namespace Flow.Launcher.Infrastructure { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { - string dp = ToDoublePin(resultList[i].ToLower()); + string dp = _settings.ShouldUseDoublePin ? resultList[i] : ToDoublePin(resultList[i].ToLower()); map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); resultBuilder.Append(' '); resultBuilder.Append(dp); From 99ff3b2ec5c9a4d8b4f136735a866f52914c246e Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 20 Nov 2023 22:49:39 +0800 Subject: [PATCH 005/545] Fix wrong condition --- Flow.Launcher.Infrastructure/DoublePinAlphabet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs index e6930ad93..a1eb788d7 100644 --- a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs @@ -57,7 +57,7 @@ namespace Flow.Launcher.Infrastructure { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { - string dp = _settings.ShouldUseDoublePin ? resultList[i] : ToDoublePin(resultList[i].ToLower()); + string dp = _settings.ShouldUseDoublePin ? ToDoublePin(resultList[i].ToLower()) : resultList[i]; map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); resultBuilder.Append(' '); resultBuilder.Append(dp); From 46d49d8fdf373e020481b111cbd23bf8ee09538d Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 25 May 2024 15:02:37 +0800 Subject: [PATCH 006/545] Only translate when string is double pinyin --- Flow.Launcher.Infrastructure/DoublePinAlphabet.cs | 4 ++-- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 4 ++-- Flow.Launcher.Infrastructure/StringMatcher.cs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs index a1eb788d7..945f47a56 100644 --- a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs @@ -22,9 +22,9 @@ namespace Flow.Launcher.Infrastructure _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public bool CanBeTranslated(string stringToTranslate) + public bool ShouldTranslate(string stringToTranslate) { - return WordsHelper.HasChinese(stringToTranslate); + return stringToTranslate.Length % 2 == 0 && !WordsHelper.HasChinese(stringToTranslate); } public (string translation, TranslationMapping map) Translate(string content) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 7d7235968..961af1d32 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -119,7 +119,7 @@ namespace Flow.Launcher.Infrastructure /// /// String to translate. /// - public bool CanBeTranslated(string stringToTranslate); + public bool ShouldTranslate(string stringToTranslate); } public class PinyinAlphabet : IAlphabet @@ -134,7 +134,7 @@ namespace Flow.Launcher.Infrastructure _settings = settings ?? throw new ArgumentNullException(nameof(settings)); } - public bool CanBeTranslated(string stringToTranslate) + public bool ShouldTranslate(string stringToTranslate) { return WordsHelper.HasChinese(stringToTranslate); } diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index bd5dbdda9..4929e4cd2 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -61,7 +61,7 @@ namespace Flow.Launcher.Infrastructure query = query.Trim(); TranslationMapping translationMapping = null; - if (_alphabet is not null && !_alphabet.CanBeTranslated(query)) + if (_alphabet is not null && _alphabet.ShouldTranslate(query)) { // We assume that if a query can be translated (containing characters of a language, like Chinese) // it actually means user doesn't want it to be translated to English letters. From b1cb852673005e955b1d4bd0bb2ed692e44308c9 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:18:57 +0800 Subject: [PATCH 007/545] Extract classes --- Flow.Launcher.Infrastructure/IAlphabet.cs | 22 ++++ .../PinyinAlphabet.cs | 113 ------------------ .../TranslationMapping.cs | 99 +++++++++++++++ 3 files changed, 121 insertions(+), 113 deletions(-) create mode 100644 Flow.Launcher.Infrastructure/IAlphabet.cs create mode 100644 Flow.Launcher.Infrastructure/TranslationMapping.cs diff --git a/Flow.Launcher.Infrastructure/IAlphabet.cs b/Flow.Launcher.Infrastructure/IAlphabet.cs new file mode 100644 index 000000000..e79ec0c6d --- /dev/null +++ b/Flow.Launcher.Infrastructure/IAlphabet.cs @@ -0,0 +1,22 @@ +namespace Flow.Launcher.Infrastructure +{ + /// + /// Translate a language to English letters using a given rule. + /// + public interface IAlphabet + { + /// + /// Translate a string to English letters, using a given rule. + /// + /// String to translate. + /// + public (string translation, TranslationMapping map) Translate(string stringToTranslate); + + /// + /// Determine if a string can be translated to English letter with this Alphabet. + /// + /// String to translate. + /// + public bool ShouldTranslate(string stringToTranslate); + } +} diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 961af1d32..d98d823d7 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -9,119 +9,6 @@ using ToolGood.Words.Pinyin; namespace Flow.Launcher.Infrastructure { - public class TranslationMapping - { - private bool constructed; - - private List originalIndexs = new List(); - private List translatedIndexs = new List(); - private int translatedLength = 0; - - public string key { get; private set; } - - public void setKey(string key) - { - this.key = key; - } - - public void AddNewIndex(int originalIndex, int translatedIndex, int length) - { - if (constructed) - throw new InvalidOperationException("Mapping shouldn't be changed after constructed"); - - originalIndexs.Add(originalIndex); - translatedIndexs.Add(translatedIndex); - translatedIndexs.Add(translatedIndex + length); - translatedLength += length - 1; - } - - public int MapToOriginalIndex(int translatedIndex) - { - if (translatedIndex > translatedIndexs.Last()) - return translatedIndex - translatedLength - 1; - - int lowerBound = 0; - int upperBound = originalIndexs.Count - 1; - - int count = 0; - - // Corner case handle - if (translatedIndex < translatedIndexs[0]) - return translatedIndex; - if (translatedIndex > translatedIndexs.Last()) - { - int indexDef = 0; - for (int k = 0; k < originalIndexs.Count; k++) - { - indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2]; - } - - return translatedIndex - indexDef - 1; - } - - // Binary Search with Range - for (int i = originalIndexs.Count / 2;; count++) - { - if (translatedIndex < translatedIndexs[i * 2]) - { - // move to lower middle - upperBound = i; - i = (i + lowerBound) / 2; - } - else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1) - { - lowerBound = i; - // move to upper middle - // due to floor of integer division, move one up on corner case - i = (i + upperBound + 1) / 2; - } - else - return originalIndexs[i]; - - if (upperBound - lowerBound <= 1 && - translatedIndex > translatedIndexs[lowerBound * 2 + 1] && - translatedIndex < translatedIndexs[upperBound * 2]) - { - int indexDef = 0; - - for (int j = 0; j < upperBound; j++) - { - indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2]; - } - - return translatedIndex - indexDef - 1; - } - } - } - - public void endConstruct() - { - if (constructed) - throw new InvalidOperationException("Mapping has already been constructed"); - constructed = true; - } - } - - /// - /// Translate a language to English letters using a given rule. - /// - public interface IAlphabet - { - /// - /// Translate a string to English letters, using a given rule. - /// - /// String to translate. - /// - public (string translation, TranslationMapping map) Translate(string stringToTranslate); - - /// - /// Determine if a string can be translated to English letter with this Alphabet. - /// - /// String to translate. - /// - public bool ShouldTranslate(string stringToTranslate); - } - public class PinyinAlphabet : IAlphabet { private ConcurrentDictionary _pinyinCache = diff --git a/Flow.Launcher.Infrastructure/TranslationMapping.cs b/Flow.Launcher.Infrastructure/TranslationMapping.cs new file mode 100644 index 000000000..f288c816a --- /dev/null +++ b/Flow.Launcher.Infrastructure/TranslationMapping.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Flow.Launcher.Infrastructure +{ + public class TranslationMapping + { + private bool constructed; + + private List originalIndexs = new List(); + private List translatedIndexs = new List(); + private int translatedLength = 0; + + public string key { get; private set; } + + public void setKey(string key) + { + this.key = key; + } + + public void AddNewIndex(int originalIndex, int translatedIndex, int length) + { + if (constructed) + throw new InvalidOperationException("Mapping shouldn't be changed after constructed"); + + originalIndexs.Add(originalIndex); + translatedIndexs.Add(translatedIndex); + translatedIndexs.Add(translatedIndex + length); + translatedLength += length - 1; + } + + public int MapToOriginalIndex(int translatedIndex) + { + if (translatedIndex > translatedIndexs.Last()) + return translatedIndex - translatedLength - 1; + + int lowerBound = 0; + int upperBound = originalIndexs.Count - 1; + + int count = 0; + + // Corner case handle + if (translatedIndex < translatedIndexs[0]) + return translatedIndex; + if (translatedIndex > translatedIndexs.Last()) + { + int indexDef = 0; + for (int k = 0; k < originalIndexs.Count; k++) + { + indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2]; + } + + return translatedIndex - indexDef - 1; + } + + // Binary Search with Range + for (int i = originalIndexs.Count / 2;; count++) + { + if (translatedIndex < translatedIndexs[i * 2]) + { + // move to lower middle + upperBound = i; + i = (i + lowerBound) / 2; + } + else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1) + { + lowerBound = i; + // move to upper middle + // due to floor of integer division, move one up on corner case + i = (i + upperBound + 1) / 2; + } + else + return originalIndexs[i]; + + if (upperBound - lowerBound <= 1 && + translatedIndex > translatedIndexs[lowerBound * 2 + 1] && + translatedIndex < translatedIndexs[upperBound * 2]) + { + int indexDef = 0; + + for (int j = 0; j < upperBound; j++) + { + indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2]; + } + + return translatedIndex - indexDef - 1; + } + } + } + + public void endConstruct() + { + if (constructed) + throw new InvalidOperationException("Mapping has already been constructed"); + constructed = true; + } + } +} From 6807afbe6d753eed6984e1b1ab6019e2864767cd Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:03:00 +0800 Subject: [PATCH 008/545] Remove unused alphabet arg in PublicAPIInstance --- Flow.Launcher/App.xaml.cs | 2 +- Flow.Launcher/PublicAPIInstance.cs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index d74ea62fb..560bb052b 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -74,7 +74,7 @@ namespace Flow.Launcher PluginManager.LoadPlugins(_settings.PluginSettings); _mainVM = new MainViewModel(_settings); - API = new PublicAPIInstance(_settingsVM, _mainVM, _alphabet); + API = new PublicAPIInstance(_settingsVM, _mainVM); Http.API = API; Http.Proxy = _settings.Proxy; diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 952ce0edb..e14d692cd 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -32,15 +32,13 @@ namespace Flow.Launcher { private readonly SettingWindowViewModel _settingsVM; private readonly MainViewModel _mainVM; - private readonly DoublePinAlphabet _alphabet; #region Constructor - public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM, DoublePinAlphabet alphabet) + public PublicAPIInstance(SettingWindowViewModel settingsVM, MainViewModel mainVM) { _settingsVM = settingsVM; _mainVM = mainVM; - _alphabet = alphabet; GlobalHotkey.hookedKeyboardCallback = KListener_hookedKeyboardCallback; WebRequest.RegisterPrefix("data", new DataWebRequestFactory()); } From a2efa11699fed4b3aac21bdff26555ce57b274aa Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:19:27 +0800 Subject: [PATCH 009/545] Merge DoublePinAlphabet logic --- .../DoublePinAlphabet.cs | 194 ------------------ .../PinyinAlphabet.cs | 127 +++++++++++- .../UserSettings/Settings.cs | 3 +- Flow.Launcher/App.xaml.cs | 2 +- 4 files changed, 121 insertions(+), 205 deletions(-) delete mode 100644 Flow.Launcher.Infrastructure/DoublePinAlphabet.cs diff --git a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs b/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs deleted file mode 100644 index 945f47a56..000000000 --- a/Flow.Launcher.Infrastructure/DoublePinAlphabet.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using Flow.Launcher.Infrastructure.UserSettings; -using ToolGood.Words.Pinyin; - -namespace Flow.Launcher.Infrastructure -{ - public class DoublePinAlphabet : IAlphabet - { - private ConcurrentDictionary _doublePinCache = - new ConcurrentDictionary(); - - private Settings _settings; - - public void Initialize([NotNull] Settings settings) - { - _settings = settings ?? throw new ArgumentNullException(nameof(settings)); - } - - public bool ShouldTranslate(string stringToTranslate) - { - return stringToTranslate.Length % 2 == 0 && !WordsHelper.HasChinese(stringToTranslate); - } - - public (string translation, TranslationMapping map) Translate(string content) - { - if (_settings.ShouldUsePinyin) - { - if (!_doublePinCache.ContainsKey(content)) - { - return BuildCacheFromContent(content); - } - else - { - return _doublePinCache[content]; - } - } - return (content, null); - } - - private (string translation, TranslationMapping map) BuildCacheFromContent(string content) - { - if (WordsHelper.HasChinese(content)) - { - var resultList = WordsHelper.GetPinyinList(content); - StringBuilder resultBuilder = new StringBuilder(); - TranslationMapping map = new TranslationMapping(); - - bool pre = false; - - for (int i = 0; i < resultList.Length; i++) - { - if (content[i] >= 0x3400 && content[i] <= 0x9FD5) - { - string dp = _settings.ShouldUseDoublePin ? ToDoublePin(resultList[i].ToLower()) : resultList[i]; - map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); - resultBuilder.Append(' '); - resultBuilder.Append(dp); - pre = true; - } - else - { - if (pre) - { - pre = false; - resultBuilder.Append(' '); - } - - resultBuilder.Append(resultList[i]); - } - } - - map.endConstruct(); - - var key = resultBuilder.ToString(); - map.setKey(key); - - return _doublePinCache[content] = (key, map); - } - else - { - return (content, null); - } - } - - private static readonly ReadOnlyDictionary special = new(new Dictionary(){ - {"a", "aa"}, - {"ai", "ai"}, - {"an", "an"}, - {"ang", "ah"}, - {"ao", "ao"}, - {"e", "ee"}, - {"ei", "ei"}, - {"en", "en"}, - {"er", "er"}, - {"o", "oo"}, - {"ou", "ou"} - }); - - - private static readonly ReadOnlyDictionary first = new(new Dictionary(){ - {"ch", "i"}, - {"sh", "u"}, - {"zh", "v"} - }); - - - private static readonly ReadOnlyDictionary second = new(new Dictionary() - { - {"ua", "x"}, - {"ei", "w"}, - {"e", "e"}, - {"ou", "z"}, - {"iu", "q"}, - {"ve", "t"}, - {"ue", "t"}, - {"u", "u"}, - {"i", "i"}, - {"o", "o"}, - {"uo", "o"}, - {"ie", "p"}, - {"a", "a"}, - {"ong", "s"}, - {"iong", "s"}, - {"ai", "d"}, - {"ing", "k"}, - {"uai", "k"}, - {"ang", "h"}, - {"uan", "r"}, - {"an", "j"}, - {"en", "f"}, - {"ia", "x"}, - {"iang", "l"}, - {"uang", "l"}, - {"eng", "g"}, - {"in", "b"}, - {"ao", "c"}, - {"v", "v"}, - {"ui", "v"}, - {"un", "y"}, - {"iao", "n"}, - {"ian", "m"} - }); - - private static string ToDoublePin(string fullPinyin) - { - // Assuming s is valid - StringBuilder doublePin = new StringBuilder(); - - if (fullPinyin.Length <= 3 && (fullPinyin[0] == 'a' || fullPinyin[0] == 'e' || fullPinyin[0] == 'o')) - { - if (special.ContainsKey(fullPinyin)) - { - return special[fullPinyin]; - } - } - - // zh, ch, sh - if (fullPinyin.Length >= 2 && first.ContainsKey(fullPinyin[..2])) - { - doublePin.Append(first[fullPinyin[..2]]); - - if (second.TryGetValue(fullPinyin[2..], out string tmp)) - { - doublePin.Append(tmp); - } - else - { - doublePin.Append(fullPinyin[2..]); - } - } - else - { - doublePin.Append(fullPinyin[0]); - - if (second.TryGetValue(fullPinyin[1..], out string tmp)) - { - doublePin.Append(tmp); - } - else - { - doublePin.Append(fullPinyin[1..]); - } - } - - return doublePin.ToString(); - } - } -} diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index d98d823d7..37e4f93d2 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,18 +1,18 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; using System.Text; using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; using ToolGood.Words.Pinyin; +using System.Collections.Generic; +using System.Collections.ObjectModel; namespace Flow.Launcher.Infrastructure { public class PinyinAlphabet : IAlphabet { - private ConcurrentDictionary _pinyinCache = - new ConcurrentDictionary(); + private readonly ConcurrentDictionary _pinyinCache = + new(); private Settings _settings; @@ -23,20 +23,22 @@ namespace Flow.Launcher.Infrastructure public bool ShouldTranslate(string stringToTranslate) { - return WordsHelper.HasChinese(stringToTranslate); + return _settings.UseDoublePinyin ? + (WordsHelper.HasChinese(stringToTranslate) && stringToTranslate.Length % 2 == 0) : + WordsHelper.HasChinese(stringToTranslate); } public (string translation, TranslationMapping map) Translate(string content) { if (_settings.ShouldUsePinyin) { - if (!_pinyinCache.ContainsKey(content)) + if (!_pinyinCache.TryGetValue(content, out var value)) { return BuildCacheFromContent(content); } else { - return _pinyinCache[content]; + return value; } } return (content, null); @@ -57,9 +59,10 @@ namespace Flow.Launcher.Infrastructure { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { - map.AddNewIndex(i, resultBuilder.Length, resultList[i].Length + 1); + string dp = _settings.UseDoublePinyin ? ToDoublePin(resultList[i].ToLower()) : resultList[i]; + map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); resultBuilder.Append(' '); - resultBuilder.Append(resultList[i]); + resultBuilder.Append(dp); pre = true; } else @@ -86,5 +89,111 @@ namespace Flow.Launcher.Infrastructure return (content, null); } } + + #region Double Pinyin + + private static readonly ReadOnlyDictionary special = new(new Dictionary(){ + {"a", "aa"}, + {"ai", "ai"}, + {"an", "an"}, + {"ang", "ah"}, + {"ao", "ao"}, + {"e", "ee"}, + {"ei", "ei"}, + {"en", "en"}, + {"er", "er"}, + {"o", "oo"}, + {"ou", "ou"} + }); + + + private static readonly ReadOnlyDictionary first = new(new Dictionary(){ + {"ch", "i"}, + {"sh", "u"}, + {"zh", "v"} + }); + + + private static readonly ReadOnlyDictionary second = new(new Dictionary() + { + {"ua", "x"}, + {"ei", "w"}, + {"e", "e"}, + {"ou", "z"}, + {"iu", "q"}, + {"ve", "t"}, + {"ue", "t"}, + {"u", "u"}, + {"i", "i"}, + {"o", "o"}, + {"uo", "o"}, + {"ie", "p"}, + {"a", "a"}, + {"ong", "s"}, + {"iong", "s"}, + {"ai", "d"}, + {"ing", "k"}, + {"uai", "k"}, + {"ang", "h"}, + {"uan", "r"}, + {"an", "j"}, + {"en", "f"}, + {"ia", "x"}, + {"iang", "l"}, + {"uang", "l"}, + {"eng", "g"}, + {"in", "b"}, + {"ao", "c"}, + {"v", "v"}, + {"ui", "v"}, + {"un", "y"}, + {"iao", "n"}, + {"ian", "m"} + }); + + private static string ToDoublePin(string fullPinyin) + { + // Assuming s is valid + StringBuilder doublePin = new StringBuilder(); + + if (fullPinyin.Length <= 3 && (fullPinyin[0] == 'a' || fullPinyin[0] == 'e' || fullPinyin[0] == 'o')) + { + if (special.TryGetValue(fullPinyin, out var value)) + { + return value; + } + } + + // zh, ch, sh + if (fullPinyin.Length >= 2 && first.ContainsKey(fullPinyin[..2])) + { + doublePin.Append(first[fullPinyin[..2]]); + + if (second.TryGetValue(fullPinyin[2..], out string tmp)) + { + doublePin.Append(tmp); + } + else + { + doublePin.Append(fullPinyin[2..]); + } + } + else + { + doublePin.Append(fullPinyin[0]); + + if (second.TryGetValue(fullPinyin[1..], out string tmp)) + { + doublePin.Append(tmp); + } + else + { + doublePin.Append(fullPinyin[1..]); + } + } + + return doublePin.ToString(); + } + #endregion } } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 8d94cdba5..e79c3f52d 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -186,7 +186,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings /// public bool ShouldUsePinyin { get; set; } = false; - public bool ShouldUseDoublePin { get; set; } = false; + public bool UseDoublePinyin { get; set; } = false; + public bool AlwaysPreview { get; set; } = false; public bool AlwaysStartEn { get; set; } = false; diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 560bb052b..83870837a 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -30,7 +30,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 DoublePinAlphabet _alphabet = new DoublePinAlphabet(); + private readonly PinyinAlphabet _alphabet = new PinyinAlphabet(); private StringMatcher _stringMatcher; [STAThread] From 12c4e37a95df44fc968a6459e7a3cbf6de4063e6 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:33:49 +0800 Subject: [PATCH 010/545] Developing --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index e79c3f52d..30e3b77be 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -186,7 +186,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings /// public bool ShouldUsePinyin { get; set; } = false; - public bool UseDoublePinyin { get; set; } = false; + public bool UseDoublePinyin { get; set; } = true; //For developing public bool AlwaysPreview { get; set; } = false; public bool AlwaysStartEn { get; set; } = false; From f673000d67e4ff1180e6d2856bf85f1640433a7c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 14:37:15 +0800 Subject: [PATCH 011/545] Fix ShouldTranslate() --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 37e4f93d2..b48a61090 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -23,9 +23,9 @@ namespace Flow.Launcher.Infrastructure public bool ShouldTranslate(string stringToTranslate) { - return _settings.UseDoublePinyin ? - (WordsHelper.HasChinese(stringToTranslate) && stringToTranslate.Length % 2 == 0) : - WordsHelper.HasChinese(stringToTranslate); + return _settings.UseDoublePinyin ? + (!WordsHelper.HasChinese(stringToTranslate) && stringToTranslate.Length % 2 == 0) : + !WordsHelper.HasChinese(stringToTranslate); } public (string translation, TranslationMapping map) Translate(string content) From b10a6e19df5afcbd13ca612f6e6952f19a3b9dde Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:18:24 +0800 Subject: [PATCH 012/545] Capitalize first letter --- .../PinyinAlphabet.cs | 104 +++++++++--------- 1 file changed, 51 insertions(+), 53 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index b48a61090..cbec7feae 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -46,71 +46,69 @@ namespace Flow.Launcher.Infrastructure private (string translation, TranslationMapping map) BuildCacheFromContent(string content) { - if (WordsHelper.HasChinese(content)) - { - var resultList = WordsHelper.GetPinyinList(content); - - StringBuilder resultBuilder = new StringBuilder(); - TranslationMapping map = new TranslationMapping(); - - bool pre = false; - - for (int i = 0; i < resultList.Length; i++) - { - if (content[i] >= 0x3400 && content[i] <= 0x9FD5) - { - string dp = _settings.UseDoublePinyin ? ToDoublePin(resultList[i].ToLower()) : resultList[i]; - map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); - resultBuilder.Append(' '); - resultBuilder.Append(dp); - pre = true; - } - else - { - if (pre) - { - pre = false; - resultBuilder.Append(' '); - } - - resultBuilder.Append(resultList[i]); - } - } - - map.endConstruct(); - - var key = resultBuilder.ToString(); - map.setKey(key); - - return _pinyinCache[content] = (key, map); - } - else + if (!WordsHelper.HasChinese(content)) { return (content, null); } + + var resultList = WordsHelper.GetPinyinList(content); + + StringBuilder resultBuilder = new StringBuilder(); + TranslationMapping map = new TranslationMapping(); + + bool pre = false; + + for (int i = 0; i < resultList.Length; i++) + { + if (content[i] >= 0x3400 && content[i] <= 0x9FD5) + { + string dp = _settings.UseDoublePinyin ? ToDoublePin(resultList[i]) : resultList[i]; + map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); + resultBuilder.Append(' '); + resultBuilder.Append(dp); + pre = true; + } + else + { + if (pre) + { + pre = false; + resultBuilder.Append(' '); + } + + resultBuilder.Append(resultList[i]); + } + } + + map.endConstruct(); + + var key = resultBuilder.ToString(); + map.setKey(key); + + return _pinyinCache[content] = (key, map); } #region Double Pinyin private static readonly ReadOnlyDictionary special = new(new Dictionary(){ - {"a", "aa"}, - {"ai", "ai"}, - {"an", "an"}, - {"ang", "ah"}, - {"ao", "ao"}, - {"e", "ee"}, - {"ei", "ei"}, - {"en", "en"}, - {"er", "er"}, - {"o", "oo"}, - {"ou", "ou"} + {"A", "aa"}, + {"Ai", "ai"}, + {"An", "an"}, + {"Ang", "ah"}, + {"Ao", "ao"}, + {"E", "ee"}, + {"Ei", "ei"}, + {"En", "en"}, + {"Er", "er"}, + {"O", "oo"}, + {"Ou", "ou"} }); private static readonly ReadOnlyDictionary first = new(new Dictionary(){ - {"ch", "i"}, - {"sh", "u"}, - {"zh", "v"} + {"Ch", "i"}, + {"Sh", "u"}, + {"Zh", "v"} }); From b816d1b866aa93b6d8f2da9f5cef334bda64748b Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 2 Jun 2024 15:21:04 +0800 Subject: [PATCH 013/545] Remove unused key in pinyin alphabet --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 1 - Flow.Launcher.Infrastructure/TranslationMapping.cs | 7 ------- 2 files changed, 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index cbec7feae..10799c676 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -83,7 +83,6 @@ namespace Flow.Launcher.Infrastructure map.endConstruct(); var key = resultBuilder.ToString(); - map.setKey(key); return _pinyinCache[content] = (key, map); } diff --git a/Flow.Launcher.Infrastructure/TranslationMapping.cs b/Flow.Launcher.Infrastructure/TranslationMapping.cs index f288c816a..c976fc522 100644 --- a/Flow.Launcher.Infrastructure/TranslationMapping.cs +++ b/Flow.Launcher.Infrastructure/TranslationMapping.cs @@ -12,13 +12,6 @@ namespace Flow.Launcher.Infrastructure private List translatedIndexs = new List(); private int translatedLength = 0; - public string key { get; private set; } - - public void setKey(string key) - { - this.key = key; - } - public void AddNewIndex(int originalIndex, int translatedIndex, int length) { if (constructed) From dd29b4ad4419aad72c58f0dac10f4f4a2e7e530b Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Sat, 22 Jun 2024 19:31:47 -0500 Subject: [PATCH 014/545] velopack prepare --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 1 + Flow.Launcher.Core/Updater.cs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index fe2cb7e58..a141243b7 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -57,6 +57,7 @@ + diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 3f64b273e..df2b2dae7 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -45,8 +45,8 @@ namespace Flow.Launcher.Core // UpdateApp CheckForUpdate will return value only if the app is squirrel installed var newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false); - var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString()); - var currentVersion = Version.Parse(Constant.Version); + var newReleaseVersion = SemanticVersioning.Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString()); + var currentVersion = SemanticVersioning.Version.Parse(Constant.Version); Log.Info($"|Updater.UpdateApp|Future Release <{newUpdateInfo.FutureReleaseEntry.Formatted()}>"); @@ -127,7 +127,7 @@ namespace Flow.Launcher.Core await using var jsonStream = await Http.GetStreamAsync(api).ConfigureAwait(false); var releases = await System.Text.Json.JsonSerializer.DeserializeAsync>(jsonStream).ConfigureAwait(false); - var latest = releases.Where(r => !r.Prerelease).OrderByDescending(r => r.PublishedAt).First(); + var latest = releases.OrderByDescending(r => r.PublishedAt).First(); var latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/"); var client = new WebClient From 865c865942a0c24efb31c1fbb36f6c4eca45db03 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Wed, 26 Feb 2025 22:37:41 +0800 Subject: [PATCH 015/545] update to .net 9 --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 2 +- .../Flow.Launcher.Infrastructure.csproj | 2 +- .../Flow.Launcher.Plugin.csproj | 2 +- Flow.Launcher.Test/Flow.Launcher.Test.csproj | 2 +- Flow.Launcher/Flow.Launcher.csproj | 3 +-- .../Net7.0-SelfContained.pubxml | 18 ------------------ ...Flow.Launcher.Plugin.BrowserBookmark.csproj | 2 +- .../Flow.Launcher.Plugin.Calculator.csproj | 2 +- .../Flow.Launcher.Plugin.Explorer.csproj | 2 +- ...Flow.Launcher.Plugin.PluginIndicator.csproj | 2 +- .../Flow.Launcher.Plugin.PluginsManager.csproj | 2 +- .../Flow.Launcher.Plugin.ProcessKiller.csproj | 2 +- .../Flow.Launcher.Plugin.Program.csproj | 2 +- .../Flow.Launcher.Plugin.Shell.csproj | 2 +- .../Flow.Launcher.Plugin.Sys.csproj | 2 +- .../Flow.Launcher.Plugin.Url.csproj | 2 +- .../Flow.Launcher.Plugin.WebSearch.csproj | 2 +- ...Flow.Launcher.Plugin.WindowsSettings.csproj | 2 +- README.md | 4 ++-- Scripts/flowlauncher.nuspec | 2 +- Scripts/post_build.ps1 | 2 +- 21 files changed, 21 insertions(+), 40 deletions(-) delete mode 100644 Flow.Launcher/Properties/PublishProfiles/Net7.0-SelfContained.pubxml diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index df2f4d2cb..8997ff58c 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -1,7 +1,7 @@ - net7.0-windows + net9.0-windows true true Library diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 5d8b26425..ed753b767 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -1,7 +1,7 @@ - net7.0-windows + net9.0-windows {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} Library true diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 2feb21b12..05c780cd8 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -1,7 +1,7 @@ - net7.0-windows + net9.0-windows {8451ECDD-2EA4-4966-BB0A-7BBC40138E80} true Library diff --git a/Flow.Launcher.Test/Flow.Launcher.Test.csproj b/Flow.Launcher.Test/Flow.Launcher.Test.csproj index 0241a374e..f04a9dcc9 100644 --- a/Flow.Launcher.Test/Flow.Launcher.Test.csproj +++ b/Flow.Launcher.Test/Flow.Launcher.Test.csproj @@ -1,7 +1,7 @@ - net7.0-windows10.0.19041.0 + net9.0-windows10.0.19041.0 {FF742965-9A80-41A5-B042-D6C7D3A21708} Library Properties diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 0baa1bef5..ef8bd8a3a 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -2,7 +2,7 @@ WinExe - net7.0-windows10.0.19041.0 + net9.0-windows10.0.19041.0 true false Flow.Launcher.App @@ -90,7 +90,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/Flow.Launcher/Properties/PublishProfiles/Net7.0-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net7.0-SelfContained.pubxml deleted file mode 100644 index 0e5cf4489..000000000 --- a/Flow.Launcher/Properties/PublishProfiles/Net7.0-SelfContained.pubxml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - FileSystem - Release - Any CPU - net7.0-windows10.0.19041.0 - ..\Output\Release\ - win-x64 - true - False - False - False - - diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index d7a626e1d..de6c017f2 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows true {9B130CC5-14FB-41FF-B310-0A95B6894C37} Properties diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj index 1b985acf9..0c2a08bf3 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows {59BD9891-3837-438A-958D-ADC7F91F6F7E} Properties Flow.Launcher.Plugin.Calculator 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 29925aeef..7a5809ad7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows true true true diff --git a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj index 21d964c11..d9e434f95 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows {FDED22C8-B637-42E8-824A-63B5B6E05A3A} Properties Flow.Launcher.Plugin.PluginIndicator diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj index b438305d6..b9c181fa3 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj @@ -1,7 +1,7 @@  Library - net7.0-windows + net9.0-windows true true true diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj index 4e216b7b2..7394e8a11 100644 --- a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows Flow.Launcher.Plugin.ProcessKiller Flow.Launcher.Plugin.ProcessKiller Flow-Launcher diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index 99c1a12e9..0c45a8590 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows10.0.19041.0 + net9.0-windows10.0.19041.0 {FDB3555B-58EF-4AE6-B5F1-904719637AB4} Properties Flow.Launcher.Plugin.Program diff --git a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj index 8f443214b..89410b7c9 100644 --- a/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj +++ b/Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows {C21BFF9C-2C99-4B5F-B7C9-A5E6DDDB37B0} Properties Flow.Launcher.Plugin.Shell diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj index dbc36ad42..999003fd8 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj +++ b/Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows {0B9DE348-9361-4940-ADB6-F5953BFFCCEC} Properties Flow.Launcher.Plugin.Sys diff --git a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj index 6d338733e..fdfe03224 100644 --- a/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj +++ b/Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows {A3DCCBCA-ACC1-421D-B16E-210896234C26} true Properties diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj index 55d69d526..3850cd3d2 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj @@ -2,7 +2,7 @@ Library - net7.0-windows + net9.0-windows {403B57F2-1856-4FC7-8A24-36AB346B763E} Properties true diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Flow.Launcher.Plugin.WindowsSettings.csproj b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Flow.Launcher.Plugin.WindowsSettings.csproj index 73fcd9f83..879cea6f8 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Flow.Launcher.Plugin.WindowsSettings.csproj +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Flow.Launcher.Plugin.WindowsSettings.csproj @@ -1,7 +1,7 @@  Library - net7.0-windows + net9.0-windows true true false diff --git a/README.md b/README.md index 02ffc7932..2b307e09a 100644 --- a/README.md +++ b/README.md @@ -391,7 +391,7 @@ Get in touch if you like to join the Flow-Launcher Team and help build this grea - Install Visual Studio 2022 -- Install .Net 7 SDK +- Install .Net 9 SDK - via Visual Studio installer - via winget `winget install Microsoft.DotNet.SDK.7` - - Manually from [here](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) + - Manually from [here](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) diff --git a/Scripts/flowlauncher.nuspec b/Scripts/flowlauncher.nuspec index 8d753bc8c..fa12150cc 100644 --- a/Scripts/flowlauncher.nuspec +++ b/Scripts/flowlauncher.nuspec @@ -11,6 +11,6 @@ Flow Launcher - Quick file search and app launcher for Windows with community-made plugins - + diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index 1757ed99e..da5672e32 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -99,7 +99,7 @@ function Pack-Squirrel-Installer ($path, $version, $output) { function Publish-Self-Contained ($p) { $csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve - $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/Net7.0-SelfContained.pubxml" -Resolve + $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/net9.0-SelfContained.pubxml" -Resolve # we call dotnet publish on the main project. # The other projects should have been built in Release at this point. From bfa1c91d339518b40c14a24c7f18f3b0c1128176 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Wed, 26 Feb 2025 22:46:08 +0800 Subject: [PATCH 016/545] fix typo --- Scripts/post_build.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scripts/post_build.ps1 b/Scripts/post_build.ps1 index da5672e32..a76f8258e 100644 --- a/Scripts/post_build.ps1 +++ b/Scripts/post_build.ps1 @@ -99,7 +99,7 @@ function Pack-Squirrel-Installer ($path, $version, $output) { function Publish-Self-Contained ($p) { $csproj = Join-Path "$p" "Flow.Launcher/Flow.Launcher.csproj" -Resolve - $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/net9.0-SelfContained.pubxml" -Resolve + $profile = Join-Path "$p" "Flow.Launcher/Properties/PublishProfiles/Net9.0-SelfContained.pubxml" -Resolve # we call dotnet publish on the main project. # The other projects should have been built in Release at this point. From 563cb74997dac2c54bbce7a3f7a57167bf2c3200 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Wed, 26 Feb 2025 22:57:31 +0800 Subject: [PATCH 017/545] add ignored publish profile --- .../Properties/Net9.0-SelfContained.pubxml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Flow.Launcher/Properties/Net9.0-SelfContained.pubxml diff --git a/Flow.Launcher/Properties/Net9.0-SelfContained.pubxml b/Flow.Launcher/Properties/Net9.0-SelfContained.pubxml new file mode 100644 index 000000000..ff4111116 --- /dev/null +++ b/Flow.Launcher/Properties/Net9.0-SelfContained.pubxml @@ -0,0 +1,18 @@ + + + + + FileSystem + Release + Any CPU + net9.0-windows10.0.19041.0 + ..\Output\Release\ + win-x64 + true + False + False + False + + From 684ff1080b3ff17047bf24145c8a82f62703b918 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Wed, 26 Feb 2025 23:12:29 +0800 Subject: [PATCH 018/545] add ignored publish profile file --- .../Net9.0-SelfContained.pubxml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Flow.Launcher/Properties/PublishProfiles/Net9.0-SelfContained.pubxml diff --git a/Flow.Launcher/Properties/PublishProfiles/Net9.0-SelfContained.pubxml b/Flow.Launcher/Properties/PublishProfiles/Net9.0-SelfContained.pubxml new file mode 100644 index 000000000..b9b6776d1 --- /dev/null +++ b/Flow.Launcher/Properties/PublishProfiles/Net9.0-SelfContained.pubxml @@ -0,0 +1,18 @@ + + + + + FileSystem + Release + Any CPU + net9.0-windows10.0.19041.0 + ..\Output\Release\ + win-x64 + true + False + False + False + + From debd4159f14416d5fb887918837b0a916a94ae71 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 28 Feb 2025 02:15:52 -0600 Subject: [PATCH 019/545] update system.drawing.common --- .../Flow.Launcher.Infrastructure.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index ed753b767..89fc211b9 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -67,7 +67,7 @@ - + From 555188058d34c0e690e3005f29213eadca2e41a9 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 28 Feb 2025 02:23:45 -0600 Subject: [PATCH 020/545] restore package with lock file --- Flow.Launcher.Core/Flow.Launcher.Core.csproj | 1 + Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj | 1 + Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj | 1 + Flow.Launcher/Flow.Launcher.csproj | 1 + 4 files changed, 4 insertions(+) diff --git a/Flow.Launcher.Core/Flow.Launcher.Core.csproj b/Flow.Launcher.Core/Flow.Launcher.Core.csproj index 8997ff58c..2ec88b2d3 100644 --- a/Flow.Launcher.Core/Flow.Launcher.Core.csproj +++ b/Flow.Launcher.Core/Flow.Launcher.Core.csproj @@ -12,6 +12,7 @@ false false en + true diff --git a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj index 89fc211b9..4d6c06773 100644 --- a/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj +++ b/Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj @@ -12,6 +12,7 @@ false false true + true diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 05c780cd8..fc988c1bc 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -11,6 +11,7 @@ false false false + true diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index ef8bd8a3a..58d96d7f5 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -12,6 +12,7 @@ false false en + true From d57eb6c8d4f788cebcfd0716ef415e17d9517d83 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 28 Feb 2025 02:27:29 -0600 Subject: [PATCH 021/545] add packages.lock.json --- Flow.Launcher.Core/packages.lock.json | 238 +++++++ .../packages.lock.json | 155 +++++ Flow.Launcher.Plugin/packages.lock.json | 77 ++ Flow.Launcher/packages.lock.json | 655 ++++++++++++++++++ 4 files changed, 1125 insertions(+) create mode 100644 Flow.Launcher.Core/packages.lock.json create mode 100644 Flow.Launcher.Infrastructure/packages.lock.json create mode 100644 Flow.Launcher.Plugin/packages.lock.json create mode 100644 Flow.Launcher/packages.lock.json diff --git a/Flow.Launcher.Core/packages.lock.json b/Flow.Launcher.Core/packages.lock.json new file mode 100644 index 000000000..0c513951b --- /dev/null +++ b/Flow.Launcher.Core/packages.lock.json @@ -0,0 +1,238 @@ +{ + "version": 1, + "dependencies": { + "net9.0-windows7.0": { + "Droplex": { + "type": "Direct", + "requested": "[1.7.0, )", + "resolved": "1.7.0", + "contentHash": "wutfIus/Ufw/9TDsp86R1ycnIH+wWrj4UhcmrzAHWjsdyC2iM07WEQ9+APTB7pQynsDnYH1r2i58XgAJ3lxUXA==", + "dependencies": { + "YamlDotNet": "9.1.0" + } + }, + "FSharp.Core": { + "type": "Direct", + "requested": "[9.0.101, )", + "resolved": "9.0.101", + "contentHash": "3/YR1SDWFA+Ojx9HiBwND+0UR8ZWoeZfkhD0DWAPCDdr/YI+CyFkArmMGzGSyPXeYtjG0sy0emzfyNwjt7zhig==" + }, + "Meziantou.Framework.Win32.Jobs": { + "type": "Direct", + "requested": "[3.4.0, )", + "resolved": "3.4.0", + "contentHash": "5GGLckfpwoC1jznInEYfK2INrHyD7K1RtwZJ98kNPKBU6jeu24i4zfgDGHHfb+eK3J+eFPAxo0aYcbUxNXIbNw==" + }, + "Microsoft.IO.RecyclableMemoryStream": { + "type": "Direct", + "requested": "[3.0.1, )", + "resolved": "3.0.1", + "contentHash": "s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==" + }, + "squirrel.windows": { + "type": "Direct", + "requested": "[1.5.2, )", + "resolved": "1.5.2", + "contentHash": "89Y/CFxWm7SEOjvuV2stVa8p+SNM9GOLk4tUNm2nUF792nfkimAgwRA/umVsdyd/OXBH8byXSh4V1qck88ZAyQ==", + "dependencies": { + "DeltaCompressionDotNet": "[1.0.0, 2.0.0)", + "Mono.Cecil": "0.9.6.1", + "Splat": "1.6.2" + } + }, + "StreamJsonRpc": { + "type": "Direct", + "requested": "[2.20.20, )", + "resolved": "2.20.20", + "contentHash": "gwG7KViLbSWS7EI0kYevinVmIga9wZNrpSY/FnWyC6DbdjKJ1xlv/FV1L9b0rLkVP8cGxfIMexdvo/+2W5eq6Q==", + "dependencies": { + "MessagePack": "2.5.187", + "Microsoft.VisualStudio.Threading": "17.10.48", + "Microsoft.VisualStudio.Threading.Analyzers": "17.10.48", + "Microsoft.VisualStudio.Validation": "17.8.8", + "Nerdbank.Streams": "2.11.74", + "Newtonsoft.Json": "13.0.1", + "System.IO.Pipelines": "8.0.0" + } + }, + "Ben.Demystifier": { + "type": "Transitive", + "resolved": "0.4.1", + "contentHash": "axFeEMfmEORy3ipAzOXG/lE+KcNptRbei3F0C4kQCdeiQtW+qJW90K5iIovITGrdLt8AjhNCwk5qLSX9/rFpoA==", + "dependencies": { + "System.Reflection.Metadata": "5.0.0" + } + }, + "BitFaster.Caching": { + "type": "Transitive", + "resolved": "2.5.3", + "contentHash": "Vo/39qcam5Xe+DbyfH0JZyqPswdOoa7jv4PGtRJ6Wj8AU+aZ+TuJRlJcIe+MQjRTJwliI8k8VSQpN8sEoBIv2g==" + }, + "CommunityToolkit.Mvvm": { + "type": "Transitive", + "resolved": "8.4.0", + "contentHash": "tqVU8yc/ADO9oiTRyTnwhFN68hCwvkliMierptWOudIAvWY1mWCh5VFh+guwHJmpMwfg0J0rY+yyd5Oy7ty9Uw==" + }, + "DeltaCompressionDotNet": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "nwbZAYd+DblXAIzlnwDSnl0CiCm8jWLfHSYnoN4wYhtIav6AegB3+T/vKzLbU2IZlPB8Bvl8U3NXpx3eaz+N5w==" + }, + "JetBrains.Annotations": { + "type": "Transitive", + "resolved": "2024.3.0", + "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug==" + }, + "MemoryPack": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "cwCtED8y400vMWx/Vp0QCSeEpVFjDU4JwF52VX9WTaqVERUvNqjG9n6osFlmFuytegyXnHvYEu1qRJ8rv/rkbg==", + "dependencies": { + "MemoryPack.Core": "1.21.3", + "MemoryPack.Generator": "1.21.3" + } + }, + "MemoryPack.Core": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "ajrYoBWT2aKeH4tlY8q/1C9qK1R/NK+7FkuVOX58ebOSxkABoFTqCR7W+Zk2rakUHZiEgNdRqO67hiRZPq6fLA==" + }, + "MemoryPack.Generator": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "hYU0TAIarDKnbkNIWvb7P4zBUL+CTahkuNkczsKvycSMR5kiwQ4IfLexywNKX3s05Izp4gzDSPbueepNWZRpWA==" + }, + "MessagePack": { + "type": "Transitive", + "resolved": "2.5.187", + "contentHash": "uW4j8m4Nc+2Mk5n6arOChavJ9bLjkis0qWASOj2h2OwmfINuzYv+mjCHUymrYhmyyKTu3N+ObtTXAY4uQ7jIhg==", + "dependencies": { + "MessagePack.Annotations": "2.5.187", + "Microsoft.NET.StringTools": "17.6.3" + } + }, + "MessagePack.Annotations": { + "type": "Transitive", + "resolved": "2.5.187", + "contentHash": "/IvvMMS8opvlHjEJ/fR2Cal4Co726Kj77Z8KiohFhuHfLHHmb9uUxW5+tSCL4ToKFfkQlrS3HD638mRq83ySqA==" + }, + "Microsoft.NET.StringTools": { + "type": "Transitive", + "resolved": "17.6.3", + "contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA==" + }, + "Microsoft.VisualStudio.Threading": { + "type": "Transitive", + "resolved": "17.12.19", + "contentHash": "eLiGMkMYyaSguqHs3lsrFxy3tAWSLuPEL2pIWRcADMDVAs2xqm3dr1d9QYjiEusTgiClF9KD6OB2NdZP72Oy0Q==", + "dependencies": { + "Microsoft.VisualStudio.Threading.Analyzers": "17.12.19", + "Microsoft.VisualStudio.Validation": "17.8.8" + } + }, + "Microsoft.VisualStudio.Threading.Analyzers": { + "type": "Transitive", + "resolved": "17.12.19", + "contentHash": "v3IYeedjoktvZ+GqYmLudxZJngmf/YWIxNT2Uy6QMMN19cvw+nkWoip1Gr1RtnFkUo1MPUVMis4C8Kj8d8DpSQ==" + }, + "Microsoft.VisualStudio.Validation": { + "type": "Transitive", + "resolved": "17.8.8", + "contentHash": "rWXThIpyQd4YIXghNkiv2+VLvzS+MCMKVRDR0GAMlflsdo+YcAN2g2r5U1Ah98OFjQMRexTFtXQQ2LkajxZi3g==" + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "9.0.2", + "contentHash": "5BkGZ6mHp2dHydR29sb0fDfAuqkv30AHtTih8wMzvPZysOmBFvHfnkR2w3tsc0pSiIg8ZoKyefJXWy9r3pBh0w==" + }, + "Mono.Cecil": { + "type": "Transitive", + "resolved": "0.9.6.1", + "contentHash": "yMsurNaOxxKIjyW9pEB+tRrR1S3DFnN1+iBgKvYvXG8kW0Y6yknJeMAe/tl3+P78/2C6304TgF7aVqpqXgEQ9Q==" + }, + "Nerdbank.Streams": { + "type": "Transitive", + "resolved": "2.11.74", + "contentHash": "r4G7uHHfoo8LCilPOdtf2C+Q5ymHOAXtciT4ZtB2xRlAvv4gPkWBYNAijFblStv3+uidp81j5DP11jMZl4BfJw==", + "dependencies": { + "Microsoft.VisualStudio.Threading": "17.10.48", + "Microsoft.VisualStudio.Validation": "17.8.8", + "System.IO.Pipelines": "8.0.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NLog": { + "type": "Transitive", + "resolved": "4.7.10", + "contentHash": "rcegW7kYOCjl7wX0SzsqpPBqnJ51JKi1WkYb6QBVX0Wc5IgH19Pv4t/co+T0s06OS0Ne44xgkY/mHg0PdrmJow==" + }, + "PropertyChanged.Fody": { + "type": "Transitive", + "resolved": "3.4.0", + "contentHash": "IAZyq0uolKo2WYm4mjx+q7A8fSGFT0x2e1s3y+ODn4JI0kqTDoo9GF2tdaypUzRFJZfdMxfC5HZW9QzdJLtOnA==", + "dependencies": { + "Fody": "6.5.1" + } + }, + "Splat": { + "type": "Transitive", + "resolved": "1.6.2", + "contentHash": "DeH0MxPU+D4JchkIDPYG4vUT+hsWs9S41cFle0/4K5EJMXWurx5DzAkj2366DfK14/XKNhsu6tCl4dZXJ3CD4w==" + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "9.0.2", + "contentHash": "JU947wzf8JbBS16Y5EIZzAlyQU+k68D7LRx6y03s2wlhlvLqkt/8uPBrjv2hJnnaJKbdb0GhQ3JZsfYXhrRjyg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "9.0.2" + } + }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" + }, + "ToolGood.Words.Pinyin": { + "type": "Transitive", + "resolved": "3.0.1.4", + "contentHash": "uQo97618y9yzLDxrnehPN+/tuiOlk5BqieEdwctHZOAS9miMXnHKgMFYVw8CSGXRglyTYXlrW7qtUlU7Fje5Ew==" + }, + "YamlDotNet": { + "type": "Transitive", + "resolved": "9.1.0", + "contentHash": "fuvGXU4Ec5HrsmEc+BiFTNPCRf1cGBI2kh/3RzMWgddM2M4ALhbSPoI3X3mhXZUD1qqQd9oSkFAtWjpz8z9eRg==" + }, + "flow.launcher.infrastructure": { + "type": "Project", + "dependencies": { + "Ben.Demystifier": "[0.4.1, )", + "BitFaster.Caching": "[2.5.3, )", + "CommunityToolkit.Mvvm": "[8.4.0, )", + "Flow.Launcher.Plugin": "[4.4.0, )", + "MemoryPack": "[1.21.3, )", + "Microsoft.VisualStudio.Threading": "[17.12.19, )", + "NLog": "[4.7.10, )", + "PropertyChanged.Fody": "[3.4.0, )", + "System.Drawing.Common": "[9.0.2, )", + "ToolGood.Words.Pinyin": "[3.0.1.4, )" + } + }, + "flow.launcher.plugin": { + "type": "Project", + "dependencies": { + "JetBrains.Annotations": "[2024.3.0, )", + "PropertyChanged.Fody": "[3.4.0, )" + } + } + } + } +} \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/packages.lock.json b/Flow.Launcher.Infrastructure/packages.lock.json new file mode 100644 index 000000000..f38f91ef9 --- /dev/null +++ b/Flow.Launcher.Infrastructure/packages.lock.json @@ -0,0 +1,155 @@ +{ + "version": 1, + "dependencies": { + "net9.0-windows7.0": { + "Ben.Demystifier": { + "type": "Direct", + "requested": "[0.4.1, )", + "resolved": "0.4.1", + "contentHash": "axFeEMfmEORy3ipAzOXG/lE+KcNptRbei3F0C4kQCdeiQtW+qJW90K5iIovITGrdLt8AjhNCwk5qLSX9/rFpoA==", + "dependencies": { + "System.Reflection.Metadata": "5.0.0" + } + }, + "BitFaster.Caching": { + "type": "Direct", + "requested": "[2.5.3, )", + "resolved": "2.5.3", + "contentHash": "Vo/39qcam5Xe+DbyfH0JZyqPswdOoa7jv4PGtRJ6Wj8AU+aZ+TuJRlJcIe+MQjRTJwliI8k8VSQpN8sEoBIv2g==" + }, + "CommunityToolkit.Mvvm": { + "type": "Direct", + "requested": "[8.4.0, )", + "resolved": "8.4.0", + "contentHash": "tqVU8yc/ADO9oiTRyTnwhFN68hCwvkliMierptWOudIAvWY1mWCh5VFh+guwHJmpMwfg0J0rY+yyd5Oy7ty9Uw==" + }, + "Fody": { + "type": "Direct", + "requested": "[6.5.5, )", + "resolved": "6.5.5", + "contentHash": "Krca41L/PDva1VsmDec5n52cQZxQAQp/bsHdzsNi8iLLI0lqKL94fNIkNaC8tVolUkCyWsbzvxfxJCeD2789fA==" + }, + "MemoryPack": { + "type": "Direct", + "requested": "[1.21.3, )", + "resolved": "1.21.3", + "contentHash": "cwCtED8y400vMWx/Vp0QCSeEpVFjDU4JwF52VX9WTaqVERUvNqjG9n6osFlmFuytegyXnHvYEu1qRJ8rv/rkbg==", + "dependencies": { + "MemoryPack.Core": "1.21.3", + "MemoryPack.Generator": "1.21.3" + } + }, + "Microsoft.VisualStudio.Threading": { + "type": "Direct", + "requested": "[17.12.19, )", + "resolved": "17.12.19", + "contentHash": "eLiGMkMYyaSguqHs3lsrFxy3tAWSLuPEL2pIWRcADMDVAs2xqm3dr1d9QYjiEusTgiClF9KD6OB2NdZP72Oy0Q==", + "dependencies": { + "Microsoft.VisualStudio.Threading.Analyzers": "17.12.19", + "Microsoft.VisualStudio.Validation": "17.8.8" + } + }, + "Microsoft.Windows.CsWin32": { + "type": "Direct", + "requested": "[0.3.106, )", + "resolved": "0.3.106", + "contentHash": "Mx5fK7uN6fwLR4wUghs6//HonAnwPBNmC2oonyJVhCUlHS/r6SUS3NkBc3+gaQiv+0/9bqdj1oSCKQFkNI+21Q==", + "dependencies": { + "Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha", + "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview", + "Microsoft.Windows.WDK.Win32Metadata": "0.11.4-experimental" + } + }, + "NLog": { + "type": "Direct", + "requested": "[4.7.10, )", + "resolved": "4.7.10", + "contentHash": "rcegW7kYOCjl7wX0SzsqpPBqnJ51JKi1WkYb6QBVX0Wc5IgH19Pv4t/co+T0s06OS0Ne44xgkY/mHg0PdrmJow==" + }, + "PropertyChanged.Fody": { + "type": "Direct", + "requested": "[3.4.0, )", + "resolved": "3.4.0", + "contentHash": "IAZyq0uolKo2WYm4mjx+q7A8fSGFT0x2e1s3y+ODn4JI0kqTDoo9GF2tdaypUzRFJZfdMxfC5HZW9QzdJLtOnA==", + "dependencies": { + "Fody": "6.5.1" + } + }, + "System.Drawing.Common": { + "type": "Direct", + "requested": "[9.0.2, )", + "resolved": "9.0.2", + "contentHash": "JU947wzf8JbBS16Y5EIZzAlyQU+k68D7LRx6y03s2wlhlvLqkt/8uPBrjv2hJnnaJKbdb0GhQ3JZsfYXhrRjyg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "9.0.2" + } + }, + "ToolGood.Words.Pinyin": { + "type": "Direct", + "requested": "[3.0.1.4, )", + "resolved": "3.0.1.4", + "contentHash": "uQo97618y9yzLDxrnehPN+/tuiOlk5BqieEdwctHZOAS9miMXnHKgMFYVw8CSGXRglyTYXlrW7qtUlU7Fje5Ew==" + }, + "JetBrains.Annotations": { + "type": "Transitive", + "resolved": "2024.3.0", + "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug==" + }, + "MemoryPack.Core": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "ajrYoBWT2aKeH4tlY8q/1C9qK1R/NK+7FkuVOX58ebOSxkABoFTqCR7W+Zk2rakUHZiEgNdRqO67hiRZPq6fLA==" + }, + "MemoryPack.Generator": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "hYU0TAIarDKnbkNIWvb7P4zBUL+CTahkuNkczsKvycSMR5kiwQ4IfLexywNKX3s05Izp4gzDSPbueepNWZRpWA==" + }, + "Microsoft.VisualStudio.Threading.Analyzers": { + "type": "Transitive", + "resolved": "17.12.19", + "contentHash": "v3IYeedjoktvZ+GqYmLudxZJngmf/YWIxNT2Uy6QMMN19cvw+nkWoip1Gr1RtnFkUo1MPUVMis4C8Kj8d8DpSQ==" + }, + "Microsoft.VisualStudio.Validation": { + "type": "Transitive", + "resolved": "17.8.8", + "contentHash": "rWXThIpyQd4YIXghNkiv2+VLvzS+MCMKVRDR0GAMlflsdo+YcAN2g2r5U1Ah98OFjQMRexTFtXQQ2LkajxZi3g==" + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "9.0.2", + "contentHash": "5BkGZ6mHp2dHydR29sb0fDfAuqkv30AHtTih8wMzvPZysOmBFvHfnkR2w3tsc0pSiIg8ZoKyefJXWy9r3pBh0w==" + }, + "Microsoft.Windows.SDK.Win32Docs": { + "type": "Transitive", + "resolved": "0.1.42-alpha", + "contentHash": "Z/9po23gUA9aoukirh2ItMU2ZS9++Js9Gdds9fu5yuMojDrmArvY2y+tq9985tR3cxFxpZO1O35Wjfo0khj5HA==" + }, + "Microsoft.Windows.SDK.Win32Metadata": { + "type": "Transitive", + "resolved": "60.0.34-preview", + "contentHash": "TA3DUNi4CTeo+ItTXBnGZFt2159XOGSl0UOlG5vjDj4WHqZjhwYyyUnzOtrbCERiSaP2Hzg7otJNWwOSZgutyA==" + }, + "Microsoft.Windows.WDK.Win32Metadata": { + "type": "Transitive", + "resolved": "0.11.4-experimental", + "contentHash": "bf5MCmUyZf0gBlYQjx9UpRAZWBkRndyt9XicR+UNLvAUAFTZQbu6YaX/sNKZlR98Grn0gydfh/yT4I3vc0AIQA==", + "dependencies": { + "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview" + } + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" + }, + "flow.launcher.plugin": { + "type": "Project", + "dependencies": { + "JetBrains.Annotations": "[2024.3.0, )", + "PropertyChanged.Fody": "[3.4.0, )" + } + } + } + } +} \ No newline at end of file diff --git a/Flow.Launcher.Plugin/packages.lock.json b/Flow.Launcher.Plugin/packages.lock.json new file mode 100644 index 000000000..6cdf96e07 --- /dev/null +++ b/Flow.Launcher.Plugin/packages.lock.json @@ -0,0 +1,77 @@ +{ + "version": 1, + "dependencies": { + "net9.0-windows7.0": { + "Fody": { + "type": "Direct", + "requested": "[6.5.4, )", + "resolved": "6.5.4", + "contentHash": "GXZuti428IZctfby10xkMbWLCibcb6s29I/psLbBoO2vHJI5eTNVybnlV/Wi1tlIu9GG0bgW/PQwMH+MCldHxw==" + }, + "JetBrains.Annotations": { + "type": "Direct", + "requested": "[2024.3.0, )", + "resolved": "2024.3.0", + "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug==" + }, + "Microsoft.SourceLink.GitHub": { + "type": "Direct", + "requested": "[1.1.1, )", + "resolved": "1.1.1", + "contentHash": "IaJGnOv/M7UQjRJks7B6p7pbPnOwisYGOIzqCz5ilGFTApZ3ktOR+6zJ12ZRPInulBmdAf1SrGdDG2MU8g6XTw==", + "dependencies": { + "Microsoft.Build.Tasks.Git": "1.1.1", + "Microsoft.SourceLink.Common": "1.1.1" + } + }, + "Microsoft.Windows.CsWin32": { + "type": "Direct", + "requested": "[0.3.106, )", + "resolved": "0.3.106", + "contentHash": "Mx5fK7uN6fwLR4wUghs6//HonAnwPBNmC2oonyJVhCUlHS/r6SUS3NkBc3+gaQiv+0/9bqdj1oSCKQFkNI+21Q==", + "dependencies": { + "Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha", + "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview", + "Microsoft.Windows.WDK.Win32Metadata": "0.11.4-experimental" + } + }, + "PropertyChanged.Fody": { + "type": "Direct", + "requested": "[3.4.0, )", + "resolved": "3.4.0", + "contentHash": "IAZyq0uolKo2WYm4mjx+q7A8fSGFT0x2e1s3y+ODn4JI0kqTDoo9GF2tdaypUzRFJZfdMxfC5HZW9QzdJLtOnA==", + "dependencies": { + "Fody": "6.5.1" + } + }, + "Microsoft.Build.Tasks.Git": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "AT3HlgTjsqHnWpBHSNeR0KxbLZD7bztlZVj7I8vgeYG9SYqbeFGh0TM/KVtC6fg53nrWHl3VfZFvb5BiQFcY6Q==" + }, + "Microsoft.SourceLink.Common": { + "type": "Transitive", + "resolved": "1.1.1", + "contentHash": "WMcGpWKrmJmzrNeuaEb23bEMnbtR/vLmvZtkAP5qWu7vQsY59GqfRJd65sFpBszbd2k/bQ8cs8eWawQKAabkVg==" + }, + "Microsoft.Windows.SDK.Win32Docs": { + "type": "Transitive", + "resolved": "0.1.42-alpha", + "contentHash": "Z/9po23gUA9aoukirh2ItMU2ZS9++Js9Gdds9fu5yuMojDrmArvY2y+tq9985tR3cxFxpZO1O35Wjfo0khj5HA==" + }, + "Microsoft.Windows.SDK.Win32Metadata": { + "type": "Transitive", + "resolved": "60.0.34-preview", + "contentHash": "TA3DUNi4CTeo+ItTXBnGZFt2159XOGSl0UOlG5vjDj4WHqZjhwYyyUnzOtrbCERiSaP2Hzg7otJNWwOSZgutyA==" + }, + "Microsoft.Windows.WDK.Win32Metadata": { + "type": "Transitive", + "resolved": "0.11.4-experimental", + "contentHash": "bf5MCmUyZf0gBlYQjx9UpRAZWBkRndyt9XicR+UNLvAUAFTZQbu6YaX/sNKZlR98Grn0gydfh/yT4I3vc0AIQA==", + "dependencies": { + "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview" + } + } + } + } +} \ No newline at end of file diff --git a/Flow.Launcher/packages.lock.json b/Flow.Launcher/packages.lock.json new file mode 100644 index 000000000..2768db74b --- /dev/null +++ b/Flow.Launcher/packages.lock.json @@ -0,0 +1,655 @@ +{ + "version": 1, + "dependencies": { + "net9.0-windows10.0.19041": { + "ChefKeys": { + "type": "Direct", + "requested": "[0.1.2, )", + "resolved": "0.1.2", + "contentHash": "hnayWejg57tg8+lZ1Q/zPR8tj9ezUtB1sY8aCv9jiZ+3wcqK0eGL+Skt9OzT9mjSsBIg4o9Jv1HdQdzjd1lkQw==" + }, + "CommunityToolkit.Mvvm": { + "type": "Direct", + "requested": "[8.4.0, )", + "resolved": "8.4.0", + "contentHash": "tqVU8yc/ADO9oiTRyTnwhFN68hCwvkliMierptWOudIAvWY1mWCh5VFh+guwHJmpMwfg0J0rY+yyd5Oy7ty9Uw==" + }, + "Fody": { + "type": "Direct", + "requested": "[6.5.4, )", + "resolved": "6.5.4", + "contentHash": "GXZuti428IZctfby10xkMbWLCibcb6s29I/psLbBoO2vHJI5eTNVybnlV/Wi1tlIu9GG0bgW/PQwMH+MCldHxw==" + }, + "InputSimulator": { + "type": "Direct", + "requested": "[1.0.4, )", + "resolved": "1.0.4", + "contentHash": "D0LvRCPQMX6/FJHBjng+RO+wRDuHTJrfo7IAc7rmkPvRqchdVGJWg3y70peOtDy3OLNK+HSOwVkH4GiuLnkKgA==" + }, + "Microsoft.Extensions.DependencyInjection": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "elNeOmkeX3eDVG6pYVeV82p29hr+UKDaBhrZyWvWLw/EVZSYEkZlQdkp0V39k/Xehs2Qa0mvoCvkVj3eQxNQ1Q==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.Hosting": { + "type": "Direct", + "requested": "[7.0.0, )", + "resolved": "7.0.0", + "contentHash": "4nFc8xCfK26G524ioreZvz/IeIKN/gY1LApoGpaIThKqBdTwauUo4ETCf12lQcoefijqe3Imnfvnk31IezFatg==", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.Configuration.CommandLine": "7.0.0", + "Microsoft.Extensions.Configuration.EnvironmentVariables": "7.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0", + "Microsoft.Extensions.Configuration.Json": "7.0.0", + "Microsoft.Extensions.Configuration.UserSecrets": "7.0.0", + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Physical": "7.0.0", + "Microsoft.Extensions.Hosting.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Configuration": "7.0.0", + "Microsoft.Extensions.Logging.Console": "7.0.0", + "Microsoft.Extensions.Logging.Debug": "7.0.0", + "Microsoft.Extensions.Logging.EventLog": "7.0.0", + "Microsoft.Extensions.Logging.EventSource": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + } + }, + "Microsoft.Toolkit.Uwp.Notifications": { + "type": "Direct", + "requested": "[7.1.3, )", + "resolved": "7.1.3", + "contentHash": "A1dglAzb24gjehmb7DwGd07mfyZ1gacAK7ObE0KwDlRc3mayH2QW7cSOy3TkkyELjLg19OQBuhPOj4SpXET9lg==", + "dependencies": { + "Microsoft.Win32.Registry": "4.7.0", + "System.Drawing.Common": "4.7.0", + "System.Reflection.Emit": "4.7.0", + "System.ValueTuple": "4.5.0" + } + }, + "Microsoft.Windows.CsWin32": { + "type": "Direct", + "requested": "[0.3.106, )", + "resolved": "0.3.106", + "contentHash": "Mx5fK7uN6fwLR4wUghs6//HonAnwPBNmC2oonyJVhCUlHS/r6SUS3NkBc3+gaQiv+0/9bqdj1oSCKQFkNI+21Q==", + "dependencies": { + "Microsoft.Windows.SDK.Win32Docs": "0.1.42-alpha", + "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview", + "Microsoft.Windows.WDK.Win32Metadata": "0.11.4-experimental" + } + }, + "ModernWpfUI": { + "type": "Direct", + "requested": "[0.9.4, )", + "resolved": "0.9.4", + "contentHash": "HJ07Be9KOiGKGcMLz/AwY+84h3yGHRPuYpYXCE6h1yPtaFwGMWfanZ70jX7W5XWx8+Qk1vGox+WGKgxxsy6EHw==" + }, + "NHotkey.Wpf": { + "type": "Direct", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "BIUKlhTG5KtFf9OQzWvkmVmktt5/FFj6AOEgag8Uf0R2YdZt5ajUzs3sVskcJcT2TztWlEHKQr1jFj3KQ0D9Nw==", + "dependencies": { + "NHotkey": "3.0.0" + } + }, + "PropertyChanged.Fody": { + "type": "Direct", + "requested": "[3.4.0, )", + "resolved": "3.4.0", + "contentHash": "IAZyq0uolKo2WYm4mjx+q7A8fSGFT0x2e1s3y+ODn4JI0kqTDoo9GF2tdaypUzRFJZfdMxfC5HZW9QzdJLtOnA==", + "dependencies": { + "Fody": "6.5.1" + } + }, + "SemanticVersioning": { + "type": "Direct", + "requested": "[3.0.0, )", + "resolved": "3.0.0", + "contentHash": "RR+8GbPQ/gjDqov/1QN1OPoUlbUruNwcL3WjWCeLw+MY7+od/ENhnkYxCfAC6rQLIu3QifaJt3kPYyP3RumqMQ==" + }, + "TaskScheduler": { + "type": "Direct", + "requested": "[2.11.0, )", + "resolved": "2.11.0", + "contentHash": "p9wH58XSNIyUtO7PIFAEldaKUzpYmlj+YWAfnUqBKnGxIZRY51I9BrsBGJijUVwlxrgmLLPUigRIv2ZTD4uPJA==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0", + "System.Diagnostics.EventLog": "8.0.0", + "System.Security.AccessControl": "6.0.1" + } + }, + "VirtualizingWrapPanel": { + "type": "Direct", + "requested": "[2.1.1, )", + "resolved": "2.1.1", + "contentHash": "Fc/yjU8jqC3qpIsNxeO5RjK2lPU7xnJtBLMSQ6L9egA2PyJLQeVeXpG8WBb5N1kN15rlJEYG8dHWJ5qUGgaNrg==" + }, + "Ben.Demystifier": { + "type": "Transitive", + "resolved": "0.4.1", + "contentHash": "axFeEMfmEORy3ipAzOXG/lE+KcNptRbei3F0C4kQCdeiQtW+qJW90K5iIovITGrdLt8AjhNCwk5qLSX9/rFpoA==", + "dependencies": { + "System.Reflection.Metadata": "5.0.0" + } + }, + "BitFaster.Caching": { + "type": "Transitive", + "resolved": "2.5.3", + "contentHash": "Vo/39qcam5Xe+DbyfH0JZyqPswdOoa7jv4PGtRJ6Wj8AU+aZ+TuJRlJcIe+MQjRTJwliI8k8VSQpN8sEoBIv2g==" + }, + "DeltaCompressionDotNet": { + "type": "Transitive", + "resolved": "1.0.0", + "contentHash": "nwbZAYd+DblXAIzlnwDSnl0CiCm8jWLfHSYnoN4wYhtIav6AegB3+T/vKzLbU2IZlPB8Bvl8U3NXpx3eaz+N5w==" + }, + "Droplex": { + "type": "Transitive", + "resolved": "1.7.0", + "contentHash": "wutfIus/Ufw/9TDsp86R1ycnIH+wWrj4UhcmrzAHWjsdyC2iM07WEQ9+APTB7pQynsDnYH1r2i58XgAJ3lxUXA==", + "dependencies": { + "YamlDotNet": "9.1.0" + } + }, + "FSharp.Core": { + "type": "Transitive", + "resolved": "9.0.101", + "contentHash": "3/YR1SDWFA+Ojx9HiBwND+0UR8ZWoeZfkhD0DWAPCDdr/YI+CyFkArmMGzGSyPXeYtjG0sy0emzfyNwjt7zhig==" + }, + "JetBrains.Annotations": { + "type": "Transitive", + "resolved": "2024.3.0", + "contentHash": "ox5pkeLQXjvJdyAB4b2sBYAlqZGLh3PjSnP1bQNVx72ONuTJ9+34/+Rq91Fc0dG29XG9RgZur9+NcP4riihTug==" + }, + "MemoryPack": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "cwCtED8y400vMWx/Vp0QCSeEpVFjDU4JwF52VX9WTaqVERUvNqjG9n6osFlmFuytegyXnHvYEu1qRJ8rv/rkbg==", + "dependencies": { + "MemoryPack.Core": "1.21.3", + "MemoryPack.Generator": "1.21.3" + } + }, + "MemoryPack.Core": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "ajrYoBWT2aKeH4tlY8q/1C9qK1R/NK+7FkuVOX58ebOSxkABoFTqCR7W+Zk2rakUHZiEgNdRqO67hiRZPq6fLA==" + }, + "MemoryPack.Generator": { + "type": "Transitive", + "resolved": "1.21.3", + "contentHash": "hYU0TAIarDKnbkNIWvb7P4zBUL+CTahkuNkczsKvycSMR5kiwQ4IfLexywNKX3s05Izp4gzDSPbueepNWZRpWA==" + }, + "MessagePack": { + "type": "Transitive", + "resolved": "2.5.187", + "contentHash": "uW4j8m4Nc+2Mk5n6arOChavJ9bLjkis0qWASOj2h2OwmfINuzYv+mjCHUymrYhmyyKTu3N+ObtTXAY4uQ7jIhg==", + "dependencies": { + "MessagePack.Annotations": "2.5.187", + "Microsoft.NET.StringTools": "17.6.3" + } + }, + "MessagePack.Annotations": { + "type": "Transitive", + "resolved": "2.5.187", + "contentHash": "/IvvMMS8opvlHjEJ/fR2Cal4Co726Kj77Z8KiohFhuHfLHHmb9uUxW5+tSCL4ToKFfkQlrS3HD638mRq83ySqA==" + }, + "Meziantou.Framework.Win32.Jobs": { + "type": "Transitive", + "resolved": "3.4.0", + "contentHash": "5GGLckfpwoC1jznInEYfK2INrHyD7K1RtwZJ98kNPKBU6jeu24i4zfgDGHHfb+eK3J+eFPAxo0aYcbUxNXIbNw==" + }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "tldQUBWt/xeH2K7/hMPPo5g8zuLc3Ro9I5d4o/XrxvxOCA2EZBtW7bCHHTc49fcBtvB8tLAb/Qsmfrq+2SJ4vA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "f34u2eaqIjNO9YLHBz8rozVZ+TcFiFs0F3r7nUJd7FRkVSxk8u4OpoK226mi49MwexHOR2ibP9MFvRUaLilcQQ==", + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "tgU4u7bZsoS9MKVRiotVMAwHtbREHr5/5zSEV+JPhg46+ox47Au84E3D2IacAaB0bk5ePNaNieTlPrfjbbRJkg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.CommandLine": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "a8Iq8SCw5m8W5pZJcPCgBpBO4E89+NaObPng+ApIhrGSv9X4JPrcFAaGM4sDgR0X83uhLgsNJq8VnGP/wqhr8A==", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.EnvironmentVariables": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "RIkfqCkvrAogirjsqSrG1E1FxgrLsOZU2nhRbl07lrajnxzSU2isj2lwQah0CtCbLWo/pOIukQzM1GfneBUnxA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.FileExtensions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "xk2lRJ1RDuqe57BmgvRPyCt6zyePKUmvT6iuXqiHR+/OIIgWVR8Ff5k2p6DwmqY8a17hx/OnrekEhziEIeQP6Q==", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Physical": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.Json": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "LDNYe3uw76W35Jci+be4LDf2lkQZe0A7EEYQVChFbc509CpZ4Iupod8li4PUXPBhEUOFI/rlQNf5xkzJRQGvtA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "System.Text.Json": "7.0.0" + } + }, + "Microsoft.Extensions.Configuration.UserSecrets": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "33HPW1PmB2RS0ietBQyvOxjp4O3wlt+4tIs8KPyMn1kqp04goiZGa7+3mc69NRLv6bphkLDy0YR7Uw3aZyf8Zw==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Json": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Physical": "7.0.0" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "h3j/QfmFN4S0w4C2A6X7arXij/M/OVw3uQHSOFxnND4DyAzO1F9eMX7Eti7lU/OkSthEE0WzRsfT/Dmx86jzCw==" + }, + "Microsoft.Extensions.FileProviders.Abstractions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "NyawiW9ZT/liQb34k9YqBSNPLuuPkrjMgQZ24Y/xXX1RoiBkLUdPMaQTmxhZ5TYu8ZKZ9qayzil75JX95vGQUg==", + "dependencies": { + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.FileProviders.Physical": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "K8D2MTR+EtzkbZ8z80LrG7Ur64R7ZZdRLt1J5cgpc/pUWl0C6IkAUapPuK28oionHueCPELUqq0oYEvZfalNdg==", + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.FileSystemGlobbing": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "2jONjKHiF+E92ynz2ZFcr9OvxIw+rTGMPEH+UZGeHTEComVav93jQUWGkso8yWwVBcEJGcNcZAaqY01FFJcj7w==" + }, + "Microsoft.Extensions.Hosting.Abstractions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "43n9Je09z0p/7ViPxfRqs5BUItRLNVh5b6JH40F2Agkh2NBsY/jpNYTtbCcxrHCsA3oRmbR6RJBzUutB4VZvNQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "Nw2muoNrOG5U5qa2ZekXwudUn2BJcD41e65zwmDHb1fQegTX66UokLWZkJRpqSSHXDOWZ5V0iqhbxOEky91atA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "kmn78+LPVMOWeITUjIlfxUPDsI0R6G0RkeAMBmQxAJ7vBJn4q2dTva7pWi65ceN5vPGjJ9q/Uae2WKgvfktJAw==" + }, + "Microsoft.Extensions.Logging.Configuration": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "FLDA0HcffKA8ycoDQLJuCNGIE42cLWPxgdQGRBaSzZrYTkMBjnf9zrr8pGT06psLq9Q+RKWmmZczQ9bCrXEBcA==", + "dependencies": { + "Microsoft.Extensions.Configuration": "7.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Options.ConfigurationExtensions": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.Console": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "qt5n8bHLZPUfuRnFxJKW5q9ZwOTncdh96rtWzWpX3Y/064MlxzCSw2ELF5Jlwdo+Y4wK3I47NmUTFsV7Sg8rqg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging.Configuration": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.Text.Json": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.Debug": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "tFGGyPDpJ8ZdQdeckCArP7nZuoY3am9zJWuvp4OD1bHq65S0epW9BNHzAWeaIO4eYwWnGm1jRNt3vRciH8H6MA==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.EventLog": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "Rp7cYL9xQRVTgjMl77H5YDxszAaO+mlA+KT0BnLSVhuCoKQQOOs1sSK2/x8BK2dZ/lKeAC/CVF+20Ef2dpKXwg==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "System.Diagnostics.EventLog": "7.0.0" + } + }, + "Microsoft.Extensions.Logging.EventSource": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "MxQXndQFviIyOPqyMeLNshXnmqcfzEHE2wWcr7BF1unSisJgouZ3tItnq+aJLGPojrW8OZSC/ZdRoR6wAq+c7w==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Logging": "7.0.0", + "Microsoft.Extensions.Logging.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0", + "System.Text.Json": "7.0.0" + } + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.Options.ConfigurationExtensions": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "95UnxZkkFdXxF6vSrtJsMHCzkDeSMuUWGs2hDT54cX+U5eVajrCJ3qLyQRW+CtpTt5OJ8bmTvpQVHu1DLhH+cA==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", + "Microsoft.Extensions.Options": "7.0.0", + "Microsoft.Extensions.Primitives": "7.0.0" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "um1KU5kxcRp3CNuI8o/GrZtD4AIOXDk+RLsytjZ9QPok3ttLUelLKpilVPuaFT3TFjOhSibUAso0odbOaCDj3Q==" + }, + "Microsoft.IO.RecyclableMemoryStream": { + "type": "Transitive", + "resolved": "3.0.1", + "contentHash": "s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==" + }, + "Microsoft.NET.StringTools": { + "type": "Transitive", + "resolved": "17.6.3", + "contentHash": "N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA==" + }, + "Microsoft.VisualStudio.Threading": { + "type": "Transitive", + "resolved": "17.12.19", + "contentHash": "eLiGMkMYyaSguqHs3lsrFxy3tAWSLuPEL2pIWRcADMDVAs2xqm3dr1d9QYjiEusTgiClF9KD6OB2NdZP72Oy0Q==", + "dependencies": { + "Microsoft.VisualStudio.Threading.Analyzers": "17.12.19", + "Microsoft.VisualStudio.Validation": "17.8.8" + } + }, + "Microsoft.VisualStudio.Threading.Analyzers": { + "type": "Transitive", + "resolved": "17.12.19", + "contentHash": "v3IYeedjoktvZ+GqYmLudxZJngmf/YWIxNT2Uy6QMMN19cvw+nkWoip1Gr1RtnFkUo1MPUVMis4C8Kj8d8DpSQ==" + }, + "Microsoft.VisualStudio.Validation": { + "type": "Transitive", + "resolved": "17.8.8", + "contentHash": "rWXThIpyQd4YIXghNkiv2+VLvzS+MCMKVRDR0GAMlflsdo+YcAN2g2r5U1Ah98OFjQMRexTFtXQQ2LkajxZi3g==" + }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "Microsoft.Win32.SystemEvents": { + "type": "Transitive", + "resolved": "9.0.2", + "contentHash": "5BkGZ6mHp2dHydR29sb0fDfAuqkv30AHtTih8wMzvPZysOmBFvHfnkR2w3tsc0pSiIg8ZoKyefJXWy9r3pBh0w==" + }, + "Microsoft.Windows.SDK.Win32Docs": { + "type": "Transitive", + "resolved": "0.1.42-alpha", + "contentHash": "Z/9po23gUA9aoukirh2ItMU2ZS9++Js9Gdds9fu5yuMojDrmArvY2y+tq9985tR3cxFxpZO1O35Wjfo0khj5HA==" + }, + "Microsoft.Windows.SDK.Win32Metadata": { + "type": "Transitive", + "resolved": "60.0.34-preview", + "contentHash": "TA3DUNi4CTeo+ItTXBnGZFt2159XOGSl0UOlG5vjDj4WHqZjhwYyyUnzOtrbCERiSaP2Hzg7otJNWwOSZgutyA==" + }, + "Microsoft.Windows.WDK.Win32Metadata": { + "type": "Transitive", + "resolved": "0.11.4-experimental", + "contentHash": "bf5MCmUyZf0gBlYQjx9UpRAZWBkRndyt9XicR+UNLvAUAFTZQbu6YaX/sNKZlR98Grn0gydfh/yT4I3vc0AIQA==", + "dependencies": { + "Microsoft.Windows.SDK.Win32Metadata": "60.0.34-preview" + } + }, + "Mono.Cecil": { + "type": "Transitive", + "resolved": "0.9.6.1", + "contentHash": "yMsurNaOxxKIjyW9pEB+tRrR1S3DFnN1+iBgKvYvXG8kW0Y6yknJeMAe/tl3+P78/2C6304TgF7aVqpqXgEQ9Q==" + }, + "Nerdbank.Streams": { + "type": "Transitive", + "resolved": "2.11.74", + "contentHash": "r4G7uHHfoo8LCilPOdtf2C+Q5ymHOAXtciT4ZtB2xRlAvv4gPkWBYNAijFblStv3+uidp81j5DP11jMZl4BfJw==", + "dependencies": { + "Microsoft.VisualStudio.Threading": "17.10.48", + "Microsoft.VisualStudio.Validation": "17.8.8", + "System.IO.Pipelines": "8.0.0" + } + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" + }, + "NHotkey": { + "type": "Transitive", + "resolved": "3.0.0", + "contentHash": "IEghs0QqWsQYH0uUmvIl0Ye6RaebWRh38eB6ToOkDnQucTYRGFOgtig0gSxlwCszTilYFz3n1ZuY762x+kDR3A==" + }, + "NLog": { + "type": "Transitive", + "resolved": "4.7.10", + "contentHash": "rcegW7kYOCjl7wX0SzsqpPBqnJ51JKi1WkYb6QBVX0Wc5IgH19Pv4t/co+T0s06OS0Ne44xgkY/mHg0PdrmJow==" + }, + "Splat": { + "type": "Transitive", + "resolved": "1.6.2", + "contentHash": "DeH0MxPU+D4JchkIDPYG4vUT+hsWs9S41cFle0/4K5EJMXWurx5DzAkj2366DfK14/XKNhsu6tCl4dZXJ3CD4w==" + }, + "squirrel.windows": { + "type": "Transitive", + "resolved": "1.5.2", + "contentHash": "89Y/CFxWm7SEOjvuV2stVa8p+SNM9GOLk4tUNm2nUF792nfkimAgwRA/umVsdyd/OXBH8byXSh4V1qck88ZAyQ==", + "dependencies": { + "DeltaCompressionDotNet": "[1.0.0, 2.0.0)", + "Mono.Cecil": "0.9.6.1", + "Splat": "1.6.2" + } + }, + "StreamJsonRpc": { + "type": "Transitive", + "resolved": "2.20.20", + "contentHash": "gwG7KViLbSWS7EI0kYevinVmIga9wZNrpSY/FnWyC6DbdjKJ1xlv/FV1L9b0rLkVP8cGxfIMexdvo/+2W5eq6Q==", + "dependencies": { + "MessagePack": "2.5.187", + "Microsoft.VisualStudio.Threading": "17.10.48", + "Microsoft.VisualStudio.Threading.Analyzers": "17.10.48", + "Microsoft.VisualStudio.Validation": "17.8.8", + "Nerdbank.Streams": "2.11.74", + "Newtonsoft.Json": "13.0.1", + "System.IO.Pipelines": "8.0.0" + } + }, + "System.Diagnostics.EventLog": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "fdYxcRjQqTTacKId/2IECojlDSFvp7LP5N78+0z/xH7v/Tuw5ZAxu23Y6PTCRinqyu2ePx+Gn1098NC6jM6d+A==" + }, + "System.Drawing.Common": { + "type": "Transitive", + "resolved": "9.0.2", + "contentHash": "JU947wzf8JbBS16Y5EIZzAlyQU+k68D7LRx6y03s2wlhlvLqkt/8uPBrjv2hJnnaJKbdb0GhQ3JZsfYXhrRjyg==", + "dependencies": { + "Microsoft.Win32.SystemEvents": "9.0.2" + } + }, + "System.IO.Pipelines": { + "type": "Transitive", + "resolved": "8.0.0", + "contentHash": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==" + }, + "System.Reflection.Emit": { + "type": "Transitive", + "resolved": "4.7.0", + "contentHash": "VR4kk8XLKebQ4MZuKuIni/7oh+QGFmZW3qORd1GvBq/8026OpW501SzT/oypwiQl4TvT8ErnReh/NzY9u+C6wQ==" + }, + "System.Reflection.Metadata": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" + }, + "System.Security.AccessControl": { + "type": "Transitive", + "resolved": "6.0.1", + "contentHash": "IQ4NXP/B3Ayzvw0rDQzVTYsCKyy0Jp9KI6aYcK7UnGVlR9+Awz++TIPCQtPYfLJfOpm8ajowMR09V7quD3sEHw==" + }, + "System.Security.Principal.Windows": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" + }, + "System.Text.Encodings.Web": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "OP6umVGxc0Z0MvZQBVigj4/U31Pw72ITihDWP9WiWDm+q5aoe0GaJivsfYGq53o6dxH7DcXWiCTl7+0o2CGdmg==" + }, + "System.Text.Json": { + "type": "Transitive", + "resolved": "7.0.0", + "contentHash": "DaGSsVqKsn/ia6RG8frjwmJonfos0srquhw09TlT8KRw5I43E+4gs+/bZj4K0vShJ5H9imCuXupb4RmS+dBy3w==", + "dependencies": { + "System.Text.Encodings.Web": "7.0.0" + } + }, + "System.ValueTuple": { + "type": "Transitive", + "resolved": "4.5.0", + "contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ==" + }, + "ToolGood.Words.Pinyin": { + "type": "Transitive", + "resolved": "3.0.1.4", + "contentHash": "uQo97618y9yzLDxrnehPN+/tuiOlk5BqieEdwctHZOAS9miMXnHKgMFYVw8CSGXRglyTYXlrW7qtUlU7Fje5Ew==" + }, + "YamlDotNet": { + "type": "Transitive", + "resolved": "9.1.0", + "contentHash": "fuvGXU4Ec5HrsmEc+BiFTNPCRf1cGBI2kh/3RzMWgddM2M4ALhbSPoI3X3mhXZUD1qqQd9oSkFAtWjpz8z9eRg==" + }, + "flow.launcher.core": { + "type": "Project", + "dependencies": { + "Droplex": "[1.7.0, )", + "FSharp.Core": "[9.0.101, )", + "Flow.Launcher.Infrastructure": "[1.0.0, )", + "Flow.Launcher.Plugin": "[4.4.0, )", + "Meziantou.Framework.Win32.Jobs": "[3.4.0, )", + "Microsoft.IO.RecyclableMemoryStream": "[3.0.1, )", + "StreamJsonRpc": "[2.20.20, )", + "squirrel.windows": "[1.5.2, )" + } + }, + "flow.launcher.infrastructure": { + "type": "Project", + "dependencies": { + "Ben.Demystifier": "[0.4.1, )", + "BitFaster.Caching": "[2.5.3, )", + "CommunityToolkit.Mvvm": "[8.4.0, )", + "Flow.Launcher.Plugin": "[4.4.0, )", + "MemoryPack": "[1.21.3, )", + "Microsoft.VisualStudio.Threading": "[17.12.19, )", + "NLog": "[4.7.10, )", + "PropertyChanged.Fody": "[3.4.0, )", + "System.Drawing.Common": "[9.0.2, )", + "ToolGood.Words.Pinyin": "[3.0.1.4, )" + } + }, + "flow.launcher.plugin": { + "type": "Project", + "dependencies": { + "JetBrains.Annotations": "[2024.3.0, )", + "PropertyChanged.Fody": "[3.4.0, )" + } + } + } + } +} \ No newline at end of file From a3a819cacba667c6af5bc3dbd61e002e9b0de95b Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 28 Feb 2025 23:08:19 +0800 Subject: [PATCH 022/545] update packages.lock.json --- Flow.Launcher/packages.lock.json | 46 ++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/Flow.Launcher/packages.lock.json b/Flow.Launcher/packages.lock.json index 2768db74b..017065044 100644 --- a/Flow.Launcher/packages.lock.json +++ b/Flow.Launcher/packages.lock.json @@ -26,6 +26,17 @@ "resolved": "1.0.4", "contentHash": "D0LvRCPQMX6/FJHBjng+RO+wRDuHTJrfo7IAc7rmkPvRqchdVGJWg3y70peOtDy3OLNK+HSOwVkH4GiuLnkKgA==" }, + "Jack251970.TaskScheduler": { + "type": "Direct", + "requested": "[2.12.1, )", + "resolved": "2.12.1", + "contentHash": "+epAtsLMugiznJCNRYCYB6eBcr+bx+CVlwPWMprO5CbnNkWu9mlSV8XN5BQJrGYwmlAtlGfZA3p3PcFFlrgR6A==", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0", + "System.Diagnostics.EventLog": "8.0.0", + "System.Security.AccessControl": "6.0.1" + } + }, "Microsoft.Extensions.DependencyInjection": { "type": "Direct", "requested": "[7.0.0, )", @@ -37,13 +48,13 @@ }, "Microsoft.Extensions.Hosting": { "type": "Direct", - "requested": "[7.0.0, )", - "resolved": "7.0.0", - "contentHash": "4nFc8xCfK26G524ioreZvz/IeIKN/gY1LApoGpaIThKqBdTwauUo4ETCf12lQcoefijqe3Imnfvnk31IezFatg==", + "requested": "[7.0.1, )", + "resolved": "7.0.1", + "contentHash": "aoeMou6XSW84wiqd895OdaGyO9PfH6nohQJ0XBcshRDafbdIU6PQIVl8TpOCssPYq3ciRseP5064hbFyCR9J9w==", "dependencies": { "Microsoft.Extensions.Configuration": "7.0.0", "Microsoft.Extensions.Configuration.Abstractions": "7.0.0", - "Microsoft.Extensions.Configuration.Binder": "7.0.0", + "Microsoft.Extensions.Configuration.Binder": "7.0.3", "Microsoft.Extensions.Configuration.CommandLine": "7.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "7.0.0", "Microsoft.Extensions.Configuration.FileExtensions": "7.0.0", @@ -61,7 +72,8 @@ "Microsoft.Extensions.Logging.Debug": "7.0.0", "Microsoft.Extensions.Logging.EventLog": "7.0.0", "Microsoft.Extensions.Logging.EventSource": "7.0.0", - "Microsoft.Extensions.Options": "7.0.0" + "Microsoft.Extensions.Options": "7.0.1", + "System.Diagnostics.DiagnosticSource": "7.0.1" } }, "Microsoft.Toolkit.Uwp.Notifications": { @@ -117,17 +129,6 @@ "resolved": "3.0.0", "contentHash": "RR+8GbPQ/gjDqov/1QN1OPoUlbUruNwcL3WjWCeLw+MY7+od/ENhnkYxCfAC6rQLIu3QifaJt3kPYyP3RumqMQ==" }, - "TaskScheduler": { - "type": "Direct", - "requested": "[2.11.0, )", - "resolved": "2.11.0", - "contentHash": "p9wH58XSNIyUtO7PIFAEldaKUzpYmlj+YWAfnUqBKnGxIZRY51I9BrsBGJijUVwlxrgmLLPUigRIv2ZTD4uPJA==", - "dependencies": { - "Microsoft.Win32.Registry": "5.0.0", - "System.Diagnostics.EventLog": "8.0.0", - "System.Security.AccessControl": "6.0.1" - } - }, "VirtualizingWrapPanel": { "type": "Direct", "requested": "[2.1.1, )", @@ -227,8 +228,8 @@ }, "Microsoft.Extensions.Configuration.Binder": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "tgU4u7bZsoS9MKVRiotVMAwHtbREHr5/5zSEV+JPhg46+ox47Au84E3D2IacAaB0bk5ePNaNieTlPrfjbbRJkg==", + "resolved": "7.0.3", + "contentHash": "1eRFwJBrkkncTpvh6mivB8zg4uBVm6+Y6stEJERrVEqZZc8Hvf+N1iIgj2ySYDUQko4J1Gw1rLf1M8bG83F0eA==", "dependencies": { "Microsoft.Extensions.Configuration.Abstractions": "7.0.0" } @@ -405,8 +406,8 @@ }, "Microsoft.Extensions.Options": { "type": "Transitive", - "resolved": "7.0.0", - "contentHash": "lP1yBnTTU42cKpMozuafbvNtQ7QcBjr/CcK3bYOGEMH55Fjt+iecXjT6chR7vbgCMqy3PG3aNQSZgo/EuY/9qQ==", + "resolved": "7.0.1", + "contentHash": "pZRDYdN1FpepOIfHU62QoBQ6zdAoTvnjxFfqAzEd9Jhb2dfhA5i6jeTdgGgcgTWFRC7oT0+3XrbQu4LjvgX1Nw==", "dependencies": { "Microsoft.Extensions.DependencyInjection.Abstractions": "7.0.0", "Microsoft.Extensions.Primitives": "7.0.0" @@ -549,6 +550,11 @@ "System.IO.Pipelines": "8.0.0" } }, + "System.Diagnostics.DiagnosticSource": { + "type": "Transitive", + "resolved": "7.0.1", + "contentHash": "T9SLFxzDp0SreCffRDXSAS5G+lq6E8qP4knHS2IBjwCdx2KEvGnGZsq7gFpselYOda7l6gXsJMD93TQsFj/URA==" + }, "System.Diagnostics.EventLog": { "type": "Transitive", "resolved": "8.0.0", From e7ec5e3dd40f0955f6da139772002d87e8a207f3 Mon Sep 17 00:00:00 2001 From: Hongtao Zhang Date: Fri, 28 Feb 2025 23:40:23 +0800 Subject: [PATCH 023/545] remove space from the font name --- Flow.Launcher/Flow.Launcher.csproj | 2 +- ...{Segoe Fluent Icons.ttf => SegoeFluentIcons.ttf} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename Flow.Launcher/Resources/{Segoe Fluent Icons.ttf => SegoeFluentIcons.ttf} (100%) diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 44c5a5f3a..6ab69c1d2 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -78,7 +78,7 @@ Designer PreserveNewest - + PreserveNewest diff --git a/Flow.Launcher/Resources/Segoe Fluent Icons.ttf b/Flow.Launcher/Resources/SegoeFluentIcons.ttf similarity index 100% rename from Flow.Launcher/Resources/Segoe Fluent Icons.ttf rename to Flow.Launcher/Resources/SegoeFluentIcons.ttf From 02662a390d4d51dcdd002cffe2e6d810936c2ff3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 22:13:25 +0000 Subject: [PATCH 024/545] Bump System.Data.OleDb from 8.0.1 to 9.0.3 Bumps [System.Data.OleDb](https://github.com/dotnet/runtime) from 8.0.1 to 9.0.3. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v8.0.1...v9.0.3) --- updated-dependencies: - dependency-name: System.Data.OleDb dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .../Flow.Launcher.Plugin.Explorer.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 549217027..413838147 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -46,7 +46,7 @@ - + From d2229f69b60ebd642f27e077846283f92a6ffc2f Mon Sep 17 00:00:00 2001 From: Kevin Zhang <45326534+taooceros@users.noreply.github.com> Date: Tue, 25 Mar 2025 22:35:20 -0500 Subject: [PATCH 025/545] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b307e09a..c02b93694 100644 --- a/README.md +++ b/README.md @@ -393,5 +393,5 @@ Get in touch if you like to join the Flow-Launcher Team and help build this grea - Install .Net 9 SDK - via Visual Studio installer - - via winget `winget install Microsoft.DotNet.SDK.7` + - via winget `winget install Microsoft.DotNet.SDK.9` - Manually from [here](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) From 9e8a950580becfb5f232df40c2a73e65a5e30200 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 5 Apr 2025 23:01:09 +0800 Subject: [PATCH 026/545] Fix build issue & Improve code quality --- .../PinyinAlphabet.cs | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index e12764ed3..a63dd99d9 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Text; -using JetBrains.Annotations; using Flow.Launcher.Infrastructure.UserSettings; using ToolGood.Words.Pinyin; using System.Collections.Generic; @@ -15,11 +13,11 @@ namespace Flow.Launcher.Infrastructure private readonly ConcurrentDictionary _pinyinCache = new(); - private Settings _settings; + private readonly Settings _settings; - public void Initialize([NotNull] Settings settings) + public PinyinAlphabet() { - _settings = settings ?? throw new ArgumentNullException(nameof(settings)); + _settings = Ioc.Default.GetRequiredService(); } public bool ShouldTranslate(string stringToTranslate) @@ -109,16 +107,6 @@ namespace Flow.Launcher.Infrastructure {"Sh", "u"}, {"Zh", "v"} }); - - public PinyinAlphabet() - { - Initialize(Ioc.Default.GetRequiredService()); - } - - private void Initialize([NotNull] Settings settings) - { - _settings = settings ?? throw new ArgumentNullException(nameof(settings)); - } private static readonly ReadOnlyDictionary second = new(new Dictionary() { @@ -200,6 +188,7 @@ namespace Flow.Launcher.Infrastructure return doublePin.ToString(); } + #endregion } } From a8a305fce08c19f9e64fd450c94974d5cca17e4d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 5 Apr 2025 23:02:28 +0800 Subject: [PATCH 027/545] Improve code quality --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index a63dd99d9..3b24ecc2b 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,10 +1,10 @@ using System.Collections.Concurrent; -using System.Text; -using Flow.Launcher.Infrastructure.UserSettings; -using ToolGood.Words.Pinyin; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Text; using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Infrastructure.UserSettings; +using ToolGood.Words.Pinyin; namespace Flow.Launcher.Infrastructure { @@ -52,12 +52,12 @@ namespace Flow.Launcher.Infrastructure var resultList = WordsHelper.GetPinyinList(content); - StringBuilder resultBuilder = new StringBuilder(); - TranslationMapping map = new TranslationMapping(); + var resultBuilder = new StringBuilder(); + var map = new TranslationMapping(); - bool pre = false; + var pre = false; - for (int i = 0; i < resultList.Length; i++) + for (var i = 0; i < resultList.Length; i++) { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { @@ -148,7 +148,7 @@ namespace Flow.Launcher.Infrastructure private static string ToDoublePin(string fullPinyin) { // Assuming s is valid - StringBuilder doublePin = new StringBuilder(); + var doublePin = new StringBuilder(); if (fullPinyin.Length <= 3 && (fullPinyin[0] == 'a' || fullPinyin[0] == 'e' || fullPinyin[0] == 'o')) { From 5be732d533278ab7ce897fd69c3cd6245741af84 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 5 Apr 2025 23:04:12 +0800 Subject: [PATCH 028/545] Use var when neccessary --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 3b24ecc2b..7bcc70251 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -163,7 +163,7 @@ namespace Flow.Launcher.Infrastructure { doublePin.Append(first[fullPinyin[..2]]); - if (second.TryGetValue(fullPinyin[2..], out string tmp)) + if (second.TryGetValue(fullPinyin[2..], out var tmp)) { doublePin.Append(tmp); } @@ -176,7 +176,7 @@ namespace Flow.Launcher.Infrastructure { doublePin.Append(fullPinyin[0]); - if (second.TryGetValue(fullPinyin[1..], out string tmp)) + if (second.TryGetValue(fullPinyin[1..], out var tmp)) { doublePin.Append(tmp); } From 1f458d3b564a37944a7a10183fc9be5696cf2e95 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 9 Apr 2025 20:06:17 +0800 Subject: [PATCH 029/545] Fix typos & Code quality --- .../TranslationMapping.cs | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/Flow.Launcher.Infrastructure/TranslationMapping.cs b/Flow.Launcher.Infrastructure/TranslationMapping.cs index c976fc522..b33a094db 100644 --- a/Flow.Launcher.Infrastructure/TranslationMapping.cs +++ b/Flow.Launcher.Infrastructure/TranslationMapping.cs @@ -8,8 +8,9 @@ namespace Flow.Launcher.Infrastructure { private bool constructed; - private List originalIndexs = new List(); - private List translatedIndexs = new List(); + private readonly List originalIndexes = new(); + private readonly List translatedIndexes = new(); + private int translatedLength = 0; public void AddNewIndex(int originalIndex, int translatedIndex, int length) @@ -17,46 +18,47 @@ namespace Flow.Launcher.Infrastructure if (constructed) throw new InvalidOperationException("Mapping shouldn't be changed after constructed"); - originalIndexs.Add(originalIndex); - translatedIndexs.Add(translatedIndex); - translatedIndexs.Add(translatedIndex + length); + originalIndexes.Add(originalIndex); + translatedIndexes.Add(translatedIndex); + translatedIndexes.Add(translatedIndex + length); translatedLength += length - 1; } public int MapToOriginalIndex(int translatedIndex) { - if (translatedIndex > translatedIndexs.Last()) + if (translatedIndex > translatedIndexes.Last()) return translatedIndex - translatedLength - 1; int lowerBound = 0; - int upperBound = originalIndexs.Count - 1; + int upperBound = originalIndexes.Count - 1; int count = 0; // Corner case handle - if (translatedIndex < translatedIndexs[0]) + if (translatedIndex < translatedIndexes[0]) return translatedIndex; - if (translatedIndex > translatedIndexs.Last()) + + if (translatedIndex > translatedIndexes.Last()) { int indexDef = 0; - for (int k = 0; k < originalIndexs.Count; k++) + for (int k = 0; k < originalIndexes.Count; k++) { - indexDef += translatedIndexs[k * 2 + 1] - translatedIndexs[k * 2]; + indexDef += translatedIndexes[k * 2 + 1] - translatedIndexes[k * 2]; } return translatedIndex - indexDef - 1; } // Binary Search with Range - for (int i = originalIndexs.Count / 2;; count++) + for (int i = originalIndexes.Count / 2;; count++) { - if (translatedIndex < translatedIndexs[i * 2]) + if (translatedIndex < translatedIndexes[i * 2]) { // move to lower middle upperBound = i; i = (i + lowerBound) / 2; } - else if (translatedIndex > translatedIndexs[i * 2 + 1] - 1) + else if (translatedIndex > translatedIndexes[i * 2 + 1] - 1) { lowerBound = i; // move to upper middle @@ -64,17 +66,19 @@ namespace Flow.Launcher.Infrastructure i = (i + upperBound + 1) / 2; } else - return originalIndexs[i]; + { + return originalIndexes[i]; + } if (upperBound - lowerBound <= 1 && - translatedIndex > translatedIndexs[lowerBound * 2 + 1] && - translatedIndex < translatedIndexs[upperBound * 2]) + translatedIndex > translatedIndexes[lowerBound * 2 + 1] && + translatedIndex < translatedIndexes[upperBound * 2]) { int indexDef = 0; for (int j = 0; j < upperBound; j++) { - indexDef += translatedIndexs[j * 2 + 1] - translatedIndexs[j * 2]; + indexDef += translatedIndexes[j * 2 + 1] - translatedIndexes[j * 2]; } return translatedIndex - indexDef - 1; From 4b7db3cbd62233323bccfdd2188f28e8b6434a43 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 10 Apr 2025 09:36:47 +0800 Subject: [PATCH 030/545] Make function static --- Flow.Launcher.Infrastructure/StringMatcher.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/StringMatcher.cs b/Flow.Launcher.Infrastructure/StringMatcher.cs index 7045517f5..2882cb8f0 100644 --- a/Flow.Launcher.Infrastructure/StringMatcher.cs +++ b/Flow.Launcher.Infrastructure/StringMatcher.cs @@ -228,7 +228,7 @@ namespace Flow.Launcher.Infrastructure return new MatchResult(false, UserSettingSearchPrecision); } - private bool IsAcronym(string stringToCompare, int compareStringIndex) + private static bool IsAcronym(string stringToCompare, int compareStringIndex) { if (IsAcronymChar(stringToCompare, compareStringIndex) || IsAcronymNumber(stringToCompare, compareStringIndex)) return true; @@ -237,7 +237,7 @@ namespace Flow.Launcher.Infrastructure } // When counting acronyms, treat a set of numbers as one acronym ie. Visual 2019 as 2 acronyms instead of 5 - private bool IsAcronymCount(string stringToCompare, int compareStringIndex) + private static bool IsAcronymCount(string stringToCompare, int compareStringIndex) { if (IsAcronymChar(stringToCompare, compareStringIndex)) return true; From f5fd6b569ca8466fe4922aa1bd975622217c81ee Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 10 Apr 2025 09:56:27 +0800 Subject: [PATCH 031/545] Use ReadOnlySpan instead --- .../PinyinAlphabet.cs | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 7bcc70251..1637a285c 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -1,4 +1,5 @@ -using System.Collections.Concurrent; +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; @@ -148,9 +149,11 @@ namespace Flow.Launcher.Infrastructure private static string ToDoublePin(string fullPinyin) { // Assuming s is valid + var fullPinyinSpan = fullPinyin.AsSpan(); var doublePin = new StringBuilder(); - if (fullPinyin.Length <= 3 && (fullPinyin[0] == 'a' || fullPinyin[0] == 'e' || fullPinyin[0] == 'o')) + // Handle special cases (a, o, e) + if (fullPinyin.Length <= 3 && (fullPinyinSpan[0] == 'a' || fullPinyinSpan[0] == 'e' || fullPinyinSpan[0] == 'o')) { if (special.TryGetValue(fullPinyin, out var value)) { @@ -158,31 +161,41 @@ namespace Flow.Launcher.Infrastructure } } - // zh, ch, sh - if (fullPinyin.Length >= 2 && first.ContainsKey(fullPinyin[..2])) + // Check for initials that are two characters long (zh, ch, sh) + if (fullPinyin.Length >= 2) { - doublePin.Append(first[fullPinyin[..2]]); + var firstTwo = fullPinyinSpan[..2]; + var firstTwoString = firstTwo.ToString(); + if (first.ContainsKey(firstTwoString)) + { + doublePin.Append(firstTwoString); - if (second.TryGetValue(fullPinyin[2..], out var tmp)) - { - doublePin.Append(tmp); - } - else - { - doublePin.Append(fullPinyin[2..]); + var lastTwo = fullPinyinSpan[2..]; + var lastTwoString = lastTwo.ToString(); + if (second.TryGetValue(lastTwoString, out var tmp)) + { + doublePin.Append(tmp); + } + else + { + doublePin.Append(lastTwo); + } } } + // Handle single-character initials else { - doublePin.Append(fullPinyin[0]); + doublePin.Append(fullPinyinSpan[0]); - if (second.TryGetValue(fullPinyin[1..], out var tmp)) + var lastOne = fullPinyinSpan[1..]; + var lastOneString = lastOne.ToString(); + if (second.TryGetValue(lastOneString, out var tmp)) { doublePin.Append(tmp); } else { - doublePin.Append(fullPinyin[1..]); + doublePin.Append(lastOne); } } From 8aa36f38c82a388c386d7e3d86c44798dad632ad Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 13 May 2025 21:50:13 +0800 Subject: [PATCH 032/545] Add ShowAtTopmost in settings --- .../UserSettings/Settings.cs | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 34bf4f90e..3f382c276 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -59,8 +59,11 @@ namespace Flow.Launcher.Infrastructure.UserSettings get => _language; set { - _language = value; - OnPropertyChanged(); + if (_language != value) + { + _language = value; + OnPropertyChanged(); + } } } public string Theme @@ -68,7 +71,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings get => _theme; set { - if (value != _theme) + if (_theme != value) { _theme = value; OnPropertyChanged(); @@ -283,9 +286,12 @@ namespace Flow.Launcher.Infrastructure.UserSettings get => _querySearchPrecision; set { - _querySearchPrecision = value; - if (_stringMatcher != null) - _stringMatcher.UserSettingSearchPrecision = value; + if (_querySearchPrecision != value) + { + _querySearchPrecision = value; + if (_stringMatcher != null) + _stringMatcher.UserSettingSearchPrecision = value; + } } } @@ -348,12 +354,28 @@ namespace Flow.Launcher.Infrastructure.UserSettings get => _hideNotifyIcon; set { - _hideNotifyIcon = value; - OnPropertyChanged(); + if (_hideNotifyIcon != value) + { + _hideNotifyIcon = value; + OnPropertyChanged(); + } } } public bool LeaveCmdOpen { get; set; } public bool HideWhenDeactivated { get; set; } = true; + private bool _showAtTopmost; + public bool ShowAtTopmost + { + get => _showAtTopmost; + set + { + if (_showAtTopmost != value) + { + _showAtTopmost = value; + OnPropertyChanged(); + } + } + } public bool SearchQueryResultsWithDelay { get; set; } public int SearchDelayTime { get; set; } = 150; From 587ab629aa9b831ba8ed684eb2039dbba6b28ff1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 13 May 2025 21:54:03 +0800 Subject: [PATCH 033/545] Support changing ShowAtTopmost --- Flow.Launcher/MainWindow.xaml.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 46eeb2adc..72a990ada 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -84,6 +84,8 @@ namespace Flow.Launcher _viewModel = Ioc.Default.GetRequiredService(); DataContext = _viewModel; + Topmost = _settings.ShowAtTopmost; + InitializeComponent(); UpdatePosition(); @@ -283,6 +285,9 @@ namespace Flow.Launcher _viewModel.QueryResults(); } break; + case nameof(Settings.ShowAtTopmost): + Topmost = _settings.ShowAtTopmost; + break; } }; From 4e88ce3f48b9eae47dc57c595acfe7862b540476 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 13 May 2025 22:01:36 +0800 Subject: [PATCH 034/545] Set ShowAtTopmost default to true --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 3f382c276..7cd3821dc 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -363,7 +363,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings } public bool LeaveCmdOpen { get; set; } public bool HideWhenDeactivated { get; set; } = true; - private bool _showAtTopmost; + private bool _showAtTopmost = true; public bool ShowAtTopmost { get => _showAtTopmost; From b8f743eb4c2ad44bc89366698a6ee8543d1d5343 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 13 May 2025 22:06:04 +0800 Subject: [PATCH 035/545] Add ui in general setting page --- Flow.Launcher/Languages/en.xaml | 2 ++ .../SettingPages/Views/SettingsPaneGeneral.xaml | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 22ab2016c..f728f1095 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -131,6 +131,8 @@ Show History Results in Home Page Maximum History Results Shown in Home Page This can only be edited if plugin supports Home feature and Home Page is enabled. + Show Search Window at Topmost + Show search window above other windows Search Plugin diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index c0c5613de..fba1b3d86 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -77,6 +77,17 @@ OnContent="{DynamicResource enable}" /> + + + + From b636f253e65114639dca2aa7d14271d013a993a6 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 13 May 2025 22:52:06 +0800 Subject: [PATCH 036/545] Add blank line --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 7cd3821dc..8dc48f7f2 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -363,6 +363,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings } public bool LeaveCmdOpen { get; set; } public bool HideWhenDeactivated { get; set; } = true; + private bool _showAtTopmost = true; public bool ShowAtTopmost { From f7f52e269a8f0aa7883169c82425fd9738a8dc7f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 21 May 2025 14:31:09 +0800 Subject: [PATCH 037/545] Set culture info before creating application --- .../Resource/Internationalization.cs | 34 ++++++---- .../UserSettings/Settings.cs | 13 +++- Flow.Launcher/App.xaml.cs | 62 ++++++++++++------- 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index b32b09e8f..3329e3a96 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -1,16 +1,17 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; +using System.Threading; +using System.Threading.Tasks; using System.Windows; +using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; -using System.Globalization; -using System.Threading.Tasks; -using CommunityToolkit.Mvvm.DependencyInjection; namespace Flow.Launcher.Core.Resource { @@ -29,13 +30,12 @@ namespace Flow.Launcher.Core.Resource private readonly Settings _settings; private readonly List _languageDirectories = new(); private readonly List _oldResources = new(); - private readonly string SystemLanguageCode; + private static string SystemLanguageCode; public Internationalization(Settings settings) { _settings = settings; AddFlowLauncherLanguageDirectory(); - SystemLanguageCode = GetSystemLanguageCodeAtStartup(); } private void AddFlowLauncherLanguageDirectory() @@ -44,7 +44,7 @@ namespace Flow.Launcher.Core.Resource _languageDirectories.Add(directory); } - private static string GetSystemLanguageCodeAtStartup() + public static void InitSystemLanguageCode() { var availableLanguages = AvailableLanguages.GetAvailableLanguages(); @@ -65,11 +65,11 @@ namespace Flow.Launcher.Core.Resource string.Equals(languageCode, threeLetterCode, StringComparison.OrdinalIgnoreCase) || string.Equals(languageCode, fullName, StringComparison.OrdinalIgnoreCase)) { - return languageCode; + SystemLanguageCode = languageCode; } } - return DefaultLanguageCode; + SystemLanguageCode = DefaultLanguageCode; } private void AddPluginLanguageDirectories() @@ -173,15 +173,25 @@ namespace Flow.Launcher.Core.Resource LoadLanguage(language); } - // Culture of main thread - // Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's - CultureInfo.CurrentCulture = CultureInfo.CreateSpecificCulture(language.LanguageCode); - CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture; + // Change culture info + ChangeCultureInfo(language.LanguageCode); // Raise event for plugins after culture is set await Task.Run(UpdatePluginMetadataTranslations); } + public static void ChangeCultureInfo(string languageCode) + { + // Culture of main thread + // Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's + var currentCulture = CultureInfo.CreateSpecificCulture(languageCode); + CultureInfo.CurrentCulture = currentCulture; + CultureInfo.CurrentUICulture = currentCulture; + var thread = Thread.CurrentThread; + thread.CurrentCulture = currentCulture; + thread.CurrentUICulture = currentCulture; + } + public bool PromptShouldUsePinyin(string languageCodeToSet) { var languageToSet = GetLanguageByLanguageCode(languageCodeToSet); diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 027eb3f92..7933d08ea 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -25,7 +25,13 @@ namespace Flow.Launcher.Infrastructure.UserSettings public void Initialize() { + // Initialize dependency injection instances after Ioc.Default is created _stringMatcher = Ioc.Default.GetRequiredService(); + + // Initialize application resources after application is created + var settingWindowFont = new FontFamily(SettingWindowFont); + Application.Current.Resources["SettingWindowFont"] = settingWindowFont; + Application.Current.Resources["ContentControlThemeFontFamily"] = settingWindowFont; } public void Save() @@ -114,8 +120,11 @@ namespace Flow.Launcher.Infrastructure.UserSettings { _settingWindowFont = value; OnPropertyChanged(); - Application.Current.Resources["SettingWindowFont"] = new FontFamily(value); - Application.Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(value); + if (Application.Current != null) + { + Application.Current.Resources["SettingWindowFont"] = new FontFamily(value); + Application.Current.Resources["ContentControlThemeFontFamily"] = new FontFamily(value); + } } } } diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 942e94470..fd64ad3e0 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -41,9 +41,9 @@ namespace Flow.Launcher private static readonly string ClassName = nameof(App); private static bool _disposed; + private static Settings _settings; private static MainWindow _mainWindow; private readonly MainViewModel _mainVM; - private readonly Settings _settings; // To prevent two disposals running at the same time. private static readonly object _disposingLock = new(); @@ -55,19 +55,7 @@ namespace Flow.Launcher public App() { // Initialize settings - try - { - var storage = new FlowLauncherJsonStorage(); - _settings = storage.Load(); - _settings.SetStorage(storage); - _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); - } - catch (Exception e) - { - ShowErrorMsgBoxAndFailFast("Cannot load setting storage, please check local data directory", e); - return; - } - + _settings.WMPInstalled = WindowsMediaPlayerHelper.IsWindowsMediaPlayerInstalled(); // Configure the dependency injection container try { @@ -119,16 +107,6 @@ namespace Flow.Launcher ShowErrorMsgBoxAndFailFast("Cannot initialize api and settings, please open new issue in Flow.Launcher", e); return; } - - // Local function - static void ShowErrorMsgBoxAndFailFast(string message, Exception e) - { - // Firstly show users the message - MessageBox.Show(e.ToString(), message, MessageBoxButton.OK, MessageBoxImage.Error); - - // Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info. - Environment.FailFast(message, e); - } } #endregion @@ -138,6 +116,29 @@ namespace Flow.Launcher [STAThread] public static void Main() { + // Initialize settings so that we can get language code + try + { + var storage = new FlowLauncherJsonStorage(); + _settings = storage.Load(); + _settings.SetStorage(storage); + } + catch (Exception e) + { + ShowErrorMsgBoxAndFailFast("Cannot load setting storage, please check local data directory", e); + return; + } + + // Initialize system language before changing culture info + Internationalization.InitSystemLanguageCode(); + + // Change culture info before application creation to localize WinForm windows + if (_settings.Language != Constant.SystemLanguageCode) + { + Internationalization.ChangeCultureInfo(_settings.Language); + } + + // Start the application as a single instance if (SingleInstance.InitializeAsFirstInstance()) { using var application = new App(); @@ -148,6 +149,19 @@ namespace Flow.Launcher #endregion + #region Fail Fast + + private static void ShowErrorMsgBoxAndFailFast(string message, Exception e) + { + // Firstly show users the message + MessageBox.Show(e.ToString(), message, MessageBoxButton.OK, MessageBoxImage.Error); + + // Flow cannot construct its App instance, so ensure Flow crashes w/ the exception info. + Environment.FailFast(message, e); + } + + #endregion + #region App Events #pragma warning disable VSTHRD100 // Avoid async void methods From b0997449c17117214a246c537b2472db5fb88596 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 21 May 2025 14:38:15 +0800 Subject: [PATCH 038/545] Handle CultureNotFoundException --- Flow.Launcher.Core/Resource/Internationalization.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Resource/Internationalization.cs b/Flow.Launcher.Core/Resource/Internationalization.cs index 3329e3a96..24edc5ed8 100644 --- a/Flow.Launcher.Core/Resource/Internationalization.cs +++ b/Flow.Launcher.Core/Resource/Internationalization.cs @@ -184,7 +184,15 @@ namespace Flow.Launcher.Core.Resource { // Culture of main thread // Use CreateSpecificCulture to preserve possible user-override settings in Windows, if Flow's language culture is the same as Windows's - var currentCulture = CultureInfo.CreateSpecificCulture(languageCode); + CultureInfo currentCulture; + try + { + currentCulture = CultureInfo.CreateSpecificCulture(languageCode); + } + catch (CultureNotFoundException) + { + currentCulture = CultureInfo.CreateSpecificCulture(SystemLanguageCode); + } CultureInfo.CurrentCulture = currentCulture; CultureInfo.CurrentUICulture = currentCulture; var thread = Thread.CurrentThread; From 949344a51e9062828e800149adb91165cc8882c3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 17:32:33 +0800 Subject: [PATCH 039/545] Add internal model for plugin management --- .../UserSettings/Settings.cs | 2 + Flow.Launcher/Languages/en.xaml | 18 ++ .../Views/SettingsPaneGeneral.xaml | 11 + .../ViewModel/PluginStoreItemViewModel.cs | 270 ++++++++++++++++-- Flow.Launcher/ViewModel/PluginViewModel.cs | 23 +- 5 files changed, 280 insertions(+), 44 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index ce1269a29..024e727ce 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -176,6 +176,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings public bool ShowHistoryResultsForHomePage { get; set; } = false; public int MaxHistoryResultsToShowForHomePage { get; set; } = 5; + public bool AutoRestartAfterChanging { get; set; } = false; + public int CustomExplorerIndex { get; set; } = 0; [JsonIgnore] diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 22ab2016c..24f74e15d 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -131,6 +131,8 @@ Show History Results in Home Page Maximum History Results Shown in Home Page This can only be edited if plugin supports Home feature and Home Page is enabled. + Automatically restart after changing plugins + Automatically restart Flow Launcher after installing/uninstalling/updating plugins Search Plugin @@ -184,6 +186,22 @@ New Version This plugin has been updated within the last 7 days New Update is Available + Error installing plugin + Error uninstalling plugin + Error updating plugin + Keep plugin settings + Do you want to keep the settings of the plugin for the next usage? + Plugin {0} successfully installed. Please restart Flow. + Plugin {0} successfully uninstalled. Please restart Flow. + Plugin {0} successfully updated. Please restart Flow. + Plugin install + {0} by {1} {2}{2}Would you like to install this plugin? + Plugin uninstall + {0} by {1} {2}{2}Would you like to uninstall this plugin? + Plugin udpate + {0} by {1} {2}{2}Would you like to update this plugin? + Downloading plugin + Automatically restart after installing/uninstalling/updating plugins in plugin store Theme diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index c0c5613de..452e026d7 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -202,6 +202,17 @@ + + + + PluginManager.GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7"); + private static readonly string ClassName = nameof(PluginStoreItemViewModel); + + private static readonly Settings Settings = Ioc.Default.GetRequiredService(); + + private readonly UserPlugin _newPlugin; + private readonly PluginPair _oldPluginPair; + public PluginStoreItemViewModel(UserPlugin plugin) { - _plugin = plugin; + _newPlugin = plugin; + _oldPluginPair = PluginManager.GetPluginForId(plugin.ID); } - private UserPlugin _plugin; + public string ID => _newPlugin.ID; + public string Name => _newPlugin.Name; + public string Description => _newPlugin.Description; + public string Author => _newPlugin.Author; + public string Version => _newPlugin.Version; + public string Language => _newPlugin.Language; + public string Website => _newPlugin.Website; + public string UrlDownload => _newPlugin.UrlDownload; + public string UrlSourceCode => _newPlugin.UrlSourceCode; + public string IcoPath => _newPlugin.IcoPath; - public string ID => _plugin.ID; - public string Name => _plugin.Name; - public string Description => _plugin.Description; - public string Author => _plugin.Author; - public string Version => _plugin.Version; - public string Language => _plugin.Language; - public string Website => _plugin.Website; - public string UrlDownload => _plugin.UrlDownload; - public string UrlSourceCode => _plugin.UrlSourceCode; - public string IcoPath => _plugin.IcoPath; - - public bool LabelInstalled => PluginManager.GetPluginForId(_plugin.ID) != null; - public bool LabelUpdate => LabelInstalled && new Version(_plugin.Version) > new Version(PluginManager.GetPluginForId(_plugin.ID).Metadata.Version); + public bool LabelInstalled => _oldPluginPair != null; + public bool LabelUpdate => LabelInstalled && new Version(_newPlugin.Version) > new Version(_oldPluginPair.Metadata.Version); internal const string None = "None"; internal const string RecentlyUpdated = "RecentlyUpdated"; @@ -41,15 +51,15 @@ namespace Flow.Launcher.ViewModel get { string category = None; - if (DateTime.Now - _plugin.LatestReleaseDate < TimeSpan.FromDays(7)) + if (DateTime.Now - _newPlugin.LatestReleaseDate < TimeSpan.FromDays(7)) { category = RecentlyUpdated; } - if (DateTime.Now - _plugin.DateAdded < TimeSpan.FromDays(7)) + if (DateTime.Now - _newPlugin.DateAdded < TimeSpan.FromDays(7)) { category = NewRelease; } - if (PluginManager.GetPluginForId(_plugin.ID) != null) + if (_oldPluginPair != null) { category = Installed; } @@ -59,11 +69,223 @@ namespace Flow.Launcher.ViewModel } [RelayCommand] - private void ShowCommandQuery(string action) + private async Task ShowCommandQueryAsync(string action) { - var actionKeyword = PluginManagerData.Metadata.ActionKeywords.Any() ? PluginManagerData.Metadata.ActionKeywords[0] + " " : String.Empty; - App.API.ChangeQuery($"{actionKeyword}{action} {_plugin.Name}"); - App.API.ShowMainWindow(); + switch (action) + { + case "install": + await InstallPluginAsync(_newPlugin); + break; + case "uninstall": + await UninstallPluginAsync(_oldPluginPair.Metadata); + break; + case "update": + await UpdatePluginAsync(_newPlugin, _oldPluginPair.Metadata); + break; + } + } + + internal static async Task InstallPluginAsync(UserPlugin newPlugin) + { + if (App.API.ShowMsgBox( + string.Format( + App.API.GetTranslation("InstallPromptSubtitle"), + newPlugin.Name, newPlugin.Author, Environment.NewLine), + App.API.GetTranslation("InstallPromptTitle"), + button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; + + try + { + // at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download + var downloadFilename = string.IsNullOrEmpty(newPlugin.Version) + ? $"{newPlugin.Name}-{Guid.NewGuid()}.zip" + : $"{newPlugin.Name}-{newPlugin.Version}.zip"; + + var filePath = Path.Combine(Path.GetTempPath(), downloadFilename); + + using var cts = new CancellationTokenSource(); + + if (!newPlugin.IsFromLocalInstallPath) + { + await DownloadFileAsync( + $"{App.API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}", + newPlugin.UrlDownload, filePath, cts); + } + else + { + filePath = newPlugin.LocalInstallPath; + } + + // check if user cancelled download before installing plugin + if (cts.IsCancellationRequested) + { + return; + } + else + { + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath); + } + + App.API.InstallPlugin(newPlugin, filePath); + + if (!newPlugin.IsFromLocalInstallPath) + { + File.Delete(filePath); + } + } + } + catch (Exception e) + { + App.API.LogException(ClassName, "Failed to install plugin", e); + App.API.ShowMsgError(App.API.GetTranslation("ErrorInstallingPlugin")); + } + + if (Settings.AutoRestartAfterChanging) + { + App.API.RestartApp(); + } + else + { + App.API.ShowMsg( + App.API.GetTranslation("installbtn"), + string.Format( + App.API.GetTranslation( + "InstallSuccessNoRestart"), + newPlugin.Name)); + } + } + + internal static async Task UninstallPluginAsync(PluginMetadata oldPlugin) + { + if (App.API.ShowMsgBox( + string.Format( + App.API.GetTranslation("UninstallPromptSubtitle"), + oldPlugin.Name, oldPlugin.Author, Environment.NewLine), + App.API.GetTranslation("UninstallPromptTitle"), + button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; + + var removePluginSettings = App.API.ShowMsgBox( + App.API.GetTranslation("KeepPluginSettingsSubtitle"), + App.API.GetTranslation("KeepPluginSettingsTitle"), + button: MessageBoxButton.YesNo) == MessageBoxResult.No; + + try + { + await App.API.UninstallPluginAsync(oldPlugin, removePluginSettings); + } + catch (Exception e) + { + App.API.LogException(ClassName, "Failed to uninstall plugin", e); + App.API.ShowMsgError(App.API.GetTranslation("ErrorUninstallingPlugin")); + } + + if (Settings.AutoRestartAfterChanging) + { + App.API.RestartApp(); + } + else + { + App.API.ShowMsg( + App.API.GetTranslation("uninstallbtn"), + string.Format( + App.API.GetTranslation( + "UninstallSuccessNoRestart"), + oldPlugin.Name)); + } + } + + internal static async Task UpdatePluginAsync(UserPlugin newPlugin, PluginMetadata oldPlugin) + { + if (App.API.ShowMsgBox( + string.Format( + App.API.GetTranslation("UpdatePromptSubtitle"), + oldPlugin.Name, oldPlugin.Author, Environment.NewLine), + App.API.GetTranslation("UpdatePromptTitle"), + button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; + + try + { + var filePath = Path.Combine(Path.GetTempPath(), $"{newPlugin.Name}-{newPlugin.Version}.zip"); + + using var cts = new CancellationTokenSource(); + + if (!newPlugin.IsFromLocalInstallPath) + { + await DownloadFileAsync( + $"{App.API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}", + newPlugin.UrlDownload, filePath, cts); + } + else + { + filePath = newPlugin.LocalInstallPath; + } + + // check if user cancelled download before installing plugin + if (cts.IsCancellationRequested) + { + return; + } + else + { + await App.API.UpdatePluginAsync(oldPlugin, newPlugin, filePath); + } + } + catch (Exception e) + { + App.API.LogException(ClassName, "Failed to update plugin", e); + App.API.ShowMsgError(App.API.GetTranslation("ErrorUpdatingPlugin")); + } + + if (Settings.AutoRestartAfterChanging) + { + App.API.RestartApp(); + } + else + { + App.API.ShowMsg( + App.API.GetTranslation("updatebtn"), + string.Format( + App.API.GetTranslation( + "UpdateSuccessNoRestart"), + newPlugin.Name)); + } + } + + private static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true) + { + if (deleteFile && File.Exists(filePath)) + File.Delete(filePath); + + if (showProgress) + { + var exceptionHappened = false; + await App.API.ShowProgressBoxAsync(prgBoxTitle, + async (reportProgress) => + { + if (reportProgress == null) + { + // when reportProgress is null, it means there is expcetion with the progress box + // so we record it with exceptionHappened and return so that progress box will close instantly + exceptionHappened = true; + return; + } + else + { + await App.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false); + } + }, cts.Cancel); + + // if exception happened while downloading and user does not cancel downloading, + // we need to redownload the plugin + if (exceptionHappened && (!cts.IsCancellationRequested)) + await App.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); + } + else + { + await App.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); + } } } } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index 01fa3d203..bda05a02d 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -1,5 +1,4 @@ -using System.Linq; -using System.Threading.Tasks; +using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; @@ -32,21 +31,6 @@ namespace Flow.Launcher.ViewModel } } - private static string PluginManagerActionKeyword - { - get - { - var keyword = PluginManager - .GetPluginForId("9f8f9b14-2518-4907-b211-35ab6290dee7") - .Metadata.ActionKeywords.FirstOrDefault(); - return keyword switch - { - null or "*" => string.Empty, - _ => keyword - }; - } - } - private async Task LoadIconAsync() { Image = await App.API.LoadImageAsync(PluginPair.Metadata.IcoPath); @@ -186,10 +170,9 @@ namespace Flow.Launcher.ViewModel } [RelayCommand] - private void OpenDeletePluginWindow() + private async Task OpenDeletePluginWindowAsync() { - App.API.ChangeQuery($"{PluginManagerActionKeyword} uninstall {PluginPair.Metadata.Name}".Trim(), true); - App.API.ShowMainWindow(); + await PluginStoreItemViewModel.UninstallPluginAsync(PluginPair.Metadata); } [RelayCommand] From 76736b785091873534770d4806572f2641f20adf Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Thu, 22 May 2025 17:37:27 +0800 Subject: [PATCH 040/545] Fix typo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher/Languages/en.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 24f74e15d..2166bdd8c 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -198,7 +198,7 @@ {0} by {1} {2}{2}Would you like to install this plugin? Plugin uninstall {0} by {1} {2}{2}Would you like to uninstall this plugin? - Plugin udpate + Plugin update {0} by {1} {2}{2}Would you like to update this plugin? Downloading plugin Automatically restart after installing/uninstalling/updating plugins in plugin store From c6c7ff882e6745216c828559191966753553e839 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 17:40:26 +0800 Subject: [PATCH 041/545] Handle default --- Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs index 3e823d635..a69c0dbd7 100644 --- a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs @@ -82,6 +82,8 @@ namespace Flow.Launcher.ViewModel case "update": await UpdatePluginAsync(_newPlugin, _oldPluginPair.Metadata); break; + default: + break; } } From 6044f87e806c97cd96f9d62beb6fb3a868ba1efe Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 17:41:13 +0800 Subject: [PATCH 042/545] Do not restart on failure --- Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs index a69c0dbd7..6b2cf6eed 100644 --- a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs @@ -142,6 +142,7 @@ namespace Flow.Launcher.ViewModel { App.API.LogException(ClassName, "Failed to install plugin", e); App.API.ShowMsgError(App.API.GetTranslation("ErrorInstallingPlugin")); + return; // don’t restart on failure } if (Settings.AutoRestartAfterChanging) @@ -181,6 +182,7 @@ namespace Flow.Launcher.ViewModel { App.API.LogException(ClassName, "Failed to uninstall plugin", e); App.API.ShowMsgError(App.API.GetTranslation("ErrorUninstallingPlugin")); + return; // don’t restart on failure } if (Settings.AutoRestartAfterChanging) @@ -238,6 +240,7 @@ namespace Flow.Launcher.ViewModel { App.API.LogException(ClassName, "Failed to update plugin", e); App.API.ShowMsgError(App.API.GetTranslation("ErrorUpdatingPlugin")); + return; // don’t restart on failure } if (Settings.AutoRestartAfterChanging) From 383c0aeffc9afc1351f3c008d62aa0915ddc0da4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 23 May 2025 13:41:59 +0800 Subject: [PATCH 043/545] Improve code quality --- Flow.Launcher.Core/Plugin/PluginManager.cs | 209 +++++++++++++++++ .../ViewModel/PluginStoreItemViewModel.cs | 221 +----------------- Flow.Launcher/ViewModel/PluginViewModel.cs | 2 +- 3 files changed, 213 insertions(+), 219 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index aae8dd764..5b14ad0b7 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using System.Windows; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Infrastructure; @@ -24,6 +25,8 @@ namespace Flow.Launcher.Core.Plugin { private static readonly string ClassName = nameof(PluginManager); + private static readonly Settings FlowSettings = Ioc.Default.GetRequiredService(); + private static IEnumerable _contextMenuPlugins; private static IEnumerable _homePlugins; @@ -547,6 +550,177 @@ namespace Flow.Launcher.Core.Plugin await UninstallPluginAsync(plugin, removePluginFromSettings, removePluginSettings, true); } + public static async Task InstallPluginAndCheckRestartAsync(UserPlugin newPlugin) + { + if (API.ShowMsgBox( + string.Format( + API.GetTranslation("InstallPromptSubtitle"), + newPlugin.Name, newPlugin.Author, Environment.NewLine), + API.GetTranslation("InstallPromptTitle"), + button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; + + try + { + // at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download + var downloadFilename = string.IsNullOrEmpty(newPlugin.Version) + ? $"{newPlugin.Name}-{Guid.NewGuid()}.zip" + : $"{newPlugin.Name}-{newPlugin.Version}.zip"; + + var filePath = Path.Combine(Path.GetTempPath(), downloadFilename); + + using var cts = new CancellationTokenSource(); + + if (!newPlugin.IsFromLocalInstallPath) + { + await DownloadFileAsync( + $"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}", + newPlugin.UrlDownload, filePath, cts); + } + else + { + filePath = newPlugin.LocalInstallPath; + } + + // check if user cancelled download before installing plugin + if (cts.IsCancellationRequested) + { + return; + } + else + { + if (!File.Exists(filePath)) + { + throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath); + } + + API.InstallPlugin(newPlugin, filePath); + + if (!newPlugin.IsFromLocalInstallPath) + { + File.Delete(filePath); + } + } + } + catch (Exception e) + { + API.LogException(ClassName, "Failed to install plugin", e); + API.ShowMsgError(API.GetTranslation("ErrorInstallingPlugin")); + return; // don’t restart on failure + } + + if (FlowSettings.AutoRestartAfterChanging) + { + API.RestartApp(); + } + else + { + API.ShowMsg( + API.GetTranslation("installbtn"), + string.Format( + API.GetTranslation( + "InstallSuccessNoRestart"), + newPlugin.Name)); + } + } + + public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin) + { + if (API.ShowMsgBox( + string.Format( + API.GetTranslation("UninstallPromptSubtitle"), + oldPlugin.Name, oldPlugin.Author, Environment.NewLine), + API.GetTranslation("UninstallPromptTitle"), + button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; + + var removePluginSettings = API.ShowMsgBox( + API.GetTranslation("KeepPluginSettingsSubtitle"), + API.GetTranslation("KeepPluginSettingsTitle"), + button: MessageBoxButton.YesNo) == MessageBoxResult.No; + + try + { + await API.UninstallPluginAsync(oldPlugin, removePluginSettings); + } + catch (Exception e) + { + API.LogException(ClassName, "Failed to uninstall plugin", e); + API.ShowMsgError(API.GetTranslation("ErrorUninstallingPlugin")); + return; // don’t restart on failure + } + + if (FlowSettings.AutoRestartAfterChanging) + { + API.RestartApp(); + } + else + { + API.ShowMsg( + API.GetTranslation("uninstallbtn"), + string.Format( + API.GetTranslation( + "UninstallSuccessNoRestart"), + oldPlugin.Name)); + } + } + + public static async Task UpdatePluginAndCheckRestartAsync(UserPlugin newPlugin, PluginMetadata oldPlugin) + { + if (API.ShowMsgBox( + string.Format( + API.GetTranslation("UpdatePromptSubtitle"), + oldPlugin.Name, oldPlugin.Author, Environment.NewLine), + API.GetTranslation("UpdatePromptTitle"), + button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; + + try + { + var filePath = Path.Combine(Path.GetTempPath(), $"{newPlugin.Name}-{newPlugin.Version}.zip"); + + using var cts = new CancellationTokenSource(); + + if (!newPlugin.IsFromLocalInstallPath) + { + await DownloadFileAsync( + $"{API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}", + newPlugin.UrlDownload, filePath, cts); + } + else + { + filePath = newPlugin.LocalInstallPath; + } + + // check if user cancelled download before installing plugin + if (cts.IsCancellationRequested) + { + return; + } + else + { + await API.UpdatePluginAsync(oldPlugin, newPlugin, filePath); + } + } + catch (Exception e) + { + API.LogException(ClassName, "Failed to update plugin", e); + API.ShowMsgError(API.GetTranslation("ErrorUpdatingPlugin")); + return; // don’t restart on failure + } + + if (FlowSettings.AutoRestartAfterChanging) + { + API.RestartApp(); + } + else + { + API.ShowMsg( + API.GetTranslation("updatebtn"), + string.Format( + API.GetTranslation( + "UpdateSuccessNoRestart"), + newPlugin.Name)); + } + } + #endregion #region Internal functions @@ -694,6 +868,41 @@ namespace Flow.Launcher.Core.Plugin } } + internal static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true) + { + if (deleteFile && File.Exists(filePath)) + File.Delete(filePath); + + if (showProgress) + { + var exceptionHappened = false; + await API.ShowProgressBoxAsync(prgBoxTitle, + async (reportProgress) => + { + if (reportProgress == null) + { + // when reportProgress is null, it means there is expcetion with the progress box + // so we record it with exceptionHappened and return so that progress box will close instantly + exceptionHappened = true; + return; + } + else + { + await API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false); + } + }, cts.Cancel); + + // if exception happened while downloading and user does not cancel downloading, + // we need to redownload the plugin + if (exceptionHappened && (!cts.IsCancellationRequested)) + await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); + } + else + { + await API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); + } + } + #endregion } } diff --git a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs index 6b2cf6eed..a504b7a05 100644 --- a/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginStoreItemViewModel.cs @@ -1,12 +1,7 @@ using System; -using System.IO; -using System.Threading; using System.Threading.Tasks; -using System.Windows; -using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Version = SemanticVersioning.Version; @@ -14,10 +9,6 @@ namespace Flow.Launcher.ViewModel { public partial class PluginStoreItemViewModel : BaseModel { - private static readonly string ClassName = nameof(PluginStoreItemViewModel); - - private static readonly Settings Settings = Ioc.Default.GetRequiredService(); - private readonly UserPlugin _newPlugin; private readonly PluginPair _oldPluginPair; @@ -74,223 +65,17 @@ namespace Flow.Launcher.ViewModel switch (action) { case "install": - await InstallPluginAsync(_newPlugin); + await PluginManager.InstallPluginAndCheckRestartAsync(_newPlugin); break; case "uninstall": - await UninstallPluginAsync(_oldPluginPair.Metadata); + await PluginManager.UninstallPluginAndCheckRestartAsync(_oldPluginPair.Metadata); break; case "update": - await UpdatePluginAsync(_newPlugin, _oldPluginPair.Metadata); + await PluginManager.UpdatePluginAndCheckRestartAsync(_newPlugin, _oldPluginPair.Metadata); break; default: break; } } - - internal static async Task InstallPluginAsync(UserPlugin newPlugin) - { - if (App.API.ShowMsgBox( - string.Format( - App.API.GetTranslation("InstallPromptSubtitle"), - newPlugin.Name, newPlugin.Author, Environment.NewLine), - App.API.GetTranslation("InstallPromptTitle"), - button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; - - try - { - // at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download - var downloadFilename = string.IsNullOrEmpty(newPlugin.Version) - ? $"{newPlugin.Name}-{Guid.NewGuid()}.zip" - : $"{newPlugin.Name}-{newPlugin.Version}.zip"; - - var filePath = Path.Combine(Path.GetTempPath(), downloadFilename); - - using var cts = new CancellationTokenSource(); - - if (!newPlugin.IsFromLocalInstallPath) - { - await DownloadFileAsync( - $"{App.API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}", - newPlugin.UrlDownload, filePath, cts); - } - else - { - filePath = newPlugin.LocalInstallPath; - } - - // check if user cancelled download before installing plugin - if (cts.IsCancellationRequested) - { - return; - } - else - { - if (!File.Exists(filePath)) - { - throw new FileNotFoundException($"Plugin {newPlugin.ID} zip file not found at {filePath}", filePath); - } - - App.API.InstallPlugin(newPlugin, filePath); - - if (!newPlugin.IsFromLocalInstallPath) - { - File.Delete(filePath); - } - } - } - catch (Exception e) - { - App.API.LogException(ClassName, "Failed to install plugin", e); - App.API.ShowMsgError(App.API.GetTranslation("ErrorInstallingPlugin")); - return; // don’t restart on failure - } - - if (Settings.AutoRestartAfterChanging) - { - App.API.RestartApp(); - } - else - { - App.API.ShowMsg( - App.API.GetTranslation("installbtn"), - string.Format( - App.API.GetTranslation( - "InstallSuccessNoRestart"), - newPlugin.Name)); - } - } - - internal static async Task UninstallPluginAsync(PluginMetadata oldPlugin) - { - if (App.API.ShowMsgBox( - string.Format( - App.API.GetTranslation("UninstallPromptSubtitle"), - oldPlugin.Name, oldPlugin.Author, Environment.NewLine), - App.API.GetTranslation("UninstallPromptTitle"), - button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; - - var removePluginSettings = App.API.ShowMsgBox( - App.API.GetTranslation("KeepPluginSettingsSubtitle"), - App.API.GetTranslation("KeepPluginSettingsTitle"), - button: MessageBoxButton.YesNo) == MessageBoxResult.No; - - try - { - await App.API.UninstallPluginAsync(oldPlugin, removePluginSettings); - } - catch (Exception e) - { - App.API.LogException(ClassName, "Failed to uninstall plugin", e); - App.API.ShowMsgError(App.API.GetTranslation("ErrorUninstallingPlugin")); - return; // don’t restart on failure - } - - if (Settings.AutoRestartAfterChanging) - { - App.API.RestartApp(); - } - else - { - App.API.ShowMsg( - App.API.GetTranslation("uninstallbtn"), - string.Format( - App.API.GetTranslation( - "UninstallSuccessNoRestart"), - oldPlugin.Name)); - } - } - - internal static async Task UpdatePluginAsync(UserPlugin newPlugin, PluginMetadata oldPlugin) - { - if (App.API.ShowMsgBox( - string.Format( - App.API.GetTranslation("UpdatePromptSubtitle"), - oldPlugin.Name, oldPlugin.Author, Environment.NewLine), - App.API.GetTranslation("UpdatePromptTitle"), - button: MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; - - try - { - var filePath = Path.Combine(Path.GetTempPath(), $"{newPlugin.Name}-{newPlugin.Version}.zip"); - - using var cts = new CancellationTokenSource(); - - if (!newPlugin.IsFromLocalInstallPath) - { - await DownloadFileAsync( - $"{App.API.GetTranslation("DownloadingPlugin")} {newPlugin.Name}", - newPlugin.UrlDownload, filePath, cts); - } - else - { - filePath = newPlugin.LocalInstallPath; - } - - // check if user cancelled download before installing plugin - if (cts.IsCancellationRequested) - { - return; - } - else - { - await App.API.UpdatePluginAsync(oldPlugin, newPlugin, filePath); - } - } - catch (Exception e) - { - App.API.LogException(ClassName, "Failed to update plugin", e); - App.API.ShowMsgError(App.API.GetTranslation("ErrorUpdatingPlugin")); - return; // don’t restart on failure - } - - if (Settings.AutoRestartAfterChanging) - { - App.API.RestartApp(); - } - else - { - App.API.ShowMsg( - App.API.GetTranslation("updatebtn"), - string.Format( - App.API.GetTranslation( - "UpdateSuccessNoRestart"), - newPlugin.Name)); - } - } - - private static async Task DownloadFileAsync(string prgBoxTitle, string downloadUrl, string filePath, CancellationTokenSource cts, bool deleteFile = true, bool showProgress = true) - { - if (deleteFile && File.Exists(filePath)) - File.Delete(filePath); - - if (showProgress) - { - var exceptionHappened = false; - await App.API.ShowProgressBoxAsync(prgBoxTitle, - async (reportProgress) => - { - if (reportProgress == null) - { - // when reportProgress is null, it means there is expcetion with the progress box - // so we record it with exceptionHappened and return so that progress box will close instantly - exceptionHappened = true; - return; - } - else - { - await App.API.HttpDownloadAsync(downloadUrl, filePath, reportProgress, cts.Token).ConfigureAwait(false); - } - }, cts.Cancel); - - // if exception happened while downloading and user does not cancel downloading, - // we need to redownload the plugin - if (exceptionHappened && (!cts.IsCancellationRequested)) - await App.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); - } - else - { - await App.API.HttpDownloadAsync(downloadUrl, filePath, token: cts.Token).ConfigureAwait(false); - } - } } } diff --git a/Flow.Launcher/ViewModel/PluginViewModel.cs b/Flow.Launcher/ViewModel/PluginViewModel.cs index bda05a02d..f902fb037 100644 --- a/Flow.Launcher/ViewModel/PluginViewModel.cs +++ b/Flow.Launcher/ViewModel/PluginViewModel.cs @@ -172,7 +172,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private async Task OpenDeletePluginWindowAsync() { - await PluginStoreItemViewModel.UninstallPluginAsync(PluginPair.Metadata); + await PluginManager.UninstallPluginAndCheckRestartAsync(PluginPair.Metadata); } [RelayCommand] From 6bf7f00f0a7c268ff2e5c62bcbe791ff84328157 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 1 Jun 2025 16:28:16 +0800 Subject: [PATCH 044/545] Add unknown source warning setting --- .../UserSettings/Settings.cs | 1 + Flow.Launcher/Languages/en.xaml | 2 ++ .../Views/SettingsPaneGeneral.xaml | 31 +++++++++++++------ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 0b2b042d4..9f8e51047 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -191,6 +191,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings public int MaxHistoryResultsToShowForHomePage { get; set; } = 5; public bool AutoRestartAfterChanging { get; set; } = false; + public bool ShowUnknownSourceWarning { get; set; } = true; public int CustomExplorerIndex { get; set; } = 0; diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 7f00926f1..2b42b8f84 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -133,6 +133,8 @@ This can only be edited if plugin supports Home feature and Home Page is enabled. Automatically restart after changing plugins Automatically restart Flow Launcher after installing/uninstalling/updating plugins + Show unknown source warning + Show warning when installing plugins from unknown sources Search Plugin diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 452e026d7..1966c4c0d 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -202,16 +202,27 @@ - - - + + + + + + + + + Date: Tue, 3 Jun 2025 23:06:24 +0800 Subject: [PATCH 045/545] Add new api OpenWebUrl --- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 13 +++++++++++++ Flow.Launcher/PublicAPIInstance.cs | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index cb60251ed..e89839131 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -305,6 +305,19 @@ namespace Flow.Launcher.Plugin /// Extra FileName Info public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null); + /// + /// Opens the URL using the browser with the given Uri object, even if the URL is a local file. + /// The browser and mode used is based on what's configured in Flow's default browser settings. + /// + public void OpenWebUrl(Uri url, bool? inPrivate = null, bool forceBrower = false); + + /// + /// Opens the URL using the browser with the given string, even if the URL is a local file. + /// The browser and mode used is based on what's configured in Flow's default browser settings. + /// Non-C# plugins should use this method. + /// + public void OpenWebUrl(string url, bool? inPrivate = null, bool forceBrower = false); + /// /// Opens the URL with the given Uri object. /// The browser and mode used is based on what's configured in Flow's default browser settings. diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index c06c56039..b238a899d 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -391,9 +391,9 @@ namespace Flow.Launcher } - private void OpenUri(Uri uri, bool? inPrivate = null) + private void OpenUri(Uri uri, bool? inPrivate = null, bool forceBrower = false) { - if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) + if (forceBrower || uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) { var browserInfo = _settings.CustomBrowser; @@ -420,6 +420,16 @@ namespace Flow.Launcher } } + public void OpenUrl(string url, bool? inPrivate = null, bool forceBrower = false) + { + OpenUri(new Uri(url), inPrivate, forceBrower); + } + + public void OpenUrl(Uri url, bool? inPrivate = null, bool forceBrower = false) + { + OpenUri(url, inPrivate, forceBrower); + } + public void OpenUrl(string url, bool? inPrivate = null) { OpenUri(new Uri(url), inPrivate); From 54c2cd13f64b3ef42d60554e79f5365da2d243dd Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 3 Jun 2025 23:06:38 +0800 Subject: [PATCH 046/545] Force web url for WebSearch plugin --- Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs index 76aeb3250..0040cffa7 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs @@ -71,7 +71,7 @@ namespace Flow.Launcher.Plugin.WebSearch Score = score, Action = c => { - _context.API.OpenUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(keyword))); + _context.API.OpenWebUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(keyword))); return true; }, @@ -135,7 +135,7 @@ namespace Flow.Launcher.Plugin.WebSearch ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, Action = c => { - _context.API.OpenUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(o))); + _context.API.OpenWebUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(o))); return true; }, From c001041ba8d2743617c4931a0ad72038e0fd0fb1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 3 Jun 2025 23:08:51 +0800 Subject: [PATCH 047/545] Fix build issue --- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 4 ++-- Flow.Launcher/PublicAPIInstance.cs | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index e89839131..b87cc52d0 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -309,14 +309,14 @@ namespace Flow.Launcher.Plugin /// Opens the URL using the browser with the given Uri object, even if the URL is a local file. /// The browser and mode used is based on what's configured in Flow's default browser settings. /// - public void OpenWebUrl(Uri url, bool? inPrivate = null, bool forceBrower = false); + public void OpenWebUrl(Uri url, bool? inPrivate = null); /// /// Opens the URL using the browser with the given string, even if the URL is a local file. /// The browser and mode used is based on what's configured in Flow's default browser settings. /// Non-C# plugins should use this method. /// - public void OpenWebUrl(string url, bool? inPrivate = null, bool forceBrower = false); + public void OpenWebUrl(string url, bool? inPrivate = null); /// /// Opens the URL with the given Uri object. diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index b238a899d..bc82c2e8f 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -390,7 +390,6 @@ namespace Flow.Launcher } } - private void OpenUri(Uri uri, bool? inPrivate = null, bool forceBrower = false) { if (forceBrower || uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) @@ -420,14 +419,14 @@ namespace Flow.Launcher } } - public void OpenUrl(string url, bool? inPrivate = null, bool forceBrower = false) + public void OpenWebUrl(string url, bool? inPrivate = null) { - OpenUri(new Uri(url), inPrivate, forceBrower); + OpenUri(new Uri(url), inPrivate, true); } - public void OpenUrl(Uri url, bool? inPrivate = null, bool forceBrower = false) + public void OpenWebUrl(Uri url, bool? inPrivate = null) { - OpenUri(url, inPrivate, forceBrower); + OpenUri(url, inPrivate, true); } public void OpenUrl(string url, bool? inPrivate = null) From f4d6ef371a7738924b3c6a3ee857ce76544e1482 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 4 Jun 2025 18:57:20 +0800 Subject: [PATCH 048/545] Fix typos --- Flow.Launcher/PublicAPIInstance.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index bc82c2e8f..b4a6b47b7 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -390,9 +390,9 @@ namespace Flow.Launcher } } - private void OpenUri(Uri uri, bool? inPrivate = null, bool forceBrower = false) + private void OpenUri(Uri uri, bool? inPrivate = null, bool forceBrowser = false) { - if (forceBrower || uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) + if (forceBrowser || uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) { var browserInfo = _settings.CustomBrowser; From 33a5ca845a5700e28c1d886cbf151aebdf6af791 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 6 Jun 2025 13:12:40 +0800 Subject: [PATCH 049/545] Support Msix FireFox bookmarks --- .../FirefoxBookmarkLoader.cs | 165 +++++++++++------- 1 file changed, 98 insertions(+), 67 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index acace2506..42a288e3a 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -264,84 +264,115 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase /// public override List GetBookmarks() { - return GetBookmarksFromPath(PlacesPath); + var bookmarks1 = GetBookmarksFromPath(PlacesPath); + var bookmarks2 = GetBookmarksFromPath(MsixPlacesPath); + return bookmarks1.Concat(bookmarks2).ToList(); } /// - /// Path to places.sqlite + /// Path to places.sqlite of Msi installer + /// E.g. C:\Users\{UserName}\AppData\Roaming\Mozilla\Firefox + /// /// - /// private static string PlacesPath { get { var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox"); - var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); - - if (!File.Exists(profileIni)) - return string.Empty; - - // get firefox default profile directory from profiles.ini - using var sReader = new StreamReader(profileIni); - var ini = sReader.ReadToEnd(); - - var lines = ini.Split("\r\n").ToList(); - - var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; - - if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) - return string.Empty; - - var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); - - var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); - - /* - Current profiles.ini structure example as of Firefox version 69.0.1 - - [Install736426B0AF4A39CB] - Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile - Locked=1 - - [Profile2] - Name=newblahprofile - IsRelative=0 - Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. - - [Profile1] - Name=default - IsRelative=1 - Path=Profiles/cydum7q4.default - Default=1 - - [Profile0] - Name=default-release - IsRelative=1 - Path=Profiles/7789f565.default-release - - [General] - StartWithLastProfile=1 - Version=2 - */ - // Seen in the example above, the IsRelative attribute is always above the Path attribute - - var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); - var absoluePath = Path.Combine(profileFolderPath, relativePath); - - // If the index is out of range, it means that the default profile is in a custom location or the file is malformed - // If the profile is in a custom location, we need to check - if (indexOfDefaultProfileAttributePath - 1 < 0 || - indexOfDefaultProfileAttributePath - 1 >= lines.Count) - { - return Directory.Exists(absoluePath) ? absoluePath : relativePath; - } - - var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; - - return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 - ? relativePath : absoluePath; + return GetProfileIniPath(profileFolderPath); } } + + /// + /// Path to places.sqlite of MSIX installer + /// E.g. C:\Users\{UserName}\AppData\Local\Packages\Mozilla.Firefox_n80bbvh6b1yt2\LocalCache\Roaming\Mozilla\Firefox + /// + /// + public static string MsixPlacesPath + { + get + { + var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var packagesPath = Path.Combine(platformPath, "Packages"); + + // Search for folder with Mozilla.Firefox prefix + var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", + SearchOption.TopDirectoryOnly).FirstOrDefault(); + + // Msix FireFox not installed + if (firefoxPackageFolder == null) return string.Empty; + + var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); + return GetProfileIniPath(profileFolderPath); + } + } + + private static string GetProfileIniPath(string profileFolderPath) + { + var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); + if (!File.Exists(profileIni)) + return string.Empty; + + // get firefox default profile directory from profiles.ini + using var sReader = new StreamReader(profileIni); + var ini = sReader.ReadToEnd(); + + var lines = ini.Split("\r\n").ToList(); + + var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; + + if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) + return string.Empty; + + var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); + + var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); + + /* + Current profiles.ini structure example as of Firefox version 69.0.1 + + [Install736426B0AF4A39CB] + Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile + Locked=1 + + [Profile2] + Name=newblahprofile + IsRelative=0 + Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. + + [Profile1] + Name=default + IsRelative=1 + Path=Profiles/cydum7q4.default + Default=1 + + [Profile0] + Name=default-release + IsRelative=1 + Path=Profiles/7789f565.default-release + + [General] + StartWithLastProfile=1 + Version=2 + */ + // Seen in the example above, the IsRelative attribute is always above the Path attribute + + var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); + var absoluePath = Path.Combine(profileFolderPath, relativePath); + + // If the index is out of range, it means that the default profile is in a custom location or the file is malformed + // If the profile is in a custom location, we need to check + if (indexOfDefaultProfileAttributePath - 1 < 0 || + indexOfDefaultProfileAttributePath - 1 >= lines.Count) + { + return Directory.Exists(absoluePath) ? absoluePath : relativePath; + } + + var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; + + return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + ? relativePath : absoluePath; + } } public static class Extensions From 57470a9799d9e968932f1b4e37c194f19bf428ad Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 6 Jun 2025 13:21:51 +0800 Subject: [PATCH 050/545] Fix IsRelative logic. --- .../FirefoxBookmarkLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 42a288e3a..61fd05073 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -370,7 +370,8 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; - return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + return (relativeAttribute == "0" || relativeAttribute == "IsRelative=0") ? relativePath : absoluePath; } } From f59e2399b9d0a58ea59eac2cdee87810a9fcb350 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 6 Jun 2025 13:25:43 +0800 Subject: [PATCH 051/545] Add error handling for directory operation --- .../FirefoxBookmarkLoader.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 61fd05073..ac382275f 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -294,16 +294,22 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase { var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var packagesPath = Path.Combine(platformPath, "Packages"); - - // Search for folder with Mozilla.Firefox prefix - var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", - SearchOption.TopDirectoryOnly).FirstOrDefault(); + try + { + // Search for folder with Mozilla.Firefox prefix + var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", + SearchOption.TopDirectoryOnly).FirstOrDefault(); - // Msix FireFox not installed - if (firefoxPackageFolder == null) return string.Empty; + // Msix FireFox not installed + if (firefoxPackageFolder == null) return string.Empty; - var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); - return GetProfileIniPath(profileFolderPath); + var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); + return GetProfileIniPath(profileFolderPath); + } + catch + { + return string.Empty; + } } } From c8e82cbd09db15ed2ba667a5f1b50b8195dbe6fb Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 8 Jun 2025 00:14:31 +0800 Subject: [PATCH 052/545] Cache connection and clear pool after all operations to avoid ObjectDisposedException --- .../ChromiumBookmarkLoader.cs | 13 +++++++++++-- .../FirefoxBookmarkLoader.cs | 13 +++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index e102e43b6..0a531f824 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -155,6 +155,9 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader return; } + // Cache connection for pool clean + SqliteConnection connection1 = null; + try { // Since some bookmarks may have same favicon id, we need to record them to avoid duplicates @@ -216,8 +219,9 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } finally { - // https://github.com/dotnet/efcore/issues/26580 - SqliteConnection.ClearPool(connection); + // Cache connection and clear pool after all operations to avoid issue: + // ObjectDisposedException: Safe handle has been closed. + connection1 = connection; connection.Close(); connection.Dispose(); } @@ -231,6 +235,11 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader // Delete temporary file try { + // https://github.com/dotnet/efcore/issues/26580 + if (connection1 != null) + { + SqliteConnection.ClearPool(connection1); + } File.Delete(tempDbPath); } catch (Exception ex) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index acace2506..5e4f7cbee 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -142,6 +142,9 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader return; } + // Cache connection for pool clean + SqliteConnection connection1 = null; + try { // Since some bookmarks may have same favicon id, we need to record them to avoid duplicates @@ -212,8 +215,9 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } finally { - // https://github.com/dotnet/efcore/issues/26580 - SqliteConnection.ClearPool(connection); + // Cache connection and clear pool after all operations to avoid issue: + // ObjectDisposedException: Safe handle has been closed. + connection1 = connection; connection.Close(); connection.Dispose(); } @@ -227,6 +231,11 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader // Delete temporary file try { + // https://github.com/dotnet/efcore/issues/26580 + if (connection1 != null) + { + SqliteConnection.ClearPool(connection1); + } File.Delete(tempDbPath); } catch (Exception ex) From c323646b1a321e566a67b5b41a73e0ede756d4af Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 8 Jun 2025 12:09:07 +0800 Subject: [PATCH 053/545] Use AddRange --- .../FirefoxBookmarkLoader.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index ac382275f..dcf7763c3 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -264,9 +264,10 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase /// public override List GetBookmarks() { - var bookmarks1 = GetBookmarksFromPath(PlacesPath); - var bookmarks2 = GetBookmarksFromPath(MsixPlacesPath); - return bookmarks1.Concat(bookmarks2).ToList(); + var bookmarks = new List(); + bookmarks.AddRange(GetBookmarksFromPath(PlacesPath)); + bookmarks.AddRange(GetBookmarksFromPath(MsixPlacesPath)); + return bookmarks; } /// From 2ed32b318d84d7b743d8830570f60a9cb81aab74 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 8 Jun 2025 12:17:47 +0800 Subject: [PATCH 054/545] Do not use pooling so that we do not need to clear pool --- .../ChromiumBookmarkLoader.cs | 12 ++---------- .../FirefoxBookmarkLoader.cs | 12 ++---------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index 0a531f824..67d54a786 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -155,9 +155,6 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader return; } - // Cache connection for pool clean - SqliteConnection connection1 = null; - try { // Since some bookmarks may have same favicon id, we need to record them to avoid duplicates @@ -167,7 +164,8 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader Parallel.ForEach(bookmarks, bookmark => { // Use read-only connection to avoid locking issues - var connection = new SqliteConnection($"Data Source={tempDbPath};Mode=ReadOnly"); + // Do not use pooling so that we do not need to clear pool: https://github.com/dotnet/efcore/issues/26580 + var connection = new SqliteConnection($"Data Source={tempDbPath};Mode=ReadOnly;Pooling=false"); connection.Open(); try @@ -221,7 +219,6 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader { // Cache connection and clear pool after all operations to avoid issue: // ObjectDisposedException: Safe handle has been closed. - connection1 = connection; connection.Close(); connection.Dispose(); } @@ -235,11 +232,6 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader // Delete temporary file try { - // https://github.com/dotnet/efcore/issues/26580 - if (connection1 != null) - { - SqliteConnection.ClearPool(connection1); - } File.Delete(tempDbPath); } catch (Exception ex) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 5e4f7cbee..b1ed0d430 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -142,9 +142,6 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader return; } - // Cache connection for pool clean - SqliteConnection connection1 = null; - try { // Since some bookmarks may have same favicon id, we need to record them to avoid duplicates @@ -154,7 +151,8 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader Parallel.ForEach(bookmarks, bookmark => { // Use read-only connection to avoid locking issues - var connection = new SqliteConnection($"Data Source={tempDbPath};Mode=ReadOnly"); + // Do not use pooling so that we do not need to clear pool: https://github.com/dotnet/efcore/issues/26580 + var connection = new SqliteConnection($"Data Source={tempDbPath};Mode=ReadOnly;Pooling=false"); connection.Open(); try @@ -217,7 +215,6 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader { // Cache connection and clear pool after all operations to avoid issue: // ObjectDisposedException: Safe handle has been closed. - connection1 = connection; connection.Close(); connection.Dispose(); } @@ -231,11 +228,6 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader // Delete temporary file try { - // https://github.com/dotnet/efcore/issues/26580 - if (connection1 != null) - { - SqliteConnection.ClearPool(connection1); - } File.Delete(tempDbPath); } catch (Exception ex) From d7b8f85f4a581dd36a5ca261a650953638830685 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 8 Jun 2025 12:35:39 +0800 Subject: [PATCH 055/545] Use FaviconHelper --- .../ChromiumBookmarkLoader.cs | 71 +++-------------- .../FirefoxBookmarkLoader.cs | 68 ++--------------- .../Helper/FaviconHelper.cs | 76 +++++++++++++++++++ 3 files changed, 92 insertions(+), 123 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index 67d54a786..6e6b2e5f4 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Text.Json; using System.Threading.Tasks; +using Flow.Launcher.Plugin.BrowserBookmark.Helper; using Flow.Launcher.Plugin.BrowserBookmark.Models; using Microsoft.Data.Sqlite; @@ -131,31 +132,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader private void LoadFaviconsFromDb(string dbPath, List bookmarks) { - // Use a copy to avoid lock issues with the original file - var tempDbPath = Path.Combine(_faviconCacheDir, $"tempfavicons_{Guid.NewGuid()}.db"); - - try - { - File.Copy(dbPath, tempDbPath, true); - } - catch (Exception ex) - { - try - { - if (File.Exists(tempDbPath)) - { - File.Delete(tempDbPath); - } - } - catch (Exception ex1) - { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); - } - Main._context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); - return; - } - - try + FaviconHelper.LoadFaviconsFromDb(_faviconCacheDir, dbPath, (tempDbPath) => { // Since some bookmarks may have same favicon id, we need to record them to avoid duplicates var savedPaths = new ConcurrentDictionary(); @@ -181,13 +158,13 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader using var cmd = connection.CreateCommand(); cmd.CommandText = @" - SELECT f.id, b.image_data - FROM favicons f - JOIN favicon_bitmaps b ON f.id = b.icon_id - JOIN icon_mapping m ON f.id = m.icon_id - WHERE m.page_url LIKE @url - ORDER BY b.width DESC - LIMIT 1"; + SELECT f.id, b.image_data + FROM favicons f + JOIN favicon_bitmaps b ON f.id = b.icon_id + JOIN icon_mapping m ON f.id = m.icon_id + WHERE m.page_url LIKE @url + ORDER BY b.width DESC + LIMIT 1"; cmd.Parameters.AddWithValue("@url", $"%{domain}%"); @@ -206,7 +183,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader // Filter out duplicate favicons if (savedPaths.TryAdd(faviconPath, true)) { - SaveBitmapData(imageData, faviconPath); + FaviconHelper.SaveBitmapData(imageData, faviconPath); } bookmark.FaviconPath = faviconPath; @@ -223,32 +200,6 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader connection.Dispose(); } }); - } - catch (Exception ex) - { - Main._context.API.LogException(ClassName, $"Failed to connect to SQLite: {tempDbPath}", ex); - } - - // Delete temporary file - try - { - File.Delete(tempDbPath); - } - catch (Exception ex) - { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); - } - } - - private static void SaveBitmapData(byte[] imageData, string outputPath) - { - try - { - File.WriteAllBytes(outputPath, imageData); - } - catch (Exception ex) - { - Main._context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); - } + }); } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index b1ed0d430..82e7c01f6 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; +using Flow.Launcher.Plugin.BrowserBookmark.Helper; using Flow.Launcher.Plugin.BrowserBookmark.Models; using Microsoft.Data.Sqlite; @@ -118,31 +119,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader private void LoadFaviconsFromDb(string dbPath, List bookmarks) { - // Use a copy to avoid lock issues with the original file - var tempDbPath = Path.Combine(_faviconCacheDir, $"tempfavicons_{Guid.NewGuid()}.sqlite"); - - try - { - File.Copy(dbPath, tempDbPath, true); - } - catch (Exception ex) - { - try - { - if (File.Exists(tempDbPath)) - { - File.Delete(tempDbPath); - } - } - catch (Exception ex1) - { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); - } - Main._context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); - return; - } - - try + FaviconHelper.LoadFaviconsFromDb(_faviconCacheDir, dbPath, (tempDbPath) => { // Since some bookmarks may have same favicon id, we need to record them to avoid duplicates var savedPaths = new ConcurrentDictionary(); @@ -190,7 +167,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader return; string faviconPath; - if (IsSvgData(imageData)) + if (FaviconHelper.IsSvgData(imageData)) { faviconPath = Path.Combine(_faviconCacheDir, $"firefox_{domain}.svg"); } @@ -202,7 +179,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader // Filter out duplicate favicons if (savedPaths.TryAdd(faviconPath, true)) { - SaveBitmapData(imageData, faviconPath); + FaviconHelper.SaveBitmapData(imageData, faviconPath); } bookmark.FaviconPath = faviconPath; @@ -219,42 +196,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader connection.Dispose(); } }); - } - catch (Exception ex) - { - Main._context.API.LogException(ClassName, $"Failed to load Firefox favicon DB: {tempDbPath}", ex); - } - - // Delete temporary file - try - { - File.Delete(tempDbPath); - } - catch (Exception ex) - { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); - } - } - - private static void SaveBitmapData(byte[] imageData, string outputPath) - { - try - { - File.WriteAllBytes(outputPath, imageData); - } - catch (Exception ex) - { - Main._context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); - } - } - - private static bool IsSvgData(byte[] data) - { - if (data.Length < 5) - return false; - string start = System.Text.Encoding.ASCII.GetString(data, 0, Math.Min(100, data.Length)); - return start.Contains(" loadAction) + { + // Use a copy to avoid lock issues with the original file + var tempDbPath = Path.Combine(faviconCacheDir, $"tempfavicons_{Guid.NewGuid()}.db"); + + try + { + File.Copy(dbPath, tempDbPath, true); + } + catch (Exception ex) + { + try + { + if (File.Exists(tempDbPath)) + { + File.Delete(tempDbPath); + } + } + catch (Exception ex1) + { + Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); + } + Main._context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); + return; + } + + try + { + loadAction(tempDbPath); + } + catch (Exception ex) + { + Main._context.API.LogException(ClassName, $"Failed to connect to SQLite: {tempDbPath}", ex); + } + + // Delete temporary file + try + { + File.Delete(tempDbPath); + } + catch (Exception ex) + { + Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); + } + } + + public static void SaveBitmapData(byte[] imageData, string outputPath) + { + try + { + File.WriteAllBytes(outputPath, imageData); + } + catch (Exception ex) + { + Main._context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); + } + } + + public static bool IsSvgData(byte[] data) + { + if (data.Length < 5) + return false; + string start = System.Text.Encoding.ASCII.GetString(data, 0, Math.Min(100, data.Length)); + return start.Contains(" Date: Mon, 9 Jun 2025 20:28:18 +0800 Subject: [PATCH 056/545] Support installing from local path --- Flow.Launcher.Core/Plugin/PluginManager.cs | 55 +++++++++++++++++++ Flow.Launcher/Languages/en.xaml | 6 ++ .../SettingsPanePluginStoreViewModel.cs | 35 +++++++++++- .../Views/SettingsPanePluginStore.xaml | 7 +++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index ef831e940..f7a2461ab 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -2,6 +2,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Text.Json; using System.Threading; @@ -633,6 +634,42 @@ namespace Flow.Launcher.Core.Plugin } } + public static async Task InstallPluginAndCheckRestartAsync(string filePath) + { + UserPlugin plugin; + try + { + using ZipArchive archive = ZipFile.OpenRead(filePath); + var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json") ?? + throw new FileNotFoundException("The zip file does not contain a plugin.json file."); + var pluginJsonEntry = archive.GetEntry(pluginJsonPath.ToString()) ?? + throw new FileNotFoundException("The zip file does not contain a plugin.json file."); + + using Stream stream = pluginJsonEntry.Open(); + plugin = JsonSerializer.Deserialize(stream); + plugin.IcoPath = "Images\\zipfolder.png"; + plugin.LocalInstallPath = filePath; + } + catch (Exception e) + { + API.LogException(ClassName, "Failed to validate zip file", e); + API.ShowMsgError(API.GetTranslation("ZipFileNotHavePluginJson")); + return; + } + + if (FlowSettings.ShowUnknownSourceWarning) + { + if (!InstallSourceKnown(plugin.Website) + && API.ShowMsgBox(string.Format( + API.GetTranslation("InstallFromUnknownSourceSubtitle"), Environment.NewLine), + API.GetTranslation("InstallFromUnknownSourceTitle"), + MessageBoxButton.YesNo) == MessageBoxResult.No) + return; + } + + await InstallPluginAndCheckRestartAsync(plugin); + } + public static async Task UninstallPluginAndCheckRestartAsync(PluginMetadata oldPlugin) { if (API.ShowMsgBox( @@ -913,6 +950,24 @@ namespace Flow.Launcher.Core.Plugin } } + private static bool InstallSourceKnown(string url) + { + var pieces = url.Split('/'); + + if (pieces.Length < 4) + return false; + + var author = pieces[3]; + var acceptedSource = "https://github.com"; + var constructedUrlPart = string.Format("{0}/{1}/", acceptedSource, author); + + return url.StartsWith(acceptedSource) && + API.GetAllPlugins().Any(x => + !string.IsNullOrEmpty(x.Metadata.Website) && + x.Metadata.Website.StartsWith(constructedUrlPart) + ); + } + #endregion } } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index b3fdd6892..6ce5d17d0 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -204,6 +204,12 @@ {0} by {1} {2}{2}Would you like to update this plugin? Downloading plugin Automatically restart after installing/uninstalling/updating plugins in plugin store + Zip file does not have a valid plugin.json configuration + Installing from an unknown source + This plugin is from an unknown source and it may contain potential risks!{0}{0}Please ensure you understand where this plugin is from and that it is safe.{0}{0}Would you like to continue still?{0}{0}(You can switch off this warning in general section of setting window) + Zip files + Please select zip file + Install plugin from local path Theme diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs index 07df0682d..b9b7c12fa 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs @@ -1,7 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using System.Windows.Forms; using CommunityToolkit.Mvvm.Input; +using Flow.Launcher.Core.Plugin; using Flow.Launcher.Plugin; using Flow.Launcher.ViewModel; @@ -96,6 +99,36 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel } } + [RelayCommand] + private async Task InstallPluginAsync() + { + var file = GetFileFromDialog( + App.API.GetTranslation("SelectZipFile"), + $"{App.API.GetTranslation("ZipFiles")} (*.zip)|*.zip"); + + if (!string.IsNullOrEmpty(file)) + await PluginManager.InstallPluginAndCheckRestartAsync(file); + } + + private static string GetFileFromDialog(string title, string filter = "") + { + var dlg = new OpenFileDialog + { + InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "\\Downloads", + Multiselect = false, + CheckFileExists = true, + CheckPathExists = true, + Title = title, + Filter = filter + }; + + return dlg.ShowDialog() switch + { + DialogResult.OK => dlg.FileName, + _ => string.Empty + }; + } + public bool SatisfiesFilter(PluginStoreItemViewModel plugin) { // Check plugin language diff --git a/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml b/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml index 9312b0c2d..68f78d46c 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPanePluginStore.xaml @@ -92,6 +92,13 @@ + Date: Tue, 10 Jun 2025 10:04:12 +0200 Subject: [PATCH 057/545] Update Button width for responsive design Modified Button to use auto width with a minimum width of 100. This change allows the button to grow when keywords do not fit. --- .../Resources/Controls/InstalledPluginDisplayKeyword.xaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml b/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml index ded6e0e27..bb1d3cc0f 100644 --- a/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml +++ b/Flow.Launcher/Resources/Controls/InstalledPluginDisplayKeyword.xaml @@ -36,7 +36,8 @@ Text="{DynamicResource actionKeywords}" /> - - - - - - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -118,14 +117,14 @@ x:Name="btnCancel" Width="145" Height="30" - Margin="10 0 5 0" + Margin="10 0 10 0" Click="BtnCancel_OnClick" Content="{DynamicResource cancel}" /> public override List GetBookmarks() { - return GetBookmarksFromPath(PlacesPath); + var bookmarks1 = GetBookmarksFromPath(PlacesPath); + var bookmarks2 = GetBookmarksFromPath(MsixPlacesPath); + return bookmarks1.Concat(bookmarks2).ToList(); } /// - /// Path to places.sqlite + /// Path to places.sqlite of Msi installer + /// E.g. C:\Users\{UserName}\AppData\Roaming\Mozilla\Firefox + /// /// - /// private static string PlacesPath { get { var profileFolderPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"Mozilla\Firefox"); - var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); - - if (!File.Exists(profileIni)) - return string.Empty; - - // get firefox default profile directory from profiles.ini - using var sReader = new StreamReader(profileIni); - var ini = sReader.ReadToEnd(); - - var lines = ini.Split("\r\n").ToList(); - - var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; - - if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) - return string.Empty; - - var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); - - var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); - - /* - Current profiles.ini structure example as of Firefox version 69.0.1 - - [Install736426B0AF4A39CB] - Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile - Locked=1 - - [Profile2] - Name=newblahprofile - IsRelative=0 - Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. - - [Profile1] - Name=default - IsRelative=1 - Path=Profiles/cydum7q4.default - Default=1 - - [Profile0] - Name=default-release - IsRelative=1 - Path=Profiles/7789f565.default-release - - [General] - StartWithLastProfile=1 - Version=2 - */ - // Seen in the example above, the IsRelative attribute is always above the Path attribute - - var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); - var absoluePath = Path.Combine(profileFolderPath, relativePath); - - // If the index is out of range, it means that the default profile is in a custom location or the file is malformed - // If the profile is in a custom location, we need to check - if (indexOfDefaultProfileAttributePath - 1 < 0 || - indexOfDefaultProfileAttributePath - 1 >= lines.Count) - { - return Directory.Exists(absoluePath) ? absoluePath : relativePath; - } - - var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; - - return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 - ? relativePath : absoluePath; + return GetProfileIniPath(profileFolderPath); } } + + /// + /// Path to places.sqlite of MSIX installer + /// E.g. C:\Users\{UserName}\AppData\Local\Packages\Mozilla.Firefox_n80bbvh6b1yt2\LocalCache\Roaming\Mozilla\Firefox + /// + /// + public static string MsixPlacesPath + { + get + { + var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var packagesPath = Path.Combine(platformPath, "Packages"); + + // Search for folder with Mozilla.Firefox prefix + var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", + SearchOption.TopDirectoryOnly).FirstOrDefault(); + + // Msix FireFox not installed + if (firefoxPackageFolder == null) return string.Empty; + + var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); + return GetProfileIniPath(profileFolderPath); + } + } + + private static string GetProfileIniPath(string profileFolderPath) + { + var profileIni = Path.Combine(profileFolderPath, @"profiles.ini"); + if (!File.Exists(profileIni)) + return string.Empty; + + // get firefox default profile directory from profiles.ini + using var sReader = new StreamReader(profileIni); + var ini = sReader.ReadToEnd(); + + var lines = ini.Split("\r\n").ToList(); + + var defaultProfileFolderNameRaw = lines.FirstOrDefault(x => x.Contains("Default=") && x != "Default=1") ?? string.Empty; + + if (string.IsNullOrEmpty(defaultProfileFolderNameRaw)) + return string.Empty; + + var defaultProfileFolderName = defaultProfileFolderNameRaw.Split('=').Last(); + + var indexOfDefaultProfileAttributePath = lines.IndexOf("Path=" + defaultProfileFolderName); + + /* + Current profiles.ini structure example as of Firefox version 69.0.1 + + [Install736426B0AF4A39CB] + Default=Profiles/7789f565.default-release <== this is the default profile this plugin will get the bookmarks from. When opened Firefox will load the default profile + Locked=1 + + [Profile2] + Name=newblahprofile + IsRelative=0 + Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. + + [Profile1] + Name=default + IsRelative=1 + Path=Profiles/cydum7q4.default + Default=1 + + [Profile0] + Name=default-release + IsRelative=1 + Path=Profiles/7789f565.default-release + + [General] + StartWithLastProfile=1 + Version=2 + */ + // Seen in the example above, the IsRelative attribute is always above the Path attribute + + var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); + var absoluePath = Path.Combine(profileFolderPath, relativePath); + + // If the index is out of range, it means that the default profile is in a custom location or the file is malformed + // If the profile is in a custom location, we need to check + if (indexOfDefaultProfileAttributePath - 1 < 0 || + indexOfDefaultProfileAttributePath - 1 >= lines.Count) + { + return Directory.Exists(absoluePath) ? absoluePath : relativePath; + } + + var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; + + return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + ? relativePath : absoluePath; + } } public static class Extensions From 281e042ab7016621c649defcca942cf854cd6129 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 6 Jun 2025 13:21:51 +0800 Subject: [PATCH 075/545] Fix IsRelative logic. --- .../FirefoxBookmarkLoader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 42a288e3a..61fd05073 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -370,7 +370,8 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; - return relativeAttribute == "0" // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 + return (relativeAttribute == "0" || relativeAttribute == "IsRelative=0") ? relativePath : absoluePath; } } From ceb05e8651f847cddf9e2fa00d15a1ef741f56b4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 6 Jun 2025 13:25:43 +0800 Subject: [PATCH 076/545] Add error handling for directory operation --- .../FirefoxBookmarkLoader.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index 61fd05073..ac382275f 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -294,16 +294,22 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase { var platformPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var packagesPath = Path.Combine(platformPath, "Packages"); - - // Search for folder with Mozilla.Firefox prefix - var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", - SearchOption.TopDirectoryOnly).FirstOrDefault(); + try + { + // Search for folder with Mozilla.Firefox prefix + var firefoxPackageFolder = Directory.EnumerateDirectories(packagesPath, "Mozilla.Firefox*", + SearchOption.TopDirectoryOnly).FirstOrDefault(); - // Msix FireFox not installed - if (firefoxPackageFolder == null) return string.Empty; + // Msix FireFox not installed + if (firefoxPackageFolder == null) return string.Empty; - var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); - return GetProfileIniPath(profileFolderPath); + var profileFolderPath = Path.Combine(firefoxPackageFolder, @"LocalCache\Roaming\Mozilla\Firefox"); + return GetProfileIniPath(profileFolderPath); + } + catch + { + return string.Empty; + } } } From aaa8e4dc780900ce721555dba06c22fb6dd3de13 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 8 Jun 2025 12:09:07 +0800 Subject: [PATCH 077/545] Use AddRange --- .../FirefoxBookmarkLoader.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index ac382275f..dcf7763c3 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -264,9 +264,10 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase /// public override List GetBookmarks() { - var bookmarks1 = GetBookmarksFromPath(PlacesPath); - var bookmarks2 = GetBookmarksFromPath(MsixPlacesPath); - return bookmarks1.Concat(bookmarks2).ToList(); + var bookmarks = new List(); + bookmarks.AddRange(GetBookmarksFromPath(PlacesPath)); + bookmarks.AddRange(GetBookmarksFromPath(MsixPlacesPath)); + return bookmarks; } /// From 44304f25d68de8dd53b9a1ac414cffbffa07f2fb Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 11 Jun 2025 21:14:05 +0800 Subject: [PATCH 078/545] Change code comments --- .../FirefoxBookmarkLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index dcf7763c3..f214997c3 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -343,9 +343,9 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase Locked=1 [Profile2] - Name=newblahprofile + Name=dummyprofile IsRelative=0 - Path=C:\t6h2yuq8.newblahprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. + Path=C:\t6h2yuq8.dummyprofile <== Note this is a custom location path for the profile user can set, we need to cater for this in code. [Profile1] Name=default From 16fd256fd61873320691acd774c87cf7df4ee8be Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 12 Jun 2025 16:27:48 +0800 Subject: [PATCH 079/545] Fix typos --- .../FirefoxBookmarkLoader.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index f214997c3..8dffeecdc 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -365,21 +365,21 @@ public class FirefoxBookmarkLoader : FirefoxBookmarkLoaderBase // Seen in the example above, the IsRelative attribute is always above the Path attribute var relativePath = Path.Combine(defaultProfileFolderName, "places.sqlite"); - var absoluePath = Path.Combine(profileFolderPath, relativePath); + var absolutePath = Path.Combine(profileFolderPath, relativePath); // If the index is out of range, it means that the default profile is in a custom location or the file is malformed // If the profile is in a custom location, we need to check if (indexOfDefaultProfileAttributePath - 1 < 0 || indexOfDefaultProfileAttributePath - 1 >= lines.Count) { - return Directory.Exists(absoluePath) ? absoluePath : relativePath; + return Directory.Exists(absolutePath) ? absolutePath : relativePath; } var relativeAttribute = lines[indexOfDefaultProfileAttributePath - 1]; // See above, the profile is located in a custom location, path is not relative, so IsRelative=0 return (relativeAttribute == "0" || relativeAttribute == "IsRelative=0") - ? relativePath : absoluePath; + ? relativePath : absolutePath; } } From fba42fff1799f8a2c9e9e68e7ab067a17a4690a2 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 13 Jun 2025 22:31:28 +0800 Subject: [PATCH 080/545] Fix transaltion logic --- .../PinyinAlphabet.cs | 46 +++++++++---------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 1637a285c..090abb490 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -32,14 +32,14 @@ namespace Flow.Launcher.Infrastructure { if (_settings.ShouldUsePinyin) { - if (!_pinyinCache.TryGetValue(content, out var value)) + if (true) { return BuildCacheFromContent(content); } - else - { - return value; - } + //else + //{ + // return value; + //} } return (content, null); } @@ -164,11 +164,10 @@ namespace Flow.Launcher.Infrastructure // Check for initials that are two characters long (zh, ch, sh) if (fullPinyin.Length >= 2) { - var firstTwo = fullPinyinSpan[..2]; - var firstTwoString = firstTwo.ToString(); - if (first.ContainsKey(firstTwoString)) + var firstTwoString = fullPinyinSpan[..2].ToString(); + if (first.TryGetValue(firstTwoString, out var firstTwoDoublePin)) { - doublePin.Append(firstTwoString); + doublePin.Append(firstTwoDoublePin); var lastTwo = fullPinyinSpan[2..]; var lastTwoString = lastTwo.ToString(); @@ -178,27 +177,26 @@ namespace Flow.Launcher.Infrastructure } else { - doublePin.Append(lastTwo); + doublePin.Append(lastTwo); // Todo: original pinyin, remove this line if not needed } } - } - // Handle single-character initials - else - { - doublePin.Append(fullPinyinSpan[0]); - - var lastOne = fullPinyinSpan[1..]; - var lastOneString = lastOne.ToString(); - if (second.TryGetValue(lastOneString, out var tmp)) - { - doublePin.Append(tmp); - } else { - doublePin.Append(lastOne); + // Handle single-character initials + doublePin.Append(fullPinyinSpan[0]); + + var lastOne = fullPinyinSpan[1..]; + var lastOneString = lastOne.ToString(); + if (second.TryGetValue(lastOneString, out var tmp)) + { + doublePin.Append(tmp); + } + else + { + doublePin.Append(lastOne); + } } } - return doublePin.ToString(); } From b31a7408d3c279e92480530fc6a8cd8167b435c2 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Fri, 13 Jun 2025 23:39:14 +0800 Subject: [PATCH 081/545] Simple refactor --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 090abb490..2c548e0a3 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -30,18 +30,12 @@ namespace Flow.Launcher.Infrastructure public (string translation, TranslationMapping map) Translate(string content) { - if (_settings.ShouldUsePinyin) - { - if (true) - { - return BuildCacheFromContent(content); - } - //else - //{ - // return value; - //} - } - return (content, null); + if (!_settings.ShouldUsePinyin) + return (content, null); + + return _pinyinCache.TryGetValue(content, out var value) + ? value + : BuildCacheFromContent(content); } private (string translation, TranslationMapping map) BuildCacheFromContent(string content) From 818aac715e47aa0bcda35b2431dbeda4219bb88d Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:32:00 +0800 Subject: [PATCH 082/545] Use lookup table to translate full pinyin to double pinyin --- .../PinyinAlphabet.cs | 166 +- .../UserSettings/Settings.cs | 2 + Flow.Launcher/Flow.Launcher.csproj | 3 + Flow.Launcher/Resources/double_pinyin.json | 3746 +++++++++++++++++ 4 files changed, 3805 insertions(+), 112 deletions(-) create mode 100644 Flow.Launcher/Resources/double_pinyin.json diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 2c548e0a3..6a2cd1e66 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -2,10 +2,13 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.IO; using System.Text; +using System.Text.Json; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Infrastructure.UserSettings; using ToolGood.Words.Pinyin; +using Flow.Launcher.Infrastructure.Logger; namespace Flow.Launcher.Infrastructure { @@ -16,9 +19,49 @@ namespace Flow.Launcher.Infrastructure private readonly Settings _settings; + private ReadOnlyDictionary currentDoublePinyinTable; + public PinyinAlphabet() { _settings = Ioc.Default.GetRequiredService(); + LoadDoublePinyinTable(); + + _settings.PropertyChanged += (sender, e) => + { + if (e.PropertyName == nameof(Settings.UseDoublePinyin) || + e.PropertyName == nameof(Settings.DoublePinyinSchema)) + { + LoadDoublePinyinTable(); + _pinyinCache.Clear(); + } + }; + } + + private void LoadDoublePinyinTable() + { + if (_settings.UseDoublePinyin) + { + var tablePath = Path.Join(AppContext.BaseDirectory, "Resources", "double_pinyin.json"); + try + { + using var fs = File.OpenRead(tablePath); + Dictionary> table = JsonSerializer.Deserialize>>(fs); + if (!table.TryGetValue(_settings.DoublePinyinSchema, out var value)) + { + throw new InvalidOperationException("DoublePinyinSchema is invalid."); + } + currentDoublePinyinTable = new ReadOnlyDictionary(value); + } + catch (System.Exception e) + { + Log.Exception(nameof(PinyinAlphabet), "Failed to load double pinyin table from file: " + tablePath, e); + currentDoublePinyinTable = new ReadOnlyDictionary(new Dictionary()); + } + } + else + { + currentDoublePinyinTable = new ReadOnlyDictionary(new Dictionary()); + } } public bool ShouldTranslate(string stringToTranslate) @@ -50,7 +93,7 @@ namespace Flow.Launcher.Infrastructure var resultBuilder = new StringBuilder(); var map = new TranslationMapping(); - var pre = false; + var previousIsChinese = false; for (var i = 0; i < resultList.Length; i++) { @@ -58,18 +101,19 @@ namespace Flow.Launcher.Infrastructure { string dp = _settings.UseDoublePinyin ? ToDoublePin(resultList[i]) : resultList[i]; map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); - resultBuilder.Append(' '); + if (previousIsChinese) + { + resultBuilder.Append(' '); + } resultBuilder.Append(dp); - pre = true; } else { - if (pre) + if (previousIsChinese) { - pre = false; + previousIsChinese = false; resultBuilder.Append(' '); } - resultBuilder.Append(resultList[i]); } } @@ -83,115 +127,13 @@ namespace Flow.Launcher.Infrastructure #region Double Pinyin - private static readonly ReadOnlyDictionary special = new(new Dictionary(){ - {"A", "aa"}, - {"Ai", "ai"}, - {"An", "an"}, - {"Ang", "ah"}, - {"Ao", "ao"}, - {"E", "ee"}, - {"Ei", "ei"}, - {"En", "en"}, - {"Er", "er"}, - {"O", "oo"}, - {"Ou", "ou"} - }); - - private static readonly ReadOnlyDictionary first = new(new Dictionary(){ - {"Ch", "i"}, - {"Sh", "u"}, - {"Zh", "v"} - }); - - private static readonly ReadOnlyDictionary second = new(new Dictionary() + private string ToDoublePin(string fullPinyin) { - {"ua", "x"}, - {"ei", "w"}, - {"e", "e"}, - {"ou", "z"}, - {"iu", "q"}, - {"ve", "t"}, - {"ue", "t"}, - {"u", "u"}, - {"i", "i"}, - {"o", "o"}, - {"uo", "o"}, - {"ie", "p"}, - {"a", "a"}, - {"ong", "s"}, - {"iong", "s"}, - {"ai", "d"}, - {"ing", "k"}, - {"uai", "k"}, - {"ang", "h"}, - {"uan", "r"}, - {"an", "j"}, - {"en", "f"}, - {"ia", "x"}, - {"iang", "l"}, - {"uang", "l"}, - {"eng", "g"}, - {"in", "b"}, - {"ao", "c"}, - {"v", "v"}, - {"ui", "v"}, - {"un", "y"}, - {"iao", "n"}, - {"ian", "m"} - }); - - private static string ToDoublePin(string fullPinyin) - { - // Assuming s is valid - var fullPinyinSpan = fullPinyin.AsSpan(); - var doublePin = new StringBuilder(); - - // Handle special cases (a, o, e) - if (fullPinyin.Length <= 3 && (fullPinyinSpan[0] == 'a' || fullPinyinSpan[0] == 'e' || fullPinyinSpan[0] == 'o')) + if (currentDoublePinyinTable.TryGetValue(fullPinyin, out var doublePinyinValue)) { - if (special.TryGetValue(fullPinyin, out var value)) - { - return value; - } + return doublePinyinValue; } - - // Check for initials that are two characters long (zh, ch, sh) - if (fullPinyin.Length >= 2) - { - var firstTwoString = fullPinyinSpan[..2].ToString(); - if (first.TryGetValue(firstTwoString, out var firstTwoDoublePin)) - { - doublePin.Append(firstTwoDoublePin); - - var lastTwo = fullPinyinSpan[2..]; - var lastTwoString = lastTwo.ToString(); - if (second.TryGetValue(lastTwoString, out var tmp)) - { - doublePin.Append(tmp); - } - else - { - doublePin.Append(lastTwo); // Todo: original pinyin, remove this line if not needed - } - } - else - { - // Handle single-character initials - doublePin.Append(fullPinyinSpan[0]); - - var lastOne = fullPinyinSpan[1..]; - var lastOneString = lastOne.ToString(); - if (second.TryGetValue(lastOneString, out var tmp)) - { - doublePin.Append(tmp); - } - else - { - doublePin.Append(lastOne); - } - } - } - return doublePin.ToString(); + return fullPinyin; } #endregion diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index b10f9502e..e7306e3dd 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -292,6 +292,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings public bool UseDoublePinyin { get; set; } = true; //For developing + public string DoublePinyinSchema { get; set; } = "XiaoHe"; //For developing + public bool AlwaysPreview { get; set; } = false; public bool AlwaysStartEn { get; set; } = false; diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index d75d15a21..37e1f6bcf 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -127,6 +127,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Flow.Launcher/Resources/double_pinyin.json b/Flow.Launcher/Resources/double_pinyin.json new file mode 100644 index 000000000..6b8ae06c0 --- /dev/null +++ b/Flow.Launcher/Resources/double_pinyin.json @@ -0,0 +1,3746 @@ +{ + "XiaoHe": { + "Lv": "lv", + "Lve": "lt", + "Lue": "lt", + "Nv": "nv", + "Nve": "nt", + "Nue": "nt", + "A": "aa", + "O": "oo", + "E": "ee", + "Ai": "ai", + "Ei": "ei", + "Ao": "ao", + "Ou": "ou", + "An": "an", + "En": "en", + "Ang": "ah", + "Eng": "eg", + "Er": "er", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "yc", + "You": "yz", + "Yan": "yj", + "Yin": "yb", + "Yang": "yh", + "Ying": "yk", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wd", + "Wei": "ww", + "Wan": "wj", + "Wen": "wf", + "Wang": "wh", + "Weng": "wg", + "Yu": "yu", + "Yue": "yt", + "Yuan": "yr", + "Yun": "yy", + "Yong": "ys", + "Ba": "ba", + "Bai": "bd", + "Ban": "bj", + "Bang": "bh", + "Bao": "bc", + "Bei": "bw", + "Ben": "bf", + "Beng": "bg", + "Bi": "bi", + "Bian": "bm", + "Biang": "bl", + "Biao": "bn", + "Bie": "bp", + "Bin": "bb", + "Bing": "bk", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cd", + "Can": "cj", + "Cang": "ch", + "Cao": "cc", + "Ce": "ce", + "Cen": "cf", + "Ceng": "cg", + "Cha": "ia", + "Chai": "id", + "Chan": "ij", + "Chang": "ih", + "Chao": "ic", + "Che": "ie", + "Chen": "if", + "Cheng": "ig", + "Chi": "ii", + "Chong": "is", + "Chou": "iz", + "Chu": "iu", + "Chua": "ix", + "Chuai": "ik", + "Chuan": "ir", + "Chuang": "il", + "Chui": "iv", + "Chun": "iy", + "Chuo": "io", + "Ci": "ci", + "Cong": "cs", + "Cou": "cz", + "Cu": "cu", + "Cuan": "cr", + "Cui": "cv", + "Cun": "cy", + "Cuo": "co", + "Da": "da", + "Dai": "dd", + "Dan": "dj", + "Dang": "dh", + "Dao": "dc", + "De": "de", + "Dei": "dw", + "Den": "df", + "Deng": "dg", + "Di": "di", + "Dia": "dx", + "Dian": "dm", + "Diao": "dn", + "Die": "dp", + "Ding": "dk", + "Diu": "dq", + "Dong": "ds", + "Dou": "dz", + "Du": "du", + "Duan": "dr", + "Dui": "dv", + "Dun": "dy", + "Duo": "do", + "Fa": "fa", + "Fan": "fj", + "Fang": "fh", + "Fei": "fw", + "Fen": "ff", + "Feng": "fg", + "Fiao": "fn", + "Fo": "fo", + "Fou": "fz", + "Fu": "fu", + "Ga": "ga", + "Gai": "gd", + "Gan": "gj", + "Gang": "gh", + "Gao": "gc", + "Ge": "ge", + "Gei": "gw", + "Gen": "gf", + "Geng": "gg", + "Gong": "gs", + "Gou": "gz", + "Gu": "gu", + "Gua": "gx", + "Guai": "gk", + "Guan": "gr", + "Guang": "gl", + "Gui": "gv", + "Gun": "gy", + "Guo": "go", + "Ha": "ha", + "Hai": "hd", + "Han": "hj", + "Hang": "hh", + "Hao": "hc", + "He": "he", + "Hei": "hw", + "Hen": "hf", + "Heng": "hg", + "Hong": "hs", + "Hou": "hz", + "Hu": "hu", + "Hua": "hx", + "Huai": "hk", + "Huan": "hr", + "Huang": "hl", + "Hui": "hv", + "Hun": "hy", + "Huo": "ho", + "Ji": "ji", + "Jia": "jx", + "Jian": "jm", + "Jiang": "jl", + "Jiao": "jn", + "Jie": "jp", + "Jin": "jb", + "Jing": "jk", + "Jiong": "js", + "Jiu": "jq", + "Ju": "ju", + "Juan": "jr", + "Jue": "jt", + "Jun": "jy", + "Ka": "ka", + "Kai": "kd", + "Kan": "kj", + "Kang": "kh", + "Kao": "kc", + "Ke": "ke", + "Ken": "kf", + "Keng": "kg", + "Kong": "ks", + "Kou": "kz", + "Ku": "ku", + "Kua": "kx", + "Kuai": "kk", + "Kuan": "kr", + "Kuang": "kl", + "Kui": "kv", + "Kun": "ky", + "Kuo": "ko", + "La": "la", + "Lai": "ld", + "Lan": "lj", + "Lang": "lh", + "Lao": "lc", + "Le": "le", + "Lei": "lw", + "Leng": "lg", + "Li": "li", + "Lia": "lx", + "Lian": "lm", + "Liang": "ll", + "Liao": "ln", + "Lie": "lp", + "Lin": "lb", + "Ling": "lk", + "Liu": "lq", + "Lo": "lo", + "Long": "ls", + "Lou": "lz", + "Lu": "lu", + "Luan": "lr", + "Lun": "ly", + "Luo": "lo", + "Ma": "ma", + "Mai": "md", + "Man": "mj", + "Mang": "mh", + "Mao": "mc", + "Me": "me", + "Mei": "mw", + "Men": "mf", + "Meng": "mg", + "Mi": "mi", + "Mian": "mm", + "Miao": "mn", + "Mie": "mp", + "Min": "mb", + "Ming": "mk", + "Miu": "mq", + "Mo": "mo", + "Mou": "mz", + "Mu": "mu", + "Na": "na", + "Nai": "nd", + "Nan": "nj", + "Nang": "nh", + "Nao": "nc", + "Ne": "ne", + "Nei": "nw", + "Nen": "nf", + "Neng": "ng", + "Ni": "ni", + "Nian": "nm", + "Niang": "nl", + "Niao": "nn", + "Nie": "np", + "Nin": "nb", + "Ning": "nk", + "Niu": "nq", + "Nong": "ns", + "Nou": "nz", + "Nu": "nu", + "Nuan": "nr", + "Nun": "ny", + "Nuo": "no", + "Pa": "pa", + "Pai": "pd", + "Pan": "pj", + "Pang": "ph", + "Pao": "pc", + "Pei": "pw", + "Pen": "pf", + "Peng": "pg", + "Pi": "pi", + "Pian": "pm", + "Piao": "pn", + "Pie": "pp", + "Pin": "pb", + "Ping": "pk", + "Po": "po", + "Pou": "pz", + "Pu": "pu", + "Qi": "qi", + "Qia": "qx", + "Qian": "qm", + "Qiang": "ql", + "Qiao": "qn", + "Qie": "qp", + "Qin": "qb", + "Qing": "qk", + "Qiong": "qs", + "Qiu": "qq", + "Qu": "qu", + "Quan": "qr", + "Que": "qt", + "Qun": "qy", + "Ran": "rj", + "Rang": "rh", + "Rao": "rc", + "Re": "re", + "Ren": "rf", + "Reng": "rg", + "Ri": "ri", + "Rong": "rs", + "Rou": "rz", + "Ru": "ru", + "Rua": "rx", + "Ruan": "rr", + "Rui": "rv", + "Run": "ry", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sd", + "San": "sj", + "Sang": "sh", + "Sao": "sc", + "Se": "se", + "Sen": "sf", + "Seng": "sg", + "Sha": "ua", + "Shai": "ud", + "Shan": "uj", + "Shang": "uh", + "Shao": "uc", + "She": "ue", + "Shei": "uw", + "Shen": "uf", + "Sheng": "ug", + "Shi": "ui", + "Shou": "uz", + "Shu": "uu", + "Shua": "ux", + "Shuai": "uk", + "Shuan": "ur", + "Shuang": "ul", + "Shui": "uv", + "Shun": "uy", + "Shuo": "uo", + "Si": "si", + "Song": "ss", + "Sou": "sz", + "Su": "su", + "Suan": "sr", + "Sui": "sv", + "Sun": "sy", + "Suo": "so", + "Ta": "ta", + "Tai": "td", + "Tan": "tj", + "Tang": "th", + "Tao": "tc", + "Te": "te", + "Tei": "tw", + "Teng": "tg", + "Ti": "ti", + "Tian": "tm", + "Tiao": "tn", + "Tie": "tp", + "Ting": "tk", + "Tong": "ts", + "Tou": "tz", + "Tu": "tu", + "Tuan": "tr", + "Tui": "tv", + "Tun": "ty", + "Tuo": "to", + "Xi": "xi", + "Xia": "xx", + "Xian": "xm", + "Xiang": "xl", + "Xiao": "xn", + "Xie": "xp", + "Xin": "xb", + "Xing": "xk", + "Xiong": "xs", + "Xiu": "xq", + "Xu": "xu", + "Xuan": "xr", + "Xue": "xt", + "Xun": "xy", + "Za": "za", + "Zai": "zd", + "Zan": "zj", + "Zang": "zh", + "Zao": "zc", + "Ze": "ze", + "Zei": "zw", + "Zen": "zf", + "Zeng": "zg", + "Zha": "va", + "Zhai": "vd", + "Zhan": "vj", + "Zhang": "vh", + "Zhao": "vc", + "Zhe": "ve", + "Zhen": "vf", + "Zheng": "vg", + "Zhi": "vi", + "Zhong": "vs", + "Zhou": "vz", + "Zhu": "vu", + "Zhua": "vx", + "Zhuai": "vk", + "Zhuan": "vr", + "Zhuang": "vl", + "Zhui": "vv", + "Zhun": "vy", + "Zhuo": "vo", + "Zi": "zi", + "Zong": "zs", + "Zou": "zz", + "Zu": "zu", + "Zuan": "zr", + "Zui": "zv", + "Zun": "zy", + "Zuo": "zo" + }, + "ZiRanMa": { + "Lv": "lv", + "Lve": "lt", + "Lue": "lt", + "Nv": "nv", + "Nve": "nt", + "Nue": "nt", + "A": "aa", + "O": "oo", + "E": "ee", + "Ai": "ai", + "Ei": "ei", + "Ao": "ao", + "Ou": "ou", + "An": "an", + "En": "en", + "Ang": "ah", + "Eng": "eg", + "Er": "er", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "yk", + "You": "yb", + "Yan": "yj", + "Yin": "yn", + "Yang": "yh", + "Ying": "yy", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wl", + "Wei": "wz", + "Wan": "wj", + "Wen": "wf", + "Wang": "wh", + "Weng": "wg", + "Yu": "yu", + "Yue": "yt", + "Yuan": "yr", + "Yun": "yp", + "Yong": "ys", + "Ba": "ba", + "Bai": "bl", + "Ban": "bj", + "Bang": "bh", + "Bao": "bk", + "Bei": "bz", + "Ben": "bf", + "Beng": "bg", + "Bi": "bi", + "Bian": "bm", + "Biang": "bd", + "Biao": "bc", + "Bie": "bx", + "Bin": "bn", + "Bing": "by", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cl", + "Can": "cj", + "Cang": "ch", + "Cao": "ck", + "Ce": "ce", + "Cen": "cf", + "Ceng": "cg", + "Cha": "ia", + "Chai": "il", + "Chan": "ij", + "Chang": "ih", + "Chao": "ik", + "Che": "ie", + "Chen": "if", + "Cheng": "ig", + "Chi": "ii", + "Chong": "is", + "Chou": "ib", + "Chu": "iu", + "Chua": "iw", + "Chuai": "iy", + "Chuan": "ir", + "Chuang": "id", + "Chui": "iv", + "Chun": "ip", + "Chuo": "io", + "Ci": "ci", + "Cong": "cs", + "Cou": "cb", + "Cu": "cu", + "Cuan": "cr", + "Cui": "cv", + "Cun": "cp", + "Cuo": "co", + "Da": "da", + "Dai": "dl", + "Dan": "dj", + "Dang": "dh", + "Dao": "dk", + "De": "de", + "Dei": "dz", + "Den": "df", + "Deng": "dg", + "Di": "di", + "Dia": "dw", + "Dian": "dm", + "Diao": "dc", + "Die": "dx", + "Ding": "dy", + "Diu": "dq", + "Dong": "ds", + "Dou": "db", + "Du": "du", + "Duan": "dr", + "Dui": "dv", + "Dun": "dp", + "Duo": "do", + "Fa": "fa", + "Fan": "fj", + "Fang": "fh", + "Fei": "fz", + "Fen": "ff", + "Feng": "fg", + "Fiao": "fc", + "Fo": "fo", + "Fou": "fb", + "Fu": "fu", + "Ga": "ga", + "Gai": "gl", + "Gan": "gj", + "Gang": "gh", + "Gao": "gk", + "Ge": "ge", + "Gei": "gz", + "Gen": "gf", + "Geng": "gg", + "Gong": "gs", + "Gou": "gb", + "Gu": "gu", + "Gua": "gw", + "Guai": "gy", + "Guan": "gr", + "Guang": "gd", + "Gui": "gv", + "Gun": "gp", + "Guo": "go", + "Ha": "ha", + "Hai": "hl", + "Han": "hj", + "Hang": "hh", + "Hao": "hk", + "He": "he", + "Hei": "hz", + "Hen": "hf", + "Heng": "hg", + "Hong": "hs", + "Hou": "hb", + "Hu": "hu", + "Hua": "hw", + "Huai": "hy", + "Huan": "hr", + "Huang": "hd", + "Hui": "hv", + "Hun": "hp", + "Huo": "ho", + "Ji": "ji", + "Jia": "jw", + "Jian": "jm", + "Jiang": "jd", + "Jiao": "jc", + "Jie": "jx", + "Jin": "jn", + "Jing": "jy", + "Jiong": "js", + "Jiu": "jq", + "Ju": "ju", + "Juan": "jr", + "Jue": "jt", + "Jun": "jp", + "Ka": "ka", + "Kai": "kl", + "Kan": "kj", + "Kang": "kh", + "Kao": "kk", + "Ke": "ke", + "Ken": "kf", + "Keng": "kg", + "Kong": "ks", + "Kou": "kb", + "Ku": "ku", + "Kua": "kw", + "Kuai": "ky", + "Kuan": "kr", + "Kuang": "kd", + "Kui": "kv", + "Kun": "kp", + "Kuo": "ko", + "La": "la", + "Lai": "ll", + "Lan": "lj", + "Lang": "lh", + "Lao": "lk", + "Le": "le", + "Lei": "lz", + "Leng": "lg", + "Li": "li", + "Lia": "lw", + "Lian": "lm", + "Liang": "ld", + "Liao": "lc", + "Lie": "lx", + "Lin": "ln", + "Ling": "ly", + "Liu": "lq", + "Lo": "lo", + "Long": "ls", + "Lou": "lb", + "Lu": "lu", + "Luan": "lr", + "Lun": "lp", + "Luo": "lo", + "Ma": "ma", + "Mai": "ml", + "Man": "mj", + "Mang": "mh", + "Mao": "mk", + "Me": "me", + "Mei": "mz", + "Men": "mf", + "Meng": "mg", + "Mi": "mi", + "Mian": "mm", + "Miao": "mc", + "Mie": "mx", + "Min": "mn", + "Ming": "my", + "Miu": "mq", + "Mo": "mo", + "Mou": "mb", + "Mu": "mu", + "Na": "na", + "Nai": "nl", + "Nan": "nj", + "Nang": "nh", + "Nao": "nk", + "Ne": "ne", + "Nei": "nz", + "Nen": "nf", + "Neng": "ng", + "Ni": "ni", + "Nian": "nm", + "Niang": "nd", + "Niao": "nc", + "Nie": "nx", + "Nin": "nn", + "Ning": "ny", + "Niu": "nq", + "Nong": "ns", + "Nou": "nb", + "Nu": "nu", + "Nuan": "nr", + "Nun": "np", + "Nuo": "no", + "Pa": "pa", + "Pai": "pl", + "Pan": "pj", + "Pang": "ph", + "Pao": "pk", + "Pei": "pz", + "Pen": "pf", + "Peng": "pg", + "Pi": "pi", + "Pian": "pm", + "Piao": "pc", + "Pie": "px", + "Pin": "pn", + "Ping": "py", + "Po": "po", + "Pou": "pb", + "Pu": "pu", + "Qi": "qi", + "Qia": "qw", + "Qian": "qm", + "Qiang": "qd", + "Qiao": "qc", + "Qie": "qx", + "Qin": "qn", + "Qing": "qy", + "Qiong": "qs", + "Qiu": "qq", + "Qu": "qu", + "Quan": "qr", + "Que": "qt", + "Qun": "qp", + "Ran": "rj", + "Rang": "rh", + "Rao": "rk", + "Re": "re", + "Ren": "rf", + "Reng": "rg", + "Ri": "ri", + "Rong": "rs", + "Rou": "rb", + "Ru": "ru", + "Rua": "rw", + "Ruan": "rr", + "Rui": "rv", + "Run": "rp", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sl", + "San": "sj", + "Sang": "sh", + "Sao": "sk", + "Se": "se", + "Sen": "sf", + "Seng": "sg", + "Sha": "ua", + "Shai": "ul", + "Shan": "uj", + "Shang": "uh", + "Shao": "uk", + "She": "ue", + "Shei": "uz", + "Shen": "uf", + "Sheng": "ug", + "Shi": "ui", + "Shou": "ub", + "Shu": "uu", + "Shua": "uw", + "Shuai": "uy", + "Shuan": "ur", + "Shuang": "ud", + "Shui": "uv", + "Shun": "up", + "Shuo": "uo", + "Si": "si", + "Song": "ss", + "Sou": "sb", + "Su": "su", + "Suan": "sr", + "Sui": "sv", + "Sun": "sp", + "Suo": "so", + "Ta": "ta", + "Tai": "tl", + "Tan": "tj", + "Tang": "th", + "Tao": "tk", + "Te": "te", + "Tei": "tz", + "Teng": "tg", + "Ti": "ti", + "Tian": "tm", + "Tiao": "tc", + "Tie": "tx", + "Ting": "ty", + "Tong": "ts", + "Tou": "tb", + "Tu": "tu", + "Tuan": "tr", + "Tui": "tv", + "Tun": "tp", + "Tuo": "to", + "Xi": "xi", + "Xia": "xw", + "Xian": "xm", + "Xiang": "xd", + "Xiao": "xc", + "Xie": "xx", + "Xin": "xn", + "Xing": "xy", + "Xiong": "xs", + "Xiu": "xq", + "Xu": "xu", + "Xuan": "xr", + "Xue": "xt", + "Xun": "xp", + "Za": "za", + "Zai": "zl", + "Zan": "zj", + "Zang": "zh", + "Zao": "zk", + "Ze": "ze", + "Zei": "zz", + "Zen": "zf", + "Zeng": "zg", + "Zha": "va", + "Zhai": "vl", + "Zhan": "vj", + "Zhang": "vh", + "Zhao": "vk", + "Zhe": "ve", + "Zhen": "vf", + "Zheng": "vg", + "Zhi": "vi", + "Zhong": "vs", + "Zhou": "vb", + "Zhu": "vu", + "Zhua": "vw", + "Zhuai": "vy", + "Zhuan": "vr", + "Zhuang": "vd", + "Zhui": "vv", + "Zhun": "vp", + "Zhuo": "vo", + "Zi": "zi", + "Zong": "zs", + "Zou": "zb", + "Zu": "zu", + "Zuan": "zr", + "Zui": "zv", + "Zun": "zp", + "Zuo": "zo" + }, + "WeiRuan": { + "Lv": "ly", + "Lve": "lt", + "Lue": "lt", + "Nv": "ny", + "Nve": "nt", + "Nue": "nt", + "A": "oa", + "O": "oo", + "E": "oe", + "Ai": "ol", + "Ei": "oz", + "Ao": "ok", + "Ou": "ob", + "An": "oj", + "En": "of", + "Ang": "oh", + "Eng": "og", + "Er": "or", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "yk", + "You": "yb", + "Yan": "yj", + "Yin": "yn", + "Yang": "yh", + "Ying": "y;", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wl", + "Wei": "wz", + "Wan": "wj", + "Wen": "wf", + "Wang": "wh", + "Weng": "wg", + "Yu": "yu", + "Yue": "yt", + "Yuan": "yr", + "Yun": "yp", + "Yong": "ys", + "Ba": "ba", + "Bai": "bl", + "Ban": "bj", + "Bang": "bh", + "Bao": "bk", + "Bei": "bz", + "Ben": "bf", + "Beng": "bg", + "Bi": "bi", + "Bian": "bm", + "Biang": "bd", + "Biao": "bc", + "Bie": "bx", + "Bin": "bn", + "Bing": "b;", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cl", + "Can": "cj", + "Cang": "ch", + "Cao": "ck", + "Ce": "ce", + "Cen": "cf", + "Ceng": "cg", + "Cha": "ia", + "Chai": "il", + "Chan": "ij", + "Chang": "ih", + "Chao": "ik", + "Che": "ie", + "Chen": "if", + "Cheng": "ig", + "Chi": "ii", + "Chong": "is", + "Chou": "ib", + "Chu": "iu", + "Chua": "iw", + "Chuai": "iy", + "Chuan": "ir", + "Chuang": "id", + "Chui": "iv", + "Chun": "ip", + "Chuo": "io", + "Ci": "ci", + "Cong": "cs", + "Cou": "cb", + "Cu": "cu", + "Cuan": "cr", + "Cui": "cv", + "Cun": "cp", + "Cuo": "co", + "Da": "da", + "Dai": "dl", + "Dan": "dj", + "Dang": "dh", + "Dao": "dk", + "De": "de", + "Dei": "dz", + "Den": "df", + "Deng": "dg", + "Di": "di", + "Dia": "dw", + "Dian": "dm", + "Diao": "dc", + "Die": "dx", + "Ding": "d;", + "Diu": "dq", + "Dong": "ds", + "Dou": "db", + "Du": "du", + "Duan": "dr", + "Dui": "dv", + "Dun": "dp", + "Duo": "do", + "Fa": "fa", + "Fan": "fj", + "Fang": "fh", + "Fei": "fz", + "Fen": "ff", + "Feng": "fg", + "Fiao": "fc", + "Fo": "fo", + "Fou": "fb", + "Fu": "fu", + "Ga": "ga", + "Gai": "gl", + "Gan": "gj", + "Gang": "gh", + "Gao": "gk", + "Ge": "ge", + "Gei": "gz", + "Gen": "gf", + "Geng": "gg", + "Gong": "gs", + "Gou": "gb", + "Gu": "gu", + "Gua": "gw", + "Guai": "gy", + "Guan": "gr", + "Guang": "gd", + "Gui": "gv", + "Gun": "gp", + "Guo": "go", + "Ha": "ha", + "Hai": "hl", + "Han": "hj", + "Hang": "hh", + "Hao": "hk", + "He": "he", + "Hei": "hz", + "Hen": "hf", + "Heng": "hg", + "Hong": "hs", + "Hou": "hb", + "Hu": "hu", + "Hua": "hw", + "Huai": "hy", + "Huan": "hr", + "Huang": "hd", + "Hui": "hv", + "Hun": "hp", + "Huo": "ho", + "Ji": "ji", + "Jia": "jw", + "Jian": "jm", + "Jiang": "jd", + "Jiao": "jc", + "Jie": "jx", + "Jin": "jn", + "Jing": "j;", + "Jiong": "js", + "Jiu": "jq", + "Ju": "ju", + "Juan": "jr", + "Jue": "jt", + "Jun": "jp", + "Ka": "ka", + "Kai": "kl", + "Kan": "kj", + "Kang": "kh", + "Kao": "kk", + "Ke": "ke", + "Ken": "kf", + "Keng": "kg", + "Kong": "ks", + "Kou": "kb", + "Ku": "ku", + "Kua": "kw", + "Kuai": "ky", + "Kuan": "kr", + "Kuang": "kd", + "Kui": "kv", + "Kun": "kp", + "Kuo": "ko", + "La": "la", + "Lai": "ll", + "Lan": "lj", + "Lang": "lh", + "Lao": "lk", + "Le": "le", + "Lei": "lz", + "Leng": "lg", + "Li": "li", + "Lia": "lw", + "Lian": "lm", + "Liang": "ld", + "Liao": "lc", + "Lie": "lx", + "Lin": "ln", + "Ling": "l;", + "Liu": "lq", + "Lo": "lo", + "Long": "ls", + "Lou": "lb", + "Lu": "lu", + "Luan": "lr", + "Lun": "lp", + "Luo": "lo", + "Ma": "ma", + "Mai": "ml", + "Man": "mj", + "Mang": "mh", + "Mao": "mk", + "Me": "me", + "Mei": "mz", + "Men": "mf", + "Meng": "mg", + "Mi": "mi", + "Mian": "mm", + "Miao": "mc", + "Mie": "mx", + "Min": "mn", + "Ming": "m;", + "Miu": "mq", + "Mo": "mo", + "Mou": "mb", + "Mu": "mu", + "Na": "na", + "Nai": "nl", + "Nan": "nj", + "Nang": "nh", + "Nao": "nk", + "Ne": "ne", + "Nei": "nz", + "Nen": "nf", + "Neng": "ng", + "Ni": "ni", + "Nian": "nm", + "Niang": "nd", + "Niao": "nc", + "Nie": "nx", + "Nin": "nn", + "Ning": "n;", + "Niu": "nq", + "Nong": "ns", + "Nou": "nb", + "Nu": "nu", + "Nuan": "nr", + "Nun": "np", + "Nuo": "no", + "Pa": "pa", + "Pai": "pl", + "Pan": "pj", + "Pang": "ph", + "Pao": "pk", + "Pei": "pz", + "Pen": "pf", + "Peng": "pg", + "Pi": "pi", + "Pian": "pm", + "Piao": "pc", + "Pie": "px", + "Pin": "pn", + "Ping": "p;", + "Po": "po", + "Pou": "pb", + "Pu": "pu", + "Qi": "qi", + "Qia": "qw", + "Qian": "qm", + "Qiang": "qd", + "Qiao": "qc", + "Qie": "qx", + "Qin": "qn", + "Qing": "q;", + "Qiong": "qs", + "Qiu": "qq", + "Qu": "qu", + "Quan": "qr", + "Que": "qt", + "Qun": "qp", + "Ran": "rj", + "Rang": "rh", + "Rao": "rk", + "Re": "re", + "Ren": "rf", + "Reng": "rg", + "Ri": "ri", + "Rong": "rs", + "Rou": "rb", + "Ru": "ru", + "Rua": "rw", + "Ruan": "rr", + "Rui": "rv", + "Run": "rp", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sl", + "San": "sj", + "Sang": "sh", + "Sao": "sk", + "Se": "se", + "Sen": "sf", + "Seng": "sg", + "Sha": "ua", + "Shai": "ul", + "Shan": "uj", + "Shang": "uh", + "Shao": "uk", + "She": "ue", + "Shei": "uz", + "Shen": "uf", + "Sheng": "ug", + "Shi": "ui", + "Shou": "ub", + "Shu": "uu", + "Shua": "uw", + "Shuai": "uy", + "Shuan": "ur", + "Shuang": "ud", + "Shui": "uv", + "Shun": "up", + "Shuo": "uo", + "Si": "si", + "Song": "ss", + "Sou": "sb", + "Su": "su", + "Suan": "sr", + "Sui": "sv", + "Sun": "sp", + "Suo": "so", + "Ta": "ta", + "Tai": "tl", + "Tan": "tj", + "Tang": "th", + "Tao": "tk", + "Te": "te", + "Tei": "tz", + "Teng": "tg", + "Ti": "ti", + "Tian": "tm", + "Tiao": "tc", + "Tie": "tx", + "Ting": "t;", + "Tong": "ts", + "Tou": "tb", + "Tu": "tu", + "Tuan": "tr", + "Tui": "tv", + "Tun": "tp", + "Tuo": "to", + "Xi": "xi", + "Xia": "xw", + "Xian": "xm", + "Xiang": "xd", + "Xiao": "xc", + "Xie": "xx", + "Xin": "xn", + "Xing": "x;", + "Xiong": "xs", + "Xiu": "xq", + "Xu": "xu", + "Xuan": "xr", + "Xue": "xt", + "Xun": "xp", + "Za": "za", + "Zai": "zl", + "Zan": "zj", + "Zang": "zh", + "Zao": "zk", + "Ze": "ze", + "Zei": "zz", + "Zen": "zf", + "Zeng": "zg", + "Zha": "va", + "Zhai": "vl", + "Zhan": "vj", + "Zhang": "vh", + "Zhao": "vk", + "Zhe": "ve", + "Zhen": "vf", + "Zheng": "vg", + "Zhi": "vi", + "Zhong": "vs", + "Zhou": "vb", + "Zhu": "vu", + "Zhua": "vw", + "Zhuai": "vy", + "Zhuan": "vr", + "Zhuang": "vd", + "Zhui": "vv", + "Zhun": "vp", + "Zhuo": "vo", + "Zi": "zi", + "Zong": "zs", + "Zou": "zb", + "Zu": "zu", + "Zuan": "zr", + "Zui": "zv", + "Zun": "zp", + "Zuo": "zo" + }, + "ZhiNengABC": { + "Lv": "lv", + "Lve": "lm", + "Lue": "lm", + "Nv": "nv", + "Nve": "nm", + "Nue": "nm", + "A": "oa", + "O": "oo", + "E": "oe", + "Ai": "ol", + "Ei": "oq", + "Ao": "ok", + "Ou": "ob", + "An": "oj", + "En": "of", + "Ang": "oh", + "Eng": "og", + "Er": "or", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "yk", + "You": "yb", + "Yan": "yj", + "Yin": "yc", + "Yang": "yh", + "Ying": "yy", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wl", + "Wei": "wq", + "Wan": "wj", + "Wen": "wf", + "Wang": "wh", + "Weng": "wg", + "Yu": "yu", + "Yue": "ym", + "Yuan": "yp", + "Yun": "yn", + "Yong": "ys", + "Ba": "ba", + "Bai": "bl", + "Ban": "bj", + "Bang": "bh", + "Bao": "bk", + "Bei": "bq", + "Ben": "bf", + "Beng": "bg", + "Bi": "bi", + "Bian": "bw", + "Biang": "bt", + "Biao": "bz", + "Bie": "bx", + "Bin": "bc", + "Bing": "by", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cl", + "Can": "cj", + "Cang": "ch", + "Cao": "ck", + "Ce": "ce", + "Cen": "cf", + "Ceng": "cg", + "Cha": "ea", + "Chai": "el", + "Chan": "ej", + "Chang": "eh", + "Chao": "ek", + "Che": "ee", + "Chen": "ef", + "Cheng": "eg", + "Chi": "ei", + "Chong": "es", + "Chou": "eb", + "Chu": "eu", + "Chua": "ed", + "Chuai": "ec", + "Chuan": "ep", + "Chuang": "et", + "Chui": "em", + "Chun": "en", + "Chuo": "eo", + "Ci": "ci", + "Cong": "cs", + "Cou": "cb", + "Cu": "cu", + "Cuan": "cp", + "Cui": "cm", + "Cun": "cn", + "Cuo": "co", + "Da": "da", + "Dai": "dl", + "Dan": "dj", + "Dang": "dh", + "Dao": "dk", + "De": "de", + "Dei": "dq", + "Den": "df", + "Deng": "dg", + "Di": "di", + "Dia": "dd", + "Dian": "dw", + "Diao": "dz", + "Die": "dx", + "Ding": "dy", + "Diu": "dr", + "Dong": "ds", + "Dou": "db", + "Du": "du", + "Duan": "dp", + "Dui": "dm", + "Dun": "dn", + "Duo": "do", + "Fa": "fa", + "Fan": "fj", + "Fang": "fh", + "Fei": "fq", + "Fen": "ff", + "Feng": "fg", + "Fiao": "fz", + "Fo": "fo", + "Fou": "fb", + "Fu": "fu", + "Ga": "ga", + "Gai": "gl", + "Gan": "gj", + "Gang": "gh", + "Gao": "gk", + "Ge": "ge", + "Gei": "gq", + "Gen": "gf", + "Geng": "gg", + "Gong": "gs", + "Gou": "gb", + "Gu": "gu", + "Gua": "gd", + "Guai": "gc", + "Guan": "gp", + "Guang": "gt", + "Gui": "gm", + "Gun": "gn", + "Guo": "go", + "Ha": "ha", + "Hai": "hl", + "Han": "hj", + "Hang": "hh", + "Hao": "hk", + "He": "he", + "Hei": "hq", + "Hen": "hf", + "Heng": "hg", + "Hong": "hs", + "Hou": "hb", + "Hu": "hu", + "Hua": "hd", + "Huai": "hc", + "Huan": "hp", + "Huang": "ht", + "Hui": "hm", + "Hun": "hn", + "Huo": "ho", + "Ji": "ji", + "Jia": "jd", + "Jian": "jw", + "Jiang": "jt", + "Jiao": "jz", + "Jie": "jx", + "Jin": "jc", + "Jing": "jy", + "Jiong": "js", + "Jiu": "jr", + "Ju": "ju", + "Juan": "jp", + "Jue": "jm", + "Jun": "jn", + "Ka": "ka", + "Kai": "kl", + "Kan": "kj", + "Kang": "kh", + "Kao": "kk", + "Ke": "ke", + "Ken": "kf", + "Keng": "kg", + "Kong": "ks", + "Kou": "kb", + "Ku": "ku", + "Kua": "kd", + "Kuai": "kc", + "Kuan": "kp", + "Kuang": "kt", + "Kui": "km", + "Kun": "kn", + "Kuo": "ko", + "La": "la", + "Lai": "ll", + "Lan": "lj", + "Lang": "lh", + "Lao": "lk", + "Le": "le", + "Lei": "lq", + "Leng": "lg", + "Li": "li", + "Lia": "ld", + "Lian": "lw", + "Liang": "lt", + "Liao": "lz", + "Lie": "lx", + "Lin": "lc", + "Ling": "ly", + "Liu": "lr", + "Lo": "lo", + "Long": "ls", + "Lou": "lb", + "Lu": "lu", + "Luan": "lp", + "Lun": "ln", + "Luo": "lo", + "Ma": "ma", + "Mai": "ml", + "Man": "mj", + "Mang": "mh", + "Mao": "mk", + "Me": "me", + "Mei": "mq", + "Men": "mf", + "Meng": "mg", + "Mi": "mi", + "Mian": "mw", + "Miao": "mz", + "Mie": "mx", + "Min": "mc", + "Ming": "my", + "Miu": "mr", + "Mo": "mo", + "Mou": "mb", + "Mu": "mu", + "Na": "na", + "Nai": "nl", + "Nan": "nj", + "Nang": "nh", + "Nao": "nk", + "Ne": "ne", + "Nei": "nq", + "Nen": "nf", + "Neng": "ng", + "Ni": "ni", + "Nian": "nw", + "Niang": "nt", + "Niao": "nz", + "Nie": "nx", + "Nin": "nc", + "Ning": "ny", + "Niu": "nr", + "Nong": "ns", + "Nou": "nb", + "Nu": "nu", + "Nuan": "np", + "Nun": "nn", + "Nuo": "no", + "Pa": "pa", + "Pai": "pl", + "Pan": "pj", + "Pang": "ph", + "Pao": "pk", + "Pei": "pq", + "Pen": "pf", + "Peng": "pg", + "Pi": "pi", + "Pian": "pw", + "Piao": "pz", + "Pie": "px", + "Pin": "pc", + "Ping": "py", + "Po": "po", + "Pou": "pb", + "Pu": "pu", + "Qi": "qi", + "Qia": "qd", + "Qian": "qw", + "Qiang": "qt", + "Qiao": "qz", + "Qie": "qx", + "Qin": "qc", + "Qing": "qy", + "Qiong": "qs", + "Qiu": "qr", + "Qu": "qu", + "Quan": "qp", + "Que": "qm", + "Qun": "qn", + "Ran": "rj", + "Rang": "rh", + "Rao": "rk", + "Re": "re", + "Ren": "rf", + "Reng": "rg", + "Ri": "ri", + "Rong": "rs", + "Rou": "rb", + "Ru": "ru", + "Rua": "rd", + "Ruan": "rp", + "Rui": "rm", + "Run": "rn", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sl", + "San": "sj", + "Sang": "sh", + "Sao": "sk", + "Se": "se", + "Sen": "sf", + "Seng": "sg", + "Sha": "va", + "Shai": "vl", + "Shan": "vj", + "Shang": "vh", + "Shao": "vk", + "She": "ve", + "Shei": "vq", + "Shen": "vf", + "Sheng": "vg", + "Shi": "vi", + "Shou": "vb", + "Shu": "vu", + "Shua": "vd", + "Shuai": "vc", + "Shuan": "vp", + "Shuang": "vt", + "Shui": "vm", + "Shun": "vn", + "Shuo": "vo", + "Si": "si", + "Song": "ss", + "Sou": "sb", + "Su": "su", + "Suan": "sp", + "Sui": "sm", + "Sun": "sn", + "Suo": "so", + "Ta": "ta", + "Tai": "tl", + "Tan": "tj", + "Tang": "th", + "Tao": "tk", + "Te": "te", + "Tei": "tq", + "Teng": "tg", + "Ti": "ti", + "Tian": "tw", + "Tiao": "tz", + "Tie": "tx", + "Ting": "ty", + "Tong": "ts", + "Tou": "tb", + "Tu": "tu", + "Tuan": "tp", + "Tui": "tm", + "Tun": "tn", + "Tuo": "to", + "Xi": "xi", + "Xia": "xd", + "Xian": "xw", + "Xiang": "xt", + "Xiao": "xz", + "Xie": "xx", + "Xin": "xc", + "Xing": "xy", + "Xiong": "xs", + "Xiu": "xr", + "Xu": "xu", + "Xuan": "xp", + "Xue": "xm", + "Xun": "xn", + "Za": "za", + "Zai": "zl", + "Zan": "zj", + "Zang": "zh", + "Zao": "zk", + "Ze": "ze", + "Zei": "zq", + "Zen": "zf", + "Zeng": "zg", + "Zha": "aa", + "Zhai": "al", + "Zhan": "aj", + "Zhang": "ah", + "Zhao": "ak", + "Zhe": "ae", + "Zhen": "af", + "Zheng": "ag", + "Zhi": "ai", + "Zhong": "as", + "Zhou": "ab", + "Zhu": "au", + "Zhua": "ad", + "Zhuai": "ac", + "Zhuan": "ap", + "Zhuang": "at", + "Zhui": "am", + "Zhun": "an", + "Zhuo": "ao", + "Zi": "zi", + "Zong": "zs", + "Zou": "zb", + "Zu": "zu", + "Zuan": "zp", + "Zui": "zm", + "Zun": "zn", + "Zuo": "zo" + }, + "ZiGuangPinYin": { + "Lv": "lv", + "Lve": "ln", + "Lue": "ln", + "Nv": "nv", + "Nve": "nn", + "Nue": "nn", + "A": "oa", + "O": "oo", + "E": "oe", + "Ai": "op", + "Ei": "ok", + "Ao": "oq", + "Ou": "oz", + "An": "or", + "En": "ow", + "Ang": "os", + "Eng": "ot", + "Er": "oj", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "yq", + "You": "yz", + "Yan": "yr", + "Yin": "yy", + "Yang": "ys", + "Ying": "yc", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wp", + "Wei": "wk", + "Wan": "wr", + "Wen": "ww", + "Wang": "ws", + "Weng": "wt", + "Yu": "yu", + "Yue": "yn", + "Yuan": "yl", + "Yun": "ym", + "Yong": "yh", + "Ba": "ba", + "Bai": "bp", + "Ban": "br", + "Bang": "bs", + "Bao": "bq", + "Bei": "bk", + "Ben": "bw", + "Beng": "bt", + "Bi": "bi", + "Bian": "bf", + "Biang": "bg", + "Biao": "bb", + "Bie": "bd", + "Bin": "by", + "Bing": "bc", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cp", + "Can": "cr", + "Cang": "cs", + "Cao": "cq", + "Ce": "ce", + "Cen": "cw", + "Ceng": "ct", + "Cha": "aa", + "Chai": "ap", + "Chan": "ar", + "Chang": "as", + "Chao": "aq", + "Che": "ae", + "Chen": "aw", + "Cheng": "at", + "Chi": "ai", + "Chong": "ah", + "Chou": "az", + "Chu": "au", + "Chua": "ax", + "Chuai": "ay", + "Chuan": "al", + "Chuang": "ag", + "Chui": "an", + "Chun": "am", + "Chuo": "ao", + "Ci": "ci", + "Cong": "ch", + "Cou": "cz", + "Cu": "cu", + "Cuan": "cl", + "Cui": "cn", + "Cun": "cm", + "Cuo": "co", + "Da": "da", + "Dai": "dp", + "Dan": "dr", + "Dang": "ds", + "Dao": "dq", + "De": "de", + "Dei": "dk", + "Den": "dw", + "Deng": "dt", + "Di": "di", + "Dia": "dx", + "Dian": "df", + "Diao": "db", + "Die": "dd", + "Ding": "dc", + "Diu": "dj", + "Dong": "dh", + "Dou": "dz", + "Du": "du", + "Duan": "dl", + "Dui": "dn", + "Dun": "dm", + "Duo": "do", + "Fa": "fa", + "Fan": "fr", + "Fang": "fs", + "Fei": "fk", + "Fen": "fw", + "Feng": "ft", + "Fiao": "fb", + "Fo": "fo", + "Fou": "fz", + "Fu": "fu", + "Ga": "ga", + "Gai": "gp", + "Gan": "gr", + "Gang": "gs", + "Gao": "gq", + "Ge": "ge", + "Gei": "gk", + "Gen": "gw", + "Geng": "gt", + "Gong": "gh", + "Gou": "gz", + "Gu": "gu", + "Gua": "gx", + "Guai": "gy", + "Guan": "gl", + "Guang": "gg", + "Gui": "gn", + "Gun": "gm", + "Guo": "go", + "Ha": "ha", + "Hai": "hp", + "Han": "hr", + "Hang": "hs", + "Hao": "hq", + "He": "he", + "Hei": "hk", + "Hen": "hw", + "Heng": "ht", + "Hong": "hh", + "Hou": "hz", + "Hu": "hu", + "Hua": "hx", + "Huai": "hy", + "Huan": "hl", + "Huang": "hg", + "Hui": "hn", + "Hun": "hm", + "Huo": "ho", + "Ji": "ji", + "Jia": "jx", + "Jian": "jf", + "Jiang": "jg", + "Jiao": "jb", + "Jie": "jd", + "Jin": "jy", + "Jing": "jc", + "Jiong": "jh", + "Jiu": "jj", + "Ju": "ju", + "Juan": "jl", + "Jue": "jn", + "Jun": "jm", + "Ka": "ka", + "Kai": "kp", + "Kan": "kr", + "Kang": "ks", + "Kao": "kq", + "Ke": "ke", + "Ken": "kw", + "Keng": "kt", + "Kong": "kh", + "Kou": "kz", + "Ku": "ku", + "Kua": "kx", + "Kuai": "ky", + "Kuan": "kl", + "Kuang": "kg", + "Kui": "kn", + "Kun": "km", + "Kuo": "ko", + "La": "la", + "Lai": "lp", + "Lan": "lr", + "Lang": "ls", + "Lao": "lq", + "Le": "le", + "Lei": "lk", + "Leng": "lt", + "Li": "li", + "Lia": "lx", + "Lian": "lf", + "Liang": "lg", + "Liao": "lb", + "Lie": "ld", + "Lin": "ly", + "Ling": "lc", + "Liu": "lj", + "Lo": "lo", + "Long": "lh", + "Lou": "lz", + "Lu": "lu", + "Luan": "ll", + "Lun": "lm", + "Luo": "lo", + "Ma": "ma", + "Mai": "mp", + "Man": "mr", + "Mang": "ms", + "Mao": "mq", + "Me": "me", + "Mei": "mk", + "Men": "mw", + "Meng": "mt", + "Mi": "mi", + "Mian": "mf", + "Miao": "mb", + "Mie": "md", + "Min": "my", + "Ming": "mc", + "Miu": "mj", + "Mo": "mo", + "Mou": "mz", + "Mu": "mu", + "Na": "na", + "Nai": "np", + "Nan": "nr", + "Nang": "ns", + "Nao": "nq", + "Ne": "ne", + "Nei": "nk", + "Nen": "nw", + "Neng": "nt", + "Ni": "ni", + "Nian": "nf", + "Niang": "ng", + "Niao": "nb", + "Nie": "nd", + "Nin": "ny", + "Ning": "nc", + "Niu": "nj", + "Nong": "nh", + "Nou": "nz", + "Nu": "nu", + "Nuan": "nl", + "Nun": "nm", + "Nuo": "no", + "Pa": "pa", + "Pai": "pp", + "Pan": "pr", + "Pang": "ps", + "Pao": "pq", + "Pei": "pk", + "Pen": "pw", + "Peng": "pt", + "Pi": "pi", + "Pian": "pf", + "Piao": "pb", + "Pie": "pd", + "Pin": "py", + "Ping": "pc", + "Po": "po", + "Pou": "pz", + "Pu": "pu", + "Qi": "qi", + "Qia": "qx", + "Qian": "qf", + "Qiang": "qg", + "Qiao": "qb", + "Qie": "qd", + "Qin": "qy", + "Qing": "qc", + "Qiong": "qh", + "Qiu": "qj", + "Qu": "qu", + "Quan": "ql", + "Que": "qn", + "Qun": "qm", + "Ran": "rr", + "Rang": "rs", + "Rao": "rq", + "Re": "re", + "Ren": "rw", + "Reng": "rt", + "Ri": "ri", + "Rong": "rh", + "Rou": "rz", + "Ru": "ru", + "Rua": "rx", + "Ruan": "rl", + "Rui": "rn", + "Run": "rm", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sp", + "San": "sr", + "Sang": "ss", + "Sao": "sq", + "Se": "se", + "Sen": "sw", + "Seng": "st", + "Sha": "ia", + "Shai": "ip", + "Shan": "ir", + "Shang": "is", + "Shao": "iq", + "She": "ie", + "Shei": "ik", + "Shen": "iw", + "Sheng": "it", + "Shi": "ii", + "Shou": "iz", + "Shu": "iu", + "Shua": "ix", + "Shuai": "iy", + "Shuan": "il", + "Shuang": "ig", + "Shui": "in", + "Shun": "im", + "Shuo": "io", + "Si": "si", + "Song": "sh", + "Sou": "sz", + "Su": "su", + "Suan": "sl", + "Sui": "sn", + "Sun": "sm", + "Suo": "so", + "Ta": "ta", + "Tai": "tp", + "Tan": "tr", + "Tang": "ts", + "Tao": "tq", + "Te": "te", + "Tei": "tk", + "Teng": "tt", + "Ti": "ti", + "Tian": "tf", + "Tiao": "tb", + "Tie": "td", + "Ting": "tc", + "Tong": "th", + "Tou": "tz", + "Tu": "tu", + "Tuan": "tl", + "Tui": "tn", + "Tun": "tm", + "Tuo": "to", + "Xi": "xi", + "Xia": "xx", + "Xian": "xf", + "Xiang": "xg", + "Xiao": "xb", + "Xie": "xd", + "Xin": "xy", + "Xing": "xc", + "Xiong": "xh", + "Xiu": "xj", + "Xu": "xu", + "Xuan": "xl", + "Xue": "xn", + "Xun": "xm", + "Za": "za", + "Zai": "zp", + "Zan": "zr", + "Zang": "zs", + "Zao": "zq", + "Ze": "ze", + "Zei": "zk", + "Zen": "zw", + "Zeng": "zt", + "Zha": "ua", + "Zhai": "up", + "Zhan": "ur", + "Zhang": "us", + "Zhao": "uq", + "Zhe": "ue", + "Zhen": "uw", + "Zheng": "ut", + "Zhi": "ui", + "Zhong": "uh", + "Zhou": "uz", + "Zhu": "uu", + "Zhua": "ux", + "Zhuai": "uy", + "Zhuan": "ul", + "Zhuang": "ug", + "Zhui": "un", + "Zhun": "um", + "Zhuo": "uo", + "Zi": "zi", + "Zong": "zh", + "Zou": "zz", + "Zu": "zu", + "Zuan": "zl", + "Zui": "zn", + "Zun": "zm", + "Zuo": "zo" + }, + "PinYinJiaJia": { + "Lv": "lv", + "Lve": "lx", + "Lue": "lx", + "Nv": "nv", + "Nve": "nx", + "Nue": "nx", + "A": "aa", + "O": "oo", + "E": "ee", + "Ai": "as", + "Ei": "ew", + "Ao": "ad", + "Ou": "op", + "An": "af", + "En": "er", + "Ang": "ag", + "Eng": "et", + "Er": "eq", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "yd", + "You": "yp", + "Yan": "yf", + "Yin": "yl", + "Yang": "yg", + "Ying": "yq", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "ws", + "Wei": "ww", + "Wan": "wf", + "Wen": "wr", + "Wang": "wg", + "Weng": "wt", + "Yu": "yu", + "Yue": "yx", + "Yuan": "yc", + "Yun": "yz", + "Yong": "yy", + "Ba": "ba", + "Bai": "bs", + "Ban": "bf", + "Bang": "bg", + "Bao": "bd", + "Bei": "bw", + "Ben": "br", + "Beng": "bt", + "Bi": "bi", + "Bian": "bj", + "Biang": "bh", + "Biao": "bk", + "Bie": "bm", + "Bin": "bl", + "Bing": "bq", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cs", + "Can": "cf", + "Cang": "cg", + "Cao": "cd", + "Ce": "ce", + "Cen": "cr", + "Ceng": "ct", + "Cha": "ua", + "Chai": "us", + "Chan": "uf", + "Chang": "ug", + "Chao": "ud", + "Che": "ue", + "Chen": "ur", + "Cheng": "ut", + "Chi": "ui", + "Chong": "uy", + "Chou": "up", + "Chu": "uu", + "Chua": "ub", + "Chuai": "ux", + "Chuan": "uc", + "Chuang": "uh", + "Chui": "uv", + "Chun": "uz", + "Chuo": "uo", + "Ci": "ci", + "Cong": "cy", + "Cou": "cp", + "Cu": "cu", + "Cuan": "cc", + "Cui": "cv", + "Cun": "cz", + "Cuo": "co", + "Da": "da", + "Dai": "ds", + "Dan": "df", + "Dang": "dg", + "Dao": "dd", + "De": "de", + "Dei": "dw", + "Den": "dr", + "Deng": "dt", + "Di": "di", + "Dia": "db", + "Dian": "dj", + "Diao": "dk", + "Die": "dm", + "Ding": "dq", + "Diu": "dn", + "Dong": "dy", + "Dou": "dp", + "Du": "du", + "Duan": "dc", + "Dui": "dv", + "Dun": "dz", + "Duo": "do", + "Fa": "fa", + "Fan": "ff", + "Fang": "fg", + "Fei": "fw", + "Fen": "fr", + "Feng": "ft", + "Fiao": "fk", + "Fo": "fo", + "Fou": "fp", + "Fu": "fu", + "Ga": "ga", + "Gai": "gs", + "Gan": "gf", + "Gang": "gg", + "Gao": "gd", + "Ge": "ge", + "Gei": "gw", + "Gen": "gr", + "Geng": "gt", + "Gong": "gy", + "Gou": "gp", + "Gu": "gu", + "Gua": "gb", + "Guai": "gx", + "Guan": "gc", + "Guang": "gh", + "Gui": "gv", + "Gun": "gz", + "Guo": "go", + "Ha": "ha", + "Hai": "hs", + "Han": "hf", + "Hang": "hg", + "Hao": "hd", + "He": "he", + "Hei": "hw", + "Hen": "hr", + "Heng": "ht", + "Hong": "hy", + "Hou": "hp", + "Hu": "hu", + "Hua": "hb", + "Huai": "hx", + "Huan": "hc", + "Huang": "hh", + "Hui": "hv", + "Hun": "hz", + "Huo": "ho", + "Ji": "ji", + "Jia": "jb", + "Jian": "jj", + "Jiang": "jh", + "Jiao": "jk", + "Jie": "jm", + "Jin": "jl", + "Jing": "jq", + "Jiong": "jy", + "Jiu": "jn", + "Ju": "ju", + "Juan": "jc", + "Jue": "jx", + "Jun": "jz", + "Ka": "ka", + "Kai": "ks", + "Kan": "kf", + "Kang": "kg", + "Kao": "kd", + "Ke": "ke", + "Ken": "kr", + "Keng": "kt", + "Kong": "ky", + "Kou": "kp", + "Ku": "ku", + "Kua": "kb", + "Kuai": "kx", + "Kuan": "kc", + "Kuang": "kh", + "Kui": "kv", + "Kun": "kz", + "Kuo": "ko", + "La": "la", + "Lai": "ls", + "Lan": "lf", + "Lang": "lg", + "Lao": "ld", + "Le": "le", + "Lei": "lw", + "Leng": "lt", + "Li": "li", + "Lia": "lb", + "Lian": "lj", + "Liang": "lh", + "Liao": "lk", + "Lie": "lm", + "Lin": "ll", + "Ling": "lq", + "Liu": "ln", + "Lo": "lo", + "Long": "ly", + "Lou": "lp", + "Lu": "lu", + "Luan": "lc", + "Lun": "lz", + "Luo": "lo", + "Ma": "ma", + "Mai": "ms", + "Man": "mf", + "Mang": "mg", + "Mao": "md", + "Me": "me", + "Mei": "mw", + "Men": "mr", + "Meng": "mt", + "Mi": "mi", + "Mian": "mj", + "Miao": "mk", + "Mie": "mm", + "Min": "ml", + "Ming": "mq", + "Miu": "mn", + "Mo": "mo", + "Mou": "mp", + "Mu": "mu", + "Na": "na", + "Nai": "ns", + "Nan": "nf", + "Nang": "ng", + "Nao": "nd", + "Ne": "ne", + "Nei": "nw", + "Nen": "nr", + "Neng": "nt", + "Ni": "ni", + "Nian": "nj", + "Niang": "nh", + "Niao": "nk", + "Nie": "nm", + "Nin": "nl", + "Ning": "nq", + "Niu": "nn", + "Nong": "ny", + "Nou": "np", + "Nu": "nu", + "Nuan": "nc", + "Nun": "nz", + "Nuo": "no", + "Pa": "pa", + "Pai": "ps", + "Pan": "pf", + "Pang": "pg", + "Pao": "pd", + "Pei": "pw", + "Pen": "pr", + "Peng": "pt", + "Pi": "pi", + "Pian": "pj", + "Piao": "pk", + "Pie": "pm", + "Pin": "pl", + "Ping": "pq", + "Po": "po", + "Pou": "pp", + "Pu": "pu", + "Qi": "qi", + "Qia": "qb", + "Qian": "qj", + "Qiang": "qh", + "Qiao": "qk", + "Qie": "qm", + "Qin": "ql", + "Qing": "qq", + "Qiong": "qy", + "Qiu": "qn", + "Qu": "qu", + "Quan": "qc", + "Que": "qx", + "Qun": "qz", + "Ran": "rf", + "Rang": "rg", + "Rao": "rd", + "Re": "re", + "Ren": "rr", + "Reng": "rt", + "Ri": "ri", + "Rong": "ry", + "Rou": "rp", + "Ru": "ru", + "Rua": "rb", + "Ruan": "rc", + "Rui": "rv", + "Run": "rz", + "Ruo": "ro", + "Sa": "sa", + "Sai": "ss", + "San": "sf", + "Sang": "sg", + "Sao": "sd", + "Se": "se", + "Sen": "sr", + "Seng": "st", + "Sha": "ia", + "Shai": "is", + "Shan": "if", + "Shang": "ig", + "Shao": "id", + "She": "ie", + "Shei": "iw", + "Shen": "ir", + "Sheng": "it", + "Shi": "ii", + "Shou": "ip", + "Shu": "iu", + "Shua": "ib", + "Shuai": "ix", + "Shuan": "ic", + "Shuang": "ih", + "Shui": "iv", + "Shun": "iz", + "Shuo": "io", + "Si": "si", + "Song": "sy", + "Sou": "sp", + "Su": "su", + "Suan": "sc", + "Sui": "sv", + "Sun": "sz", + "Suo": "so", + "Ta": "ta", + "Tai": "ts", + "Tan": "tf", + "Tang": "tg", + "Tao": "td", + "Te": "te", + "Tei": "tw", + "Teng": "tt", + "Ti": "ti", + "Tian": "tj", + "Tiao": "tk", + "Tie": "tm", + "Ting": "tq", + "Tong": "ty", + "Tou": "tp", + "Tu": "tu", + "Tuan": "tc", + "Tui": "tv", + "Tun": "tz", + "Tuo": "to", + "Xi": "xi", + "Xia": "xb", + "Xian": "xj", + "Xiang": "xh", + "Xiao": "xk", + "Xie": "xm", + "Xin": "xl", + "Xing": "xq", + "Xiong": "xy", + "Xiu": "xn", + "Xu": "xu", + "Xuan": "xc", + "Xue": "xx", + "Xun": "xz", + "Za": "za", + "Zai": "zs", + "Zan": "zf", + "Zang": "zg", + "Zao": "zd", + "Ze": "ze", + "Zei": "zw", + "Zen": "zr", + "Zeng": "zt", + "Zha": "va", + "Zhai": "vs", + "Zhan": "vf", + "Zhang": "vg", + "Zhao": "vd", + "Zhe": "ve", + "Zhen": "vr", + "Zheng": "vt", + "Zhi": "vi", + "Zhong": "vy", + "Zhou": "vp", + "Zhu": "vu", + "Zhua": "vb", + "Zhuai": "vx", + "Zhuan": "vc", + "Zhuang": "vh", + "Zhui": "vv", + "Zhun": "vz", + "Zhuo": "vo", + "Zi": "zi", + "Zong": "zy", + "Zou": "zp", + "Zu": "zu", + "Zuan": "zc", + "Zui": "zv", + "Zun": "zz", + "Zuo": "zo" + }, + "XingKongJianDao": { + "Lv": "lv", + "Lve": "ly", + "Lue": "ly", + "Nv": "nv", + "Nve": "ny", + "Nue": "ny", + "A": "xa", + "O": "xo", + "E": "xe", + "Ai": "xj", + "Ei": "xw", + "Ao": "xs", + "Ou": "xt", + "An": "xd", + "En": "xk", + "Ang": "xf", + "Eng": "xh", + "Er": "xu", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "ys", + "You": "yt", + "Yan": "yd", + "Yin": "yb", + "Yang": "yf", + "Ying": "yg", + "Wu": "wj", + "Wa": "ws", + "Wo": "wo", + "Wai": "wh", + "Wei": "ww", + "Wan": "wf", + "Wen": "wn", + "Wang": "wp", + "Weng": "wr", + "Yu": "yv", + "Yue": "yy", + "Yuan": "yr", + "Yun": "yw", + "Yong": "yl", + "Ba": "ba", + "Bai": "bj", + "Ban": "bd", + "Bang": "bf", + "Bao": "bs", + "Bei": "bw", + "Ben": "bk", + "Beng": "bh", + "Bi": "bi", + "Bian": "bm", + "Biang": "bx", + "Biao": "bp", + "Bie": "bc", + "Bin": "bb", + "Bing": "bg", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "cj", + "Can": "cd", + "Cang": "cf", + "Cao": "cs", + "Ce": "ce", + "Cen": "ck", + "Ceng": "ch", + "Cha": "ja", + "Chai": "jj", + "Chan": "jd", + "Chang": "jf", + "Chao": "js", + "Che": "je", + "Chen": "jk", + "Cheng": "jh", + "Chi": "wi", + "Chong": "wl", + "Chou": "jt", + "Chu": "ju", + "Chua": "wx", + "Chuai": "wg", + "Chuan": "wr", + "Chuang": "wn", + "Chui": "wy", + "Chun": "jz", + "Chuo": "jo", + "Ci": "ci", + "Cong": "cl", + "Cou": "ct", + "Cu": "cu", + "Cuan": "cr", + "Cui": "cy", + "Cun": "cz", + "Cuo": "co", + "Da": "da", + "Dai": "dj", + "Dan": "dd", + "Dang": "df", + "Dao": "ds", + "De": "de", + "Dei": "dw", + "Den": "dk", + "Deng": "dh", + "Di": "di", + "Dia": "dx", + "Dian": "dm", + "Diao": "dp", + "Die": "dc", + "Ding": "dg", + "Diu": "dq", + "Dong": "dl", + "Dou": "dt", + "Du": "du", + "Duan": "dr", + "Dui": "dy", + "Dun": "dz", + "Duo": "do", + "Fa": "fs", + "Fan": "ff", + "Fang": "fp", + "Fei": "fw", + "Fen": "fn", + "Feng": "fr", + "Fiao": "fp", + "Fo": "fl", + "Fou": "fd", + "Fu": "fl", + "Ga": "ga", + "Gai": "gj", + "Gan": "gd", + "Gang": "gf", + "Gao": "gs", + "Ge": "ge", + "Gei": "gw", + "Gen": "gk", + "Geng": "gh", + "Gong": "gl", + "Gou": "gt", + "Gu": "gu", + "Gua": "gx", + "Guai": "gg", + "Guan": "gr", + "Guang": "gn", + "Gui": "gy", + "Gun": "gz", + "Guo": "go", + "Ha": "ha", + "Hai": "hj", + "Han": "hd", + "Hang": "hf", + "Hao": "hs", + "He": "he", + "Hei": "hw", + "Hen": "hk", + "Heng": "hh", + "Hong": "hl", + "Hou": "ht", + "Hu": "hu", + "Hua": "hx", + "Huai": "hg", + "Huan": "hr", + "Huang": "hn", + "Hui": "hy", + "Hun": "hz", + "Huo": "ho", + "Ji": "jk", + "Jia": "js", + "Jian": "jm", + "Jiang": "jn", + "Jiao": "jp", + "Jie": "jc", + "Jin": "jb", + "Jing": "jg", + "Jiong": "jy", + "Jiu": "jq", + "Ju": "jv", + "Juan": "jt", + "Jue": "jh", + "Jun": "jw", + "Ka": "ka", + "Kai": "kj", + "Kan": "kd", + "Kang": "kf", + "Kao": "ks", + "Ke": "ke", + "Ken": "kk", + "Keng": "kh", + "Kong": "kl", + "Kou": "kt", + "Ku": "ku", + "Kua": "kx", + "Kuai": "kg", + "Kuan": "kr", + "Kuang": "kn", + "Kui": "ky", + "Kun": "kz", + "Kuo": "ko", + "La": "la", + "Lai": "lj", + "Lan": "ld", + "Lang": "lf", + "Lao": "ls", + "Le": "le", + "Lei": "lw", + "Leng": "lh", + "Li": "li", + "Lia": "lx", + "Lian": "lm", + "Liang": "ln", + "Liao": "lp", + "Lie": "lc", + "Lin": "lb", + "Ling": "lg", + "Liu": "lq", + "Lo": "ll", + "Long": "ll", + "Lou": "lt", + "Lu": "lu", + "Luan": "lr", + "Lun": "lz", + "Luo": "lo", + "Ma": "ma", + "Mai": "mj", + "Man": "md", + "Mang": "mf", + "Mao": "ms", + "Me": "me", + "Mei": "mw", + "Men": "mk", + "Meng": "mh", + "Mi": "mi", + "Mian": "mm", + "Miao": "mp", + "Mie": "mc", + "Min": "mb", + "Ming": "mg", + "Miu": "mq", + "Mo": "mo", + "Mou": "mt", + "Mu": "mu", + "Na": "na", + "Nai": "nj", + "Nan": "nd", + "Nang": "nf", + "Nao": "ns", + "Ne": "ne", + "Nei": "nw", + "Nen": "nk", + "Neng": "nh", + "Ni": "ni", + "Nian": "nm", + "Niang": "nn", + "Niao": "np", + "Nie": "nc", + "Nin": "nb", + "Ning": "ng", + "Niu": "nq", + "Nong": "nl", + "Nou": "nt", + "Nu": "nu", + "Nuan": "nr", + "Nun": "nz", + "Nuo": "no", + "Pa": "pa", + "Pai": "pj", + "Pan": "pd", + "Pang": "pf", + "Pao": "ps", + "Pei": "pw", + "Pen": "pk", + "Peng": "ph", + "Pi": "pi", + "Pian": "pm", + "Piao": "pp", + "Pie": "pc", + "Pin": "pb", + "Ping": "pg", + "Po": "po", + "Pou": "pt", + "Pu": "pu", + "Qi": "qk", + "Qia": "qs", + "Qian": "qm", + "Qiang": "qx", + "Qiao": "qp", + "Qie": "qc", + "Qin": "qb", + "Qing": "qg", + "Qiong": "qy", + "Qiu": "qq", + "Qu": "qv", + "Quan": "qt", + "Que": "qh", + "Qun": "qw", + "Ran": "rd", + "Rang": "rf", + "Rao": "rs", + "Re": "re", + "Ren": "rk", + "Reng": "rh", + "Ri": "ri", + "Rong": "rl", + "Rou": "rt", + "Ru": "ru", + "Rua": "rx", + "Ruan": "rr", + "Rui": "ry", + "Run": "rz", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sj", + "San": "sd", + "Sang": "sf", + "Sao": "ss", + "Se": "se", + "Sen": "sk", + "Seng": "sh", + "Sha": "ea", + "Shai": "ej", + "Shan": "ed", + "Shang": "ef", + "Shao": "es", + "She": "ee", + "Shei": "ew", + "Shen": "ek", + "Sheng": "eh", + "Shi": "ei", + "Shou": "et", + "Shu": "eu", + "Shua": "ex", + "Shuai": "eg", + "Shuan": "er", + "Shuang": "en", + "Shui": "ey", + "Shun": "ez", + "Shuo": "eo", + "Si": "si", + "Song": "sl", + "Sou": "st", + "Su": "su", + "Suan": "sr", + "Sui": "sy", + "Sun": "sz", + "Suo": "so", + "Ta": "ta", + "Tai": "tj", + "Tan": "td", + "Tang": "tf", + "Tao": "ts", + "Te": "te", + "Tei": "tw", + "Teng": "th", + "Ti": "ti", + "Tian": "tm", + "Tiao": "tp", + "Tie": "tc", + "Ting": "tg", + "Tong": "tl", + "Tou": "tt", + "Tu": "tu", + "Tuan": "tr", + "Tui": "ty", + "Tun": "tz", + "Tuo": "to", + "Xi": "xi", + "Xia": "xx", + "Xian": "xm", + "Xiang": "xn", + "Xiao": "xp", + "Xie": "xc", + "Xin": "xb", + "Xing": "xg", + "Xiong": "xl", + "Xiu": "xq", + "Xu": "xv", + "Xuan": "xr", + "Xue": "xy", + "Xun": "xw", + "Za": "za", + "Zai": "zj", + "Zan": "zd", + "Zang": "zf", + "Zao": "zs", + "Ze": "ze", + "Zei": "zw", + "Zen": "zk", + "Zeng": "zh", + "Zha": "qa", + "Zhai": "fj", + "Zhan": "qd", + "Zhang": "qf", + "Zhao": "fs", + "Zhe": "fe", + "Zhen": "qk", + "Zheng": "qh", + "Zhi": "fi", + "Zhong": "fy", + "Zhou": "qt", + "Zhu": "qu", + "Zhua": "fx", + "Zhuai": "fg", + "Zhuan": "fr", + "Zhuang": "fn", + "Zhui": "fy", + "Zhun": "fz", + "Zhuo": "qo", + "Zi": "zi", + "Zong": "zl", + "Zou": "zt", + "Zu": "zu", + "Zuan": "zr", + "Zui": "zy", + "Zun": "zz", + "Zuo": "zo" + }, + "DaNiu": { + "Lv": "lv", + "Lve": "lx", + "Lue": "lx", + "Nv": "nv", + "Nve": "nx", + "Nue": "nx", + "A": "ea", + "O": "eo", + "E": "ee", + "Ai": "eh", + "Ei": "ew", + "Ao": "es", + "Ou": "er", + "An": "ed", + "En": "ek", + "Ang": "ef", + "Eng": "ej", + "Er": "eu", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "ys", + "You": "yr", + "Yan": "yd", + "Yin": "yb", + "Yang": "yf", + "Ying": "yg", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wh", + "Wei": "ww", + "Wan": "wd", + "Wen": "wk", + "Wang": "wf", + "Weng": "wj", + "Yu": "yu", + "Yue": "yh", + "Yuan": "yj", + "Yun": "yw", + "Yong": "yl", + "Ba": "ba", + "Bai": "bh", + "Ban": "bd", + "Bang": "bf", + "Bao": "bs", + "Bei": "bw", + "Ben": "bk", + "Beng": "bj", + "Bi": "bi", + "Bian": "bc", + "Biang": "bn", + "Biao": "bm", + "Bie": "bp", + "Bin": "bb", + "Bing": "bg", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "ch", + "Can": "cd", + "Cang": "cf", + "Cao": "cs", + "Ce": "ce", + "Cen": "ck", + "Ceng": "cj", + "Cha": "ia", + "Chai": "ih", + "Chan": "id", + "Chang": "if", + "Chao": "is", + "Che": "ie", + "Chen": "ik", + "Cheng": "ij", + "Chi": "ii", + "Chong": "il", + "Chou": "ir", + "Chu": "iu", + "Chua": "iq", + "Chuai": "ig", + "Chuan": "iz", + "Chuang": "ix", + "Chui": "in", + "Chun": "iy", + "Chuo": "io", + "Ci": "ci", + "Cong": "cl", + "Cou": "cr", + "Cu": "cu", + "Cuan": "cz", + "Cui": "cn", + "Cun": "cy", + "Cuo": "co", + "Da": "da", + "Dai": "dh", + "Dan": "dd", + "Dang": "df", + "Dao": "ds", + "De": "de", + "Dei": "dw", + "Den": "dk", + "Deng": "dj", + "Di": "di", + "Dia": "dk", + "Dian": "dc", + "Diao": "dm", + "Die": "dp", + "Ding": "dg", + "Diu": "dt", + "Dong": "dl", + "Dou": "dr", + "Du": "du", + "Duan": "dz", + "Dui": "dn", + "Dun": "dy", + "Duo": "do", + "Fa": "fa", + "Fan": "fd", + "Fang": "ff", + "Fei": "fw", + "Fen": "fk", + "Feng": "fj", + "Fiao": "fm", + "Fo": "fo", + "Fou": "fr", + "Fu": "fu", + "Ga": "ga", + "Gai": "gh", + "Gan": "gd", + "Gang": "gf", + "Gao": "gs", + "Ge": "ge", + "Gei": "gw", + "Gen": "gk", + "Geng": "gj", + "Gong": "gl", + "Gou": "gr", + "Gu": "gu", + "Gua": "gq", + "Guai": "gg", + "Guan": "gz", + "Guang": "gx", + "Gui": "gn", + "Gun": "gy", + "Guo": "go", + "Ha": "ha", + "Hai": "hh", + "Han": "hd", + "Hang": "hf", + "Hao": "hs", + "He": "he", + "Hei": "hw", + "Hen": "hk", + "Heng": "hj", + "Hong": "hl", + "Hou": "hr", + "Hu": "hu", + "Hua": "hq", + "Huai": "hg", + "Huan": "hz", + "Huang": "hx", + "Hui": "hn", + "Hun": "hy", + "Huo": "ho", + "Ji": "ji", + "Jia": "jk", + "Jian": "jc", + "Jiang": "jn", + "Jiao": "jm", + "Jie": "jp", + "Jin": "jb", + "Jing": "jg", + "Jiong": "jl", + "Jiu": "jt", + "Ju": "ju", + "Juan": "jj", + "Jue": "jh", + "Jun": "jw", + "Ka": "ka", + "Kai": "kh", + "Kan": "kd", + "Kang": "kf", + "Kao": "ks", + "Ke": "ke", + "Ken": "kk", + "Keng": "kj", + "Kong": "kl", + "Kou": "kr", + "Ku": "ku", + "Kua": "kq", + "Kuai": "kg", + "Kuan": "kz", + "Kuang": "kx", + "Kui": "kn", + "Kun": "ky", + "Kuo": "ko", + "La": "la", + "Lai": "lh", + "Lan": "ld", + "Lang": "lf", + "Lao": "ls", + "Le": "le", + "Lei": "lw", + "Leng": "lj", + "Li": "li", + "Lia": "lk", + "Lian": "lc", + "Liang": "ln", + "Liao": "lm", + "Lie": "lp", + "Lin": "lb", + "Ling": "lg", + "Liu": "lt", + "Lo": "lo", + "Long": "ll", + "Lou": "lr", + "Lu": "lu", + "Luan": "lz", + "Lun": "ly", + "Luo": "lo", + "Ma": "ma", + "Mai": "mh", + "Man": "md", + "Mang": "mf", + "Mao": "ms", + "Me": "me", + "Mei": "mw", + "Men": "mk", + "Meng": "mj", + "Mi": "mi", + "Mian": "mc", + "Miao": "mm", + "Mie": "mp", + "Min": "mb", + "Ming": "mg", + "Miu": "mt", + "Mo": "mo", + "Mou": "mr", + "Mu": "mu", + "Na": "na", + "Nai": "nh", + "Nan": "nd", + "Nang": "nf", + "Nao": "ns", + "Ne": "ne", + "Nei": "nw", + "Nen": "nk", + "Neng": "nj", + "Ni": "ni", + "Nian": "nc", + "Niang": "nn", + "Niao": "nm", + "Nie": "np", + "Nin": "nb", + "Ning": "ng", + "Niu": "nt", + "Nong": "nl", + "Nou": "nr", + "Nu": "nu", + "Nuan": "nz", + "Nun": "ny", + "Nuo": "no", + "Pa": "pa", + "Pai": "ph", + "Pan": "pd", + "Pang": "pf", + "Pao": "ps", + "Pei": "pw", + "Pen": "pk", + "Peng": "pj", + "Pi": "pi", + "Pian": "pc", + "Piao": "pm", + "Pie": "pp", + "Pin": "pb", + "Ping": "pg", + "Po": "po", + "Pou": "pr", + "Pu": "pu", + "Qi": "qi", + "Qia": "qk", + "Qian": "qc", + "Qiang": "qn", + "Qiao": "qm", + "Qie": "qp", + "Qin": "qb", + "Qing": "qg", + "Qiong": "ql", + "Qiu": "qt", + "Qu": "qu", + "Quan": "qj", + "Que": "qh", + "Qun": "qw", + "Ran": "rd", + "Rang": "rf", + "Rao": "rs", + "Re": "re", + "Ren": "rk", + "Reng": "rj", + "Ri": "ri", + "Rong": "rl", + "Rou": "rr", + "Ru": "ru", + "Rua": "rq", + "Ruan": "rz", + "Rui": "rn", + "Run": "ry", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sh", + "San": "sd", + "Sang": "sf", + "Sao": "ss", + "Se": "se", + "Sen": "sk", + "Seng": "sj", + "Sha": "ua", + "Shai": "uh", + "Shan": "ud", + "Shang": "uf", + "Shao": "us", + "She": "ue", + "Shei": "uw", + "Shen": "uk", + "Sheng": "uj", + "Shi": "ui", + "Shou": "ur", + "Shu": "uu", + "Shua": "uq", + "Shuai": "ug", + "Shuan": "uz", + "Shuang": "ux", + "Shui": "un", + "Shun": "uy", + "Shuo": "uo", + "Si": "si", + "Song": "sl", + "Sou": "sr", + "Su": "su", + "Suan": "sz", + "Sui": "sn", + "Sun": "sy", + "Suo": "so", + "Ta": "ta", + "Tai": "th", + "Tan": "td", + "Tang": "tf", + "Tao": "ts", + "Te": "te", + "Tei": "tw", + "Teng": "tj", + "Ti": "ti", + "Tian": "tc", + "Tiao": "tm", + "Tie": "tp", + "Ting": "tg", + "Tong": "tl", + "Tou": "tr", + "Tu": "tu", + "Tuan": "tz", + "Tui": "tn", + "Tun": "ty", + "Tuo": "to", + "Xi": "xi", + "Xia": "xk", + "Xian": "xc", + "Xiang": "xn", + "Xiao": "xm", + "Xie": "xp", + "Xin": "xb", + "Xing": "xg", + "Xiong": "xl", + "Xiu": "xt", + "Xu": "xu", + "Xuan": "xj", + "Xue": "xh", + "Xun": "xw", + "Za": "za", + "Zai": "zh", + "Zan": "zd", + "Zang": "zf", + "Zao": "zs", + "Ze": "ze", + "Zei": "zw", + "Zen": "zk", + "Zeng": "zj", + "Zha": "aa", + "Zhai": "ah", + "Zhan": "ad", + "Zhang": "af", + "Zhao": "as", + "Zhe": "ae", + "Zhen": "ak", + "Zheng": "aj", + "Zhi": "ai", + "Zhong": "al", + "Zhou": "ar", + "Zhu": "au", + "Zhua": "aq", + "Zhuai": "ag", + "Zhuan": "az", + "Zhuang": "ax", + "Zhui": "an", + "Zhun": "ay", + "Zhuo": "ao", + "Zi": "zi", + "Zong": "zl", + "Zou": "zr", + "Zu": "zu", + "Zuan": "zz", + "Zui": "zn", + "Zun": "zy", + "Zuo": "zo" + }, + "XiaoLang": { + "Lv": "lx", + "Lve": "lb", + "Lue": "lb", + "Nv": "nx", + "Nve": "nb", + "Nue": "nb", + "A": "aa", + "O": "oo", + "E": "uu", + "Ai": "ai", + "Ei": "ui", + "Ao": "ao", + "Ou": "ou", + "An": "an", + "En": "un", + "Ang": "ah", + "Eng": "un", + "Er": "ur", + "Yi": "yi", + "Ya": "ya", + "Yo": "yo", + "Ye": "ye", + "Yao": "ys", + "You": "yr", + "Yan": "yj", + "Yin": "yd", + "Yang": "yh", + "Ying": "yv", + "Wu": "wu", + "Wa": "wa", + "Wo": "wo", + "Wai": "wk", + "Wei": "ww", + "Wan": "wj", + "Wen": "wm", + "Wang": "wh", + "Weng": "wn", + "Yu": "yu", + "Yue": "yb", + "Yuan": "yg", + "Yun": "yy", + "Yong": "yl", + "Ba": "ba", + "Bai": "bk", + "Ban": "bj", + "Bang": "bh", + "Bao": "bs", + "Bei": "bw", + "Ben": "bm", + "Beng": "bn", + "Bi": "bi", + "Bian": "bf", + "Biang": "bm", + "Biao": "bc", + "Bie": "bp", + "Bin": "bd", + "Bing": "bv", + "Bo": "bo", + "Bu": "bu", + "Ca": "ca", + "Cai": "ck", + "Can": "cj", + "Cang": "ch", + "Cao": "cs", + "Ce": "ce", + "Cen": "cm", + "Ceng": "cn", + "Cha": "ia", + "Chai": "ik", + "Chan": "ij", + "Chang": "ih", + "Chao": "is", + "Che": "ie", + "Chen": "im", + "Cheng": "in", + "Chi": "ii", + "Chong": "il", + "Chou": "ir", + "Chu": "iu", + "Chua": "if", + "Chuai": "iv", + "Chuan": "ig", + "Chuang": "iz", + "Chui": "id", + "Chun": "iy", + "Chuo": "io", + "Ci": "ci", + "Cong": "cl", + "Cou": "cr", + "Cu": "cu", + "Cuan": "cg", + "Cui": "cd", + "Cun": "cy", + "Cuo": "co", + "Da": "da", + "Dai": "dk", + "Dan": "dj", + "Dang": "dh", + "Dao": "ds", + "De": "de", + "Dei": "dw", + "Den": "dm", + "Deng": "dn", + "Di": "di", + "Dia": "dk", + "Dian": "df", + "Diao": "dc", + "Die": "dp", + "Ding": "dv", + "Diu": "dt", + "Dong": "dl", + "Dou": "dr", + "Du": "du", + "Duan": "dg", + "Dui": "dd", + "Dun": "dy", + "Duo": "do", + "Fa": "fa", + "Fan": "fj", + "Fang": "fh", + "Fei": "fw", + "Fen": "fm", + "Feng": "fn", + "Fiao": "fc", + "Fo": "fo", + "Fou": "fr", + "Fu": "fu", + "Ga": "ga", + "Gai": "gk", + "Gan": "gj", + "Gang": "gh", + "Gao": "gs", + "Ge": "ge", + "Gei": "gw", + "Gen": "gm", + "Geng": "gn", + "Gong": "gl", + "Gou": "gr", + "Gu": "gu", + "Gua": "gf", + "Guai": "gv", + "Guan": "gg", + "Guang": "gz", + "Gui": "gd", + "Gun": "gy", + "Guo": "go", + "Ha": "ha", + "Hai": "hk", + "Han": "hj", + "Hang": "hh", + "Hao": "hs", + "He": "he", + "Hei": "hw", + "Hen": "hm", + "Heng": "hn", + "Hong": "hl", + "Hou": "hr", + "Hu": "hu", + "Hua": "hf", + "Huai": "hv", + "Huan": "hg", + "Huang": "hz", + "Hui": "hd", + "Hun": "hy", + "Huo": "ho", + "Ji": "ji", + "Jia": "jk", + "Jian": "jf", + "Jiang": "jm", + "Jiao": "jc", + "Jie": "jp", + "Jin": "jd", + "Jing": "jv", + "Jiong": "jj", + "Jiu": "jt", + "Ju": "ju", + "Juan": "jg", + "Jue": "jb", + "Jun": "jy", + "Ka": "ka", + "Kai": "kk", + "Kan": "kj", + "Kang": "kh", + "Kao": "ks", + "Ke": "ke", + "Ken": "km", + "Keng": "kn", + "Kong": "kl", + "Kou": "kr", + "Ku": "ku", + "Kua": "kf", + "Kuai": "kv", + "Kuan": "kg", + "Kuang": "kz", + "Kui": "kd", + "Kun": "ky", + "Kuo": "ko", + "La": "la", + "Lai": "lk", + "Lan": "lj", + "Lang": "lh", + "Lao": "ls", + "Le": "le", + "Lei": "lw", + "Leng": "ln", + "Li": "li", + "Lia": "lk", + "Lian": "lf", + "Liang": "lm", + "Liao": "lc", + "Lie": "lp", + "Lin": "ld", + "Ling": "lv", + "Liu": "lt", + "Lo": "lo", + "Long": "ll", + "Lou": "lr", + "Lu": "lu", + "Luan": "lg", + "Lun": "ly", + "Luo": "lo", + "Ma": "ma", + "Mai": "mk", + "Man": "mj", + "Mang": "mh", + "Mao": "ms", + "Me": "me", + "Mei": "mw", + "Men": "mm", + "Meng": "mn", + "Mi": "mi", + "Mian": "mf", + "Miao": "mc", + "Mie": "mp", + "Min": "md", + "Ming": "mv", + "Miu": "mt", + "Mo": "mo", + "Mou": "mr", + "Mu": "mu", + "Na": "na", + "Nai": "nk", + "Nan": "nj", + "Nang": "nh", + "Nao": "ns", + "Ne": "ne", + "Nei": "nw", + "Nen": "nm", + "Neng": "nn", + "Ni": "ni", + "Nian": "nf", + "Niang": "nm", + "Niao": "nc", + "Nie": "np", + "Nin": "nd", + "Ning": "nv", + "Niu": "nt", + "Nong": "nl", + "Nou": "nr", + "Nu": "nu", + "Nuan": "ng", + "Nun": "ny", + "Nuo": "no", + "Pa": "pa", + "Pai": "pk", + "Pan": "pj", + "Pang": "ph", + "Pao": "ps", + "Pei": "pw", + "Pen": "pm", + "Peng": "pn", + "Pi": "pi", + "Pian": "pf", + "Piao": "pc", + "Pie": "pp", + "Pin": "pd", + "Ping": "pv", + "Po": "po", + "Pou": "pr", + "Pu": "pu", + "Qi": "qi", + "Qia": "qk", + "Qian": "qf", + "Qiang": "qm", + "Qiao": "qc", + "Qie": "qp", + "Qin": "qd", + "Qing": "qv", + "Qiong": "qj", + "Qiu": "qt", + "Qu": "qu", + "Quan": "qg", + "Que": "qb", + "Qun": "qy", + "Ran": "rj", + "Rang": "rh", + "Rao": "rs", + "Re": "re", + "Ren": "rm", + "Reng": "rn", + "Ri": "ri", + "Rong": "rl", + "Rou": "rr", + "Ru": "ru", + "Rua": "rf", + "Ruan": "rg", + "Rui": "rd", + "Run": "ry", + "Ruo": "ro", + "Sa": "sa", + "Sai": "sk", + "San": "sj", + "Sang": "sh", + "Sao": "ss", + "Se": "se", + "Sen": "sm", + "Seng": "sn", + "Sha": "va", + "Shai": "vk", + "Shan": "vj", + "Shang": "vh", + "Shao": "vs", + "She": "ve", + "Shei": "vw", + "Shen": "vm", + "Sheng": "vn", + "Shi": "vi", + "Shou": "vr", + "Shu": "vu", + "Shua": "vf", + "Shuai": "vv", + "Shuan": "vg", + "Shuang": "vz", + "Shui": "vd", + "Shun": "vy", + "Shuo": "vo", + "Si": "si", + "Song": "sl", + "Sou": "sr", + "Su": "su", + "Suan": "sg", + "Sui": "sd", + "Sun": "sy", + "Suo": "so", + "Ta": "ta", + "Tai": "tk", + "Tan": "tj", + "Tang": "th", + "Tao": "ts", + "Te": "te", + "Tei": "tw", + "Teng": "tn", + "Ti": "ti", + "Tian": "tf", + "Tiao": "tc", + "Tie": "tp", + "Ting": "tv", + "Tong": "tl", + "Tou": "tr", + "Tu": "tu", + "Tuan": "tg", + "Tui": "td", + "Tun": "ty", + "Tuo": "to", + "Xi": "xi", + "Xia": "xk", + "Xian": "xf", + "Xiang": "xm", + "Xiao": "xc", + "Xie": "xp", + "Xin": "xd", + "Xing": "xv", + "Xiong": "xj", + "Xiu": "xt", + "Xu": "xu", + "Xuan": "xg", + "Xue": "xb", + "Xun": "xy", + "Za": "za", + "Zai": "zk", + "Zan": "zj", + "Zang": "zh", + "Zao": "zs", + "Ze": "ze", + "Zei": "zw", + "Zen": "zm", + "Zeng": "zn", + "Zha": "ea", + "Zhai": "ek", + "Zhan": "ej", + "Zhang": "eh", + "Zhao": "es", + "Zhe": "ee", + "Zhen": "em", + "Zheng": "en", + "Zhi": "ei", + "Zhong": "el", + "Zhou": "er", + "Zhu": "eu", + "Zhua": "ef", + "Zhuai": "ev", + "Zhuan": "eg", + "Zhuang": "ez", + "Zhui": "ed", + "Zhun": "ey", + "Zhuo": "eo", + "Zi": "zi", + "Zong": "zl", + "Zou": "zr", + "Zu": "zu", + "Zuan": "zg", + "Zui": "zd", + "Zun": "zy", + "Zuo": "zo" + } +} \ No newline at end of file From 31cd8949fee2d156f16aaf45cb6e50cfac150e7c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 14 Jun 2025 14:39:01 +0800 Subject: [PATCH 083/545] Compress json --- Flow.Launcher/Resources/double_pinyin.json | 3747 +------------------- 1 file changed, 1 insertion(+), 3746 deletions(-) diff --git a/Flow.Launcher/Resources/double_pinyin.json b/Flow.Launcher/Resources/double_pinyin.json index 6b8ae06c0..83972038f 100644 --- a/Flow.Launcher/Resources/double_pinyin.json +++ b/Flow.Launcher/Resources/double_pinyin.json @@ -1,3746 +1 @@ -{ - "XiaoHe": { - "Lv": "lv", - "Lve": "lt", - "Lue": "lt", - "Nv": "nv", - "Nve": "nt", - "Nue": "nt", - "A": "aa", - "O": "oo", - "E": "ee", - "Ai": "ai", - "Ei": "ei", - "Ao": "ao", - "Ou": "ou", - "An": "an", - "En": "en", - "Ang": "ah", - "Eng": "eg", - "Er": "er", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "yc", - "You": "yz", - "Yan": "yj", - "Yin": "yb", - "Yang": "yh", - "Ying": "yk", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wd", - "Wei": "ww", - "Wan": "wj", - "Wen": "wf", - "Wang": "wh", - "Weng": "wg", - "Yu": "yu", - "Yue": "yt", - "Yuan": "yr", - "Yun": "yy", - "Yong": "ys", - "Ba": "ba", - "Bai": "bd", - "Ban": "bj", - "Bang": "bh", - "Bao": "bc", - "Bei": "bw", - "Ben": "bf", - "Beng": "bg", - "Bi": "bi", - "Bian": "bm", - "Biang": "bl", - "Biao": "bn", - "Bie": "bp", - "Bin": "bb", - "Bing": "bk", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cd", - "Can": "cj", - "Cang": "ch", - "Cao": "cc", - "Ce": "ce", - "Cen": "cf", - "Ceng": "cg", - "Cha": "ia", - "Chai": "id", - "Chan": "ij", - "Chang": "ih", - "Chao": "ic", - "Che": "ie", - "Chen": "if", - "Cheng": "ig", - "Chi": "ii", - "Chong": "is", - "Chou": "iz", - "Chu": "iu", - "Chua": "ix", - "Chuai": "ik", - "Chuan": "ir", - "Chuang": "il", - "Chui": "iv", - "Chun": "iy", - "Chuo": "io", - "Ci": "ci", - "Cong": "cs", - "Cou": "cz", - "Cu": "cu", - "Cuan": "cr", - "Cui": "cv", - "Cun": "cy", - "Cuo": "co", - "Da": "da", - "Dai": "dd", - "Dan": "dj", - "Dang": "dh", - "Dao": "dc", - "De": "de", - "Dei": "dw", - "Den": "df", - "Deng": "dg", - "Di": "di", - "Dia": "dx", - "Dian": "dm", - "Diao": "dn", - "Die": "dp", - "Ding": "dk", - "Diu": "dq", - "Dong": "ds", - "Dou": "dz", - "Du": "du", - "Duan": "dr", - "Dui": "dv", - "Dun": "dy", - "Duo": "do", - "Fa": "fa", - "Fan": "fj", - "Fang": "fh", - "Fei": "fw", - "Fen": "ff", - "Feng": "fg", - "Fiao": "fn", - "Fo": "fo", - "Fou": "fz", - "Fu": "fu", - "Ga": "ga", - "Gai": "gd", - "Gan": "gj", - "Gang": "gh", - "Gao": "gc", - "Ge": "ge", - "Gei": "gw", - "Gen": "gf", - "Geng": "gg", - "Gong": "gs", - "Gou": "gz", - "Gu": "gu", - "Gua": "gx", - "Guai": "gk", - "Guan": "gr", - "Guang": "gl", - "Gui": "gv", - "Gun": "gy", - "Guo": "go", - "Ha": "ha", - "Hai": "hd", - "Han": "hj", - "Hang": "hh", - "Hao": "hc", - "He": "he", - "Hei": "hw", - "Hen": "hf", - "Heng": "hg", - "Hong": "hs", - "Hou": "hz", - "Hu": "hu", - "Hua": "hx", - "Huai": "hk", - "Huan": "hr", - "Huang": "hl", - "Hui": "hv", - "Hun": "hy", - "Huo": "ho", - "Ji": "ji", - "Jia": "jx", - "Jian": "jm", - "Jiang": "jl", - "Jiao": "jn", - "Jie": "jp", - "Jin": "jb", - "Jing": "jk", - "Jiong": "js", - "Jiu": "jq", - "Ju": "ju", - "Juan": "jr", - "Jue": "jt", - "Jun": "jy", - "Ka": "ka", - "Kai": "kd", - "Kan": "kj", - "Kang": "kh", - "Kao": "kc", - "Ke": "ke", - "Ken": "kf", - "Keng": "kg", - "Kong": "ks", - "Kou": "kz", - "Ku": "ku", - "Kua": "kx", - "Kuai": "kk", - "Kuan": "kr", - "Kuang": "kl", - "Kui": "kv", - "Kun": "ky", - "Kuo": "ko", - "La": "la", - "Lai": "ld", - "Lan": "lj", - "Lang": "lh", - "Lao": "lc", - "Le": "le", - "Lei": "lw", - "Leng": "lg", - "Li": "li", - "Lia": "lx", - "Lian": "lm", - "Liang": "ll", - "Liao": "ln", - "Lie": "lp", - "Lin": "lb", - "Ling": "lk", - "Liu": "lq", - "Lo": "lo", - "Long": "ls", - "Lou": "lz", - "Lu": "lu", - "Luan": "lr", - "Lun": "ly", - "Luo": "lo", - "Ma": "ma", - "Mai": "md", - "Man": "mj", - "Mang": "mh", - "Mao": "mc", - "Me": "me", - "Mei": "mw", - "Men": "mf", - "Meng": "mg", - "Mi": "mi", - "Mian": "mm", - "Miao": "mn", - "Mie": "mp", - "Min": "mb", - "Ming": "mk", - "Miu": "mq", - "Mo": "mo", - "Mou": "mz", - "Mu": "mu", - "Na": "na", - "Nai": "nd", - "Nan": "nj", - "Nang": "nh", - "Nao": "nc", - "Ne": "ne", - "Nei": "nw", - "Nen": "nf", - "Neng": "ng", - "Ni": "ni", - "Nian": "nm", - "Niang": "nl", - "Niao": "nn", - "Nie": "np", - "Nin": "nb", - "Ning": "nk", - "Niu": "nq", - "Nong": "ns", - "Nou": "nz", - "Nu": "nu", - "Nuan": "nr", - "Nun": "ny", - "Nuo": "no", - "Pa": "pa", - "Pai": "pd", - "Pan": "pj", - "Pang": "ph", - "Pao": "pc", - "Pei": "pw", - "Pen": "pf", - "Peng": "pg", - "Pi": "pi", - "Pian": "pm", - "Piao": "pn", - "Pie": "pp", - "Pin": "pb", - "Ping": "pk", - "Po": "po", - "Pou": "pz", - "Pu": "pu", - "Qi": "qi", - "Qia": "qx", - "Qian": "qm", - "Qiang": "ql", - "Qiao": "qn", - "Qie": "qp", - "Qin": "qb", - "Qing": "qk", - "Qiong": "qs", - "Qiu": "qq", - "Qu": "qu", - "Quan": "qr", - "Que": "qt", - "Qun": "qy", - "Ran": "rj", - "Rang": "rh", - "Rao": "rc", - "Re": "re", - "Ren": "rf", - "Reng": "rg", - "Ri": "ri", - "Rong": "rs", - "Rou": "rz", - "Ru": "ru", - "Rua": "rx", - "Ruan": "rr", - "Rui": "rv", - "Run": "ry", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sd", - "San": "sj", - "Sang": "sh", - "Sao": "sc", - "Se": "se", - "Sen": "sf", - "Seng": "sg", - "Sha": "ua", - "Shai": "ud", - "Shan": "uj", - "Shang": "uh", - "Shao": "uc", - "She": "ue", - "Shei": "uw", - "Shen": "uf", - "Sheng": "ug", - "Shi": "ui", - "Shou": "uz", - "Shu": "uu", - "Shua": "ux", - "Shuai": "uk", - "Shuan": "ur", - "Shuang": "ul", - "Shui": "uv", - "Shun": "uy", - "Shuo": "uo", - "Si": "si", - "Song": "ss", - "Sou": "sz", - "Su": "su", - "Suan": "sr", - "Sui": "sv", - "Sun": "sy", - "Suo": "so", - "Ta": "ta", - "Tai": "td", - "Tan": "tj", - "Tang": "th", - "Tao": "tc", - "Te": "te", - "Tei": "tw", - "Teng": "tg", - "Ti": "ti", - "Tian": "tm", - "Tiao": "tn", - "Tie": "tp", - "Ting": "tk", - "Tong": "ts", - "Tou": "tz", - "Tu": "tu", - "Tuan": "tr", - "Tui": "tv", - "Tun": "ty", - "Tuo": "to", - "Xi": "xi", - "Xia": "xx", - "Xian": "xm", - "Xiang": "xl", - "Xiao": "xn", - "Xie": "xp", - "Xin": "xb", - "Xing": "xk", - "Xiong": "xs", - "Xiu": "xq", - "Xu": "xu", - "Xuan": "xr", - "Xue": "xt", - "Xun": "xy", - "Za": "za", - "Zai": "zd", - "Zan": "zj", - "Zang": "zh", - "Zao": "zc", - "Ze": "ze", - "Zei": "zw", - "Zen": "zf", - "Zeng": "zg", - "Zha": "va", - "Zhai": "vd", - "Zhan": "vj", - "Zhang": "vh", - "Zhao": "vc", - "Zhe": "ve", - "Zhen": "vf", - "Zheng": "vg", - "Zhi": "vi", - "Zhong": "vs", - "Zhou": "vz", - "Zhu": "vu", - "Zhua": "vx", - "Zhuai": "vk", - "Zhuan": "vr", - "Zhuang": "vl", - "Zhui": "vv", - "Zhun": "vy", - "Zhuo": "vo", - "Zi": "zi", - "Zong": "zs", - "Zou": "zz", - "Zu": "zu", - "Zuan": "zr", - "Zui": "zv", - "Zun": "zy", - "Zuo": "zo" - }, - "ZiRanMa": { - "Lv": "lv", - "Lve": "lt", - "Lue": "lt", - "Nv": "nv", - "Nve": "nt", - "Nue": "nt", - "A": "aa", - "O": "oo", - "E": "ee", - "Ai": "ai", - "Ei": "ei", - "Ao": "ao", - "Ou": "ou", - "An": "an", - "En": "en", - "Ang": "ah", - "Eng": "eg", - "Er": "er", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "yk", - "You": "yb", - "Yan": "yj", - "Yin": "yn", - "Yang": "yh", - "Ying": "yy", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wl", - "Wei": "wz", - "Wan": "wj", - "Wen": "wf", - "Wang": "wh", - "Weng": "wg", - "Yu": "yu", - "Yue": "yt", - "Yuan": "yr", - "Yun": "yp", - "Yong": "ys", - "Ba": "ba", - "Bai": "bl", - "Ban": "bj", - "Bang": "bh", - "Bao": "bk", - "Bei": "bz", - "Ben": "bf", - "Beng": "bg", - "Bi": "bi", - "Bian": "bm", - "Biang": "bd", - "Biao": "bc", - "Bie": "bx", - "Bin": "bn", - "Bing": "by", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cl", - "Can": "cj", - "Cang": "ch", - "Cao": "ck", - "Ce": "ce", - "Cen": "cf", - "Ceng": "cg", - "Cha": "ia", - "Chai": "il", - "Chan": "ij", - "Chang": "ih", - "Chao": "ik", - "Che": "ie", - "Chen": "if", - "Cheng": "ig", - "Chi": "ii", - "Chong": "is", - "Chou": "ib", - "Chu": "iu", - "Chua": "iw", - "Chuai": "iy", - "Chuan": "ir", - "Chuang": "id", - "Chui": "iv", - "Chun": "ip", - "Chuo": "io", - "Ci": "ci", - "Cong": "cs", - "Cou": "cb", - "Cu": "cu", - "Cuan": "cr", - "Cui": "cv", - "Cun": "cp", - "Cuo": "co", - "Da": "da", - "Dai": "dl", - "Dan": "dj", - "Dang": "dh", - "Dao": "dk", - "De": "de", - "Dei": "dz", - "Den": "df", - "Deng": "dg", - "Di": "di", - "Dia": "dw", - "Dian": "dm", - "Diao": "dc", - "Die": "dx", - "Ding": "dy", - "Diu": "dq", - "Dong": "ds", - "Dou": "db", - "Du": "du", - "Duan": "dr", - "Dui": "dv", - "Dun": "dp", - "Duo": "do", - "Fa": "fa", - "Fan": "fj", - "Fang": "fh", - "Fei": "fz", - "Fen": "ff", - "Feng": "fg", - "Fiao": "fc", - "Fo": "fo", - "Fou": "fb", - "Fu": "fu", - "Ga": "ga", - "Gai": "gl", - "Gan": "gj", - "Gang": "gh", - "Gao": "gk", - "Ge": "ge", - "Gei": "gz", - "Gen": "gf", - "Geng": "gg", - "Gong": "gs", - "Gou": "gb", - "Gu": "gu", - "Gua": "gw", - "Guai": "gy", - "Guan": "gr", - "Guang": "gd", - "Gui": "gv", - "Gun": "gp", - "Guo": "go", - "Ha": "ha", - "Hai": "hl", - "Han": "hj", - "Hang": "hh", - "Hao": "hk", - "He": "he", - "Hei": "hz", - "Hen": "hf", - "Heng": "hg", - "Hong": "hs", - "Hou": "hb", - "Hu": "hu", - "Hua": "hw", - "Huai": "hy", - "Huan": "hr", - "Huang": "hd", - "Hui": "hv", - "Hun": "hp", - "Huo": "ho", - "Ji": "ji", - "Jia": "jw", - "Jian": "jm", - "Jiang": "jd", - "Jiao": "jc", - "Jie": "jx", - "Jin": "jn", - "Jing": "jy", - "Jiong": "js", - "Jiu": "jq", - "Ju": "ju", - "Juan": "jr", - "Jue": "jt", - "Jun": "jp", - "Ka": "ka", - "Kai": "kl", - "Kan": "kj", - "Kang": "kh", - "Kao": "kk", - "Ke": "ke", - "Ken": "kf", - "Keng": "kg", - "Kong": "ks", - "Kou": "kb", - "Ku": "ku", - "Kua": "kw", - "Kuai": "ky", - "Kuan": "kr", - "Kuang": "kd", - "Kui": "kv", - "Kun": "kp", - "Kuo": "ko", - "La": "la", - "Lai": "ll", - "Lan": "lj", - "Lang": "lh", - "Lao": "lk", - "Le": "le", - "Lei": "lz", - "Leng": "lg", - "Li": "li", - "Lia": "lw", - "Lian": "lm", - "Liang": "ld", - "Liao": "lc", - "Lie": "lx", - "Lin": "ln", - "Ling": "ly", - "Liu": "lq", - "Lo": "lo", - "Long": "ls", - "Lou": "lb", - "Lu": "lu", - "Luan": "lr", - "Lun": "lp", - "Luo": "lo", - "Ma": "ma", - "Mai": "ml", - "Man": "mj", - "Mang": "mh", - "Mao": "mk", - "Me": "me", - "Mei": "mz", - "Men": "mf", - "Meng": "mg", - "Mi": "mi", - "Mian": "mm", - "Miao": "mc", - "Mie": "mx", - "Min": "mn", - "Ming": "my", - "Miu": "mq", - "Mo": "mo", - "Mou": "mb", - "Mu": "mu", - "Na": "na", - "Nai": "nl", - "Nan": "nj", - "Nang": "nh", - "Nao": "nk", - "Ne": "ne", - "Nei": "nz", - "Nen": "nf", - "Neng": "ng", - "Ni": "ni", - "Nian": "nm", - "Niang": "nd", - "Niao": "nc", - "Nie": "nx", - "Nin": "nn", - "Ning": "ny", - "Niu": "nq", - "Nong": "ns", - "Nou": "nb", - "Nu": "nu", - "Nuan": "nr", - "Nun": "np", - "Nuo": "no", - "Pa": "pa", - "Pai": "pl", - "Pan": "pj", - "Pang": "ph", - "Pao": "pk", - "Pei": "pz", - "Pen": "pf", - "Peng": "pg", - "Pi": "pi", - "Pian": "pm", - "Piao": "pc", - "Pie": "px", - "Pin": "pn", - "Ping": "py", - "Po": "po", - "Pou": "pb", - "Pu": "pu", - "Qi": "qi", - "Qia": "qw", - "Qian": "qm", - "Qiang": "qd", - "Qiao": "qc", - "Qie": "qx", - "Qin": "qn", - "Qing": "qy", - "Qiong": "qs", - "Qiu": "qq", - "Qu": "qu", - "Quan": "qr", - "Que": "qt", - "Qun": "qp", - "Ran": "rj", - "Rang": "rh", - "Rao": "rk", - "Re": "re", - "Ren": "rf", - "Reng": "rg", - "Ri": "ri", - "Rong": "rs", - "Rou": "rb", - "Ru": "ru", - "Rua": "rw", - "Ruan": "rr", - "Rui": "rv", - "Run": "rp", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sl", - "San": "sj", - "Sang": "sh", - "Sao": "sk", - "Se": "se", - "Sen": "sf", - "Seng": "sg", - "Sha": "ua", - "Shai": "ul", - "Shan": "uj", - "Shang": "uh", - "Shao": "uk", - "She": "ue", - "Shei": "uz", - "Shen": "uf", - "Sheng": "ug", - "Shi": "ui", - "Shou": "ub", - "Shu": "uu", - "Shua": "uw", - "Shuai": "uy", - "Shuan": "ur", - "Shuang": "ud", - "Shui": "uv", - "Shun": "up", - "Shuo": "uo", - "Si": "si", - "Song": "ss", - "Sou": "sb", - "Su": "su", - "Suan": "sr", - "Sui": "sv", - "Sun": "sp", - "Suo": "so", - "Ta": "ta", - "Tai": "tl", - "Tan": "tj", - "Tang": "th", - "Tao": "tk", - "Te": "te", - "Tei": "tz", - "Teng": "tg", - "Ti": "ti", - "Tian": "tm", - "Tiao": "tc", - "Tie": "tx", - "Ting": "ty", - "Tong": "ts", - "Tou": "tb", - "Tu": "tu", - "Tuan": "tr", - "Tui": "tv", - "Tun": "tp", - "Tuo": "to", - "Xi": "xi", - "Xia": "xw", - "Xian": "xm", - "Xiang": "xd", - "Xiao": "xc", - "Xie": "xx", - "Xin": "xn", - "Xing": "xy", - "Xiong": "xs", - "Xiu": "xq", - "Xu": "xu", - "Xuan": "xr", - "Xue": "xt", - "Xun": "xp", - "Za": "za", - "Zai": "zl", - "Zan": "zj", - "Zang": "zh", - "Zao": "zk", - "Ze": "ze", - "Zei": "zz", - "Zen": "zf", - "Zeng": "zg", - "Zha": "va", - "Zhai": "vl", - "Zhan": "vj", - "Zhang": "vh", - "Zhao": "vk", - "Zhe": "ve", - "Zhen": "vf", - "Zheng": "vg", - "Zhi": "vi", - "Zhong": "vs", - "Zhou": "vb", - "Zhu": "vu", - "Zhua": "vw", - "Zhuai": "vy", - "Zhuan": "vr", - "Zhuang": "vd", - "Zhui": "vv", - "Zhun": "vp", - "Zhuo": "vo", - "Zi": "zi", - "Zong": "zs", - "Zou": "zb", - "Zu": "zu", - "Zuan": "zr", - "Zui": "zv", - "Zun": "zp", - "Zuo": "zo" - }, - "WeiRuan": { - "Lv": "ly", - "Lve": "lt", - "Lue": "lt", - "Nv": "ny", - "Nve": "nt", - "Nue": "nt", - "A": "oa", - "O": "oo", - "E": "oe", - "Ai": "ol", - "Ei": "oz", - "Ao": "ok", - "Ou": "ob", - "An": "oj", - "En": "of", - "Ang": "oh", - "Eng": "og", - "Er": "or", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "yk", - "You": "yb", - "Yan": "yj", - "Yin": "yn", - "Yang": "yh", - "Ying": "y;", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wl", - "Wei": "wz", - "Wan": "wj", - "Wen": "wf", - "Wang": "wh", - "Weng": "wg", - "Yu": "yu", - "Yue": "yt", - "Yuan": "yr", - "Yun": "yp", - "Yong": "ys", - "Ba": "ba", - "Bai": "bl", - "Ban": "bj", - "Bang": "bh", - "Bao": "bk", - "Bei": "bz", - "Ben": "bf", - "Beng": "bg", - "Bi": "bi", - "Bian": "bm", - "Biang": "bd", - "Biao": "bc", - "Bie": "bx", - "Bin": "bn", - "Bing": "b;", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cl", - "Can": "cj", - "Cang": "ch", - "Cao": "ck", - "Ce": "ce", - "Cen": "cf", - "Ceng": "cg", - "Cha": "ia", - "Chai": "il", - "Chan": "ij", - "Chang": "ih", - "Chao": "ik", - "Che": "ie", - "Chen": "if", - "Cheng": "ig", - "Chi": "ii", - "Chong": "is", - "Chou": "ib", - "Chu": "iu", - "Chua": "iw", - "Chuai": "iy", - "Chuan": "ir", - "Chuang": "id", - "Chui": "iv", - "Chun": "ip", - "Chuo": "io", - "Ci": "ci", - "Cong": "cs", - "Cou": "cb", - "Cu": "cu", - "Cuan": "cr", - "Cui": "cv", - "Cun": "cp", - "Cuo": "co", - "Da": "da", - "Dai": "dl", - "Dan": "dj", - "Dang": "dh", - "Dao": "dk", - "De": "de", - "Dei": "dz", - "Den": "df", - "Deng": "dg", - "Di": "di", - "Dia": "dw", - "Dian": "dm", - "Diao": "dc", - "Die": "dx", - "Ding": "d;", - "Diu": "dq", - "Dong": "ds", - "Dou": "db", - "Du": "du", - "Duan": "dr", - "Dui": "dv", - "Dun": "dp", - "Duo": "do", - "Fa": "fa", - "Fan": "fj", - "Fang": "fh", - "Fei": "fz", - "Fen": "ff", - "Feng": "fg", - "Fiao": "fc", - "Fo": "fo", - "Fou": "fb", - "Fu": "fu", - "Ga": "ga", - "Gai": "gl", - "Gan": "gj", - "Gang": "gh", - "Gao": "gk", - "Ge": "ge", - "Gei": "gz", - "Gen": "gf", - "Geng": "gg", - "Gong": "gs", - "Gou": "gb", - "Gu": "gu", - "Gua": "gw", - "Guai": "gy", - "Guan": "gr", - "Guang": "gd", - "Gui": "gv", - "Gun": "gp", - "Guo": "go", - "Ha": "ha", - "Hai": "hl", - "Han": "hj", - "Hang": "hh", - "Hao": "hk", - "He": "he", - "Hei": "hz", - "Hen": "hf", - "Heng": "hg", - "Hong": "hs", - "Hou": "hb", - "Hu": "hu", - "Hua": "hw", - "Huai": "hy", - "Huan": "hr", - "Huang": "hd", - "Hui": "hv", - "Hun": "hp", - "Huo": "ho", - "Ji": "ji", - "Jia": "jw", - "Jian": "jm", - "Jiang": "jd", - "Jiao": "jc", - "Jie": "jx", - "Jin": "jn", - "Jing": "j;", - "Jiong": "js", - "Jiu": "jq", - "Ju": "ju", - "Juan": "jr", - "Jue": "jt", - "Jun": "jp", - "Ka": "ka", - "Kai": "kl", - "Kan": "kj", - "Kang": "kh", - "Kao": "kk", - "Ke": "ke", - "Ken": "kf", - "Keng": "kg", - "Kong": "ks", - "Kou": "kb", - "Ku": "ku", - "Kua": "kw", - "Kuai": "ky", - "Kuan": "kr", - "Kuang": "kd", - "Kui": "kv", - "Kun": "kp", - "Kuo": "ko", - "La": "la", - "Lai": "ll", - "Lan": "lj", - "Lang": "lh", - "Lao": "lk", - "Le": "le", - "Lei": "lz", - "Leng": "lg", - "Li": "li", - "Lia": "lw", - "Lian": "lm", - "Liang": "ld", - "Liao": "lc", - "Lie": "lx", - "Lin": "ln", - "Ling": "l;", - "Liu": "lq", - "Lo": "lo", - "Long": "ls", - "Lou": "lb", - "Lu": "lu", - "Luan": "lr", - "Lun": "lp", - "Luo": "lo", - "Ma": "ma", - "Mai": "ml", - "Man": "mj", - "Mang": "mh", - "Mao": "mk", - "Me": "me", - "Mei": "mz", - "Men": "mf", - "Meng": "mg", - "Mi": "mi", - "Mian": "mm", - "Miao": "mc", - "Mie": "mx", - "Min": "mn", - "Ming": "m;", - "Miu": "mq", - "Mo": "mo", - "Mou": "mb", - "Mu": "mu", - "Na": "na", - "Nai": "nl", - "Nan": "nj", - "Nang": "nh", - "Nao": "nk", - "Ne": "ne", - "Nei": "nz", - "Nen": "nf", - "Neng": "ng", - "Ni": "ni", - "Nian": "nm", - "Niang": "nd", - "Niao": "nc", - "Nie": "nx", - "Nin": "nn", - "Ning": "n;", - "Niu": "nq", - "Nong": "ns", - "Nou": "nb", - "Nu": "nu", - "Nuan": "nr", - "Nun": "np", - "Nuo": "no", - "Pa": "pa", - "Pai": "pl", - "Pan": "pj", - "Pang": "ph", - "Pao": "pk", - "Pei": "pz", - "Pen": "pf", - "Peng": "pg", - "Pi": "pi", - "Pian": "pm", - "Piao": "pc", - "Pie": "px", - "Pin": "pn", - "Ping": "p;", - "Po": "po", - "Pou": "pb", - "Pu": "pu", - "Qi": "qi", - "Qia": "qw", - "Qian": "qm", - "Qiang": "qd", - "Qiao": "qc", - "Qie": "qx", - "Qin": "qn", - "Qing": "q;", - "Qiong": "qs", - "Qiu": "qq", - "Qu": "qu", - "Quan": "qr", - "Que": "qt", - "Qun": "qp", - "Ran": "rj", - "Rang": "rh", - "Rao": "rk", - "Re": "re", - "Ren": "rf", - "Reng": "rg", - "Ri": "ri", - "Rong": "rs", - "Rou": "rb", - "Ru": "ru", - "Rua": "rw", - "Ruan": "rr", - "Rui": "rv", - "Run": "rp", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sl", - "San": "sj", - "Sang": "sh", - "Sao": "sk", - "Se": "se", - "Sen": "sf", - "Seng": "sg", - "Sha": "ua", - "Shai": "ul", - "Shan": "uj", - "Shang": "uh", - "Shao": "uk", - "She": "ue", - "Shei": "uz", - "Shen": "uf", - "Sheng": "ug", - "Shi": "ui", - "Shou": "ub", - "Shu": "uu", - "Shua": "uw", - "Shuai": "uy", - "Shuan": "ur", - "Shuang": "ud", - "Shui": "uv", - "Shun": "up", - "Shuo": "uo", - "Si": "si", - "Song": "ss", - "Sou": "sb", - "Su": "su", - "Suan": "sr", - "Sui": "sv", - "Sun": "sp", - "Suo": "so", - "Ta": "ta", - "Tai": "tl", - "Tan": "tj", - "Tang": "th", - "Tao": "tk", - "Te": "te", - "Tei": "tz", - "Teng": "tg", - "Ti": "ti", - "Tian": "tm", - "Tiao": "tc", - "Tie": "tx", - "Ting": "t;", - "Tong": "ts", - "Tou": "tb", - "Tu": "tu", - "Tuan": "tr", - "Tui": "tv", - "Tun": "tp", - "Tuo": "to", - "Xi": "xi", - "Xia": "xw", - "Xian": "xm", - "Xiang": "xd", - "Xiao": "xc", - "Xie": "xx", - "Xin": "xn", - "Xing": "x;", - "Xiong": "xs", - "Xiu": "xq", - "Xu": "xu", - "Xuan": "xr", - "Xue": "xt", - "Xun": "xp", - "Za": "za", - "Zai": "zl", - "Zan": "zj", - "Zang": "zh", - "Zao": "zk", - "Ze": "ze", - "Zei": "zz", - "Zen": "zf", - "Zeng": "zg", - "Zha": "va", - "Zhai": "vl", - "Zhan": "vj", - "Zhang": "vh", - "Zhao": "vk", - "Zhe": "ve", - "Zhen": "vf", - "Zheng": "vg", - "Zhi": "vi", - "Zhong": "vs", - "Zhou": "vb", - "Zhu": "vu", - "Zhua": "vw", - "Zhuai": "vy", - "Zhuan": "vr", - "Zhuang": "vd", - "Zhui": "vv", - "Zhun": "vp", - "Zhuo": "vo", - "Zi": "zi", - "Zong": "zs", - "Zou": "zb", - "Zu": "zu", - "Zuan": "zr", - "Zui": "zv", - "Zun": "zp", - "Zuo": "zo" - }, - "ZhiNengABC": { - "Lv": "lv", - "Lve": "lm", - "Lue": "lm", - "Nv": "nv", - "Nve": "nm", - "Nue": "nm", - "A": "oa", - "O": "oo", - "E": "oe", - "Ai": "ol", - "Ei": "oq", - "Ao": "ok", - "Ou": "ob", - "An": "oj", - "En": "of", - "Ang": "oh", - "Eng": "og", - "Er": "or", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "yk", - "You": "yb", - "Yan": "yj", - "Yin": "yc", - "Yang": "yh", - "Ying": "yy", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wl", - "Wei": "wq", - "Wan": "wj", - "Wen": "wf", - "Wang": "wh", - "Weng": "wg", - "Yu": "yu", - "Yue": "ym", - "Yuan": "yp", - "Yun": "yn", - "Yong": "ys", - "Ba": "ba", - "Bai": "bl", - "Ban": "bj", - "Bang": "bh", - "Bao": "bk", - "Bei": "bq", - "Ben": "bf", - "Beng": "bg", - "Bi": "bi", - "Bian": "bw", - "Biang": "bt", - "Biao": "bz", - "Bie": "bx", - "Bin": "bc", - "Bing": "by", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cl", - "Can": "cj", - "Cang": "ch", - "Cao": "ck", - "Ce": "ce", - "Cen": "cf", - "Ceng": "cg", - "Cha": "ea", - "Chai": "el", - "Chan": "ej", - "Chang": "eh", - "Chao": "ek", - "Che": "ee", - "Chen": "ef", - "Cheng": "eg", - "Chi": "ei", - "Chong": "es", - "Chou": "eb", - "Chu": "eu", - "Chua": "ed", - "Chuai": "ec", - "Chuan": "ep", - "Chuang": "et", - "Chui": "em", - "Chun": "en", - "Chuo": "eo", - "Ci": "ci", - "Cong": "cs", - "Cou": "cb", - "Cu": "cu", - "Cuan": "cp", - "Cui": "cm", - "Cun": "cn", - "Cuo": "co", - "Da": "da", - "Dai": "dl", - "Dan": "dj", - "Dang": "dh", - "Dao": "dk", - "De": "de", - "Dei": "dq", - "Den": "df", - "Deng": "dg", - "Di": "di", - "Dia": "dd", - "Dian": "dw", - "Diao": "dz", - "Die": "dx", - "Ding": "dy", - "Diu": "dr", - "Dong": "ds", - "Dou": "db", - "Du": "du", - "Duan": "dp", - "Dui": "dm", - "Dun": "dn", - "Duo": "do", - "Fa": "fa", - "Fan": "fj", - "Fang": "fh", - "Fei": "fq", - "Fen": "ff", - "Feng": "fg", - "Fiao": "fz", - "Fo": "fo", - "Fou": "fb", - "Fu": "fu", - "Ga": "ga", - "Gai": "gl", - "Gan": "gj", - "Gang": "gh", - "Gao": "gk", - "Ge": "ge", - "Gei": "gq", - "Gen": "gf", - "Geng": "gg", - "Gong": "gs", - "Gou": "gb", - "Gu": "gu", - "Gua": "gd", - "Guai": "gc", - "Guan": "gp", - "Guang": "gt", - "Gui": "gm", - "Gun": "gn", - "Guo": "go", - "Ha": "ha", - "Hai": "hl", - "Han": "hj", - "Hang": "hh", - "Hao": "hk", - "He": "he", - "Hei": "hq", - "Hen": "hf", - "Heng": "hg", - "Hong": "hs", - "Hou": "hb", - "Hu": "hu", - "Hua": "hd", - "Huai": "hc", - "Huan": "hp", - "Huang": "ht", - "Hui": "hm", - "Hun": "hn", - "Huo": "ho", - "Ji": "ji", - "Jia": "jd", - "Jian": "jw", - "Jiang": "jt", - "Jiao": "jz", - "Jie": "jx", - "Jin": "jc", - "Jing": "jy", - "Jiong": "js", - "Jiu": "jr", - "Ju": "ju", - "Juan": "jp", - "Jue": "jm", - "Jun": "jn", - "Ka": "ka", - "Kai": "kl", - "Kan": "kj", - "Kang": "kh", - "Kao": "kk", - "Ke": "ke", - "Ken": "kf", - "Keng": "kg", - "Kong": "ks", - "Kou": "kb", - "Ku": "ku", - "Kua": "kd", - "Kuai": "kc", - "Kuan": "kp", - "Kuang": "kt", - "Kui": "km", - "Kun": "kn", - "Kuo": "ko", - "La": "la", - "Lai": "ll", - "Lan": "lj", - "Lang": "lh", - "Lao": "lk", - "Le": "le", - "Lei": "lq", - "Leng": "lg", - "Li": "li", - "Lia": "ld", - "Lian": "lw", - "Liang": "lt", - "Liao": "lz", - "Lie": "lx", - "Lin": "lc", - "Ling": "ly", - "Liu": "lr", - "Lo": "lo", - "Long": "ls", - "Lou": "lb", - "Lu": "lu", - "Luan": "lp", - "Lun": "ln", - "Luo": "lo", - "Ma": "ma", - "Mai": "ml", - "Man": "mj", - "Mang": "mh", - "Mao": "mk", - "Me": "me", - "Mei": "mq", - "Men": "mf", - "Meng": "mg", - "Mi": "mi", - "Mian": "mw", - "Miao": "mz", - "Mie": "mx", - "Min": "mc", - "Ming": "my", - "Miu": "mr", - "Mo": "mo", - "Mou": "mb", - "Mu": "mu", - "Na": "na", - "Nai": "nl", - "Nan": "nj", - "Nang": "nh", - "Nao": "nk", - "Ne": "ne", - "Nei": "nq", - "Nen": "nf", - "Neng": "ng", - "Ni": "ni", - "Nian": "nw", - "Niang": "nt", - "Niao": "nz", - "Nie": "nx", - "Nin": "nc", - "Ning": "ny", - "Niu": "nr", - "Nong": "ns", - "Nou": "nb", - "Nu": "nu", - "Nuan": "np", - "Nun": "nn", - "Nuo": "no", - "Pa": "pa", - "Pai": "pl", - "Pan": "pj", - "Pang": "ph", - "Pao": "pk", - "Pei": "pq", - "Pen": "pf", - "Peng": "pg", - "Pi": "pi", - "Pian": "pw", - "Piao": "pz", - "Pie": "px", - "Pin": "pc", - "Ping": "py", - "Po": "po", - "Pou": "pb", - "Pu": "pu", - "Qi": "qi", - "Qia": "qd", - "Qian": "qw", - "Qiang": "qt", - "Qiao": "qz", - "Qie": "qx", - "Qin": "qc", - "Qing": "qy", - "Qiong": "qs", - "Qiu": "qr", - "Qu": "qu", - "Quan": "qp", - "Que": "qm", - "Qun": "qn", - "Ran": "rj", - "Rang": "rh", - "Rao": "rk", - "Re": "re", - "Ren": "rf", - "Reng": "rg", - "Ri": "ri", - "Rong": "rs", - "Rou": "rb", - "Ru": "ru", - "Rua": "rd", - "Ruan": "rp", - "Rui": "rm", - "Run": "rn", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sl", - "San": "sj", - "Sang": "sh", - "Sao": "sk", - "Se": "se", - "Sen": "sf", - "Seng": "sg", - "Sha": "va", - "Shai": "vl", - "Shan": "vj", - "Shang": "vh", - "Shao": "vk", - "She": "ve", - "Shei": "vq", - "Shen": "vf", - "Sheng": "vg", - "Shi": "vi", - "Shou": "vb", - "Shu": "vu", - "Shua": "vd", - "Shuai": "vc", - "Shuan": "vp", - "Shuang": "vt", - "Shui": "vm", - "Shun": "vn", - "Shuo": "vo", - "Si": "si", - "Song": "ss", - "Sou": "sb", - "Su": "su", - "Suan": "sp", - "Sui": "sm", - "Sun": "sn", - "Suo": "so", - "Ta": "ta", - "Tai": "tl", - "Tan": "tj", - "Tang": "th", - "Tao": "tk", - "Te": "te", - "Tei": "tq", - "Teng": "tg", - "Ti": "ti", - "Tian": "tw", - "Tiao": "tz", - "Tie": "tx", - "Ting": "ty", - "Tong": "ts", - "Tou": "tb", - "Tu": "tu", - "Tuan": "tp", - "Tui": "tm", - "Tun": "tn", - "Tuo": "to", - "Xi": "xi", - "Xia": "xd", - "Xian": "xw", - "Xiang": "xt", - "Xiao": "xz", - "Xie": "xx", - "Xin": "xc", - "Xing": "xy", - "Xiong": "xs", - "Xiu": "xr", - "Xu": "xu", - "Xuan": "xp", - "Xue": "xm", - "Xun": "xn", - "Za": "za", - "Zai": "zl", - "Zan": "zj", - "Zang": "zh", - "Zao": "zk", - "Ze": "ze", - "Zei": "zq", - "Zen": "zf", - "Zeng": "zg", - "Zha": "aa", - "Zhai": "al", - "Zhan": "aj", - "Zhang": "ah", - "Zhao": "ak", - "Zhe": "ae", - "Zhen": "af", - "Zheng": "ag", - "Zhi": "ai", - "Zhong": "as", - "Zhou": "ab", - "Zhu": "au", - "Zhua": "ad", - "Zhuai": "ac", - "Zhuan": "ap", - "Zhuang": "at", - "Zhui": "am", - "Zhun": "an", - "Zhuo": "ao", - "Zi": "zi", - "Zong": "zs", - "Zou": "zb", - "Zu": "zu", - "Zuan": "zp", - "Zui": "zm", - "Zun": "zn", - "Zuo": "zo" - }, - "ZiGuangPinYin": { - "Lv": "lv", - "Lve": "ln", - "Lue": "ln", - "Nv": "nv", - "Nve": "nn", - "Nue": "nn", - "A": "oa", - "O": "oo", - "E": "oe", - "Ai": "op", - "Ei": "ok", - "Ao": "oq", - "Ou": "oz", - "An": "or", - "En": "ow", - "Ang": "os", - "Eng": "ot", - "Er": "oj", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "yq", - "You": "yz", - "Yan": "yr", - "Yin": "yy", - "Yang": "ys", - "Ying": "yc", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wp", - "Wei": "wk", - "Wan": "wr", - "Wen": "ww", - "Wang": "ws", - "Weng": "wt", - "Yu": "yu", - "Yue": "yn", - "Yuan": "yl", - "Yun": "ym", - "Yong": "yh", - "Ba": "ba", - "Bai": "bp", - "Ban": "br", - "Bang": "bs", - "Bao": "bq", - "Bei": "bk", - "Ben": "bw", - "Beng": "bt", - "Bi": "bi", - "Bian": "bf", - "Biang": "bg", - "Biao": "bb", - "Bie": "bd", - "Bin": "by", - "Bing": "bc", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cp", - "Can": "cr", - "Cang": "cs", - "Cao": "cq", - "Ce": "ce", - "Cen": "cw", - "Ceng": "ct", - "Cha": "aa", - "Chai": "ap", - "Chan": "ar", - "Chang": "as", - "Chao": "aq", - "Che": "ae", - "Chen": "aw", - "Cheng": "at", - "Chi": "ai", - "Chong": "ah", - "Chou": "az", - "Chu": "au", - "Chua": "ax", - "Chuai": "ay", - "Chuan": "al", - "Chuang": "ag", - "Chui": "an", - "Chun": "am", - "Chuo": "ao", - "Ci": "ci", - "Cong": "ch", - "Cou": "cz", - "Cu": "cu", - "Cuan": "cl", - "Cui": "cn", - "Cun": "cm", - "Cuo": "co", - "Da": "da", - "Dai": "dp", - "Dan": "dr", - "Dang": "ds", - "Dao": "dq", - "De": "de", - "Dei": "dk", - "Den": "dw", - "Deng": "dt", - "Di": "di", - "Dia": "dx", - "Dian": "df", - "Diao": "db", - "Die": "dd", - "Ding": "dc", - "Diu": "dj", - "Dong": "dh", - "Dou": "dz", - "Du": "du", - "Duan": "dl", - "Dui": "dn", - "Dun": "dm", - "Duo": "do", - "Fa": "fa", - "Fan": "fr", - "Fang": "fs", - "Fei": "fk", - "Fen": "fw", - "Feng": "ft", - "Fiao": "fb", - "Fo": "fo", - "Fou": "fz", - "Fu": "fu", - "Ga": "ga", - "Gai": "gp", - "Gan": "gr", - "Gang": "gs", - "Gao": "gq", - "Ge": "ge", - "Gei": "gk", - "Gen": "gw", - "Geng": "gt", - "Gong": "gh", - "Gou": "gz", - "Gu": "gu", - "Gua": "gx", - "Guai": "gy", - "Guan": "gl", - "Guang": "gg", - "Gui": "gn", - "Gun": "gm", - "Guo": "go", - "Ha": "ha", - "Hai": "hp", - "Han": "hr", - "Hang": "hs", - "Hao": "hq", - "He": "he", - "Hei": "hk", - "Hen": "hw", - "Heng": "ht", - "Hong": "hh", - "Hou": "hz", - "Hu": "hu", - "Hua": "hx", - "Huai": "hy", - "Huan": "hl", - "Huang": "hg", - "Hui": "hn", - "Hun": "hm", - "Huo": "ho", - "Ji": "ji", - "Jia": "jx", - "Jian": "jf", - "Jiang": "jg", - "Jiao": "jb", - "Jie": "jd", - "Jin": "jy", - "Jing": "jc", - "Jiong": "jh", - "Jiu": "jj", - "Ju": "ju", - "Juan": "jl", - "Jue": "jn", - "Jun": "jm", - "Ka": "ka", - "Kai": "kp", - "Kan": "kr", - "Kang": "ks", - "Kao": "kq", - "Ke": "ke", - "Ken": "kw", - "Keng": "kt", - "Kong": "kh", - "Kou": "kz", - "Ku": "ku", - "Kua": "kx", - "Kuai": "ky", - "Kuan": "kl", - "Kuang": "kg", - "Kui": "kn", - "Kun": "km", - "Kuo": "ko", - "La": "la", - "Lai": "lp", - "Lan": "lr", - "Lang": "ls", - "Lao": "lq", - "Le": "le", - "Lei": "lk", - "Leng": "lt", - "Li": "li", - "Lia": "lx", - "Lian": "lf", - "Liang": "lg", - "Liao": "lb", - "Lie": "ld", - "Lin": "ly", - "Ling": "lc", - "Liu": "lj", - "Lo": "lo", - "Long": "lh", - "Lou": "lz", - "Lu": "lu", - "Luan": "ll", - "Lun": "lm", - "Luo": "lo", - "Ma": "ma", - "Mai": "mp", - "Man": "mr", - "Mang": "ms", - "Mao": "mq", - "Me": "me", - "Mei": "mk", - "Men": "mw", - "Meng": "mt", - "Mi": "mi", - "Mian": "mf", - "Miao": "mb", - "Mie": "md", - "Min": "my", - "Ming": "mc", - "Miu": "mj", - "Mo": "mo", - "Mou": "mz", - "Mu": "mu", - "Na": "na", - "Nai": "np", - "Nan": "nr", - "Nang": "ns", - "Nao": "nq", - "Ne": "ne", - "Nei": "nk", - "Nen": "nw", - "Neng": "nt", - "Ni": "ni", - "Nian": "nf", - "Niang": "ng", - "Niao": "nb", - "Nie": "nd", - "Nin": "ny", - "Ning": "nc", - "Niu": "nj", - "Nong": "nh", - "Nou": "nz", - "Nu": "nu", - "Nuan": "nl", - "Nun": "nm", - "Nuo": "no", - "Pa": "pa", - "Pai": "pp", - "Pan": "pr", - "Pang": "ps", - "Pao": "pq", - "Pei": "pk", - "Pen": "pw", - "Peng": "pt", - "Pi": "pi", - "Pian": "pf", - "Piao": "pb", - "Pie": "pd", - "Pin": "py", - "Ping": "pc", - "Po": "po", - "Pou": "pz", - "Pu": "pu", - "Qi": "qi", - "Qia": "qx", - "Qian": "qf", - "Qiang": "qg", - "Qiao": "qb", - "Qie": "qd", - "Qin": "qy", - "Qing": "qc", - "Qiong": "qh", - "Qiu": "qj", - "Qu": "qu", - "Quan": "ql", - "Que": "qn", - "Qun": "qm", - "Ran": "rr", - "Rang": "rs", - "Rao": "rq", - "Re": "re", - "Ren": "rw", - "Reng": "rt", - "Ri": "ri", - "Rong": "rh", - "Rou": "rz", - "Ru": "ru", - "Rua": "rx", - "Ruan": "rl", - "Rui": "rn", - "Run": "rm", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sp", - "San": "sr", - "Sang": "ss", - "Sao": "sq", - "Se": "se", - "Sen": "sw", - "Seng": "st", - "Sha": "ia", - "Shai": "ip", - "Shan": "ir", - "Shang": "is", - "Shao": "iq", - "She": "ie", - "Shei": "ik", - "Shen": "iw", - "Sheng": "it", - "Shi": "ii", - "Shou": "iz", - "Shu": "iu", - "Shua": "ix", - "Shuai": "iy", - "Shuan": "il", - "Shuang": "ig", - "Shui": "in", - "Shun": "im", - "Shuo": "io", - "Si": "si", - "Song": "sh", - "Sou": "sz", - "Su": "su", - "Suan": "sl", - "Sui": "sn", - "Sun": "sm", - "Suo": "so", - "Ta": "ta", - "Tai": "tp", - "Tan": "tr", - "Tang": "ts", - "Tao": "tq", - "Te": "te", - "Tei": "tk", - "Teng": "tt", - "Ti": "ti", - "Tian": "tf", - "Tiao": "tb", - "Tie": "td", - "Ting": "tc", - "Tong": "th", - "Tou": "tz", - "Tu": "tu", - "Tuan": "tl", - "Tui": "tn", - "Tun": "tm", - "Tuo": "to", - "Xi": "xi", - "Xia": "xx", - "Xian": "xf", - "Xiang": "xg", - "Xiao": "xb", - "Xie": "xd", - "Xin": "xy", - "Xing": "xc", - "Xiong": "xh", - "Xiu": "xj", - "Xu": "xu", - "Xuan": "xl", - "Xue": "xn", - "Xun": "xm", - "Za": "za", - "Zai": "zp", - "Zan": "zr", - "Zang": "zs", - "Zao": "zq", - "Ze": "ze", - "Zei": "zk", - "Zen": "zw", - "Zeng": "zt", - "Zha": "ua", - "Zhai": "up", - "Zhan": "ur", - "Zhang": "us", - "Zhao": "uq", - "Zhe": "ue", - "Zhen": "uw", - "Zheng": "ut", - "Zhi": "ui", - "Zhong": "uh", - "Zhou": "uz", - "Zhu": "uu", - "Zhua": "ux", - "Zhuai": "uy", - "Zhuan": "ul", - "Zhuang": "ug", - "Zhui": "un", - "Zhun": "um", - "Zhuo": "uo", - "Zi": "zi", - "Zong": "zh", - "Zou": "zz", - "Zu": "zu", - "Zuan": "zl", - "Zui": "zn", - "Zun": "zm", - "Zuo": "zo" - }, - "PinYinJiaJia": { - "Lv": "lv", - "Lve": "lx", - "Lue": "lx", - "Nv": "nv", - "Nve": "nx", - "Nue": "nx", - "A": "aa", - "O": "oo", - "E": "ee", - "Ai": "as", - "Ei": "ew", - "Ao": "ad", - "Ou": "op", - "An": "af", - "En": "er", - "Ang": "ag", - "Eng": "et", - "Er": "eq", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "yd", - "You": "yp", - "Yan": "yf", - "Yin": "yl", - "Yang": "yg", - "Ying": "yq", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "ws", - "Wei": "ww", - "Wan": "wf", - "Wen": "wr", - "Wang": "wg", - "Weng": "wt", - "Yu": "yu", - "Yue": "yx", - "Yuan": "yc", - "Yun": "yz", - "Yong": "yy", - "Ba": "ba", - "Bai": "bs", - "Ban": "bf", - "Bang": "bg", - "Bao": "bd", - "Bei": "bw", - "Ben": "br", - "Beng": "bt", - "Bi": "bi", - "Bian": "bj", - "Biang": "bh", - "Biao": "bk", - "Bie": "bm", - "Bin": "bl", - "Bing": "bq", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cs", - "Can": "cf", - "Cang": "cg", - "Cao": "cd", - "Ce": "ce", - "Cen": "cr", - "Ceng": "ct", - "Cha": "ua", - "Chai": "us", - "Chan": "uf", - "Chang": "ug", - "Chao": "ud", - "Che": "ue", - "Chen": "ur", - "Cheng": "ut", - "Chi": "ui", - "Chong": "uy", - "Chou": "up", - "Chu": "uu", - "Chua": "ub", - "Chuai": "ux", - "Chuan": "uc", - "Chuang": "uh", - "Chui": "uv", - "Chun": "uz", - "Chuo": "uo", - "Ci": "ci", - "Cong": "cy", - "Cou": "cp", - "Cu": "cu", - "Cuan": "cc", - "Cui": "cv", - "Cun": "cz", - "Cuo": "co", - "Da": "da", - "Dai": "ds", - "Dan": "df", - "Dang": "dg", - "Dao": "dd", - "De": "de", - "Dei": "dw", - "Den": "dr", - "Deng": "dt", - "Di": "di", - "Dia": "db", - "Dian": "dj", - "Diao": "dk", - "Die": "dm", - "Ding": "dq", - "Diu": "dn", - "Dong": "dy", - "Dou": "dp", - "Du": "du", - "Duan": "dc", - "Dui": "dv", - "Dun": "dz", - "Duo": "do", - "Fa": "fa", - "Fan": "ff", - "Fang": "fg", - "Fei": "fw", - "Fen": "fr", - "Feng": "ft", - "Fiao": "fk", - "Fo": "fo", - "Fou": "fp", - "Fu": "fu", - "Ga": "ga", - "Gai": "gs", - "Gan": "gf", - "Gang": "gg", - "Gao": "gd", - "Ge": "ge", - "Gei": "gw", - "Gen": "gr", - "Geng": "gt", - "Gong": "gy", - "Gou": "gp", - "Gu": "gu", - "Gua": "gb", - "Guai": "gx", - "Guan": "gc", - "Guang": "gh", - "Gui": "gv", - "Gun": "gz", - "Guo": "go", - "Ha": "ha", - "Hai": "hs", - "Han": "hf", - "Hang": "hg", - "Hao": "hd", - "He": "he", - "Hei": "hw", - "Hen": "hr", - "Heng": "ht", - "Hong": "hy", - "Hou": "hp", - "Hu": "hu", - "Hua": "hb", - "Huai": "hx", - "Huan": "hc", - "Huang": "hh", - "Hui": "hv", - "Hun": "hz", - "Huo": "ho", - "Ji": "ji", - "Jia": "jb", - "Jian": "jj", - "Jiang": "jh", - "Jiao": "jk", - "Jie": "jm", - "Jin": "jl", - "Jing": "jq", - "Jiong": "jy", - "Jiu": "jn", - "Ju": "ju", - "Juan": "jc", - "Jue": "jx", - "Jun": "jz", - "Ka": "ka", - "Kai": "ks", - "Kan": "kf", - "Kang": "kg", - "Kao": "kd", - "Ke": "ke", - "Ken": "kr", - "Keng": "kt", - "Kong": "ky", - "Kou": "kp", - "Ku": "ku", - "Kua": "kb", - "Kuai": "kx", - "Kuan": "kc", - "Kuang": "kh", - "Kui": "kv", - "Kun": "kz", - "Kuo": "ko", - "La": "la", - "Lai": "ls", - "Lan": "lf", - "Lang": "lg", - "Lao": "ld", - "Le": "le", - "Lei": "lw", - "Leng": "lt", - "Li": "li", - "Lia": "lb", - "Lian": "lj", - "Liang": "lh", - "Liao": "lk", - "Lie": "lm", - "Lin": "ll", - "Ling": "lq", - "Liu": "ln", - "Lo": "lo", - "Long": "ly", - "Lou": "lp", - "Lu": "lu", - "Luan": "lc", - "Lun": "lz", - "Luo": "lo", - "Ma": "ma", - "Mai": "ms", - "Man": "mf", - "Mang": "mg", - "Mao": "md", - "Me": "me", - "Mei": "mw", - "Men": "mr", - "Meng": "mt", - "Mi": "mi", - "Mian": "mj", - "Miao": "mk", - "Mie": "mm", - "Min": "ml", - "Ming": "mq", - "Miu": "mn", - "Mo": "mo", - "Mou": "mp", - "Mu": "mu", - "Na": "na", - "Nai": "ns", - "Nan": "nf", - "Nang": "ng", - "Nao": "nd", - "Ne": "ne", - "Nei": "nw", - "Nen": "nr", - "Neng": "nt", - "Ni": "ni", - "Nian": "nj", - "Niang": "nh", - "Niao": "nk", - "Nie": "nm", - "Nin": "nl", - "Ning": "nq", - "Niu": "nn", - "Nong": "ny", - "Nou": "np", - "Nu": "nu", - "Nuan": "nc", - "Nun": "nz", - "Nuo": "no", - "Pa": "pa", - "Pai": "ps", - "Pan": "pf", - "Pang": "pg", - "Pao": "pd", - "Pei": "pw", - "Pen": "pr", - "Peng": "pt", - "Pi": "pi", - "Pian": "pj", - "Piao": "pk", - "Pie": "pm", - "Pin": "pl", - "Ping": "pq", - "Po": "po", - "Pou": "pp", - "Pu": "pu", - "Qi": "qi", - "Qia": "qb", - "Qian": "qj", - "Qiang": "qh", - "Qiao": "qk", - "Qie": "qm", - "Qin": "ql", - "Qing": "qq", - "Qiong": "qy", - "Qiu": "qn", - "Qu": "qu", - "Quan": "qc", - "Que": "qx", - "Qun": "qz", - "Ran": "rf", - "Rang": "rg", - "Rao": "rd", - "Re": "re", - "Ren": "rr", - "Reng": "rt", - "Ri": "ri", - "Rong": "ry", - "Rou": "rp", - "Ru": "ru", - "Rua": "rb", - "Ruan": "rc", - "Rui": "rv", - "Run": "rz", - "Ruo": "ro", - "Sa": "sa", - "Sai": "ss", - "San": "sf", - "Sang": "sg", - "Sao": "sd", - "Se": "se", - "Sen": "sr", - "Seng": "st", - "Sha": "ia", - "Shai": "is", - "Shan": "if", - "Shang": "ig", - "Shao": "id", - "She": "ie", - "Shei": "iw", - "Shen": "ir", - "Sheng": "it", - "Shi": "ii", - "Shou": "ip", - "Shu": "iu", - "Shua": "ib", - "Shuai": "ix", - "Shuan": "ic", - "Shuang": "ih", - "Shui": "iv", - "Shun": "iz", - "Shuo": "io", - "Si": "si", - "Song": "sy", - "Sou": "sp", - "Su": "su", - "Suan": "sc", - "Sui": "sv", - "Sun": "sz", - "Suo": "so", - "Ta": "ta", - "Tai": "ts", - "Tan": "tf", - "Tang": "tg", - "Tao": "td", - "Te": "te", - "Tei": "tw", - "Teng": "tt", - "Ti": "ti", - "Tian": "tj", - "Tiao": "tk", - "Tie": "tm", - "Ting": "tq", - "Tong": "ty", - "Tou": "tp", - "Tu": "tu", - "Tuan": "tc", - "Tui": "tv", - "Tun": "tz", - "Tuo": "to", - "Xi": "xi", - "Xia": "xb", - "Xian": "xj", - "Xiang": "xh", - "Xiao": "xk", - "Xie": "xm", - "Xin": "xl", - "Xing": "xq", - "Xiong": "xy", - "Xiu": "xn", - "Xu": "xu", - "Xuan": "xc", - "Xue": "xx", - "Xun": "xz", - "Za": "za", - "Zai": "zs", - "Zan": "zf", - "Zang": "zg", - "Zao": "zd", - "Ze": "ze", - "Zei": "zw", - "Zen": "zr", - "Zeng": "zt", - "Zha": "va", - "Zhai": "vs", - "Zhan": "vf", - "Zhang": "vg", - "Zhao": "vd", - "Zhe": "ve", - "Zhen": "vr", - "Zheng": "vt", - "Zhi": "vi", - "Zhong": "vy", - "Zhou": "vp", - "Zhu": "vu", - "Zhua": "vb", - "Zhuai": "vx", - "Zhuan": "vc", - "Zhuang": "vh", - "Zhui": "vv", - "Zhun": "vz", - "Zhuo": "vo", - "Zi": "zi", - "Zong": "zy", - "Zou": "zp", - "Zu": "zu", - "Zuan": "zc", - "Zui": "zv", - "Zun": "zz", - "Zuo": "zo" - }, - "XingKongJianDao": { - "Lv": "lv", - "Lve": "ly", - "Lue": "ly", - "Nv": "nv", - "Nve": "ny", - "Nue": "ny", - "A": "xa", - "O": "xo", - "E": "xe", - "Ai": "xj", - "Ei": "xw", - "Ao": "xs", - "Ou": "xt", - "An": "xd", - "En": "xk", - "Ang": "xf", - "Eng": "xh", - "Er": "xu", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "ys", - "You": "yt", - "Yan": "yd", - "Yin": "yb", - "Yang": "yf", - "Ying": "yg", - "Wu": "wj", - "Wa": "ws", - "Wo": "wo", - "Wai": "wh", - "Wei": "ww", - "Wan": "wf", - "Wen": "wn", - "Wang": "wp", - "Weng": "wr", - "Yu": "yv", - "Yue": "yy", - "Yuan": "yr", - "Yun": "yw", - "Yong": "yl", - "Ba": "ba", - "Bai": "bj", - "Ban": "bd", - "Bang": "bf", - "Bao": "bs", - "Bei": "bw", - "Ben": "bk", - "Beng": "bh", - "Bi": "bi", - "Bian": "bm", - "Biang": "bx", - "Biao": "bp", - "Bie": "bc", - "Bin": "bb", - "Bing": "bg", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "cj", - "Can": "cd", - "Cang": "cf", - "Cao": "cs", - "Ce": "ce", - "Cen": "ck", - "Ceng": "ch", - "Cha": "ja", - "Chai": "jj", - "Chan": "jd", - "Chang": "jf", - "Chao": "js", - "Che": "je", - "Chen": "jk", - "Cheng": "jh", - "Chi": "wi", - "Chong": "wl", - "Chou": "jt", - "Chu": "ju", - "Chua": "wx", - "Chuai": "wg", - "Chuan": "wr", - "Chuang": "wn", - "Chui": "wy", - "Chun": "jz", - "Chuo": "jo", - "Ci": "ci", - "Cong": "cl", - "Cou": "ct", - "Cu": "cu", - "Cuan": "cr", - "Cui": "cy", - "Cun": "cz", - "Cuo": "co", - "Da": "da", - "Dai": "dj", - "Dan": "dd", - "Dang": "df", - "Dao": "ds", - "De": "de", - "Dei": "dw", - "Den": "dk", - "Deng": "dh", - "Di": "di", - "Dia": "dx", - "Dian": "dm", - "Diao": "dp", - "Die": "dc", - "Ding": "dg", - "Diu": "dq", - "Dong": "dl", - "Dou": "dt", - "Du": "du", - "Duan": "dr", - "Dui": "dy", - "Dun": "dz", - "Duo": "do", - "Fa": "fs", - "Fan": "ff", - "Fang": "fp", - "Fei": "fw", - "Fen": "fn", - "Feng": "fr", - "Fiao": "fp", - "Fo": "fl", - "Fou": "fd", - "Fu": "fl", - "Ga": "ga", - "Gai": "gj", - "Gan": "gd", - "Gang": "gf", - "Gao": "gs", - "Ge": "ge", - "Gei": "gw", - "Gen": "gk", - "Geng": "gh", - "Gong": "gl", - "Gou": "gt", - "Gu": "gu", - "Gua": "gx", - "Guai": "gg", - "Guan": "gr", - "Guang": "gn", - "Gui": "gy", - "Gun": "gz", - "Guo": "go", - "Ha": "ha", - "Hai": "hj", - "Han": "hd", - "Hang": "hf", - "Hao": "hs", - "He": "he", - "Hei": "hw", - "Hen": "hk", - "Heng": "hh", - "Hong": "hl", - "Hou": "ht", - "Hu": "hu", - "Hua": "hx", - "Huai": "hg", - "Huan": "hr", - "Huang": "hn", - "Hui": "hy", - "Hun": "hz", - "Huo": "ho", - "Ji": "jk", - "Jia": "js", - "Jian": "jm", - "Jiang": "jn", - "Jiao": "jp", - "Jie": "jc", - "Jin": "jb", - "Jing": "jg", - "Jiong": "jy", - "Jiu": "jq", - "Ju": "jv", - "Juan": "jt", - "Jue": "jh", - "Jun": "jw", - "Ka": "ka", - "Kai": "kj", - "Kan": "kd", - "Kang": "kf", - "Kao": "ks", - "Ke": "ke", - "Ken": "kk", - "Keng": "kh", - "Kong": "kl", - "Kou": "kt", - "Ku": "ku", - "Kua": "kx", - "Kuai": "kg", - "Kuan": "kr", - "Kuang": "kn", - "Kui": "ky", - "Kun": "kz", - "Kuo": "ko", - "La": "la", - "Lai": "lj", - "Lan": "ld", - "Lang": "lf", - "Lao": "ls", - "Le": "le", - "Lei": "lw", - "Leng": "lh", - "Li": "li", - "Lia": "lx", - "Lian": "lm", - "Liang": "ln", - "Liao": "lp", - "Lie": "lc", - "Lin": "lb", - "Ling": "lg", - "Liu": "lq", - "Lo": "ll", - "Long": "ll", - "Lou": "lt", - "Lu": "lu", - "Luan": "lr", - "Lun": "lz", - "Luo": "lo", - "Ma": "ma", - "Mai": "mj", - "Man": "md", - "Mang": "mf", - "Mao": "ms", - "Me": "me", - "Mei": "mw", - "Men": "mk", - "Meng": "mh", - "Mi": "mi", - "Mian": "mm", - "Miao": "mp", - "Mie": "mc", - "Min": "mb", - "Ming": "mg", - "Miu": "mq", - "Mo": "mo", - "Mou": "mt", - "Mu": "mu", - "Na": "na", - "Nai": "nj", - "Nan": "nd", - "Nang": "nf", - "Nao": "ns", - "Ne": "ne", - "Nei": "nw", - "Nen": "nk", - "Neng": "nh", - "Ni": "ni", - "Nian": "nm", - "Niang": "nn", - "Niao": "np", - "Nie": "nc", - "Nin": "nb", - "Ning": "ng", - "Niu": "nq", - "Nong": "nl", - "Nou": "nt", - "Nu": "nu", - "Nuan": "nr", - "Nun": "nz", - "Nuo": "no", - "Pa": "pa", - "Pai": "pj", - "Pan": "pd", - "Pang": "pf", - "Pao": "ps", - "Pei": "pw", - "Pen": "pk", - "Peng": "ph", - "Pi": "pi", - "Pian": "pm", - "Piao": "pp", - "Pie": "pc", - "Pin": "pb", - "Ping": "pg", - "Po": "po", - "Pou": "pt", - "Pu": "pu", - "Qi": "qk", - "Qia": "qs", - "Qian": "qm", - "Qiang": "qx", - "Qiao": "qp", - "Qie": "qc", - "Qin": "qb", - "Qing": "qg", - "Qiong": "qy", - "Qiu": "qq", - "Qu": "qv", - "Quan": "qt", - "Que": "qh", - "Qun": "qw", - "Ran": "rd", - "Rang": "rf", - "Rao": "rs", - "Re": "re", - "Ren": "rk", - "Reng": "rh", - "Ri": "ri", - "Rong": "rl", - "Rou": "rt", - "Ru": "ru", - "Rua": "rx", - "Ruan": "rr", - "Rui": "ry", - "Run": "rz", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sj", - "San": "sd", - "Sang": "sf", - "Sao": "ss", - "Se": "se", - "Sen": "sk", - "Seng": "sh", - "Sha": "ea", - "Shai": "ej", - "Shan": "ed", - "Shang": "ef", - "Shao": "es", - "She": "ee", - "Shei": "ew", - "Shen": "ek", - "Sheng": "eh", - "Shi": "ei", - "Shou": "et", - "Shu": "eu", - "Shua": "ex", - "Shuai": "eg", - "Shuan": "er", - "Shuang": "en", - "Shui": "ey", - "Shun": "ez", - "Shuo": "eo", - "Si": "si", - "Song": "sl", - "Sou": "st", - "Su": "su", - "Suan": "sr", - "Sui": "sy", - "Sun": "sz", - "Suo": "so", - "Ta": "ta", - "Tai": "tj", - "Tan": "td", - "Tang": "tf", - "Tao": "ts", - "Te": "te", - "Tei": "tw", - "Teng": "th", - "Ti": "ti", - "Tian": "tm", - "Tiao": "tp", - "Tie": "tc", - "Ting": "tg", - "Tong": "tl", - "Tou": "tt", - "Tu": "tu", - "Tuan": "tr", - "Tui": "ty", - "Tun": "tz", - "Tuo": "to", - "Xi": "xi", - "Xia": "xx", - "Xian": "xm", - "Xiang": "xn", - "Xiao": "xp", - "Xie": "xc", - "Xin": "xb", - "Xing": "xg", - "Xiong": "xl", - "Xiu": "xq", - "Xu": "xv", - "Xuan": "xr", - "Xue": "xy", - "Xun": "xw", - "Za": "za", - "Zai": "zj", - "Zan": "zd", - "Zang": "zf", - "Zao": "zs", - "Ze": "ze", - "Zei": "zw", - "Zen": "zk", - "Zeng": "zh", - "Zha": "qa", - "Zhai": "fj", - "Zhan": "qd", - "Zhang": "qf", - "Zhao": "fs", - "Zhe": "fe", - "Zhen": "qk", - "Zheng": "qh", - "Zhi": "fi", - "Zhong": "fy", - "Zhou": "qt", - "Zhu": "qu", - "Zhua": "fx", - "Zhuai": "fg", - "Zhuan": "fr", - "Zhuang": "fn", - "Zhui": "fy", - "Zhun": "fz", - "Zhuo": "qo", - "Zi": "zi", - "Zong": "zl", - "Zou": "zt", - "Zu": "zu", - "Zuan": "zr", - "Zui": "zy", - "Zun": "zz", - "Zuo": "zo" - }, - "DaNiu": { - "Lv": "lv", - "Lve": "lx", - "Lue": "lx", - "Nv": "nv", - "Nve": "nx", - "Nue": "nx", - "A": "ea", - "O": "eo", - "E": "ee", - "Ai": "eh", - "Ei": "ew", - "Ao": "es", - "Ou": "er", - "An": "ed", - "En": "ek", - "Ang": "ef", - "Eng": "ej", - "Er": "eu", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "ys", - "You": "yr", - "Yan": "yd", - "Yin": "yb", - "Yang": "yf", - "Ying": "yg", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wh", - "Wei": "ww", - "Wan": "wd", - "Wen": "wk", - "Wang": "wf", - "Weng": "wj", - "Yu": "yu", - "Yue": "yh", - "Yuan": "yj", - "Yun": "yw", - "Yong": "yl", - "Ba": "ba", - "Bai": "bh", - "Ban": "bd", - "Bang": "bf", - "Bao": "bs", - "Bei": "bw", - "Ben": "bk", - "Beng": "bj", - "Bi": "bi", - "Bian": "bc", - "Biang": "bn", - "Biao": "bm", - "Bie": "bp", - "Bin": "bb", - "Bing": "bg", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "ch", - "Can": "cd", - "Cang": "cf", - "Cao": "cs", - "Ce": "ce", - "Cen": "ck", - "Ceng": "cj", - "Cha": "ia", - "Chai": "ih", - "Chan": "id", - "Chang": "if", - "Chao": "is", - "Che": "ie", - "Chen": "ik", - "Cheng": "ij", - "Chi": "ii", - "Chong": "il", - "Chou": "ir", - "Chu": "iu", - "Chua": "iq", - "Chuai": "ig", - "Chuan": "iz", - "Chuang": "ix", - "Chui": "in", - "Chun": "iy", - "Chuo": "io", - "Ci": "ci", - "Cong": "cl", - "Cou": "cr", - "Cu": "cu", - "Cuan": "cz", - "Cui": "cn", - "Cun": "cy", - "Cuo": "co", - "Da": "da", - "Dai": "dh", - "Dan": "dd", - "Dang": "df", - "Dao": "ds", - "De": "de", - "Dei": "dw", - "Den": "dk", - "Deng": "dj", - "Di": "di", - "Dia": "dk", - "Dian": "dc", - "Diao": "dm", - "Die": "dp", - "Ding": "dg", - "Diu": "dt", - "Dong": "dl", - "Dou": "dr", - "Du": "du", - "Duan": "dz", - "Dui": "dn", - "Dun": "dy", - "Duo": "do", - "Fa": "fa", - "Fan": "fd", - "Fang": "ff", - "Fei": "fw", - "Fen": "fk", - "Feng": "fj", - "Fiao": "fm", - "Fo": "fo", - "Fou": "fr", - "Fu": "fu", - "Ga": "ga", - "Gai": "gh", - "Gan": "gd", - "Gang": "gf", - "Gao": "gs", - "Ge": "ge", - "Gei": "gw", - "Gen": "gk", - "Geng": "gj", - "Gong": "gl", - "Gou": "gr", - "Gu": "gu", - "Gua": "gq", - "Guai": "gg", - "Guan": "gz", - "Guang": "gx", - "Gui": "gn", - "Gun": "gy", - "Guo": "go", - "Ha": "ha", - "Hai": "hh", - "Han": "hd", - "Hang": "hf", - "Hao": "hs", - "He": "he", - "Hei": "hw", - "Hen": "hk", - "Heng": "hj", - "Hong": "hl", - "Hou": "hr", - "Hu": "hu", - "Hua": "hq", - "Huai": "hg", - "Huan": "hz", - "Huang": "hx", - "Hui": "hn", - "Hun": "hy", - "Huo": "ho", - "Ji": "ji", - "Jia": "jk", - "Jian": "jc", - "Jiang": "jn", - "Jiao": "jm", - "Jie": "jp", - "Jin": "jb", - "Jing": "jg", - "Jiong": "jl", - "Jiu": "jt", - "Ju": "ju", - "Juan": "jj", - "Jue": "jh", - "Jun": "jw", - "Ka": "ka", - "Kai": "kh", - "Kan": "kd", - "Kang": "kf", - "Kao": "ks", - "Ke": "ke", - "Ken": "kk", - "Keng": "kj", - "Kong": "kl", - "Kou": "kr", - "Ku": "ku", - "Kua": "kq", - "Kuai": "kg", - "Kuan": "kz", - "Kuang": "kx", - "Kui": "kn", - "Kun": "ky", - "Kuo": "ko", - "La": "la", - "Lai": "lh", - "Lan": "ld", - "Lang": "lf", - "Lao": "ls", - "Le": "le", - "Lei": "lw", - "Leng": "lj", - "Li": "li", - "Lia": "lk", - "Lian": "lc", - "Liang": "ln", - "Liao": "lm", - "Lie": "lp", - "Lin": "lb", - "Ling": "lg", - "Liu": "lt", - "Lo": "lo", - "Long": "ll", - "Lou": "lr", - "Lu": "lu", - "Luan": "lz", - "Lun": "ly", - "Luo": "lo", - "Ma": "ma", - "Mai": "mh", - "Man": "md", - "Mang": "mf", - "Mao": "ms", - "Me": "me", - "Mei": "mw", - "Men": "mk", - "Meng": "mj", - "Mi": "mi", - "Mian": "mc", - "Miao": "mm", - "Mie": "mp", - "Min": "mb", - "Ming": "mg", - "Miu": "mt", - "Mo": "mo", - "Mou": "mr", - "Mu": "mu", - "Na": "na", - "Nai": "nh", - "Nan": "nd", - "Nang": "nf", - "Nao": "ns", - "Ne": "ne", - "Nei": "nw", - "Nen": "nk", - "Neng": "nj", - "Ni": "ni", - "Nian": "nc", - "Niang": "nn", - "Niao": "nm", - "Nie": "np", - "Nin": "nb", - "Ning": "ng", - "Niu": "nt", - "Nong": "nl", - "Nou": "nr", - "Nu": "nu", - "Nuan": "nz", - "Nun": "ny", - "Nuo": "no", - "Pa": "pa", - "Pai": "ph", - "Pan": "pd", - "Pang": "pf", - "Pao": "ps", - "Pei": "pw", - "Pen": "pk", - "Peng": "pj", - "Pi": "pi", - "Pian": "pc", - "Piao": "pm", - "Pie": "pp", - "Pin": "pb", - "Ping": "pg", - "Po": "po", - "Pou": "pr", - "Pu": "pu", - "Qi": "qi", - "Qia": "qk", - "Qian": "qc", - "Qiang": "qn", - "Qiao": "qm", - "Qie": "qp", - "Qin": "qb", - "Qing": "qg", - "Qiong": "ql", - "Qiu": "qt", - "Qu": "qu", - "Quan": "qj", - "Que": "qh", - "Qun": "qw", - "Ran": "rd", - "Rang": "rf", - "Rao": "rs", - "Re": "re", - "Ren": "rk", - "Reng": "rj", - "Ri": "ri", - "Rong": "rl", - "Rou": "rr", - "Ru": "ru", - "Rua": "rq", - "Ruan": "rz", - "Rui": "rn", - "Run": "ry", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sh", - "San": "sd", - "Sang": "sf", - "Sao": "ss", - "Se": "se", - "Sen": "sk", - "Seng": "sj", - "Sha": "ua", - "Shai": "uh", - "Shan": "ud", - "Shang": "uf", - "Shao": "us", - "She": "ue", - "Shei": "uw", - "Shen": "uk", - "Sheng": "uj", - "Shi": "ui", - "Shou": "ur", - "Shu": "uu", - "Shua": "uq", - "Shuai": "ug", - "Shuan": "uz", - "Shuang": "ux", - "Shui": "un", - "Shun": "uy", - "Shuo": "uo", - "Si": "si", - "Song": "sl", - "Sou": "sr", - "Su": "su", - "Suan": "sz", - "Sui": "sn", - "Sun": "sy", - "Suo": "so", - "Ta": "ta", - "Tai": "th", - "Tan": "td", - "Tang": "tf", - "Tao": "ts", - "Te": "te", - "Tei": "tw", - "Teng": "tj", - "Ti": "ti", - "Tian": "tc", - "Tiao": "tm", - "Tie": "tp", - "Ting": "tg", - "Tong": "tl", - "Tou": "tr", - "Tu": "tu", - "Tuan": "tz", - "Tui": "tn", - "Tun": "ty", - "Tuo": "to", - "Xi": "xi", - "Xia": "xk", - "Xian": "xc", - "Xiang": "xn", - "Xiao": "xm", - "Xie": "xp", - "Xin": "xb", - "Xing": "xg", - "Xiong": "xl", - "Xiu": "xt", - "Xu": "xu", - "Xuan": "xj", - "Xue": "xh", - "Xun": "xw", - "Za": "za", - "Zai": "zh", - "Zan": "zd", - "Zang": "zf", - "Zao": "zs", - "Ze": "ze", - "Zei": "zw", - "Zen": "zk", - "Zeng": "zj", - "Zha": "aa", - "Zhai": "ah", - "Zhan": "ad", - "Zhang": "af", - "Zhao": "as", - "Zhe": "ae", - "Zhen": "ak", - "Zheng": "aj", - "Zhi": "ai", - "Zhong": "al", - "Zhou": "ar", - "Zhu": "au", - "Zhua": "aq", - "Zhuai": "ag", - "Zhuan": "az", - "Zhuang": "ax", - "Zhui": "an", - "Zhun": "ay", - "Zhuo": "ao", - "Zi": "zi", - "Zong": "zl", - "Zou": "zr", - "Zu": "zu", - "Zuan": "zz", - "Zui": "zn", - "Zun": "zy", - "Zuo": "zo" - }, - "XiaoLang": { - "Lv": "lx", - "Lve": "lb", - "Lue": "lb", - "Nv": "nx", - "Nve": "nb", - "Nue": "nb", - "A": "aa", - "O": "oo", - "E": "uu", - "Ai": "ai", - "Ei": "ui", - "Ao": "ao", - "Ou": "ou", - "An": "an", - "En": "un", - "Ang": "ah", - "Eng": "un", - "Er": "ur", - "Yi": "yi", - "Ya": "ya", - "Yo": "yo", - "Ye": "ye", - "Yao": "ys", - "You": "yr", - "Yan": "yj", - "Yin": "yd", - "Yang": "yh", - "Ying": "yv", - "Wu": "wu", - "Wa": "wa", - "Wo": "wo", - "Wai": "wk", - "Wei": "ww", - "Wan": "wj", - "Wen": "wm", - "Wang": "wh", - "Weng": "wn", - "Yu": "yu", - "Yue": "yb", - "Yuan": "yg", - "Yun": "yy", - "Yong": "yl", - "Ba": "ba", - "Bai": "bk", - "Ban": "bj", - "Bang": "bh", - "Bao": "bs", - "Bei": "bw", - "Ben": "bm", - "Beng": "bn", - "Bi": "bi", - "Bian": "bf", - "Biang": "bm", - "Biao": "bc", - "Bie": "bp", - "Bin": "bd", - "Bing": "bv", - "Bo": "bo", - "Bu": "bu", - "Ca": "ca", - "Cai": "ck", - "Can": "cj", - "Cang": "ch", - "Cao": "cs", - "Ce": "ce", - "Cen": "cm", - "Ceng": "cn", - "Cha": "ia", - "Chai": "ik", - "Chan": "ij", - "Chang": "ih", - "Chao": "is", - "Che": "ie", - "Chen": "im", - "Cheng": "in", - "Chi": "ii", - "Chong": "il", - "Chou": "ir", - "Chu": "iu", - "Chua": "if", - "Chuai": "iv", - "Chuan": "ig", - "Chuang": "iz", - "Chui": "id", - "Chun": "iy", - "Chuo": "io", - "Ci": "ci", - "Cong": "cl", - "Cou": "cr", - "Cu": "cu", - "Cuan": "cg", - "Cui": "cd", - "Cun": "cy", - "Cuo": "co", - "Da": "da", - "Dai": "dk", - "Dan": "dj", - "Dang": "dh", - "Dao": "ds", - "De": "de", - "Dei": "dw", - "Den": "dm", - "Deng": "dn", - "Di": "di", - "Dia": "dk", - "Dian": "df", - "Diao": "dc", - "Die": "dp", - "Ding": "dv", - "Diu": "dt", - "Dong": "dl", - "Dou": "dr", - "Du": "du", - "Duan": "dg", - "Dui": "dd", - "Dun": "dy", - "Duo": "do", - "Fa": "fa", - "Fan": "fj", - "Fang": "fh", - "Fei": "fw", - "Fen": "fm", - "Feng": "fn", - "Fiao": "fc", - "Fo": "fo", - "Fou": "fr", - "Fu": "fu", - "Ga": "ga", - "Gai": "gk", - "Gan": "gj", - "Gang": "gh", - "Gao": "gs", - "Ge": "ge", - "Gei": "gw", - "Gen": "gm", - "Geng": "gn", - "Gong": "gl", - "Gou": "gr", - "Gu": "gu", - "Gua": "gf", - "Guai": "gv", - "Guan": "gg", - "Guang": "gz", - "Gui": "gd", - "Gun": "gy", - "Guo": "go", - "Ha": "ha", - "Hai": "hk", - "Han": "hj", - "Hang": "hh", - "Hao": "hs", - "He": "he", - "Hei": "hw", - "Hen": "hm", - "Heng": "hn", - "Hong": "hl", - "Hou": "hr", - "Hu": "hu", - "Hua": "hf", - "Huai": "hv", - "Huan": "hg", - "Huang": "hz", - "Hui": "hd", - "Hun": "hy", - "Huo": "ho", - "Ji": "ji", - "Jia": "jk", - "Jian": "jf", - "Jiang": "jm", - "Jiao": "jc", - "Jie": "jp", - "Jin": "jd", - "Jing": "jv", - "Jiong": "jj", - "Jiu": "jt", - "Ju": "ju", - "Juan": "jg", - "Jue": "jb", - "Jun": "jy", - "Ka": "ka", - "Kai": "kk", - "Kan": "kj", - "Kang": "kh", - "Kao": "ks", - "Ke": "ke", - "Ken": "km", - "Keng": "kn", - "Kong": "kl", - "Kou": "kr", - "Ku": "ku", - "Kua": "kf", - "Kuai": "kv", - "Kuan": "kg", - "Kuang": "kz", - "Kui": "kd", - "Kun": "ky", - "Kuo": "ko", - "La": "la", - "Lai": "lk", - "Lan": "lj", - "Lang": "lh", - "Lao": "ls", - "Le": "le", - "Lei": "lw", - "Leng": "ln", - "Li": "li", - "Lia": "lk", - "Lian": "lf", - "Liang": "lm", - "Liao": "lc", - "Lie": "lp", - "Lin": "ld", - "Ling": "lv", - "Liu": "lt", - "Lo": "lo", - "Long": "ll", - "Lou": "lr", - "Lu": "lu", - "Luan": "lg", - "Lun": "ly", - "Luo": "lo", - "Ma": "ma", - "Mai": "mk", - "Man": "mj", - "Mang": "mh", - "Mao": "ms", - "Me": "me", - "Mei": "mw", - "Men": "mm", - "Meng": "mn", - "Mi": "mi", - "Mian": "mf", - "Miao": "mc", - "Mie": "mp", - "Min": "md", - "Ming": "mv", - "Miu": "mt", - "Mo": "mo", - "Mou": "mr", - "Mu": "mu", - "Na": "na", - "Nai": "nk", - "Nan": "nj", - "Nang": "nh", - "Nao": "ns", - "Ne": "ne", - "Nei": "nw", - "Nen": "nm", - "Neng": "nn", - "Ni": "ni", - "Nian": "nf", - "Niang": "nm", - "Niao": "nc", - "Nie": "np", - "Nin": "nd", - "Ning": "nv", - "Niu": "nt", - "Nong": "nl", - "Nou": "nr", - "Nu": "nu", - "Nuan": "ng", - "Nun": "ny", - "Nuo": "no", - "Pa": "pa", - "Pai": "pk", - "Pan": "pj", - "Pang": "ph", - "Pao": "ps", - "Pei": "pw", - "Pen": "pm", - "Peng": "pn", - "Pi": "pi", - "Pian": "pf", - "Piao": "pc", - "Pie": "pp", - "Pin": "pd", - "Ping": "pv", - "Po": "po", - "Pou": "pr", - "Pu": "pu", - "Qi": "qi", - "Qia": "qk", - "Qian": "qf", - "Qiang": "qm", - "Qiao": "qc", - "Qie": "qp", - "Qin": "qd", - "Qing": "qv", - "Qiong": "qj", - "Qiu": "qt", - "Qu": "qu", - "Quan": "qg", - "Que": "qb", - "Qun": "qy", - "Ran": "rj", - "Rang": "rh", - "Rao": "rs", - "Re": "re", - "Ren": "rm", - "Reng": "rn", - "Ri": "ri", - "Rong": "rl", - "Rou": "rr", - "Ru": "ru", - "Rua": "rf", - "Ruan": "rg", - "Rui": "rd", - "Run": "ry", - "Ruo": "ro", - "Sa": "sa", - "Sai": "sk", - "San": "sj", - "Sang": "sh", - "Sao": "ss", - "Se": "se", - "Sen": "sm", - "Seng": "sn", - "Sha": "va", - "Shai": "vk", - "Shan": "vj", - "Shang": "vh", - "Shao": "vs", - "She": "ve", - "Shei": "vw", - "Shen": "vm", - "Sheng": "vn", - "Shi": "vi", - "Shou": "vr", - "Shu": "vu", - "Shua": "vf", - "Shuai": "vv", - "Shuan": "vg", - "Shuang": "vz", - "Shui": "vd", - "Shun": "vy", - "Shuo": "vo", - "Si": "si", - "Song": "sl", - "Sou": "sr", - "Su": "su", - "Suan": "sg", - "Sui": "sd", - "Sun": "sy", - "Suo": "so", - "Ta": "ta", - "Tai": "tk", - "Tan": "tj", - "Tang": "th", - "Tao": "ts", - "Te": "te", - "Tei": "tw", - "Teng": "tn", - "Ti": "ti", - "Tian": "tf", - "Tiao": "tc", - "Tie": "tp", - "Ting": "tv", - "Tong": "tl", - "Tou": "tr", - "Tu": "tu", - "Tuan": "tg", - "Tui": "td", - "Tun": "ty", - "Tuo": "to", - "Xi": "xi", - "Xia": "xk", - "Xian": "xf", - "Xiang": "xm", - "Xiao": "xc", - "Xie": "xp", - "Xin": "xd", - "Xing": "xv", - "Xiong": "xj", - "Xiu": "xt", - "Xu": "xu", - "Xuan": "xg", - "Xue": "xb", - "Xun": "xy", - "Za": "za", - "Zai": "zk", - "Zan": "zj", - "Zang": "zh", - "Zao": "zs", - "Ze": "ze", - "Zei": "zw", - "Zen": "zm", - "Zeng": "zn", - "Zha": "ea", - "Zhai": "ek", - "Zhan": "ej", - "Zhang": "eh", - "Zhao": "es", - "Zhe": "ee", - "Zhen": "em", - "Zheng": "en", - "Zhi": "ei", - "Zhong": "el", - "Zhou": "er", - "Zhu": "eu", - "Zhua": "ef", - "Zhuai": "ev", - "Zhuan": "eg", - "Zhuang": "ez", - "Zhui": "ed", - "Zhun": "ey", - "Zhuo": "eo", - "Zi": "zi", - "Zong": "zl", - "Zou": "zr", - "Zu": "zu", - "Zuan": "zg", - "Zui": "zd", - "Zun": "zy", - "Zuo": "zo" - } -} \ No newline at end of file +{"XiaoHe":{"Lv":"lv","Lve":"lt","Lue":"lt","Nv":"nv","Nve":"nt","Nue":"nt","A":"aa","O":"oo","E":"ee","Ai":"ai","Ei":"ei","Ao":"ao","Ou":"ou","An":"an","En":"en","Ang":"ah","Eng":"eg","Er":"er","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"yc","You":"yz","Yan":"yj","Yin":"yb","Yang":"yh","Ying":"yk","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wd","Wei":"ww","Wan":"wj","Wen":"wf","Wang":"wh","Weng":"wg","Yu":"yu","Yue":"yt","Yuan":"yr","Yun":"yy","Yong":"ys","Ba":"ba","Bai":"bd","Ban":"bj","Bang":"bh","Bao":"bc","Bei":"bw","Ben":"bf","Beng":"bg","Bi":"bi","Bian":"bm","Biang":"bl","Biao":"bn","Bie":"bp","Bin":"bb","Bing":"bk","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cd","Can":"cj","Cang":"ch","Cao":"cc","Ce":"ce","Cen":"cf","Ceng":"cg","Cha":"ia","Chai":"id","Chan":"ij","Chang":"ih","Chao":"ic","Che":"ie","Chen":"if","Cheng":"ig","Chi":"ii","Chong":"is","Chou":"iz","Chu":"iu","Chua":"ix","Chuai":"ik","Chuan":"ir","Chuang":"il","Chui":"iv","Chun":"iy","Chuo":"io","Ci":"ci","Cong":"cs","Cou":"cz","Cu":"cu","Cuan":"cr","Cui":"cv","Cun":"cy","Cuo":"co","Da":"da","Dai":"dd","Dan":"dj","Dang":"dh","Dao":"dc","De":"de","Dei":"dw","Den":"df","Deng":"dg","Di":"di","Dia":"dx","Dian":"dm","Diao":"dn","Die":"dp","Ding":"dk","Diu":"dq","Dong":"ds","Dou":"dz","Du":"du","Duan":"dr","Dui":"dv","Dun":"dy","Duo":"do","Fa":"fa","Fan":"fj","Fang":"fh","Fei":"fw","Fen":"ff","Feng":"fg","Fiao":"fn","Fo":"fo","Fou":"fz","Fu":"fu","Ga":"ga","Gai":"gd","Gan":"gj","Gang":"gh","Gao":"gc","Ge":"ge","Gei":"gw","Gen":"gf","Geng":"gg","Gong":"gs","Gou":"gz","Gu":"gu","Gua":"gx","Guai":"gk","Guan":"gr","Guang":"gl","Gui":"gv","Gun":"gy","Guo":"go","Ha":"ha","Hai":"hd","Han":"hj","Hang":"hh","Hao":"hc","He":"he","Hei":"hw","Hen":"hf","Heng":"hg","Hong":"hs","Hou":"hz","Hu":"hu","Hua":"hx","Huai":"hk","Huan":"hr","Huang":"hl","Hui":"hv","Hun":"hy","Huo":"ho","Ji":"ji","Jia":"jx","Jian":"jm","Jiang":"jl","Jiao":"jn","Jie":"jp","Jin":"jb","Jing":"jk","Jiong":"js","Jiu":"jq","Ju":"ju","Juan":"jr","Jue":"jt","Jun":"jy","Ka":"ka","Kai":"kd","Kan":"kj","Kang":"kh","Kao":"kc","Ke":"ke","Ken":"kf","Keng":"kg","Kong":"ks","Kou":"kz","Ku":"ku","Kua":"kx","Kuai":"kk","Kuan":"kr","Kuang":"kl","Kui":"kv","Kun":"ky","Kuo":"ko","La":"la","Lai":"ld","Lan":"lj","Lang":"lh","Lao":"lc","Le":"le","Lei":"lw","Leng":"lg","Li":"li","Lia":"lx","Lian":"lm","Liang":"ll","Liao":"ln","Lie":"lp","Lin":"lb","Ling":"lk","Liu":"lq","Lo":"lo","Long":"ls","Lou":"lz","Lu":"lu","Luan":"lr","Lun":"ly","Luo":"lo","Ma":"ma","Mai":"md","Man":"mj","Mang":"mh","Mao":"mc","Me":"me","Mei":"mw","Men":"mf","Meng":"mg","Mi":"mi","Mian":"mm","Miao":"mn","Mie":"mp","Min":"mb","Ming":"mk","Miu":"mq","Mo":"mo","Mou":"mz","Mu":"mu","Na":"na","Nai":"nd","Nan":"nj","Nang":"nh","Nao":"nc","Ne":"ne","Nei":"nw","Nen":"nf","Neng":"ng","Ni":"ni","Nian":"nm","Niang":"nl","Niao":"nn","Nie":"np","Nin":"nb","Ning":"nk","Niu":"nq","Nong":"ns","Nou":"nz","Nu":"nu","Nuan":"nr","Nun":"ny","Nuo":"no","Pa":"pa","Pai":"pd","Pan":"pj","Pang":"ph","Pao":"pc","Pei":"pw","Pen":"pf","Peng":"pg","Pi":"pi","Pian":"pm","Piao":"pn","Pie":"pp","Pin":"pb","Ping":"pk","Po":"po","Pou":"pz","Pu":"pu","Qi":"qi","Qia":"qx","Qian":"qm","Qiang":"ql","Qiao":"qn","Qie":"qp","Qin":"qb","Qing":"qk","Qiong":"qs","Qiu":"qq","Qu":"qu","Quan":"qr","Que":"qt","Qun":"qy","Ran":"rj","Rang":"rh","Rao":"rc","Re":"re","Ren":"rf","Reng":"rg","Ri":"ri","Rong":"rs","Rou":"rz","Ru":"ru","Rua":"rx","Ruan":"rr","Rui":"rv","Run":"ry","Ruo":"ro","Sa":"sa","Sai":"sd","San":"sj","Sang":"sh","Sao":"sc","Se":"se","Sen":"sf","Seng":"sg","Sha":"ua","Shai":"ud","Shan":"uj","Shang":"uh","Shao":"uc","She":"ue","Shei":"uw","Shen":"uf","Sheng":"ug","Shi":"ui","Shou":"uz","Shu":"uu","Shua":"ux","Shuai":"uk","Shuan":"ur","Shuang":"ul","Shui":"uv","Shun":"uy","Shuo":"uo","Si":"si","Song":"ss","Sou":"sz","Su":"su","Suan":"sr","Sui":"sv","Sun":"sy","Suo":"so","Ta":"ta","Tai":"td","Tan":"tj","Tang":"th","Tao":"tc","Te":"te","Tei":"tw","Teng":"tg","Ti":"ti","Tian":"tm","Tiao":"tn","Tie":"tp","Ting":"tk","Tong":"ts","Tou":"tz","Tu":"tu","Tuan":"tr","Tui":"tv","Tun":"ty","Tuo":"to","Xi":"xi","Xia":"xx","Xian":"xm","Xiang":"xl","Xiao":"xn","Xie":"xp","Xin":"xb","Xing":"xk","Xiong":"xs","Xiu":"xq","Xu":"xu","Xuan":"xr","Xue":"xt","Xun":"xy","Za":"za","Zai":"zd","Zan":"zj","Zang":"zh","Zao":"zc","Ze":"ze","Zei":"zw","Zen":"zf","Zeng":"zg","Zha":"va","Zhai":"vd","Zhan":"vj","Zhang":"vh","Zhao":"vc","Zhe":"ve","Zhen":"vf","Zheng":"vg","Zhi":"vi","Zhong":"vs","Zhou":"vz","Zhu":"vu","Zhua":"vx","Zhuai":"vk","Zhuan":"vr","Zhuang":"vl","Zhui":"vv","Zhun":"vy","Zhuo":"vo","Zi":"zi","Zong":"zs","Zou":"zz","Zu":"zu","Zuan":"zr","Zui":"zv","Zun":"zy","Zuo":"zo"},"ZiRanMa":{"Lv":"lv","Lve":"lt","Lue":"lt","Nv":"nv","Nve":"nt","Nue":"nt","A":"aa","O":"oo","E":"ee","Ai":"ai","Ei":"ei","Ao":"ao","Ou":"ou","An":"an","En":"en","Ang":"ah","Eng":"eg","Er":"er","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"yk","You":"yb","Yan":"yj","Yin":"yn","Yang":"yh","Ying":"yy","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wl","Wei":"wz","Wan":"wj","Wen":"wf","Wang":"wh","Weng":"wg","Yu":"yu","Yue":"yt","Yuan":"yr","Yun":"yp","Yong":"ys","Ba":"ba","Bai":"bl","Ban":"bj","Bang":"bh","Bao":"bk","Bei":"bz","Ben":"bf","Beng":"bg","Bi":"bi","Bian":"bm","Biang":"bd","Biao":"bc","Bie":"bx","Bin":"bn","Bing":"by","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cl","Can":"cj","Cang":"ch","Cao":"ck","Ce":"ce","Cen":"cf","Ceng":"cg","Cha":"ia","Chai":"il","Chan":"ij","Chang":"ih","Chao":"ik","Che":"ie","Chen":"if","Cheng":"ig","Chi":"ii","Chong":"is","Chou":"ib","Chu":"iu","Chua":"iw","Chuai":"iy","Chuan":"ir","Chuang":"id","Chui":"iv","Chun":"ip","Chuo":"io","Ci":"ci","Cong":"cs","Cou":"cb","Cu":"cu","Cuan":"cr","Cui":"cv","Cun":"cp","Cuo":"co","Da":"da","Dai":"dl","Dan":"dj","Dang":"dh","Dao":"dk","De":"de","Dei":"dz","Den":"df","Deng":"dg","Di":"di","Dia":"dw","Dian":"dm","Diao":"dc","Die":"dx","Ding":"dy","Diu":"dq","Dong":"ds","Dou":"db","Du":"du","Duan":"dr","Dui":"dv","Dun":"dp","Duo":"do","Fa":"fa","Fan":"fj","Fang":"fh","Fei":"fz","Fen":"ff","Feng":"fg","Fiao":"fc","Fo":"fo","Fou":"fb","Fu":"fu","Ga":"ga","Gai":"gl","Gan":"gj","Gang":"gh","Gao":"gk","Ge":"ge","Gei":"gz","Gen":"gf","Geng":"gg","Gong":"gs","Gou":"gb","Gu":"gu","Gua":"gw","Guai":"gy","Guan":"gr","Guang":"gd","Gui":"gv","Gun":"gp","Guo":"go","Ha":"ha","Hai":"hl","Han":"hj","Hang":"hh","Hao":"hk","He":"he","Hei":"hz","Hen":"hf","Heng":"hg","Hong":"hs","Hou":"hb","Hu":"hu","Hua":"hw","Huai":"hy","Huan":"hr","Huang":"hd","Hui":"hv","Hun":"hp","Huo":"ho","Ji":"ji","Jia":"jw","Jian":"jm","Jiang":"jd","Jiao":"jc","Jie":"jx","Jin":"jn","Jing":"jy","Jiong":"js","Jiu":"jq","Ju":"ju","Juan":"jr","Jue":"jt","Jun":"jp","Ka":"ka","Kai":"kl","Kan":"kj","Kang":"kh","Kao":"kk","Ke":"ke","Ken":"kf","Keng":"kg","Kong":"ks","Kou":"kb","Ku":"ku","Kua":"kw","Kuai":"ky","Kuan":"kr","Kuang":"kd","Kui":"kv","Kun":"kp","Kuo":"ko","La":"la","Lai":"ll","Lan":"lj","Lang":"lh","Lao":"lk","Le":"le","Lei":"lz","Leng":"lg","Li":"li","Lia":"lw","Lian":"lm","Liang":"ld","Liao":"lc","Lie":"lx","Lin":"ln","Ling":"ly","Liu":"lq","Lo":"lo","Long":"ls","Lou":"lb","Lu":"lu","Luan":"lr","Lun":"lp","Luo":"lo","Ma":"ma","Mai":"ml","Man":"mj","Mang":"mh","Mao":"mk","Me":"me","Mei":"mz","Men":"mf","Meng":"mg","Mi":"mi","Mian":"mm","Miao":"mc","Mie":"mx","Min":"mn","Ming":"my","Miu":"mq","Mo":"mo","Mou":"mb","Mu":"mu","Na":"na","Nai":"nl","Nan":"nj","Nang":"nh","Nao":"nk","Ne":"ne","Nei":"nz","Nen":"nf","Neng":"ng","Ni":"ni","Nian":"nm","Niang":"nd","Niao":"nc","Nie":"nx","Nin":"nn","Ning":"ny","Niu":"nq","Nong":"ns","Nou":"nb","Nu":"nu","Nuan":"nr","Nun":"np","Nuo":"no","Pa":"pa","Pai":"pl","Pan":"pj","Pang":"ph","Pao":"pk","Pei":"pz","Pen":"pf","Peng":"pg","Pi":"pi","Pian":"pm","Piao":"pc","Pie":"px","Pin":"pn","Ping":"py","Po":"po","Pou":"pb","Pu":"pu","Qi":"qi","Qia":"qw","Qian":"qm","Qiang":"qd","Qiao":"qc","Qie":"qx","Qin":"qn","Qing":"qy","Qiong":"qs","Qiu":"qq","Qu":"qu","Quan":"qr","Que":"qt","Qun":"qp","Ran":"rj","Rang":"rh","Rao":"rk","Re":"re","Ren":"rf","Reng":"rg","Ri":"ri","Rong":"rs","Rou":"rb","Ru":"ru","Rua":"rw","Ruan":"rr","Rui":"rv","Run":"rp","Ruo":"ro","Sa":"sa","Sai":"sl","San":"sj","Sang":"sh","Sao":"sk","Se":"se","Sen":"sf","Seng":"sg","Sha":"ua","Shai":"ul","Shan":"uj","Shang":"uh","Shao":"uk","She":"ue","Shei":"uz","Shen":"uf","Sheng":"ug","Shi":"ui","Shou":"ub","Shu":"uu","Shua":"uw","Shuai":"uy","Shuan":"ur","Shuang":"ud","Shui":"uv","Shun":"up","Shuo":"uo","Si":"si","Song":"ss","Sou":"sb","Su":"su","Suan":"sr","Sui":"sv","Sun":"sp","Suo":"so","Ta":"ta","Tai":"tl","Tan":"tj","Tang":"th","Tao":"tk","Te":"te","Tei":"tz","Teng":"tg","Ti":"ti","Tian":"tm","Tiao":"tc","Tie":"tx","Ting":"ty","Tong":"ts","Tou":"tb","Tu":"tu","Tuan":"tr","Tui":"tv","Tun":"tp","Tuo":"to","Xi":"xi","Xia":"xw","Xian":"xm","Xiang":"xd","Xiao":"xc","Xie":"xx","Xin":"xn","Xing":"xy","Xiong":"xs","Xiu":"xq","Xu":"xu","Xuan":"xr","Xue":"xt","Xun":"xp","Za":"za","Zai":"zl","Zan":"zj","Zang":"zh","Zao":"zk","Ze":"ze","Zei":"zz","Zen":"zf","Zeng":"zg","Zha":"va","Zhai":"vl","Zhan":"vj","Zhang":"vh","Zhao":"vk","Zhe":"ve","Zhen":"vf","Zheng":"vg","Zhi":"vi","Zhong":"vs","Zhou":"vb","Zhu":"vu","Zhua":"vw","Zhuai":"vy","Zhuan":"vr","Zhuang":"vd","Zhui":"vv","Zhun":"vp","Zhuo":"vo","Zi":"zi","Zong":"zs","Zou":"zb","Zu":"zu","Zuan":"zr","Zui":"zv","Zun":"zp","Zuo":"zo"},"WeiRuan":{"Lv":"ly","Lve":"lt","Lue":"lt","Nv":"ny","Nve":"nt","Nue":"nt","A":"oa","O":"oo","E":"oe","Ai":"ol","Ei":"oz","Ao":"ok","Ou":"ob","An":"oj","En":"of","Ang":"oh","Eng":"og","Er":"or","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"yk","You":"yb","Yan":"yj","Yin":"yn","Yang":"yh","Ying":"y;","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wl","Wei":"wz","Wan":"wj","Wen":"wf","Wang":"wh","Weng":"wg","Yu":"yu","Yue":"yt","Yuan":"yr","Yun":"yp","Yong":"ys","Ba":"ba","Bai":"bl","Ban":"bj","Bang":"bh","Bao":"bk","Bei":"bz","Ben":"bf","Beng":"bg","Bi":"bi","Bian":"bm","Biang":"bd","Biao":"bc","Bie":"bx","Bin":"bn","Bing":"b;","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cl","Can":"cj","Cang":"ch","Cao":"ck","Ce":"ce","Cen":"cf","Ceng":"cg","Cha":"ia","Chai":"il","Chan":"ij","Chang":"ih","Chao":"ik","Che":"ie","Chen":"if","Cheng":"ig","Chi":"ii","Chong":"is","Chou":"ib","Chu":"iu","Chua":"iw","Chuai":"iy","Chuan":"ir","Chuang":"id","Chui":"iv","Chun":"ip","Chuo":"io","Ci":"ci","Cong":"cs","Cou":"cb","Cu":"cu","Cuan":"cr","Cui":"cv","Cun":"cp","Cuo":"co","Da":"da","Dai":"dl","Dan":"dj","Dang":"dh","Dao":"dk","De":"de","Dei":"dz","Den":"df","Deng":"dg","Di":"di","Dia":"dw","Dian":"dm","Diao":"dc","Die":"dx","Ding":"d;","Diu":"dq","Dong":"ds","Dou":"db","Du":"du","Duan":"dr","Dui":"dv","Dun":"dp","Duo":"do","Fa":"fa","Fan":"fj","Fang":"fh","Fei":"fz","Fen":"ff","Feng":"fg","Fiao":"fc","Fo":"fo","Fou":"fb","Fu":"fu","Ga":"ga","Gai":"gl","Gan":"gj","Gang":"gh","Gao":"gk","Ge":"ge","Gei":"gz","Gen":"gf","Geng":"gg","Gong":"gs","Gou":"gb","Gu":"gu","Gua":"gw","Guai":"gy","Guan":"gr","Guang":"gd","Gui":"gv","Gun":"gp","Guo":"go","Ha":"ha","Hai":"hl","Han":"hj","Hang":"hh","Hao":"hk","He":"he","Hei":"hz","Hen":"hf","Heng":"hg","Hong":"hs","Hou":"hb","Hu":"hu","Hua":"hw","Huai":"hy","Huan":"hr","Huang":"hd","Hui":"hv","Hun":"hp","Huo":"ho","Ji":"ji","Jia":"jw","Jian":"jm","Jiang":"jd","Jiao":"jc","Jie":"jx","Jin":"jn","Jing":"j;","Jiong":"js","Jiu":"jq","Ju":"ju","Juan":"jr","Jue":"jt","Jun":"jp","Ka":"ka","Kai":"kl","Kan":"kj","Kang":"kh","Kao":"kk","Ke":"ke","Ken":"kf","Keng":"kg","Kong":"ks","Kou":"kb","Ku":"ku","Kua":"kw","Kuai":"ky","Kuan":"kr","Kuang":"kd","Kui":"kv","Kun":"kp","Kuo":"ko","La":"la","Lai":"ll","Lan":"lj","Lang":"lh","Lao":"lk","Le":"le","Lei":"lz","Leng":"lg","Li":"li","Lia":"lw","Lian":"lm","Liang":"ld","Liao":"lc","Lie":"lx","Lin":"ln","Ling":"l;","Liu":"lq","Lo":"lo","Long":"ls","Lou":"lb","Lu":"lu","Luan":"lr","Lun":"lp","Luo":"lo","Ma":"ma","Mai":"ml","Man":"mj","Mang":"mh","Mao":"mk","Me":"me","Mei":"mz","Men":"mf","Meng":"mg","Mi":"mi","Mian":"mm","Miao":"mc","Mie":"mx","Min":"mn","Ming":"m;","Miu":"mq","Mo":"mo","Mou":"mb","Mu":"mu","Na":"na","Nai":"nl","Nan":"nj","Nang":"nh","Nao":"nk","Ne":"ne","Nei":"nz","Nen":"nf","Neng":"ng","Ni":"ni","Nian":"nm","Niang":"nd","Niao":"nc","Nie":"nx","Nin":"nn","Ning":"n;","Niu":"nq","Nong":"ns","Nou":"nb","Nu":"nu","Nuan":"nr","Nun":"np","Nuo":"no","Pa":"pa","Pai":"pl","Pan":"pj","Pang":"ph","Pao":"pk","Pei":"pz","Pen":"pf","Peng":"pg","Pi":"pi","Pian":"pm","Piao":"pc","Pie":"px","Pin":"pn","Ping":"p;","Po":"po","Pou":"pb","Pu":"pu","Qi":"qi","Qia":"qw","Qian":"qm","Qiang":"qd","Qiao":"qc","Qie":"qx","Qin":"qn","Qing":"q;","Qiong":"qs","Qiu":"qq","Qu":"qu","Quan":"qr","Que":"qt","Qun":"qp","Ran":"rj","Rang":"rh","Rao":"rk","Re":"re","Ren":"rf","Reng":"rg","Ri":"ri","Rong":"rs","Rou":"rb","Ru":"ru","Rua":"rw","Ruan":"rr","Rui":"rv","Run":"rp","Ruo":"ro","Sa":"sa","Sai":"sl","San":"sj","Sang":"sh","Sao":"sk","Se":"se","Sen":"sf","Seng":"sg","Sha":"ua","Shai":"ul","Shan":"uj","Shang":"uh","Shao":"uk","She":"ue","Shei":"uz","Shen":"uf","Sheng":"ug","Shi":"ui","Shou":"ub","Shu":"uu","Shua":"uw","Shuai":"uy","Shuan":"ur","Shuang":"ud","Shui":"uv","Shun":"up","Shuo":"uo","Si":"si","Song":"ss","Sou":"sb","Su":"su","Suan":"sr","Sui":"sv","Sun":"sp","Suo":"so","Ta":"ta","Tai":"tl","Tan":"tj","Tang":"th","Tao":"tk","Te":"te","Tei":"tz","Teng":"tg","Ti":"ti","Tian":"tm","Tiao":"tc","Tie":"tx","Ting":"t;","Tong":"ts","Tou":"tb","Tu":"tu","Tuan":"tr","Tui":"tv","Tun":"tp","Tuo":"to","Xi":"xi","Xia":"xw","Xian":"xm","Xiang":"xd","Xiao":"xc","Xie":"xx","Xin":"xn","Xing":"x;","Xiong":"xs","Xiu":"xq","Xu":"xu","Xuan":"xr","Xue":"xt","Xun":"xp","Za":"za","Zai":"zl","Zan":"zj","Zang":"zh","Zao":"zk","Ze":"ze","Zei":"zz","Zen":"zf","Zeng":"zg","Zha":"va","Zhai":"vl","Zhan":"vj","Zhang":"vh","Zhao":"vk","Zhe":"ve","Zhen":"vf","Zheng":"vg","Zhi":"vi","Zhong":"vs","Zhou":"vb","Zhu":"vu","Zhua":"vw","Zhuai":"vy","Zhuan":"vr","Zhuang":"vd","Zhui":"vv","Zhun":"vp","Zhuo":"vo","Zi":"zi","Zong":"zs","Zou":"zb","Zu":"zu","Zuan":"zr","Zui":"zv","Zun":"zp","Zuo":"zo"},"ZhiNengABC":{"Lv":"lv","Lve":"lm","Lue":"lm","Nv":"nv","Nve":"nm","Nue":"nm","A":"oa","O":"oo","E":"oe","Ai":"ol","Ei":"oq","Ao":"ok","Ou":"ob","An":"oj","En":"of","Ang":"oh","Eng":"og","Er":"or","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"yk","You":"yb","Yan":"yj","Yin":"yc","Yang":"yh","Ying":"yy","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wl","Wei":"wq","Wan":"wj","Wen":"wf","Wang":"wh","Weng":"wg","Yu":"yu","Yue":"ym","Yuan":"yp","Yun":"yn","Yong":"ys","Ba":"ba","Bai":"bl","Ban":"bj","Bang":"bh","Bao":"bk","Bei":"bq","Ben":"bf","Beng":"bg","Bi":"bi","Bian":"bw","Biang":"bt","Biao":"bz","Bie":"bx","Bin":"bc","Bing":"by","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cl","Can":"cj","Cang":"ch","Cao":"ck","Ce":"ce","Cen":"cf","Ceng":"cg","Cha":"ea","Chai":"el","Chan":"ej","Chang":"eh","Chao":"ek","Che":"ee","Chen":"ef","Cheng":"eg","Chi":"ei","Chong":"es","Chou":"eb","Chu":"eu","Chua":"ed","Chuai":"ec","Chuan":"ep","Chuang":"et","Chui":"em","Chun":"en","Chuo":"eo","Ci":"ci","Cong":"cs","Cou":"cb","Cu":"cu","Cuan":"cp","Cui":"cm","Cun":"cn","Cuo":"co","Da":"da","Dai":"dl","Dan":"dj","Dang":"dh","Dao":"dk","De":"de","Dei":"dq","Den":"df","Deng":"dg","Di":"di","Dia":"dd","Dian":"dw","Diao":"dz","Die":"dx","Ding":"dy","Diu":"dr","Dong":"ds","Dou":"db","Du":"du","Duan":"dp","Dui":"dm","Dun":"dn","Duo":"do","Fa":"fa","Fan":"fj","Fang":"fh","Fei":"fq","Fen":"ff","Feng":"fg","Fiao":"fz","Fo":"fo","Fou":"fb","Fu":"fu","Ga":"ga","Gai":"gl","Gan":"gj","Gang":"gh","Gao":"gk","Ge":"ge","Gei":"gq","Gen":"gf","Geng":"gg","Gong":"gs","Gou":"gb","Gu":"gu","Gua":"gd","Guai":"gc","Guan":"gp","Guang":"gt","Gui":"gm","Gun":"gn","Guo":"go","Ha":"ha","Hai":"hl","Han":"hj","Hang":"hh","Hao":"hk","He":"he","Hei":"hq","Hen":"hf","Heng":"hg","Hong":"hs","Hou":"hb","Hu":"hu","Hua":"hd","Huai":"hc","Huan":"hp","Huang":"ht","Hui":"hm","Hun":"hn","Huo":"ho","Ji":"ji","Jia":"jd","Jian":"jw","Jiang":"jt","Jiao":"jz","Jie":"jx","Jin":"jc","Jing":"jy","Jiong":"js","Jiu":"jr","Ju":"ju","Juan":"jp","Jue":"jm","Jun":"jn","Ka":"ka","Kai":"kl","Kan":"kj","Kang":"kh","Kao":"kk","Ke":"ke","Ken":"kf","Keng":"kg","Kong":"ks","Kou":"kb","Ku":"ku","Kua":"kd","Kuai":"kc","Kuan":"kp","Kuang":"kt","Kui":"km","Kun":"kn","Kuo":"ko","La":"la","Lai":"ll","Lan":"lj","Lang":"lh","Lao":"lk","Le":"le","Lei":"lq","Leng":"lg","Li":"li","Lia":"ld","Lian":"lw","Liang":"lt","Liao":"lz","Lie":"lx","Lin":"lc","Ling":"ly","Liu":"lr","Lo":"lo","Long":"ls","Lou":"lb","Lu":"lu","Luan":"lp","Lun":"ln","Luo":"lo","Ma":"ma","Mai":"ml","Man":"mj","Mang":"mh","Mao":"mk","Me":"me","Mei":"mq","Men":"mf","Meng":"mg","Mi":"mi","Mian":"mw","Miao":"mz","Mie":"mx","Min":"mc","Ming":"my","Miu":"mr","Mo":"mo","Mou":"mb","Mu":"mu","Na":"na","Nai":"nl","Nan":"nj","Nang":"nh","Nao":"nk","Ne":"ne","Nei":"nq","Nen":"nf","Neng":"ng","Ni":"ni","Nian":"nw","Niang":"nt","Niao":"nz","Nie":"nx","Nin":"nc","Ning":"ny","Niu":"nr","Nong":"ns","Nou":"nb","Nu":"nu","Nuan":"np","Nun":"nn","Nuo":"no","Pa":"pa","Pai":"pl","Pan":"pj","Pang":"ph","Pao":"pk","Pei":"pq","Pen":"pf","Peng":"pg","Pi":"pi","Pian":"pw","Piao":"pz","Pie":"px","Pin":"pc","Ping":"py","Po":"po","Pou":"pb","Pu":"pu","Qi":"qi","Qia":"qd","Qian":"qw","Qiang":"qt","Qiao":"qz","Qie":"qx","Qin":"qc","Qing":"qy","Qiong":"qs","Qiu":"qr","Qu":"qu","Quan":"qp","Que":"qm","Qun":"qn","Ran":"rj","Rang":"rh","Rao":"rk","Re":"re","Ren":"rf","Reng":"rg","Ri":"ri","Rong":"rs","Rou":"rb","Ru":"ru","Rua":"rd","Ruan":"rp","Rui":"rm","Run":"rn","Ruo":"ro","Sa":"sa","Sai":"sl","San":"sj","Sang":"sh","Sao":"sk","Se":"se","Sen":"sf","Seng":"sg","Sha":"va","Shai":"vl","Shan":"vj","Shang":"vh","Shao":"vk","She":"ve","Shei":"vq","Shen":"vf","Sheng":"vg","Shi":"vi","Shou":"vb","Shu":"vu","Shua":"vd","Shuai":"vc","Shuan":"vp","Shuang":"vt","Shui":"vm","Shun":"vn","Shuo":"vo","Si":"si","Song":"ss","Sou":"sb","Su":"su","Suan":"sp","Sui":"sm","Sun":"sn","Suo":"so","Ta":"ta","Tai":"tl","Tan":"tj","Tang":"th","Tao":"tk","Te":"te","Tei":"tq","Teng":"tg","Ti":"ti","Tian":"tw","Tiao":"tz","Tie":"tx","Ting":"ty","Tong":"ts","Tou":"tb","Tu":"tu","Tuan":"tp","Tui":"tm","Tun":"tn","Tuo":"to","Xi":"xi","Xia":"xd","Xian":"xw","Xiang":"xt","Xiao":"xz","Xie":"xx","Xin":"xc","Xing":"xy","Xiong":"xs","Xiu":"xr","Xu":"xu","Xuan":"xp","Xue":"xm","Xun":"xn","Za":"za","Zai":"zl","Zan":"zj","Zang":"zh","Zao":"zk","Ze":"ze","Zei":"zq","Zen":"zf","Zeng":"zg","Zha":"aa","Zhai":"al","Zhan":"aj","Zhang":"ah","Zhao":"ak","Zhe":"ae","Zhen":"af","Zheng":"ag","Zhi":"ai","Zhong":"as","Zhou":"ab","Zhu":"au","Zhua":"ad","Zhuai":"ac","Zhuan":"ap","Zhuang":"at","Zhui":"am","Zhun":"an","Zhuo":"ao","Zi":"zi","Zong":"zs","Zou":"zb","Zu":"zu","Zuan":"zp","Zui":"zm","Zun":"zn","Zuo":"zo"},"ZiGuangPinYin":{"Lv":"lv","Lve":"ln","Lue":"ln","Nv":"nv","Nve":"nn","Nue":"nn","A":"oa","O":"oo","E":"oe","Ai":"op","Ei":"ok","Ao":"oq","Ou":"oz","An":"or","En":"ow","Ang":"os","Eng":"ot","Er":"oj","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"yq","You":"yz","Yan":"yr","Yin":"yy","Yang":"ys","Ying":"yc","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wp","Wei":"wk","Wan":"wr","Wen":"ww","Wang":"ws","Weng":"wt","Yu":"yu","Yue":"yn","Yuan":"yl","Yun":"ym","Yong":"yh","Ba":"ba","Bai":"bp","Ban":"br","Bang":"bs","Bao":"bq","Bei":"bk","Ben":"bw","Beng":"bt","Bi":"bi","Bian":"bf","Biang":"bg","Biao":"bb","Bie":"bd","Bin":"by","Bing":"bc","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cp","Can":"cr","Cang":"cs","Cao":"cq","Ce":"ce","Cen":"cw","Ceng":"ct","Cha":"aa","Chai":"ap","Chan":"ar","Chang":"as","Chao":"aq","Che":"ae","Chen":"aw","Cheng":"at","Chi":"ai","Chong":"ah","Chou":"az","Chu":"au","Chua":"ax","Chuai":"ay","Chuan":"al","Chuang":"ag","Chui":"an","Chun":"am","Chuo":"ao","Ci":"ci","Cong":"ch","Cou":"cz","Cu":"cu","Cuan":"cl","Cui":"cn","Cun":"cm","Cuo":"co","Da":"da","Dai":"dp","Dan":"dr","Dang":"ds","Dao":"dq","De":"de","Dei":"dk","Den":"dw","Deng":"dt","Di":"di","Dia":"dx","Dian":"df","Diao":"db","Die":"dd","Ding":"dc","Diu":"dj","Dong":"dh","Dou":"dz","Du":"du","Duan":"dl","Dui":"dn","Dun":"dm","Duo":"do","Fa":"fa","Fan":"fr","Fang":"fs","Fei":"fk","Fen":"fw","Feng":"ft","Fiao":"fb","Fo":"fo","Fou":"fz","Fu":"fu","Ga":"ga","Gai":"gp","Gan":"gr","Gang":"gs","Gao":"gq","Ge":"ge","Gei":"gk","Gen":"gw","Geng":"gt","Gong":"gh","Gou":"gz","Gu":"gu","Gua":"gx","Guai":"gy","Guan":"gl","Guang":"gg","Gui":"gn","Gun":"gm","Guo":"go","Ha":"ha","Hai":"hp","Han":"hr","Hang":"hs","Hao":"hq","He":"he","Hei":"hk","Hen":"hw","Heng":"ht","Hong":"hh","Hou":"hz","Hu":"hu","Hua":"hx","Huai":"hy","Huan":"hl","Huang":"hg","Hui":"hn","Hun":"hm","Huo":"ho","Ji":"ji","Jia":"jx","Jian":"jf","Jiang":"jg","Jiao":"jb","Jie":"jd","Jin":"jy","Jing":"jc","Jiong":"jh","Jiu":"jj","Ju":"ju","Juan":"jl","Jue":"jn","Jun":"jm","Ka":"ka","Kai":"kp","Kan":"kr","Kang":"ks","Kao":"kq","Ke":"ke","Ken":"kw","Keng":"kt","Kong":"kh","Kou":"kz","Ku":"ku","Kua":"kx","Kuai":"ky","Kuan":"kl","Kuang":"kg","Kui":"kn","Kun":"km","Kuo":"ko","La":"la","Lai":"lp","Lan":"lr","Lang":"ls","Lao":"lq","Le":"le","Lei":"lk","Leng":"lt","Li":"li","Lia":"lx","Lian":"lf","Liang":"lg","Liao":"lb","Lie":"ld","Lin":"ly","Ling":"lc","Liu":"lj","Lo":"lo","Long":"lh","Lou":"lz","Lu":"lu","Luan":"ll","Lun":"lm","Luo":"lo","Ma":"ma","Mai":"mp","Man":"mr","Mang":"ms","Mao":"mq","Me":"me","Mei":"mk","Men":"mw","Meng":"mt","Mi":"mi","Mian":"mf","Miao":"mb","Mie":"md","Min":"my","Ming":"mc","Miu":"mj","Mo":"mo","Mou":"mz","Mu":"mu","Na":"na","Nai":"np","Nan":"nr","Nang":"ns","Nao":"nq","Ne":"ne","Nei":"nk","Nen":"nw","Neng":"nt","Ni":"ni","Nian":"nf","Niang":"ng","Niao":"nb","Nie":"nd","Nin":"ny","Ning":"nc","Niu":"nj","Nong":"nh","Nou":"nz","Nu":"nu","Nuan":"nl","Nun":"nm","Nuo":"no","Pa":"pa","Pai":"pp","Pan":"pr","Pang":"ps","Pao":"pq","Pei":"pk","Pen":"pw","Peng":"pt","Pi":"pi","Pian":"pf","Piao":"pb","Pie":"pd","Pin":"py","Ping":"pc","Po":"po","Pou":"pz","Pu":"pu","Qi":"qi","Qia":"qx","Qian":"qf","Qiang":"qg","Qiao":"qb","Qie":"qd","Qin":"qy","Qing":"qc","Qiong":"qh","Qiu":"qj","Qu":"qu","Quan":"ql","Que":"qn","Qun":"qm","Ran":"rr","Rang":"rs","Rao":"rq","Re":"re","Ren":"rw","Reng":"rt","Ri":"ri","Rong":"rh","Rou":"rz","Ru":"ru","Rua":"rx","Ruan":"rl","Rui":"rn","Run":"rm","Ruo":"ro","Sa":"sa","Sai":"sp","San":"sr","Sang":"ss","Sao":"sq","Se":"se","Sen":"sw","Seng":"st","Sha":"ia","Shai":"ip","Shan":"ir","Shang":"is","Shao":"iq","She":"ie","Shei":"ik","Shen":"iw","Sheng":"it","Shi":"ii","Shou":"iz","Shu":"iu","Shua":"ix","Shuai":"iy","Shuan":"il","Shuang":"ig","Shui":"in","Shun":"im","Shuo":"io","Si":"si","Song":"sh","Sou":"sz","Su":"su","Suan":"sl","Sui":"sn","Sun":"sm","Suo":"so","Ta":"ta","Tai":"tp","Tan":"tr","Tang":"ts","Tao":"tq","Te":"te","Tei":"tk","Teng":"tt","Ti":"ti","Tian":"tf","Tiao":"tb","Tie":"td","Ting":"tc","Tong":"th","Tou":"tz","Tu":"tu","Tuan":"tl","Tui":"tn","Tun":"tm","Tuo":"to","Xi":"xi","Xia":"xx","Xian":"xf","Xiang":"xg","Xiao":"xb","Xie":"xd","Xin":"xy","Xing":"xc","Xiong":"xh","Xiu":"xj","Xu":"xu","Xuan":"xl","Xue":"xn","Xun":"xm","Za":"za","Zai":"zp","Zan":"zr","Zang":"zs","Zao":"zq","Ze":"ze","Zei":"zk","Zen":"zw","Zeng":"zt","Zha":"ua","Zhai":"up","Zhan":"ur","Zhang":"us","Zhao":"uq","Zhe":"ue","Zhen":"uw","Zheng":"ut","Zhi":"ui","Zhong":"uh","Zhou":"uz","Zhu":"uu","Zhua":"ux","Zhuai":"uy","Zhuan":"ul","Zhuang":"ug","Zhui":"un","Zhun":"um","Zhuo":"uo","Zi":"zi","Zong":"zh","Zou":"zz","Zu":"zu","Zuan":"zl","Zui":"zn","Zun":"zm","Zuo":"zo"},"PinYinJiaJia":{"Lv":"lv","Lve":"lx","Lue":"lx","Nv":"nv","Nve":"nx","Nue":"nx","A":"aa","O":"oo","E":"ee","Ai":"as","Ei":"ew","Ao":"ad","Ou":"op","An":"af","En":"er","Ang":"ag","Eng":"et","Er":"eq","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"yd","You":"yp","Yan":"yf","Yin":"yl","Yang":"yg","Ying":"yq","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"ws","Wei":"ww","Wan":"wf","Wen":"wr","Wang":"wg","Weng":"wt","Yu":"yu","Yue":"yx","Yuan":"yc","Yun":"yz","Yong":"yy","Ba":"ba","Bai":"bs","Ban":"bf","Bang":"bg","Bao":"bd","Bei":"bw","Ben":"br","Beng":"bt","Bi":"bi","Bian":"bj","Biang":"bh","Biao":"bk","Bie":"bm","Bin":"bl","Bing":"bq","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cs","Can":"cf","Cang":"cg","Cao":"cd","Ce":"ce","Cen":"cr","Ceng":"ct","Cha":"ua","Chai":"us","Chan":"uf","Chang":"ug","Chao":"ud","Che":"ue","Chen":"ur","Cheng":"ut","Chi":"ui","Chong":"uy","Chou":"up","Chu":"uu","Chua":"ub","Chuai":"ux","Chuan":"uc","Chuang":"uh","Chui":"uv","Chun":"uz","Chuo":"uo","Ci":"ci","Cong":"cy","Cou":"cp","Cu":"cu","Cuan":"cc","Cui":"cv","Cun":"cz","Cuo":"co","Da":"da","Dai":"ds","Dan":"df","Dang":"dg","Dao":"dd","De":"de","Dei":"dw","Den":"dr","Deng":"dt","Di":"di","Dia":"db","Dian":"dj","Diao":"dk","Die":"dm","Ding":"dq","Diu":"dn","Dong":"dy","Dou":"dp","Du":"du","Duan":"dc","Dui":"dv","Dun":"dz","Duo":"do","Fa":"fa","Fan":"ff","Fang":"fg","Fei":"fw","Fen":"fr","Feng":"ft","Fiao":"fk","Fo":"fo","Fou":"fp","Fu":"fu","Ga":"ga","Gai":"gs","Gan":"gf","Gang":"gg","Gao":"gd","Ge":"ge","Gei":"gw","Gen":"gr","Geng":"gt","Gong":"gy","Gou":"gp","Gu":"gu","Gua":"gb","Guai":"gx","Guan":"gc","Guang":"gh","Gui":"gv","Gun":"gz","Guo":"go","Ha":"ha","Hai":"hs","Han":"hf","Hang":"hg","Hao":"hd","He":"he","Hei":"hw","Hen":"hr","Heng":"ht","Hong":"hy","Hou":"hp","Hu":"hu","Hua":"hb","Huai":"hx","Huan":"hc","Huang":"hh","Hui":"hv","Hun":"hz","Huo":"ho","Ji":"ji","Jia":"jb","Jian":"jj","Jiang":"jh","Jiao":"jk","Jie":"jm","Jin":"jl","Jing":"jq","Jiong":"jy","Jiu":"jn","Ju":"ju","Juan":"jc","Jue":"jx","Jun":"jz","Ka":"ka","Kai":"ks","Kan":"kf","Kang":"kg","Kao":"kd","Ke":"ke","Ken":"kr","Keng":"kt","Kong":"ky","Kou":"kp","Ku":"ku","Kua":"kb","Kuai":"kx","Kuan":"kc","Kuang":"kh","Kui":"kv","Kun":"kz","Kuo":"ko","La":"la","Lai":"ls","Lan":"lf","Lang":"lg","Lao":"ld","Le":"le","Lei":"lw","Leng":"lt","Li":"li","Lia":"lb","Lian":"lj","Liang":"lh","Liao":"lk","Lie":"lm","Lin":"ll","Ling":"lq","Liu":"ln","Lo":"lo","Long":"ly","Lou":"lp","Lu":"lu","Luan":"lc","Lun":"lz","Luo":"lo","Ma":"ma","Mai":"ms","Man":"mf","Mang":"mg","Mao":"md","Me":"me","Mei":"mw","Men":"mr","Meng":"mt","Mi":"mi","Mian":"mj","Miao":"mk","Mie":"mm","Min":"ml","Ming":"mq","Miu":"mn","Mo":"mo","Mou":"mp","Mu":"mu","Na":"na","Nai":"ns","Nan":"nf","Nang":"ng","Nao":"nd","Ne":"ne","Nei":"nw","Nen":"nr","Neng":"nt","Ni":"ni","Nian":"nj","Niang":"nh","Niao":"nk","Nie":"nm","Nin":"nl","Ning":"nq","Niu":"nn","Nong":"ny","Nou":"np","Nu":"nu","Nuan":"nc","Nun":"nz","Nuo":"no","Pa":"pa","Pai":"ps","Pan":"pf","Pang":"pg","Pao":"pd","Pei":"pw","Pen":"pr","Peng":"pt","Pi":"pi","Pian":"pj","Piao":"pk","Pie":"pm","Pin":"pl","Ping":"pq","Po":"po","Pou":"pp","Pu":"pu","Qi":"qi","Qia":"qb","Qian":"qj","Qiang":"qh","Qiao":"qk","Qie":"qm","Qin":"ql","Qing":"qq","Qiong":"qy","Qiu":"qn","Qu":"qu","Quan":"qc","Que":"qx","Qun":"qz","Ran":"rf","Rang":"rg","Rao":"rd","Re":"re","Ren":"rr","Reng":"rt","Ri":"ri","Rong":"ry","Rou":"rp","Ru":"ru","Rua":"rb","Ruan":"rc","Rui":"rv","Run":"rz","Ruo":"ro","Sa":"sa","Sai":"ss","San":"sf","Sang":"sg","Sao":"sd","Se":"se","Sen":"sr","Seng":"st","Sha":"ia","Shai":"is","Shan":"if","Shang":"ig","Shao":"id","She":"ie","Shei":"iw","Shen":"ir","Sheng":"it","Shi":"ii","Shou":"ip","Shu":"iu","Shua":"ib","Shuai":"ix","Shuan":"ic","Shuang":"ih","Shui":"iv","Shun":"iz","Shuo":"io","Si":"si","Song":"sy","Sou":"sp","Su":"su","Suan":"sc","Sui":"sv","Sun":"sz","Suo":"so","Ta":"ta","Tai":"ts","Tan":"tf","Tang":"tg","Tao":"td","Te":"te","Tei":"tw","Teng":"tt","Ti":"ti","Tian":"tj","Tiao":"tk","Tie":"tm","Ting":"tq","Tong":"ty","Tou":"tp","Tu":"tu","Tuan":"tc","Tui":"tv","Tun":"tz","Tuo":"to","Xi":"xi","Xia":"xb","Xian":"xj","Xiang":"xh","Xiao":"xk","Xie":"xm","Xin":"xl","Xing":"xq","Xiong":"xy","Xiu":"xn","Xu":"xu","Xuan":"xc","Xue":"xx","Xun":"xz","Za":"za","Zai":"zs","Zan":"zf","Zang":"zg","Zao":"zd","Ze":"ze","Zei":"zw","Zen":"zr","Zeng":"zt","Zha":"va","Zhai":"vs","Zhan":"vf","Zhang":"vg","Zhao":"vd","Zhe":"ve","Zhen":"vr","Zheng":"vt","Zhi":"vi","Zhong":"vy","Zhou":"vp","Zhu":"vu","Zhua":"vb","Zhuai":"vx","Zhuan":"vc","Zhuang":"vh","Zhui":"vv","Zhun":"vz","Zhuo":"vo","Zi":"zi","Zong":"zy","Zou":"zp","Zu":"zu","Zuan":"zc","Zui":"zv","Zun":"zz","Zuo":"zo"},"XingKongJianDao":{"Lv":"lv","Lve":"ly","Lue":"ly","Nv":"nv","Nve":"ny","Nue":"ny","A":"xa","O":"xo","E":"xe","Ai":"xj","Ei":"xw","Ao":"xs","Ou":"xt","An":"xd","En":"xk","Ang":"xf","Eng":"xh","Er":"xu","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"ys","You":"yt","Yan":"yd","Yin":"yb","Yang":"yf","Ying":"yg","Wu":"wj","Wa":"ws","Wo":"wo","Wai":"wh","Wei":"ww","Wan":"wf","Wen":"wn","Wang":"wp","Weng":"wr","Yu":"yv","Yue":"yy","Yuan":"yr","Yun":"yw","Yong":"yl","Ba":"ba","Bai":"bj","Ban":"bd","Bang":"bf","Bao":"bs","Bei":"bw","Ben":"bk","Beng":"bh","Bi":"bi","Bian":"bm","Biang":"bx","Biao":"bp","Bie":"bc","Bin":"bb","Bing":"bg","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"cj","Can":"cd","Cang":"cf","Cao":"cs","Ce":"ce","Cen":"ck","Ceng":"ch","Cha":"ja","Chai":"jj","Chan":"jd","Chang":"jf","Chao":"js","Che":"je","Chen":"jk","Cheng":"jh","Chi":"wi","Chong":"wl","Chou":"jt","Chu":"ju","Chua":"wx","Chuai":"wg","Chuan":"wr","Chuang":"wn","Chui":"wy","Chun":"jz","Chuo":"jo","Ci":"ci","Cong":"cl","Cou":"ct","Cu":"cu","Cuan":"cr","Cui":"cy","Cun":"cz","Cuo":"co","Da":"da","Dai":"dj","Dan":"dd","Dang":"df","Dao":"ds","De":"de","Dei":"dw","Den":"dk","Deng":"dh","Di":"di","Dia":"dx","Dian":"dm","Diao":"dp","Die":"dc","Ding":"dg","Diu":"dq","Dong":"dl","Dou":"dt","Du":"du","Duan":"dr","Dui":"dy","Dun":"dz","Duo":"do","Fa":"fs","Fan":"ff","Fang":"fp","Fei":"fw","Fen":"fn","Feng":"fr","Fiao":"fp","Fo":"fl","Fou":"fd","Fu":"fl","Ga":"ga","Gai":"gj","Gan":"gd","Gang":"gf","Gao":"gs","Ge":"ge","Gei":"gw","Gen":"gk","Geng":"gh","Gong":"gl","Gou":"gt","Gu":"gu","Gua":"gx","Guai":"gg","Guan":"gr","Guang":"gn","Gui":"gy","Gun":"gz","Guo":"go","Ha":"ha","Hai":"hj","Han":"hd","Hang":"hf","Hao":"hs","He":"he","Hei":"hw","Hen":"hk","Heng":"hh","Hong":"hl","Hou":"ht","Hu":"hu","Hua":"hx","Huai":"hg","Huan":"hr","Huang":"hn","Hui":"hy","Hun":"hz","Huo":"ho","Ji":"jk","Jia":"js","Jian":"jm","Jiang":"jn","Jiao":"jp","Jie":"jc","Jin":"jb","Jing":"jg","Jiong":"jy","Jiu":"jq","Ju":"jv","Juan":"jt","Jue":"jh","Jun":"jw","Ka":"ka","Kai":"kj","Kan":"kd","Kang":"kf","Kao":"ks","Ke":"ke","Ken":"kk","Keng":"kh","Kong":"kl","Kou":"kt","Ku":"ku","Kua":"kx","Kuai":"kg","Kuan":"kr","Kuang":"kn","Kui":"ky","Kun":"kz","Kuo":"ko","La":"la","Lai":"lj","Lan":"ld","Lang":"lf","Lao":"ls","Le":"le","Lei":"lw","Leng":"lh","Li":"li","Lia":"lx","Lian":"lm","Liang":"ln","Liao":"lp","Lie":"lc","Lin":"lb","Ling":"lg","Liu":"lq","Lo":"ll","Long":"ll","Lou":"lt","Lu":"lu","Luan":"lr","Lun":"lz","Luo":"lo","Ma":"ma","Mai":"mj","Man":"md","Mang":"mf","Mao":"ms","Me":"me","Mei":"mw","Men":"mk","Meng":"mh","Mi":"mi","Mian":"mm","Miao":"mp","Mie":"mc","Min":"mb","Ming":"mg","Miu":"mq","Mo":"mo","Mou":"mt","Mu":"mu","Na":"na","Nai":"nj","Nan":"nd","Nang":"nf","Nao":"ns","Ne":"ne","Nei":"nw","Nen":"nk","Neng":"nh","Ni":"ni","Nian":"nm","Niang":"nn","Niao":"np","Nie":"nc","Nin":"nb","Ning":"ng","Niu":"nq","Nong":"nl","Nou":"nt","Nu":"nu","Nuan":"nr","Nun":"nz","Nuo":"no","Pa":"pa","Pai":"pj","Pan":"pd","Pang":"pf","Pao":"ps","Pei":"pw","Pen":"pk","Peng":"ph","Pi":"pi","Pian":"pm","Piao":"pp","Pie":"pc","Pin":"pb","Ping":"pg","Po":"po","Pou":"pt","Pu":"pu","Qi":"qk","Qia":"qs","Qian":"qm","Qiang":"qx","Qiao":"qp","Qie":"qc","Qin":"qb","Qing":"qg","Qiong":"qy","Qiu":"qq","Qu":"qv","Quan":"qt","Que":"qh","Qun":"qw","Ran":"rd","Rang":"rf","Rao":"rs","Re":"re","Ren":"rk","Reng":"rh","Ri":"ri","Rong":"rl","Rou":"rt","Ru":"ru","Rua":"rx","Ruan":"rr","Rui":"ry","Run":"rz","Ruo":"ro","Sa":"sa","Sai":"sj","San":"sd","Sang":"sf","Sao":"ss","Se":"se","Sen":"sk","Seng":"sh","Sha":"ea","Shai":"ej","Shan":"ed","Shang":"ef","Shao":"es","She":"ee","Shei":"ew","Shen":"ek","Sheng":"eh","Shi":"ei","Shou":"et","Shu":"eu","Shua":"ex","Shuai":"eg","Shuan":"er","Shuang":"en","Shui":"ey","Shun":"ez","Shuo":"eo","Si":"si","Song":"sl","Sou":"st","Su":"su","Suan":"sr","Sui":"sy","Sun":"sz","Suo":"so","Ta":"ta","Tai":"tj","Tan":"td","Tang":"tf","Tao":"ts","Te":"te","Tei":"tw","Teng":"th","Ti":"ti","Tian":"tm","Tiao":"tp","Tie":"tc","Ting":"tg","Tong":"tl","Tou":"tt","Tu":"tu","Tuan":"tr","Tui":"ty","Tun":"tz","Tuo":"to","Xi":"xi","Xia":"xx","Xian":"xm","Xiang":"xn","Xiao":"xp","Xie":"xc","Xin":"xb","Xing":"xg","Xiong":"xl","Xiu":"xq","Xu":"xv","Xuan":"xr","Xue":"xy","Xun":"xw","Za":"za","Zai":"zj","Zan":"zd","Zang":"zf","Zao":"zs","Ze":"ze","Zei":"zw","Zen":"zk","Zeng":"zh","Zha":"qa","Zhai":"fj","Zhan":"qd","Zhang":"qf","Zhao":"fs","Zhe":"fe","Zhen":"qk","Zheng":"qh","Zhi":"fi","Zhong":"fy","Zhou":"qt","Zhu":"qu","Zhua":"fx","Zhuai":"fg","Zhuan":"fr","Zhuang":"fn","Zhui":"fy","Zhun":"fz","Zhuo":"qo","Zi":"zi","Zong":"zl","Zou":"zt","Zu":"zu","Zuan":"zr","Zui":"zy","Zun":"zz","Zuo":"zo"},"DaNiu":{"Lv":"lv","Lve":"lx","Lue":"lx","Nv":"nv","Nve":"nx","Nue":"nx","A":"ea","O":"eo","E":"ee","Ai":"eh","Ei":"ew","Ao":"es","Ou":"er","An":"ed","En":"ek","Ang":"ef","Eng":"ej","Er":"eu","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"ys","You":"yr","Yan":"yd","Yin":"yb","Yang":"yf","Ying":"yg","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wh","Wei":"ww","Wan":"wd","Wen":"wk","Wang":"wf","Weng":"wj","Yu":"yu","Yue":"yh","Yuan":"yj","Yun":"yw","Yong":"yl","Ba":"ba","Bai":"bh","Ban":"bd","Bang":"bf","Bao":"bs","Bei":"bw","Ben":"bk","Beng":"bj","Bi":"bi","Bian":"bc","Biang":"bn","Biao":"bm","Bie":"bp","Bin":"bb","Bing":"bg","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"ch","Can":"cd","Cang":"cf","Cao":"cs","Ce":"ce","Cen":"ck","Ceng":"cj","Cha":"ia","Chai":"ih","Chan":"id","Chang":"if","Chao":"is","Che":"ie","Chen":"ik","Cheng":"ij","Chi":"ii","Chong":"il","Chou":"ir","Chu":"iu","Chua":"iq","Chuai":"ig","Chuan":"iz","Chuang":"ix","Chui":"in","Chun":"iy","Chuo":"io","Ci":"ci","Cong":"cl","Cou":"cr","Cu":"cu","Cuan":"cz","Cui":"cn","Cun":"cy","Cuo":"co","Da":"da","Dai":"dh","Dan":"dd","Dang":"df","Dao":"ds","De":"de","Dei":"dw","Den":"dk","Deng":"dj","Di":"di","Dia":"dk","Dian":"dc","Diao":"dm","Die":"dp","Ding":"dg","Diu":"dt","Dong":"dl","Dou":"dr","Du":"du","Duan":"dz","Dui":"dn","Dun":"dy","Duo":"do","Fa":"fa","Fan":"fd","Fang":"ff","Fei":"fw","Fen":"fk","Feng":"fj","Fiao":"fm","Fo":"fo","Fou":"fr","Fu":"fu","Ga":"ga","Gai":"gh","Gan":"gd","Gang":"gf","Gao":"gs","Ge":"ge","Gei":"gw","Gen":"gk","Geng":"gj","Gong":"gl","Gou":"gr","Gu":"gu","Gua":"gq","Guai":"gg","Guan":"gz","Guang":"gx","Gui":"gn","Gun":"gy","Guo":"go","Ha":"ha","Hai":"hh","Han":"hd","Hang":"hf","Hao":"hs","He":"he","Hei":"hw","Hen":"hk","Heng":"hj","Hong":"hl","Hou":"hr","Hu":"hu","Hua":"hq","Huai":"hg","Huan":"hz","Huang":"hx","Hui":"hn","Hun":"hy","Huo":"ho","Ji":"ji","Jia":"jk","Jian":"jc","Jiang":"jn","Jiao":"jm","Jie":"jp","Jin":"jb","Jing":"jg","Jiong":"jl","Jiu":"jt","Ju":"ju","Juan":"jj","Jue":"jh","Jun":"jw","Ka":"ka","Kai":"kh","Kan":"kd","Kang":"kf","Kao":"ks","Ke":"ke","Ken":"kk","Keng":"kj","Kong":"kl","Kou":"kr","Ku":"ku","Kua":"kq","Kuai":"kg","Kuan":"kz","Kuang":"kx","Kui":"kn","Kun":"ky","Kuo":"ko","La":"la","Lai":"lh","Lan":"ld","Lang":"lf","Lao":"ls","Le":"le","Lei":"lw","Leng":"lj","Li":"li","Lia":"lk","Lian":"lc","Liang":"ln","Liao":"lm","Lie":"lp","Lin":"lb","Ling":"lg","Liu":"lt","Lo":"lo","Long":"ll","Lou":"lr","Lu":"lu","Luan":"lz","Lun":"ly","Luo":"lo","Ma":"ma","Mai":"mh","Man":"md","Mang":"mf","Mao":"ms","Me":"me","Mei":"mw","Men":"mk","Meng":"mj","Mi":"mi","Mian":"mc","Miao":"mm","Mie":"mp","Min":"mb","Ming":"mg","Miu":"mt","Mo":"mo","Mou":"mr","Mu":"mu","Na":"na","Nai":"nh","Nan":"nd","Nang":"nf","Nao":"ns","Ne":"ne","Nei":"nw","Nen":"nk","Neng":"nj","Ni":"ni","Nian":"nc","Niang":"nn","Niao":"nm","Nie":"np","Nin":"nb","Ning":"ng","Niu":"nt","Nong":"nl","Nou":"nr","Nu":"nu","Nuan":"nz","Nun":"ny","Nuo":"no","Pa":"pa","Pai":"ph","Pan":"pd","Pang":"pf","Pao":"ps","Pei":"pw","Pen":"pk","Peng":"pj","Pi":"pi","Pian":"pc","Piao":"pm","Pie":"pp","Pin":"pb","Ping":"pg","Po":"po","Pou":"pr","Pu":"pu","Qi":"qi","Qia":"qk","Qian":"qc","Qiang":"qn","Qiao":"qm","Qie":"qp","Qin":"qb","Qing":"qg","Qiong":"ql","Qiu":"qt","Qu":"qu","Quan":"qj","Que":"qh","Qun":"qw","Ran":"rd","Rang":"rf","Rao":"rs","Re":"re","Ren":"rk","Reng":"rj","Ri":"ri","Rong":"rl","Rou":"rr","Ru":"ru","Rua":"rq","Ruan":"rz","Rui":"rn","Run":"ry","Ruo":"ro","Sa":"sa","Sai":"sh","San":"sd","Sang":"sf","Sao":"ss","Se":"se","Sen":"sk","Seng":"sj","Sha":"ua","Shai":"uh","Shan":"ud","Shang":"uf","Shao":"us","She":"ue","Shei":"uw","Shen":"uk","Sheng":"uj","Shi":"ui","Shou":"ur","Shu":"uu","Shua":"uq","Shuai":"ug","Shuan":"uz","Shuang":"ux","Shui":"un","Shun":"uy","Shuo":"uo","Si":"si","Song":"sl","Sou":"sr","Su":"su","Suan":"sz","Sui":"sn","Sun":"sy","Suo":"so","Ta":"ta","Tai":"th","Tan":"td","Tang":"tf","Tao":"ts","Te":"te","Tei":"tw","Teng":"tj","Ti":"ti","Tian":"tc","Tiao":"tm","Tie":"tp","Ting":"tg","Tong":"tl","Tou":"tr","Tu":"tu","Tuan":"tz","Tui":"tn","Tun":"ty","Tuo":"to","Xi":"xi","Xia":"xk","Xian":"xc","Xiang":"xn","Xiao":"xm","Xie":"xp","Xin":"xb","Xing":"xg","Xiong":"xl","Xiu":"xt","Xu":"xu","Xuan":"xj","Xue":"xh","Xun":"xw","Za":"za","Zai":"zh","Zan":"zd","Zang":"zf","Zao":"zs","Ze":"ze","Zei":"zw","Zen":"zk","Zeng":"zj","Zha":"aa","Zhai":"ah","Zhan":"ad","Zhang":"af","Zhao":"as","Zhe":"ae","Zhen":"ak","Zheng":"aj","Zhi":"ai","Zhong":"al","Zhou":"ar","Zhu":"au","Zhua":"aq","Zhuai":"ag","Zhuan":"az","Zhuang":"ax","Zhui":"an","Zhun":"ay","Zhuo":"ao","Zi":"zi","Zong":"zl","Zou":"zr","Zu":"zu","Zuan":"zz","Zui":"zn","Zun":"zy","Zuo":"zo"},"XiaoLang":{"Lv":"lx","Lve":"lb","Lue":"lb","Nv":"nx","Nve":"nb","Nue":"nb","A":"aa","O":"oo","E":"uu","Ai":"ai","Ei":"ui","Ao":"ao","Ou":"ou","An":"an","En":"un","Ang":"ah","Eng":"un","Er":"ur","Yi":"yi","Ya":"ya","Yo":"yo","Ye":"ye","Yao":"ys","You":"yr","Yan":"yj","Yin":"yd","Yang":"yh","Ying":"yv","Wu":"wu","Wa":"wa","Wo":"wo","Wai":"wk","Wei":"ww","Wan":"wj","Wen":"wm","Wang":"wh","Weng":"wn","Yu":"yu","Yue":"yb","Yuan":"yg","Yun":"yy","Yong":"yl","Ba":"ba","Bai":"bk","Ban":"bj","Bang":"bh","Bao":"bs","Bei":"bw","Ben":"bm","Beng":"bn","Bi":"bi","Bian":"bf","Biang":"bm","Biao":"bc","Bie":"bp","Bin":"bd","Bing":"bv","Bo":"bo","Bu":"bu","Ca":"ca","Cai":"ck","Can":"cj","Cang":"ch","Cao":"cs","Ce":"ce","Cen":"cm","Ceng":"cn","Cha":"ia","Chai":"ik","Chan":"ij","Chang":"ih","Chao":"is","Che":"ie","Chen":"im","Cheng":"in","Chi":"ii","Chong":"il","Chou":"ir","Chu":"iu","Chua":"if","Chuai":"iv","Chuan":"ig","Chuang":"iz","Chui":"id","Chun":"iy","Chuo":"io","Ci":"ci","Cong":"cl","Cou":"cr","Cu":"cu","Cuan":"cg","Cui":"cd","Cun":"cy","Cuo":"co","Da":"da","Dai":"dk","Dan":"dj","Dang":"dh","Dao":"ds","De":"de","Dei":"dw","Den":"dm","Deng":"dn","Di":"di","Dia":"dk","Dian":"df","Diao":"dc","Die":"dp","Ding":"dv","Diu":"dt","Dong":"dl","Dou":"dr","Du":"du","Duan":"dg","Dui":"dd","Dun":"dy","Duo":"do","Fa":"fa","Fan":"fj","Fang":"fh","Fei":"fw","Fen":"fm","Feng":"fn","Fiao":"fc","Fo":"fo","Fou":"fr","Fu":"fu","Ga":"ga","Gai":"gk","Gan":"gj","Gang":"gh","Gao":"gs","Ge":"ge","Gei":"gw","Gen":"gm","Geng":"gn","Gong":"gl","Gou":"gr","Gu":"gu","Gua":"gf","Guai":"gv","Guan":"gg","Guang":"gz","Gui":"gd","Gun":"gy","Guo":"go","Ha":"ha","Hai":"hk","Han":"hj","Hang":"hh","Hao":"hs","He":"he","Hei":"hw","Hen":"hm","Heng":"hn","Hong":"hl","Hou":"hr","Hu":"hu","Hua":"hf","Huai":"hv","Huan":"hg","Huang":"hz","Hui":"hd","Hun":"hy","Huo":"ho","Ji":"ji","Jia":"jk","Jian":"jf","Jiang":"jm","Jiao":"jc","Jie":"jp","Jin":"jd","Jing":"jv","Jiong":"jj","Jiu":"jt","Ju":"ju","Juan":"jg","Jue":"jb","Jun":"jy","Ka":"ka","Kai":"kk","Kan":"kj","Kang":"kh","Kao":"ks","Ke":"ke","Ken":"km","Keng":"kn","Kong":"kl","Kou":"kr","Ku":"ku","Kua":"kf","Kuai":"kv","Kuan":"kg","Kuang":"kz","Kui":"kd","Kun":"ky","Kuo":"ko","La":"la","Lai":"lk","Lan":"lj","Lang":"lh","Lao":"ls","Le":"le","Lei":"lw","Leng":"ln","Li":"li","Lia":"lk","Lian":"lf","Liang":"lm","Liao":"lc","Lie":"lp","Lin":"ld","Ling":"lv","Liu":"lt","Lo":"lo","Long":"ll","Lou":"lr","Lu":"lu","Luan":"lg","Lun":"ly","Luo":"lo","Ma":"ma","Mai":"mk","Man":"mj","Mang":"mh","Mao":"ms","Me":"me","Mei":"mw","Men":"mm","Meng":"mn","Mi":"mi","Mian":"mf","Miao":"mc","Mie":"mp","Min":"md","Ming":"mv","Miu":"mt","Mo":"mo","Mou":"mr","Mu":"mu","Na":"na","Nai":"nk","Nan":"nj","Nang":"nh","Nao":"ns","Ne":"ne","Nei":"nw","Nen":"nm","Neng":"nn","Ni":"ni","Nian":"nf","Niang":"nm","Niao":"nc","Nie":"np","Nin":"nd","Ning":"nv","Niu":"nt","Nong":"nl","Nou":"nr","Nu":"nu","Nuan":"ng","Nun":"ny","Nuo":"no","Pa":"pa","Pai":"pk","Pan":"pj","Pang":"ph","Pao":"ps","Pei":"pw","Pen":"pm","Peng":"pn","Pi":"pi","Pian":"pf","Piao":"pc","Pie":"pp","Pin":"pd","Ping":"pv","Po":"po","Pou":"pr","Pu":"pu","Qi":"qi","Qia":"qk","Qian":"qf","Qiang":"qm","Qiao":"qc","Qie":"qp","Qin":"qd","Qing":"qv","Qiong":"qj","Qiu":"qt","Qu":"qu","Quan":"qg","Que":"qb","Qun":"qy","Ran":"rj","Rang":"rh","Rao":"rs","Re":"re","Ren":"rm","Reng":"rn","Ri":"ri","Rong":"rl","Rou":"rr","Ru":"ru","Rua":"rf","Ruan":"rg","Rui":"rd","Run":"ry","Ruo":"ro","Sa":"sa","Sai":"sk","San":"sj","Sang":"sh","Sao":"ss","Se":"se","Sen":"sm","Seng":"sn","Sha":"va","Shai":"vk","Shan":"vj","Shang":"vh","Shao":"vs","She":"ve","Shei":"vw","Shen":"vm","Sheng":"vn","Shi":"vi","Shou":"vr","Shu":"vu","Shua":"vf","Shuai":"vv","Shuan":"vg","Shuang":"vz","Shui":"vd","Shun":"vy","Shuo":"vo","Si":"si","Song":"sl","Sou":"sr","Su":"su","Suan":"sg","Sui":"sd","Sun":"sy","Suo":"so","Ta":"ta","Tai":"tk","Tan":"tj","Tang":"th","Tao":"ts","Te":"te","Tei":"tw","Teng":"tn","Ti":"ti","Tian":"tf","Tiao":"tc","Tie":"tp","Ting":"tv","Tong":"tl","Tou":"tr","Tu":"tu","Tuan":"tg","Tui":"td","Tun":"ty","Tuo":"to","Xi":"xi","Xia":"xk","Xian":"xf","Xiang":"xm","Xiao":"xc","Xie":"xp","Xin":"xd","Xing":"xv","Xiong":"xj","Xiu":"xt","Xu":"xu","Xuan":"xg","Xue":"xb","Xun":"xy","Za":"za","Zai":"zk","Zan":"zj","Zang":"zh","Zao":"zs","Ze":"ze","Zei":"zw","Zen":"zm","Zeng":"zn","Zha":"ea","Zhai":"ek","Zhan":"ej","Zhang":"eh","Zhao":"es","Zhe":"ee","Zhen":"em","Zheng":"en","Zhi":"ei","Zhong":"el","Zhou":"er","Zhu":"eu","Zhua":"ef","Zhuai":"ev","Zhuan":"eg","Zhuang":"ez","Zhui":"ed","Zhun":"ey","Zhuo":"eo","Zi":"zi","Zong":"zl","Zou":"zr","Zu":"zu","Zuan":"zg","Zui":"zd","Zun":"zy","Zuo":"zo"}} \ No newline at end of file From 4fb2e3d14e856cb6917204ce824d89b3cdf8de9c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:33:48 +0800 Subject: [PATCH 084/545] Fix translation mapping logic --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 6a2cd1e66..36f007f39 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -99,13 +99,19 @@ namespace Flow.Launcher.Infrastructure { if (content[i] >= 0x3400 && content[i] <= 0x9FD5) { - string dp = _settings.UseDoublePinyin ? ToDoublePin(resultList[i]) : resultList[i]; - map.AddNewIndex(i, resultBuilder.Length, dp.Length + 1); + string translated = _settings.UseDoublePinyin ? ToDoublePin(resultList[i]) : resultList[i]; if (previousIsChinese) { + map.AddNewIndex(i, resultBuilder.Length, translated.Length + 1); resultBuilder.Append(' '); + resultBuilder.Append(translated); + } + else + { + map.AddNewIndex(i, resultBuilder.Length, translated.Length); + resultBuilder.Append(translated); + previousIsChinese = true; } - resultBuilder.Append(dp); } else { From 7ae91b1af326126c88f22cc60d63f85b8b5263e8 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 14 Jun 2025 20:45:30 +1000 Subject: [PATCH 085/545] Release 1.20.1 | Plugin 4.6.0 (#3706) --- .github/ISSUE_TEMPLATE/bug-report.yaml | 2 + .github/update_release_pr.py | 35 +- .github/workflows/default_plugins.yml | 85 +- .../Plugin/JsonRPCPluginSettings.cs | 2 +- Flow.Launcher.Core/Resource/Theme.cs | 10 +- .../Resource/TranslationConverter.cs | 25 - .../NativeMethods.txt | 5 + .../Storage/FlowLauncherJsonStorage.cs | 4 +- .../Storage/PluginBinaryStorage.cs | 4 +- .../Storage/PluginJsonStorage.cs | 4 +- .../UserSettings/CustomShortcutModel.cs | 8 + Flow.Launcher.Infrastructure/Win32Helper.cs | 5 + .../Flow.Launcher.Plugin.csproj | 8 +- Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs | 19 +- .../SharedCommands/SearchWeb.cs | 43 +- Flow.Launcher/Helper/ErrorReporting.cs | 10 +- Flow.Launcher/HotkeyControlDialog.xaml | 12 +- Flow.Launcher/Languages/ar.xaml | 10 + Flow.Launcher/Languages/cs.xaml | 10 + Flow.Launcher/Languages/da.xaml | 12 +- Flow.Launcher/Languages/de.xaml | 10 + Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/Languages/es-419.xaml | 10 + Flow.Launcher/Languages/es.xaml | 12 +- Flow.Launcher/Languages/fr.xaml | 12 +- Flow.Launcher/Languages/he.xaml | 10 + Flow.Launcher/Languages/it.xaml | 10 + Flow.Launcher/Languages/ja.xaml | 10 + Flow.Launcher/Languages/ko.xaml | 10 + Flow.Launcher/Languages/nb.xaml | 10 + Flow.Launcher/Languages/nl.xaml | 10 + Flow.Launcher/Languages/pl.xaml | 10 + Flow.Launcher/Languages/pt-br.xaml | 10 + Flow.Launcher/Languages/pt-pt.xaml | 14 +- Flow.Launcher/Languages/ru.xaml | 10 + Flow.Launcher/Languages/sk.xaml | 14 +- Flow.Launcher/Languages/sr.xaml | 10 + Flow.Launcher/Languages/tr.xaml | 60 +- Flow.Launcher/Languages/uk-UA.xaml | 10 + Flow.Launcher/Languages/vi.xaml | 10 + Flow.Launcher/Languages/zh-cn.xaml | 12 +- Flow.Launcher/Languages/zh-tw.xaml | 10 + Flow.Launcher/MainWindow.xaml.cs | 146 +- Flow.Launcher/Properties/Resources.fr-FR.resx | 130 -- Flow.Launcher/Properties/Resources.he-IL.resx | 130 -- Flow.Launcher/PublicAPIInstance.cs | 53 +- .../InstalledPluginDisplayKeyword.xaml | 3 +- .../Resources/CustomControlTemplate.xaml | 73 + .../Resources/Pages/WelcomePage1.xaml | 6 +- .../Resources/Pages/WelcomePage2.xaml | 10 +- .../Resources/Pages/WelcomePage4.xaml | 2 +- .../Resources/Pages/WelcomePage5.xaml | 10 +- .../Resources/SettingWindowStyle.xaml | 1 - .../SettingsPaneGeneralViewModel.cs | 2 + .../Views/SettingsPaneGeneral.xaml | 3 +- .../Views/SettingsPaneHotkey.xaml | 2 +- Flow.Launcher/Themes/Base.xaml | 4 + Flow.Launcher/WelcomeWindow.xaml | 6 +- .../ChromiumBookmarkLoader.cs | 128 +- .../FirefoxBookmarkLoader.cs | 284 ++-- .../Helper/FaviconHelper.cs | 76 + .../Languages/ar.xaml | 2 + .../Languages/cs.xaml | 2 + .../Languages/da.xaml | 2 + .../Languages/de.xaml | 2 + .../Languages/en.xaml | 2 + .../Languages/es-419.xaml | 2 + .../Languages/es.xaml | 2 + .../Languages/fr.xaml | 2 + .../Languages/he.xaml | 2 + .../Languages/it.xaml | 2 + .../Languages/ja.xaml | 2 + .../Languages/ko.xaml | 2 + .../Languages/nb.xaml | 2 + .../Languages/nl.xaml | 2 + .../Languages/pl.xaml | 2 + .../Languages/pt-br.xaml | 2 + .../Languages/pt-pt.xaml | 2 + .../Languages/ru.xaml | 2 + .../Languages/sk.xaml | 2 + .../Languages/sr.xaml | 2 + .../Languages/tr.xaml | 2 + .../Languages/uk-UA.xaml | 2 + .../Languages/vi.xaml | 2 + .../Languages/zh-cn.xaml | 2 + .../Languages/zh-tw.xaml | 2 + .../Main.cs | 12 +- .../Models/Settings.cs | 2 + .../Views/SettingsControl.xaml | 8 + .../Flow.Launcher.Plugin.Explorer.csproj | 3 +- .../Languages/ar.xaml | 11 + .../Languages/cs.xaml | 11 + .../Languages/da.xaml | 11 + .../Languages/de.xaml | 11 + .../Languages/en.xaml | 3 + .../Languages/es-419.xaml | 11 + .../Languages/es.xaml | 11 + .../Languages/fr.xaml | 11 + .../Languages/he.xaml | 11 + .../Languages/it.xaml | 11 + .../Languages/ja.xaml | 11 + .../Languages/ko.xaml | 11 + .../Languages/nb.xaml | 11 + .../Languages/nl.xaml | 11 + .../Languages/pl.xaml | 11 + .../Languages/pt-br.xaml | 11 + .../Languages/pt-pt.xaml | 13 +- .../Languages/ru.xaml | 11 + .../Languages/sk.xaml | 11 + .../Languages/sr.xaml | 11 + .../Languages/tr.xaml | 23 +- .../Languages/uk-UA.xaml | 11 + .../Languages/vi.xaml | 11 + .../Languages/zh-cn.xaml | 11 + .../Languages/zh-tw.xaml | 11 + .../Everything/EverythingSearchManager.cs | 33 +- .../Search/ResultManager.cs | 8 +- .../ViewModels/ActionKeywordModel.cs | 2 + .../Views/ExplorerSettings.xaml | 1461 +++++++++-------- .../Views/ExplorerSettings.xaml.cs | 58 +- .../Languages/tr.xaml | 10 +- .../PluginsManager.cs | 110 +- .../Languages/tr.xaml | 24 +- .../Programs/ShellLinkHelper.cs | 9 +- Plugins/Flow.Launcher.Plugin.Shell/Main.cs | 141 +- .../Languages/tr.xaml | 8 +- .../Flow.Launcher.Plugin.WebSearch/Main.cs | 4 +- .../Properties/Resources.pt-PT.resx | 6 +- README.md | 4 + appveyor.yml | 15 +- 130 files changed, 2300 insertions(+), 1606 deletions(-) delete mode 100644 Flow.Launcher.Core/Resource/TranslationConverter.cs delete mode 100644 Flow.Launcher/Properties/Resources.fr-FR.resx delete mode 100644 Flow.Launcher/Properties/Resources.he-IL.resx create mode 100644 Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs diff --git a/.github/ISSUE_TEMPLATE/bug-report.yaml b/.github/ISSUE_TEMPLATE/bug-report.yaml index 294c06fc1..11a921955 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yaml +++ b/.github/ISSUE_TEMPLATE/bug-report.yaml @@ -16,6 +16,8 @@ body: I have checked that this issue has not already been reported. - label: > I am using the latest version of Flow Launcher. + - label: > + I am using the prerelease version of Flow Launcher. - type: textarea attributes: diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index f90f6181d..ccea511b3 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -11,7 +11,7 @@ def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: st token (str): GitHub token. owner (str): The owner of the repository. repo (str): The name of the repository. - label (str): The label name. + label (str): The label name. Filter is not applied when empty string. state (str): State of PR, e.g. open, closed, all Returns: @@ -89,7 +89,7 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all") Args: pull_request_items (list[dict]): List of PR items. - label (str): The label name. + label (str): The label name. Filter is not applied when empty string. state (str): State of PR, e.g. open, closed, all Returns: @@ -99,14 +99,36 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all") pr_list = [] count = 0 for pr in pull_request_items: - if pr["state"] == state and [item for item in pr["labels"] if item["name"] == label]: + if state in [pr["state"], "all"] and (not label or [item for item in pr["labels"] if item["name"] == label]): pr_list.append(pr) count += 1 - print(f"Found {count} PRs with {label if label else 'no'} label and state as {state}") + print(f"Found {count} PRs with {label if label else 'no filter on'} label and state as {state}") return pr_list +def get_prs_assignees(pull_request_items: list[dict], label: str = "", state: str = "all") -> list[str]: + """ + Returns a list of pull request assignees after applying the label and state filters, excludes jjw24. + + Args: + pull_request_items (list[dict]): List of PR items. + label (str): The label name. Filter is not applied when empty string. + state (str): State of PR, e.g. open, closed, all + + Returns: + list: A list of strs, where each string is an assignee name. List is not distinct, so can contain + duplicate names. + Returns an empty list if none are found. + """ + assignee_list = [] + for pr in pull_request_items: + if state in [pr["state"], "all"] and (not label or [item for item in pr["labels"] if item["name"] == label]): + [assignee_list.append(assignee["login"]) for assignee in pr["assignees"] if assignee["login"] != "jjw24" ] + + print(f"Found {len(assignee_list)} assignees with {label if label else 'no filter on'} label and state as {state}") + + return assignee_list def get_pr_descriptions(pull_request_items: list[dict]) -> str: """ @@ -208,6 +230,11 @@ if __name__ == "__main__": description_content += f"## Features\n{get_pr_descriptions(enhancement_prs)}" if enhancement_prs else "" description_content += f"## Bug fixes\n{get_pr_descriptions(bug_fix_prs)}" if bug_fix_prs else "" + assignees = list(set(get_prs_assignees(pull_requests, "enhancement", "closed") + get_prs_assignees(pull_requests, "bug", "closed"))) + assignees.sort(key=str.lower) + + description_content += f"### Authors:\n{', '.join(assignees)}" + update_pull_request_description( github_token, repository_owner, repository_name, release_pr[0]["number"], description_content ) diff --git a/.github/workflows/default_plugins.yml b/.github/workflows/default_plugins.yml index 85acafae1..ec8dfcd4e 100644 --- a/.github/workflows/default_plugins.yml +++ b/.github/workflows/default_plugins.yml @@ -3,11 +3,10 @@ name: Publish Default Plugins on: push: branches: ['master'] - paths: ['Plugins/**'] workflow_dispatch: jobs: - build: + publish: runs-on: windows-latest steps: @@ -17,39 +16,24 @@ jobs: with: dotnet-version: 7.0.x - - name: Determine New Plugin Updates - uses: dorny/paths-filter@v3 - id: changes - with: - filters: | - browserbookmark: - - 'Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json' - calculator: - - 'Plugins/Flow.Launcher.Plugin.Calculator/plugin.json' - explorer: - - 'Plugins/Flow.Launcher.Plugin.Explorer/plugin.json' - pluginindicator: - - 'Plugins/Flow.Launcher.Plugin.PluginIndicator/plugin.json' - pluginsmanager: - - 'Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json' - processkiller: - - 'Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json' - program: - - 'Plugins/Flow.Launcher.Plugin.Program/plugin.json' - shell: - - 'Plugins/Flow.Launcher.Plugin.Shell/plugin.json' - sys: - - 'Plugins/Flow.Launcher.Plugin.Sys/plugin.json' - url: - - 'Plugins/Flow.Launcher.Plugin.Url/plugin.json' - websearch: - - 'Plugins/Flow.Launcher.Plugin.WebSearch/plugin.json' - windowssettings: - - 'Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json' - base: 'master' + - name: Update Plugins To Production Version + run: | + $version = "1.0.0" + Get-Content appveyor.yml | ForEach-Object { + if ($_ -match "version:\s*'(\d+\.\d+\.\d+)\.") { + $version = $matches[1] + } + } + + $jsonFiles = Get-ChildItem -Path ".\Plugins\*\plugin.json" + foreach ($file in $jsonFiles) { + $plugin_old_ver = Get-Content $file.FullName -Raw | ConvertFrom-Json + (Get-Content $file) -replace '"Version"\s*:\s*".*?"', "`"Version`": `"$version`"" | Set-Content $file + $plugin_new_ver = Get-Content $file.FullName -Raw | ConvertFrom-Json + Write-Host "Updated" $plugin_old_ver.Name "version from" $plugin_old_ver.Version "to" $plugin_new_ver.Version + } - name: Get BrowserBookmark Version - if: steps.changes.outputs.browserbookmark == 'true' id: updated-version-browserbookmark uses: notiz-dev/github-action-json-property@release with: @@ -57,14 +41,12 @@ jobs: prop_path: 'Version' - name: Build BrowserBookmark - if: steps.changes.outputs.browserbookmark == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.BrowserBookmark" 7z a -tzip "Flow.Launcher.Plugin.BrowserBookmark.zip" "./Flow.Launcher.Plugin.BrowserBookmark/*" rm -r "Flow.Launcher.Plugin.BrowserBookmark" - name: Publish BrowserBookmark - if: steps.changes.outputs.browserbookmark == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.BrowserBookmark" @@ -76,7 +58,6 @@ jobs: - name: Get Calculator Version - if: steps.changes.outputs.calculator == 'true' id: updated-version-calculator uses: notiz-dev/github-action-json-property@release with: @@ -84,14 +65,12 @@ jobs: prop_path: 'Version' - name: Build Calculator - if: steps.changes.outputs.calculator == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.Calculator" 7z a -tzip "Flow.Launcher.Plugin.Calculator.zip" "./Flow.Launcher.Plugin.Calculator/*" rm -r "Flow.Launcher.Plugin.Calculator" - name: Publish Calculator - if: steps.changes.outputs.calculator == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.Calculator" @@ -103,7 +82,6 @@ jobs: - name: Get Explorer Version - if: steps.changes.outputs.explorer == 'true' id: updated-version-explorer uses: notiz-dev/github-action-json-property@release with: @@ -111,14 +89,12 @@ jobs: prop_path: 'Version' - name: Build Explorer - if: steps.changes.outputs.explorer == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.Explorer" 7z a -tzip "Flow.Launcher.Plugin.Explorer.zip" "./Flow.Launcher.Plugin.Explorer/*" rm -r "Flow.Launcher.Plugin.Explorer" - name: Publish Explorer - if: steps.changes.outputs.explorer == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.Explorer" @@ -130,7 +106,6 @@ jobs: - name: Get PluginIndicator Version - if: steps.changes.outputs.pluginindicator == 'true' id: updated-version-pluginindicator uses: notiz-dev/github-action-json-property@release with: @@ -138,14 +113,12 @@ jobs: prop_path: 'Version' - name: Build PluginIndicator - if: steps.changes.outputs.pluginindicator == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.PluginIndicator/Flow.Launcher.Plugin.PluginIndicator.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.PluginIndicator" 7z a -tzip "Flow.Launcher.Plugin.PluginIndicator.zip" "./Flow.Launcher.Plugin.PluginIndicator/*" rm -r "Flow.Launcher.Plugin.PluginIndicator" - name: Publish PluginIndicator - if: steps.changes.outputs.pluginindicator == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginIndicator" @@ -157,7 +130,6 @@ jobs: - name: Get PluginsManager Version - if: steps.changes.outputs.pluginsmanager == 'true' id: updated-version-pluginsmanager uses: notiz-dev/github-action-json-property@release with: @@ -165,14 +137,12 @@ jobs: prop_path: 'Version' - name: Build PluginsManager - if: steps.changes.outputs.pluginsmanager == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.PluginsManager/Flow.Launcher.Plugin.PluginsManager.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.PluginsManager" 7z a -tzip "Flow.Launcher.Plugin.PluginsManager.zip" "./Flow.Launcher.Plugin.PluginsManager/*" rm -r "Flow.Launcher.Plugin.PluginsManager" - name: Publish PluginsManager - if: steps.changes.outputs.pluginsmanager == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.PluginsManager" @@ -184,7 +154,6 @@ jobs: - name: Get ProcessKiller Version - if: steps.changes.outputs.processkiller == 'true' id: updated-version-processkiller uses: notiz-dev/github-action-json-property@release with: @@ -192,14 +161,12 @@ jobs: prop_path: 'Version' - name: Build ProcessKiller - if: steps.changes.outputs.processkiller == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.ProcessKiller" 7z a -tzip "Flow.Launcher.Plugin.ProcessKiller.zip" "./Flow.Launcher.Plugin.ProcessKiller/*" rm -r "Flow.Launcher.Plugin.ProcessKiller" - name: Publish ProcessKiller - if: steps.changes.outputs.processkiller == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller" @@ -211,7 +178,6 @@ jobs: - name: Get Program Version - if: steps.changes.outputs.program == 'true' id: updated-version-program uses: notiz-dev/github-action-json-property@release with: @@ -219,14 +185,12 @@ jobs: prop_path: 'Version' - name: Build Program - if: steps.changes.outputs.program == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj' --framework net7.0-windows10.0.19041.0 -c Release -o "Flow.Launcher.Plugin.Program" 7z a -tzip "Flow.Launcher.Plugin.Program.zip" "./Flow.Launcher.Plugin.Program/*" rm -r "Flow.Launcher.Plugin.Program" - name: Publish Program - if: steps.changes.outputs.program == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.Program" @@ -238,7 +202,6 @@ jobs: - name: Get Shell Version - if: steps.changes.outputs.shell == 'true' id: updated-version-shell uses: notiz-dev/github-action-json-property@release with: @@ -246,14 +209,12 @@ jobs: prop_path: 'Version' - name: Build Shell - if: steps.changes.outputs.shell == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.Shell/Flow.Launcher.Plugin.Shell.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.Shell" 7z a -tzip "Flow.Launcher.Plugin.Shell.zip" "./Flow.Launcher.Plugin.Shell/*" rm -r "Flow.Launcher.Plugin.Shell" - name: Publish Shell - if: steps.changes.outputs.shell == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.Shell" @@ -265,7 +226,6 @@ jobs: - name: Get Sys Version - if: steps.changes.outputs.sys == 'true' id: updated-version-sys uses: notiz-dev/github-action-json-property@release with: @@ -273,14 +233,12 @@ jobs: prop_path: 'Version' - name: Build Sys - if: steps.changes.outputs.sys == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.Sys" 7z a -tzip "Flow.Launcher.Plugin.Sys.zip" "./Flow.Launcher.Plugin.Sys/*" rm -r "Flow.Launcher.Plugin.Sys" - name: Publish Sys - if: steps.changes.outputs.sys == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.Sys" @@ -292,7 +250,6 @@ jobs: - name: Get Url Version - if: steps.changes.outputs.url == 'true' id: updated-version-url uses: notiz-dev/github-action-json-property@release with: @@ -300,14 +257,12 @@ jobs: prop_path: 'Version' - name: Build Url - if: steps.changes.outputs.url == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.Url/Flow.Launcher.Plugin.Url.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.Url" 7z a -tzip "Flow.Launcher.Plugin.Url.zip" "./Flow.Launcher.Plugin.Url/*" rm -r "Flow.Launcher.Plugin.Url" - name: Publish Url - if: steps.changes.outputs.url == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.Url" @@ -319,7 +274,6 @@ jobs: - name: Get WebSearch Version - if: steps.changes.outputs.websearch == 'true' id: updated-version-websearch uses: notiz-dev/github-action-json-property@release with: @@ -327,14 +281,12 @@ jobs: prop_path: 'Version' - name: Build WebSearch - if: steps.changes.outputs.websearch == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.WebSearch" 7z a -tzip "Flow.Launcher.Plugin.WebSearch.zip" "./Flow.Launcher.Plugin.WebSearch/*" rm -r "Flow.Launcher.Plugin.WebSearch" - name: Publish WebSearch - if: steps.changes.outputs.websearch == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.WebSearch" @@ -346,7 +298,6 @@ jobs: - name: Get WindowsSettings Version - if: steps.changes.outputs.windowssettings == 'true' id: updated-version-windowssettings uses: notiz-dev/github-action-json-property@release with: @@ -354,14 +305,12 @@ jobs: prop_path: 'Version' - name: Build WindowsSettings - if: steps.changes.outputs.windowssettings == 'true' run: | dotnet publish 'Plugins/Flow.Launcher.Plugin.WindowsSettings/Flow.Launcher.Plugin.WindowsSettings.csproj' --framework net7.0-windows -c Release -o "Flow.Launcher.Plugin.WindowsSettings" 7z a -tzip "Flow.Launcher.Plugin.WindowsSettings.zip" "./Flow.Launcher.Plugin.WindowsSettings/*" rm -r "Flow.Launcher.Plugin.WindowsSettings" - name: Publish WindowsSettings - if: steps.changes.outputs.windowssettings == 'true' uses: softprops/action-gh-release@v2 with: repository: "Flow-Launcher/Flow.Launcher.Plugin.WindowsSettings" diff --git a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs index 003e72a5d..435d97ab7 100644 --- a/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs +++ b/Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs @@ -12,7 +12,7 @@ using Flow.Launcher.Plugin; namespace Flow.Launcher.Core.Plugin { - public class JsonRPCPluginSettings + public class JsonRPCPluginSettings : ISavable { public required JsonRpcConfigurationModel? Configuration { get; init; } diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index 059359694..a6e8dc6bf 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -671,7 +671,15 @@ namespace Flow.Launcher.Core.Resource windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property.Name == "Background")); windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent))); } - + + // For themes with blur enabled, the window border is rendered by the system, so it's treated as a simple rectangle regardless of thickness. + //(This is to avoid issues when the window is forcibly changed to a rectangular shape during snap scenarios.) + var cornerRadiusSetter = windowBorderStyle.Setters.OfType().FirstOrDefault(x => x.Property == Border.CornerRadiusProperty); + if (cornerRadiusSetter != null) + cornerRadiusSetter.Value = new CornerRadius(0); + else + windowBorderStyle.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(0))); + // Apply the blur effect Win32Helper.DWMSetBackdropForWindow(mainWindow, backdropType); ColorizeWindow(theme, backdropType); diff --git a/Flow.Launcher.Core/Resource/TranslationConverter.cs b/Flow.Launcher.Core/Resource/TranslationConverter.cs deleted file mode 100644 index eb0032758..000000000 --- a/Flow.Launcher.Core/Resource/TranslationConverter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Globalization; -using System.Windows.Data; -using CommunityToolkit.Mvvm.DependencyInjection; -using Flow.Launcher.Plugin; - -namespace Flow.Launcher.Core.Resource -{ - public class TranslationConverter : IValueConverter - { - // We should not initialize API in static constructor because it will create another API instance - private static IPublicAPI api = null; - private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - var key = value.ToString(); - if (string.IsNullOrEmpty(key)) return key; - return API.GetTranslation(key); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => - throw new InvalidOperationException(); - } -} diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index 53c877c4f..edc71feef 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -42,6 +42,11 @@ MONITORINFOEXW WM_ENTERSIZEMOVE WM_EXITSIZEMOVE +WM_NCLBUTTONDBLCLK +WM_SYSCOMMAND + +SC_MAXIMIZE +SC_MINIMIZE OleInitialize OleUninitialize diff --git a/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs index 158e0cdf5..857490bad 100644 --- a/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/FlowLauncherJsonStorage.cs @@ -2,11 +2,13 @@ using System.Threading.Tasks; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Infrastructure.Storage { - public class FlowLauncherJsonStorage : JsonStorage where T : new() + // Expose ISaveable interface in derived class to make sure we are calling the new version of Save method + public class FlowLauncherJsonStorage : JsonStorage, ISavable where T : new() { private static readonly string ClassName = "FlowLauncherJsonStorage"; diff --git a/Flow.Launcher.Infrastructure/Storage/PluginBinaryStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginBinaryStorage.cs index 01da96d62..0e0906e73 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginBinaryStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginBinaryStorage.cs @@ -1,11 +1,13 @@ using System.IO; using System.Threading.Tasks; using Flow.Launcher.Infrastructure.Logger; +using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Infrastructure.Storage { - public class PluginBinaryStorage : BinaryStorage where T : new() + // Expose ISaveable interface in derived class to make sure we are calling the new version of Save method + public class PluginBinaryStorage : BinaryStorage, ISavable where T : new() { private static readonly string ClassName = "PluginBinaryStorage"; diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index 147152949..d59083071 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -2,11 +2,13 @@ using System.Threading.Tasks; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; namespace Flow.Launcher.Infrastructure.Storage { - public class PluginJsonStorage : JsonStorage where T : new() + // Expose ISaveable interface in derived class to make sure we are calling the new version of Save method + public class PluginJsonStorage : JsonStorage, ISavable where T : new() { // Use assembly name to check which plugin is using this storage public readonly string AssemblyName; diff --git a/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs b/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs index 2d15b54c5..2603d4675 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/CustomShortcutModel.cs @@ -1,6 +1,8 @@ using System; using System.Text.Json.Serialization; using System.Threading.Tasks; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Plugin; namespace Flow.Launcher.Infrastructure.UserSettings { @@ -53,6 +55,12 @@ namespace Flow.Launcher.Infrastructure.UserSettings { public string Description { get; set; } + public string LocalizedDescription => API.GetTranslation(Description); + + // We should not initialize API in static constructor because it will create another API instance + private static IPublicAPI api = null; + private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService(); + public BaseBuiltinShortcutModel(string key, string description) { Key = key; diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 1be803fd4..86e7b7c97 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -324,6 +324,11 @@ namespace Flow.Launcher.Infrastructure public const int WM_ENTERSIZEMOVE = (int)PInvoke.WM_ENTERSIZEMOVE; public const int WM_EXITSIZEMOVE = (int)PInvoke.WM_EXITSIZEMOVE; + public const int WM_NCLBUTTONDBLCLK = (int)PInvoke.WM_NCLBUTTONDBLCLK; + public const int WM_SYSCOMMAND = (int)PInvoke.WM_SYSCOMMAND; + + public const int SC_MAXIMIZE = (int)PInvoke.SC_MAXIMIZE; + public const int SC_MINIMIZE = (int)PInvoke.SC_MINIMIZE; #endregion diff --git a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj index 4a26cec95..4a49e9589 100644 --- a/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj +++ b/Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj @@ -14,10 +14,10 @@ - 4.5.0 - 4.5.0 - 4.5.0 - 4.5.0 + 4.6.0 + 4.6.0 + 4.6.0 + 4.6.0 Flow.Launcher.Plugin Flow-Launcher MIT diff --git a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs index cb60251ed..09c402bcf 100644 --- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs +++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs @@ -306,13 +306,28 @@ namespace Flow.Launcher.Plugin public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null); /// - /// Opens the URL with the given Uri object. + /// Opens the URL using the browser with the given Uri object, even if the URL is a local file. + /// The browser and mode used is based on what's configured in Flow's default browser settings. + /// + public void OpenWebUrl(Uri url, bool? inPrivate = null); + + /// + /// Opens the URL using the browser with the given string, even if the URL is a local file. + /// The browser and mode used is based on what's configured in Flow's default browser settings. + /// Non-C# plugins should use this method. + /// + public void OpenWebUrl(string url, bool? inPrivate = null); + + /// + /// Opens the URL with the given Uri object in browser if scheme is Http or Https. + /// If the URL is a local file, it will instead be opened with the default application for that file type. /// The browser and mode used is based on what's configured in Flow's default browser settings. /// public void OpenUrl(Uri url, bool? inPrivate = null); /// - /// Opens the URL with the given string. + /// Opens the URL with the given string in browser if scheme is Http or Https. + /// If the URL is a local file, it will instead be opened with the default application for that file type. /// The browser and mode used is based on what's configured in Flow's default browser settings. /// Non-C# plugins should use this method. /// diff --git a/Flow.Launcher.Plugin/SharedCommands/SearchWeb.cs b/Flow.Launcher.Plugin/SharedCommands/SearchWeb.cs index 752c85933..ed3e91daf 100644 --- a/Flow.Launcher.Plugin/SharedCommands/SearchWeb.cs +++ b/Flow.Launcher.Plugin/SharedCommands/SearchWeb.cs @@ -1,8 +1,9 @@ -using Microsoft.Win32; -using System; +using System; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; +using Microsoft.Win32; namespace Flow.Launcher.Plugin.SharedCommands { @@ -13,7 +14,7 @@ namespace Flow.Launcher.Plugin.SharedCommands { private static string GetDefaultBrowserPath() { - string name = string.Empty; + var name = string.Empty; try { using var regDefault = Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice", false); @@ -23,8 +24,7 @@ namespace Flow.Launcher.Plugin.SharedCommands name = regKey.GetValue(null).ToString().ToLower().Replace("\"", ""); if (!name.EndsWith("exe")) - name = name.Substring(0, name.LastIndexOf(".exe") + 4); - + name = name[..(name.LastIndexOf(".exe") + 4)]; } catch { @@ -65,12 +65,21 @@ namespace Flow.Launcher.Plugin.SharedCommands { Process.Start(psi)?.Dispose(); } - catch (System.ComponentModel.Win32Exception) + // This error may be thrown if browser path is incorrect + catch (Win32Exception) { - Process.Start(new ProcessStartInfo + try { - FileName = url, UseShellExecute = true - }); + Process.Start(new ProcessStartInfo + { + FileName = url, + UseShellExecute = true + }); + } + catch + { + throw; // Re-throw the exception if we cannot open the URL in the default browser + } } } @@ -100,12 +109,20 @@ namespace Flow.Launcher.Plugin.SharedCommands Process.Start(psi)?.Dispose(); } // This error may be thrown if browser path is incorrect - catch (System.ComponentModel.Win32Exception) + catch (Win32Exception) { - Process.Start(new ProcessStartInfo + try { - FileName = url, UseShellExecute = true - }); + Process.Start(new ProcessStartInfo + { + FileName = url, + UseShellExecute = true + }); + } + catch + { + throw; // Re-throw the exception if we cannot open the URL in the default browser + } } } } diff --git a/Flow.Launcher/Helper/ErrorReporting.cs b/Flow.Launcher/Helper/ErrorReporting.cs index aa810ba65..e201284cb 100644 --- a/Flow.Launcher/Helper/ErrorReporting.cs +++ b/Flow.Launcher/Helper/ErrorReporting.cs @@ -1,20 +1,21 @@ using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; -using System.Windows; using System.Windows.Threading; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Exception; +using Flow.Launcher.Infrastructure.Logger; using NLog; namespace Flow.Launcher.Helper; public static class ErrorReporting { - private static void Report(Exception e, [CallerMemberName] string methodName = "UnHandledException") + private static void Report(Exception e, bool silent = false, [CallerMemberName] string methodName = "UnHandledException") { var logger = LogManager.GetLogger(methodName); logger.Fatal(ExceptionFormatter.FormatExcpetion(e)); + if (silent) return; var reportWindow = new ReportWindow(e); reportWindow.Show(); } @@ -35,8 +36,9 @@ public static class ErrorReporting public static void TaskSchedulerUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) { - // handle unobserved task exceptions on UI thread - Application.Current.Dispatcher.Invoke(() => Report(e.Exception)); + // log exception but do not handle unobserved task exceptions on UI thread + //Application.Current.Dispatcher.Invoke(() => Report(e.Exception, true)); + Log.Exception(nameof(ErrorReporting), "Unobserved task exception occurred.", e.Exception); // prevent application exit, so the user can copy the prompted error info e.SetObserved(); } diff --git a/Flow.Launcher/HotkeyControlDialog.xaml b/Flow.Launcher/HotkeyControlDialog.xaml index 1edce6d06..d416f1bdc 100644 --- a/Flow.Launcher/HotkeyControlDialog.xaml +++ b/Flow.Launcher/HotkeyControlDialog.xaml @@ -125,12 +125,12 @@ BorderThickness="0 1 0 0" CornerRadius="0 0 8 8"> public bool ShouldUsePinyin { get; set; } = false; - public bool UseDoublePinyin { get; set; } = true; //For developing + private bool _useDoublePinyin = true; // TODO: change default to false BEFORE RELEASE + public bool UseDoublePinyin + { + get => _useDoublePinyin; + set + { + if (_useDoublePinyin != value) + { + _useDoublePinyin = value; + OnPropertyChanged(); + } + } + } - public string DoublePinyinSchema { get; set; } = "XiaoHe"; //For developing + private string _doublePinyinSchema = "XiaoHe"; + public string DoublePinyinSchema + { + get => _doublePinyinSchema; + set + { + if (_doublePinyinSchema != value) + { + _doublePinyinSchema = value; + OnPropertyChanged(); + } + } + } public bool AlwaysPreview { get; set; } = false; From d2dc307bc020ebd8205ce01ee8ae5e262703a943 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jun 2025 20:06:01 +0800 Subject: [PATCH 116/545] Fix logic of ShouldTranslate() --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index ffb92a9bf..91c13ffad 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -76,9 +76,7 @@ namespace Flow.Launcher.Infrastructure public bool ShouldTranslate(string stringToTranslate) { - return _settings.UseDoublePinyin ? - (!WordsHelper.HasChinese(stringToTranslate) && stringToTranslate.Length % 2 == 0) : - !WordsHelper.HasChinese(stringToTranslate); + return WordsHelper.HasChinese(stringToTranslate); } public (string translation, TranslationMapping map) Translate(string content) From 1bc80d5dd99cdc2fdf6ee900c1c5c4d351a0a1eb Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Thu, 19 Jun 2025 21:52:15 +0800 Subject: [PATCH 117/545] Fix translated length --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 91c13ffad..f11a49613 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -106,7 +106,7 @@ namespace Flow.Launcher.Infrastructure if (previousIsChinese) { resultBuilder.Append(' '); - map.AddNewIndex(i, resultBuilder.Length, translated.Length + 1); + map.AddNewIndex(i, resultBuilder.Length, translated.Length); resultBuilder.Append(translated); } else From 247355e1427af61d73f39fafedd66b2f0d2f6909 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sat, 21 Jun 2025 21:34:49 +1000 Subject: [PATCH 118/545] simplify assignee by using filtered PR list --- .github/update_release_pr.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index ccea511b3..bf5f9a15e 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -107,14 +107,12 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all") return pr_list -def get_prs_assignees(pull_request_items: list[dict], label: str = "", state: str = "all") -> list[str]: +def get_prs_assignees(pull_request_items: list[dict]) -> list[str]: """ - Returns a list of pull request assignees after applying the label and state filters, excludes jjw24. + Returns a list of pull request assignees, excludes jjw24. Args: - pull_request_items (list[dict]): List of PR items. - label (str): The label name. Filter is not applied when empty string. - state (str): State of PR, e.g. open, closed, all + pull_request_items (list[dict]): List of PR items to get the assignees from. Returns: list: A list of strs, where each string is an assignee name. List is not distinct, so can contain @@ -123,10 +121,9 @@ def get_prs_assignees(pull_request_items: list[dict], label: str = "", state: st """ assignee_list = [] for pr in pull_request_items: - if state in [pr["state"], "all"] and (not label or [item for item in pr["labels"] if item["name"] == label]): - [assignee_list.append(assignee["login"]) for assignee in pr["assignees"] if assignee["login"] != "jjw24" ] + [assignee_list.append(assignee["login"]) for assignee in pr["assignees"] if assignee["login"] != "jjw24" ] - print(f"Found {len(assignee_list)} assignees with {label if label else 'no filter on'} label and state as {state}") + print(f"Found {len(assignee_list)} assignees") return assignee_list @@ -230,7 +227,7 @@ if __name__ == "__main__": description_content += f"## Features\n{get_pr_descriptions(enhancement_prs)}" if enhancement_prs else "" description_content += f"## Bug fixes\n{get_pr_descriptions(bug_fix_prs)}" if bug_fix_prs else "" - assignees = list(set(get_prs_assignees(pull_requests, "enhancement", "closed") + get_prs_assignees(pull_requests, "bug", "closed"))) + assignees = list(set(get_prs_assignees(enhancement_prs) + get_prs_assignees(bug_fix_prs))) assignees.sort(key=str.lower) description_content += f"### Authors:\n{', '.join(assignees)}" From 4e57e3a66cebec0af365c2bc6b7e462644d5c92d Mon Sep 17 00:00:00 2001 From: Jeremy Date: Sat, 21 Jun 2025 21:37:12 +1000 Subject: [PATCH 119/545] determine milestone from release PR instead of querying milestones --- .github/update_release_pr.py | 77 ++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 43 deletions(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index bf5f9a15e..0ae83151d 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -1,11 +1,12 @@ from os import getenv +from typing import Optional import requests def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: str = "all") -> list[dict]: """ - Fetches pull requests from a GitHub repository that match a given milestone and label. + Fetches pull requests from a GitHub repository that match a given label and state. Args: token (str): GitHub token. @@ -23,39 +24,10 @@ def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: st "Accept": "application/vnd.github.v3+json", } - milestone_id = None - milestone_url = f"https://api.github.com/repos/{owner}/{repo}/milestones" - params = {"state": "open"} - - try: - response = requests.get(milestone_url, headers=headers, params=params) - response.raise_for_status() - milestones = response.json() - - if len(milestones) > 2: - print("More than two milestones found, unable to determine the milestone required.") - exit(1) - - # milestones.pop() - for ms in milestones: - if ms["title"] != "Future": - milestone_id = ms["number"] - print(f"Gathering PRs with milestone {ms['title']}...") - break - - if not milestone_id: - print(f"No suitable milestone found in repository '{owner}/{repo}'.") - exit(1) - - except requests.exceptions.RequestException as e: - print(f"Error fetching milestones: {e}") - exit(1) - - # This endpoint allows filtering by milestone and label. A PR in GH's perspective is a type of issue. + # This endpoint allows filtering by label(and milestone). A PR in GH's perspective is a type of issue. prs_url = f"https://api.github.com/repos/{owner}/{repo}/issues" params = { "state": state, - "milestone": milestone_id, "labels": label, "per_page": 100, } @@ -83,7 +55,7 @@ def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: st return all_prs -def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all") -> list[dict]: +def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all", milestone_number: Optional[int] = None) -> list[dict]: """ Returns a list of pull requests after applying the label and state filters. @@ -91,6 +63,7 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all") pull_request_items (list[dict]): List of PR items. label (str): The label name. Filter is not applied when empty string. state (str): State of PR, e.g. open, closed, all + milestone_number (Optional[int]): The milestone number to filter by. If None, no milestone filtering is applied. Returns: list: A list of dictionaries, where each dictionary represents a pull request. @@ -99,11 +72,20 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all") pr_list = [] count = 0 for pr in pull_request_items: - if state in [pr["state"], "all"] and (not label or [item for item in pr["labels"] if item["name"] == label]): - pr_list.append(pr) - count += 1 + if state not in [pr["state"], "all"]: + continue - print(f"Found {count} PRs with {label if label else 'no filter on'} label and state as {state}") + if label and not [item for item in pr["labels"] if item["name"] == label]: + continue + + if milestone_number: + if not pr.get("milestone") or pr["milestone"]["number"] != milestone_number: + continue + + pr_list.append(pr) + count += 1 + + print(f"Found {count} PRs with {label if label else 'no filter on'} label, state as {state}, and milestone {pr.get("milestone",{}).get("number","None")}") return pr_list @@ -204,15 +186,16 @@ if __name__ == "__main__": print(f"Fetching {state} PRs for {repository_owner}/{repository_name} ...") - pull_requests = get_github_prs(github_token, repository_owner, repository_name) + # First, get all PRs to find the release PR and determine the milestone + all_pull_requests = get_github_prs(github_token, repository_owner, repository_name) - if not pull_requests: - print("No matching pull requests found") + if not all_pull_requests: + print("No pull requests found") exit(1) - print(f"\nFound total of {len(pull_requests)} pull requests") + print(f"\nFound total of {len(all_pull_requests)} pull requests") - release_pr = get_prs(pull_requests, "release", "open") + release_pr = get_prs(all_pull_requests, "release", "open") if len(release_pr) != 1: print(f"Unable to find the exact release PR. Returned result: {release_pr}") @@ -220,8 +203,16 @@ if __name__ == "__main__": print(f"Found release PR: {release_pr[0]['title']}") - enhancement_prs = get_prs(pull_requests, "enhancement", "closed") - bug_fix_prs = get_prs(pull_requests, "bug", "closed") + release_milestone_number = release_pr[0].get("milestone",{}).get("number",None) + + if not release_milestone_number: + print("Release PR does not have a milestone assigned.") + exit(1) + + print(f"Using milestone number: {release_milestone_number}") + + enhancement_prs = get_prs(all_pull_requests, "enhancement", "closed", release_milestone_number) + bug_fix_prs = get_prs(all_pull_requests, "bug", "closed", release_milestone_number) description_content = "# Release notes\n" description_content += f"## Features\n{get_pr_descriptions(enhancement_prs)}" if enhancement_prs else "" From 60d59668636db3bbef2488b0291328a78eacc655 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 21 Jun 2025 11:46:12 +0000 Subject: [PATCH 120/545] formatting --- .github/update_release_pr.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index 0ae83151d..68e4c0659 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -55,7 +55,9 @@ def get_github_prs(token: str, owner: str, repo: str, label: str = "", state: st return all_prs -def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all", milestone_number: Optional[int] = None) -> list[dict]: +def get_prs( + pull_request_items: list[dict], label: str = "", state: str = "all", milestone_number: Optional[int] = None +) -> list[dict]: """ Returns a list of pull requests after applying the label and state filters. @@ -85,10 +87,13 @@ def get_prs(pull_request_items: list[dict], label: str = "", state: str = "all", pr_list.append(pr) count += 1 - print(f"Found {count} PRs with {label if label else 'no filter on'} label, state as {state}, and milestone {pr.get("milestone",{}).get("number","None")}") + print( + f"Found {count} PRs with {label if label else 'no filter on'} label, state as {state}, and milestone {pr.get("milestone",{}).get("number","None")}" + ) return pr_list + def get_prs_assignees(pull_request_items: list[dict]) -> list[str]: """ Returns a list of pull request assignees, excludes jjw24. @@ -103,12 +108,13 @@ def get_prs_assignees(pull_request_items: list[dict]) -> list[str]: """ assignee_list = [] for pr in pull_request_items: - [assignee_list.append(assignee["login"]) for assignee in pr["assignees"] if assignee["login"] != "jjw24" ] + [assignee_list.append(assignee["login"]) for assignee in pr["assignees"] if assignee["login"] != "jjw24"] print(f"Found {len(assignee_list)} assignees") return assignee_list + def get_pr_descriptions(pull_request_items: list[dict]) -> str: """ Returns the concatenated string of pr title and number in the format of @@ -203,7 +209,7 @@ if __name__ == "__main__": print(f"Found release PR: {release_pr[0]['title']}") - release_milestone_number = release_pr[0].get("milestone",{}).get("number",None) + release_milestone_number = release_pr[0].get("milestone", {}).get("number", None) if not release_milestone_number: print("Release PR does not have a milestone assigned.") From 9b02e1f74e180c906a7b0f13cde1cfb3c38904de Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Sat, 21 Jun 2025 21:52:54 +1000 Subject: [PATCH 121/545] fix typo Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/update_release_pr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index 68e4c0659..d637a3275 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -88,7 +88,7 @@ def get_prs( count += 1 print( - f"Found {count} PRs with {label if label else 'no filter on'} label, state as {state}, and milestone {pr.get("milestone",{}).get("number","None")}" + f"Found {count} PRs with {label if label else 'no filter on'} label, state as {state}, and milestone {pr.get('milestone', {}).get('number', 'None')}" ) return pr_list From fe7985d5644a2c3b86ff369736fb461e7fc0fba4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 23 Jun 2025 12:25:16 +0800 Subject: [PATCH 122/545] Use Flow.Launcher.Localization to improve code quality --- .../DecimalSeparator.cs | 11 +++--- .../Flow.Launcher.Plugin.Calculator.csproj | 2 +- .../Flow.Launcher.Plugin.Calculator/Main.cs | 35 +++++++++---------- .../ViewModels/SettingsViewModel.cs | 16 +++++++++ .../Views/CalculatorSettings.xaml | 19 +++------- .../Views/CalculatorSettings.xaml.cs | 12 +++---- 6 files changed, 48 insertions(+), 47 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/DecimalSeparator.cs b/Plugins/Flow.Launcher.Plugin.Calculator/DecimalSeparator.cs index 81a68739b..0ece36d54 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/DecimalSeparator.cs +++ b/Plugins/Flow.Launcher.Plugin.Calculator/DecimalSeparator.cs @@ -1,18 +1,17 @@ -using System.ComponentModel; -using Flow.Launcher.Core.Resource; +using Flow.Launcher.Localization.Attributes; namespace Flow.Launcher.Plugin.Calculator { - [TypeConverter(typeof(LocalizationConverter))] + [EnumLocalize] public enum DecimalSeparator { - [LocalizedDescription("flowlauncher_plugin_calculator_decimal_seperator_use_system_locale")] + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_calculator_decimal_seperator_use_system_locale))] UseSystemLocale, - [LocalizedDescription("flowlauncher_plugin_calculator_decimal_seperator_dot")] + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_calculator_decimal_seperator_dot))] Dot, - [LocalizedDescription("flowlauncher_plugin_calculator_decimal_seperator_comma")] + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_calculator_decimal_seperator_comma))] Comma } } diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj index 9cdef365d..73dacf3d1 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -42,7 +42,6 @@ - @@ -63,6 +62,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs index b1e4cd606..f35e64237 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs @@ -5,7 +5,6 @@ using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Windows.Controls; using Mages.Core; -using Flow.Launcher.Plugin.Calculator.ViewModels; using Flow.Launcher.Plugin.Calculator.Views; namespace Flow.Launcher.Plugin.Calculator @@ -24,19 +23,17 @@ namespace Flow.Launcher.Plugin.Calculator @")+$", RegexOptions.Compiled); private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled); private static Engine MagesEngine; - private const string comma = ","; - private const string dot = "."; + private const string Comma = ","; + private const string Dot = "."; - private PluginInitContext Context { get; set; } + internal static PluginInitContext Context { get; set; } = null!; private static Settings _settings; - private static SettingsViewModel _viewModel; public void Init(PluginInitContext context) { Context = context; _settings = context.API.LoadSettingJsonStorage(); - _viewModel = new SettingsViewModel(_settings); MagesEngine = new Engine(new Configuration { @@ -72,10 +69,10 @@ namespace Flow.Launcher.Plugin.Calculator var result = MagesEngine.Interpret(expression); if (result?.ToString() == "NaN") - result = Context.API.GetTranslation("flowlauncher_plugin_calculator_not_a_number"); + result = Localize.flowlauncher_plugin_calculator_not_a_number(); if (result is Function) - result = Context.API.GetTranslation("flowlauncher_plugin_calculator_expression_not_complete"); + result = Localize.flowlauncher_plugin_calculator_expression_not_complete(); if (!string.IsNullOrEmpty(result?.ToString())) { @@ -89,7 +86,7 @@ namespace Flow.Launcher.Plugin.Calculator Title = newResult, IcoPath = "Images/calculator.png", Score = 300, - SubTitle = Context.API.GetTranslation("flowlauncher_plugin_calculator_copy_number_to_clipboard"), + SubTitle = Localize.flowlauncher_plugin_calculator_copy_number_to_clipboard(), CopyText = newResult, Action = c => { @@ -134,16 +131,16 @@ namespace Flow.Launcher.Plugin.Calculator return false; } - if ((query.Search.Contains(dot) && GetDecimalSeparator() != dot) || - (query.Search.Contains(comma) && GetDecimalSeparator() != comma)) + if ((query.Search.Contains(Dot) && GetDecimalSeparator() != Dot) || + (query.Search.Contains(Comma) && GetDecimalSeparator() != Comma)) return false; return true; } - private string ChangeDecimalSeparator(decimal value, string newDecimalSeparator) + private static string ChangeDecimalSeparator(decimal value, string newDecimalSeparator) { - if (String.IsNullOrEmpty(newDecimalSeparator)) + if (string.IsNullOrEmpty(newDecimalSeparator)) { return value.ToString(); } @@ -161,13 +158,13 @@ namespace Flow.Launcher.Plugin.Calculator return _settings.DecimalSeparator switch { DecimalSeparator.UseSystemLocale => systemDecimalSeparator, - DecimalSeparator.Dot => dot, - DecimalSeparator.Comma => comma, + DecimalSeparator.Dot => Dot, + DecimalSeparator.Comma => Comma, _ => systemDecimalSeparator, }; } - private bool IsBracketComplete(string query) + private static bool IsBracketComplete(string query) { var matchs = RegBrackets.Matches(query); var leftBracketCount = 0; @@ -188,17 +185,17 @@ namespace Flow.Launcher.Plugin.Calculator public string GetTranslatedPluginTitle() { - return Context.API.GetTranslation("flowlauncher_plugin_caculator_plugin_name"); + return Localize.flowlauncher_plugin_caculator_plugin_name(); } public string GetTranslatedPluginDescription() { - return Context.API.GetTranslation("flowlauncher_plugin_caculator_plugin_description"); + return Localize.flowlauncher_plugin_caculator_plugin_description(); } public Control CreateSettingPanel() { - return new CalculatorSettings(_viewModel); + return new CalculatorSettings(_settings); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs index 09f745669..a1f07bd17 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Calculator/ViewModels/SettingsViewModel.cs @@ -8,10 +8,26 @@ namespace Flow.Launcher.Plugin.Calculator.ViewModels public SettingsViewModel(Settings settings) { Settings = settings; + DecimalSeparatorLocalized.UpdateLabels(AllDecimalSeparator); } public Settings Settings { get; init; } public IEnumerable MaxDecimalPlacesRange => Enumerable.Range(1, 20); + + public List AllDecimalSeparator { get; } = DecimalSeparatorLocalized.GetValues(); + + public DecimalSeparator SelectedDecimalSeparator + { + get => Settings.DecimalSeparator; + set + { + if (Settings.DecimalSeparator != value) + { + Settings.DecimalSeparator = value; + OnPropertyChanged(); + } + } + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml b/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml index ceee3897c..589f3ddcd 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Views/CalculatorSettings.xaml @@ -3,20 +3,15 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:calculator="clr-namespace:Flow.Launcher.Plugin.Calculator" - xmlns:core="clr-namespace:Flow.Launcher.Core.Resource;assembly=Flow.Launcher.Core" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:Flow.Launcher.Infrastructure.UI;assembly=Flow.Launcher.Infrastructure" xmlns:viewModels="clr-namespace:Flow.Launcher.Plugin.Calculator.ViewModels" + d:DataContext="{d:DesignInstance Type=viewModels:SettingsViewModel}" d:DesignHeight="450" d:DesignWidth="800" Loaded="CalculatorSettings_Loaded" mc:Ignorable="d"> - - - - @@ -42,14 +37,10 @@ Margin="{StaticResource SettingPanelItemRightTopBottomMargin}" HorizontalAlignment="Left" VerticalAlignment="Center" - ItemsSource="{Binding Source={ui:EnumBindingSource {x:Type calculator:DecimalSeparator}}}" - SelectedItem="{Binding Settings.DecimalSeparator}"> - - - - - - + DisplayMemberPath="Display" + ItemsSource="{Binding AllDecimalSeparator}" + SelectedValue="{Binding SelectedDecimalSeparator, Mode=TwoWay}" + SelectedValuePath="Value" /> Date: Mon, 23 Jun 2025 12:37:58 +0800 Subject: [PATCH 123/545] Adjust indent --- .../Flow.Launcher.Plugin.Calculator.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj index 73dacf3d1..719b6c74f 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Flow.Launcher.Plugin.Calculator.csproj @@ -62,7 +62,7 @@ - + From 1b05643b64acaa357bb5f3195f933d0d1210fbf7 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 23 Jun 2025 12:38:27 +0800 Subject: [PATCH 124/545] Use Flow.Launcher.Localization to improve code quality --- .../ChromiumBookmarkLoader.cs | 8 ++--- .../Commands/BookmarkLoader.cs | 4 +-- .../FirefoxBookmarkLoader.cs | 10 +++--- ...low.Launcher.Plugin.BrowserBookmark.csproj | 2 +- .../Helper/FaviconHelper.cs | 10 +++--- .../Main.cs | 24 +++++++------- .../Models/CustomBrowser.cs | 32 +++++++++++++++---- .../Views/CustomBrowserSetting.xaml | 7 ++-- 8 files changed, 58 insertions(+), 39 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs index 6e6b2e5f4..6dc0f7a9a 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/ChromiumBookmarkLoader.cs @@ -45,7 +45,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to register bookmark file monitoring: {bookmarkPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to register bookmark file monitoring: {bookmarkPath}", ex); continue; } @@ -58,7 +58,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader var faviconDbPath = Path.Combine(profile, "Favicons"); if (File.Exists(faviconDbPath)) { - Main._context.API.StopwatchLogInfo(ClassName, $"Load {profileBookmarks.Count} favicons cost", () => + Main.Context.API.StopwatchLogInfo(ClassName, $"Load {profileBookmarks.Count} favicons cost", () => { LoadFaviconsFromDb(faviconDbPath, profileBookmarks); }); @@ -125,7 +125,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } else { - Main._context.API.LogError(ClassName, $"type property not found for {subElement.GetString()}"); + Main.Context.API.LogError(ClassName, $"type property not found for {subElement.GetString()}"); } } } @@ -190,7 +190,7 @@ public abstract class ChromiumBookmarkLoader : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to extract bookmark favicon: {bookmark.Url}", ex); + Main.Context.API.LogException(ClassName, $"Failed to extract bookmark favicon: {bookmark.Url}", ex); } finally { diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs index 758ce68ae..b76adae93 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Commands/BookmarkLoader.cs @@ -9,11 +9,11 @@ internal static class BookmarkLoader { internal static MatchResult MatchProgram(Bookmark bookmark, string queryString) { - var match = Main._context.API.FuzzySearch(queryString, bookmark.Name); + var match = Main.Context.API.FuzzySearch(queryString, bookmark.Name); if (match.IsSearchPrecisionScoreMet()) return match; - return Main._context.API.FuzzySearch(queryString, bookmark.Url); + return Main.Context.API.FuzzySearch(queryString, bookmark.Url); } internal static List LoadAllBookmarks(Settings setting) diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs index ec3b867ea..68e5d5caa 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/FirefoxBookmarkLoader.cs @@ -49,7 +49,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to register Firefox bookmark file monitoring: {placesPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to register Firefox bookmark file monitoring: {placesPath}", ex); return bookmarks; } @@ -84,7 +84,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader var faviconDbPath = Path.Combine(Path.GetDirectoryName(placesPath), "favicons.sqlite"); if (File.Exists(faviconDbPath)) { - Main._context.API.StopwatchLogInfo(ClassName, $"Load {bookmarks.Count} favicons cost", () => + Main.Context.API.StopwatchLogInfo(ClassName, $"Load {bookmarks.Count} favicons cost", () => { LoadFaviconsFromDb(faviconDbPath, bookmarks); }); @@ -98,7 +98,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to load Firefox bookmarks: {placesPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to load Firefox bookmarks: {placesPath}", ex); } // Delete temporary file @@ -111,7 +111,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); } return bookmarks; @@ -186,7 +186,7 @@ public abstract class FirefoxBookmarkLoaderBase : IBookmarkLoader } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to extract Firefox favicon: {bookmark.Url}", ex); + Main.Context.API.LogException(ClassName, $"Failed to extract Firefox favicon: {bookmark.Url}", ex); } finally { diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj index 3fb0fa46f..bf558bc31 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj @@ -81,7 +81,6 @@ - @@ -96,6 +95,7 @@ + diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs index a879dcefd..b88bd7640 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Helper/FaviconHelper.cs @@ -27,9 +27,9 @@ public static class FaviconHelper } catch (Exception ex1) { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); + Main.Context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex1); } - Main._context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to copy favicon DB: {dbPath}", ex); return; } @@ -39,7 +39,7 @@ public static class FaviconHelper } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to connect to SQLite: {tempDbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to connect to SQLite: {tempDbPath}", ex); } // Delete temporary file @@ -49,7 +49,7 @@ public static class FaviconHelper } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to delete temporary favicon DB: {tempDbPath}", ex); } } @@ -61,7 +61,7 @@ public static class FaviconHelper } catch (Exception ex) { - Main._context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); + Main.Context.API.LogException(ClassName, $"Failed to save image: {outputPath}", ex); } } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs index 91ade206b..3b67e6f18 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs @@ -19,7 +19,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex internal static string _faviconCacheDir; - internal static PluginInitContext _context; + internal static PluginInitContext Context { get; set; } internal static Settings _settings; @@ -29,7 +29,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex public void Init(PluginInitContext context) { - _context = context; + Context = context; _settings = context.API.LoadSettingJsonStorage(); @@ -42,7 +42,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex private static void LoadBookmarksIfEnabled() { - if (_context.CurrentPluginMetadata.Disabled) + if (Context.CurrentPluginMetadata.Disabled) { // Don't load or monitor files if disabled return; @@ -84,7 +84,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex Score = BookmarkLoader.MatchProgram(c, param).Score, Action = _ => { - _context.API.OpenUrl(c.Url); + Context.API.OpenUrl(c.Url); return true; }, @@ -108,7 +108,7 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex Score = 5, Action = _ => { - _context.API.OpenUrl(c.Url); + Context.API.OpenUrl(c.Url); return true; }, ContextData = new BookmarkAttributes { Url = c.Url } @@ -192,12 +192,12 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex public string GetTranslatedPluginTitle() { - return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_name"); + return Localize.flowlauncher_plugin_browserbookmark_plugin_name(); } public string GetTranslatedPluginDescription() { - return _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_plugin_description"); + return Localize.flowlauncher_plugin_browserbookmark_plugin_description(); } public Control CreateSettingPanel() @@ -211,22 +211,22 @@ public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContex { new() { - Title = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_title"), - SubTitle = _context.API.GetTranslation("flowlauncher_plugin_browserbookmark_copyurl_subtitle"), + Title = Localize.flowlauncher_plugin_browserbookmark_copyurl_title(), + SubTitle = Localize.flowlauncher_plugin_browserbookmark_copyurl_subtitle(), Action = _ => { try { - _context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); + Context.API.CopyToClipboard(((BookmarkAttributes)selectedResult.ContextData).Url); return true; } catch (Exception e) { var message = "Failed to set url in clipboard"; - _context.API.LogException(ClassName, message, e); + Context.API.LogException(ClassName, message, e); - _context.API.ShowMsg(message); + Context.API.ShowMsg(message); return false; } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs index 74e0f299a..af1e3fee4 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Models/CustomBrowser.cs @@ -1,4 +1,7 @@ -namespace Flow.Launcher.Plugin.BrowserBookmark.Models; +using System.Collections.Generic; +using Flow.Launcher.Localization.Attributes; + +namespace Flow.Launcher.Plugin.BrowserBookmark.Models; public class CustomBrowser : BaseModel { @@ -11,8 +14,11 @@ public class CustomBrowser : BaseModel get => _name; set { - _name = value; - OnPropertyChanged(); + if (_name != value) + { + _name = value; + OnPropertyChanged(); + } } } @@ -21,24 +27,36 @@ public class CustomBrowser : BaseModel get => _dataDirectoryPath; set { - _dataDirectoryPath = value; - OnPropertyChanged(); + if (_dataDirectoryPath != value) + { + _dataDirectoryPath = value; + OnPropertyChanged(); + } } } + public List AllBrowserTypes { get; } = BrowserTypeLocalized.GetValues(); + public BrowserType BrowserType { get => _browserType; set { - _browserType = value; - OnPropertyChanged(); + if (_browserType != value) + { + _browserType = value; + OnPropertyChanged(); + } } } } +[EnumLocalize] public enum BrowserType { + [EnumLocalizeValue("Chromium")] Chromium, + + [EnumLocalizeValue("Firefox")] Firefox, } diff --git a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml index 80b004ff9..f67d359bf 100644 --- a/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml +++ b/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Views/CustomBrowserSetting.xaml @@ -5,7 +5,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:Flow.Launcher.Plugin.BrowserBookmark.Models" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:Flow.Launcher.Infrastructure.UI;assembly=Flow.Launcher.Infrastructure" Title="{DynamicResource flowlauncher_plugin_browserbookmark_bookmarkDataSetting}" Width="550" Background="{DynamicResource PopuBGColor}" @@ -142,8 +141,10 @@ Margin="5 10 10 0" HorizontalAlignment="Left" VerticalAlignment="Center" - ItemsSource="{Binding Source={ui:EnumBindingSource {x:Type local:BrowserType}}}" - SelectedItem="{Binding BrowserType}" /> + DisplayMemberPath="Display" + ItemsSource="{Binding AllBrowserTypes}" + SelectedValue="{Binding BrowserType}" + SelectedValuePath="Value" /> Date: Mon, 23 Jun 2025 12:45:31 +0800 Subject: [PATCH 125/545] Use trick to get the cache directory path --- .../Flow.Launcher.Plugin.Program.csproj | 1 - Plugins/Flow.Launcher.Plugin.Program/Main.cs | 11 ++++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index 99c1a12e9..7e61f19b3 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -58,7 +58,6 @@ - diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index d28845994..211afcfb0 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows.Controls; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.Program.Programs; using Flow.Launcher.Plugin.Program.Views; using Flow.Launcher.Plugin.Program.Views.Models; @@ -234,11 +233,17 @@ namespace Flow.Launcher.Plugin.Program } } + // If plugin cache directory is this: D:\\Data\\Cache\\Plugins\\Flow.Launcher.Plugin.Program + // then the parent directory is: D:\\Data\\Cache + // So we can use the parent of the parent directory to get the cache directory path + var directoryInfo = new DirectoryInfo(pluginCacheDirectory); + var cacheDirectory = directoryInfo.Parent.Parent.FullName; + // Move old cache files to the new cache directory - var oldWin32CacheFile = Path.Combine(DataLocation.CacheDirectory, $"{Win32CacheName}.cache"); + var oldWin32CacheFile = Path.Combine(cacheDirectory, $"{Win32CacheName}.cache"); var newWin32CacheFile = Path.Combine(pluginCacheDirectory, $"{Win32CacheName}.cache"); MoveFile(oldWin32CacheFile, newWin32CacheFile); - var oldUWPCacheFile = Path.Combine(DataLocation.CacheDirectory, $"{UwpCacheName}.cache"); + var oldUWPCacheFile = Path.Combine(cacheDirectory, $"{UwpCacheName}.cache"); var newUWPCacheFile = Path.Combine(pluginCacheDirectory, $"{UwpCacheName}.cache"); MoveFile(oldUWPCacheFile, newUWPCacheFile); From 6143c9945497397c19ef3476c8a17ebd0c922bd1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 23 Jun 2025 12:47:44 +0800 Subject: [PATCH 126/545] Remove useless class --- .../UI/EnumBindingSource.cs | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs diff --git a/Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs b/Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs deleted file mode 100644 index f9504e6d9..000000000 --- a/Flow.Launcher.Infrastructure/UI/EnumBindingSource.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; -using System.Windows.Markup; - -namespace Flow.Launcher.Infrastructure.UI -{ - [Obsolete("EnumBindingSourceExtension is obsolete. Use with Flow.Launcher.Localization NuGet package instead.")] - public class EnumBindingSourceExtension : MarkupExtension - { - private Type _enumType; - public Type EnumType - { - get { return _enumType; } - set - { - if (value != _enumType) - { - if (value != null) - { - Type enumType = Nullable.GetUnderlyingType(value) ?? value; - if (!enumType.IsEnum) - { - throw new ArgumentException("Type must represent an enum."); - } - } - - _enumType = value; - } - } - } - - public EnumBindingSourceExtension() { } - - public EnumBindingSourceExtension(Type enumType) - { - EnumType = enumType; - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - if (_enumType == null) - { - throw new InvalidOperationException("The EnumType must be specified."); - } - - Type actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType; - Array enumValues = Enum.GetValues(actualEnumType); - - if (actualEnumType == _enumType) - { - return enumValues; - } - - Array tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1); - enumValues.CopyTo(tempArray, 1); - return tempArray; - } - } -} From 107da050a57dca45991be856cfba3c6640e8e9c8 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 23 Jun 2025 13:02:04 +0800 Subject: [PATCH 127/545] Fix build issue --- .../Flow.Launcher.Plugin.Program.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj index 7e61f19b3..16a8c03f4 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj +++ b/Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj @@ -63,11 +63,13 @@ + all runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file From 9be2ef092476727aaf9404e0a196165df4535fbc Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 23 Jun 2025 13:03:45 +0800 Subject: [PATCH 128/545] Remove unused class --- .../Resource/LocalizationConverter.cs | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 Flow.Launcher.Core/Resource/LocalizationConverter.cs diff --git a/Flow.Launcher.Core/Resource/LocalizationConverter.cs b/Flow.Launcher.Core/Resource/LocalizationConverter.cs deleted file mode 100644 index fdda33926..000000000 --- a/Flow.Launcher.Core/Resource/LocalizationConverter.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Reflection; -using System.Windows.Data; - -namespace Flow.Launcher.Core.Resource -{ - [Obsolete("LocalizationConverter is obsolete. Use with Flow.Launcher.Localization NuGet package instead.")] - public class LocalizationConverter : IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (targetType == typeof(string) && value != null) - { - FieldInfo fi = value.GetType().GetField(value.ToString()); - if (fi != null) - { - string localizedDescription = string.Empty; - var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false); - if ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) - { - localizedDescription = attributes[0].Description; - } - - return (!String.IsNullOrEmpty(localizedDescription)) ? localizedDescription : value.ToString(); - } - } - - return string.Empty; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} From c4cbf941cf4a681255a39c9fc38850b178be1fde Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 23 Jun 2025 13:13:45 +0800 Subject: [PATCH 129/545] Add directory null check --- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 211afcfb0..b9187a801 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -237,15 +237,17 @@ namespace Flow.Launcher.Plugin.Program // then the parent directory is: D:\\Data\\Cache // So we can use the parent of the parent directory to get the cache directory path var directoryInfo = new DirectoryInfo(pluginCacheDirectory); - var cacheDirectory = directoryInfo.Parent.Parent.FullName; - - // Move old cache files to the new cache directory - var oldWin32CacheFile = Path.Combine(cacheDirectory, $"{Win32CacheName}.cache"); - var newWin32CacheFile = Path.Combine(pluginCacheDirectory, $"{Win32CacheName}.cache"); - MoveFile(oldWin32CacheFile, newWin32CacheFile); - var oldUWPCacheFile = Path.Combine(cacheDirectory, $"{UwpCacheName}.cache"); - var newUWPCacheFile = Path.Combine(pluginCacheDirectory, $"{UwpCacheName}.cache"); - MoveFile(oldUWPCacheFile, newUWPCacheFile); + var cacheDirectory = directoryInfo.Parent?.Parent?.FullName; + // Move old cache files to the new cache directory if cache directory exists + if (!string.IsNullOrEmpty(cacheDirectory)) + { + var oldWin32CacheFile = Path.Combine(cacheDirectory, $"{Win32CacheName}.cache"); + var newWin32CacheFile = Path.Combine(pluginCacheDirectory, $"{Win32CacheName}.cache"); + MoveFile(oldWin32CacheFile, newWin32CacheFile); + var oldUWPCacheFile = Path.Combine(cacheDirectory, $"{UwpCacheName}.cache"); + var newUWPCacheFile = Path.Combine(pluginCacheDirectory, $"{UwpCacheName}.cache"); + MoveFile(oldUWPCacheFile, newUWPCacheFile); + } await _win32sLock.WaitAsync(); _win32s = await context.API.LoadCacheBinaryStorageAsync(Win32CacheName, pluginCacheDirectory, new List()); From d68964bfa2e0942ae3345adecf5fe507e4bdb266 Mon Sep 17 00:00:00 2001 From: TBM13 Date: Thu, 26 Jun 2025 02:58:24 -0300 Subject: [PATCH 130/545] Calculator: Support hex numbers --- Plugins/Flow.Launcher.Plugin.Calculator/Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs index b1e4cd606..eb3c808e7 100644 --- a/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Calculator/Main.cs @@ -20,7 +20,7 @@ namespace Flow.Launcher.Plugin.Calculator @"bin2dec|hex2dec|oct2dec|" + @"factorial|sign|isprime|isinfty|" + @"==|~=|&&|\|\||(?:\<|\>)=?|" + - @"[ei]|[0-9]|[\+\%\-\*\/\^\., ""]|[\(\)\|\!\[\]]" + + @"[ei]|[0-9]|0x[\da-fA-F]+|[\+\%\-\*\/\^\., ""]|[\(\)\|\!\[\]]" + @")+$", RegexOptions.Compiled); private static readonly Regex RegBrackets = new Regex(@"[\(\)\[\]]", RegexOptions.Compiled); private static Engine MagesEngine; From c9de2f02f8f2466da2853404bdeb49056ac17d61 Mon Sep 17 00:00:00 2001 From: DB P Date: Fri, 27 Jun 2025 18:51:51 +0900 Subject: [PATCH 131/545] Fix Card Error --- Flow.Launcher/Resources/Controls/Card.xaml | 6 ++--- Flow.Launcher/Resources/Controls/Card.xaml.cs | 5 ++++- .../Views/SettingsPaneGeneral.xaml | 22 ++++++++++++++----- .../Views/SettingsPaneHotkey.xaml | 19 ++++++++++++++-- .../SettingPages/Views/SettingsPaneProxy.xaml | 10 ++++----- .../SettingPages/Views/SettingsPaneTheme.xaml | 16 ++++++++++---- 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/Flow.Launcher/Resources/Controls/Card.xaml b/Flow.Launcher/Resources/Controls/Card.xaml index 33c1299a9..e3c5f8194 100644 --- a/Flow.Launcher/Resources/Controls/Card.xaml +++ b/Flow.Launcher/Resources/Controls/Card.xaml @@ -38,21 +38,21 @@ - + - + - + diff --git a/Flow.Launcher/Resources/Controls/Card.xaml.cs b/Flow.Launcher/Resources/Controls/Card.xaml.cs index c8f788aca..6a70dded2 100644 --- a/Flow.Launcher/Resources/Controls/Card.xaml.cs +++ b/Flow.Launcher/Resources/Controls/Card.xaml.cs @@ -9,7 +9,10 @@ namespace Flow.Launcher.Resources.Controls { Default, Inside, - InsideFit + InsideFit, + First, + Middle, + Last } public Card() diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 7f8555d65..d114736d5 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -91,7 +91,10 @@ - + @@ -196,7 +200,10 @@ - + - + + Sub="{DynamicResource KoreanImeRegistryTooltip}" + Type="First"> + Sub="{DynamicResource KoreanImeOpenLinkToolTip}" + Type="Last"> + Date: Mon, 14 Jul 2025 16:24:46 +0800 Subject: [PATCH 233/545] Rename function name --- Flow.Launcher.Core/Plugin/PluginInstaller.cs | 2 +- Flow.Launcher/App.xaml.cs | 4 ++-- .../ViewModels/SettingsPanePluginStoreViewModel.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs index 692fe3ce1..4c551f993 100644 --- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs +++ b/Flow.Launcher.Core/Plugin/PluginInstaller.cs @@ -284,7 +284,7 @@ public static class PluginInstaller /// If true, only use the primary URL for updates. /// Cancellation token to cancel the update operation. /// - public static async Task UpdatePluginAsync(bool silentUpdate = true, bool usePrimaryUrlOnly = false, CancellationToken token = default) + public static async Task CheckForPluginUpdatesAsync(bool silentUpdate = true, bool usePrimaryUrlOnly = false, CancellationToken token = default) { // Update the plugin manifest await API.UpdatePluginManifestAsync(usePrimaryUrlOnly, token); diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 6b04f11d9..7e3915b2b 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -298,11 +298,11 @@ namespace Flow.Launcher { // check plugin updates every 5 hour var timer = new PeriodicTimer(TimeSpan.FromHours(5)); - await PluginInstaller.UpdatePluginAsync(); + await PluginInstaller.CheckForPluginUpdatesAsync(); while (await timer.WaitForNextTickAsync()) // check updates on startup - await PluginInstaller.UpdatePluginAsync(); + await PluginInstaller.CheckForPluginUpdatesAsync(); } }); } diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs index bfec08c52..96cd44072 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs @@ -112,7 +112,7 @@ public partial class SettingsPanePluginStoreViewModel : BaseModel [RelayCommand] private async Task CheckPluginUpdatesAsync() { - await PluginInstaller.UpdatePluginAsync(silentUpdate: false); + await PluginInstaller.CheckForPluginUpdatesAsync(silentUpdate: false); } private static string GetFileFromDialog(string title, string filter = "") From 69d5e33150c83ceaf455aec48a1b83004efc83ad Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 14 Jul 2025 16:31:09 +0800 Subject: [PATCH 234/545] Show message box with button instead --- Flow.Launcher.Core/Plugin/PluginInstaller.cs | 22 ++++++++++++-------- Flow.Launcher/Languages/en.xaml | 4 ++-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs index 4c551f993..84f0f1fd9 100644 --- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs +++ b/Flow.Launcher.Core/Plugin/PluginInstaller.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; @@ -327,17 +328,20 @@ public static class PluginInstaller return; } - if (API.ShowMsgBox( - string.Format(API.GetTranslation("updateAllPluginsSubtitle"), - Environment.NewLine, string.Join(", ", resultsForUpdate.Select(x => x.PluginExistingMetadata.Name))), + // Show message box with button to update all plugins + API.ShowMsgWithButton( API.GetTranslation("updateAllPluginsTitle"), - MessageBoxButton.YesNo) == MessageBoxResult.No) - { - return; - } + API.GetTranslation("updateAllPluginsButtonContent"), + () => + { + UpdateAllPlugins(resultsForUpdate); + }, + string.Join(", ", resultsForUpdate.Select(x => x.PluginExistingMetadata.Name))); + } - // Update all plugins - await Task.WhenAll(resultsForUpdate.Select(async plugin => + private static void UpdateAllPlugins(IEnumerable resultsForUpdate) + { + _ = Task.WhenAll(resultsForUpdate.Select(async plugin => { var downloadToFilePath = Path.Combine(Path.GetTempPath(), $"{plugin.Name}-{plugin.NewVersion}.zip"); diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index ee500324e..53f26c5f4 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -235,8 +235,8 @@ Install plugin from local path No update available All plugins are up to date - Update all plugins - Would you like to update these plugins?{0}{0}{1} + Plugin updates available + Update all plugins Check plugin updates From 44fbc6eed5763b089c78cc8f9a2eab3e8cb33185 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 14 Jul 2025 16:35:48 +0800 Subject: [PATCH 235/545] Add auto update subtitle --- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 53f26c5f4..3905df7c6 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -93,6 +93,7 @@ Always Start Typing in English Mode Temporarily change your input method to English mode when activating Flow. Auto Update + Automatically check app updates and notify if there are any updates available Select Hide Flow Launcher on startup Flow Launcher search window is hidden in the tray after starting up. diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 78b6d8db0..cfb292633 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -182,7 +182,8 @@ + Icon="" + Sub="{DynamicResource autoUpdatesTooltip}"> Date: Mon, 14 Jul 2025 16:49:04 +0800 Subject: [PATCH 236/545] Change double pinyin panel design --- .../Views/SettingsPaneGeneral.xaml | 47 ++++++++----------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index df0243ce8..38fc8df54 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -371,44 +371,37 @@ OnContent="{DynamicResource enable}" /> - - - - - + + + + + + - - + + - + Date: Mon, 14 Jul 2025 16:56:12 +0800 Subject: [PATCH 237/545] Replace dynamic type with a strongly-typed model --- Flow.Launcher.Core/Plugin/PluginInstaller.cs | 24 +++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs index 84f0f1fd9..c00c83d9e 100644 --- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs +++ b/Flow.Launcher.Core/Plugin/PluginInstaller.cs @@ -300,14 +300,14 @@ public static class PluginInstaller 0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest) && !API.PluginModified(existingPlugin.Metadata.ID) select - new + new PluginUpdateInfo() { - existingPlugin.Metadata.ID, - pluginUpdateSource.Name, - pluginUpdateSource.Author, + ID = existingPlugin.Metadata.ID, + Name = existingPlugin.Metadata.Name, + Author = existingPlugin.Metadata.Author, CurrentVersion = existingPlugin.Metadata.Version, NewVersion = pluginUpdateSource.Version, - existingPlugin.Metadata.IcoPath, + IcoPath = existingPlugin.Metadata.IcoPath, PluginExistingMetadata = existingPlugin.Metadata, PluginNewUserPlugin = pluginUpdateSource }).ToList(); @@ -339,7 +339,7 @@ public static class PluginInstaller string.Join(", ", resultsForUpdate.Select(x => x.PluginExistingMetadata.Name))); } - private static void UpdateAllPlugins(IEnumerable resultsForUpdate) + private static void UpdateAllPlugins(IEnumerable resultsForUpdate) { _ = Task.WhenAll(resultsForUpdate.Select(async plugin => { @@ -445,4 +445,16 @@ public static class PluginInstaller x.Metadata.Website.StartsWith(constructedUrlPart) ); } + + private record PluginUpdateInfo + { + public string ID { get; init; } + public string Name { get; init; } + public string Author { get; init; } + public string CurrentVersion { get; init; } + public string NewVersion { get; init; } + public string IcoPath { get; init; } + public PluginMetadata PluginExistingMetadata { get; init; } + public UserPlugin PluginNewUserPlugin { get; init; } + } } From 6317d0eec6f42b788324fdcf9e6a2c2fdea388f4 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 14 Jul 2025 19:29:12 +0800 Subject: [PATCH 238/545] Reload on all settings change --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 13 ++++++++++--- .../UserSettings/Settings.cs | 14 +++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index cc4eccdc5..0f6d00014 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -25,10 +25,17 @@ namespace Flow.Launcher.Infrastructure _settings.PropertyChanged += (sender, e) => { - if (e.PropertyName == nameof(Settings.UseDoublePinyin) || - e.PropertyName == nameof(Settings.DoublePinyinSchema)) + switch (e.PropertyName) { - Reload(); + case nameof(Settings.ShouldUsePinyin): + Reload(); + break; + case nameof(Settings.UseDoublePinyin): + Reload(); + break; + case nameof(Settings.DoublePinyinSchema): + Reload(); + break; } }; } diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 6b10d693d..726a0023b 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -328,7 +328,19 @@ namespace Flow.Launcher.Infrastructure.UserSettings /// /// when false Alphabet static service will always return empty results /// - public bool ShouldUsePinyin { get; set; } = false; + private bool _useAlphabet = true; + public bool ShouldUsePinyin + { + get => _useAlphabet; + set + { + if (_useAlphabet != value) + { + _useAlphabet = value; + OnPropertyChanged(); + } + } + } private bool _useDoublePinyin = false; public bool UseDoublePinyin From 8c56c0bddf4a4b7b361b26a3a6b32038144c2f35 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 14 Jul 2025 19:30:16 +0800 Subject: [PATCH 239/545] Fix logic --- Flow.Launcher.Infrastructure/PinyinAlphabet.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs index 0f6d00014..1c0cc6872 100644 --- a/Flow.Launcher.Infrastructure/PinyinAlphabet.cs +++ b/Flow.Launcher.Infrastructure/PinyinAlphabet.cs @@ -27,14 +27,18 @@ namespace Flow.Launcher.Infrastructure { switch (e.PropertyName) { - case nameof(Settings.ShouldUsePinyin): - Reload(); + case nameof (Settings.ShouldUsePinyin): + if (_settings.ShouldUsePinyin) + { + Reload(); + } break; case nameof(Settings.UseDoublePinyin): - Reload(); - break; case nameof(Settings.DoublePinyinSchema): - Reload(); + if (_settings.UseDoublePinyin) + { + Reload(); + } break; } }; From fd4efe009cf2839b5eb01c95aaceb025a84edda2 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:07:25 +0800 Subject: [PATCH 240/545] Hide double pin card when use pinyin is false --- Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 38fc8df54..a879007c3 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -386,6 +386,8 @@ Date: Mon, 14 Jul 2025 21:21:47 +0800 Subject: [PATCH 241/545] Update spell check --- .github/actions/spelling/expect.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 0fea6d9ab..d8c99bce9 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -104,3 +104,12 @@ metadatas WMP VSTHRD CJK +XiaoHe +ZiRanMa +WeiRuan +ZhiNengABC +ZiGuangPinYin +PinYinJiaJia +XingKongJianDao +DaNiu +XiaoLang From 970aa5eefe89d3a3009753ed76a8bec64cd1d827 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:24:11 +0800 Subject: [PATCH 242/545] Fix typo --- .../UserSettings/Settings.cs | 2 +- .../ChineseDetectionPerformanceTest.cs | 265 ++++++++++++++++++ 2 files changed, 266 insertions(+), 1 deletion(-) create mode 100644 Flow.Launcher.Test/ChineseDetectionPerformanceTest.cs diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 726a0023b..271f618da 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -514,7 +514,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings { var list = FixedHotkeys(); - // Customizeable hotkeys + // Customizable hotkeys if (!string.IsNullOrEmpty(Hotkey)) list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = "")); if (!string.IsNullOrEmpty(PreviewHotkey)) diff --git a/Flow.Launcher.Test/ChineseDetectionPerformanceTest.cs b/Flow.Launcher.Test/ChineseDetectionPerformanceTest.cs new file mode 100644 index 000000000..1747f2b4a --- /dev/null +++ b/Flow.Launcher.Test/ChineseDetectionPerformanceTest.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using NUnit.Framework.Legacy; +using Flow.Launcher.Infrastructure; +using ToolGood.Words.Pinyin; + +namespace Flow.Launcher.Test +{ + /// + /// Performance test comparing ContainsChinese() vs WordsHelper.HasChinese() + /// + /// This test verifies: + /// 1. Both methods produce identical results (correctness) + /// 2. Performance characteristics of both implementations + /// 3. Memory allocation patterns + /// + /// The ContainsChinese() method uses optimized Unicode range checking with ReadOnlySpan + /// while WordsHelper.HasChinese() uses the ToolGood.Words library implementation. + /// + [TestFixture] + public class ChineseDetectionPerformanceTest + { + private readonly List _testStrings = new() + { + // Pure English - should return false + "Hello World", + "Visual Studio Code", + "Microsoft Office 2023", + "Adobe Photoshop Creative Suite", + "Google Chrome Browser Application", + + // Pure Chinese - should return true + "你好世界", + "微软办公软件", + "谷歌浏览器", + "北京大学计算机科学与技术学院", + "中华人民共和国国家发展和改革委员会", + + // Mixed content - should return true + "Hello 世界", + "Visual Studio 代码编辑器", + "QQ音乐 Music Player", + "Windows 10 操作系统", + "GitHub 代码仓库管理平台", + + // Edge cases + "", + " ", + "123456", + "!@#$%^&*()", + "café résumé naïve", // Accented characters (not Chinese) + + // Long strings for performance testing + "This is a very long English string that contains no Chinese characters but is designed to test performance with longer text content that might appear in file names or application descriptions", + "这是一个非常长的中文字符串,包含了很多汉字,用来测试在处理较长中文文本时的性能表现,比如可能出现在文件名或应用程序描述中的文本内容", + "This is a mixed 混合内容的字符串 that contains both English and Chinese characters 中英文混合 to test performance with 复杂的文本内容 in real-world scenarios 真实场景中的应用" + }; + + [Test] + public void ContainsChinese_CorrectnessTest() + { + // Verify ContainsChinese works correctly for known cases + ClassicAssert.IsFalse(ContainsChinese("Hello World"), "Pure English should return false"); + ClassicAssert.IsTrue(ContainsChinese("你好世界"), "Pure Chinese should return true"); + ClassicAssert.IsTrue(ContainsChinese("Hello 世界"), "Mixed content should return true"); + ClassicAssert.IsFalse(ContainsChinese(""), "Empty string should return false"); + ClassicAssert.IsFalse(ContainsChinese("123456"), "Numbers should return false"); + ClassicAssert.IsFalse(ContainsChinese("café résumé"), "Accented characters should return false"); + } + + [Test] + public void WordsHelper_CorrectnessTest() + { + // Verify WordsHelper.HasChinese works correctly for known cases + ClassicAssert.IsFalse(WordsHelper.HasChinese("Hello World"), "Pure English should return false"); + ClassicAssert.IsTrue(WordsHelper.HasChinese("你好世界"), "Pure Chinese should return true"); + ClassicAssert.IsTrue(WordsHelper.HasChinese("Hello 世界"), "Mixed content should return true"); + ClassicAssert.IsFalse(WordsHelper.HasChinese(""), "Empty string should return false"); + ClassicAssert.IsFalse(WordsHelper.HasChinese("123456"), "Numbers should return false"); + ClassicAssert.IsFalse(WordsHelper.HasChinese("café résumé"), "Accented characters should return false"); + } + + [Test] + public void BothMethods_ShouldProduceSameResults() + { + // Critical test: verify both methods produce identical results for all test cases + foreach (var testString in _testStrings) + { + var wordsHelperResult = WordsHelper.HasChinese(testString); + var containsChineseResult = ContainsChinese(testString); + + ClassicAssert.AreEqual(wordsHelperResult, containsChineseResult, + $"Results differ for string: '{testString}'. WordsHelper: {wordsHelperResult}, ContainsChinese: {containsChineseResult}"); + } + + Console.WriteLine($"✓ Both methods produce identical results for all {_testStrings.Count} test cases"); + } + + [Test] + public void PerformanceComparison_BasicBenchmark() + { + const int iterations = 1000000; + + Console.WriteLine("=== CHINESE CHARACTER DETECTION PERFORMANCE TEST ==="); + Console.WriteLine($"Test iterations: {iterations:N0}"); + Console.WriteLine($"Test strings: {_testStrings.Count}"); + Console.WriteLine($"Total operations: {iterations * _testStrings.Count:N0}"); + Console.WriteLine(); + + // Warmup to ensure JIT compilation + Console.WriteLine("Warming up..."); + for (int i = 0; i < 1000; i++) + { + foreach (var testString in _testStrings) + { + _ = ContainsChinese(testString); + _ = WordsHelper.HasChinese(testString); + } + } + + // Benchmark ContainsChinese method + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + var sw1 = System.Diagnostics.Stopwatch.StartNew(); + for (int i = 0; i < iterations; i++) + { + foreach (var testString in _testStrings) + { + _ = ContainsChinese(testString); + } + } + sw1.Stop(); + + // Benchmark WordsHelper.HasChinese method + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + var sw2 = System.Diagnostics.Stopwatch.StartNew(); + for (int i = 0; i < iterations; i++) + { + foreach (var testString in _testStrings) + { + _ = WordsHelper.HasChinese(testString); + } + } + sw2.Stop(); + + // Calculate and display results + var containsChineseMs = sw1.Elapsed.TotalMilliseconds; + var wordsHelperMs = sw2.Elapsed.TotalMilliseconds; + var speedRatio = wordsHelperMs / containsChineseMs; + var timeDifference = wordsHelperMs - containsChineseMs; + + Console.WriteLine("RESULTS:"); + Console.WriteLine($"ContainsChinese(): {containsChineseMs:F3} ms"); + Console.WriteLine($"WordsHelper.HasChinese(): {wordsHelperMs:F3} ms"); + Console.WriteLine($"Time difference: {timeDifference:F3} ms"); + Console.WriteLine($"Speed improvement: {speedRatio:F2}x"); + Console.WriteLine($"Performance gain: {((speedRatio - 1) * 100):F1}%"); + Console.WriteLine(); + + if (speedRatio > 1.0) + { + Console.WriteLine($"✓ ContainsChinese() is {speedRatio:F2}x faster than WordsHelper.HasChinese()"); + } + else + { + Console.WriteLine($"⚠ WordsHelper.HasChinese() is {(1/speedRatio):F2}x faster than ContainsChinese()"); + } + + // Test always passes - this is a measurement test + ClassicAssert.IsTrue(true); + } + + [Test] + public void PerformanceComparison_ByStringType() + { + Console.WriteLine("=== PERFORMANCE BY STRING TYPE ==="); + + var categories = new Dictionary> + { + ["Pure English"] = _testStrings.Where(s => !ContainsChinese(s) && s.All(c => c <= 127)).ToList(), + ["Pure Chinese"] = _testStrings.Where(s => ContainsChinese(s) && s.All(c => IsChineseCharacter(c) || char.IsWhiteSpace(c))).ToList(), + ["Mixed Content"] = _testStrings.Where(s => ContainsChinese(s) && s.Any(c => c <= 127 && char.IsLetter(c))).ToList(), + ["Edge Cases"] = _testStrings.Where(s => string.IsNullOrWhiteSpace(s) || s.All(c => !char.IsLetter(c))).ToList() + }; + + foreach (var category in categories) + { + if (category.Value.Count == 0) continue; + + Console.WriteLine($"\n{category.Key} ({category.Value.Count} strings):"); + + var sample = category.Value.First(); + var displayText = sample.Length > 40 ? sample.Substring(0, 40) + "..." : sample; + Console.WriteLine($" Sample: '{displayText}'"); + + const int categoryIterations = 5000; + + // Test each method + var sw1 = System.Diagnostics.Stopwatch.StartNew(); + for (int i = 0; i < categoryIterations; i++) + { + foreach (var str in category.Value) + { + _ = ContainsChinese(str); + } + } + sw1.Stop(); + + var sw2 = System.Diagnostics.Stopwatch.StartNew(); + for (int i = 0; i < categoryIterations; i++) + { + foreach (var str in category.Value) + { + _ = WordsHelper.HasChinese(str); + } + } + sw2.Stop(); + + var ratio = (double)sw2.ElapsedTicks / sw1.ElapsedTicks; + Console.WriteLine($" Performance: ContainsChinese is {ratio:F2}x faster"); + } + + ClassicAssert.IsTrue(true); + } + + /// + /// Optimized Chinese character detection using comprehensive CJK Unicode ranges + /// This method uses ReadOnlySpan for better performance and covers all CJK character ranges + /// + private static bool ContainsChinese(ReadOnlySpan text) + { + foreach (var c in text) + { + if (IsChineseCharacter(c)) + return true; + } + return false; + } + + /// + /// Check if a character is a Chinese character using comprehensive Unicode ranges + /// Covers CJK Unified Ideographs and all extension blocks + /// + private static bool IsChineseCharacter(char c) + { + return (c >= 0x4E00 && c <= 0x9FFF) || // CJK Unified Ideographs (most common Chinese characters) + (c >= 0x3400 && c <= 0x4DBF) || // CJK Extension A + (c >= 0x20000 && c <= 0x2A6DF) || // CJK Extension B + (c >= 0x2A700 && c <= 0x2B73F) || // CJK Extension C + (c >= 0x2B740 && c <= 0x2B81F) || // CJK Extension D + (c >= 0x2B820 && c <= 0x2CEAF) || // CJK Extension E + (c >= 0x2CEB0 && c <= 0x2EBEF) || // CJK Extension F + (c >= 0xF900 && c <= 0xFAFF) || // CJK Compatibility Ideographs + (c >= 0x2F800 && c <= 0x2FA1F); // CJK Compatibility Supplement + } + } +} From f3bca632326a215836daa84cc3ef056fc1ad9157 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:46:54 +0800 Subject: [PATCH 243/545] Update wording --- Flow.Launcher/Languages/en.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 2fca06605..acd38baac 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -106,7 +106,7 @@ Search with Pinyin Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese. Use Double Pinyin - Allows using Double Pinyin to search. Double Pinyin is a variation of Pinyin that uses two characters. + Use Double Pinyin instead of Full Pinyin to search. Double Pinyin Schema Xiao He Zi Ran Ma From dae16b9b8de42752162c21d07741425d86c62d4e Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 14 Jul 2025 21:53:49 +0800 Subject: [PATCH 244/545] Try to fix false spell check alarms by using stable version --- .github/workflows/spelling.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index 47bd66107..eb3bec416 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -72,7 +72,7 @@ jobs: steps: - name: check-spelling id: spelling - uses: check-spelling/check-spelling@prerelease + uses: check-spelling/check-spelling@0.0.25 with: suppress_push_for_open_pull_request: 1 checkout: true From c15ff61f92e6d1a5a755ca9c559a327728be3b5c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Mon, 14 Jul 2025 22:19:34 +0800 Subject: [PATCH 245/545] Use stable version --- .github/workflows/spelling.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index eb3bec416..ebea86d62 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -128,7 +128,7 @@ jobs: if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request') steps: - name: comment - uses: check-spelling/check-spelling@prerelease + uses: check-spelling/check-spelling@0.0.25 with: checkout: true spell_check_this: check-spelling/spell-check-this@main From e08b73154880ae1b1065195a2b39c253937da587 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 00:10:44 +0800 Subject: [PATCH 246/545] Disable line_forbidden.patterns --- .../actions/spelling/line_forbidden.patterns | 124 +++++++++--------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/.github/actions/spelling/line_forbidden.patterns b/.github/actions/spelling/line_forbidden.patterns index 7341d9b73..119d89321 100644 --- a/.github/actions/spelling/line_forbidden.patterns +++ b/.github/actions/spelling/line_forbidden.patterns @@ -1,62 +1,62 @@ -# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere -# \bm_data\b - -# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, -# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want -# to use this: -#\bfit\( - -# s.b. GitHub -#\bGithub\b - -# s.b. GitLab -\bGitlab\b - -# s.b. JavaScript -\bJavascript\b - -# s.b. Microsoft -\bMicroSoft\b - -# s.b. another -\ban[- ]other\b - -# s.b. greater than -\bgreater then\b - -# s.b. into -\sin to\s - -# s.b. opt-in -\sopt in\s - -# s.b. less than -\bless then\b - -# s.b. otherwise -\bother[- ]wise\b - -# s.b. nonexistent -\bnon existing\b -\b[Nn]o[nt][- ]existent\b - -# s.b. preexisting -[Pp]re[- ]existing - -# s.b. preempt -[Pp]re[- ]empt\b - -# s.b. preemptively -[Pp]re[- ]emptively - -# s.b. reentrancy -[Rr]e[- ]entrancy - -# s.b. reentrant -[Rr]e[- ]entrant - -# s.b. workaround(s) -\bwork[- ]arounds?\b - -# Reject duplicate words -\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s +## reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere +## \bm_data\b +# +## If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, +## you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want +## to use this: +##\bfit\( +# +## s.b. GitHub +##\bGithub\b +# +## s.b. GitLab +#\bGitlab\b +# +## s.b. JavaScript +#\bJavascript\b +# +## s.b. Microsoft +#\bMicroSoft\b +# +## s.b. another +#\ban[- ]other\b +# +## s.b. greater than +#\bgreater then\b +# +## s.b. into +#\sin to\s +# +## s.b. opt-in +#\sopt in\s +# +## s.b. less than +#\bless then\b +# +## s.b. otherwise +#\bother[- ]wise\b +# +## s.b. nonexistent +#\bnon existing\b +#\b[Nn]o[nt][- ]existent\b +# +## s.b. preexisting +#[Pp]re[- ]existing +# +## s.b. preempt +#[Pp]re[- ]empt\b +# +## s.b. preemptively +#[Pp]re[- ]emptively +# +## s.b. reentrancy +#[Rr]e[- ]entrancy +# +## s.b. reentrant +#[Rr]e[- ]entrant +# +## s.b. workaround(s) +#\bwork[- ]arounds?\b +# +## Reject duplicate words +#\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s From ab0e6640734df9ab78e403f7576d83c897c9748c Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 19:16:59 +0800 Subject: [PATCH 247/545] Use a stable version --- .github/workflows/spelling.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spelling.yml b/.github/workflows/spelling.yml index 47bd66107..f738263fa 100644 --- a/.github/workflows/spelling.yml +++ b/.github/workflows/spelling.yml @@ -72,7 +72,7 @@ jobs: steps: - name: check-spelling id: spelling - uses: check-spelling/check-spelling@prerelease + uses: check-spelling/check-spelling@0.0.24 with: suppress_push_for_open_pull_request: 1 checkout: true @@ -128,7 +128,7 @@ jobs: if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request') steps: - name: comment - uses: check-spelling/check-spelling@prerelease + uses: check-spelling/check-spelling@0.0.24 with: checkout: true spell_check_this: check-spelling/spell-check-this@main From af50c7bdc3181665915656b3f52a46f52f860729 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 19:57:42 +0800 Subject: [PATCH 248/545] Add double pinyin schemas to patterns They are not well formed English words so can be rejected by built-in checks. Use regex as a workaround. --- .github/actions/spelling/allow.txt | 2 -- .github/actions/spelling/expect.txt | 9 --------- .github/actions/spelling/patterns.txt | 9 +++++++++ 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index a36a6af3e..1d7f12d4a 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -4,5 +4,3 @@ ssh ubuntu runcount Firefox -Português -Português (Brasil) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index d8c99bce9..0fea6d9ab 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -104,12 +104,3 @@ metadatas WMP VSTHRD CJK -XiaoHe -ZiRanMa -WeiRuan -ZhiNengABC -ZiGuangPinYin -PinYinJiaJia -XingKongJianDao -DaNiu -XiaoLang diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index f308ec599..f7c54aa73 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -134,3 +134,12 @@ \bčeština\b \bPortuguês\b \bIoc\b +\bXiaoHe\b +\bZiRanMa\b +\bWeiRuan\b +\bZhiNengABC\b +\bZiGuangPinYin\b +\bPinYinJiaJia\b +\bXingKongJianDao\b +\bDaNiu\b +\bXiaoLang\b From a858aa8f5554b7e87d01c4c3d563516625ffdbc2 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Tue, 15 Jul 2025 19:58:12 +0800 Subject: [PATCH 249/545] Update auto update desc Co-authored-by: Jeremy Wu --- Flow.Launcher/Languages/en.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 3905df7c6..725d8d3e1 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -93,7 +93,7 @@ Always Start Typing in English Mode Temporarily change your input method to English mode when activating Flow. Auto Update - Automatically check app updates and notify if there are any updates available + Automatically check and update the app when available Select Hide Flow Launcher on startup Flow Launcher search window is hidden in the tray after starting up. From 34238051cf2cca8be2cabec27d599548f27d2645 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 20:03:17 +0800 Subject: [PATCH 250/545] Update spelling patterns to support optional spaces in Pinyin matching --- .github/actions/spelling/patterns.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/actions/spelling/patterns.txt b/.github/actions/spelling/patterns.txt index f7c54aa73..eb8534c49 100644 --- a/.github/actions/spelling/patterns.txt +++ b/.github/actions/spelling/patterns.txt @@ -134,12 +134,12 @@ \bčeština\b \bPortuguês\b \bIoc\b -\bXiaoHe\b -\bZiRanMa\b -\bWeiRuan\b -\bZhiNengABC\b -\bZiGuangPinYin\b -\bPinYinJiaJia\b -\bXingKongJianDao\b -\bDaNiu\b -\bXiaoLang\b +\bXiao\s*He\b +\bZi\s*Ran\s*Ma\b +\bWei\s*Ruan\b +\bZhi\s*Neng\s*ABC\b +\bZi\s*Guang\s*Pin\s*Yin\b +\bPin\s*Yin\s*Jia\s*Jia\b +\bXing\s*Kong\s*Jian\s*Dao\b +\bDa\s*Niu\b +\bXiao\s*Lang\b From 07415913ed5d0741fa021370bf459a89aad1c6f8 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 20:05:03 +0800 Subject: [PATCH 251/545] Add word --- .github/actions/spelling/allow.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 1d7f12d4a..5bcf16c97 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -4,3 +4,4 @@ ssh ubuntu runcount Firefox +workaround \ No newline at end of file From e3e8eff5c989b2a6ef28aefd185b2dbe98952f2f Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 20:06:33 +0800 Subject: [PATCH 252/545] Fix EOF newline --- .github/actions/spelling/allow.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/spelling/allow.txt b/.github/actions/spelling/allow.txt index 5bcf16c97..670a7a799 100644 --- a/.github/actions/spelling/allow.txt +++ b/.github/actions/spelling/allow.txt @@ -4,4 +4,4 @@ ssh ubuntu runcount Firefox -workaround \ No newline at end of file +workaround From 37d6cea2d32822c9b26ede0ee6f2b1a1e4cf5f63 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 15 Jul 2025 22:10:07 +1000 Subject: [PATCH 253/545] fix typo --- Flow.Launcher.Core/Plugin/PluginInstaller.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher.Core/Plugin/PluginInstaller.cs b/Flow.Launcher.Core/Plugin/PluginInstaller.cs index c00c83d9e..a79f4b47c 100644 --- a/Flow.Launcher.Core/Plugin/PluginInstaller.cs +++ b/Flow.Launcher.Core/Plugin/PluginInstaller.cs @@ -281,7 +281,7 @@ public static class PluginInstaller /// /// Updates the plugin to the latest version available from its source. /// - /// If true, do not show any messages when there is no udpate available. + /// If true, do not show any messages when there is no update available. /// If true, only use the primary URL for updates. /// Cancellation token to cancel the update operation. /// From a34b8f2630a93c439dfea4107a9f27eeb5b3c464 Mon Sep 17 00:00:00 2001 From: WayneFerdon Date: Tue, 15 Jul 2025 21:22:19 +0800 Subject: [PATCH 254/545] [Plugin.Sys Enhancement] Support returning all usable commands while query is empty; ChangeQuery by ThemeSelector Action with ActionKeyword at the front as well --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 39bf49654..09581709f 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -70,13 +70,19 @@ namespace Flow.Launcher.Plugin.Sys return _themeSelector.Query(query); } - var commands = Commands(); + var commands = Commands(query); var results = new List(); + var isEmptyQuery = string.IsNullOrEmpty(query.Search) || string.IsNullOrWhiteSpace(query.Search); foreach (var c in commands) { var command = _settings.Commands.First(x => x.Key == c.Title); c.Title = command.Name; c.SubTitle = command.Description; + if (isEmptyQuery) + { + results.Add(c); + continue; + } // Match from localized title & localized subtitle & keyword var titleMatch = _context.API.FuzzySearch(query.Search, c.Title); @@ -188,7 +194,7 @@ namespace Flow.Launcher.Plugin.Sys } } - private List Commands() + private List Commands(Query query) { var results = new List(); var recycleBinFolder = "shell:RecycleBinFolder"; @@ -491,7 +497,7 @@ namespace Flow.Launcher.Plugin.Sys Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\ue790"), Action = c => { - _context.API.ChangeQuery($"{ThemeSelector.Keyword} "); + _context.API.ChangeQuery($"{query.ActionKeyword}{ (string.IsNullOrEmpty(query.ActionKeyword) ? string.Empty : Plugin.Query.ActionKeywordSeparator)}{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}"); return false; } } From aece80390560dec310327817f6c26618a8bacabc Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 15 Jul 2025 21:50:41 +0800 Subject: [PATCH 255/545] Simplify logic --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index 09581709f..fc0770375 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -72,7 +72,7 @@ namespace Flow.Launcher.Plugin.Sys var commands = Commands(query); var results = new List(); - var isEmptyQuery = string.IsNullOrEmpty(query.Search) || string.IsNullOrWhiteSpace(query.Search); + var isEmptyQuery = string.IsNullOrWhiteSpace(query.Search); foreach (var c in commands) { var command = _settings.Commands.First(x => x.Key == c.Title); From 539a8523636678b8b10daa60181b04a13bc3cc25 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 15 Jul 2025 21:59:40 +0800 Subject: [PATCH 256/545] Improve logic --- Plugins/Flow.Launcher.Plugin.Sys/Main.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs index fc0770375..d2dcf6e5a 100644 --- a/Plugins/Flow.Launcher.Plugin.Sys/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Sys/Main.cs @@ -497,7 +497,15 @@ namespace Flow.Launcher.Plugin.Sys Glyph = new GlyphInfo (FontFamily:"/Resources/#Segoe Fluent Icons", Glyph:"\ue790"), Action = c => { - _context.API.ChangeQuery($"{query.ActionKeyword}{ (string.IsNullOrEmpty(query.ActionKeyword) ? string.Empty : Plugin.Query.ActionKeywordSeparator)}{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}"); + if (string.IsNullOrEmpty(query.ActionKeyword)) + { + _context.API.ChangeQuery($"{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}"); + } + else + { + _context.API.ChangeQuery($"{query.ActionKeyword}{Plugin.Query.ActionKeywordSeparator}{ThemeSelector.Keyword}{Plugin.Query.ActionKeywordSeparator}"); + + } return false; } } From 3bf1887362513444a45bd48e5b6c19f37056807b Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 23:56:03 +0800 Subject: [PATCH 257/545] Intoduce dependency --- .../Flow.Launcher.Plugin.Explorer.csproj | 1 + 1 file changed, 1 insertion(+) 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 93691814a..6b1fcdd0d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj @@ -47,6 +47,7 @@ + From e116668ef9223ec24d3e4f8e1b26325ea9f9d4e7 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Tue, 15 Jul 2025 23:57:21 +0800 Subject: [PATCH 258/545] Rename file --- .../Search/Everything/{SortOption.cs => EverythingSortOption.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/{SortOption.cs => EverythingSortOption.cs} (100%) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs similarity index 100% rename from Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/SortOption.cs rename to Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs From 363c0fb2a0984d7616c6fe7b496f1bef5ed7935e Mon Sep 17 00:00:00 2001 From: Kevin Zhang <45326534+taooceros@users.noreply.github.com> Date: Tue, 15 Jul 2025 18:11:16 -0500 Subject: [PATCH 259/545] Update dotnet.yml --- .github/workflows/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 7498262de..812a56257 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -16,7 +16,7 @@ jobs: runs-on: windows-latest env: - FlowVersion: 1.19.5 + FlowVersion: 1.20.2 NUGET_CERT_REVOCATION_MODE: offline BUILD_NUMBER: ${{ github.run_number }} steps: From 5ed017b026ca3638a728b46027992aab7c691e07 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:02:58 +0800 Subject: [PATCH 260/545] Revert line_forbidden.patterns --- .../actions/spelling/line_forbidden.patterns | 124 +++++++++--------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/.github/actions/spelling/line_forbidden.patterns b/.github/actions/spelling/line_forbidden.patterns index 119d89321..7341d9b73 100644 --- a/.github/actions/spelling/line_forbidden.patterns +++ b/.github/actions/spelling/line_forbidden.patterns @@ -1,62 +1,62 @@ -## reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere -## \bm_data\b -# -## If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, -## you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want -## to use this: -##\bfit\( -# -## s.b. GitHub -##\bGithub\b -# -## s.b. GitLab -#\bGitlab\b -# -## s.b. JavaScript -#\bJavascript\b -# -## s.b. Microsoft -#\bMicroSoft\b -# -## s.b. another -#\ban[- ]other\b -# -## s.b. greater than -#\bgreater then\b -# -## s.b. into -#\sin to\s -# -## s.b. opt-in -#\sopt in\s -# -## s.b. less than -#\bless then\b -# -## s.b. otherwise -#\bother[- ]wise\b -# -## s.b. nonexistent -#\bnon existing\b -#\b[Nn]o[nt][- ]existent\b -# -## s.b. preexisting -#[Pp]re[- ]existing -# -## s.b. preempt -#[Pp]re[- ]empt\b -# -## s.b. preemptively -#[Pp]re[- ]emptively -# -## s.b. reentrancy -#[Rr]e[- ]entrancy -# -## s.b. reentrant -#[Rr]e[- ]entrant -# -## s.b. workaround(s) -#\bwork[- ]arounds?\b -# -## Reject duplicate words -#\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s +# reject `m_data` as there's a certain OS which has evil defines that break things if it's used elsewhere +# \bm_data\b + +# If you have a framework that uses `it()` for testing and `fit()` for debugging a specific test, +# you might not want to check in code where you were debugging w/ `fit()`, in which case, you might want +# to use this: +#\bfit\( + +# s.b. GitHub +#\bGithub\b + +# s.b. GitLab +\bGitlab\b + +# s.b. JavaScript +\bJavascript\b + +# s.b. Microsoft +\bMicroSoft\b + +# s.b. another +\ban[- ]other\b + +# s.b. greater than +\bgreater then\b + +# s.b. into +\sin to\s + +# s.b. opt-in +\sopt in\s + +# s.b. less than +\bless then\b + +# s.b. otherwise +\bother[- ]wise\b + +# s.b. nonexistent +\bnon existing\b +\b[Nn]o[nt][- ]existent\b + +# s.b. preexisting +[Pp]re[- ]existing + +# s.b. preempt +[Pp]re[- ]empt\b + +# s.b. preemptively +[Pp]re[- ]emptively + +# s.b. reentrancy +[Rr]e[- ]entrancy + +# s.b. reentrant +[Rr]e[- ]entrant + +# s.b. workaround(s) +\bwork[- ]arounds?\b + +# Reject duplicate words +\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s From 30f7ae0d6726557bdd6d5878e240fe8817847bb6 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Wed, 16 Jul 2025 21:28:17 +0800 Subject: [PATCH 261/545] Use Localization for Explorer plugin --- .../Helper/SortOptionTranslationHelper.cs | 25 ----------- .../Languages/en.xaml | 41 ++++++++++++------- Plugins/Flow.Launcher.Plugin.Explorer/Main.cs | 2 - .../Search/Everything/EverythingAPI.cs | 7 ++-- .../Everything/EverythingApiDllImport.cs | 9 ++-- .../Everything/EverythingSearchOption.cs | 6 +-- .../Search/Everything/EverythingSortOption.cs | 32 ++++++++++++++- .../Flow.Launcher.Plugin.Explorer/Settings.cs | 8 +--- .../ViewModels/SettingsViewModel.cs | 21 ++++++++-- .../Converters/EverythingEnumNameConverter.cs | 20 --------- .../Views/ExplorerSettings.xaml | 21 +++------- .../Views/ExplorerSettings.xaml.cs | 9 +--- 12 files changed, 93 insertions(+), 108 deletions(-) delete mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs delete mode 100644 Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs deleted file mode 100644 index 72f58f5b6..000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/SortOptionTranslationHelper.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using JetBrains.Annotations; -using System; - -namespace Flow.Launcher.Plugin.Explorer.Helper; - -public static class SortOptionTranslationHelper -{ - [CanBeNull] - public static IPublicAPI API { get; internal set; } - - public static string GetTranslatedName(this SortOption sortOption) - { - const string prefix = "flowlauncher_plugin_everything_sort_by_"; - - ArgumentNullException.ThrowIfNull(API); - - var enumName = Enum.GetName(sortOption); - var splited = enumName!.Split('_'); - var name = string.Join('_', splited[..^1]); - var direction = splited[^1]; - - return $"{API.GetTranslation(prefix + name.ToLower())} {API.GetTranslation(prefix + direction.ToLower())}"; - } -} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 2e0f6a67d..6a28a5be8 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -143,20 +143,33 @@ Warning: Everything service is not running Error while querying Everything Sort By - Name - Path - Size - Extension - Type Name - Date Created - Date Modified - Attributes - File List FileName - Run Count - Date Recently Changed - Date Accessed - Date Run - + Name ↑ + Name ↓ + Path ↑ + Path ↓ + Size ↑ + Size ↓ + Extension ↑ + Extension ↓ + Type Name ↑ + Type Name ↓ + Date Created ↑ + Date Created ↓ + Date Modified ↑ + Date Modified ↓ + Attributes ↑ + Attributes ↓ + File List FileName ↑ + File List FileName ↓ + Run Count ↑ + Run Count ↓ + Date Recently Changed ↑ + Date Recently Changed ↓ + Date Accessed ↑ + Date Accessed ↓ + Date Run ↑ + Date Run ↓ + Warning: This is not a Fast Sort option, searches may be slow diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index f1aea98b4..54292d550 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -42,8 +42,6 @@ namespace Flow.Launcher.Plugin.Explorer contextMenu = new ContextMenu(Context, Settings, viewModel); searchManager = new SearchManager(Settings, Context); ResultManager.Init(Context, Settings); - - SortOptionTranslationHelper.API = context.API; EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK", Environment.Is64BitProcess ? "x64" : "x86")); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs index 6159c9355..fd62566d5 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingAPI.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; +using Flow.Launcher.Plugin.Explorer.Search.Everything.Exceptions; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; @@ -36,7 +35,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything /// /// Checks whether the sort option is Fast Sort. /// - public static bool IsFastSortOption(SortOption sortOption) + public static bool IsFastSortOption(EverythingSortOption sortOption) { var fastSortOptionEnabled = EverythingApiDllImport.Everything_IsFastSort(sortOption); @@ -112,7 +111,7 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything EverythingApiDllImport.Everything_SetSort(option.SortOption); EverythingApiDllImport.Everything_SetMatchPath(option.IsFullPathSearch); - if (option.SortOption == SortOption.RUN_COUNT_DESCENDING) + if (option.SortOption == EverythingSortOption.RUN_COUNT_DESCENDING) { EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME | EVERYTHING_REQUEST_RUN_COUNT); } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs index 5b80819fa..c952a980c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingApiDllImport.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using System; +using System; using System.IO; using System.Runtime.InteropServices; using System.Text; @@ -114,11 +113,11 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything // Everything 1.4 [DllImport(DLL)] - public static extern void Everything_SetSort(SortOption dwSortType); + public static extern void Everything_SetSort(EverythingSortOption dwSortType); [DllImport(DLL)] - public static extern bool Everything_IsFastSort(SortOption dwSortType); + public static extern bool Everything_IsFastSort(EverythingSortOption dwSortType); [DllImport(DLL)] - public static extern SortOption Everything_GetSort(); + public static extern EverythingSortOption Everything_GetSort(); [DllImport(DLL)] public static extern uint Everything_GetResultListSort(); [DllImport(DLL)] diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs index 92b8e9623..d8b670a08 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSearchOption.cs @@ -1,10 +1,8 @@ -using Flow.Launcher.Plugin.Everything.Everything; - -namespace Flow.Launcher.Plugin.Explorer.Search.Everything +namespace Flow.Launcher.Plugin.Explorer.Search.Everything { public record struct EverythingSearchOption( string Keyword, - SortOption SortOption, + EverythingSortOption SortOption, bool IsContentSearch = false, string ContentSearchKeyword = default, string ParentPath = default, diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs index 3c2fc3660..6a3d7cb67 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/Everything/EverythingSortOption.cs @@ -1,31 +1,59 @@ -namespace Flow.Launcher.Plugin.Everything.Everything +using Flow.Launcher.Localization.Attributes; + +namespace Flow.Launcher.Plugin.Explorer.Search.Everything { - public enum SortOption : uint + [EnumLocalize] + public enum EverythingSortOption : uint { + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_name_ascending))] NAME_ASCENDING = 1u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_name_descending))] NAME_DESCENDING = 2u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_path_ascending))] PATH_ASCENDING = 3u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_path_descending))] PATH_DESCENDING = 4u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_size_ascending))] SIZE_ASCENDING = 5u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_size_descending))] SIZE_DESCENDING = 6u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_extension_ascending))] EXTENSION_ASCENDING = 7u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_extension_descending))] EXTENSION_DESCENDING = 8u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_type_name_ascending))] TYPE_NAME_ASCENDING = 9u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_type_name_descending))] TYPE_NAME_DESCENDING = 10u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_created_ascending))] DATE_CREATED_ASCENDING = 11u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_created_descending))] DATE_CREATED_DESCENDING = 12u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_modified_ascending))] DATE_MODIFIED_ASCENDING = 13u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_modified_descending))] DATE_MODIFIED_DESCENDING = 14u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_attributes_ascending))] ATTRIBUTES_ASCENDING = 15u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_attributes_descending))] ATTRIBUTES_DESCENDING = 16u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_file_list_filename_ascending))] FILE_LIST_FILENAME_ASCENDING = 17u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_file_list_filename_descending))] FILE_LIST_FILENAME_DESCENDING = 18u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_run_count_descending))] RUN_COUNT_DESCENDING = 20u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_recently_changed_ascending))] DATE_RECENTLY_CHANGED_ASCENDING = 21u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_recently_changed_descending))] DATE_RECENTLY_CHANGED_DESCENDING = 22u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_accessed_ascending))] DATE_ACCESSED_ASCENDING = 23u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_accessed_descending))] DATE_ACCESSED_DESCENDING = 24u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_run_ascending))] DATE_RUN_ASCENDING = 25u, + [EnumLocalizeKey(nameof(Localize.flowlauncher_plugin_everything_sort_by_date_run_descending))] DATE_RUN_DESCENDING = 26u } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 77540f3a8..672e81d03 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -1,5 +1,4 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search; using Flow.Launcher.Plugin.Explorer.Search.Everything; using Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks; using Flow.Launcher.Plugin.Explorer.Search.WindowsIndex; @@ -145,10 +144,7 @@ namespace Flow.Launcher.Plugin.Explorer public string EverythingInstalledPath { get; set; } - [JsonIgnore] - public SortOption[] SortOptions { get; set; } = Enum.GetValues(); - - public SortOption SortOption { get; set; } = SortOption.NAME_ASCENDING; + public EverythingSortOption SortOption { get; set; } = EverythingSortOption.NAME_ASCENDING; public bool EnableEverythingContentSearch { get; set; } = false; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index 5aa6a13be..efffb19e0 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -35,6 +35,7 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels InitializeEngineSelection(); InitializeActionKeywordModels(); + EverythingSortOptionLocalized.UpdateLabels(AllEverythingSortOptions); } public void Save() @@ -578,6 +579,20 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels #region Everything FastSortWarning + public List AllEverythingSortOptions { get; } = EverythingSortOptionLocalized.GetValues(); + + public EverythingSortOption SelectedEverythingSortOption + { + get => Settings.SortOption; + set + { + Settings.SortOption = value; + OnPropertyChanged(nameof(SelectedEverythingSortOption)); + OnPropertyChanged(nameof(FastSortWarningVisibility)); + OnPropertyChanged(nameof(SortOptionWarningMessage)); + } + } + public Visibility FastSortWarningVisibility { get @@ -607,15 +622,15 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels // this method is used to determine if Everything service is running because as at Everything v1.4.1 // the sdk does not provide a dedicated interface to determine if it is running. return EverythingApi.IsFastSortOption(Settings.SortOption) ? string.Empty - : Context.API.GetTranslation("flowlauncher_plugin_everything_nonfastsort_warning"); + : Localize.flowlauncher_plugin_everything_nonfastsort_warning(); } catch (IPCErrorException) { - return Context.API.GetTranslation("flowlauncher_plugin_everything_is_not_running"); + return Localize.flowlauncher_plugin_everything_is_not_running(); } catch (DllNotFoundException) { - return Context.API.GetTranslation("flowlauncher_plugin_everything_sdk_issue"); + return Localize.flowlauncher_plugin_everything_sdk_issue(); } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs deleted file mode 100644 index e24b21dcd..000000000 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/Converters/EverythingEnumNameConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Flow.Launcher.Plugin.Everything.Everything; -using Flow.Launcher.Plugin.Explorer.Helper; -using System; -using System.Globalization; -using System.Windows.Data; - -namespace Flow.Launcher.Plugin.Explorer.Views.Converters; - -public class EnumNameConverter : IValueConverter -{ - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value is SortOption option ? option.GetTranslatedName() : value; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index 59373b4de..08abc3ba6 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -2,7 +2,6 @@ x:Class="Flow.Launcher.Plugin.Explorer.Views.ExplorerSettings" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:converters="clr-namespace:Flow.Launcher.Plugin.Explorer.Views.Converters" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:qa="clr-namespace:Flow.Launcher.Plugin.Explorer.Search.QuickAccessLinks" @@ -74,8 +73,6 @@ - - + + + + + + + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + - - - - - + + + + + +