mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-25 06:01:49 +01:00
Merge fadbb406f2 into bef50438f5
This commit is contained in:
commit
90d58d67b0
2 changed files with 277 additions and 9 deletions
|
|
@ -31,6 +31,9 @@ internal class PluginCategoryManager
|
||||||
new(CategoryKind.PluginChangelogs, "special.plugins", () => Locs.Category_Plugins),
|
new(CategoryKind.PluginChangelogs, "special.plugins", () => Locs.Category_Plugins),
|
||||||
new(CategoryKind.PluginProfiles, "special.profiles", () => Locs.Category_PluginProfiles),
|
new(CategoryKind.PluginProfiles, "special.profiles", () => Locs.Category_PluginProfiles),
|
||||||
new(CategoryKind.UpdateablePlugins, "special.updateable", () => Locs.Category_UpdateablePlugins),
|
new(CategoryKind.UpdateablePlugins, "special.updateable", () => Locs.Category_UpdateablePlugins),
|
||||||
|
new(CategoryKind.EnabledPlugins, "special.enabled", () => Locs.Category_EnabledPlugins),
|
||||||
|
new(CategoryKind.DisabledPlugins, "special.disabled", () => Locs.Category_DisabledPlugins),
|
||||||
|
new(CategoryKind.IncompatiblePlugins, "special.incompatible", () => Locs.Category_IncompatiblePlugins),
|
||||||
|
|
||||||
// Tag-driven categories
|
// Tag-driven categories
|
||||||
new(CategoryKind.Other, "other", () => Locs.Category_Other),
|
new(CategoryKind.Other, "other", () => Locs.Category_Other),
|
||||||
|
|
@ -48,7 +51,7 @@ internal class PluginCategoryManager
|
||||||
private GroupInfo[] groupList =
|
private GroupInfo[] groupList =
|
||||||
[
|
[
|
||||||
new(GroupKind.DevTools, () => Locs.Group_DevTools, CategoryKind.DevInstalled, CategoryKind.IconTester),
|
new(GroupKind.DevTools, () => Locs.Group_DevTools, CategoryKind.DevInstalled, CategoryKind.IconTester),
|
||||||
new(GroupKind.Installed, () => Locs.Group_Installed, CategoryKind.All, CategoryKind.IsTesting, CategoryKind.UpdateablePlugins, CategoryKind.PluginProfiles),
|
new(GroupKind.Installed, () => Locs.Group_Installed, CategoryKind.All, CategoryKind.IsTesting, CategoryKind.UpdateablePlugins, CategoryKind.EnabledPlugins, CategoryKind.DisabledPlugins, CategoryKind.IncompatiblePlugins, CategoryKind.PluginProfiles),
|
||||||
new(GroupKind.Available, () => Locs.Group_Available, CategoryKind.All),
|
new(GroupKind.Available, () => Locs.Group_Available, CategoryKind.All),
|
||||||
new(GroupKind.Changelog, () => Locs.Group_Changelog, CategoryKind.All, CategoryKind.DalamudChangelogs, CategoryKind.PluginChangelogs)
|
new(GroupKind.Changelog, () => Locs.Group_Changelog, CategoryKind.All, CategoryKind.DalamudChangelogs, CategoryKind.PluginChangelogs)
|
||||||
|
|
||||||
|
|
@ -143,6 +146,21 @@ internal class PluginCategoryManager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
UpdateablePlugins = 15,
|
UpdateablePlugins = 15,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enabled plugins.
|
||||||
|
/// </summary>
|
||||||
|
EnabledPlugins = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disabled plugins.
|
||||||
|
/// </summary>
|
||||||
|
DisabledPlugins = 17,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Incompatible plugins.
|
||||||
|
/// </summary>
|
||||||
|
IncompatiblePlugins = 18,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Plugins tagged as "other".
|
/// Plugins tagged as "other".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -556,6 +574,12 @@ internal class PluginCategoryManager
|
||||||
|
|
||||||
public static string Category_UpdateablePlugins => Loc.Localize("InstallerCategoryCanBeUpdated", "Can be updated");
|
public static string Category_UpdateablePlugins => Loc.Localize("InstallerCategoryCanBeUpdated", "Can be updated");
|
||||||
|
|
||||||
|
public static string Category_EnabledPlugins => Loc.Localize("InstallerCategoryEnabledPlugins", "Enabled");
|
||||||
|
|
||||||
|
public static string Category_DisabledPlugins => Loc.Localize("InstallerCategoryDisabledPlugins", "Disabled");
|
||||||
|
|
||||||
|
public static string Category_IncompatiblePlugins => Loc.Localize("InstallerCategoryIncompatiblePlugins", "Incompatible");
|
||||||
|
|
||||||
public static string Category_Other => Loc.Localize("InstallerCategoryOther", "Other");
|
public static string Category_Other => Loc.Localize("InstallerCategoryOther", "Other");
|
||||||
|
|
||||||
public static string Category_Jobs => Loc.Localize("InstallerCategoryJobs", "Jobs");
|
public static string Category_Jobs => Loc.Localize("InstallerCategoryJobs", "Jobs");
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,27 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
private string filterText = Locs.SortBy_Alphabetical;
|
private string filterText = Locs.SortBy_Alphabetical;
|
||||||
private bool adaptiveSort = true;
|
private bool adaptiveSort = true;
|
||||||
|
|
||||||
private OperationStatus installStatus = OperationStatus.Idle;
|
private string? selectedRepoUrl = null; // null = All Repositories
|
||||||
|
private string selectedRepoUrlNormalized = string.Empty;
|
||||||
|
private int repoFilterCacheKey = 0;
|
||||||
|
|
||||||
|
private readonly List<string> cachedRepoUrls = new();
|
||||||
|
private readonly HashSet<string> cachedRepoUrlsNormalized = new(StringComparer.OrdinalIgnoreCase);
|
||||||
|
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 updateStatus = OperationStatus.Idle;
|
private OperationStatus updateStatus = OperationStatus.Idle;
|
||||||
|
|
||||||
private OperationStatus enableDisableStatus = OperationStatus.Idle;
|
private OperationStatus enableDisableStatus = OperationStatus.Idle;
|
||||||
|
|
@ -236,6 +256,9 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
Testing,
|
Testing,
|
||||||
Updateable,
|
Updateable,
|
||||||
Dev,
|
Dev,
|
||||||
|
Enabled,
|
||||||
|
Disabled,
|
||||||
|
Incompatible,
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool AnyOperationInProgress => this.installStatus == OperationStatus.InProgress ||
|
private bool AnyOperationInProgress => this.installStatus == OperationStatus.InProgress ||
|
||||||
|
|
@ -787,8 +810,63 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
ImGui.EndCombo();
|
ImGui.EndCombo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Repository filter (overarching filter for repositories)
|
||||||
|
this.RefreshRepoFilterList();
|
||||||
|
|
||||||
|
// Disabled for dev plugin list, changelog views, or profile editor (plugin collections).
|
||||||
|
var disableRepoFilter =
|
||||||
|
isProfileManager ||
|
||||||
|
this.categoryManager.CurrentGroupKind is
|
||||||
|
PluginCategoryManager.GroupKind.Changelog or
|
||||||
|
PluginCategoryManager.GroupKind.DevTools;
|
||||||
|
|
||||||
|
using (ImRaii.Disabled(disableRepoFilter))
|
||||||
|
{
|
||||||
|
ImGuiHelpers.ScaledDummy(5);
|
||||||
|
|
||||||
|
ImGui.AlignTextToFramePadding();
|
||||||
|
ImGui.TextUnformatted("Repository Filter");
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
// Fill remaining width of the header row
|
||||||
|
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
|
||||||
|
|
||||||
|
var repoPreview = this.selectedRepoUrl ?? "All Repositories";
|
||||||
|
if (ImGui.BeginCombo("##RepoFilterCombo", repoPreview))
|
||||||
|
{
|
||||||
|
if (ImGui.Selectable("All Repositories", this.selectedRepoUrl == null))
|
||||||
|
{
|
||||||
|
this.SetSelectedRepo(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui.Selectable("XIVLauncher", this.selectedRepoUrl == XivLauncherRepoKey))
|
||||||
|
{
|
||||||
|
this.SetSelectedRepo(XivLauncherRepoKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
for (var i = 0; i < this.cachedRepoUrls.Count; i++)
|
||||||
|
{
|
||||||
|
var repoUrl = this.cachedRepoUrls[i];
|
||||||
|
var selected = this.selectedRepoUrl == repoUrl;
|
||||||
|
|
||||||
|
// Use stable unique IDs to avoid ImGui collisions with long/duplicate URLs.
|
||||||
|
if (ImGui.Selectable($"{repoUrl}##repo_{i}", selected))
|
||||||
|
{
|
||||||
|
this.SetSelectedRepo(repoUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGuiHelpers.ScaledDummy(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawFooter()
|
private void DrawFooter()
|
||||||
{
|
{
|
||||||
var configuration = Service<DalamudConfiguration>.Get();
|
var configuration = Service<DalamudConfiguration>.Get();
|
||||||
|
|
@ -1304,6 +1382,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
|
|
||||||
var filteredAvailableManifests = availableManifests
|
var filteredAvailableManifests = availableManifests
|
||||||
.Where(rm => !this.IsManifestFiltered(rm))
|
.Where(rm => !this.IsManifestFiltered(rm))
|
||||||
|
.Where(this.PassesRepoFilter)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (filteredAvailableManifests.Count == 0)
|
if (filteredAvailableManifests.Count == 0)
|
||||||
|
|
@ -1316,7 +1395,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
{
|
{
|
||||||
var plugin = this.pluginListInstalled
|
var plugin = this.pluginListInstalled
|
||||||
.FirstOrDefault(plugin => plugin.Manifest.InternalName == availableManifest.InternalName &&
|
.FirstOrDefault(plugin => plugin.Manifest.InternalName == availableManifest.InternalName &&
|
||||||
plugin.Manifest.RepoUrl == availableManifest.RepoUrl &&
|
RepoUrlMatches(GetRepoFilterUrl(plugin), GetRepoFilterUrl(availableManifest)) &&
|
||||||
!plugin.IsDev);
|
!plugin.IsDev);
|
||||||
|
|
||||||
// We "consumed" this plugin from the pile and remove it.
|
// We "consumed" this plugin from the pile and remove it.
|
||||||
|
|
@ -1337,6 +1416,9 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
if (this.IsManifestFiltered(installedPlugin.Manifest))
|
if (this.IsManifestFiltered(installedPlugin.Manifest))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (!this.PassesRepoFilter(GetRepoFilterUrl(installedPlugin)))
|
||||||
|
continue;
|
||||||
|
|
||||||
// TODO: We should also check categories here, for good measure
|
// TODO: We should also check categories here, for good measure
|
||||||
|
|
||||||
proxies.Add(new PluginInstallerAvailablePluginProxy(null, installedPlugin));
|
proxies.Add(new PluginInstallerAvailablePluginProxy(null, installedPlugin));
|
||||||
|
|
@ -1439,6 +1521,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
|
|
||||||
var filteredList = pluginList
|
var filteredList = pluginList
|
||||||
.Where(plugin => !this.IsManifestFiltered(plugin.Manifest))
|
.Where(plugin => !this.IsManifestFiltered(plugin.Manifest))
|
||||||
|
.Where(plugin => this.PassesRepoFilter(!string.IsNullOrWhiteSpace(plugin.Manifest.InstalledFromUrl) ? plugin.Manifest.InstalledFromUrl : plugin.Manifest.RepoUrl))
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (filteredList.Count == 0)
|
if (filteredList.Count == 0)
|
||||||
|
|
@ -1454,6 +1537,15 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
if (filter == InstalledPluginListFilter.Testing && !manager.HasTestingOptIn(plugin.Manifest))
|
if (filter == InstalledPluginListFilter.Testing && !manager.HasTestingOptIn(plugin.Manifest))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (filter == InstalledPluginListFilter.Enabled && (!plugin.IsWantedByAnyProfile || plugin.IsOutdated || plugin.IsBanned || plugin.IsOrphaned || plugin.IsDecommissioned))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (filter == InstalledPluginListFilter.Disabled && (plugin.IsWantedByAnyProfile || plugin.IsOutdated || plugin.IsBanned || plugin.IsOrphaned || plugin.IsDecommissioned))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (filter == InstalledPluginListFilter.Incompatible && !(plugin.IsOutdated || plugin.IsBanned || plugin.IsOrphaned || plugin.IsDecommissioned))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Find applicable update and manifest, if we have them
|
// Find applicable update and manifest, if we have them
|
||||||
AvailablePluginUpdate? update = null;
|
AvailablePluginUpdate? update = null;
|
||||||
RemotePluginManifest? remoteManifest = null;
|
RemotePluginManifest? remoteManifest = null;
|
||||||
|
|
@ -1467,7 +1559,7 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
// Find the applicable remote manifest
|
// Find the applicable remote manifest
|
||||||
remoteManifest = this.pluginListAvailable
|
remoteManifest = this.pluginListAvailable
|
||||||
.FirstOrDefault(rm => rm.InternalName == plugin.Manifest.InternalName &&
|
.FirstOrDefault(rm => rm.InternalName == plugin.Manifest.InternalName &&
|
||||||
rm.RepoUrl == plugin.Manifest.RepoUrl);
|
RepoUrlMatches(rm.RepoUrl, plugin.Manifest.RepoUrl));
|
||||||
}
|
}
|
||||||
else if (!plugin.IsDev)
|
else if (!plugin.IsDev)
|
||||||
{
|
{
|
||||||
|
|
@ -1486,6 +1578,9 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
InstalledPluginListFilter.Testing => Locs.TabBody_NoPluginsTesting,
|
InstalledPluginListFilter.Testing => Locs.TabBody_NoPluginsTesting,
|
||||||
InstalledPluginListFilter.Updateable => Locs.TabBody_NoPluginsUpdateable,
|
InstalledPluginListFilter.Updateable => Locs.TabBody_NoPluginsUpdateable,
|
||||||
InstalledPluginListFilter.Dev => Locs.TabBody_NoPluginsDev,
|
InstalledPluginListFilter.Dev => Locs.TabBody_NoPluginsDev,
|
||||||
|
InstalledPluginListFilter.Enabled => Locs.TabBody_NoPluginsEnabled,
|
||||||
|
InstalledPluginListFilter.Disabled => Locs.TabBody_NoPluginsDisabled,
|
||||||
|
InstalledPluginListFilter.Incompatible => Locs.TabBody_NoPluginsIncompatible,
|
||||||
_ => throw new ArgumentException(null, nameof(filter)),
|
_ => throw new ArgumentException(null, nameof(filter)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1726,6 +1821,18 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
this.DrawInstalledPluginList(InstalledPluginListFilter.Updateable);
|
this.DrawInstalledPluginList(InstalledPluginListFilter.Updateable);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PluginCategoryManager.CategoryKind.EnabledPlugins:
|
||||||
|
this.DrawInstalledPluginList(InstalledPluginListFilter.Enabled);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PluginCategoryManager.CategoryKind.DisabledPlugins:
|
||||||
|
this.DrawInstalledPluginList(InstalledPluginListFilter.Disabled);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PluginCategoryManager.CategoryKind.IncompatiblePlugins:
|
||||||
|
this.DrawInstalledPluginList(InstalledPluginListFilter.Incompatible);
|
||||||
|
break;
|
||||||
|
|
||||||
case PluginCategoryManager.CategoryKind.PluginProfiles:
|
case PluginCategoryManager.CategoryKind.PluginProfiles:
|
||||||
this.profileManagerWidget.Draw();
|
this.profileManagerWidget.Draw();
|
||||||
break;
|
break;
|
||||||
|
|
@ -3950,12 +4057,12 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var pluginsMatchingSearch = this.pluginListAvailable.Where(rm => !this.IsManifestFiltered(rm)).ToArray();
|
var pluginsMatchingSearch = this.pluginListAvailable.Where(rm => this.PassesRepoFilter(rm) && !this.IsManifestFiltered(rm)).ToArray();
|
||||||
|
|
||||||
// Check if the search results are different, and clear the open collapsibles if they are
|
// Check if the search results are different, and clear the open collapsibles if they are
|
||||||
if (previousSearchText != null)
|
if (previousSearchText != null)
|
||||||
{
|
{
|
||||||
var previousSearchResults = this.pluginListAvailable.Where(rm => !this.IsManifestFiltered(rm)).ToArray();
|
var previousSearchResults = this.pluginListAvailable.Where(rm => this.PassesRepoFilter(rm) && !this.IsManifestFiltered(rm)).ToArray();
|
||||||
if (!previousSearchResults.SequenceEqual(pluginsMatchingSearch))
|
if (!previousSearchResults.SequenceEqual(pluginsMatchingSearch))
|
||||||
this.openPluginCollapsibles.Clear();
|
this.openPluginCollapsibles.Clear();
|
||||||
}
|
}
|
||||||
|
|
@ -3966,11 +4073,142 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
|
|
||||||
private void UpdateCategoriesOnPluginsChange()
|
private void UpdateCategoriesOnPluginsChange()
|
||||||
{
|
{
|
||||||
this.categoryManager.BuildCategories(this.pluginListAvailable);
|
this.categoryManager.BuildCategories(this.pluginListAvailable.Where(this.PassesRepoFilter).ToList());
|
||||||
this.UpdateCategoriesOnSearchChange(null);
|
this.UpdateCategoriesOnSearchChange(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawFontawesomeIconOutlined(FontAwesomeIcon icon, Vector4 outline, Vector4 iconColor)
|
private void RefreshRepoFilterList()
|
||||||
|
{
|
||||||
|
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.cachedRepoUrlsNormalized.Clear();
|
||||||
|
|
||||||
|
// Main repo is represented by the "XIVLauncher" entry; here we only list third-party repos.
|
||||||
|
var seenDisplay = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
foreach (var repo in config.ThirdRepoList)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(repo.Url))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var trimmed = repo.Url.Trim();
|
||||||
|
if (!seenDisplay.Add(trimmed))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this.cachedRepoUrls.Add(trimmed);
|
||||||
|
|
||||||
|
var normalized = NormalizeRepoUrl(trimmed);
|
||||||
|
if (!string.IsNullOrEmpty(normalized))
|
||||||
|
this.cachedRepoUrlsNormalized.Add(normalized);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static string NormalizeRepoUrl(string? url)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(url))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
url = url.Trim();
|
||||||
|
|
||||||
|
// Best-effort URI normalization: ignore query/fragment; compare by path.
|
||||||
|
if (Uri.TryCreate(url, UriKind.Absolute, out var uri))
|
||||||
|
{
|
||||||
|
var left = uri.GetLeftPart(UriPartial.Path);
|
||||||
|
return left.TrimEnd('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
return url.TrimEnd('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool RepoUrlMatches(string? a, string? b)
|
||||||
|
{
|
||||||
|
var na = NormalizeRepoUrl(a);
|
||||||
|
var nb = NormalizeRepoUrl(b);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(na) || string.IsNullOrEmpty(nb))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (string.Equals(na, nb, StringComparison.OrdinalIgnoreCase))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Allow prefix matches to handle minor formatting differences (e.g. /api/6 suffix).
|
||||||
|
// Ensure the prefix boundary is a path separator.
|
||||||
|
if (na.Length < nb.Length && nb.StartsWith(na, StringComparison.OrdinalIgnoreCase))
|
||||||
|
return nb[na.Length] == '/';
|
||||||
|
|
||||||
|
if (nb.Length < na.Length && na.StartsWith(nb, StringComparison.OrdinalIgnoreCase))
|
||||||
|
return na[nb.Length] == '/';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static string? GetRepoFilterUrl(RemotePluginManifest manifest)
|
||||||
|
{
|
||||||
|
// For available manifests, RepoUrl is often the plugin's project URL (or null).
|
||||||
|
// The repository identity we care about is the *source repo* (pluginmaster URL) vs XIVLauncher (main repo).
|
||||||
|
if (manifest.SourceRepo != null && manifest.SourceRepo.IsThirdParty)
|
||||||
|
return manifest.SourceRepo.PluginMasterUrl;
|
||||||
|
|
||||||
|
return PluginRepository.MainRepoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetRepoFilterUrl(LocalPlugin plugin)
|
||||||
|
{
|
||||||
|
// Installed third-party plugins store their origin in InstalledFromUrl.
|
||||||
|
if (plugin.IsThirdParty)
|
||||||
|
return plugin.Manifest.InstalledFromUrl;
|
||||||
|
|
||||||
|
return PluginRepository.MainRepoUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PassesRepoFilter(string? repoUrl)
|
||||||
|
{
|
||||||
|
// null => All Repositories
|
||||||
|
if (this.selectedRepoUrl == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Anything not from the user's third-party repo list
|
||||||
|
if (this.selectedRepoUrl == XivLauncherRepoKey)
|
||||||
|
{
|
||||||
|
// Treat empty and the known main repo URL as "XIVLauncher"
|
||||||
|
if (string.IsNullOrWhiteSpace(repoUrl) || RepoUrlMatches(repoUrl, PluginRepository.MainRepoUrl))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var normalized = NormalizeRepoUrl(repoUrl);
|
||||||
|
if (string.IsNullOrEmpty(normalized))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Anything not matching the configured third-party repos is considered "XIVLauncher".
|
||||||
|
return !this.cachedRepoUrlsNormalized.Contains(normalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RepoUrlMatches(repoUrl, this.selectedRepoUrlNormalized);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool PassesRepoFilter(RemotePluginManifest manifest) => this.PassesRepoFilter(GetRepoFilterUrl(manifest));
|
||||||
|
|
||||||
|
private void DrawFontawesomeIconOutlined(FontAwesomeIcon icon, Vector4 outline, Vector4 iconColor)
|
||||||
{
|
{
|
||||||
var positionOffset = ImGuiHelpers.ScaledVector2(0.0f, 1.0f);
|
var positionOffset = ImGuiHelpers.ScaledVector2(0.0f, 1.0f);
|
||||||
var cursorStart = ImGui.GetCursorPos() + positionOffset;
|
var cursorStart = ImGui.GetCursorPos() + positionOffset;
|
||||||
|
|
@ -4098,6 +4336,12 @@ internal class PluginInstallerWindow : Window, IDisposable
|
||||||
|
|
||||||
public static string TabBody_NoPluginsDev => Loc.Localize("InstallerNoPluginsDev", "You don't have any dev plugins. Add them from the settings.");
|
public static string TabBody_NoPluginsDev => Loc.Localize("InstallerNoPluginsDev", "You don't have any dev plugins. Add them from the settings.");
|
||||||
|
|
||||||
|
public static string TabBody_NoPluginsEnabled => Loc.Localize("InstallerNoPluginsEnabled", "You don't have any enabled plugins.");
|
||||||
|
|
||||||
|
public static string TabBody_NoPluginsDisabled => Loc.Localize("InstallerNoPluginsDisabled", "You don't have any disabled plugins.");
|
||||||
|
|
||||||
|
public static string TabBody_NoPluginsIncompatible => Loc.Localize("InstallerNoPluginsIncompatible", "You don't have any incompatible plugins.");
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Search text
|
#region Search text
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue