Optimization of PluginInstallerWindow

Refactored repository selection logic. Reduced code duplication and improving maintainability. Added caching for third-party repo list to avoid unnecessary rebuilds. Updated repo filter logic to use normalized URLs for more reliable matching.
This commit is contained in:
Jerric 2025-12-25 15:10:30 -05:00
parent 2539d330ac
commit a563c8355f

View file

@ -127,10 +127,25 @@ internal class PluginInstallerWindow : Window, IDisposable
private bool adaptiveSort = true; private bool adaptiveSort = true;
private string? selectedRepoUrl = null; // null = All Repositories private string? selectedRepoUrl = null; // null = All Repositories
private List<string> cachedRepoUrls = new(); private string selectedRepoUrlNormalized = string.Empty;
private HashSet<string> cachedRepoUrlsNormalized = new(StringComparer.OrdinalIgnoreCase); private int repoFilterCacheKey = 0;
private readonly List<string> cachedRepoUrls = new();
private readonly HashSet<string> cachedRepoUrlsNormalized = new(StringComparer.OrdinalIgnoreCase);
private const string XivLauncherRepoKey = "XIVLauncher"; private const string XivLauncherRepoKey = "XIVLauncher";
private void SetSelectedRepo(string? repoUrl)
{
if (this.selectedRepoUrl == repoUrl)
return;
this.selectedRepoUrl = repoUrl;
this.selectedRepoUrlNormalized = NormalizeRepoUrl(repoUrl);
this.UpdateCategoriesOnPluginsChange();
this.openPluginCollapsibles.Clear();
}
private OperationStatus installStatus = OperationStatus.Idle; private OperationStatus installStatus = OperationStatus.Idle;
private OperationStatus updateStatus = OperationStatus.Idle; private OperationStatus updateStatus = OperationStatus.Idle;
@ -817,16 +832,12 @@ internal class PluginInstallerWindow : Window, IDisposable
{ {
if (ImGui.Selectable("All Repositories", this.selectedRepoUrl == null)) if (ImGui.Selectable("All Repositories", this.selectedRepoUrl == null))
{ {
this.selectedRepoUrl = null; this.SetSelectedRepo(null);
this.UpdateCategoriesOnPluginsChange();
this.openPluginCollapsibles.Clear();
} }
if (ImGui.Selectable("XIVLauncher", this.selectedRepoUrl == XivLauncherRepoKey)) if (ImGui.Selectable("XIVLauncher", this.selectedRepoUrl == XivLauncherRepoKey))
{ {
this.selectedRepoUrl = XivLauncherRepoKey; this.SetSelectedRepo(XivLauncherRepoKey);
this.UpdateCategoriesOnPluginsChange();
this.openPluginCollapsibles.Clear();
} }
ImGui.Separator(); ImGui.Separator();
@ -839,9 +850,7 @@ internal class PluginInstallerWindow : Window, IDisposable
// Use stable unique IDs to avoid ImGui collisions with long/duplicate URLs. // Use stable unique IDs to avoid ImGui collisions with long/duplicate URLs.
if (ImGui.Selectable($"{repoUrl}##repo_{i}", selected)) if (ImGui.Selectable($"{repoUrl}##repo_{i}", selected))
{ {
this.selectedRepoUrl = repoUrl; this.SetSelectedRepo(repoUrl);
this.UpdateCategoriesOnPluginsChange();
this.openPluginCollapsibles.Clear();
} }
} }
@ -4067,6 +4076,24 @@ internal class PluginInstallerWindow : Window, IDisposable
{ {
var config = Service<DalamudConfiguration>.Get(); var config = Service<DalamudConfiguration>.Get();
// Avoid rebuilding every frame unless the repo list actually changed.
var newKey = 17;
unchecked
{
foreach (var repo in config.ThirdRepoList)
{
if (string.IsNullOrWhiteSpace(repo.Url))
continue;
newKey = (newKey * 31) + StringComparer.OrdinalIgnoreCase.GetHashCode(repo.Url.Trim());
}
}
if (newKey == this.repoFilterCacheKey)
return;
this.repoFilterCacheKey = newKey;
this.cachedRepoUrls.Clear(); this.cachedRepoUrls.Clear();
this.cachedRepoUrlsNormalized.Clear(); this.cachedRepoUrlsNormalized.Clear();
@ -4168,10 +4195,10 @@ internal class PluginInstallerWindow : Window, IDisposable
return true; return true;
// Anything not matching the configured third-party repos is considered "XIVLauncher". // Anything not matching the configured third-party repos is considered "XIVLauncher".
return !this.cachedRepoUrlsNormalized.Any(u => RepoUrlMatches(u, normalized) || string.Equals(u, normalized, StringComparison.OrdinalIgnoreCase)); return !this.cachedRepoUrlsNormalized.Contains(normalized);
} }
return RepoUrlMatches(repoUrl, this.selectedRepoUrl); return RepoUrlMatches(repoUrl, this.selectedRepoUrlNormalized);
} }
private bool PassesRepoFilter(RemotePluginManifest manifest) => this.PassesRepoFilter(GetRepoFilterUrl(manifest)); private bool PassesRepoFilter(RemotePluginManifest manifest) => this.PassesRepoFilter(GetRepoFilterUrl(manifest));