mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #4042 from 01Dri/feature/history_mode
Add "Last opened" history mode & Fix non-result history item save issue
This commit is contained in:
commit
3d9ef2c63f
12 changed files with 262 additions and 57 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
|
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
|
||||||
<!-- Work around https://github.com/dotnet/runtime/issues/109682 -->
|
<!-- Workaround https://github.com/dotnet/runtime/issues/109682 -->
|
||||||
<CETCompat>false</CETCompat>
|
<CETCompat>false</CETCompat>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -7,6 +7,7 @@ using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Infrastructure.Storage;
|
using Flow.Launcher.Infrastructure.Storage;
|
||||||
|
using Flow.Launcher.Localization.Attributes;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
|
|
||||||
|
|
@ -513,6 +514,21 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected;
|
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))]
|
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||||
public AnimationSpeeds AnimationSpeed { get; set; } = AnimationSpeeds.Medium;
|
public AnimationSpeeds AnimationSpeed { get; set; } = AnimationSpeeds.Medium;
|
||||||
public int CustomAnimationLength { get; set; } = 360;
|
public int CustomAnimationLength { get; set; } = 360;
|
||||||
|
|
@ -695,4 +711,14 @@ namespace Flow.Launcher.Infrastructure.UserSettings
|
||||||
FullPathOpen,
|
FullPathOpen,
|
||||||
Directory
|
Directory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[EnumLocalize]
|
||||||
|
public enum HistoryStyle
|
||||||
|
{
|
||||||
|
[EnumLocalizeKey(nameof(Localize.queryHistory))]
|
||||||
|
Query,
|
||||||
|
|
||||||
|
[EnumLocalizeKey(nameof(Localize.executedHistory))]
|
||||||
|
LastOpened
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
|
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
|
||||||
<!-- Work around https://github.com/dotnet/wpf/issues/6792 -->
|
<!-- Workaround https://github.com/dotnet/wpf/issues/6792 -->
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
|
<FilteredAnalyzer Include="@(Analyzer->Distinct())" />
|
||||||
<Analyzer Remove="@(Analyzer)" />
|
<Analyzer Remove="@(Analyzer)" />
|
||||||
|
|
|
||||||
45
Flow.Launcher/Helper/ResultHelper.cs
Normal file
45
Flow.Launcher/Helper/ResultHelper.cs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Flow.Launcher.Core.Plugin;
|
||||||
|
using Flow.Launcher.Plugin;
|
||||||
|
using Flow.Launcher.Storage;
|
||||||
|
|
||||||
|
namespace Flow.Launcher.Helper;
|
||||||
|
|
||||||
|
#nullable enable
|
||||||
|
|
||||||
|
public static class ResultHelper
|
||||||
|
{
|
||||||
|
public static async Task<Result?> PopulateResultsAsync(LastOpenedHistoryItem item)
|
||||||
|
{
|
||||||
|
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<Result?> PopulateResultsAsync(string pluginId, string rawQuery, string title, string subTitle, string recordKey)
|
||||||
|
{
|
||||||
|
var plugin = PluginManager.GetPluginForId(pluginId);
|
||||||
|
if (plugin == null) return null;
|
||||||
|
var query = QueryBuilder.Build(rawQuery, PluginManager.NonGlobalPlugins);
|
||||||
|
if (query == null) return null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var freshResults = await plugin.Plugin.QueryAsync(query, CancellationToken.None);
|
||||||
|
// Try to match by record key first if it is valid, otherwise fall back to title + subtitle match
|
||||||
|
if (string.IsNullOrEmpty(recordKey))
|
||||||
|
{
|
||||||
|
return freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return freshResults?.FirstOrDefault(r => r.RecordKey == recordKey) ??
|
||||||
|
freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Exception e)
|
||||||
|
{
|
||||||
|
App.API.LogException(nameof(ResultHelper), $"Failed to query results for {plugin.Metadata.Name}", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -166,6 +166,10 @@
|
||||||
<system:String x:Key="homePageToolTip">Show home page results when query text is empty.</system:String>
|
<system:String x:Key="homePageToolTip">Show home page results when query text is empty.</system:String>
|
||||||
<system:String x:Key="historyResultsForHomePage">Show History Results in Home Page</system:String>
|
<system:String x:Key="historyResultsForHomePage">Show History Results in Home Page</system:String>
|
||||||
<system:String x:Key="historyResultsCountForHomePage">Maximum History Results Shown in Home Page</system:String>
|
<system:String x:Key="historyResultsCountForHomePage">Maximum History Results Shown in Home Page</system:String>
|
||||||
|
<system:String x:Key="historyStyle">History Style</system:String>
|
||||||
|
<system:String x:Key="historyStyleTooltip">Choose the type of history to show in the History and Home Page</system:String>
|
||||||
|
<system:String x:Key="queryHistory">Query history</system:String>
|
||||||
|
<system:String x:Key="executedHistory">Last opened history</system:String>
|
||||||
<system:String x:Key="homeToggleBoxToolTip">This can only be edited if plugin supports Home feature and Home Page is enabled.</system:String>
|
<system:String x:Key="homeToggleBoxToolTip">This can only be edited if plugin supports Home feature and Home Page is enabled.</system:String>
|
||||||
<system:String x:Key="showAtTopmost">Show Search Window at Foremost</system:String>
|
<system:String x:Key="showAtTopmost">Show Search Window at Foremost</system:String>
|
||||||
<system:String x:Key="showAtTopmostToolTip">Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position.</system:String>
|
<system:String x:Key="showAtTopmostToolTip">Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position.</system:String>
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,7 @@ namespace Flow.Launcher
|
||||||
break;
|
break;
|
||||||
case nameof(Settings.ShowHomePage):
|
case nameof(Settings.ShowHomePage):
|
||||||
case nameof(Settings.ShowHistoryResultsForHomePage):
|
case nameof(Settings.ShowHistoryResultsForHomePage):
|
||||||
|
case nameof(Settings.HistoryStyle):
|
||||||
if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText))
|
if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText))
|
||||||
{
|
{
|
||||||
_viewModel.QueryResults();
|
_viewModel.QueryResults();
|
||||||
|
|
@ -859,7 +860,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
public void UpdatePosition()
|
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())
|
if (_viewModel.IsDialogJumpWindowUnderDialog())
|
||||||
{
|
{
|
||||||
InitializeDialogJumpPosition();
|
InitializeDialogJumpPosition();
|
||||||
|
|
@ -883,7 +884,7 @@ namespace Flow.Launcher
|
||||||
|
|
||||||
private void InitializePosition()
|
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();
|
||||||
InitializePositionInner();
|
InitializePositionInner();
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,8 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
||||||
public List<LastQueryModeData> LastQueryModes { get; } =
|
public List<LastQueryModeData> LastQueryModes { get; } =
|
||||||
DropdownDataGeneric<LastQueryMode>.GetValues<LastQueryModeData>("LastQuery");
|
DropdownDataGeneric<LastQueryMode>.GetValues<LastQueryModeData>("LastQuery");
|
||||||
|
|
||||||
|
public List<HistoryStyleLocalized> HistoryStyles { get; } = HistoryStyleLocalized.GetValues();
|
||||||
|
|
||||||
public bool EnableDialogJump
|
public bool EnableDialogJump
|
||||||
{
|
{
|
||||||
get => Settings.EnableDialogJump;
|
get => Settings.EnableDialogJump;
|
||||||
|
|
@ -213,6 +215,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
|
||||||
DropdownDataGeneric<SearchWindowAligns>.UpdateLabels(SearchWindowAligns);
|
DropdownDataGeneric<SearchWindowAligns>.UpdateLabels(SearchWindowAligns);
|
||||||
DropdownDataGeneric<SearchPrecisionScore>.UpdateLabels(SearchPrecisionScores);
|
DropdownDataGeneric<SearchPrecisionScore>.UpdateLabels(SearchPrecisionScores);
|
||||||
DropdownDataGeneric<LastQueryMode>.UpdateLabels(LastQueryModes);
|
DropdownDataGeneric<LastQueryMode>.UpdateLabels(LastQueryModes);
|
||||||
|
HistoryStyleLocalized.UpdateLabels(HistoryStyles);
|
||||||
DropdownDataGeneric<DoublePinyinSchemas>.UpdateLabels(DoublePinyinSchemas);
|
DropdownDataGeneric<DoublePinyinSchemas>.UpdateLabels(DoublePinyinSchemas);
|
||||||
DropdownDataGeneric<DialogJumpWindowPositions>.UpdateLabels(DialogJumpWindowPositions);
|
DropdownDataGeneric<DialogJumpWindowPositions>.UpdateLabels(DialogJumpWindowPositions);
|
||||||
DropdownDataGeneric<DialogJumpResultBehaviours>.UpdateLabels(DialogJumpResultBehaviours);
|
DropdownDataGeneric<DialogJumpResultBehaviours>.UpdateLabels(DialogJumpResultBehaviours);
|
||||||
|
|
|
||||||
|
|
@ -245,6 +245,22 @@
|
||||||
SelectedValuePath="Value" />
|
SelectedValuePath="Value" />
|
||||||
</ui:SettingsCard>
|
</ui:SettingsCard>
|
||||||
|
|
||||||
|
<ui:SettingsCard
|
||||||
|
Margin="0 14 0 0"
|
||||||
|
Description="{DynamicResource historyStyleTooltip}"
|
||||||
|
Header="{DynamicResource historyStyle}">
|
||||||
|
<ui:SettingsCard.HeaderIcon>
|
||||||
|
<ui:FontIcon Glyph="" />
|
||||||
|
</ui:SettingsCard.HeaderIcon>
|
||||||
|
|
||||||
|
<ComboBox
|
||||||
|
MaxWidth="200"
|
||||||
|
DisplayMemberPath="Display"
|
||||||
|
ItemsSource="{Binding HistoryStyles}"
|
||||||
|
SelectedValue="{Binding Settings.HistoryStyle}"
|
||||||
|
SelectedValuePath="Value" />
|
||||||
|
</ui:SettingsCard>
|
||||||
|
|
||||||
<ui:SettingsCard
|
<ui:SettingsCard
|
||||||
Margin="0 14 0 0"
|
Margin="0 14 0 0"
|
||||||
Description="{DynamicResource autoRestartAfterChangingToolTip}"
|
Description="{DynamicResource autoRestartAfterChangingToolTip}"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Flow.Launcher.Storage
|
namespace Flow.Launcher.Storage
|
||||||
{
|
{
|
||||||
|
[Obsolete("Use LastOpenedHistoryItem instead. This class will be removed in future versions.")]
|
||||||
public class HistoryItem
|
public class HistoryItem
|
||||||
{
|
{
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
|
|
@ -42,4 +43,4 @@ namespace Flow.Launcher.Storage
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
Flow.Launcher/Storage/LastOpenedHistoryItem.cs
Normal file
31
Flow.Launcher/Storage/LastOpenedHistoryItem.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
using System;
|
||||||
|
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; }
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,33 +2,63 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Flow.Launcher.Plugin;
|
||||||
|
|
||||||
namespace Flow.Launcher.Storage
|
namespace Flow.Launcher.Storage
|
||||||
{
|
{
|
||||||
public class History
|
public class History
|
||||||
{
|
{
|
||||||
[JsonInclude]
|
[JsonInclude]
|
||||||
public List<HistoryItem> Items { get; private set; } = new List<HistoryItem>();
|
#pragma warning disable CS0618 // Type or member is obsolete
|
||||||
|
public List<HistoryItem> Items { get; private set; } = [];
|
||||||
|
#pragma warning restore CS0618 // Type or member is obsolete
|
||||||
|
|
||||||
private int _maxHistory = 300;
|
[JsonInclude]
|
||||||
|
public List<LastOpenedHistoryItem> LastOpenedHistoryItems { get; private set; } = [];
|
||||||
|
|
||||||
public void Add(string query)
|
private readonly int _maxHistory = 300;
|
||||||
|
|
||||||
|
public void PopulateHistoryFromLegacyHistory()
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(query)) return;
|
if (Items.Count == 0) return;
|
||||||
if (Items.Count > _maxHistory)
|
// Migrate old history items to new LastOpenedHistoryItems
|
||||||
|
foreach (var item in Items)
|
||||||
{
|
{
|
||||||
Items.RemoveAt(0);
|
LastOpenedHistoryItems.Add(new LastOpenedHistoryItem
|
||||||
|
{
|
||||||
|
Query = item.Query,
|
||||||
|
ExecutedDateTime = item.ExecutedDateTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Items.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
LastOpenedHistoryItems.RemoveAt(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Items.Count > 0 && Items.Last().Query == query)
|
// If the last item is the same as the current result, just update the timestamp
|
||||||
|
if (LastOpenedHistoryItems.Count > 0 &&
|
||||||
|
LastOpenedHistoryItems.Last().Equals(result))
|
||||||
{
|
{
|
||||||
Items.Last().ExecutedDateTime = DateTime.Now;
|
LastOpenedHistoryItems.Last().ExecutedDateTime = DateTime.Now;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Items.Add(new HistoryItem
|
LastOpenedHistoryItems.Add(new LastOpenedHistoryItem
|
||||||
{
|
{
|
||||||
Query = query,
|
Title = result.Title,
|
||||||
|
SubTitle = result.SubTitle,
|
||||||
|
PluginID = result.PluginID,
|
||||||
|
Query = result.OriginQuery.RawQuery,
|
||||||
|
RecordKey = result.RecordKey,
|
||||||
ExecutedDateTime = DateTime.Now
|
ExecutedDateTime = DateTime.Now
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,17 @@ using System.Threading;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
using Flow.Launcher.Core.Plugin;
|
using Flow.Launcher.Core.Plugin;
|
||||||
|
using Flow.Launcher.Helper;
|
||||||
using Flow.Launcher.Infrastructure;
|
using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Infrastructure.Hotkey;
|
|
||||||
using Flow.Launcher.Infrastructure.DialogJump;
|
using Flow.Launcher.Infrastructure.DialogJump;
|
||||||
|
using Flow.Launcher.Infrastructure.Hotkey;
|
||||||
using Flow.Launcher.Infrastructure.Storage;
|
using Flow.Launcher.Infrastructure.Storage;
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
using Flow.Launcher.Infrastructure.UserSettings;
|
||||||
using Flow.Launcher.Plugin;
|
using Flow.Launcher.Plugin;
|
||||||
|
|
@ -151,6 +152,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
_userSelectedRecordStorage = new FlowLauncherJsonStorage<UserSelectedRecord>();
|
_userSelectedRecordStorage = new FlowLauncherJsonStorage<UserSelectedRecord>();
|
||||||
_topMostRecord = new FlowLauncherJsonStorageTopMostRecord();
|
_topMostRecord = new FlowLauncherJsonStorageTopMostRecord();
|
||||||
_history = _historyItemsStorage.Load();
|
_history = _historyItemsStorage.Load();
|
||||||
|
_history.PopulateHistoryFromLegacyHistory();
|
||||||
_userSelectedRecord = _userSelectedRecordStorage.Load();
|
_userSelectedRecord = _userSelectedRecordStorage.Load();
|
||||||
|
|
||||||
ContextMenu = new ResultsViewModel(Settings, this)
|
ContextMenu = new ResultsViewModel(Settings, this)
|
||||||
|
|
@ -352,7 +354,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
if (QueryResultsSelected())
|
if (QueryResultsSelected())
|
||||||
{
|
{
|
||||||
SelectedResults = History;
|
SelectedResults = History;
|
||||||
History.SelectedIndex = _history.Items.Count - 1;
|
History.SelectedIndex = _history.LastOpenedHistoryItems.Count - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -380,10 +382,11 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void ReverseHistory()
|
public void ReverseHistory()
|
||||||
{
|
{
|
||||||
if (_history.Items.Count > 0)
|
var historyItems = _history.LastOpenedHistoryItems;
|
||||||
|
if (historyItems.Count > 0)
|
||||||
{
|
{
|
||||||
ChangeQueryText(_history.Items[^lastHistoryIndex].Query);
|
ChangeQueryText(historyItems[^lastHistoryIndex].Query);
|
||||||
if (lastHistoryIndex < _history.Items.Count)
|
if (lastHistoryIndex < historyItems.Count)
|
||||||
{
|
{
|
||||||
lastHistoryIndex++;
|
lastHistoryIndex++;
|
||||||
}
|
}
|
||||||
|
|
@ -393,9 +396,10 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void ForwardHistory()
|
public void ForwardHistory()
|
||||||
{
|
{
|
||||||
if (_history.Items.Count > 0)
|
var historyItems = _history.LastOpenedHistoryItems;
|
||||||
|
if (historyItems.Count > 0)
|
||||||
{
|
{
|
||||||
ChangeQueryText(_history.Items[^lastHistoryIndex].Query);
|
ChangeQueryText(historyItems[^lastHistoryIndex].Query);
|
||||||
if (lastHistoryIndex > 1)
|
if (lastHistoryIndex > 1)
|
||||||
{
|
{
|
||||||
lastHistoryIndex--;
|
lastHistoryIndex--;
|
||||||
|
|
@ -487,6 +491,8 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private async Task OpenResultAsync(string index)
|
private async Task OpenResultAsync(string index)
|
||||||
{
|
{
|
||||||
|
// Must check query results selected before executing the action
|
||||||
|
var queryResultsSelected = QueryResultsSelected();
|
||||||
var results = SelectedResults;
|
var results = SelectedResults;
|
||||||
if (index is not null)
|
if (index is not null)
|
||||||
{
|
{
|
||||||
|
|
@ -527,10 +533,12 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (QueryResultsSelected())
|
// Record user selected result for result ranking
|
||||||
|
_userSelectedRecord.Add(result);
|
||||||
|
// Add item to history only if it is from results but not context menu or history
|
||||||
|
if (queryResultsSelected)
|
||||||
{
|
{
|
||||||
_userSelectedRecord.Add(result);
|
_history.Add(result);
|
||||||
_history.Add(result.OriginQuery.RawQuery);
|
|
||||||
lastHistoryIndex = 1;
|
lastHistoryIndex = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -559,7 +567,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
resultsCopy.Add(resultCopy);
|
resultsCopy.Add(resultCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultsCopy;
|
return resultsCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -606,10 +614,11 @@ namespace Flow.Launcher.ViewModel
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
private void SelectPrevItem()
|
private void SelectPrevItem()
|
||||||
{
|
{
|
||||||
|
var historyItems = _history.LastOpenedHistoryItems;
|
||||||
if (QueryResultsSelected() // Results selected
|
if (QueryResultsSelected() // Results selected
|
||||||
&& string.IsNullOrEmpty(QueryText) // No input
|
&& 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.
|
||||||
&& _history.Items.Count > 0) // Have history items
|
&& historyItems.Count > 0) // Have history items
|
||||||
{
|
{
|
||||||
lastHistoryIndex = 1;
|
lastHistoryIndex = 1;
|
||||||
ReverseHistory();
|
ReverseHistory();
|
||||||
|
|
@ -908,7 +917,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
private string _placeholderText;
|
private string _placeholderText;
|
||||||
public string PlaceholderText
|
public string PlaceholderText
|
||||||
{
|
{
|
||||||
get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder(): _placeholderText;
|
get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder() : _placeholderText;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_placeholderText = value;
|
_placeholderText = value;
|
||||||
|
|
@ -1150,6 +1159,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
HideInternalPreview();
|
HideInternalPreview();
|
||||||
_ = OpenExternalPreviewAsync(path);
|
_ = OpenExternalPreviewAsync(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case true
|
case true
|
||||||
when !CanExternalPreviewSelectedResult(out var _):
|
when !CanExternalPreviewSelectedResult(out var _):
|
||||||
|
|
@ -1263,18 +1273,18 @@ namespace Flow.Launcher.ViewModel
|
||||||
var filtered = results.Select(x => x.Clone()).Where
|
var filtered = results.Select(x => x.Clone()).Where
|
||||||
(
|
(
|
||||||
r =>
|
r =>
|
||||||
{
|
{
|
||||||
var match = App.API.FuzzySearch(query, r.Title);
|
var match = App.API.FuzzySearch(query, r.Title);
|
||||||
if (!match.IsSearchPrecisionScoreMet())
|
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;
|
r.Score = match.Score;
|
||||||
return true;
|
return true;
|
||||||
}).ToList();
|
}).ToList();
|
||||||
ContextMenu.AddResults(filtered, id);
|
ContextMenu.AddResults(filtered, id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1290,7 +1300,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
var query = QueryText.ToLower().Trim();
|
var query = QueryText.ToLower().Trim();
|
||||||
History.Clear();
|
History.Clear();
|
||||||
|
|
||||||
var results = GetHistoryItems(_history.Items);
|
var results = GetHistoryItems(_history.LastOpenedHistoryItems);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(query))
|
if (!string.IsNullOrEmpty(query))
|
||||||
{
|
{
|
||||||
|
|
@ -1307,26 +1317,64 @@ namespace Flow.Launcher.ViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<Result> GetHistoryItems(IEnumerable<HistoryItem> historyItems)
|
private List<Result> GetHistoryItems(IEnumerable<LastOpenedHistoryItem> historyItems)
|
||||||
{
|
{
|
||||||
var results = new List<Result>();
|
var results = new List<Result>();
|
||||||
foreach (var h in historyItems)
|
if (Settings.HistoryStyle == HistoryStyle.Query)
|
||||||
{
|
{
|
||||||
var result = new Result
|
foreach (var h in historyItems)
|
||||||
{
|
{
|
||||||
Title = Localize.executeQuery(h.Query),
|
var result = new Result
|
||||||
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
|
||||||
IcoPath = Constant.HistoryIcon,
|
|
||||||
OriginQuery = new Query { RawQuery = h.Query },
|
|
||||||
Action = _ =>
|
|
||||||
{
|
{
|
||||||
App.API.BackToQueryResults();
|
Title = Localize.executeQuery(h.Query),
|
||||||
App.API.ChangeQuery(h.Query);
|
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime),
|
||||||
return false;
|
IcoPath = Constant.HistoryIcon,
|
||||||
},
|
OriginQuery = new Query { RawQuery = h.Query },
|
||||||
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C")
|
Action = _ =>
|
||||||
};
|
{
|
||||||
results.Add(result);
|
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 },
|
||||||
|
AsyncAction = async c =>
|
||||||
|
{
|
||||||
|
var reflectResult = await ResultHelper.PopulateResultsAsync(h);
|
||||||
|
if (reflectResult != 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.ExecuteAsync(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we cannot get the result, fallback to re-query
|
||||||
|
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;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
@ -1558,7 +1606,7 @@ namespace Flow.Launcher.ViewModel
|
||||||
void QueryHistoryTask(CancellationToken token)
|
void QueryHistoryTask(CancellationToken token)
|
||||||
{
|
{
|
||||||
// Select last history results and revert its order to make sure last history results are on top
|
// 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 = _history.LastOpenedHistoryItems.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse();
|
||||||
|
|
||||||
var results = GetHistoryItems(historyItems);
|
var results = GetHistoryItems(historyItems);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue