From 3cc4f13f4d60d0837edf4020e474a7710589953b Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 1 Oct 2025 23:05:41 -0300 Subject: [PATCH 01/52] feat: New option to show executed results in settings --- .../UserSettings/Settings.cs | 15 +++++++++ Flow.Launcher/Languages/en.xaml | 1 + .../Views/SettingsPaneGeneral.xaml | 31 +++++++++++++------ Flow.Launcher/Storage/ExecutedHistory.cs | 21 +++++++++++++ 4 files changed, 59 insertions(+), 9 deletions(-) create mode 100644 Flow.Launcher/Storage/ExecutedHistory.cs diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 23f9047fef7..231e8cc0f27 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -230,6 +230,21 @@ public bool ShowHistoryResultsForHomePage } } + + private bool _showHistoryExecutedResultsForHomePage = false; + public bool ShowHistoryExecutedResultsForHomePage + { + get => _showHistoryExecutedResultsForHomePage; + set + { + if (_showHistoryExecutedResultsForHomePage != value) + { + _showHistoryExecutedResultsForHomePage = value; + OnPropertyChanged(); + } + } + } + public int MaxHistoryResultsToShowForHomePage { get; set; } = 5; public bool AutoRestartAfterChanging { get; set; } = false; diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index f7fd0c8e588..0fd1af78df2 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -165,6 +165,7 @@ Home Page Show home page results when query text is empty. Show History Results in Home Page + Show History Executed 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 Foremost diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 81e15df6950..cfbe8c6c10f 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -381,18 +381,31 @@ OnContent="{DynamicResource enable}" /> - + + + + + + + Items { get; private set; } = new List(); + private int _maxHistory = 300; + + public void Add(Result result) + { + Items.Add(result); + } + +} From c0369e6e7672ddacffa1a91ac7eb660b48aba998 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Thu, 2 Oct 2025 00:03:48 -0300 Subject: [PATCH 02/52] feat: radio button with history query option or history executed option --- .../UserSettings/Settings.cs | 20 +++++-- Flow.Launcher/Languages/en.xaml | 6 ++- Flow.Launcher/MainWindow.xaml.cs | 2 +- .../Views/SettingsPaneGeneral.xaml | 53 ++++++++----------- Flow.Launcher/Storage/ExecutedHistory.cs | 30 +++++++++-- Flow.Launcher/Storage/ExecutedHistoryItem.cs | 17 ++++++ Flow.Launcher/ViewModel/MainViewModel.cs | 51 +++++++++++++++++- 7 files changed, 134 insertions(+), 45 deletions(-) create mode 100644 Flow.Launcher/Storage/ExecutedHistoryItem.cs diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 231e8cc0f27..08035ee4412 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -216,16 +216,21 @@ public bool ShowHomePage } } - private bool _showHistoryResultsForHomePage = false; - public bool ShowHistoryResultsForHomePage + private bool _showHistoryQueryResultsForHomePage = false; + public bool ShowHistoryQueryResultsForHomePage { - get => _showHistoryResultsForHomePage; + get => _showHistoryQueryResultsForHomePage; set { - if (_showHistoryResultsForHomePage != value) + if (_showHistoryQueryResultsForHomePage != value) { - _showHistoryResultsForHomePage = value; + _showHistoryQueryResultsForHomePage = value; OnPropertyChanged(); + if (value && _showHistoryExecutedResultsForHomePage) + { + _showHistoryExecutedResultsForHomePage = false; + OnPropertyChanged(nameof(ShowHistoryExecutedResultsForHomePage)); + } } } } @@ -241,6 +246,11 @@ public bool ShowHistoryExecutedResultsForHomePage { _showHistoryExecutedResultsForHomePage = value; OnPropertyChanged(); + if (value && _showHistoryQueryResultsForHomePage) + { + _showHistoryQueryResultsForHomePage = false; + OnPropertyChanged(nameof(ShowHistoryQueryResultsForHomePage)); + } } } } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 0fd1af78df2..abadab964cf 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -164,7 +164,11 @@ Please check your system registry access or contact support. Home Page Show home page results when query text is empty. - Show History Results in Home Page + Home Page History + Choose the type of history to show on the home page + Query History + Executed History + Show History Query Results in Home Page Show History Executed 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. diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 7b6a0d79bed..e6696c34c1b 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -317,7 +317,7 @@ private void OnLoaded(object sender, RoutedEventArgs e) InitializeContextMenu(); break; case nameof(Settings.ShowHomePage): - case nameof(Settings.ShowHistoryResultsForHomePage): + case nameof(Settings.ShowHistoryQueryResultsForHomePage): if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText)) { _viewModel.QueryResults(); diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index cfbe8c6c10f..9fe45e89ed8 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -373,39 +373,30 @@ OnContent="{DynamicResource enable}" /> - - - - - - - - - + + + + + + + + + + + - - - - Items { get; private set; } = new List(); - private int _maxHistory = 300; + [JsonInclude] public List Items { get; private set; } = []; + private const int MaxHistory = 300; public void Add(Result result) { - Items.Add(result); - } + var item = new ExecutedHistoryItem + { + Title = result.Title, + SubTitle = result.SubTitle, + IcoPath = result.IcoPath ?? string.Empty, + PluginID = result.PluginID, + OriginQuery = result.OriginQuery, + ExecutedDateTime = DateTime.Now + }; + + var existing = Items.FirstOrDefault(x => x.OriginQuery.RawQuery == item.OriginQuery.RawQuery && x.PluginID == item.PluginID); + if (existing != null) + { + Items.Remove(existing); + } + Items.Add(item); + + if (Items.Count > MaxHistory) + { + Items.RemoveAt(0); + } + } } diff --git a/Flow.Launcher/Storage/ExecutedHistoryItem.cs b/Flow.Launcher/Storage/ExecutedHistoryItem.cs new file mode 100644 index 00000000000..8ae6d333648 --- /dev/null +++ b/Flow.Launcher/Storage/ExecutedHistoryItem.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Flow.Launcher.Plugin; + +namespace Flow.Launcher.Storage; +public class ExecutedHistoryItem +{ + public string Title { get; set; } = string.Empty; + public string SubTitle { get; set; } = string.Empty; + public string IcoPath { get; set; } = string.Empty; + public string PluginID { get; set; } = string.Empty; + public Query OriginQuery { get; set; } = null!; + public DateTime ExecutedDateTime { get; set; } +} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d492f28c58c..abdd239e9c3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -41,9 +41,11 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results private readonly FlowLauncherJsonStorage _historyItemsStorage; + private readonly FlowLauncherJsonStorage _executedHistoryStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord; private readonly History _history; + private readonly ExecutedHistory _executedHistory; private int lastHistoryIndex = 1; private readonly UserSelectedRecord _userSelectedRecord; @@ -148,9 +150,11 @@ public MainViewModel() }; _historyItemsStorage = new FlowLauncherJsonStorage(); + _executedHistoryStorage = new FlowLauncherJsonStorage(); _userSelectedRecordStorage = new FlowLauncherJsonStorage(); _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); _history = _historyItemsStorage.Load(); + _executedHistory = _executedHistoryStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load(); ContextMenu = new ResultsViewModel(Settings, this) @@ -529,6 +533,9 @@ private async Task OpenResultAsync(string index) if (QueryResultsSelected()) { + if(Settings.ShowHistoryExecutedResultsForHomePage) + _executedHistory.Add(result); + _userSelectedRecord.Add(result); _history.Add(result.OriginQuery.RawQuery); lastHistoryIndex = 1; @@ -1448,10 +1455,14 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b }).ToArray(); // Query history results for home page firstly so it will be put on top of the results - if (Settings.ShowHistoryResultsForHomePage) + if (Settings.ShowHistoryQueryResultsForHomePage) { QueryHistoryTask(currentCancellationToken); } + else if (Settings.ShowHistoryExecutedResultsForHomePage) + { + QueryExecutedHistoryTask(currentCancellationToken); + } } else { @@ -1574,6 +1585,41 @@ void QueryHistoryTask(CancellationToken token) App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } } + + void QueryExecutedHistoryTask(CancellationToken token) + { + var historyItems = _executedHistory.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + + var results = new List(); + foreach (var item in historyItems) + { + var result = new Result + { + Title = item.Title, + SubTitle = item.SubTitle, + IcoPath = item.IcoPath, + PluginID = item.PluginID, + OriginQuery = item.OriginQuery, + Action = _ => + { + App.API.ChangeQuery(item.OriginQuery.RawQuery); + return false; + }, + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") + }; + results.Add(result); + } + + if (token.IsCancellationRequested) return; + + App.API.LogDebug(ClassName, "Update results for executed history"); + + if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, _historyMetadata, query, + token, reSelect))) + { + App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); + } + } } private async Task ConstructQueryAsync(string queryText, IEnumerable customShortcuts, @@ -1698,7 +1744,7 @@ private bool ShouldClearExistingResultsForQuery(Query query, bool currentIsHomeQ /// True if existing results should be cleared, false otherwise. private bool ShouldClearExistingResultsForNonQuery(ICollection plugins) { - if (!Settings.ShowHistoryResultsForHomePage && (plugins.Count == 0 || plugins.All(x => x.Metadata.HomeDisabled == true))) + if (!Settings.ShowHistoryQueryResultsForHomePage && (plugins.Count == 0 || plugins.All(x => x.Metadata.HomeDisabled == true))) { App.API.LogDebug(ClassName, $"Existing results should be cleared for non-query"); return true; @@ -2163,6 +2209,7 @@ public async void Hide(bool reset = true) public void Save() { _historyItemsStorage.Save(); + _executedHistoryStorage.Save(); _userSelectedRecordStorage.Save(); _topMostRecord.Save(); } From bc1f9d3734c666c7e18c53a69dd7b86a002858f7 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Thu, 2 Oct 2025 00:09:28 -0300 Subject: [PATCH 03/52] refactor: renaming executed history to last opened history --- .../UserSettings/Settings.cs | 16 ++++++------- Flow.Launcher/Languages/en.xaml | 4 ++-- .../Views/SettingsPaneGeneral.xaml | 4 ++-- ...xecutedHistory.cs => LastOpenedHistory.cs} | 6 ++--- ...istoryItem.cs => LastOpenedHistoryItem.cs} | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 24 +++++++++---------- 6 files changed, 28 insertions(+), 28 deletions(-) rename Flow.Launcher/Storage/{ExecutedHistory.cs => LastOpenedHistory.cs} (85%) rename Flow.Launcher/Storage/{ExecutedHistoryItem.cs => LastOpenedHistoryItem.cs} (93%) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 08035ee4412..e33bf04ac36 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -226,25 +226,25 @@ public bool ShowHistoryQueryResultsForHomePage { _showHistoryQueryResultsForHomePage = value; OnPropertyChanged(); - if (value && _showHistoryExecutedResultsForHomePage) + if (value && _showHistoryLastOpenedResultsForHomePage) { - _showHistoryExecutedResultsForHomePage = false; - OnPropertyChanged(nameof(ShowHistoryExecutedResultsForHomePage)); + _showHistoryLastOpenedResultsForHomePage = false; + OnPropertyChanged(nameof(ShowHistoryLastOpenedResultsForHomePage)); } } } } - private bool _showHistoryExecutedResultsForHomePage = false; - public bool ShowHistoryExecutedResultsForHomePage + private bool _showHistoryLastOpenedResultsForHomePage = false; + public bool ShowHistoryLastOpenedResultsForHomePage { - get => _showHistoryExecutedResultsForHomePage; + get => _showHistoryLastOpenedResultsForHomePage; set { - if (_showHistoryExecutedResultsForHomePage != value) + if (_showHistoryLastOpenedResultsForHomePage != value) { - _showHistoryExecutedResultsForHomePage = value; + _showHistoryLastOpenedResultsForHomePage = value; OnPropertyChanged(); if (value && _showHistoryQueryResultsForHomePage) { diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index abadab964cf..14677e1ea8c 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -167,9 +167,9 @@ Home Page History Choose the type of history to show on the home page Query History - Executed History + Last Opened History Show History Query Results in Home Page - Show History Executed Results in Home Page + Show History Last Opened 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 Foremost diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 9fe45e89ed8..e694a84d8e5 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -377,8 +377,8 @@ - diff --git a/Flow.Launcher/Storage/ExecutedHistory.cs b/Flow.Launcher/Storage/LastOpenedHistory.cs similarity index 85% rename from Flow.Launcher/Storage/ExecutedHistory.cs rename to Flow.Launcher/Storage/LastOpenedHistory.cs index d9b9966afb8..6394e2ce576 100644 --- a/Flow.Launcher/Storage/ExecutedHistory.cs +++ b/Flow.Launcher/Storage/LastOpenedHistory.cs @@ -8,14 +8,14 @@ using Flow.Launcher.ViewModel; namespace Flow.Launcher.Storage; -public class ExecutedHistory +public class LastOpenedHistory { - [JsonInclude] public List Items { get; private set; } = []; + [JsonInclude] public List Items { get; private set; } = []; private const int MaxHistory = 300; public void Add(Result result) { - var item = new ExecutedHistoryItem + var item = new LastOpenedHistoryItem { Title = result.Title, SubTitle = result.SubTitle, diff --git a/Flow.Launcher/Storage/ExecutedHistoryItem.cs b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs similarity index 93% rename from Flow.Launcher/Storage/ExecutedHistoryItem.cs rename to Flow.Launcher/Storage/LastOpenedHistoryItem.cs index 8ae6d333648..28bd49a9528 100644 --- a/Flow.Launcher/Storage/ExecutedHistoryItem.cs +++ b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs @@ -6,7 +6,7 @@ using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; -public class ExecutedHistoryItem +public class LastOpenedHistoryItem { public string Title { get; set; } = string.Empty; public string SubTitle { get; set; } = string.Empty; diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index abdd239e9c3..2e3e8d4d70c 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -41,11 +41,11 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results private readonly FlowLauncherJsonStorage _historyItemsStorage; - private readonly FlowLauncherJsonStorage _executedHistoryStorage; + private readonly FlowLauncherJsonStorage _lastOpenedHistoryStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord; private readonly History _history; - private readonly ExecutedHistory _executedHistory; + private readonly LastOpenedHistory _lastOpenedHistory; private int lastHistoryIndex = 1; private readonly UserSelectedRecord _userSelectedRecord; @@ -150,11 +150,11 @@ public MainViewModel() }; _historyItemsStorage = new FlowLauncherJsonStorage(); - _executedHistoryStorage = new FlowLauncherJsonStorage(); + _lastOpenedHistoryStorage = new FlowLauncherJsonStorage(); _userSelectedRecordStorage = new FlowLauncherJsonStorage(); _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); _history = _historyItemsStorage.Load(); - _executedHistory = _executedHistoryStorage.Load(); + _lastOpenedHistory = _lastOpenedHistoryStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load(); ContextMenu = new ResultsViewModel(Settings, this) @@ -533,8 +533,8 @@ private async Task OpenResultAsync(string index) if (QueryResultsSelected()) { - if(Settings.ShowHistoryExecutedResultsForHomePage) - _executedHistory.Add(result); + if(Settings.ShowHistoryLastOpenedResultsForHomePage) + _lastOpenedHistory.Add(result); _userSelectedRecord.Add(result); _history.Add(result.OriginQuery.RawQuery); @@ -1459,9 +1459,9 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b { QueryHistoryTask(currentCancellationToken); } - else if (Settings.ShowHistoryExecutedResultsForHomePage) + else if (Settings.ShowHistoryLastOpenedResultsForHomePage) { - QueryExecutedHistoryTask(currentCancellationToken); + QueryLastOpenedHistoryTask(currentCancellationToken); } } else @@ -1586,9 +1586,9 @@ void QueryHistoryTask(CancellationToken token) } } - void QueryExecutedHistoryTask(CancellationToken token) + void QueryLastOpenedHistoryTask(CancellationToken token) { - var historyItems = _executedHistory.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _lastOpenedHistory.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); var results = new List(); foreach (var item in historyItems) @@ -1612,7 +1612,7 @@ void QueryExecutedHistoryTask(CancellationToken token) if (token.IsCancellationRequested) return; - App.API.LogDebug(ClassName, "Update results for executed history"); + App.API.LogDebug(ClassName, "Update results for last opened history"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, _historyMetadata, query, token, reSelect))) @@ -2209,7 +2209,7 @@ public async void Hide(bool reset = true) public void Save() { _historyItemsStorage.Save(); - _executedHistoryStorage.Save(); + _lastOpenedHistoryStorage.Save(); _userSelectedRecordStorage.Save(); _topMostRecord.Save(); } From 5fcd01224c3bc28fd0f6566c5c49a5c22f6a2106 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Thu, 2 Oct 2025 00:19:40 -0300 Subject: [PATCH 04/52] feat: text --- Flow.Launcher/Languages/en.xaml | 6 +++--- Flow.Launcher/Storage/LastOpenedHistory.cs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 14677e1ea8c..7fd10272aa1 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -168,9 +168,9 @@ Choose the type of history to show on the home page Query History Last Opened History - Show History Query Results in Home Page - Show History Last Opened Results in Home Page - Maximum History Results Shown in Home Page + Show Query History + Show Last Opened History + Maximum History Results Shown This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. diff --git a/Flow.Launcher/Storage/LastOpenedHistory.cs b/Flow.Launcher/Storage/LastOpenedHistory.cs index 6394e2ce576..19f30855e14 100644 --- a/Flow.Launcher/Storage/LastOpenedHistory.cs +++ b/Flow.Launcher/Storage/LastOpenedHistory.cs @@ -25,6 +25,7 @@ public void Add(Result result) ExecutedDateTime = DateTime.Now }; + // Aparenta estar duplicando... var existing = Items.FirstOrDefault(x => x.OriginQuery.RawQuery == item.OriginQuery.RawQuery && x.PluginID == item.PluginID); if (existing != null) { From 7ba4f8de4ab5c4af4ab64f638e094b0a5bb3df6d Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 4 Oct 2025 02:19:57 -0300 Subject: [PATCH 05/52] feat: last opened history --- Flow.Launcher/ViewModel/MainViewModel.cs | 33 +++++++++++++----------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 2e3e8d4d70c..871ac869a94 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -40,11 +40,11 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private string _queryTextBeforeLeaveResults; private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results - private readonly FlowLauncherJsonStorage _historyItemsStorage; + private readonly FlowLauncherJsonStorage _queryHistoryItemsStorage; private readonly FlowLauncherJsonStorage _lastOpenedHistoryStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord; - private readonly History _history; + private readonly History _queryHistory; private readonly LastOpenedHistory _lastOpenedHistory; private int lastHistoryIndex = 1; private readonly UserSelectedRecord _userSelectedRecord; @@ -149,11 +149,11 @@ public MainViewModel() } }; - _historyItemsStorage = new FlowLauncherJsonStorage(); + _queryHistoryItemsStorage = new FlowLauncherJsonStorage(); _lastOpenedHistoryStorage = new FlowLauncherJsonStorage(); _userSelectedRecordStorage = new FlowLauncherJsonStorage(); _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); - _history = _historyItemsStorage.Load(); + _queryHistory = _queryHistoryItemsStorage.Load(); _lastOpenedHistory = _lastOpenedHistoryStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load(); @@ -356,7 +356,7 @@ private void LoadHistory() if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _history.Items.Count - 1; + History.SelectedIndex = _queryHistory.Items.Count - 1; } else { @@ -384,10 +384,10 @@ public void ReQuery(bool reselect) [RelayCommand] public void ReverseHistory() { - if (_history.Items.Count > 0) + if (_queryHistory.Items.Count > 0) { - ChangeQueryText(_history.Items[^lastHistoryIndex].Query); - if (lastHistoryIndex < _history.Items.Count) + ChangeQueryText(_queryHistory.Items[^lastHistoryIndex].Query); + if (lastHistoryIndex < _queryHistory.Items.Count) { lastHistoryIndex++; } @@ -397,9 +397,9 @@ public void ReverseHistory() [RelayCommand] public void ForwardHistory() { - if (_history.Items.Count > 0) + if (_queryHistory.Items.Count > 0) { - ChangeQueryText(_history.Items[^lastHistoryIndex].Query); + ChangeQueryText(_queryHistory.Items[^lastHistoryIndex].Query); if (lastHistoryIndex > 1) { lastHistoryIndex--; @@ -535,9 +535,12 @@ private async Task OpenResultAsync(string index) { if(Settings.ShowHistoryLastOpenedResultsForHomePage) _lastOpenedHistory.Add(result); + else + { + _queryHistory.Add(result.OriginQuery.RawQuery); + } _userSelectedRecord.Add(result); - _history.Add(result.OriginQuery.RawQuery); lastHistoryIndex = 1; } } @@ -616,7 +619,7 @@ private void SelectPrevItem() 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. - && _history.Items.Count > 0) // Have history items + && _queryHistory.Items.Count > 0) // Have history items { lastHistoryIndex = 1; ReverseHistory(); @@ -1297,7 +1300,7 @@ private void QueryHistory() var query = QueryText.ToLower().Trim(); History.Clear(); - var results = GetHistoryItems(_history.Items); + var results = GetHistoryItems(_queryHistory.Items); if (!string.IsNullOrEmpty(query)) { @@ -1571,7 +1574,7 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : void QueryHistoryTask(CancellationToken token) { // Select last history results and revert its order to make sure last history results are on top - var historyItems = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _queryHistory.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); var results = GetHistoryItems(historyItems); @@ -2208,7 +2211,7 @@ public async void Hide(bool reset = true) /// public void Save() { - _historyItemsStorage.Save(); + _queryHistoryItemsStorage.Save(); _lastOpenedHistoryStorage.Save(); _userSelectedRecordStorage.Save(); _topMostRecord.Save(); From e5736567f67353de6552ece5accd5e6b9c3621db Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 7 Oct 2025 00:33:16 -0300 Subject: [PATCH 06/52] feat: created a base History model --- Flow.Launcher/Storage/History.cs | 92 +++++++++++++++++++ Flow.Launcher/Storage/HistoryItem.cs | 79 ++++++++-------- Flow.Launcher/Storage/LastOpenedHistory.cs | 42 --------- .../Storage/LastOpenedHistoryItem.cs | 17 ---- Flow.Launcher/Storage/QueryHistory.cs | 37 -------- 5 files changed, 135 insertions(+), 132 deletions(-) create mode 100644 Flow.Launcher/Storage/History.cs delete mode 100644 Flow.Launcher/Storage/LastOpenedHistory.cs delete mode 100644 Flow.Launcher/Storage/LastOpenedHistoryItem.cs delete mode 100644 Flow.Launcher/Storage/QueryHistory.cs diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs new file mode 100644 index 00000000000..5a94c8a8a75 --- /dev/null +++ b/Flow.Launcher/Storage/History.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; +using Flow.Launcher.Infrastructure.UserSettings; +using Flow.Launcher.Plugin; +using JetBrains.Annotations; + +namespace Flow.Launcher.Storage +{ + public class History + { + [JsonInclude] + public List LastOpenedHistoryItems { get; private set; } = []; + [JsonInclude] + public List QueryHistoryItems { get; private set; } = []; + + private int _maxHistory = 300; + + public void AddToHistory(Result result, Settings settings) + { + if (settings.ShowHistoryQueryResultsForHomePage) + { + AddLastQuery(result); + return; + } + AddLastOpened(result); + } + + public List GetHistoryItems(Settings settings) + { + if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems; + if (settings.ShowHistoryLastOpenedResultsForHomePage) return LastOpenedHistoryItems; + return new List(); + } + + private void AddLastQuery(Result result) + { + if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; + if (QueryHistoryItems.Count > _maxHistory) + { + QueryHistoryItems.RemoveAt(0); + } + + if (QueryHistoryItems.Count > 0 && QueryHistoryItems.Last().OriginQuery == result.OriginQuery) + { + QueryHistoryItems.Last().ExecutedDateTime = DateTime.Now; + } + else + { + QueryHistoryItems.Add(new HistoryItem + { + OriginQuery = result.OriginQuery, + ExecutedDateTime = DateTime.Now + }); + } + } + + private void AddLastOpened(Result result) + { + var item = new HistoryItem + { + Title = result.Title, + SubTitle = result.SubTitle, + IcoPath = result.IcoPath ?? string.Empty, + PluginID = result.PluginID, + OriginQuery = result.OriginQuery, + ExecutedDateTime = DateTime.Now, + }; + + var existing = LastOpenedHistoryItems. + FirstOrDefault(x => x.Title == item.Title && x.PluginID == item.PluginID); + + + if (existing != null) + { + existing.ExecutedDateTime = DateTime.Now; + } + else + { + if (LastOpenedHistoryItems.Count > _maxHistory) + { + LastOpenedHistoryItems.RemoveAt(0); + } + + LastOpenedHistoryItems.Add(item); + } + } + } +} diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index 6f0bf746181..cb95e75d12d 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -1,45 +1,52 @@ -using System; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Flow.Launcher.Plugin; -namespace Flow.Launcher.Storage +namespace Flow.Launcher.Storage; +public class HistoryItem { - public class HistoryItem + public string Title { get; set; } = string.Empty; + public string SubTitle { get; set; } = string.Empty; + public string IcoPath { get; set; } = string.Empty; + public string PluginID { get; set; } = string.Empty; + public Query OriginQuery { get; set; } = null!; + public DateTime ExecutedDateTime { get; set; } + + public string GetTimeAgo() { - public string Query { get; set; } - public DateTime ExecutedDateTime { get; set; } + return DateTimeAgo(ExecutedDateTime); + } - public string GetTimeAgo() + private string DateTimeAgo(DateTime dt) + { + var span = DateTime.Now - dt; + if (span.Days > 365) { - return DateTimeAgo(ExecutedDateTime); + int years = (span.Days / 365); + if (span.Days % 365 != 0) + years += 1; + return $"about {years} {(years == 1 ? "year" : "years")} ago"; } - - private string DateTimeAgo(DateTime dt) + if (span.Days > 30) { - var span = DateTime.Now - dt; - if (span.Days > 365) - { - int years = (span.Days / 365); - if (span.Days % 365 != 0) - years += 1; - return $"about {years} {(years == 1 ? "year" : "years")} ago"; - } - if (span.Days > 30) - { - int months = (span.Days / 30); - if (span.Days % 31 != 0) - months += 1; - return $"about {months} {(months == 1 ? "month" : "months")} ago"; - } - if (span.Days > 0) - return $"about {span.Days} {(span.Days == 1 ? "day" : "days")} ago"; - if (span.Hours > 0) - return $"about {span.Hours} {(span.Hours == 1 ? "hour" : "hours")} ago"; - if (span.Minutes > 0) - return $"about {span.Minutes} {(span.Minutes == 1 ? "minute" : "minutes")} ago"; - if (span.Seconds > 5) - return $"about {span.Seconds} seconds ago"; - if (span.Seconds <= 5) - return "just now"; - return string.Empty; + int months = (span.Days / 30); + if (span.Days % 31 != 0) + months += 1; + return $"about {months} {(months == 1 ? "month" : "months")} ago"; } + if (span.Days > 0) + return $"about {span.Days} {(span.Days == 1 ? "day" : "days")} ago"; + if (span.Hours > 0) + return $"about {span.Hours} {(span.Hours == 1 ? "hour" : "hours")} ago"; + if (span.Minutes > 0) + return $"about {span.Minutes} {(span.Minutes == 1 ? "minute" : "minutes")} ago"; + if (span.Seconds > 5) + return $"about {span.Seconds} seconds ago"; + if (span.Seconds <= 5) + return "just now"; + return string.Empty; } -} \ No newline at end of file +} diff --git a/Flow.Launcher/Storage/LastOpenedHistory.cs b/Flow.Launcher/Storage/LastOpenedHistory.cs deleted file mode 100644 index 19f30855e14..00000000000 --- a/Flow.Launcher/Storage/LastOpenedHistory.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Flow.Launcher.Plugin; -using Flow.Launcher.ViewModel; - -namespace Flow.Launcher.Storage; -public class LastOpenedHistory -{ - [JsonInclude] public List Items { get; private set; } = []; - private const int MaxHistory = 300; - - public void Add(Result result) - { - var item = new LastOpenedHistoryItem - { - Title = result.Title, - SubTitle = result.SubTitle, - IcoPath = result.IcoPath ?? string.Empty, - PluginID = result.PluginID, - OriginQuery = result.OriginQuery, - ExecutedDateTime = DateTime.Now - }; - - // Aparenta estar duplicando... - var existing = Items.FirstOrDefault(x => x.OriginQuery.RawQuery == item.OriginQuery.RawQuery && x.PluginID == item.PluginID); - if (existing != null) - { - Items.Remove(existing); - } - - Items.Add(item); - - if (Items.Count > MaxHistory) - { - Items.RemoveAt(0); - } - } -} diff --git a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs deleted file mode 100644 index 28bd49a9528..00000000000 --- a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Flow.Launcher.Plugin; - -namespace Flow.Launcher.Storage; -public class LastOpenedHistoryItem -{ - public string Title { get; set; } = string.Empty; - public string SubTitle { get; set; } = string.Empty; - public string IcoPath { get; set; } = string.Empty; - public string PluginID { get; set; } = string.Empty; - public Query OriginQuery { get; set; } = null!; - public DateTime ExecutedDateTime { get; set; } -} diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs deleted file mode 100644 index a5383b179ab..00000000000 --- a/Flow.Launcher/Storage/QueryHistory.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.Json.Serialization; - -namespace Flow.Launcher.Storage -{ - public class History - { - [JsonInclude] - public List Items { get; private set; } = new List(); - - private int _maxHistory = 300; - - public void Add(string query) - { - if (string.IsNullOrEmpty(query)) return; - if (Items.Count > _maxHistory) - { - Items.RemoveAt(0); - } - - if (Items.Count > 0 && Items.Last().Query == query) - { - Items.Last().ExecutedDateTime = DateTime.Now; - } - else - { - Items.Add(new HistoryItem - { - Query = query, - ExecutedDateTime = DateTime.Now - }); - } - } - } -} From 9e182a2e47442f187b8556ec7ff85c12e3500739 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 7 Oct 2025 00:35:34 -0300 Subject: [PATCH 07/52] feat: base history model in MainView and refactoring code to replace action between query result or last opened --- Flow.Launcher/ViewModel/MainViewModel.cs | 154 ++++++++++------------- 1 file changed, 69 insertions(+), 85 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 871ac869a94..d4dda62aab3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -8,21 +8,23 @@ using System.Threading.Channels; using System.Threading.Tasks; using System.Windows; -using System.Windows.Input; using System.Windows.Controls; +using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; +using Droplex; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure; -using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.DialogJump; +using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Storage; +using JetBrains.Annotations; using Microsoft.VisualStudio.Threading; using ModernWpf; @@ -39,13 +41,10 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private bool _previousIsHomeQuery; private string _queryTextBeforeLeaveResults; private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results - - private readonly FlowLauncherJsonStorage _queryHistoryItemsStorage; - private readonly FlowLauncherJsonStorage _lastOpenedHistoryStorage; + private readonly FlowLauncherJsonStorage _historyStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord; - private readonly History _queryHistory; - private readonly LastOpenedHistory _lastOpenedHistory; + private readonly History _history; private int lastHistoryIndex = 1; private readonly UserSelectedRecord _userSelectedRecord; @@ -149,12 +148,13 @@ public MainViewModel() } }; - _queryHistoryItemsStorage = new FlowLauncherJsonStorage(); - _lastOpenedHistoryStorage = new FlowLauncherJsonStorage(); + _historyStorage = new FlowLauncherJsonStorage(); + _userSelectedRecordStorage = new FlowLauncherJsonStorage(); _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); - _queryHistory = _queryHistoryItemsStorage.Load(); - _lastOpenedHistory = _lastOpenedHistoryStorage.Load(); + + + _history = _historyStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load(); ContextMenu = new ResultsViewModel(Settings, this) @@ -356,7 +356,7 @@ private void LoadHistory() if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _queryHistory.Items.Count - 1; + History.SelectedIndex = _history.GetHistoryItems(Settings).Count - 1; } else { @@ -384,10 +384,11 @@ public void ReQuery(bool reselect) [RelayCommand] public void ReverseHistory() { - if (_queryHistory.Items.Count > 0) + var historyItems = _history.GetHistoryItems(Settings); + if (historyItems.Count > 0) { - ChangeQueryText(_queryHistory.Items[^lastHistoryIndex].Query); - if (lastHistoryIndex < _queryHistory.Items.Count) + ChangeQueryText(historyItems[^lastHistoryIndex].OriginQuery.RawQuery); + if (lastHistoryIndex < historyItems.Count) { lastHistoryIndex++; } @@ -397,9 +398,11 @@ public void ReverseHistory() [RelayCommand] public void ForwardHistory() { - if (_queryHistory.Items.Count > 0) + var historyItems = _history.GetHistoryItems(Settings); + + if (historyItems.Count > 0) { - ChangeQueryText(_queryHistory.Items[^lastHistoryIndex].Query); + ChangeQueryText(historyItems[^lastHistoryIndex].OriginQuery.RawQuery); if (lastHistoryIndex > 1) { lastHistoryIndex--; @@ -533,13 +536,7 @@ private async Task OpenResultAsync(string index) if (QueryResultsSelected()) { - if(Settings.ShowHistoryLastOpenedResultsForHomePage) - _lastOpenedHistory.Add(result); - else - { - _queryHistory.Add(result.OriginQuery.RawQuery); - } - + _history.AddToHistory(result, Settings); _userSelectedRecord.Add(result); lastHistoryIndex = 1; } @@ -616,10 +613,11 @@ private void SelectNextPage() [RelayCommand] private void SelectPrevItem() { + var historyItems = _history.GetHistoryItems(Settings); 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. - && _queryHistory.Items.Count > 0) // Have history items + && historyItems.Count > 0) // Have history items { lastHistoryIndex = 1; ReverseHistory(); @@ -1300,7 +1298,9 @@ private void QueryHistory() var query = QueryText.ToLower().Trim(); History.Clear(); - var results = GetHistoryItems(_queryHistory.Items); + var items = _history.GetHistoryItems(Settings); + + var results = GetHistoryResults(items); if (!string.IsNullOrEmpty(query)) { @@ -1317,32 +1317,60 @@ private void QueryHistory() } } - private static List GetHistoryItems(IEnumerable historyItems) + private List GetHistoryResults(IEnumerable historyItems) { var results = new List(); + Func defaultAction = _ => false; + foreach (var h in historyItems) { - var title = App.API.GetTranslation("executeQuery"); - var time = App.API.GetTranslation("lastExecuteTime"); - var result = new Result + // Achar uma forma melhor de fazer isso + if (Settings.ShowHistoryLastOpenedResultsForHomePage) { - Title = string.Format(title, h.Query), - SubTitle = string.Format(time, h.ExecutedDateTime), - IcoPath = Constant.HistoryIcon, - OriginQuery = new Query { RawQuery = h.Query }, - Action = _ => + var pluginPair = PluginManager.GetPluginForId(h.PluginID); + if (pluginPair != null) + { + var queryResults = PluginManager + .QueryForPluginAsync(pluginPair, h.OriginQuery, CancellationToken.None) + .GetAwaiter() + .GetResult(); + var originalResult = queryResults?.FirstOrDefault(r => + r.Title == h.Title && r.SubTitle == h.SubTitle); + if (originalResult?.Action != null) + { + defaultAction = originalResult.Action; + } + + } + } + else + { + defaultAction = _ => { App.API.BackToQueryResults(); - App.API.ChangeQuery(h.Query); + App.API.ChangeQuery(h.OriginQuery.RawQuery); return false; - }, + }; + } + var timeT = App.API.GetTranslation("lastExecuteTime"); + var result = new Result + { + Title = Settings.ShowHistoryQueryResultsForHomePage ? string.Format(App.API.GetTranslation("executeQuery"), h.OriginQuery.RawQuery) : h.Title, + SubTitle = string.Format(timeT, h.ExecutedDateTime), + IcoPath = Constant.HistoryIcon, + PluginID = h.PluginID, + OriginQuery = h.OriginQuery, + Action = defaultAction, Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") }; results.Add(result); } return results; + } + + private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) { _updateSource?.Cancel(); @@ -1457,15 +1485,7 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b true => Task.CompletedTask }).ToArray(); - // Query history results for home page firstly so it will be put on top of the results - if (Settings.ShowHistoryQueryResultsForHomePage) - { - QueryHistoryTask(currentCancellationToken); - } - else if (Settings.ShowHistoryLastOpenedResultsForHomePage) - { - QueryLastOpenedHistoryTask(currentCancellationToken); - } + QueryHistoryTask(currentCancellationToken); } else { @@ -1574,9 +1594,9 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : void QueryHistoryTask(CancellationToken token) { // Select last history results and revert its order to make sure last history results are on top - var historyItems = _queryHistory.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _history.GetHistoryItems(Settings).TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); - var results = GetHistoryItems(historyItems); + var results = GetHistoryResults(historyItems); if (token.IsCancellationRequested) return; @@ -1588,41 +1608,6 @@ void QueryHistoryTask(CancellationToken token) App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } } - - void QueryLastOpenedHistoryTask(CancellationToken token) - { - var historyItems = _lastOpenedHistory.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); - - var results = new List(); - foreach (var item in historyItems) - { - var result = new Result - { - Title = item.Title, - SubTitle = item.SubTitle, - IcoPath = item.IcoPath, - PluginID = item.PluginID, - OriginQuery = item.OriginQuery, - Action = _ => - { - App.API.ChangeQuery(item.OriginQuery.RawQuery); - return false; - }, - Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") - }; - results.Add(result); - } - - if (token.IsCancellationRequested) return; - - App.API.LogDebug(ClassName, "Update results for last opened history"); - - if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(results, _historyMetadata, query, - token, reSelect))) - { - App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); - } - } } private async Task ConstructQueryAsync(string queryText, IEnumerable customShortcuts, @@ -2211,8 +2196,7 @@ public async void Hide(bool reset = true) /// public void Save() { - _queryHistoryItemsStorage.Save(); - _lastOpenedHistoryStorage.Save(); + _historyStorage.Save(); _userSelectedRecordStorage.Save(); _topMostRecord.Save(); } From 368134058730fe0f79aaef9fcb47d3179a63342f Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 8 Oct 2025 21:11:27 -0300 Subject: [PATCH 08/52] feat: toggle history --- .../Views/SettingsPaneGeneral.xaml | 63 ++++++++++++------- 1 file changed, 42 insertions(+), 21 deletions(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index e694a84d8e5..e722e973403 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -374,27 +374,48 @@ - - - - - - - - - - + + + + + + + + Date: Wed, 8 Oct 2025 21:12:14 -0300 Subject: [PATCH 09/52] faet: query action save --- Flow.Launcher/Storage/History.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 5a94c8a8a75..33128256efd 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -20,7 +20,7 @@ public class History private int _maxHistory = 300; public void AddToHistory(Result result, Settings settings) - { + { if (settings.ShowHistoryQueryResultsForHomePage) { AddLastQuery(result); @@ -44,7 +44,7 @@ private void AddLastQuery(Result result) QueryHistoryItems.RemoveAt(0); } - if (QueryHistoryItems.Count > 0 && QueryHistoryItems.Last().OriginQuery == result.OriginQuery) + if (QueryHistoryItems.Count > 0 && QueryHistoryItems.Last().OriginQuery.RawQuery == result.OriginQuery.RawQuery) { QueryHistoryItems.Last().ExecutedDateTime = DateTime.Now; } @@ -53,7 +53,13 @@ private void AddLastQuery(Result result) QueryHistoryItems.Add(new HistoryItem { OriginQuery = result.OriginQuery, - ExecutedDateTime = DateTime.Now + ExecutedDateTime = DateTime.Now, + QueryAction = _ => + { + App.API.BackToQueryResults(); + App.API.ChangeQuery(result.OriginQuery.RawQuery); + return false; + } }); } } @@ -68,6 +74,7 @@ private void AddLastOpened(Result result) PluginID = result.PluginID, OriginQuery = result.OriginQuery, ExecutedDateTime = DateTime.Now, + ExecuteAction = result.Action }; var existing = LastOpenedHistoryItems. From 06711d3b8b55b7d3d8bca37e99e4d0a7c1fb8f6b Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 8 Oct 2025 21:12:36 -0300 Subject: [PATCH 10/52] feat: Saving actions for history --- Flow.Launcher/Storage/HistoryItem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index cb95e75d12d..e8838d16936 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -14,6 +14,9 @@ public class HistoryItem public string PluginID { get; set; } = string.Empty; public Query OriginQuery { get; set; } = null!; public DateTime ExecutedDateTime { get; set; } + public Func ExecuteAction { get; set; } + public Func QueryAction { get; set; } + public string GetTimeAgo() { From c051c5cd50b8c997f59818f5b809040b980ea2c4 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 8 Oct 2025 21:15:10 -0300 Subject: [PATCH 11/52] feat: new history logic in MainViewModel --- .../UserSettings/Settings.cs | 22 +++++++++++ Flow.Launcher/ViewModel/MainViewModel.cs | 37 +++---------------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index e33bf04ac36..0c839c497f3 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -215,6 +215,28 @@ public bool ShowHomePage } } } + private bool _showHistoryOnHomePage = true; + public bool ShowHistoryOnHomePage + { + get + { + if (ShowHistoryQueryResultsForHomePage || ShowHistoryLastOpenedResultsForHomePage) return true; + return _showHistoryOnHomePage; + } + set + { + if (_showHistoryOnHomePage != value) + { + _showHistoryOnHomePage = value; + OnPropertyChanged(); + if (value == false) + { + ShowHistoryQueryResultsForHomePage = false; + ShowHistoryLastOpenedResultsForHomePage = false; + } + } + } + } private bool _showHistoryQueryResultsForHomePage = false; public bool ShowHistoryQueryResultsForHomePage diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d4dda62aab3..23dac59e981 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -536,7 +536,10 @@ private async Task OpenResultAsync(string index) if (QueryResultsSelected()) { - _history.AddToHistory(result, Settings); + if (Settings.ShowHistoryOnHomePage) + { + _history.AddToHistory(result, Settings); + } _userSelectedRecord.Add(result); lastHistoryIndex = 1; } @@ -1320,38 +1323,8 @@ private void QueryHistory() private List GetHistoryResults(IEnumerable historyItems) { var results = new List(); - Func defaultAction = _ => false; - foreach (var h in historyItems) { - // Achar uma forma melhor de fazer isso - if (Settings.ShowHistoryLastOpenedResultsForHomePage) - { - var pluginPair = PluginManager.GetPluginForId(h.PluginID); - if (pluginPair != null) - { - var queryResults = PluginManager - .QueryForPluginAsync(pluginPair, h.OriginQuery, CancellationToken.None) - .GetAwaiter() - .GetResult(); - var originalResult = queryResults?.FirstOrDefault(r => - r.Title == h.Title && r.SubTitle == h.SubTitle); - if (originalResult?.Action != null) - { - defaultAction = originalResult.Action; - } - - } - } - else - { - defaultAction = _ => - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(h.OriginQuery.RawQuery); - return false; - }; - } var timeT = App.API.GetTranslation("lastExecuteTime"); var result = new Result { @@ -1360,7 +1333,7 @@ private List GetHistoryResults(IEnumerable historyItems) IcoPath = Constant.HistoryIcon, PluginID = h.PluginID, OriginQuery = h.OriginQuery, - Action = defaultAction, + Action = Settings.ShowHistoryLastOpenedResultsForHomePage ? h.ExecuteAction : h.QueryAction, Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") }; results.Add(result); From b290055e83cedecd59019cd03e8b843fc255e243 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 8 Oct 2025 21:25:13 -0300 Subject: [PATCH 12/52] feat: up --- Flow.Launcher/ViewModel/MainViewModel.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 23dac59e981..e119ebb2665 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1458,7 +1458,10 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b true => Task.CompletedTask }).ToArray(); - QueryHistoryTask(currentCancellationToken); + if (Settings.ShowHistoryOnHomePage) + { + QueryHistoryTask(currentCancellationToken); + } } else { From 156cb3055c900beff507aee0db7559079a5fa1a1 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 8 Oct 2025 22:06:39 -0300 Subject: [PATCH 13/52] merge --- .../Views/SettingsPaneGeneral.xaml | 72 ++++++---------- Flow.Launcher/ViewModel/MainViewModel.cs | 86 +++++++++++-------- 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index bf7aaecf2c6..ddd7747d14f 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -392,55 +392,37 @@ OnContent="{DynamicResource enable}" /> - + - - - - - - - - - - + + + + + + + + + + + + + + _historyStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord; @@ -241,14 +244,16 @@ async Task UpdateActionAsync() // Indicate if to clear existing results so to show only ones from plugins with action keywords var query = item.Query; var currentIsHomeQuery = query.IsHomeQuery; - var shouldClearExistingResults = ShouldClearExistingResultsForQuery(query, currentIsHomeQuery); + var shouldClearExistingResults = + ShouldClearExistingResultsForQuery(query, currentIsHomeQuery); _lastQuery = item.Query; _previousIsHomeQuery = currentIsHomeQuery; // If the queue already has the item, we need to pass the shouldClearExistingResults flag if (queue.TryGetValue(item.ID, out var existingItem)) { - item.ShouldClearExistingResults = shouldClearExistingResults || existingItem.ShouldClearExistingResults; + item.ShouldClearExistingResults = shouldClearExistingResults || + existingItem.ShouldClearExistingResults; } else { @@ -319,7 +324,7 @@ public void RegisterResultsUpdatedEvent() App.API.LogDebug(ClassName, $"Update results for plugin <{pair.Metadata.Name}>"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, - token))) + token))) { App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } @@ -422,9 +427,11 @@ private void LoadContextMenu() if (result is DialogJumpResult dialogJumpResult) { Win32Helper.SetForegroundWindow(DialogWindowHandle); - _ = Task.Run(() => DialogJump.JumpToPathAsync(DialogWindowHandle, dialogJumpResult.DialogJumpPath)); + _ = Task.Run(() => + DialogJump.JumpToPathAsync(DialogWindowHandle, dialogJumpResult.DialogJumpPath)); } } + return; } @@ -540,12 +547,14 @@ private async Task OpenResultAsync(string index) { _history.AddToHistory(result, Settings); } + _userSelectedRecord.Add(result); lastHistoryIndex = 1; } } - private static IReadOnlyList DeepCloneResults(IReadOnlyList results, bool isDialogJump, CancellationToken token = default) + private static IReadOnlyList DeepCloneResults(IReadOnlyList results, bool isDialogJump, + CancellationToken token = default) { var resultsCopy = new List(); @@ -569,7 +578,7 @@ private static IReadOnlyList DeepCloneResults(IReadOnlyList resu resultsCopy.Add(resultCopy); } } - + return resultsCopy; } @@ -619,7 +628,8 @@ private void SelectPrevItem() var historyItems = _history.GetHistoryItems(Settings); 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. + && 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. && historyItems.Count > 0) // Have history items { lastHistoryIndex = 1; @@ -692,6 +702,7 @@ public void CopyAlternative() public bool GameModeStatus { get; set; } = false; private string _queryText; + public string QueryText { get => _queryText; @@ -853,7 +864,8 @@ private ResultsViewModel SelectedResults // If we are returning from history and we have not set select item yet, // we need to clear the preview selected item - if (isReturningFromHistory && _selectedItemFromQueryResults.HasValue && (!_selectedItemFromQueryResults.Value)) + if (isReturningFromHistory && _selectedItemFromQueryResults.HasValue && + (!_selectedItemFromQueryResults.Value)) { PreviewSelectedItem = null; } @@ -871,6 +883,7 @@ private ResultsViewModel SelectedResults ContextMenu.Visibility = Visibility.Visible; History.Visibility = Visibility.Collapsed; } + _queryTextBeforeLeaveResults = QueryText; // Because of Fody's optimization @@ -886,7 +899,8 @@ private ResultsViewModel SelectedResults { // If we are returning from query results and we have not set select item yet, // we need to clear the preview selected item - if (isReturningFromQueryResults && _selectedItemFromQueryResults.HasValue && _selectedItemFromQueryResults.Value) + if (isReturningFromQueryResults && _selectedItemFromQueryResults.HasValue && + _selectedItemFromQueryResults.Value) { PreviewSelectedItem = null; } @@ -896,7 +910,9 @@ private ResultsViewModel SelectedResults } public Visibility ShowCustomizedPreview - => InternalPreviewVisible && PreviewSelectedItem?.Result.PreviewPanel != null ? Visibility.Visible : Visibility.Collapsed; + => InternalPreviewVisible && PreviewSelectedItem?.Result.PreviewPanel != null + ? Visibility.Visible + : Visibility.Collapsed; public UserControl CustomizedPreviewControl => ShowCustomizedPreview == Visibility.Visible ? PreviewSelectedItem?.Result.PreviewPanel.Value : null; @@ -917,9 +933,10 @@ public UserControl CustomizedPreviewControl public double SearchIconOpacity { get; set; } = 1; private string _placeholderText; + public string PlaceholderText { - get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder(): _placeholderText; + get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder() : _placeholderText; set { _placeholderText = value; @@ -1015,6 +1032,7 @@ private static string VerifyOrSetDefaultHotkey(string hotkey, string defaultHotk private bool? _selectedItemFromQueryResults; private ResultViewModel _previewSelectedItem; + public ResultViewModel PreviewSelectedItem { get => _previewSelectedItem; @@ -1035,7 +1053,8 @@ public bool InternalPreviewVisible if (ResultAreaColumn == ResultAreaColumnPreviewHidden) return false; #if DEBUG - throw new NotImplementedException("ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value"); + throw new NotImplementedException( + "ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value"); #else App.API.LogError(ClassName, "ResultAreaColumnPreviewHidden/ResultAreaColumnPreviewShown int value not implemented", "InternalPreviewVisible"); return false; @@ -1161,6 +1180,7 @@ when CanExternalPreviewSelectedResult(out var path): HideInternalPreview(); _ = OpenExternalPreviewAsync(path); } + break; case true when !CanExternalPreviewSelectedResult(out var _): @@ -1169,6 +1189,7 @@ when CanExternalPreviewSelectedResult(out var path): await CloseExternalPreviewAsync(); ShowInternalPreview(); } + break; case false when InternalPreviewVisible: @@ -1257,10 +1278,7 @@ private void QueryContextMenu() List results; if (selected.PluginID == null) // SelectedItem from history in home page. { - results = new() - { - ContextMenuTopMost(selected) - }; + results = new() { ContextMenuTopMost(selected) }; } else { @@ -1272,20 +1290,19 @@ private void QueryContextMenu() if (!string.IsNullOrEmpty(query)) { var filtered = results.Select(x => x.Clone()).Where - ( - r => + (r => + { + var match = App.API.FuzzySearch(query, r.Title); + if (!match.IsSearchPrecisionScoreMet()) { - var match = App.API.FuzzySearch(query, r.Title); - if (!match.IsSearchPrecisionScoreMet()) - { - match = App.API.FuzzySearch(query, r.SubTitle); - } + match = App.API.FuzzySearch(query, r.SubTitle); + } - if (!match.IsSearchPrecisionScoreMet()) return false; + if (!match.IsSearchPrecisionScoreMet()) return false; - r.Score = match.Score; - return true; - }).ToList(); + r.Score = match.Score; + return true; + }).ToList(); ContextMenu.AddResults(filtered, id); } else @@ -1308,9 +1325,8 @@ private void QueryHistory() if (!string.IsNullOrEmpty(query)) { var filtered = results.Where - ( - r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || - App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() + (r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || + App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() ).ToList(); History.AddResults(filtered, id); } @@ -1320,14 +1336,15 @@ private void QueryHistory() } } - private List GetHistoryResults(IEnumerable historyItems) + private List GetHistoryResults(IEnumerable historyItems) { var results = new List(); foreach (var h in historyItems) { var result = new Result { - Title = Settings.ShowHistoryLastOpenedResultsForHomePage ? Localize.executeQuery(h.Query) : h.Title + Title = + Settings.ShowHistoryQueryResultsForHomePage ? Localize.executeQuery(h.OriginQuery.RawQuery) : h.Title, SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), IcoPath = Constant.HistoryIcon, PluginID = h.PluginID, @@ -1337,10 +1354,11 @@ private List GetHistoryResults(IEnumerable historyItems) }; results.Add(result); } + return results; } - private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) + private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) { _updateSource?.Cancel(); From d122276e7193060e1eed9b4ccb7e766405033127 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 8 Oct 2025 22:09:09 -0300 Subject: [PATCH 14/52] feat: clean imports --- Flow.Launcher/Storage/HistoryItem.cs | 39 ---------------------------- 1 file changed, 39 deletions(-) diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index e8838d16936..d7503108ca8 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; @@ -17,39 +13,4 @@ public class HistoryItem public Func ExecuteAction { get; set; } public Func QueryAction { get; set; } - - public string GetTimeAgo() - { - return DateTimeAgo(ExecutedDateTime); - } - - private string DateTimeAgo(DateTime dt) - { - var span = DateTime.Now - dt; - if (span.Days > 365) - { - int years = (span.Days / 365); - if (span.Days % 365 != 0) - years += 1; - return $"about {years} {(years == 1 ? "year" : "years")} ago"; - } - if (span.Days > 30) - { - int months = (span.Days / 30); - if (span.Days % 31 != 0) - months += 1; - return $"about {months} {(months == 1 ? "month" : "months")} ago"; - } - if (span.Days > 0) - return $"about {span.Days} {(span.Days == 1 ? "day" : "days")} ago"; - if (span.Hours > 0) - return $"about {span.Hours} {(span.Hours == 1 ? "hour" : "hours")} ago"; - if (span.Minutes > 0) - return $"about {span.Minutes} {(span.Minutes == 1 ? "minute" : "minutes")} ago"; - if (span.Seconds > 5) - return $"about {span.Seconds} seconds ago"; - if (span.Seconds <= 5) - return "just now"; - return string.Empty; - } } From 50f5e850dd4e45d698dd7e891c4de3f0fbe5961d Mon Sep 17 00:00:00 2001 From: 01Dri Date: Thu, 9 Oct 2025 23:47:59 -0300 Subject: [PATCH 15/52] feat: code quality --- Flow.Launcher/Storage/History.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 33128256efd..9155f02d891 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -32,8 +32,7 @@ public void AddToHistory(Result result, Settings settings) public List GetHistoryItems(Settings settings) { if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems; - if (settings.ShowHistoryLastOpenedResultsForHomePage) return LastOpenedHistoryItems; - return new List(); + return LastOpenedHistoryItems; } private void AddLastQuery(Result result) From 545c4208d95aaef87f4bed87092739e9bd09020d Mon Sep 17 00:00:00 2001 From: 01Dri Date: Fri, 10 Oct 2025 00:07:24 -0300 Subject: [PATCH 16/52] code quality --- Flow.Launcher/ViewModel/MainViewModel.cs | 72 ++++++++++-------------- 1 file changed, 29 insertions(+), 43 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ef2aea86878..7512ae4c2b7 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -40,9 +40,7 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private Query _lastQuery; private bool _previousIsHomeQuery; private string _queryTextBeforeLeaveResults; - - private string - _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results + private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results private readonly FlowLauncherJsonStorage _historyStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; @@ -156,7 +154,6 @@ public MainViewModel() _userSelectedRecordStorage = new FlowLauncherJsonStorage(); _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); - _history = _historyStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load(); @@ -244,16 +241,14 @@ async Task UpdateActionAsync() // Indicate if to clear existing results so to show only ones from plugins with action keywords var query = item.Query; var currentIsHomeQuery = query.IsHomeQuery; - var shouldClearExistingResults = - ShouldClearExistingResultsForQuery(query, currentIsHomeQuery); + var shouldClearExistingResults = ShouldClearExistingResultsForQuery(query, currentIsHomeQuery); _lastQuery = item.Query; _previousIsHomeQuery = currentIsHomeQuery; // If the queue already has the item, we need to pass the shouldClearExistingResults flag if (queue.TryGetValue(item.ID, out var existingItem)) { - item.ShouldClearExistingResults = shouldClearExistingResults || - existingItem.ShouldClearExistingResults; + item.ShouldClearExistingResults = shouldClearExistingResults || existingItem.ShouldClearExistingResults; } else { @@ -324,7 +319,7 @@ public void RegisterResultsUpdatedEvent() App.API.LogDebug(ClassName, $"Update results for plugin <{pair.Metadata.Name}>"); if (!_resultsUpdateChannelWriter.TryWrite(new ResultsForUpdate(resultsCopy, pair.Metadata, e.Query, - token))) + token))) { App.API.LogError(ClassName, "Unable to add item to Result Update Queue"); } @@ -427,8 +422,7 @@ private void LoadContextMenu() if (result is DialogJumpResult dialogJumpResult) { Win32Helper.SetForegroundWindow(DialogWindowHandle); - _ = Task.Run(() => - DialogJump.JumpToPathAsync(DialogWindowHandle, dialogJumpResult.DialogJumpPath)); + _ = Task.Run(() => DialogJump.JumpToPathAsync(DialogWindowHandle, dialogJumpResult.DialogJumpPath)); } } @@ -553,8 +547,7 @@ private async Task OpenResultAsync(string index) } } - private static IReadOnlyList DeepCloneResults(IReadOnlyList results, bool isDialogJump, - CancellationToken token = default) + private static IReadOnlyList DeepCloneResults(IReadOnlyList results, bool isDialogJump, CancellationToken token = default) { var resultsCopy = new List(); @@ -578,7 +571,6 @@ private static IReadOnlyList DeepCloneResults(IReadOnlyList resu resultsCopy.Add(resultCopy); } } - return resultsCopy; } @@ -628,9 +620,8 @@ private void SelectPrevItem() var historyItems = _history.GetHistoryItems(Settings); 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. - && historyItems.Count > 0) // Have history items + && 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. + && historyItems.Count > 0) { lastHistoryIndex = 1; ReverseHistory(); @@ -702,7 +693,6 @@ public void CopyAlternative() public bool GameModeStatus { get; set; } = false; private string _queryText; - public string QueryText { get => _queryText; @@ -864,8 +854,7 @@ private ResultsViewModel SelectedResults // If we are returning from history and we have not set select item yet, // we need to clear the preview selected item - if (isReturningFromHistory && _selectedItemFromQueryResults.HasValue && - (!_selectedItemFromQueryResults.Value)) + if (isReturningFromHistory && _selectedItemFromQueryResults.HasValue && (!_selectedItemFromQueryResults.Value)) { PreviewSelectedItem = null; } @@ -883,7 +872,6 @@ private ResultsViewModel SelectedResults ContextMenu.Visibility = Visibility.Visible; History.Visibility = Visibility.Collapsed; } - _queryTextBeforeLeaveResults = QueryText; // Because of Fody's optimization @@ -899,8 +887,7 @@ private ResultsViewModel SelectedResults { // If we are returning from query results and we have not set select item yet, // we need to clear the preview selected item - if (isReturningFromQueryResults && _selectedItemFromQueryResults.HasValue && - _selectedItemFromQueryResults.Value) + if (isReturningFromQueryResults && _selectedItemFromQueryResults.HasValue && _selectedItemFromQueryResults.Value) { PreviewSelectedItem = null; } @@ -910,9 +897,7 @@ private ResultsViewModel SelectedResults } public Visibility ShowCustomizedPreview - => InternalPreviewVisible && PreviewSelectedItem?.Result.PreviewPanel != null - ? Visibility.Visible - : Visibility.Collapsed; + => InternalPreviewVisible && PreviewSelectedItem?.Result.PreviewPanel != null ? Visibility.Visible : Visibility.Collapsed; public UserControl CustomizedPreviewControl => ShowCustomizedPreview == Visibility.Visible ? PreviewSelectedItem?.Result.PreviewPanel.Value : null; @@ -933,7 +918,6 @@ public UserControl CustomizedPreviewControl public double SearchIconOpacity { get; set; } = 1; private string _placeholderText; - public string PlaceholderText { get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder() : _placeholderText; @@ -1032,7 +1016,6 @@ private static string VerifyOrSetDefaultHotkey(string hotkey, string defaultHotk private bool? _selectedItemFromQueryResults; private ResultViewModel _previewSelectedItem; - public ResultViewModel PreviewSelectedItem { get => _previewSelectedItem; @@ -1053,8 +1036,7 @@ public bool InternalPreviewVisible if (ResultAreaColumn == ResultAreaColumnPreviewHidden) return false; #if DEBUG - throw new NotImplementedException( - "ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value"); + throw new NotImplementedException("ResultAreaColumn should match ResultAreaColumnPreviewShown/ResultAreaColumnPreviewHidden value"); #else App.API.LogError(ClassName, "ResultAreaColumnPreviewHidden/ResultAreaColumnPreviewShown int value not implemented", "InternalPreviewVisible"); return false; @@ -1189,7 +1171,6 @@ when CanExternalPreviewSelectedResult(out var path): await CloseExternalPreviewAsync(); ShowInternalPreview(); } - break; case false when InternalPreviewVisible: @@ -1278,7 +1259,10 @@ private void QueryContextMenu() List results; if (selected.PluginID == null) // SelectedItem from history in home page. { - results = new() { ContextMenuTopMost(selected) }; + results = new() + { + ContextMenuTopMost(selected) + }; } else { @@ -1290,15 +1274,16 @@ private void QueryContextMenu() if (!string.IsNullOrEmpty(query)) { var filtered = results.Select(x => x.Clone()).Where - (r => - { - var match = App.API.FuzzySearch(query, r.Title); - if (!match.IsSearchPrecisionScoreMet()) - { - match = App.API.FuzzySearch(query, r.SubTitle); - } + ( + r => + { + var match = App.API.FuzzySearch(query, r.Title); + if (!match.IsSearchPrecisionScoreMet()) + { + match = App.API.FuzzySearch(query, r.SubTitle); + } - if (!match.IsSearchPrecisionScoreMet()) return false; + if (!match.IsSearchPrecisionScoreMet()) return false; r.Score = match.Score; return true; @@ -1325,9 +1310,10 @@ private void QueryHistory() if (!string.IsNullOrEmpty(query)) { var filtered = results.Where - (r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || - App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() - ).ToList(); + ( + r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || + App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() + ).ToList(); History.AddResults(filtered, id); } else From 8e8e9d35ac0eef9760c29a2ab3660573cffb6b87 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Fri, 10 Oct 2025 00:08:27 -0300 Subject: [PATCH 17/52] code quality --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 7512ae4c2b7..ad530cc1d5d 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -10,12 +10,10 @@ using System.Windows; using System.Windows.Input; using System.Windows.Controls; -using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.Input; -using Droplex; using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.DialogJump; From 9e1b8c1a729fddef291332bc30443d1cb512b93c Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 02:43:27 -0300 Subject: [PATCH 18/52] feat: Populate new history system with legacy query history --- Flow.Launcher/Storage/History.cs | 96 ++++++++++++++++------ Flow.Launcher/Storage/HistoryItem.cs | 6 +- Flow.Launcher/Storage/HistoryItemLegacy.cs | 13 +++ Flow.Launcher/Storage/HistoryLegacy.cs | 12 +++ Flow.Launcher/ViewModel/MainViewModel.cs | 24 +++--- 5 files changed, 114 insertions(+), 37 deletions(-) create mode 100644 Flow.Launcher/Storage/HistoryItemLegacy.cs create mode 100644 Flow.Launcher/Storage/HistoryLegacy.cs diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 9155f02d891..0dd1925582a 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -1,38 +1,89 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Flow.Launcher.Infrastructure.UserSettings; +using System.Threading; +using Flow.Launcher.Core.Plugin; using Flow.Launcher.Plugin; -using JetBrains.Annotations; namespace Flow.Launcher.Storage { + public class History { - [JsonInclude] - public List LastOpenedHistoryItems { get; private set; } = []; - [JsonInclude] - public List QueryHistoryItems { get; private set; } = []; + //Legacy + [JsonInclude] public List Items { get; private set; } = []; + [JsonInclude] public List LastOpenedHistoryItems { get; private set; } = []; + [JsonInclude] public List QueryHistoryItems { get; private set; } = []; private int _maxHistory = 300; - public void AddToHistory(Result result, Settings settings) - { - if (settings.ShowHistoryQueryResultsForHomePage) + public void AddToHistory(Result result, bool isQuery) + { + if (isQuery) { - AddLastQuery(result); + AddLastQuery(result); return; } + AddLastOpened(result); } - public List GetHistoryItems(Settings settings) - { - if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems; - return LastOpenedHistoryItems; + + + public List GetHistoryItems(bool isQuery) + { + if (isQuery) return PopulateActions(QueryHistoryItems, isQuery); + return PopulateActions(LastOpenedHistoryItems, isQuery); + } + + public void PopulateHistoryWithLegacyHistory() + { + foreach (var item in Items) + { + QueryHistoryItems.Add(new HistoryItem + { + RawQuery = item.Query, + ExecutedDateTime = item.ExecutedDateTime ?? DateTime.Now, + QueryAction = GetQueryAction(item.Query) + }); + } + if (Items.Any()) Items.Clear(); + } + + private List PopulateActions(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.RawQuery); + if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.RawQuery, item.Title, item.SubTitle); + } + + return items; + } + + private Func GetExecuteAction(string pluginId, string rawQuery, string title, string subTitle) + { + var plugin = PluginManager.GetPluginForId(pluginId); + + var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins); + var freshResults = plugin.Plugin + .QueryAsync(query, CancellationToken.None) + .GetAwaiter() + .GetResult(); + return freshResults?.FirstOrDefault(r => r.Title == title + && r.SubTitle == subTitle)?.Action; + } + private Func GetQueryAction(string query) + { + return _=> + { + App.API.BackToQueryResults(); + App.API.ChangeQuery(query); + return false; + }; } private void AddLastQuery(Result result) @@ -43,7 +94,7 @@ private void AddLastQuery(Result result) QueryHistoryItems.RemoveAt(0); } - if (QueryHistoryItems.Count > 0 && QueryHistoryItems.Last().OriginQuery.RawQuery == result.OriginQuery.RawQuery) + if (QueryHistoryItems.Count > 0 && QueryHistoryItems.Last().RawQuery == result.OriginQuery.RawQuery) { QueryHistoryItems.Last().ExecutedDateTime = DateTime.Now; } @@ -51,14 +102,9 @@ private void AddLastQuery(Result result) { QueryHistoryItems.Add(new HistoryItem { - OriginQuery = result.OriginQuery, + RawQuery = result.OriginQuery.RawQuery, ExecutedDateTime = DateTime.Now, - QueryAction = _ => - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(result.OriginQuery.RawQuery); - return false; - } + QueryAction = GetQueryAction(result.OriginQuery.RawQuery) }); } } @@ -71,7 +117,7 @@ private void AddLastOpened(Result result) SubTitle = result.SubTitle, IcoPath = result.IcoPath ?? string.Empty, PluginID = result.PluginID, - OriginQuery = result.OriginQuery, + RawQuery = result.OriginQuery.RawQuery, ExecutedDateTime = DateTime.Now, ExecuteAction = result.Action }; diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index d7503108ca8..fb63aeffca8 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -1,4 +1,5 @@ using System; +using System.Text.Json.Serialization; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; @@ -8,9 +9,12 @@ public class HistoryItem public string SubTitle { get; set; } = string.Empty; public string IcoPath { get; set; } = string.Empty; public string PluginID { get; set; } = string.Empty; - public Query OriginQuery { get; set; } = null!; + public string RawQuery { get; set; } + public DateTime ExecutedDateTime { get; set; } + [JsonIgnore] public Func ExecuteAction { get; set; } + [JsonIgnore] public Func QueryAction { get; set; } } diff --git a/Flow.Launcher/Storage/HistoryItemLegacy.cs b/Flow.Launcher/Storage/HistoryItemLegacy.cs new file mode 100644 index 00000000000..1ae62ff9ecc --- /dev/null +++ b/Flow.Launcher/Storage/HistoryItemLegacy.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Flow.Launcher.Storage; +public class HistoryItemLegacy +{ + public string Query { get; set; } + public DateTime? ExecutedDateTime { get; set; } + +} diff --git a/Flow.Launcher/Storage/HistoryLegacy.cs b/Flow.Launcher/Storage/HistoryLegacy.cs new file mode 100644 index 00000000000..8311c0a8d50 --- /dev/null +++ b/Flow.Launcher/Storage/HistoryLegacy.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Flow.Launcher.Storage; +public class HistoryLegacy +{ + [JsonInclude] public List Items { get; private set; } = []; +} diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ad530cc1d5d..db67539aac9 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -153,6 +153,7 @@ public MainViewModel() _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); _history = _historyStorage.Load(); + _history.PopulateHistoryWithLegacyHistory(); _userSelectedRecord = _userSelectedRecordStorage.Load(); ContextMenu = new ResultsViewModel(Settings, this) @@ -354,7 +355,7 @@ private void LoadHistory() if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _history.GetHistoryItems(Settings).Count - 1; + History.SelectedIndex = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage).Count - 1; } else { @@ -382,10 +383,10 @@ public void ReQuery(bool reselect) [RelayCommand] public void ReverseHistory() { - var historyItems = _history.GetHistoryItems(Settings); + var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); if (historyItems.Count > 0) { - ChangeQueryText(historyItems[^lastHistoryIndex].OriginQuery.RawQuery); + ChangeQueryText(historyItems[^lastHistoryIndex].RawQuery); if (lastHistoryIndex < historyItems.Count) { lastHistoryIndex++; @@ -396,11 +397,11 @@ public void ReverseHistory() [RelayCommand] public void ForwardHistory() { - var historyItems = _history.GetHistoryItems(Settings); + var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); if (historyItems.Count > 0) { - ChangeQueryText(historyItems[^lastHistoryIndex].OriginQuery.RawQuery); + ChangeQueryText(historyItems[^lastHistoryIndex].RawQuery); if (lastHistoryIndex > 1) { lastHistoryIndex--; @@ -537,7 +538,7 @@ private async Task OpenResultAsync(string index) { if (Settings.ShowHistoryOnHomePage) { - _history.AddToHistory(result, Settings); + _history.AddToHistory(result, Settings.ShowHistoryQueryResultsForHomePage); } _userSelectedRecord.Add(result); @@ -615,7 +616,7 @@ private void SelectNextPage() [RelayCommand] private void SelectPrevItem() { - var historyItems = _history.GetHistoryItems(Settings); + var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); 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. @@ -1301,7 +1302,7 @@ private void QueryHistory() var query = QueryText.ToLower().Trim(); History.Clear(); - var items = _history.GetHistoryItems(Settings); + var items = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); var results = GetHistoryResults(items); @@ -1323,16 +1324,17 @@ private void QueryHistory() private List GetHistoryResults(IEnumerable historyItems) { var results = new List(); + foreach (var h in historyItems) { var result = new Result { Title = - Settings.ShowHistoryQueryResultsForHomePage ? Localize.executeQuery(h.OriginQuery.RawQuery) : h.Title, + Settings.ShowHistoryQueryResultsForHomePage ? Localize.executeQuery(h.RawQuery) : h.Title, SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), IcoPath = Constant.HistoryIcon, PluginID = h.PluginID, - OriginQuery = h.OriginQuery, + OriginQuery = QueryBuilder.Build(h.RawQuery, PluginManager.NonGlobalPlugins), Action = Settings.ShowHistoryLastOpenedResultsForHomePage ? h.ExecuteAction : h.QueryAction, Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") }; @@ -1568,7 +1570,7 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : 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(Settings).TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage).TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); var results = GetHistoryResults(historyItems); From bf2acfec3880b9708b833e22e9a944ba14432524 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 02:54:29 -0300 Subject: [PATCH 19/52] feat: code quality --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 4 ++-- Flow.Launcher/Storage/History.cs | 2 -- Flow.Launcher/Storage/HistoryItem.cs | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 051326dbc2b..20b4fa0164d 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -237,7 +237,7 @@ public bool ShowHistoryOnHomePage } } - private bool _showHistoryQueryResultsForHomePage = false; + private bool _showHistoryQueryResultsForHomePage = true; public bool ShowHistoryQueryResultsForHomePage { get => _showHistoryQueryResultsForHomePage; @@ -257,7 +257,7 @@ public bool ShowHistoryQueryResultsForHomePage } - private bool _showHistoryLastOpenedResultsForHomePage = false; + private bool _showHistoryLastOpenedResultsForHomePage; public bool ShowHistoryLastOpenedResultsForHomePage { get => _showHistoryLastOpenedResultsForHomePage; diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 0dd1925582a..b8a39508893 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -30,7 +30,6 @@ public void AddToHistory(Result result, bool isQuery) } - public List GetHistoryItems(bool isQuery) { if (isQuery) return PopulateActions(QueryHistoryItems, isQuery); @@ -115,7 +114,6 @@ private void AddLastOpened(Result result) { Title = result.Title, SubTitle = result.SubTitle, - IcoPath = result.IcoPath ?? string.Empty, PluginID = result.PluginID, RawQuery = result.OriginQuery.RawQuery, ExecutedDateTime = DateTime.Now, diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index fb63aeffca8..6a06a400a7f 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -7,7 +7,6 @@ public class HistoryItem { public string Title { get; set; } = string.Empty; public string SubTitle { get; set; } = string.Empty; - public string IcoPath { get; set; } = string.Empty; public string PluginID { get; set; } = string.Empty; public string RawQuery { get; set; } From 95122e91f528a24416e7911598801477529b8338 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 02:56:49 -0300 Subject: [PATCH 20/52] feat: code quality --- Flow.Launcher/Storage/History.cs | 3 ++- Flow.Launcher/Storage/HistoryLegacy.cs | 12 ------------ 2 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 Flow.Launcher/Storage/HistoryLegacy.cs diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index b8a39508893..539ec64bb9c 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -30,6 +30,7 @@ public void AddToHistory(Result result, bool isQuery) } + public List GetHistoryItems(bool isQuery) { if (isQuery) return PopulateActions(QueryHistoryItems, isQuery); @@ -121,7 +122,7 @@ private void AddLastOpened(Result result) }; var existing = LastOpenedHistoryItems. - FirstOrDefault(x => x.Title == item.Title && x.PluginID == item.PluginID); + FirstOrDefault(x => x.Title == item.Title && x.SubTitle == item.SubTitle && x.PluginID == item.PluginID); if (existing != null) diff --git a/Flow.Launcher/Storage/HistoryLegacy.cs b/Flow.Launcher/Storage/HistoryLegacy.cs deleted file mode 100644 index 8311c0a8d50..00000000000 --- a/Flow.Launcher/Storage/HistoryLegacy.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; - -namespace Flow.Launcher.Storage; -public class HistoryLegacy -{ - [JsonInclude] public List Items { get; private set; } = []; -} From e6cae1a79bd4d7fe6a38fcf8b616e256ff591e29 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 03:08:23 -0300 Subject: [PATCH 21/52] feat: helper --- Flow.Launcher/Storage/History.cs | 55 ++++++-------------------- Flow.Launcher/Storage/HistoryHelper.cs | 45 +++++++++++++++++++++ Flow.Launcher/Storage/HistoryItem.cs | 3 ++ 3 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 Flow.Launcher/Storage/HistoryHelper.cs diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 539ec64bb9c..542bfbebcf0 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -2,13 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; -using System.Threading; -using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage { - public class History { //Legacy @@ -30,11 +28,15 @@ public void AddToHistory(Result result, bool isQuery) } - - public List GetHistoryItems(bool isQuery) + public List GetHistoryItems(Settings settings) { - if (isQuery) return PopulateActions(QueryHistoryItems, isQuery); - return PopulateActions(LastOpenedHistoryItems, isQuery); + if (settings.ShowHistoryOnHomePage) + { + if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems.PopulateActions(true); + return LastOpenedHistoryItems.PopulateActions(false); + } + + return new List(); } public void PopulateHistoryWithLegacyHistory() @@ -45,46 +47,13 @@ public void PopulateHistoryWithLegacyHistory() { RawQuery = item.Query, ExecutedDateTime = item.ExecutedDateTime ?? DateTime.Now, - QueryAction = GetQueryAction(item.Query) + QueryAction = HistoryHelper.GetQueryAction(item.Query) }); } if (Items.Any()) Items.Clear(); } - private List PopulateActions(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.RawQuery); - if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.RawQuery, item.Title, item.SubTitle); - } - - return items; - } - - private Func GetExecuteAction(string pluginId, string rawQuery, string title, string subTitle) - { - var plugin = PluginManager.GetPluginForId(pluginId); - - var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins); - var freshResults = plugin.Plugin - .QueryAsync(query, CancellationToken.None) - .GetAwaiter() - .GetResult(); - return freshResults?.FirstOrDefault(r => r.Title == title - && r.SubTitle == subTitle)?.Action; - } - private Func GetQueryAction(string query) - { - return _=> - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(query); - return false; - }; - } + private void AddLastQuery(Result result) { @@ -104,7 +73,7 @@ private void AddLastQuery(Result result) { RawQuery = result.OriginQuery.RawQuery, ExecutedDateTime = DateTime.Now, - QueryAction = GetQueryAction(result.OriginQuery.RawQuery) + QueryAction = HistoryHelper.GetQueryAction(result.OriginQuery.RawQuery) }); } } diff --git a/Flow.Launcher/Storage/HistoryHelper.cs b/Flow.Launcher/Storage/HistoryHelper.cs new file mode 100644 index 00000000000..9373a439cb6 --- /dev/null +++ b/Flow.Launcher/Storage/HistoryHelper.cs @@ -0,0 +1,45 @@ +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; +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.RawQuery); + if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.RawQuery, item.Title, item.SubTitle); + } + + return items; + } + + private static Func GetExecuteAction(string pluginId, string rawQuery, string title, string subTitle) + { + var plugin = PluginManager.GetPluginForId(pluginId); + + var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins); + var freshResults = plugin.Plugin + .QueryAsync(query, CancellationToken.None) + .GetAwaiter() + .GetResult(); + return freshResults?.FirstOrDefault(r => r.Title == title + && r.SubTitle == subTitle)?.Action; + } + public static Func GetQueryAction(string query) + { + return _ => + { + App.API.BackToQueryResults(); + App.API.ChangeQuery(query); + return false; + }; + } +} diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index 6a06a400a7f..04b97118e0a 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text.Json.Serialization; using Flow.Launcher.Plugin; @@ -16,4 +17,6 @@ public class HistoryItem [JsonIgnore] public Func QueryAction { get; set; } + + } From e468c48da4a4a13148d1eb6cc59a8b3ce666f1aa Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 03:15:10 -0300 Subject: [PATCH 22/52] feat: fix erros --- Flow.Launcher/Storage/History.cs | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 542bfbebcf0..4ae24c202d1 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -91,7 +91,7 @@ private void AddLastOpened(Result result) }; var existing = LastOpenedHistoryItems. - FirstOrDefault(x => x.Title == item.Title && x.SubTitle == item.SubTitle && x.PluginID == item.PluginID); + FirstOrDefault(x => x.Title == item.Title && x.PluginID == item.PluginID); if (existing != null) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index db67539aac9..febb2d05ea7 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -355,7 +355,7 @@ private void LoadHistory() if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage).Count - 1; + History.SelectedIndex = _history.GetHistoryItems(Settings).Count - 1; } else { @@ -383,7 +383,7 @@ public void ReQuery(bool reselect) [RelayCommand] public void ReverseHistory() { - var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); + var historyItems = _history.GetHistoryItems(Settings); if (historyItems.Count > 0) { ChangeQueryText(historyItems[^lastHistoryIndex].RawQuery); @@ -397,7 +397,7 @@ public void ReverseHistory() [RelayCommand] public void ForwardHistory() { - var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); + var historyItems = _history.GetHistoryItems(Settings); if (historyItems.Count > 0) { @@ -616,7 +616,7 @@ private void SelectNextPage() [RelayCommand] private void SelectPrevItem() { - var historyItems = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); + var historyItems = _history.GetHistoryItems(Settings); 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. @@ -1302,7 +1302,7 @@ private void QueryHistory() var query = QueryText.ToLower().Trim(); History.Clear(); - var items = _history.GetHistoryItems(Settings.ShowHistoryQueryResultsForHomePage); + var items = _history.GetHistoryItems(Settings); var results = GetHistoryResults(items); @@ -1570,7 +1570,7 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : 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(Settings.ShowHistoryQueryResultsForHomePage).TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _history.GetHistoryItems(Settings).TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); var results = GetHistoryResults(historyItems); From d7579cce9e85c934e0e33224e98bf1f0cef43596 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 03:23:14 -0300 Subject: [PATCH 23/52] fix erros --- Flow.Launcher/Storage/History.cs | 10 +++++----- Flow.Launcher/ViewModel/MainViewModel.cs | 6 +----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 4ae24c202d1..d99bfbfdbf1 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -16,14 +16,14 @@ public class History private int _maxHistory = 300; - public void AddToHistory(Result result, bool isQuery) + public void AddToHistory(Result result, Settings settings) { - if (isQuery) - { - AddLastQuery(result); + if (!settings.ShowHistoryOnHomePage) return; + if (settings.ShowHistoryQueryResultsForHomePage) + { + AddLastQuery(result); return; } - AddLastOpened(result); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index febb2d05ea7..77fa6426d2b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -536,11 +536,7 @@ private async Task OpenResultAsync(string index) if (QueryResultsSelected()) { - if (Settings.ShowHistoryOnHomePage) - { - _history.AddToHistory(result, Settings.ShowHistoryQueryResultsForHomePage); - } - + _history.AddToHistory(result, Settings); _userSelectedRecord.Add(result); lastHistoryIndex = 1; } From 690d33ece31434103eb1e165a65361e82aaf1bcb Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 03:43:06 -0300 Subject: [PATCH 24/52] up --- Flow.Launcher/Storage/History.cs | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index d99bfbfdbf1..a11222db8ad 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -39,7 +39,7 @@ public List GetHistoryItems(Settings settings) return new List(); } - public void PopulateHistoryWithLegacyHistory() + public void PopulateHistoryFromLegacyHistory() { foreach (var item in Items) { diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 77fa6426d2b..45c471527b1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -153,7 +153,7 @@ public MainViewModel() _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); _history = _historyStorage.Load(); - _history.PopulateHistoryWithLegacyHistory(); + _history.PopulateHistoryFromLegacyHistory(); _userSelectedRecord = _userSelectedRecordStorage.Load(); ContextMenu = new ResultsViewModel(Settings, this) From a1f82e1652a0a867291e8e70d75cac8ecf19cc0d Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 03:47:04 -0300 Subject: [PATCH 25/52] refactor: using count for better performance --- Flow.Launcher/Storage/History.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index a11222db8ad..b0fd2a4c991 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -50,7 +50,7 @@ public void PopulateHistoryFromLegacyHistory() QueryAction = HistoryHelper.GetQueryAction(item.Query) }); } - if (Items.Any()) Items.Clear(); + if (Items.Count > 0) Items.Clear(); } From a3b7c6808bb0b8be1ffba786493641c9bdec3792 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 04:29:33 -0300 Subject: [PATCH 26/52] up --- Flow.Launcher/MainWindow.xaml.cs | 1 + Flow.Launcher/Storage/HistoryHelper.cs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index d6bccac4607..e05975ff8f8 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -322,6 +322,7 @@ private void OnLoaded(object sender, RoutedEventArgs e) break; case nameof(Settings.ShowHomePage): case nameof(Settings.ShowHistoryQueryResultsForHomePage): + case nameof(Settings.ShowHistoryLastOpenedResultsForHomePage): if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText)) { _viewModel.QueryResults(); diff --git a/Flow.Launcher/Storage/HistoryHelper.cs b/Flow.Launcher/Storage/HistoryHelper.cs index 9373a439cb6..7da77af2b6d 100644 --- a/Flow.Launcher/Storage/HistoryHelper.cs +++ b/Flow.Launcher/Storage/HistoryHelper.cs @@ -21,10 +21,19 @@ internal static List PopulateActions(this List items, return items; } + public static Func GetQueryAction(string query) + { + return _ => + { + App.API.BackToQueryResults(); + App.API.ChangeQuery(query); + return false; + }; + } + private static Func GetExecuteAction(string pluginId, string rawQuery, string title, string subTitle) { var plugin = PluginManager.GetPluginForId(pluginId); - var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins); var freshResults = plugin.Plugin .QueryAsync(query, CancellationToken.None) @@ -33,13 +42,4 @@ private static Func GetExecuteAction(string pluginId, strin return freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle)?.Action; } - public static Func GetQueryAction(string query) - { - return _ => - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(query); - return false; - }; - } } From 2b7c2048ef007d851ec57321400a09cda5bca5f2 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 11 Oct 2025 05:26:28 -0300 Subject: [PATCH 27/52] up --- Flow.Launcher/Storage/History.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index b0fd2a4c991..346964f9f1b 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -30,13 +30,8 @@ public void AddToHistory(Result result, Settings settings) public List GetHistoryItems(Settings settings) { - if (settings.ShowHistoryOnHomePage) - { - if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems.PopulateActions(true); - return LastOpenedHistoryItems.PopulateActions(false); - } - - return new List(); + if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems.PopulateActions(true); + return LastOpenedHistoryItems.PopulateActions(false); } public void PopulateHistoryFromLegacyHistory() From e3527f47ea8f74119c63758a1437b72fd7f2a957 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Oct 2025 15:27:06 +0800 Subject: [PATCH 28/52] Add RecordKey for precise history matching and refactor Added a `RecordKey` property to `HistoryItem` for unique identification of history records, enabling more accurate matching during queries and executions. Updated `HistoryHelper` methods to utilize `RecordKey` for matching, with fallback to `Title` and `SubTitle`. Enhanced `GetExecuteAction` with error handling, nullable reference types, and improved matching logic. Included `RecordKey` in `History` object creation. Enabled nullable reference types in `HistoryHelper.cs` for better code safety. Refactored code for clarity and maintainability. --- Flow.Launcher/Storage/History.cs | 1 + Flow.Launcher/Storage/HistoryHelper.cs | 44 +++++++++++++++++++------- Flow.Launcher/Storage/HistoryItem.cs | 1 + 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 346964f9f1b..5b69df05636 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -81,6 +81,7 @@ private void AddLastOpened(Result result) SubTitle = result.SubTitle, PluginID = result.PluginID, RawQuery = result.OriginQuery.RawQuery, + RecordKey = result.RecordKey, ExecutedDateTime = DateTime.Now, ExecuteAction = result.Action }; diff --git a/Flow.Launcher/Storage/HistoryHelper.cs b/Flow.Launcher/Storage/HistoryHelper.cs index 7da77af2b6d..bb7f62eba99 100644 --- a/Flow.Launcher/Storage/HistoryHelper.cs +++ b/Flow.Launcher/Storage/HistoryHelper.cs @@ -6,40 +6,62 @@ using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; + +#nullable enable + public static class HistoryHelper { - internal static List PopulateActions(this List items, bool isQuery) + 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.RawQuery); - if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.RawQuery, item.Title, item.SubTitle); + if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.RawQuery, item.Title, item.SubTitle, item.RecordKey) ?? GetQueryAction(item.RawQuery); } return items; } - public static Func GetQueryAction(string query) + public static Func GetQueryAction(string rawQuery) { return _ => { App.API.BackToQueryResults(); - App.API.ChangeQuery(query); + App.API.ChangeQuery(rawQuery); return false; }; } - private static Func GetExecuteAction(string pluginId, string rawQuery, string title, string subTitle) + 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); - var freshResults = plugin.Plugin - .QueryAsync(query, CancellationToken.None) - .GetAwaiter() - .GetResult(); - return freshResults?.FirstOrDefault(r => r.Title == title - && r.SubTitle == subTitle)?.Action; + 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/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index 04b97118e0a..dc058c96091 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -10,6 +10,7 @@ public class HistoryItem public string SubTitle { get; set; } = string.Empty; public string PluginID { get; set; } = string.Empty; public string RawQuery { get; set; } + public string RecordKey { get; set; } = string.Empty; public DateTime ExecutedDateTime { get; set; } [JsonIgnore] From 7fa78f03040620ee6188d481bb3c0b636a179e27 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Mon, 13 Oct 2025 15:30:38 +0800 Subject: [PATCH 29/52] Code cleanup --- Flow.Launcher/Storage/History.cs | 21 ++++++++++++--------- Flow.Launcher/Storage/HistoryItem.cs | 8 +++----- Flow.Launcher/Storage/HistoryItemLegacy.cs | 7 ++----- Flow.Launcher/ViewModel/MainViewModel.cs | 14 ++++++-------- 4 files changed, 23 insertions(+), 27 deletions(-) diff --git a/Flow.Launcher/Storage/History.cs b/Flow.Launcher/Storage/History.cs index 5b69df05636..b7ee8348043 100644 --- a/Flow.Launcher/Storage/History.cs +++ b/Flow.Launcher/Storage/History.cs @@ -10,9 +10,14 @@ namespace Flow.Launcher.Storage public class History { //Legacy - [JsonInclude] public List Items { get; private set; } = []; - [JsonInclude] public List LastOpenedHistoryItems { get; private set; } = []; - [JsonInclude] public List QueryHistoryItems { get; private set; } = []; + [JsonInclude] + public List Items { get; private set; } = []; + + [JsonInclude] + public List LastOpenedHistoryItems { get; private set; } = []; + + [JsonInclude] + public List QueryHistoryItems { get; private set; } = []; private int _maxHistory = 300; @@ -20,7 +25,7 @@ public void AddToHistory(Result result, Settings settings) { if (!settings.ShowHistoryOnHomePage) return; if (settings.ShowHistoryQueryResultsForHomePage) - { + { AddLastQuery(result); return; } @@ -28,7 +33,7 @@ public void AddToHistory(Result result, Settings settings) } - public List GetHistoryItems(Settings settings) + public List GetHistoryItems(Settings settings) { if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems.PopulateActions(true); return LastOpenedHistoryItems.PopulateActions(false); @@ -48,8 +53,6 @@ public void PopulateHistoryFromLegacyHistory() if (Items.Count > 0) Items.Clear(); } - - private void AddLastQuery(Result result) { if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; @@ -83,11 +86,11 @@ private void AddLastOpened(Result result) RawQuery = result.OriginQuery.RawQuery, RecordKey = result.RecordKey, ExecutedDateTime = DateTime.Now, - ExecuteAction = result.Action + ExecuteAction = result.Action }; var existing = LastOpenedHistoryItems. - FirstOrDefault(x => x.Title == item.Title && x.PluginID == item.PluginID); + FirstOrDefault(x => x.Title == item.Title && x.PluginID == item.PluginID); if (existing != null) diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index dc058c96091..dcace8130f6 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -1,9 +1,9 @@ using System; -using System.Collections.Generic; using System.Text.Json.Serialization; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; + public class HistoryItem { public string Title { get; set; } = string.Empty; @@ -11,13 +11,11 @@ public class HistoryItem public string PluginID { get; set; } = string.Empty; public string RawQuery { get; set; } public string RecordKey { get; set; } = string.Empty; - public DateTime ExecutedDateTime { get; set; } + [JsonIgnore] public Func ExecuteAction { get; set; } + [JsonIgnore] public Func QueryAction { get; set; } - - - } diff --git a/Flow.Launcher/Storage/HistoryItemLegacy.cs b/Flow.Launcher/Storage/HistoryItemLegacy.cs index 1ae62ff9ecc..e1e0a12aecc 100644 --- a/Flow.Launcher/Storage/HistoryItemLegacy.cs +++ b/Flow.Launcher/Storage/HistoryItemLegacy.cs @@ -1,13 +1,10 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace Flow.Launcher.Storage; + +[Obsolete] public class HistoryItemLegacy { public string Query { get; set; } public DateTime? ExecutedDateTime { get; set; } - } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 45c471527b1..f378ff39f16 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -8,8 +8,8 @@ using System.Threading.Channels; using System.Threading.Tasks; using System.Windows; -using System.Windows.Input; using System.Windows.Controls; +using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; using CommunityToolkit.Mvvm.DependencyInjection; @@ -1280,9 +1280,9 @@ private void QueryContextMenu() if (!match.IsSearchPrecisionScoreMet()) return false; - r.Score = match.Score; - return true; - }).ToList(); + r.Score = match.Score; + return true; + }).ToList(); ContextMenu.AddResults(filtered, id); } else @@ -1308,7 +1308,7 @@ private void QueryHistory() ( r => App.API.FuzzySearch(query, r.Title).IsSearchPrecisionScoreMet() || App.API.FuzzySearch(query, r.SubTitle).IsSearchPrecisionScoreMet() - ).ToList(); + ).ToList(); History.AddResults(filtered, id); } else @@ -1320,7 +1320,6 @@ private void QueryHistory() private List GetHistoryResults(IEnumerable historyItems) { var results = new List(); - foreach (var h in historyItems) { var result = new Result @@ -1336,11 +1335,10 @@ private List GetHistoryResults(IEnumerable historyItems) }; results.Add(result); } - return results; } - private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) + private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) { _updateSource?.Cancel(); From b84ca9b28373289fc7858a6f3f7c6f217d46bd9a Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 14 Oct 2025 19:39:33 +0800 Subject: [PATCH 30/52] Improve code quality --- Flow.Launcher/Storage/HistoryHelper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Flow.Launcher/Storage/HistoryHelper.cs b/Flow.Launcher/Storage/HistoryHelper.cs index bb7f62eba99..2f58b5bb7be 100644 --- a/Flow.Launcher/Storage/HistoryHelper.cs +++ b/Flow.Launcher/Storage/HistoryHelper.cs @@ -13,7 +13,6 @@ 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; From f6d5a27e0b5169bdcf1d239bd24f92f8b13ac790 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 14 Oct 2025 20:28:39 +0800 Subject: [PATCH 31/52] Refactor and enhance history management system Refactored the `History` class to separate query and last opened history into distinct models, introducing `LastOpenedHistoryItem` and deprecating `HistoryItem`. Added a `HistoryStyle` enum and property to allow users to toggle between "Query History" and "Last Opened History." Simplified history display logic and updated the UI with a dropdown for history style selection. Improved history item display with dynamic action population and relative timestamps. Enhanced performance by optimizing history storage with a maximum limit and streamlined logic for adding/retrieving items. Ensured backward compatibility by migrating legacy history data to the new format. Updated localization strings, removed deprecated properties, and cleaned up redundant code. Fixed bugs related to inconsistent history actions and edge cases with legacy data. --- .../UserSettings/Settings.cs | 83 +++++-------- Flow.Launcher/Languages/en.xaml | 13 +- Flow.Launcher/MainWindow.xaml.cs | 4 +- .../SettingsPaneGeneralViewModel.cs | 3 + .../Views/SettingsPaneGeneral.xaml | 30 +++-- Flow.Launcher/Storage/History.cs | 111 ------------------ Flow.Launcher/Storage/HistoryHelper.cs | 6 +- Flow.Launcher/Storage/HistoryItem.cs | 55 ++++++--- Flow.Launcher/Storage/HistoryItemLegacy.cs | 10 -- .../Storage/LastOpenedHistoryItem.cs | 38 ++++++ Flow.Launcher/Storage/QueryHistory.cs | 76 ++++++++++++ Flow.Launcher/ViewModel/MainViewModel.cs | 56 +++++---- 12 files changed, 246 insertions(+), 239 deletions(-) delete mode 100644 Flow.Launcher/Storage/History.cs delete mode 100644 Flow.Launcher/Storage/HistoryItemLegacy.cs create mode 100644 Flow.Launcher/Storage/LastOpenedHistoryItem.cs create mode 100644 Flow.Launcher/Storage/QueryHistory.cs diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 20b4fa0164d..6adefdb6a21 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -7,6 +7,7 @@ using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Storage; +using Flow.Launcher.Localization.Attributes; using Flow.Launcher.Plugin; using Flow.Launcher.Plugin.SharedModels; @@ -214,64 +215,17 @@ public bool ShowHomePage } } } - private bool _showHistoryOnHomePage = true; - public bool ShowHistoryOnHomePage - { - get - { - if (ShowHistoryQueryResultsForHomePage || ShowHistoryLastOpenedResultsForHomePage) return true; - return _showHistoryOnHomePage; - } - set - { - if (_showHistoryOnHomePage != value) - { - _showHistoryOnHomePage = value; - OnPropertyChanged(); - if (value == false) - { - ShowHistoryQueryResultsForHomePage = false; - ShowHistoryLastOpenedResultsForHomePage = false; - } - } - } - } - private bool _showHistoryQueryResultsForHomePage = true; - public bool ShowHistoryQueryResultsForHomePage + private bool _showHistoryResultsForHomePage = false; + public bool ShowHistoryResultsForHomePage { - get => _showHistoryQueryResultsForHomePage; + get => _showHistoryResultsForHomePage; set { - if (_showHistoryQueryResultsForHomePage != value) + if (_showHistoryResultsForHomePage != value) { - _showHistoryQueryResultsForHomePage = value; + _showHistoryResultsForHomePage = value; OnPropertyChanged(); - if (value && _showHistoryLastOpenedResultsForHomePage) - { - _showHistoryLastOpenedResultsForHomePage = false; - OnPropertyChanged(nameof(ShowHistoryLastOpenedResultsForHomePage)); - } - } - } - } - - - private bool _showHistoryLastOpenedResultsForHomePage; - public bool ShowHistoryLastOpenedResultsForHomePage - { - get => _showHistoryLastOpenedResultsForHomePage; - set - { - if (_showHistoryLastOpenedResultsForHomePage != value) - { - _showHistoryLastOpenedResultsForHomePage = value; - OnPropertyChanged(); - if (value && _showHistoryQueryResultsForHomePage) - { - _showHistoryQueryResultsForHomePage = false; - OnPropertyChanged(nameof(ShowHistoryQueryResultsForHomePage)); - } } } } @@ -560,6 +514,21 @@ public bool ShowAtTopmost [JsonConverter(typeof(JsonStringEnumConverter))] public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected; + private HistoryStyle _historyStyle = HistoryStyle.Query; + [JsonConverter(typeof(JsonStringEnumConverter))] + public HistoryStyle HistoryStyle + { + get => _historyStyle; + set + { + if (_historyStyle != value) + { + _historyStyle = value; + OnPropertyChanged(); + } + } + } + [JsonConverter(typeof(JsonStringEnumConverter))] public AnimationSpeeds AnimationSpeed { get; set; } = AnimationSpeeds.Medium; public int CustomAnimationLength { get; set; } = 360; @@ -742,4 +711,14 @@ public enum DialogJumpFileResultBehaviours FullPathOpen, Directory } + + [EnumLocalize] + public enum HistoryStyle + { + [EnumLocalizeKey(nameof(Localize.queryHistory))] + Query, + + [EnumLocalizeKey(nameof(Localize.executedHistory))] + LastOpened + } } diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 0f44d77df65..dd35bcc1d26 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -164,13 +164,12 @@ Please check your system registry access or contact support. Home Page Show home page results when query text is empty. - Home Page History - Choose the type of history to show on the home page - Query History - Last Opened History - Show Query History - Show Last Opened History - Maximum History Results Shown + Show History Results in Home Page + Maximum History Results Shown in Home Page + History Style + Choose the type of history to show in the history and home page + Query history + Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. Show Search Window at Foremost Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position. diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index e05975ff8f8..88d6b660648 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -321,8 +321,8 @@ private void OnLoaded(object sender, RoutedEventArgs e) InitializeContextMenu(); break; case nameof(Settings.ShowHomePage): - case nameof(Settings.ShowHistoryQueryResultsForHomePage): - case nameof(Settings.ShowHistoryLastOpenedResultsForHomePage): + case nameof(Settings.ShowHistoryResultsForHomePage): + case nameof(Settings.HistoryStyle): if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText)) { _viewModel.QueryResults(); diff --git a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs index 6641ac6895c..aa78849bad9 100644 --- a/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs +++ b/Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs @@ -147,6 +147,8 @@ public bool PortableMode public List LastQueryModes { get; } = DropdownDataGeneric.GetValues("LastQuery"); + public List HistoryStyles { get; } = HistoryStyleLocalized.GetValues(); + public bool EnableDialogJump { get => Settings.EnableDialogJump; @@ -213,6 +215,7 @@ private void UpdateEnumDropdownLocalizations() DropdownDataGeneric.UpdateLabels(SearchWindowAligns); DropdownDataGeneric.UpdateLabels(SearchPrecisionScores); DropdownDataGeneric.UpdateLabels(LastQueryModes); + HistoryStyleLocalized.UpdateLabels(HistoryStyles); DropdownDataGeneric.UpdateLabels(DoublePinyinSchemas); DropdownDataGeneric.UpdateLabels(DialogJumpWindowPositions); DropdownDataGeneric.UpdateLabels(DialogJumpResultBehaviours); diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index ddd7747d14f..0c48b511a89 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -13,7 +13,7 @@ xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure" Title="General" d:DataContext="{d:DesignInstance settingsViewModels:SettingsPaneGeneralViewModel}" - d:DesignHeight="450" + d:DesignHeight="10000" d:DesignWidth="800" mc:Ignorable="d"> @@ -245,6 +245,22 @@ SelectedValuePath="Value" /> + + + + + + + + - + - - - - - - - + Items { get; private set; } = []; - - [JsonInclude] - public List LastOpenedHistoryItems { get; private set; } = []; - - [JsonInclude] - public List QueryHistoryItems { get; private set; } = []; - - private int _maxHistory = 300; - - public void AddToHistory(Result result, Settings settings) - { - if (!settings.ShowHistoryOnHomePage) return; - if (settings.ShowHistoryQueryResultsForHomePage) - { - AddLastQuery(result); - return; - } - AddLastOpened(result); - } - - - public List GetHistoryItems(Settings settings) - { - if (settings.ShowHistoryQueryResultsForHomePage) return QueryHistoryItems.PopulateActions(true); - return LastOpenedHistoryItems.PopulateActions(false); - } - - public void PopulateHistoryFromLegacyHistory() - { - foreach (var item in Items) - { - QueryHistoryItems.Add(new HistoryItem - { - RawQuery = item.Query, - ExecutedDateTime = item.ExecutedDateTime ?? DateTime.Now, - QueryAction = HistoryHelper.GetQueryAction(item.Query) - }); - } - if (Items.Count > 0) Items.Clear(); - } - - private void AddLastQuery(Result result) - { - if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; - if (QueryHistoryItems.Count > _maxHistory) - { - QueryHistoryItems.RemoveAt(0); - } - - if (QueryHistoryItems.Count > 0 && QueryHistoryItems.Last().RawQuery == result.OriginQuery.RawQuery) - { - QueryHistoryItems.Last().ExecutedDateTime = DateTime.Now; - } - else - { - QueryHistoryItems.Add(new HistoryItem - { - RawQuery = result.OriginQuery.RawQuery, - ExecutedDateTime = DateTime.Now, - QueryAction = HistoryHelper.GetQueryAction(result.OriginQuery.RawQuery) - }); - } - } - - private void AddLastOpened(Result result) - { - var item = new HistoryItem - { - Title = result.Title, - SubTitle = result.SubTitle, - PluginID = result.PluginID, - RawQuery = result.OriginQuery.RawQuery, - RecordKey = result.RecordKey, - ExecutedDateTime = DateTime.Now, - ExecuteAction = result.Action - }; - - var existing = LastOpenedHistoryItems. - FirstOrDefault(x => x.Title == item.Title && x.PluginID == item.PluginID); - - - if (existing != null) - { - existing.ExecutedDateTime = DateTime.Now; - } - else - { - if (LastOpenedHistoryItems.Count > _maxHistory) - { - LastOpenedHistoryItems.RemoveAt(0); - } - - LastOpenedHistoryItems.Add(item); - } - } - } -} diff --git a/Flow.Launcher/Storage/HistoryHelper.cs b/Flow.Launcher/Storage/HistoryHelper.cs index 2f58b5bb7be..d9d0ec5a88e 100644 --- a/Flow.Launcher/Storage/HistoryHelper.cs +++ b/Flow.Launcher/Storage/HistoryHelper.cs @@ -11,13 +11,13 @@ namespace Flow.Launcher.Storage; public static class HistoryHelper { - internal static List PopulateActions(this List items, bool isQuery) + 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.RawQuery); - if (!isQuery && item.ExecuteAction == null) item.ExecuteAction = GetExecuteAction(item.PluginID, item.RawQuery, item.Title, item.SubTitle, item.RecordKey) ?? GetQueryAction(item.RawQuery); + 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; diff --git a/Flow.Launcher/Storage/HistoryItem.cs b/Flow.Launcher/Storage/HistoryItem.cs index dcace8130f6..63604d2c842 100644 --- a/Flow.Launcher/Storage/HistoryItem.cs +++ b/Flow.Launcher/Storage/HistoryItem.cs @@ -1,21 +1,46 @@ using System; -using System.Text.Json.Serialization; -using Flow.Launcher.Plugin; -namespace Flow.Launcher.Storage; - -public class HistoryItem +namespace Flow.Launcher.Storage { - public string Title { get; set; } = string.Empty; - public string SubTitle { get; set; } = string.Empty; - public string PluginID { get; set; } = string.Empty; - public string RawQuery { get; set; } - public string RecordKey { get; set; } = string.Empty; - public DateTime ExecutedDateTime { get; set; } + [Obsolete("Use LastOpenedHistoryItem instead. This class will be removed in future versions.")] + public class HistoryItem + { + public string Query { get; set; } + public DateTime ExecutedDateTime { get; set; } - [JsonIgnore] - public Func ExecuteAction { get; set; } + public string GetTimeAgo() + { + return DateTimeAgo(ExecutedDateTime); + } - [JsonIgnore] - public Func QueryAction { get; set; } + private string DateTimeAgo(DateTime dt) + { + var span = DateTime.Now - dt; + if (span.Days > 365) + { + int years = (span.Days / 365); + if (span.Days % 365 != 0) + years += 1; + return $"about {years} {(years == 1 ? "year" : "years")} ago"; + } + if (span.Days > 30) + { + int months = (span.Days / 30); + if (span.Days % 31 != 0) + months += 1; + return $"about {months} {(months == 1 ? "month" : "months")} ago"; + } + if (span.Days > 0) + return $"about {span.Days} {(span.Days == 1 ? "day" : "days")} ago"; + if (span.Hours > 0) + return $"about {span.Hours} {(span.Hours == 1 ? "hour" : "hours")} ago"; + if (span.Minutes > 0) + return $"about {span.Minutes} {(span.Minutes == 1 ? "minute" : "minutes")} ago"; + if (span.Seconds > 5) + return $"about {span.Seconds} seconds ago"; + if (span.Seconds <= 5) + return "just now"; + return string.Empty; + } + } } diff --git a/Flow.Launcher/Storage/HistoryItemLegacy.cs b/Flow.Launcher/Storage/HistoryItemLegacy.cs deleted file mode 100644 index e1e0a12aecc..00000000000 --- a/Flow.Launcher/Storage/HistoryItemLegacy.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System; - -namespace Flow.Launcher.Storage; - -[Obsolete] -public class HistoryItemLegacy -{ - public string Query { get; set; } - public DateTime? ExecutedDateTime { get; set; } -} diff --git a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs new file mode 100644 index 00000000000..c09933cc9c3 --- /dev/null +++ b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs @@ -0,0 +1,38 @@ +using System; +using System.Text.Json.Serialization; +using Flow.Launcher.Plugin; + +namespace Flow.Launcher.Storage; + +public class LastOpenedHistoryItem +{ + public string Title { get; set; } = string.Empty; + public string SubTitle { get; set; } = string.Empty; + public string PluginID { get; set; } = string.Empty; + public string Query { get; set; } = string.Empty; + 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)) + { + return Title == r.Title + && SubTitle == r.SubTitle + && PluginID == r.PluginID + && Query == r.OriginQuery.RawQuery; + } + else + { + return RecordKey == r.RecordKey + && PluginID == r.PluginID + && Query == r.OriginQuery.RawQuery; + } + } +} diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs new file mode 100644 index 00000000000..bd23837f822 --- /dev/null +++ b/Flow.Launcher/Storage/QueryHistory.cs @@ -0,0 +1,76 @@ +using System; +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 +{ + public class History + { + [JsonInclude] +#pragma warning disable CS0618 // Type or member is obsolete + public List Items { get; private set; } = []; +#pragma warning restore CS0618 // Type or member is obsolete + + [JsonInclude] + public List LastOpenedHistoryItems { get; private set; } = []; + + private readonly int _maxHistory = 300; + private static readonly Settings _settings = Ioc.Default.GetRequiredService(); + + public void PopulateHistoryFromLegacyHistory() + { + if (Items.Count == 0) return; + // Migrate old history items to new LastOpenedHistoryItems + foreach (var item in Items) + { + LastOpenedHistoryItems.Add(new LastOpenedHistoryItem + { + Query = item.Query, + ExecutedDateTime = item.ExecutedDateTime, + QueryAction = HistoryHelper.GetQueryAction(item.Query) + }); + } + Items.Clear(); + } + + public void Add(Result result) + { + if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; + + // Maintain the max history limit + if (LastOpenedHistoryItems.Count > _maxHistory) + { + LastOpenedHistoryItems.RemoveAt(0); + } + + // If the last item is the same as the current result, just update the timestamp + if (LastOpenedHistoryItems.Count > 0 && + LastOpenedHistoryItems.Last().Equals(result)) + { + LastOpenedHistoryItems.Last().ExecutedDateTime = DateTime.Now; + } + else + { + LastOpenedHistoryItems.Add(new LastOpenedHistoryItem + { + Title = result.Title, + SubTitle = result.SubTitle, + PluginID = result.PluginID, + Query = result.OriginQuery.RawQuery, + RecordKey = result.RecordKey, + ExecutedDateTime = DateTime.Now, + ExecuteAction = result.Action + }); + } + } + + 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 f378ff39f16..846b46a43c0 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -40,7 +40,7 @@ public partial class MainViewModel : BaseModel, ISavable, IDisposable private string _queryTextBeforeLeaveResults; private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results - private readonly FlowLauncherJsonStorage _historyStorage; + private readonly FlowLauncherJsonStorage _historyItemsStorage; private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord; private readonly History _history; @@ -147,12 +147,10 @@ public MainViewModel() } }; - _historyStorage = new FlowLauncherJsonStorage(); - + _historyItemsStorage = new FlowLauncherJsonStorage(); _userSelectedRecordStorage = new FlowLauncherJsonStorage(); _topMostRecord = new FlowLauncherJsonStorageTopMostRecord(); - - _history = _historyStorage.Load(); + _history = _historyItemsStorage.Load(); _history.PopulateHistoryFromLegacyHistory(); _userSelectedRecord = _userSelectedRecordStorage.Load(); @@ -355,7 +353,7 @@ private void LoadHistory() if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _history.GetHistoryItems(Settings).Count - 1; + History.SelectedIndex = _history.GetHistoryItems().Count - 1; } else { @@ -383,10 +381,10 @@ public void ReQuery(bool reselect) [RelayCommand] public void ReverseHistory() { - var historyItems = _history.GetHistoryItems(Settings); + var historyItems = _history.GetHistoryItems(); if (historyItems.Count > 0) { - ChangeQueryText(historyItems[^lastHistoryIndex].RawQuery); + ChangeQueryText(historyItems[^lastHistoryIndex].Query); if (lastHistoryIndex < historyItems.Count) { lastHistoryIndex++; @@ -397,11 +395,10 @@ public void ReverseHistory() [RelayCommand] public void ForwardHistory() { - var historyItems = _history.GetHistoryItems(Settings); - + var historyItems = _history.GetHistoryItems(); if (historyItems.Count > 0) { - ChangeQueryText(historyItems[^lastHistoryIndex].RawQuery); + ChangeQueryText(historyItems[^lastHistoryIndex].Query); if (lastHistoryIndex > 1) { lastHistoryIndex--; @@ -533,11 +530,10 @@ private async Task OpenResultAsync(string index) Hide(); } } - if (QueryResultsSelected()) { - _history.AddToHistory(result, Settings); _userSelectedRecord.Add(result); + _history.Add(result); lastHistoryIndex = 1; } } @@ -566,6 +562,7 @@ private static IReadOnlyList DeepCloneResults(IReadOnlyList resu resultsCopy.Add(resultCopy); } } + return resultsCopy; } @@ -612,11 +609,11 @@ private void SelectNextPage() [RelayCommand] private void SelectPrevItem() { - var historyItems = _history.GetHistoryItems(Settings); + var historyItems = _history.GetHistoryItems(); 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. - && historyItems.Count > 0) + && historyItems.Count > 0) // Have history items { lastHistoryIndex = 1; ReverseHistory(); @@ -1298,9 +1295,7 @@ private void QueryHistory() var query = QueryText.ToLower().Trim(); History.Clear(); - var items = _history.GetHistoryItems(Settings); - - var results = GetHistoryResults(items); + var results = GetHistoryItems(_history.GetHistoryItems()); if (!string.IsNullOrEmpty(query)) { @@ -1317,20 +1312,22 @@ private void QueryHistory() } } - private List GetHistoryResults(IEnumerable historyItems) + private List GetHistoryItems(IEnumerable historyItems) { var results = new List(); foreach (var h in historyItems) { var result = new Result { - Title = - Settings.ShowHistoryQueryResultsForHomePage ? Localize.executeQuery(h.RawQuery) : h.Title, + Title = Settings.HistoryStyle == HistoryStyle.Query ? + Localize.executeQuery(h.Query) : + 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, - PluginID = h.PluginID, - OriginQuery = QueryBuilder.Build(h.RawQuery, PluginManager.NonGlobalPlugins), - Action = Settings.ShowHistoryLastOpenedResultsForHomePage ? h.ExecuteAction : h.QueryAction, + 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); @@ -1452,7 +1449,8 @@ private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, b true => Task.CompletedTask }).ToArray(); - if (Settings.ShowHistoryOnHomePage) + // Query history results for home page firstly so it will be put on top of the results + if (Settings.ShowHistoryResultsForHomePage) { QueryHistoryTask(currentCancellationToken); } @@ -1564,9 +1562,9 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : 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(Settings).TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); + var historyItems = _history.GetHistoryItems().TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); - var results = GetHistoryResults(historyItems); + var results = GetHistoryItems(historyItems); if (token.IsCancellationRequested) return; @@ -1702,7 +1700,7 @@ private bool ShouldClearExistingResultsForQuery(Query query, bool currentIsHomeQ /// True if existing results should be cleared, false otherwise. private bool ShouldClearExistingResultsForNonQuery(ICollection plugins) { - if (!Settings.ShowHistoryQueryResultsForHomePage && (plugins.Count == 0 || plugins.All(x => x.Metadata.HomeDisabled == true))) + if (!Settings.ShowHistoryResultsForHomePage && (plugins.Count == 0 || plugins.All(x => x.Metadata.HomeDisabled == true))) { App.API.LogDebug(ClassName, $"Existing results should be cleared for non-query"); return true; @@ -2166,7 +2164,7 @@ public async void Hide(bool reset = true) /// public void Save() { - _historyStorage.Save(); + _historyItemsStorage.Save(); _userSelectedRecordStorage.Save(); _topMostRecord.Save(); } From 693bae763138d6ea865f413a5eb7064423437f89 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 14 Oct 2025 20:47:57 +0800 Subject: [PATCH 32/52] Optimize query result selection handling Refactored `QueryResultsSelected()` usage by introducing a local variable `queryResultsSelected` to avoid redundant method calls, improving efficiency and readability. Added a comment to clarify the purpose of the variable. Updated conditional logic to use the new variable instead of directly invoking the method. --- Flow.Launcher/ViewModel/MainViewModel.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 846b46a43c0..ceced2d185f 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -491,6 +491,8 @@ private void AutocompleteQuery() [RelayCommand] private async Task OpenResultAsync(string index) { + // Must check query results selected before executing the action + var queryResultsSelected = QueryResultsSelected(); var results = SelectedResults; if (index is not null) { @@ -530,7 +532,7 @@ private async Task OpenResultAsync(string index) Hide(); } } - if (QueryResultsSelected()) + if (queryResultsSelected) { _userSelectedRecord.Add(result); _history.Add(result); From 787ccad3841849d106a6cdf289b556a14f927ab9 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 14 Oct 2025 21:29:22 +0800 Subject: [PATCH 33/52] 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. --- Flow.Launcher/Helper/ResultHelper.cs | 44 ++++++++++ Flow.Launcher/Storage/HistoryHelper.cs | 66 --------------- .../Storage/LastOpenedHistoryItem.cs | 7 -- Flow.Launcher/Storage/QueryHistory.cs | 14 +--- Flow.Launcher/ViewModel/MainViewModel.cs | 80 ++++++++++++++----- 5 files changed, 108 insertions(+), 103 deletions(-) create mode 100644 Flow.Launcher/Helper/ResultHelper.cs delete mode 100644 Flow.Launcher/Storage/HistoryHelper.cs diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs new file mode 100644 index 00000000000..f99ba037771 --- /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 d9d0ec5a88e..00000000000 --- 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 c09933cc9c3..47647066c91 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 bd23837f822..7d264d09f52 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 @@ public class History 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 @@ public void PopulateHistoryFromLegacyHistory() LastOpenedHistoryItems.Add(new LastOpenedHistoryItem { Query = item.Query, - ExecutedDateTime = item.ExecutedDateTime, - QueryAction = HistoryHelper.GetQueryAction(item.Query) + ExecutedDateTime = item.ExecutedDateTime }); } Items.Clear(); @@ -62,15 +58,9 @@ public void Add(Result result) 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 ceced2d185f..8fd6de6f5f7 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -15,6 +15,7 @@ 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 @@ private void LoadHistory() if (QueryResultsSelected()) { SelectedResults = History; - History.SelectedIndex = _history.GetHistoryItems().Count - 1; + History.SelectedIndex = _history.LastOpenedHistoryItems.Count - 1; } else { @@ -381,7 +382,7 @@ public void ReQuery(bool reselect) [RelayCommand] public void ReverseHistory() { - var historyItems = _history.GetHistoryItems(); + var historyItems = _history.LastOpenedHistoryItems; if (historyItems.Count > 0) { ChangeQueryText(historyItems[^lastHistoryIndex].Query); @@ -395,7 +396,7 @@ public void ReverseHistory() [RelayCommand] public void ForwardHistory() { - var historyItems = _history.GetHistoryItems(); + var historyItems = _history.LastOpenedHistoryItems; if (historyItems.Count > 0) { ChangeQueryText(historyItems[^lastHistoryIndex].Query); @@ -611,7 +612,7 @@ private void SelectNextPage() [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 @@ private void QueryHistory() 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 @@ private void QueryHistory() 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 @@ await PluginManager.QueryHomeForPluginAsync(plugin, query, token) : 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); From 66fe0b824522030d83fb56d6df2ea786aa8624a3 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 14 Oct 2025 23:23:52 +0800 Subject: [PATCH 34/52] Adjust design-time height in SettingsPaneGeneral.xaml --- Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml index 0c48b511a89..720cb440b9b 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml @@ -13,7 +13,7 @@ xmlns:userSettings="clr-namespace:Flow.Launcher.Infrastructure.UserSettings;assembly=Flow.Launcher.Infrastructure" Title="General" d:DataContext="{d:DesignInstance settingsViewModels:SettingsPaneGeneralViewModel}" - d:DesignHeight="10000" + d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"> From 0131b92c7a5801214b7fc1c9293f27621334363a Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 22:47:58 -0300 Subject: [PATCH 35/52] The HistoryStyle property is used to distinguish history items --- Flow.Launcher/Storage/LastOpenedHistoryItem.cs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs index 47647066c91..1cf93b1ff13 100644 --- a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs +++ b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs @@ -1,4 +1,5 @@ using System; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; @@ -10,22 +11,7 @@ public class LastOpenedHistoryItem public string PluginID { get; set; } = string.Empty; public string Query { get; set; } = string.Empty; public string RecordKey { get; set; } = string.Empty; + public HistoryStyle HistoryStyle { get; set; } public DateTime ExecutedDateTime { get; set; } - public bool Equals(Result r) - { - if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey)) - { - return Title == r.Title - && SubTitle == r.SubTitle - && PluginID == r.PluginID - && Query == r.OriginQuery.RawQuery; - } - else - { - return RecordKey == r.RecordKey - && PluginID == r.PluginID - && Query == r.OriginQuery.RawQuery; - } - } } From ced824d791c7cd2e78a26aa5695d328e4463bfc4 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 22:49:03 -0300 Subject: [PATCH 36/52] is equals --- Flow.Launcher/Helper/ResultHelper.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs index f99ba037771..a0a7b079387 100644 --- a/Flow.Launcher/Helper/ResultHelper.cs +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Core.Plugin; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Storage; @@ -41,4 +42,18 @@ public static class ResultHelper return null; } } + + public static bool IsEquals(this Result result, LastOpenedHistoryItem item, HistoryStyle style) + { + bool keyMatches = string.IsNullOrEmpty(result.RecordKey) + ? item.Title == result.Title + : item.RecordKey == result.RecordKey; + + bool queryMatches = style != HistoryStyle.Query || item.Query == result.OriginQuery.RawQuery; + + return keyMatches + && queryMatches + && item.PluginID == result.PluginID + && item.HistoryStyle == style; + } } From d5a2695766b9121c0e3debdd37a7ac2d8f511cb3 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 22:50:29 -0300 Subject: [PATCH 37/52] Update the history item if it equals the last added item or already exists in the list. --- Flow.Launcher/Storage/QueryHistory.cs | 55 ++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs index 7d264d09f52..7be099115b1 100644 --- a/Flow.Launcher/Storage/QueryHistory.cs +++ b/Flow.Launcher/Storage/QueryHistory.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; +using CommunityToolkit.Mvvm.DependencyInjection; +using Flow.Launcher.Helper; +using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage @@ -16,8 +19,11 @@ public class History [JsonInclude] public List LastOpenedHistoryItems { get; private set; } = []; + private readonly Settings _settings = Ioc.Default.GetRequiredService(); + private readonly int _maxHistory = 300; + public void PopulateHistoryFromLegacyHistory() { if (Items.Count == 0) return; @@ -25,7 +31,7 @@ public void PopulateHistoryFromLegacyHistory() foreach (var item in Items) { LastOpenedHistoryItems.Add(new LastOpenedHistoryItem - { + { Query = item.Query, ExecutedDateTime = item.ExecutedDateTime }); @@ -34,33 +40,48 @@ public void PopulateHistoryFromLegacyHistory() } public void Add(Result result) - { + { if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; + if (string.IsNullOrEmpty(result.PluginID)) return; + var style = _settings.HistoryStyle; // Maintain the max history limit - if (LastOpenedHistoryItems.Count > _maxHistory) + if (LastOpenedHistoryItems.Count > _maxHistory) { LastOpenedHistoryItems.RemoveAt(0); } // If the last item is the same as the current result, just update the timestamp - if (LastOpenedHistoryItems.Count > 0 && - LastOpenedHistoryItems.Last().Equals(result)) + if (LastOpenedHistoryItems.Count > 0) { - LastOpenedHistoryItems.Last().ExecutedDateTime = DateTime.Now; - } - else - { - LastOpenedHistoryItems.Add(new LastOpenedHistoryItem + var last = LastOpenedHistoryItems.Last(); + if (result.IsEquals(last, style)) { - Title = result.Title, - SubTitle = result.SubTitle, - PluginID = result.PluginID, - Query = result.OriginQuery.RawQuery, - RecordKey = result.RecordKey, - ExecutedDateTime = DateTime.Now - }); + last.ExecutedDateTime = DateTime.Now; + return; + } + + var existItem = LastOpenedHistoryItems.FirstOrDefault(x => result.IsEquals(x, style)); + + if (existItem != null) + { + existItem.ExecutedDateTime = DateTime.Now; + return; + } } + + LastOpenedHistoryItems.Add(new LastOpenedHistoryItem + { + Title = result.Title, + SubTitle = result.SubTitle, + PluginID = result.PluginID, + Query = result.OriginQuery.RawQuery, + RecordKey = result.RecordKey, + ExecutedDateTime = DateTime.Now, + HistoryStyle = style + }); } + + } } From 9f652c33b4900a7a7738a483b9de2bf155701b52 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 22:51:09 -0300 Subject: [PATCH 38/52] History items filtered based on HistoryStyle. --- Flow.Launcher/ViewModel/MainViewModel.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 8fd6de6f5f7..22476a79cab 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1318,9 +1318,10 @@ private void QueryHistory() private List GetHistoryItems(IEnumerable historyItems) { var results = new List(); + var historyItemsFiltered = historyItems.Where(x => x.HistoryStyle == Settings.HistoryStyle).ToList(); if (Settings.HistoryStyle == HistoryStyle.Query) { - foreach (var h in historyItems) + foreach (var h in historyItemsFiltered) { var result = new Result { @@ -1341,7 +1342,7 @@ private List GetHistoryItems(IEnumerable historyI } else { - foreach (var h in historyItems) + foreach (var h in historyItemsFiltered) { var result = new Result { @@ -1364,15 +1365,14 @@ private List GetHistoryItems(IEnumerable historyI { await reflectResult.AsyncAction(c); } + return false; } - else - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(h.Query); - return false; - } - }, + + App.API.BackToQueryResults(); + App.API.ChangeQuery(h.Query); + return false; + }, Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") }; results.Add(result); From 8e96d1a461ac229be6f9fbdd2798282c521bfb10 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 22:51:28 -0300 Subject: [PATCH 39/52] HistoryStyle enum values --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 6adefdb6a21..da712e3fc03 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -716,9 +716,9 @@ public enum DialogJumpFileResultBehaviours public enum HistoryStyle { [EnumLocalizeKey(nameof(Localize.queryHistory))] - Query, + Query = 1, [EnumLocalizeKey(nameof(Localize.executedHistory))] - LastOpened + LastOpened = 2 } } From f31abe83b0c2ee41cbb5922b5826993bc3b6c1bf Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 23:12:25 -0300 Subject: [PATCH 40/52] PopulateHistoryFromLegacyHistory with HistoryStyle --- Flow.Launcher/Storage/QueryHistory.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs index 7be099115b1..5d19aed3885 100644 --- a/Flow.Launcher/Storage/QueryHistory.cs +++ b/Flow.Launcher/Storage/QueryHistory.cs @@ -33,7 +33,8 @@ public void PopulateHistoryFromLegacyHistory() LastOpenedHistoryItems.Add(new LastOpenedHistoryItem { Query = item.Query, - ExecutedDateTime = item.ExecutedDateTime + ExecutedDateTime = item.ExecutedDateTime, + HistoryStyle = HistoryStyle.Query }); } Items.Clear(); From 764c674350a6696bd9d5b646d987504f68f8097d Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 23:15:14 -0300 Subject: [PATCH 41/52] code quality --- Flow.Launcher/Helper/ResultHelper.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs index a0a7b079387..d4732055ba2 100644 --- a/Flow.Launcher/Helper/ResultHelper.cs +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -45,11 +45,12 @@ public static class ResultHelper public static bool IsEquals(this Result result, LastOpenedHistoryItem item, HistoryStyle style) { - bool keyMatches = string.IsNullOrEmpty(result.RecordKey) - ? item.Title == result.Title - : item.RecordKey == result.RecordKey; + bool keyMatches = string.IsNullOrEmpty(result.RecordKey) && string.IsNullOrEmpty(item.RecordKey) + ? item.Title == result.Title + : !string.IsNullOrEmpty(result.RecordKey) && !string.IsNullOrEmpty(item.RecordKey) && item.RecordKey == result.RecordKey; + + bool queryMatches = style != HistoryStyle.Query || (result.OriginQuery != null && item.Query == result.OriginQuery.RawQuery); - bool queryMatches = style != HistoryStyle.Query || item.Query == result.OriginQuery.RawQuery; return keyMatches && queryMatches From a8d3cdf62cec6e81e5862bbc9f60c6974d99ae83 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Tue, 14 Oct 2025 23:26:32 -0300 Subject: [PATCH 42/52] SubTitle equals --- Flow.Launcher/Helper/ResultHelper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs index d4732055ba2..f2ba66cbf45 100644 --- a/Flow.Launcher/Helper/ResultHelper.cs +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -54,6 +54,7 @@ public static bool IsEquals(this Result result, LastOpenedHistoryItem item, Hist return keyMatches && queryMatches + && item.SubTitle == result.SubTitle && item.PluginID == result.PluginID && item.HistoryStyle == style; } From 9ca7c8431bfb7e196ce8ff672ad72fd252b09c1d Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 15 Oct 2025 00:34:16 -0300 Subject: [PATCH 43/52] Revert modifications and returning actions --- .../UserSettings/Settings.cs | 4 +- Flow.Launcher/Helper/ResultHelper.cs | 17 ------ .../Storage/LastOpenedHistoryItem.cs | 18 +++++- Flow.Launcher/Storage/QueryHistory.cs | 58 ++++++------------- Flow.Launcher/ViewModel/MainViewModel.cs | 18 +++--- 5 files changed, 45 insertions(+), 70 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index da712e3fc03..6adefdb6a21 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -716,9 +716,9 @@ public enum DialogJumpFileResultBehaviours public enum HistoryStyle { [EnumLocalizeKey(nameof(Localize.queryHistory))] - Query = 1, + Query, [EnumLocalizeKey(nameof(Localize.executedHistory))] - LastOpened = 2 + LastOpened } } diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs index f2ba66cbf45..f99ba037771 100644 --- a/Flow.Launcher/Helper/ResultHelper.cs +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -2,7 +2,6 @@ using System.Threading; using System.Threading.Tasks; using Flow.Launcher.Core.Plugin; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; using Flow.Launcher.Storage; @@ -42,20 +41,4 @@ public static class ResultHelper return null; } } - - public static bool IsEquals(this Result result, LastOpenedHistoryItem item, HistoryStyle style) - { - bool keyMatches = string.IsNullOrEmpty(result.RecordKey) && string.IsNullOrEmpty(item.RecordKey) - ? item.Title == result.Title - : !string.IsNullOrEmpty(result.RecordKey) && !string.IsNullOrEmpty(item.RecordKey) && item.RecordKey == result.RecordKey; - - bool queryMatches = style != HistoryStyle.Query || (result.OriginQuery != null && item.Query == result.OriginQuery.RawQuery); - - - return keyMatches - && queryMatches - && item.SubTitle == result.SubTitle - && item.PluginID == result.PluginID - && item.HistoryStyle == style; - } } diff --git a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs index 1cf93b1ff13..47647066c91 100644 --- a/Flow.Launcher/Storage/LastOpenedHistoryItem.cs +++ b/Flow.Launcher/Storage/LastOpenedHistoryItem.cs @@ -1,5 +1,4 @@ using System; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage; @@ -11,7 +10,22 @@ public class LastOpenedHistoryItem public string PluginID { get; set; } = string.Empty; public string Query { get; set; } = string.Empty; public string RecordKey { get; set; } = string.Empty; - public HistoryStyle HistoryStyle { get; set; } public DateTime ExecutedDateTime { get; set; } + public bool Equals(Result r) + { + if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey)) + { + return Title == r.Title + && SubTitle == r.SubTitle + && PluginID == r.PluginID + && Query == r.OriginQuery.RawQuery; + } + else + { + return RecordKey == r.RecordKey + && PluginID == r.PluginID + && Query == r.OriginQuery.RawQuery; + } + } } diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs index 5d19aed3885..7d264d09f52 100644 --- a/Flow.Launcher/Storage/QueryHistory.cs +++ b/Flow.Launcher/Storage/QueryHistory.cs @@ -2,9 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Text.Json.Serialization; -using CommunityToolkit.Mvvm.DependencyInjection; -using Flow.Launcher.Helper; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; namespace Flow.Launcher.Storage @@ -19,11 +16,8 @@ public class History [JsonInclude] public List LastOpenedHistoryItems { get; private set; } = []; - private readonly Settings _settings = Ioc.Default.GetRequiredService(); - private readonly int _maxHistory = 300; - public void PopulateHistoryFromLegacyHistory() { if (Items.Count == 0) return; @@ -31,58 +25,42 @@ public void PopulateHistoryFromLegacyHistory() foreach (var item in Items) { LastOpenedHistoryItems.Add(new LastOpenedHistoryItem - { + { Query = item.Query, - ExecutedDateTime = item.ExecutedDateTime, - HistoryStyle = HistoryStyle.Query + ExecutedDateTime = item.ExecutedDateTime }); } Items.Clear(); } public void Add(Result result) - { + { if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; - if (string.IsNullOrEmpty(result.PluginID)) return; - var style = _settings.HistoryStyle; // Maintain the max history limit - if (LastOpenedHistoryItems.Count > _maxHistory) + if (LastOpenedHistoryItems.Count > _maxHistory) { LastOpenedHistoryItems.RemoveAt(0); } // If the last item is the same as the current result, just update the timestamp - if (LastOpenedHistoryItems.Count > 0) + if (LastOpenedHistoryItems.Count > 0 && + LastOpenedHistoryItems.Last().Equals(result)) { - var last = LastOpenedHistoryItems.Last(); - if (result.IsEquals(last, style)) - { - last.ExecutedDateTime = DateTime.Now; - return; - } - - var existItem = LastOpenedHistoryItems.FirstOrDefault(x => result.IsEquals(x, style)); - - if (existItem != null) - { - existItem.ExecutedDateTime = DateTime.Now; - return; - } + LastOpenedHistoryItems.Last().ExecutedDateTime = DateTime.Now; } - - LastOpenedHistoryItems.Add(new LastOpenedHistoryItem + else { - Title = result.Title, - SubTitle = result.SubTitle, - PluginID = result.PluginID, - Query = result.OriginQuery.RawQuery, - RecordKey = result.RecordKey, - ExecutedDateTime = DateTime.Now, - HistoryStyle = style - }); + LastOpenedHistoryItems.Add(new LastOpenedHistoryItem + { + Title = result.Title, + SubTitle = result.SubTitle, + PluginID = result.PluginID, + Query = result.OriginQuery.RawQuery, + RecordKey = result.RecordKey, + ExecutedDateTime = DateTime.Now + }); + } } - - } } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 22476a79cab..8fd6de6f5f7 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1318,10 +1318,9 @@ private void QueryHistory() private List GetHistoryItems(IEnumerable historyItems) { var results = new List(); - var historyItemsFiltered = historyItems.Where(x => x.HistoryStyle == Settings.HistoryStyle).ToList(); if (Settings.HistoryStyle == HistoryStyle.Query) { - foreach (var h in historyItemsFiltered) + foreach (var h in historyItems) { var result = new Result { @@ -1342,7 +1341,7 @@ private List GetHistoryItems(IEnumerable historyI } else { - foreach (var h in historyItemsFiltered) + foreach (var h in historyItems) { var result = new Result { @@ -1365,14 +1364,15 @@ private List GetHistoryItems(IEnumerable historyI { await reflectResult.AsyncAction(c); } - return false; } - - App.API.BackToQueryResults(); - App.API.ChangeQuery(h.Query); - 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); From 10d353defe6dfb42ed20f04db78f5091c41218cf Mon Sep 17 00:00:00 2001 From: 01Dri Date: Wed, 15 Oct 2025 00:34:38 -0300 Subject: [PATCH 44/52] Returning actions --- Flow.Launcher/Storage/QueryHistory.cs | 1 + Flow.Launcher/ViewModel/MainViewModel.cs | 15 ++++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Flow.Launcher/Storage/QueryHistory.cs b/Flow.Launcher/Storage/QueryHistory.cs index 7d264d09f52..8284f7eea01 100644 --- a/Flow.Launcher/Storage/QueryHistory.cs +++ b/Flow.Launcher/Storage/QueryHistory.cs @@ -36,6 +36,7 @@ public void PopulateHistoryFromLegacyHistory() public void Add(Result result) { if (string.IsNullOrEmpty(result.OriginQuery.RawQuery)) return; + if (string.IsNullOrEmpty(result.PluginID)) return; // Maintain the max history limit if (LastOpenedHistoryItems.Count > _maxHistory) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 8fd6de6f5f7..d9bcf0a33ac 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1358,20 +1358,17 @@ private List GetHistoryItems(IEnumerable historyI { if (reflectResult.Action != null) { - reflectResult.Action(c); + return reflectResult.Action(c); } - else if (reflectResult.AsyncAction != null) + if (reflectResult.AsyncAction != null) { - await reflectResult.AsyncAction(c); + return await reflectResult.AsyncAction(c); } return false; } - else - { - App.API.BackToQueryResults(); - App.API.ChangeQuery(h.Query); - return false; - } + App.API.BackToQueryResults(); + App.API.ChangeQuery(h.Query); + return false; }, Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C") }; From 4b6ee4ea98dc73d6f8b760483d60e23a2ddbc3e8 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:23:00 +0800 Subject: [PATCH 45/52] Improve code quality --- Flow.Launcher/ViewModel/MainViewModel.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d9bcf0a33ac..4df87208c52 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -422,7 +422,6 @@ private void LoadContextMenu() _ = Task.Run(() => DialogJump.JumpToPathAsync(DialogWindowHandle, dialogJumpResult.DialogJumpPath)); } } - return; } @@ -1358,14 +1357,20 @@ private List GetHistoryItems(IEnumerable historyI { if (reflectResult.Action != null) { + // Since some actions may need to hide the Flow window to execute + // So let us populate the results of them return reflectResult.Action(c); } if (reflectResult.AsyncAction != null) { - return await reflectResult.AsyncAction(c); + // Since some actions may need to hide the Flow window to execute + // So let us populate the results of them + return await reflectResult.AsyncAction(c); } return false; } + + // If we cannot get the result, fallback to re-query App.API.BackToQueryResults(); App.API.ChangeQuery(h.Query); return false; From 1298b76b7781c0a5b957c78c17d08e4dd0552767 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:23:52 +0800 Subject: [PATCH 46/52] Track user-selected results for ranking purposes Added logic to record user-selected results in `_userSelectedRecord` before executing both synchronous and asynchronous actions. This enables tracking of user interactions for result ranking or analytics. Comments were added to clarify the purpose of the new logic. --- Flow.Launcher/ViewModel/MainViewModel.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 4df87208c52..14f6dda3905 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1357,12 +1357,18 @@ private List GetHistoryItems(IEnumerable historyI { if (reflectResult.Action != null) { + // Record the user selected record for result ranking + _userSelectedRecord.Add(reflectResult); + // Since some actions may need to hide the Flow window to execute // So let us populate the results of them return reflectResult.Action(c); } if (reflectResult.AsyncAction != null) { + // Record the user selected record for result ranking + _userSelectedRecord.Add(reflectResult); + // Since some actions may need to hide the Flow window to execute // So let us populate the results of them return await reflectResult.AsyncAction(c); From c73689fbc3701812d0e05a47c4add7fad959a044 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:24:36 +0800 Subject: [PATCH 47/52] Fix spelling --- Directory.Build.props | 2 +- Flow.Launcher/Flow.Launcher.csproj | 2 +- Flow.Launcher/MainWindow.xaml.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a5545af1248..b8c1d13ea91 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ true - + false \ No newline at end of file diff --git a/Flow.Launcher/Flow.Launcher.csproj b/Flow.Launcher/Flow.Launcher.csproj index 8c7670426bb..576bf6f2f13 100644 --- a/Flow.Launcher/Flow.Launcher.csproj +++ b/Flow.Launcher/Flow.Launcher.csproj @@ -185,7 +185,7 @@ - + diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 88d6b660648..530ca8488bd 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -860,7 +860,7 @@ private void InitializeContextMenu() public void UpdatePosition() { - // Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 + // Initialize call twice to workaround multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 if (_viewModel.IsDialogJumpWindowUnderDialog()) { InitializeDialogJumpPosition(); @@ -884,7 +884,7 @@ private async Task PositionResetAsync() private void InitializePosition() { - // Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 + // Initialize call twice to workaround multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 InitializePositionInner(); InitializePositionInner(); return; From 629c2eb4c65b752a5796f5268f138468e514656d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:26:21 +0800 Subject: [PATCH 48/52] Record user-selected results for ranking Moved `_userSelectedRecord.Add(result)` outside the `if (queryResultsSelected)` block to ensure all user-selected results are recorded, regardless of their source (query results, context menu, or history). Added a comment to clarify that only query results are added to history. --- Flow.Launcher/ViewModel/MainViewModel.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 14f6dda3905..4c5c0229cbc 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -532,9 +532,12 @@ private async Task OpenResultAsync(string index) Hide(); } } + + // Record user selected result for result ranking + _userSelectedRecord.Add(result); + // Add item to histroy only if it is from results but not context menu or history if (queryResultsSelected) { - _userSelectedRecord.Add(result); _history.Add(result); lastHistoryIndex = 1; } From b784a14aee3c4004b410444d4576809eaabc324d Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:28:54 +0800 Subject: [PATCH 49/52] Update tooltip text for `historyStyleTooltip` The tooltip text for the key `historyStyleTooltip` was updated to improve capitalization and consistency. "History" and "Home Page" were capitalized to align with the formatting of other keys in the file. --- 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 dd35bcc1d26..2ced2935326 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -167,7 +167,7 @@ Show History Results in Home Page Maximum History Results Shown in Home Page History Style - Choose the type of history to show in the history and home page + Choose the type of history to show in the History and Home Page Query history Last opened history This can only be edited if plugin supports Home feature and Home Page is enabled. From 83cab764a125b328367e84d9df36191f85fe57ba Mon Sep 17 00:00:00 2001 From: Jack Ye Date: Wed, 15 Oct 2025 12:30:59 +0800 Subject: [PATCH 50/52] Fix typos Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 4c5c0229cbc..d0c59a7f25e 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -535,7 +535,7 @@ private async Task OpenResultAsync(string index) // Record user selected result for result ranking _userSelectedRecord.Add(result); - // Add item to histroy only if it is from results but not context menu or history + // Add item to history only if it is from results but not context menu or history if (queryResultsSelected) { _history.Add(result); From df4f08b071b82866b99430327843b20a5ecd64f9 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:35:53 +0800 Subject: [PATCH 51/52] Add exception logging to ResultHelper catch block Updated the `catch` block in the `ResultHelper` class to explicitly catch `System.Exception` and log the error using `App.API.LogException`. The log includes the class name, a failure message for querying results, and the exception details. This improves error visibility and debugging. --- Flow.Launcher/Helper/ResultHelper.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/Helper/ResultHelper.cs b/Flow.Launcher/Helper/ResultHelper.cs index f99ba037771..389b06b4f72 100644 --- a/Flow.Launcher/Helper/ResultHelper.cs +++ b/Flow.Launcher/Helper/ResultHelper.cs @@ -36,8 +36,9 @@ public static class ResultHelper freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle); } } - catch + catch (System.Exception e) { + App.API.LogException(nameof(ResultHelper), $"Failed to query results for {plugin.Metadata.Name}", e); return null; } } From b13c29ab91aee6f2a8674ee232811fa425bf2ded Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Wed, 15 Oct 2025 12:40:00 +0800 Subject: [PATCH 52/52] Record user selection after successful execution --- Flow.Launcher/ViewModel/MainViewModel.cs | 25 ++++++------------------ 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index d0c59a7f25e..706be8bb8e6 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1358,25 +1358,12 @@ private List GetHistoryItems(IEnumerable historyI var reflectResult = await ResultHelper.PopulateResultsAsync(h); if (reflectResult != null) { - if (reflectResult.Action != null) - { - // Record the user selected record for result ranking - _userSelectedRecord.Add(reflectResult); - - // Since some actions may need to hide the Flow window to execute - // So let us populate the results of them - return reflectResult.Action(c); - } - if (reflectResult.AsyncAction != null) - { - // Record the user selected record for result ranking - _userSelectedRecord.Add(reflectResult); - - // Since some actions may need to hide the Flow window to execute - // So let us populate the results of them - return await reflectResult.AsyncAction(c); - } - return false; + // Record the user selected record for result ranking + _userSelectedRecord.Add(reflectResult); + + // Since some actions may need to hide the Flow window to execute + // So let us populate the results of them + return await reflectResult.ExecuteAsync(c); } // If we cannot get the result, fallback to re-query