Add new default 'search score' sorting method for plugin search (#1882)

This commit is contained in:
nebel 2024-07-04 01:37:25 +09:00 committed by GitHub
parent a4c234c4fa
commit 583c007253
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -124,6 +124,7 @@ internal class PluginInstallerWindow : Window, IDisposable
private PluginSortKind sortKind = PluginSortKind.Alphabetical;
private string filterText = Locs.SortBy_Alphabetical;
private bool adaptiveSort = true;
private OperationStatus installStatus = OperationStatus.Idle;
private OperationStatus updateStatus = OperationStatus.Idle;
@ -208,6 +209,7 @@ internal class PluginInstallerWindow : Window, IDisposable
NotInstalled,
EnabledDisabled,
ProfileOrNot,
SearchScore,
}
[Flags]
@ -280,6 +282,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (!this.isSearchTextPrefilled) this.searchText = string.Empty;
this.sortKind = PluginSortKind.Alphabetical;
this.filterText = Locs.SortBy_Alphabetical;
this.adaptiveSort = true;
if (this.updateStatus == OperationStatus.Complete || this.updateStatus == OperationStatus.Idle)
{
@ -599,6 +602,7 @@ internal class PluginInstallerWindow : Window, IDisposable
var sortByTextWidth = ImGui.CalcTextSize(sortByText).X;
var sortSelectables = new (string Localization, PluginSortKind SortKind)[]
{
(Locs.SortBy_SearchScore, PluginSortKind.SearchScore),
(Locs.SortBy_Alphabetical, PluginSortKind.Alphabetical),
(Locs.SortBy_DownloadCounts, PluginSortKind.DownloadCount),
(Locs.SortBy_LastUpdate, PluginSortKind.LastUpdate),
@ -651,7 +655,29 @@ internal class PluginInstallerWindow : Window, IDisposable
}
if (searchTextChanged)
{
if (this.adaptiveSort)
{
if (string.IsNullOrWhiteSpace(this.searchText))
{
this.sortKind = PluginSortKind.Alphabetical;
this.filterText = Locs.SortBy_Alphabetical;
}
else
{
this.sortKind = PluginSortKind.SearchScore;
this.filterText = Locs.SortBy_SearchScore;
}
this.ResortPlugins();
}
else if (this.sortKind == PluginSortKind.SearchScore)
{
this.ResortPlugins();
}
this.UpdateCategoriesOnSearchChange(prevSearchText);
}
}
// Disable sort if changelogs or profile editor
@ -664,10 +690,14 @@ internal class PluginInstallerWindow : Window, IDisposable
{
foreach (var selectable in sortSelectables)
{
if (selectable.SortKind == PluginSortKind.SearchScore && string.IsNullOrWhiteSpace(this.searchText))
continue;
if (ImGui.Selectable(selectable.Localization))
{
this.sortKind = selectable.SortKind;
this.filterText = selectable.Localization;
this.adaptiveSort = false;
lock (this.listLock)
{
@ -3492,8 +3522,6 @@ internal class PluginInstallerWindow : Window, IDisposable
private bool IsManifestFiltered(IPluginManifest manifest)
{
var searchString = this.searchText.ToLowerInvariant();
var matcher = new FuzzyMatcher(searchString, MatchMode.FuzzyParts);
var hasSearchString = !string.IsNullOrWhiteSpace(this.searchText);
var oldApi = (manifest.TestingDalamudApiLevel == null
|| manifest.TestingDalamudApiLevel < PluginManager.DalamudApiLevel)
@ -3503,12 +3531,30 @@ internal class PluginInstallerWindow : Window, IDisposable
if (oldApi && !hasSearchString && !installed)
return true;
return hasSearchString && !(
(!manifest.Name.IsNullOrEmpty() && matcher.Matches(manifest.Name.ToLowerInvariant()) > 0) ||
(!manifest.InternalName.IsNullOrEmpty() && matcher.Matches(manifest.InternalName.ToLowerInvariant()) > 0) ||
(!manifest.Author.IsNullOrEmpty() && matcher.Matches(manifest.Author.ToLowerInvariant()) > 0) ||
(!manifest.Punchline.IsNullOrEmpty() && manifest.Punchline.ToLowerInvariant().Contains(searchString)) ||
(manifest.Tags != null && matcher.MatchesAny(manifest.Tags.Select(term => term.ToLowerInvariant()).ToArray()) > 0));
if (!hasSearchString)
return false;
return this.GetManifestSearchScore(manifest) < 1;
}
private int GetManifestSearchScore(IPluginManifest manifest)
{
var searchString = this.searchText.ToLowerInvariant();
var matcher = new FuzzyMatcher(searchString, MatchMode.FuzzyParts);
var scores = new List<int> { 0 };
if (!manifest.Name.IsNullOrEmpty())
scores.Add(matcher.Matches(manifest.Name.ToLowerInvariant()) * 110);
if (!manifest.InternalName.IsNullOrEmpty())
scores.Add(matcher.Matches(manifest.InternalName.ToLowerInvariant()) * 105);
if (!manifest.Author.IsNullOrEmpty())
scores.Add(matcher.Matches(manifest.Author.ToLowerInvariant()) * 100);
if (!manifest.Punchline.IsNullOrEmpty())
scores.Add(matcher.Matches(manifest.Punchline.ToLowerInvariant()) * 100);
if (manifest.Tags != null)
scores.Add(matcher.MatchesAny(manifest.Tags.ToArray()) * 100);
return scores.Max();
}
private (bool IsInstalled, LocalPlugin Plugin) IsManifestInstalled(IPluginManifest? manifest)
@ -3609,6 +3655,10 @@ internal class PluginInstallerWindow : Window, IDisposable
var profman = Service<ProfileManager>.Get();
this.pluginListInstalled.Sort((p1, p2) => profman.IsInDefaultProfile(p1.EffectiveWorkingPluginId).CompareTo(profman.IsInDefaultProfile(p2.EffectiveWorkingPluginId)));
break;
case PluginSortKind.SearchScore:
this.pluginListAvailable = this.pluginListAvailable.OrderByDescending(this.GetManifestSearchScore).ThenBy(m => m.Name).ToList();
this.pluginListInstalled = this.pluginListInstalled.OrderByDescending(p => this.GetManifestSearchScore(p.Manifest)).ThenBy(m => m.Name).ToList();
break;
default:
throw new InvalidEnumArgumentException("Unknown plugin sort type.");
}
@ -3754,6 +3804,8 @@ internal class PluginInstallerWindow : Window, IDisposable
#region SortBy
public static string SortBy_SearchScore => Loc.Localize("InstallerSearchScore", "Search score");
public static string SortBy_Alphabetical => Loc.Localize("InstallerAlphabetical", "Alphabetical");
public static string SortBy_DownloadCounts => Loc.Localize("InstallerDownloadCount", "Download Count");