diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs new file mode 100644 index 000000000..f99ba0377 --- /dev/null +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -0,0 +1,44 @@ +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Plugin; +using Flow.Launcher.Storage; + +namespace Flow.Launcher.Helper; + +#nullable enable + +public static class ResultHelper +{ + public static async Task PopulateResultsAsync(LastOpenedHistoryItem item) + { + return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey); + } + + public static async Task PopulateResultsAsync(string pluginId, string rawQuery, string title, string subTitle, string recordKey) + { + var plugin = PluginManager.GetPluginForId(pluginId); + if (plugin == null) return null; + var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins); + if (query == null) return null; + try + { + var freshResults = await plugin.Plugin.QueryAsync(query, CancellationToken.None); + // Try to match by record key first if it is valid, otherwise fall back to title + subtitle match + if (string.IsNullOrEmpty(recordKey)) + { + return freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle); + } + else + { + return freshResults?.FirstOrDefault(r => r.RecordKey == recordKey) ?? + freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle); + } + } + catch + { + return null; + } + } +} diff --git a/Flow.Launcher/Storage/HistoryHelper.cs b/Flow.Launcher/Storage/HistoryHelper.cs deleted file mode 100644 index d9d0ec5a8..000000000 --- a/Flow.Launcher/Storage/HistoryHelper.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Plugin; - -namespace Flow.Launcher.Storage; - -#nullable enable - -public static class HistoryHelper -{ - internal static List PopulateActions(this List items, bool isQuery) - { - foreach (var item in items) - { - if (item.QueryAction != null && item.ExecuteAction != null) continue; - if (isQuery && item.QueryAction == null) item.QueryAction = GetQueryAction(item.Query); - if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey) ?? GetQueryAction(item.Query); - } - - return items; - } - - public static Func GetQueryAction(string rawQuery) - { - return _ => - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(rawQuery); - return false; - }; - } - - private static Func? GetExecuteAction(string pluginId, string rawQuery, string title, string subTitle, string recordKey) - { - var plugin = PluginManager.GetPluginForId(pluginId); - if (plugin == null) return null; - var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins); - if (query == null) return null; - try - { -#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits - var freshResults = plugin.Plugin - .QueryAsync(query, CancellationToken.None) - .GetAwaiter() - .GetResult(); -#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits - // Try to match by record key first if it is valid, otherwise fall back to title + subtitle match - if (string.IsNullOrEmpty(recordKey)) - { - return freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle)?.Action; - } - else - { - return freshResults?.FirstOrDefault(r => r.RecordKey == recordKey)?.Action ?? - freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle)?.Action; - } - } - catch - { - return null; - } - } -} diff --git a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs index c09933cc9..47647066c 100644 --- a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs +++ b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs @@ -1,5 +1,4 @@ using System; -using System.Text.Json.Serialization; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; @@ -13,12 +12,6 @@ public class LastOpenedHistoryItem public string RecordKey { get; set; } = string.Empty; public DateTime ExecutedDateTime { get; set; } - [JsonIgnore] - public Func ExecuteAction { get; set; } - - [JsonIgnore] - public Func QueryAction { get; set; } - public bool Equals(Result r) { if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey)) diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs index bd23837f8..7d264d09f 100644 --- a/Flow.Launcher/Storage/QueryHistory.cs +++ b/Flow.Launcher/Storage/QueryHistory.cs @@ -2,8 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; -using CommunityToolkit.Mvvm.DependencyInjection; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage @@ -19,7 +17,6 @@ namespace Flow.Launcher.Storage public List LastOpenedHistoryItems { get; private set; } = []; private readonly int _maxHistory = 300; - private static readonly Settings _settings = Ioc.Default.GetRequiredService(); public void PopulateHistoryFromLegacyHistory() { @@ -30,8 +27,7 @@ namespace Flow.Launcher.Storage LastOpenedHistoryItems.Add(new LastOpenedHistoryItem { Query = item.Query, - ExecutedDateTime = item.ExecutedDateTime, - QueryAction = HistoryHelper.GetQueryAction(item.Query) + ExecutedDateTime = item.ExecutedDateTime }); } Items.Clear(); @@ -62,15 +58,9 @@ namespace Flow.Launcher.Storage PluginID = result.PluginID, Query = result.OriginQuery.RawQuery, RecordKey = result.RecordKey, - ExecutedDateTime = DateTime.Now, - ExecuteAction = result.Action + ExecutedDateTime = DateTime.Now }); } } - - public List GetHistoryItems() - { - return LastOpenedHistoryItems.PopulateActions(_settings.HistoryStyle == HistoryStyle.Query); - } } } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ceced2d18..8fd6de6f5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -15,6 +15,7 @@ using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Helper; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; using Flow.Launcher.Infrastructure.Hotkey; @@ -353,7 +354,7 @@ namespace Flow.Launcher.ViewModel if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _history.GetHistoryItems().Count - 1; + History.SelectedIndex = _history.LastOpenedHistoryItems.Count - 1; } else { @@ -381,7 +382,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] public void ReverseHistory() { - var historyItems = _history.GetHistoryItems(); + var historyItems = _history.LastOpenedHistoryItems; if (historyItems.Count > 0) { ChangeQueryText(historyItems[^lastHistoryIndex].Query); @@ -395,7 +396,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] public void ForwardHistory() { - var historyItems = _history.GetHistoryItems(); + var historyItems = _history.LastOpenedHistoryItems; if (historyItems.Count > 0) { ChangeQueryText(historyItems[^lastHistoryIndex].Query); @@ -611,7 +612,7 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private void SelectPrevItem() { - var historyItems = _history.GetHistoryItems(); + var historyItems = _history.LastOpenedHistoryItems; if (QueryResultsSelected() // Results selected && string.IsNullOrEmpty(QueryText) // No input && Results.Visibility != Visibility.Visible // No items in result list, e.g. when home page is off and no query text is entered, therefore the view is collapsed. @@ -1297,7 +1298,7 @@ namespace Flow.Launcher.ViewModel var query = QueryText.ToLower().Trim(); History.Clear(); - var results = GetHistoryItems(_history.GetHistoryItems()); + var results = GetHistoryItems(_history.LastOpenedHistoryItems); if (!string.IsNullOrEmpty(query)) { @@ -1317,22 +1318,65 @@ namespace Flow.Launcher.ViewModel private List GetHistoryItems(IEnumerable historyItems) { var results = new List(); - foreach (var h in historyItems) + if (Settings.HistoryStyle == HistoryStyle.Query) { - var result = new Result + foreach (var h in historyItems) { - Title = Settings.HistoryStyle == HistoryStyle.Query ? - Localize.executeQuery(h.Query) : - string.IsNullOrEmpty(h.Title) ? // Old migrated history items have no title + var result = new Result + { + Title = Localize.executeQuery(h.Query), + SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), + IcoPath = Constant.HistoryIcon, + OriginQuery = new Query { RawQuery = h.Query }, + Action = _ => + { + App.API.BackToQueryResults(); + App.API.ChangeQuery(h.Query); + return false; + }, + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") + }; + results.Add(result); + } + } + else + { + foreach (var h in historyItems) + { + var result = new Result + { + Title = string.IsNullOrEmpty(h.Title) ? // Old migrated history items have no title Localize.executeQuery(h.Query) : h.Title, - SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), - IcoPath = Constant.HistoryIcon, - OriginQuery = new Query { RawQuery = h.Query }, - Action = Settings.HistoryStyle == HistoryStyle.Query ? h.QueryAction : h.ExecuteAction, - Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") - }; - results.Add(result); + SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), + IcoPath = Constant.HistoryIcon, + OriginQuery = new Query { RawQuery = h.Query }, + AsyncAction = async c => + { + var reflectResult = await ResultHelper.PopulateResultsAsync(h); + if (reflectResult != null) + { + if (reflectResult.Action != null) + { + reflectResult.Action(c); + } + else if (reflectResult.AsyncAction != null) + { + await reflectResult.AsyncAction(c); + } + return false; + } + else + { + App.API.BackToQueryResults(); + App.API.ChangeQuery(h.Query); + return false; + } + }, + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") + }; + results.Add(result); + } } return results; } @@ -1564,7 +1608,7 @@ namespace Flow.Launcher.ViewModel void QueryHistoryTask(CancellationToken token) { // Select last history results and revert its order to make sure last history results are on top - var historyItems = _history.GetHistoryItems().TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _history.LastOpenedHistoryItems.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); var results = GetHistoryItems(historyItems);