mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Refactor history handling with async ResultHelper
Replaced `HistoryHelper` with a new `ResultHelper` class to handle plugin result population asynchronously, improving performance and maintainability. Removed `ExecuteAction` and `QueryAction` properties from `LastOpenedHistoryItem` and updated `QueryHistory` and `MainViewModel` to use `LastOpenedHistoryItems` directly. Refactored history result generation to support `AsyncAction` in `Result` objects, replacing synchronous plugin queries. Simplified legacy history migration and enhanced support for `HistoryStyle`. Improved error handling, code readability, and UI-related logic for history navigation.
This commit is contained in:
parent
693bae7631
commit
787ccad384
5 changed files with 108 additions and 103 deletions
44
Flow.Launcher/Helper/ResultHelper.cs
Normal file
44
Flow.Launcher/Helper/ResultHelper.cs
Normal file
|
|
@ -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<Result?> PopulateResultsAsync(LastOpenedHistoryItem item)
|
||||
{
|
||||
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
|
||||
}
|
||||
|
||||
public static async Task<Result?> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<LastOpenedHistoryItem> PopulateActions(this List<LastOpenedHistoryItem> 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<ActionContext, bool> GetQueryAction(string rawQuery)
|
||||
{
|
||||
return _ =>
|
||||
{
|
||||
App.API.BackToQueryResults();
|
||||
App.API.ChangeQuery(rawQuery);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
private static Func<ActionContext, bool>? 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ActionContext, bool> ExecuteAction { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Func<ActionContext, bool> QueryAction { get; set; }
|
||||
|
||||
public bool Equals(Result r)
|
||||
{
|
||||
if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey))
|
||||
|
|
|
|||
|
|
@ -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<LastOpenedHistoryItem> LastOpenedHistoryItems { get; private set; } = [];
|
||||
|
||||
private readonly int _maxHistory = 300;
|
||||
private static readonly Settings _settings = Ioc.Default.GetRequiredService<Settings>();
|
||||
|
||||
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<LastOpenedHistoryItem> GetHistoryItems()
|
||||
{
|
||||
return LastOpenedHistoryItems.PopulateActions(_settings.HistoryStyle == HistoryStyle.Query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Result> GetHistoryItems(IEnumerable<LastOpenedHistoryItem> historyItems)
|
||||
{
|
||||
var results = new List<Result>();
|
||||
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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue