diff --git a/Flow.Launcher.Core/Plugin/QueryBuilder.cs b/Flow.Launcher.Core/Plugin/QueryBuilder.cs index df336e14b..ef387b693 100644 --- a/Flow.Launcher.Core/Plugin/QueryBuilder.cs +++ b/Flow.Launcher.Core/Plugin/QueryBuilder.cs @@ -10,35 +10,31 @@ namespace Flow.Launcher.Core.Plugin public static Query Build(string text, Dictionary nonGlobalPlugins) { // replace multiple white spaces with one white space - var terms = text.Split(new[] { Query.TermSeperater }, StringSplitOptions.RemoveEmptyEntries); + var terms = text.Split(Query.TermSeparator, StringSplitOptions.RemoveEmptyEntries); if (terms.Length == 0) { // nothing was typed return null; } - var rawQuery = string.Join(Query.TermSeperater, terms); + var rawQuery = string.Join(Query.TermSeparator, terms); string actionKeyword, search; string possibleActionKeyword = terms[0]; - List actionParameters; + string[] searchTerms; + if (nonGlobalPlugins.TryGetValue(possibleActionKeyword, out var pluginPair) && !pluginPair.Metadata.Disabled) { // use non global plugin for query actionKeyword = possibleActionKeyword; - actionParameters = terms.Skip(1).ToList(); - search = actionParameters.Count > 0 ? rawQuery.Substring(actionKeyword.Length + 1) : string.Empty; + search = terms.Length > 1 ? rawQuery[(actionKeyword.Length + 1)..] : string.Empty; + searchTerms = terms[1..]; } else { // non action keyword actionKeyword = string.Empty; search = rawQuery; + searchTerms = terms; } - var query = new Query - { - Terms = terms, - RawQuery = rawQuery, - ActionKeyword = actionKeyword, - Search = search - }; + var query = new Query(rawQuery, search,terms, searchTerms, actionKeyword); return query; } diff --git a/Flow.Launcher.Core/Resource/Theme.cs b/Flow.Launcher.Core/Resource/Theme.cs index e70de673e..4648aef63 100644 --- a/Flow.Launcher.Core/Resource/Theme.cs +++ b/Flow.Launcher.Core/Resource/Theme.cs @@ -145,11 +145,9 @@ namespace Flow.Launcher.Core.Resource public ResourceDictionary GetResourceDictionary() { var dict = CurrentThemeResourceDictionary(); - - Style queryBoxStyle = dict["QueryBoxStyle"] as Style; - Style querySuggestionBoxStyle = dict["QuerySuggestionBoxStyle"] as Style; - - if (queryBoxStyle != null && querySuggestionBoxStyle != null) + + if (dict["QueryBoxStyle"] is Style queryBoxStyle && + dict["QuerySuggestionBoxStyle"] is Style querySuggestionBoxStyle) { var fontFamily = new FontFamily(Settings.QueryBoxFont); var fontStyle = FontHelper.GetFontStyleFromInvariantStringOrNormal(Settings.QueryBoxFontStyle); @@ -174,11 +172,12 @@ namespace Flow.Launcher.Core.Resource querySuggestionBoxStyle.Setters.Add(new Setter(TextBox.FontStretchProperty, fontStretch)); } - Style resultItemStyle = dict["ItemTitleStyle"] as Style; - Style resultSubItemStyle = dict["ItemSubTitleStyle"] as Style; - Style resultItemSelectedStyle = dict["ItemTitleSelectedStyle"] as Style; - Style resultSubItemSelectedStyle = dict["ItemSubTitleSelectedStyle"] as Style; - if (resultItemStyle != null && resultSubItemStyle != null && resultSubItemSelectedStyle != null && resultItemSelectedStyle != null) + if (dict["ItemTitleStyle"] is Style resultItemStyle && + dict["ItemSubTitleStyle"] is Style resultSubItemStyle && + dict["ItemSubTitleSelectedStyle"] is Style resultSubItemSelectedStyle && + dict["ItemTitleSelectedStyle"] is Style resultItemSelectedStyle && + dict["ItemHotkeyStyle"] is Style resultHotkeyItemStyle && + dict["ItemHotkeySelectedStyle"] is Style resultHotkeyItemSelectedStyle) { Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(Settings.ResultFont)); Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(Settings.ResultFontStyle)); @@ -186,7 +185,9 @@ namespace Flow.Launcher.Core.Resource Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(Settings.ResultFontStretch)); Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; - Array.ForEach(new[] { resultItemStyle, resultSubItemStyle, resultItemSelectedStyle, resultSubItemSelectedStyle }, o => Array.ForEach(setters, p => o.Setters.Add(p))); + Array.ForEach( + new[] { resultItemStyle, resultSubItemStyle, resultItemSelectedStyle, resultSubItemSelectedStyle, resultHotkeyItemStyle, resultHotkeyItemSelectedStyle }, o + => Array.ForEach(setters, p => o.Setters.Add(p))); } var windowStyle = dict["WindowStyle"] as Style; @@ -236,17 +237,19 @@ namespace Flow.Launcher.Core.Resource public void AddDropShadowEffectToCurrentTheme() { - var dict = CurrentThemeResourceDictionary(); + var dict = GetResourceDictionary(); var windowBorderStyle = dict["WindowBorderStyle"] as Style; - var effectSetter = new Setter(); - effectSetter.Property = Border.EffectProperty; - effectSetter.Value = new DropShadowEffect + var effectSetter = new Setter { - Opacity = 0.9, - ShadowDepth = 2, - BlurRadius = 15 + Property = Border.EffectProperty, + Value = new DropShadowEffect + { + Opacity = 0.4, + ShadowDepth = 2, + BlurRadius = 15 + } }; var marginSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) as Setter; @@ -261,7 +264,7 @@ namespace Flow.Launcher.Core.Resource } else { - var baseMargin = (Thickness) marginSetter.Value; + var baseMargin = (Thickness)marginSetter.Value; var newMargin = new Thickness( baseMargin.Left + ShadowExtraMargin, baseMargin.Top + ShadowExtraMargin, @@ -282,8 +285,8 @@ namespace Flow.Launcher.Core.Resource var effectSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.EffectProperty) as Setter; var marginSetter = windowBorderStyle.Setters.FirstOrDefault(setterBase => setterBase is Setter setter && setter.Property == Border.MarginProperty) as Setter; - - if(effectSetter != null) + + if (effectSetter != null) { windowBorderStyle.Setters.Remove(effectSetter); } @@ -371,11 +374,11 @@ namespace Flow.Launcher.Core.Resource private void SetWindowAccent(Window w, AccentState state) { var windowHelper = new WindowInteropHelper(w); - + // this determines the width of the main query window w.Width = mainWindowWidth; windowHelper.EnsureHandle(); - + var accent = new AccentPolicy { AccentState = state }; var accentStructSize = Marshal.SizeOf(accent); diff --git a/Flow.Launcher.Core/Updater.cs b/Flow.Launcher.Core/Updater.cs index 76713ce2a..e09c6380c 100644 --- a/Flow.Launcher.Core/Updater.cs +++ b/Flow.Launcher.Core/Updater.cs @@ -16,6 +16,7 @@ using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using System.Text.Json.Serialization; +using System.Threading; namespace Flow.Launcher.Core { @@ -28,21 +29,21 @@ namespace Flow.Launcher.Core GitHubRepository = gitHubRepository; } - public async Task UpdateApp(IPublicAPI api, bool silentUpdate = true) + private SemaphoreSlim UpdateLock { get; } = new SemaphoreSlim(1); + + public async Task UpdateAppAsync(IPublicAPI api, bool silentUpdate = true) { + await UpdateLock.WaitAsync(); try { - UpdateInfo newUpdateInfo; - if (!silentUpdate) api.ShowMsg(api.GetTranslation("pleaseWait"), - api.GetTranslation("update_flowlauncher_update_check")); + api.GetTranslation("update_flowlauncher_update_check")); using var updateManager = await GitHubUpdateManager(GitHubRepository).ConfigureAwait(false); - // UpdateApp CheckForUpdate will return value only if the app is squirrel installed - newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false); + var newUpdateInfo = await updateManager.CheckForUpdate().NonNull().ConfigureAwait(false); var newReleaseVersion = Version.Parse(newUpdateInfo.FutureReleaseEntry.Version.ToString()); var currentVersion = Version.Parse(Constant.Version); @@ -58,7 +59,7 @@ namespace Flow.Launcher.Core if (!silentUpdate) api.ShowMsg(api.GetTranslation("update_flowlauncher_update_found"), - api.GetTranslation("update_flowlauncher_updating")); + api.GetTranslation("update_flowlauncher_updating")); await updateManager.DownloadReleases(newUpdateInfo.ReleasesToApply).ConfigureAwait(false); @@ -70,8 +71,8 @@ namespace Flow.Launcher.Core FilesFolders.CopyAll(DataLocation.PortableDataPath, targetDestination); if (!FilesFolders.VerifyBothFolderFilesEqual(DataLocation.PortableDataPath, targetDestination)) MessageBox.Show(string.Format(api.GetTranslation("update_flowlauncher_fail_moving_portable_user_profile_data"), - DataLocation.PortableDataPath, - targetDestination)); + DataLocation.PortableDataPath, + targetDestination)); } else { @@ -87,12 +88,15 @@ namespace Flow.Launcher.Core UpdateManager.RestartApp(Constant.ApplicationFileName); } } - catch (Exception e) when (e is HttpRequestException || e is WebException || e is SocketException || e.InnerException is TimeoutException) + catch (Exception e) when (e is HttpRequestException or WebException or SocketException || e.InnerException is TimeoutException) { Log.Exception($"|Updater.UpdateApp|Check your connection and proxy settings to github-cloud.s3.amazonaws.com.", e); api.ShowMsg(api.GetTranslation("update_flowlauncher_fail"), - api.GetTranslation("update_flowlauncher_check_connection")); - return; + api.GetTranslation("update_flowlauncher_check_connection")); + } + finally + { + UpdateLock.Release(); } } @@ -115,13 +119,16 @@ namespace Flow.Launcher.Core var uri = new Uri(repository); var api = $"https://api.github.com/repos{uri.AbsolutePath}/releases"; - var jsonStream = await Http.GetStreamAsync(api).ConfigureAwait(false); + 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 latestUrl = latest.HtmlUrl.Replace("/tag/", "/download/"); - - var client = new WebClient { Proxy = Http.WebProxy }; + + var client = new WebClient + { + Proxy = Http.WebProxy + }; var downloader = new FileDownloader(client); var manager = new UpdateManager(latestUrl, urlDownloader: downloader); diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index ebef2c631..907314ba8 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -32,6 +32,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings public string ResultFontStyle { get; set; } public string ResultFontWeight { get; set; } public string ResultFontStretch { get; set; } + public bool UseGlyphIcons { get; set; } = true; /// diff --git a/Flow.Launcher.Plugin/Query.cs b/Flow.Launcher.Plugin/Query.cs index 1eb5c9c14..3fcf3c1d7 100644 --- a/Flow.Launcher.Plugin/Query.cs +++ b/Flow.Launcher.Plugin/Query.cs @@ -1,4 +1,5 @@ -using System; +using JetBrains.Annotations; +using System; using System.Collections.Generic; using System.Linq; @@ -11,11 +12,12 @@ namespace Flow.Launcher.Plugin /// /// to allow unit tests for plug ins /// - public Query(string rawQuery, string search, string[] terms, string actionKeyword = "") + public Query(string rawQuery, string search, string[] terms, string[] searchTerms, string actionKeyword = "") { Search = search; RawQuery = rawQuery; Terms = terms; + SearchTerms = searchTerms; ActionKeyword = actionKeyword; } @@ -23,7 +25,7 @@ namespace Flow.Launcher.Plugin /// Raw query, this includes action keyword if it has /// We didn't recommend use this property directly. You should always use Search property. /// - public string RawQuery { get; internal set; } + public string RawQuery { get; internal init; } /// /// Search part of a query. @@ -31,45 +33,53 @@ namespace Flow.Launcher.Plugin /// Since we allow user to switch a exclusive plugin to generic plugin, /// so this property will always give you the "real" query part of the query /// - public string Search { get; internal set; } + public string Search { get; internal init; } /// - /// The raw query splited into a string array. + /// The search string split into a string array. /// - public string[] Terms { get; set; } + public string[] SearchTerms { get; init; } + + /// + /// The raw query split into a string array + /// + [Obsolete("It may or may not include action keyword, which can be confusing. Use SearchTerms instead")] + public string[] Terms { get; init; } /// /// Query can be splited into multiple terms by whitespace /// - public const string TermSeperater = " "; + public const string TermSeparator = " "; + + [Obsolete("Typo")] + public const string TermSeperater = TermSeparator; /// /// User can set multiple action keywords seperated by ';' /// - public const string ActionKeywordSeperater = ";"; + public const string ActionKeywordSeparator = ";"; + + [Obsolete("Typo")] + public const string ActionKeywordSeperater = ActionKeywordSeparator; + /// /// '*' is used for System Plugin /// public const string GlobalPluginWildcardSign = "*"; - public string ActionKeyword { get; set; } + public string ActionKeyword { get; init; } /// /// Return first search split by space if it has /// public string FirstSearch => SplitSearch(0); + private string _secondToEndSearch; + /// /// strings from second search (including) to last search /// - public string SecondToEndSearch - { - get - { - var index = string.IsNullOrEmpty(ActionKeyword) ? 1 : 2; - return string.Join(TermSeperater, Terms.Skip(index).ToArray()); - } - } + public string SecondToEndSearch => SearchTerms.Length > 1 ? (_secondToEndSearch ??= string.Join(' ', SearchTerms[1..])) : ""; /// /// Return second search split by space if it has @@ -83,16 +93,9 @@ namespace Flow.Launcher.Plugin private string SplitSearch(int index) { - try - { - return string.IsNullOrEmpty(ActionKeyword) ? Terms[index] : Terms[index + 1]; - } - catch (IndexOutOfRangeException) - { - return string.Empty; - } + return index < SearchTerms.Length ? SearchTerms[index] : string.Empty; } public override string ToString() => RawQuery; } -} +} \ No newline at end of file diff --git a/Flow.Launcher/ActionKeywords.xaml.cs b/Flow.Launcher/ActionKeywords.xaml.cs index 4a2368347..281be6e52 100644 --- a/Flow.Launcher/ActionKeywords.xaml.cs +++ b/Flow.Launcher/ActionKeywords.xaml.cs @@ -30,7 +30,7 @@ namespace Flow.Launcher private void ActionKeyword_OnLoaded(object sender, RoutedEventArgs e) { - tbOldActionKeyword.Text = string.Join(Query.ActionKeywordSeperater, plugin.Metadata.ActionKeywords.ToArray()); + tbOldActionKeyword.Text = string.Join(Query.ActionKeywordSeparator, plugin.Metadata.ActionKeywords.ToArray()); tbAction.Focus(); } diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index c2a32100d..8c869e941 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -129,12 +129,12 @@ namespace Flow.Launcher var timer = new Timer(1000 * 60 * 60 * 5); timer.Elapsed += async (s, e) => { - await _updater.UpdateApp(API); + await _updater.UpdateAppAsync(API); }; timer.Start(); // check updates on startup - await _updater.UpdateApp(API); + await _updater.UpdateAppAsync(API); } }); } diff --git a/Flow.Launcher/Converters/BorderClipConverter.cs b/Flow.Launcher/Converters/BorderClipConverter.cs new file mode 100644 index 000000000..83e83f1de --- /dev/null +++ b/Flow.Launcher/Converters/BorderClipConverter.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Data; +using System.Windows.Media; +using System.Windows.Documents; +using System.Windows.Shapes; + +// For Clipping inside listbox item + +namespace Flow.Launcher.Converters +{ + public class BorderClipConverter : IMultiValueConverter + { + public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) + { + if (values.Length == 3 && values[0] is double && values[1] is double && values[2] is CornerRadius) + { + var width = (double)values[0]; + var height = (double)values[1]; + Path myPath = new Path(); + if (width < Double.Epsilon || height < Double.Epsilon) + { + return Geometry.Empty; + } + var radius = (CornerRadius)values[2]; + var radiusHeight = radius.TopLeft; + + // Drawing Round box for bottom round, and rect for top area of listbox. + var corner = new RectangleGeometry(new Rect(0, 0, width, height), radius.TopLeft, radius.TopLeft); + var box = new RectangleGeometry(new Rect(0, 0, width, radiusHeight), 0, 0); + + GeometryGroup myGeometryGroup = new GeometryGroup(); + myGeometryGroup.Children.Add(corner); + myGeometryGroup.Children.Add(box); + + CombinedGeometry c1 = new CombinedGeometry(GeometryCombineMode.Union, corner, box); + myPath.Data = c1; + + myPath.Data.Freeze(); + return myPath.Data; + } + + return DependencyProperty.UnsetValue; + } + + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + } + +} diff --git a/Flow.Launcher/Converters/HighlightTextConverter.cs b/Flow.Launcher/Converters/HighlightTextConverter.cs index 006e52320..972dd1bc8 100644 --- a/Flow.Launcher/Converters/HighlightTextConverter.cs +++ b/Flow.Launcher/Converters/HighlightTextConverter.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Data; +using System.Windows.Media; using System.Windows.Documents; namespace Flow.Launcher.Converters @@ -30,7 +31,9 @@ namespace Flow.Launcher.Converters var currentCharacter = text.Substring(i, 1); if (this.ShouldHighlight(highlightData, i)) { - textBlock.Inlines.Add(new Bold(new Run(currentCharacter))); + + textBlock.Inlines.Add(new Run(currentCharacter) { Style = (Style)Application.Current.FindResource("HighlightStyle") }); + } else { diff --git a/Flow.Launcher/Converters/OpenResultHotkeyVisibilityConverter.cs b/Flow.Launcher/Converters/OpenResultHotkeyVisibilityConverter.cs index 7de5af79a..e82fa959c 100644 --- a/Flow.Launcher/Converters/OpenResultHotkeyVisibilityConverter.cs +++ b/Flow.Launcher/Converters/OpenResultHotkeyVisibilityConverter.cs @@ -16,12 +16,10 @@ namespace Flow.Launcher.Converters public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var hotkeyNumber = int.MaxValue; - - if (value is ListBoxItem listBoxItem) - { - ListBox listBox = ItemsControl.ItemsControlFromItemContainer(listBoxItem) as ListBox; + + if (value is ListBoxItem listBoxItem + && ItemsControl.ItemsControlFromItemContainer(listBoxItem) is ListBox listBox) hotkeyNumber = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1; - } return hotkeyNumber <= MaxVisibleHotkeys ? Visibility.Visible : Visibility.Collapsed; } diff --git a/Flow.Launcher/Converters/OrdinalConverter.cs b/Flow.Launcher/Converters/OrdinalConverter.cs index 970ed183c..f9fa220e3 100644 --- a/Flow.Launcher/Converters/OrdinalConverter.cs +++ b/Flow.Launcher/Converters/OrdinalConverter.cs @@ -8,11 +8,9 @@ namespace Flow.Launcher.Converters { public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture) { - if (value is ListBoxItem listBoxItem) - { - ListBox listBox = ItemsControl.ItemsControlFromItemContainer(listBoxItem) as ListBox; + if (value is ListBoxItem listBoxItem + && ItemsControl.ItemsControlFromItemContainer(listBoxItem) is ListBox listBox) return listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem) + 1; - } return 0; } diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 529fc52a2..edf41e193 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -77,6 +77,9 @@ Designer PreserveNewest + + PreserveNewest + diff --git a/Flow.Launcher/Helper/HotKeyMapper.cs b/Flow.Launcher/Helper/HotKeyMapper.cs index d5fcabace..fe25ecf18 100644 --- a/Flow.Launcher/Helper/HotKeyMapper.cs +++ b/Flow.Launcher/Helper/HotKeyMapper.cs @@ -6,6 +6,8 @@ using NHotkey.Wpf; using Flow.Launcher.Core.Resource; using System.Windows; using Flow.Launcher.ViewModel; +using System.Threading.Tasks; +using System.Threading; namespace Flow.Launcher.Helper { @@ -19,10 +21,15 @@ namespace Flow.Launcher.Helper mainViewModel = mainVM; settings = mainViewModel._settings; - SetHotkey(settings.Hotkey, OnHotkey); + SetHotkey(settings.Hotkey, OnToggleHotkey); LoadCustomPluginHotkey(); } + internal static void OnToggleHotkey(object sender, HotkeyEventArgs args) + { + mainViewModel.ToggleFlowLauncher(); + } + private static void SetHotkey(string hotkeyStr, EventHandler action) { var hotkey = new HotkeyModel(hotkeyStr); @@ -53,44 +60,6 @@ namespace Flow.Launcher.Helper } } - internal static void OnHotkey(object sender, HotkeyEventArgs e) - { - if (!ShouldIgnoreHotkeys()) - { - UpdateLastQUeryMode(); - - mainViewModel.ToggleFlowLauncher(); - e.Handled = true; - } - } - - /// - /// Checks if Flow Launcher should ignore any hotkeys - /// - private static bool ShouldIgnoreHotkeys() - { - return settings.IgnoreHotkeysOnFullscreen && WindowsInteropHelper.IsWindowFullscreen(); - } - - private static void UpdateLastQUeryMode() - { - switch(settings.LastQueryMode) - { - case LastQueryMode.Empty: - mainViewModel.ChangeQueryText(string.Empty); - break; - case LastQueryMode.Preserved: - mainViewModel.LastQuerySelected = true; - break; - case LastQueryMode.Selected: - mainViewModel.LastQuerySelected = false; - break; - default: - throw new ArgumentException($"wrong LastQueryMode: <{settings.LastQueryMode}>"); - - } - } - internal static void LoadCustomPluginHotkey() { if (settings.CustomPluginHotkeys == null) @@ -106,11 +75,11 @@ namespace Flow.Launcher.Helper { SetHotkey(hotkey.Hotkey, (s, e) => { - if (ShouldIgnoreHotkeys()) + if (mainViewModel.ShouldIgnoreHotkeys()) return; mainViewModel.MainWindowVisibility = Visibility.Visible; - mainViewModel.ChangeQueryText(hotkey.ActionKeyword); + mainViewModel.ChangeQueryText(hotkey.ActionKeyword, true); }); } diff --git a/Flow.Launcher/HotkeyControl.xaml b/Flow.Launcher/HotkeyControl.xaml index e732cbe97..ab786fd56 100644 --- a/Flow.Launcher/HotkeyControl.xaml +++ b/Flow.Launcher/HotkeyControl.xaml @@ -9,11 +9,11 @@ d:DesignHeight="300" d:DesignWidth="300"> - + - - + + \ No newline at end of file diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 90a920e3e..4a9b92700 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -38,7 +38,7 @@ Hide tray icon Query Search Precision Should Use Pinyin - Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for transliterating Chinese + Allows using Pinyin to search. Pinyin is the standard system of romanized spelling for translating Chinese Shadow effect is not allowed while current theme has blur effect enabled @@ -81,8 +81,9 @@ Please select an item Are you sure you want to delete {0} plugin hotkey? Query window shadow effect - Shadow effect has a substantial usage of GPU. - Not recommended if your computer performance is limited. + Shadow effect has a substantial usage of GPU. Not recommended if your computer performance is limited. + Use Segoe Fluent Icons + Use Segoe Fluent Icons for query results where supported HTTP Proxy diff --git a/Flow.Launcher/Languages/sk.xaml b/Flow.Launcher/Languages/sk.xaml index 346c70837..b766ccfa2 100644 --- a/Flow.Launcher/Languages/sk.xaml +++ b/Flow.Launcher/Languages/sk.xaml @@ -81,8 +81,9 @@ Vyberte položku, prosím Ste si istý, že chcete odstrániť klávesovú skratku {0} pre plugin? Tieňový efekt v poli vyhľadávania - Tieňový efekt významne využíva GPU. - Neodporúča sa, ak je výkon počítača obmedzený. + Tieňový efekt významne využíva GPU. Neodporúča sa, ak je výkon počítača obmedzený. + Použiť ikony Segoe Fluent + Použiť ikony Segoe Fluent, ak sú podporované HTTP Proxy @@ -179,4 +180,4 @@ Aktualizovať súbory Aktualizovať popis - \ No newline at end of file + diff --git a/Flow.Launcher/Languages/zh-cn.xaml b/Flow.Launcher/Languages/zh-cn.xaml index efc7f19d9..0c2307dc5 100644 --- a/Flow.Launcher/Languages/zh-cn.xaml +++ b/Flow.Launcher/Languages/zh-cn.xaml @@ -76,8 +76,7 @@ 请选择一项 你确定要删除插件 {0} 的热键吗? 查询窗口阴影效果 - 阴影效果将占用大量的GPU资源。 - 如果您的计算机性能有限,则不建议使用。 + 阴影效果将占用大量的GPU资源。 如果您的计算机性能有限,则不建议使用。 HTTP 代理 diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 83cc016bb..73b13be8c 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -30,6 +30,7 @@ d:DataContext="{d:DesignInstance vm:MainViewModel}"> + @@ -45,6 +46,8 @@ + + @@ -62,13 +65,12 @@ - + + IsEnabled="False"> @@ -82,34 +84,67 @@ PreviewDragOver="OnPreviewDragOver" AllowDrop="True" Visibility="Visible" - Background="Transparent" - Margin="18,0,56,0"> + Background="Transparent"> - + + - + + + - + + - - - - - - - - - - + Y1="0" Y2="0" X1="-150" X2="-50" Height="2" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}},Path=ActualWidth}" StrokeThickness="1"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 7521c65d2..057c3f07d 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -207,9 +207,9 @@ namespace Flow.Launcher private void InitProgressbarAnimation() { - var da = new DoubleAnimation(ProgressBar.X2, ActualWidth + 100, + var da = new DoubleAnimation(ProgressBar.X2, ActualWidth + 150, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); - var da1 = new DoubleAnimation(ProgressBar.X1, ActualWidth, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); + var da1 = new DoubleAnimation(ProgressBar.X1, ActualWidth + 50, new Duration(new TimeSpan(0, 0, 0, 0, 1600))); Storyboard.SetTargetProperty(da, new PropertyPath("(Line.X2)")); Storyboard.SetTargetProperty(da1, new PropertyPath("(Line.X1)")); _progressBarStoryboard.Children.Add(da); @@ -262,7 +262,7 @@ namespace Flow.Launcher { if (_settings.HideWhenDeactive) { - Hide(); + _viewModel.Hide(); } } @@ -313,25 +313,43 @@ namespace Flow.Launcher /// private void OnKeyDown(object sender, KeyEventArgs e) { - if (e.Key == Key.Down) + switch (e.Key) { - _viewModel.SelectNextItemCommand.Execute(null); - e.Handled = true; - } - else if (e.Key == Key.Up) - { - _viewModel.SelectPrevItemCommand.Execute(null); - e.Handled = true; - } - else if (e.Key == Key.PageDown) - { - _viewModel.SelectNextPageCommand.Execute(null); - e.Handled = true; - } - else if (e.Key == Key.PageUp) - { - _viewModel.SelectPrevPageCommand.Execute(null); - e.Handled = true; + case Key.Down: + _viewModel.SelectNextItemCommand.Execute(null); + e.Handled = true; + break; + case Key.Up: + _viewModel.SelectPrevItemCommand.Execute(null); + e.Handled = true; + break; + case Key.PageDown: + _viewModel.SelectNextPageCommand.Execute(null); + e.Handled = true; + break; + case Key.PageUp: + _viewModel.SelectPrevPageCommand.Execute(null); + e.Handled = true; + break; + case Key.Right: + if (_viewModel.SelectedIsFromQueryResults() + && QueryTextBox.CaretIndex == QueryTextBox.Text.Length + && !string.IsNullOrEmpty(QueryTextBox.Text)) + { + _viewModel.LoadContextMenuCommand.Execute(null); + e.Handled = true; + } + break; + case Key.Left: + if (!_viewModel.SelectedIsFromQueryResults() && QueryTextBox.CaretIndex == 0) + { + _viewModel.EscCommand.Execute(null); + e.Handled = true; + } + break; + default: + break; + } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index f7c91e96f..be778d798 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -48,12 +48,7 @@ namespace Flow.Launcher public void ChangeQuery(string query, bool requery = false) { - _mainVM.ChangeQueryText(query); - } - - public void ChangeQueryText(string query, bool selectAll = false) - { - _mainVM.ChangeQueryText(query); + _mainVM.ChangeQueryText(query, requery); } public void RestartApp() diff --git a/Flow.Launcher/Resources/Segoe Fluent Icons.ttf b/Flow.Launcher/Resources/Segoe Fluent Icons.ttf new file mode 100644 index 000000000..8f05a4bbc Binary files /dev/null and b/Flow.Launcher/Resources/Segoe Fluent Icons.ttf differ diff --git a/Flow.Launcher/ResultListBox.xaml b/Flow.Launcher/ResultListBox.xaml index dfee89810..d52474d3f 100644 --- a/Flow.Launcher/ResultListBox.xaml +++ b/Flow.Launcher/ResultListBox.xaml @@ -20,6 +20,7 @@ IsSynchronizedWithCurrentItem="True" PreviewMouseDown="ListBox_PreviewMouseDown"> + - + + @@ -104,7 +110,7 @@ + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  + + + + + + + + + + + + +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  + + + + + + + + + + + + + +  + + + + + + + + + + + +  + + + + + + + + + + + +  + + + + + + + + + + - - - - + + + + + + + - - - - + + + + + + + + +  + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + + + + + + + + + + + + + + + + - - - - - + Style="{DynamicResource QueryBoxStyle}"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  + + - - - - - + + + + + + + + + + + +  + + + + + + + + + - + - - - - - - - - + Width="130" Margin="10 0 0 0"> + + + + + + + + + + + + + + +  + - - - - - - - + + + + + + - + - - - - - - - - + Width="130" Margin="10 -2 0 0"> + + + + + + + + + + + + + + +  + - - - + + + + + + + + + + + + +  + + + + - - - + + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +  + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - -