diff --git a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs index 515b0bedcc3..9d76b6be099 100644 --- a/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs +++ b/Flow.Launcher.Core/Plugin/PluginAssemblyLoader.cs @@ -15,20 +15,6 @@ internal class PluginAssemblyLoader : AssemblyLoadContext private readonly AssemblyName assemblyName; - private static readonly ConcurrentDictionary loadedAssembly; - - static PluginAssemblyLoader() - { - var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies(); - loadedAssembly = new ConcurrentDictionary( - currentAssemblies.Select(x => new KeyValuePair(x.FullName, default))); - - AppDomain.CurrentDomain.AssemblyLoad += (sender, args) => - { - loadedAssembly[args.LoadedAssembly.FullName] = default; - }; - } - internal PluginAssemblyLoader(string assemblyFilePath) { dependencyResolver = new AssemblyDependencyResolver(assemblyFilePath); @@ -47,10 +33,9 @@ protected override Assembly Load(AssemblyName assemblyName) // When resolving dependencies, ignore assembly depenedencies that already exits with Flow.Launcher // Otherwise duplicate assembly will be loaded and some weird behavior will occur, such as WinRT.Runtime.dll // will fail due to loading multiple versions in process, each with their own static instance of registration state - if (assemblyPath == null || ExistsInReferencedPackage(assemblyName)) - return null; + var existAssembly = Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName); - return LoadFromAssemblyPath(assemblyPath); + return existAssembly ?? (assemblyPath == null ? null : LoadFromAssemblyPath(assemblyPath)); } internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, Type type) @@ -58,10 +43,5 @@ internal Type FromAssemblyGetTypeOfInterface(Assembly assembly, Type type) var allTypes = assembly.ExportedTypes; return allTypes.First(o => o.IsClass && !o.IsAbstract && o.GetInterfaces().Any(t => t == type)); } - - internal bool ExistsInReferencedPackage(AssemblyName assemblyName) - { - return loadedAssembly.ContainsKey(assemblyName.FullName); - } } } \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Image/ImageCache.cs b/Flow.Launcher.Infrastructure/Image/ImageCache.cs index 13277c7d995..04e11bf1ace 100644 --- a/Flow.Launcher.Infrastructure/Image/ImageCache.cs +++ b/Flow.Launcher.Infrastructure/Image/ImageCache.cs @@ -74,7 +74,7 @@ async void SliceExtra() // To delete the images from the data dictionary based on the resizing of the Usage Dictionary // Double Check to avoid concurrent remove if (Data.Count > permissibleFactor * MaxCached) - foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key).ToArray()) + foreach (var key in Data.OrderBy(x => x.Value.usage).Take(Data.Count - MaxCached).Select(x => x.Key)) Data.TryRemove(key, out _); semaphore.Release(); } diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs index 98327d8da5f..a3ad20f7748 100644 --- a/Flow.Launcher/Helper/HotKeyMapper.cs +++ b/Flow.Launcher/Helper/HotKeyMapper.cs @@ -25,7 +25,7 @@ internal static void Initialize(MainViewModel mainVM) internal static void OnToggleHotkey(object sender, HotkeyEventArgs args) { - if (!mainViewModel.GameModeStatus) + if (!mainViewModel.ShouldIgnoreHotkeys() && !mainViewModel.GameModeStatus) mainViewModel.ToggleFlowLauncher(); } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 4b0f4933c28..ec355a0ac11 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -176,8 +176,8 @@ Browser Browser Name Browser Path - New Window - New Tab + New Window + New Tab Private Mode diff --git a/Flow.Launcher/Languages/ko.xaml b/Flow.Launcher/Languages/ko.xaml index 59485e1f16e..7184bef34ac 100644 --- a/Flow.Launcher/Languages/ko.xaml +++ b/Flow.Launcher/Languages/ko.xaml @@ -175,8 +175,8 @@ 브라우저 브라우저 이름 브라우저 경로 - 새 창 - 새 탭 + 새 창 + 새 탭 프라이빗 모드 diff --git a/Flow.Launcher/Languages/pt-pt.xaml b/Flow.Launcher/Languages/pt-pt.xaml index b641f0e868a..764ba542bbe 100644 --- a/Flow.Launcher/Languages/pt-pt.xaml +++ b/Flow.Launcher/Languages/pt-pt.xaml @@ -176,8 +176,8 @@ Navegador Nome do navegador Caminho do navegador - Nova janela - Novo separador + Nova janela + Novo separador Modo privado diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index 385eef658a1..dac746d0f1e 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -174,8 +174,8 @@ Prehliadač Názov prehliadača Cesta k prehliadaču - Nové okno - Nová karta + Nové okno + Nová karta Privátny režim diff --git a/Flow.Launcher/ReportWindow.xaml.cs b/Flow.Launcher/ReportWindow.xaml.cs index 7318fe4cd25..6a9fd60e0b0 100644 --- a/Flow.Launcher/ReportWindow.xaml.cs +++ b/Flow.Launcher/ReportWindow.xaml.cs @@ -52,8 +52,8 @@ private Paragraph Hyperlink(string textBeforeUrl, string url) var link = new Hyperlink { IsEnabled = true }; link.Inlines.Add(url); link.NavigateUri = new Uri(url); - link.RequestNavigate += (s, e) => SearchWeb.NewTabInBrowser(e.Uri.ToString()); - link.Click += (s, e) => SearchWeb.NewTabInBrowser(url); + link.RequestNavigate += (s, e) => SearchWeb.OpenInBrowserTab(e.Uri.ToString()); + link.Click += (s, e) => SearchWeb.OpenInBrowserTab(url); paragraph.Inlines.Add(textBeforeUrl); paragraph.Inlines.Add(link); diff --git a/Flow.Launcher/SelectBrowserWindow.xaml b/Flow.Launcher/SelectBrowserWindow.xaml index 79e27e63f20..98bc391ddf6 100644 --- a/Flow.Launcher/SelectBrowserWindow.xaml +++ b/Flow.Launcher/SelectBrowserWindow.xaml @@ -196,7 +196,7 @@ VerticalAlignment="Center" Orientation="Horizontal"> + Content="{DynamicResource defaultBrowser_newTab}"> diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 338b9640615..15babee8bc7 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -232,7 +232,7 @@ private void OnPluginNameClick(object sender, MouseButtonEventArgs e) var uri = new Uri(website); if (Uri.CheckSchemeName(uri.Scheme)) { - website.NewTabInBrowser(); + website.OpenInBrowserTab(); } } } diff --git a/Flow.Launcher/ViewModel/ResultViewModel.cs b/Flow.Launcher/ViewModel/ResultViewModel.cs index 908de0c0993..4d32d792dd0 100644 --- a/Flow.Launcher/ViewModel/ResultViewModel.cs +++ b/Flow.Launcher/ViewModel/ResultViewModel.cs @@ -7,11 +7,16 @@ using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using System.IO; +using System.Drawing.Text; +using System.Collections.Generic; namespace Flow.Launcher.ViewModel { public class ResultViewModel : BaseModel { + private static PrivateFontCollection fontCollection = new(); + private static Dictionary fonts = new(); + public ResultViewModel(Result result, Settings settings) { if (result != null) @@ -23,13 +28,29 @@ public ResultViewModel(Result result, Settings settings) // Checks if it's a system installed font, which does not require path to be provided. if (glyph.FontFamily.EndsWith(".ttf") || glyph.FontFamily.EndsWith(".otf")) { - var fontPath = Result.Glyph.FontFamily; - Glyph = Path.IsPathRooted(fontPath) - ? Result.Glyph - : Result.Glyph with + string fontFamilyPath = glyph.FontFamily; + + if (!Path.IsPathRooted(fontFamilyPath)) + { + fontFamilyPath = Path.Combine(Result.PluginDirectory, fontFamilyPath); + } + + if (fonts.ContainsKey(fontFamilyPath)) + { + Glyph = glyph with + { + FontFamily = fonts[fontFamilyPath] + }; + } + else + { + fontCollection.AddFontFile(fontFamilyPath); + fonts[fontFamilyPath] = $"{Path.GetDirectoryName(fontFamilyPath)}/#{fontCollection.Families[^1].Name}"; + Glyph = glyph with { - FontFamily = Path.Combine(Result.PluginDirectory, fontPath) + FontFamily = fonts[fontFamilyPath] }; + } } else { diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 8d4177c2b66..53e994d3423 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -333,7 +333,7 @@ internal List InstallFromWeb(string url) { if (e.SpecialKeyState.CtrlPressed) { - SearchWeb.NewTabInBrowser(plugin.UrlDownload); + SearchWeb.OpenInBrowserTab(plugin.UrlDownload); return ShouldHideWindow; } @@ -397,7 +397,7 @@ internal async ValueTask> RequestInstallOrUpdate(string searchName, { if (e.SpecialKeyState.CtrlPressed) { - SearchWeb.NewTabInBrowser(x.Website); + SearchWeb.OpenInBrowserTab(x.Website); return ShouldHideWindow; } diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs index 31d56c1085e..2ed41213008 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/Main.cs @@ -41,8 +41,8 @@ public async Task> QueryAsync(Query query, CancellationToken token) var results = new List(); foreach (SearchSource searchSource in _settings.SearchSources.Where(o => (o.ActionKeyword == query.ActionKeyword || - o.ActionKeyword == SearchSourceGlobalPluginWildCardSign) - && o.Enabled)) + o.ActionKeyword == SearchSourceGlobalPluginWildCardSign) + && o.Enabled)) { string keyword = string.Empty; keyword = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? query.ToString() : query.Search; @@ -105,11 +105,11 @@ private async Task UpdateResultsFromSuggestionAsync(List results, string if (_settings.EnableSuggestion) { var suggestions = await SuggestionsAsync(keyword, subtitle, searchSource, token).ConfigureAwait(false); - if (token.IsCancellationRequested || !suggestions.Any()) + var enumerable = suggestions?.ToList(); + if (token.IsCancellationRequested || enumerable is not { Count: > 0 }) return; - - - results.AddRange(suggestions); + + results.AddRange(enumerable); token.ThrowIfCancellationRequested(); } @@ -118,32 +118,32 @@ private async Task UpdateResultsFromSuggestionAsync(List results, string private async Task> SuggestionsAsync(string keyword, string subtitle, SearchSource searchSource, CancellationToken token) { var source = _settings.SelectedSuggestion; - if (source != null) + if (source == null) { - //Suggestions appear below actual result, and appear above global action keyword match if non-global; - var score = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? scoreSuggestions : scoreSuggestions + 1; + return new List(); + } + //Suggestions appear below actual result, and appear above global action keyword match if non-global; + var score = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? scoreSuggestions : scoreSuggestions + 1; - var suggestions = await source.Suggestions(keyword, token).ConfigureAwait(false); + var suggestions = await source.SuggestionsAsync(keyword, token).ConfigureAwait(false); - token.ThrowIfCancellationRequested(); + token.ThrowIfCancellationRequested(); - var resultsFromSuggestion = suggestions?.Select(o => new Result + var resultsFromSuggestion = suggestions?.Select(o => new Result + { + Title = o, + SubTitle = subtitle, + Score = score, + IcoPath = searchSource.IconPath, + ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, + Action = c => { - Title = o, - SubTitle = subtitle, - Score = score, - IcoPath = searchSource.IconPath, - ActionKeywordAssigned = searchSource.ActionKeyword == SearchSourceGlobalPluginWildCardSign ? string.Empty : searchSource.ActionKeyword, - Action = c => - { - _context.API.OpenUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(o))); + _context.API.OpenUrl(searchSource.Url.Replace("{q}", Uri.EscapeDataString(o))); - return true; - } - }); - return resultsFromSuggestion; - } - return new List(); + return true; + } + }); + return resultsFromSuggestion; } public Task InitAsync(PluginInitContext context) @@ -191,4 +191,4 @@ public string GetTranslatedPluginDescription() public event ResultUpdatedEventHandler ResultsUpdated; } -} +} \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs index ccb5b20d730..d1fbd4ac5ed 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Baidu.cs @@ -16,7 +16,7 @@ public class Baidu : SuggestionSource { private readonly Regex _reg = new Regex("window.baidu.sug\\((.*)\\)"); - public override async Task> Suggestions(string query, CancellationToken token) + public override async Task> SuggestionsAsync(string query, CancellationToken token) { string result; @@ -25,7 +25,7 @@ public override async Task> Suggestions(string query, CancellationT const string api = "http://suggestion.baidu.com/su?json=1&wd="; result = await Http.GetAsync(api + Uri.EscapeUriString(query), token).ConfigureAwait(false); } - catch (Exception e) when (e is HttpRequestException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return null; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs index 38c5fb4a0f8..971fc079cf1 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Bing.cs @@ -15,7 +15,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { class Bing : SuggestionSource { - public override async Task> Suggestions(string query, CancellationToken token) + public override async Task> SuggestionsAsync(string query, CancellationToken token) { try @@ -40,7 +40,7 @@ public override async Task> Suggestions(string query, CancellationT } - catch (Exception e) when (e is HttpRequestException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return null; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs index c5f43d081be..a6c18b1ef2b 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/Google.cs @@ -14,7 +14,7 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public class Google : SuggestionSource { - public override async Task> Suggestions(string query, CancellationToken token) + public override async Task> SuggestionsAsync(string query, CancellationToken token) { try { @@ -32,7 +32,7 @@ public override async Task> Suggestions(string query, CancellationT return results.EnumerateArray().Select(o => o.GetString()).ToList(); } - catch (Exception e) when (e is HttpRequestException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or {InnerException: TimeoutException}) { Log.Exception("|Baidu.Suggestions|Can't get suggestion from baidu", e); return null; diff --git a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs index c58e61141ef..e89addee989 100644 --- a/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs +++ b/Plugins/Flow.Launcher.Plugin.WebSearch/SuggestionSources/SuggestionSource.cs @@ -6,6 +6,6 @@ namespace Flow.Launcher.Plugin.WebSearch.SuggestionSources { public abstract class SuggestionSource { - public abstract Task> Suggestions(string query, CancellationToken token); + public abstract Task> SuggestionsAsync(string query, CancellationToken token); } } diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs index 3005567c48d..c693331e900 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/Helper/ResultHelper.cs @@ -34,8 +34,9 @@ internal static List GetResultList( var resultList = new List(); foreach (var entry in list) { - const int highScore = 20; - const int midScore = 10; + // Adjust the score to lower the order of many irrelevant matches from area strings + // that may only be for description. + const int nonNameMatchScoreAdj = 10; Result? result; Debug.Assert(_api != null, nameof(_api) + " != null"); @@ -44,7 +45,7 @@ internal static List GetResultList( if (nameMatch.IsSearchPrecisionScoreMet()) { - var settingResult = NewSettingResult(nameMatch.Score + highScore, entry.Type); + var settingResult = NewSettingResult(nameMatch.Score, entry.Type); settingResult.TitleHighlightData = nameMatch.MatchData; result = settingResult; } @@ -53,7 +54,7 @@ internal static List GetResultList( var areaMatch = _api.FuzzySearch(query.Search, entry.Area); if (areaMatch.IsSearchPrecisionScoreMet()) { - var settingResult = NewSettingResult(areaMatch.Score + midScore, entry.Type); + var settingResult = NewSettingResult(areaMatch.Score - nonNameMatchScoreAdj, entry.Type); result = settingResult; } else @@ -61,7 +62,7 @@ internal static List GetResultList( result = entry.AltNames? .Select(altName => _api.FuzzySearch(query.Search, altName)) .Where(match => match.IsSearchPrecisionScoreMet()) - .Select(altNameMatch => NewSettingResult(altNameMatch.Score + midScore, entry.Type)) + .Select(altNameMatch => NewSettingResult(altNameMatch.Score - nonNameMatchScoreAdj, entry.Type)) .FirstOrDefault(); } @@ -75,7 +76,7 @@ internal static List GetResultList( .SelectMany(x => x) .Contains(x, StringComparer.CurrentCultureIgnoreCase)) ) - result = NewSettingResult(midScore, entry.Type); + result = NewSettingResult(nonNameMatchScoreAdj, entry.Type); } } @@ -115,7 +116,7 @@ private static string GetSubtitle(string section, string entryType) private static void AddOptionalToolTip(WindowsSetting entry, Result result) { var toolTipText = new StringBuilder(); - + var settingType = entry.Type == "AppSettingsApp" ? "System settings" : "Control Panel"; toolTipText.AppendLine($"{Resources.Application}: {settingType}"); diff --git a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json index f5211e9da79..61336db6750 100644 --- a/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json +++ b/Plugins/Flow.Launcher.Plugin.WindowsSettings/plugin.json @@ -4,7 +4,7 @@ "Description": "Search settings inside Control Panel and Settings App", "Name": "Windows Settings", "Author": "TobiasSekan", - "Version": "2.0.1", + "Version": "2.0.2", "Language": "csharp", "Website": "https://github.com/Flow-Launcher/Flow.Launcher", "ExecuteFileName": "Flow.Launcher.Plugin.WindowsSettings.dll", diff --git a/appveyor.yml b/appveyor.yml index df9f4e6683b..ea1dcb22acc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.9.2.{build}' +version: '1.9.3.{build}' init: - ps: |