diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs
index 2ea845ed1..5108a535e 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs
@@ -41,6 +41,9 @@ internal class DalamudChangelogEntry : IChangelogEntry
///
public string Text { get; init; }
+ ///
+ public string? Author { get; private set; } = null;
+
///
public DateTime Date => this.changelog.Date;
}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs
index 086a389d3..622ad912b 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs
@@ -1,24 +1,39 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
+using System.Threading;
using System.Threading.Tasks;
+using Dalamud.Plugin.Internal;
+using Serilog;
+
namespace Dalamud.Interface.Internal.Windows.PluginInstaller;
///
/// Class responsible for managing Dalamud changelogs.
///
-internal class DalamudChangelogManager : IDisposable
+internal class DalamudChangelogManager
{
- private const string ChangelogUrl = "https://kamori.goats.dev/Plugin/CoreChangelog";
+ private const string DalamudChangelogUrl = "https://kamori.goats.dev/Dalamud/Release/Changelog";
+ private const string PluginChangelogUrl = "https://kamori.goats.dev/Plugin/History/{0}?track={1}";
- private readonly HttpClient client = new();
+ private readonly PluginManager manager;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The responsible PluginManager.
+ public DalamudChangelogManager(PluginManager manager)
+ {
+ this.manager = manager;
+ }
///
/// Gets a list of all available changelogs.
///
- public IReadOnlyList? Changelogs { get; private set; }
+ public IReadOnlyList? Changelogs { get; private set; }
///
/// Reload the changelog list.
@@ -26,12 +41,58 @@ internal class DalamudChangelogManager : IDisposable
/// A representing the asynchronous operation.
public async Task ReloadChangelogAsync()
{
- this.Changelogs = await this.client.GetFromJsonAsync>(ChangelogUrl);
+ using var client = new HttpClient();
+ this.Changelogs = null;
+
+ var dalamudChangelogs = await client.GetFromJsonAsync>(DalamudChangelogUrl);
+ var changelogs = dalamudChangelogs.Select(x => new DalamudChangelogEntry(x)).Cast();
+
+ foreach (var plugin in this.manager.InstalledPlugins)
+ {
+ if (plugin.Manifest.IsThirdParty || !plugin.Manifest.IsDip17Plugin)
+ continue;
+
+ var pluginChangelogs = await client.GetFromJsonAsync(string.Format(
+ PluginChangelogUrl,
+ plugin.Manifest.InternalName,
+ plugin.Manifest.Dip17Channel));
+
+ changelogs = changelogs.Concat(pluginChangelogs.Versions
+ .Where(x => x.Dip17Track == plugin.Manifest.Dip17Channel)
+ .Select(x => new PluginChangelogEntry(plugin, x)));
+ }
+
+ this.Changelogs = changelogs.OrderByDescending(x => x.Date).ToList();
}
- ///
- public void Dispose()
+ ///
+ /// API response for a history of plugin versions.
+ ///
+ internal class PluginHistory
{
- this.client.Dispose();
+ ///
+ /// Gets or sets the version history of the plugin.
+ ///
+ public List Versions { get; set; } = null!;
+
+ ///
+ /// A single plugin version.
+ ///
+ internal class PluginVersion
+ {
+#pragma warning disable SA1600
+ public string Version { get; set; } = null!;
+
+ public string Dip17Track { get; set; } = null!;
+
+ public string? Changelog { get; set; }
+
+ public DateTime PublishedAt { get; set; }
+
+ public int? PrNumber { get; set; }
+
+ public string? PublishedBy { get; set; }
+#pragma warning restore SA1600
+ }
}
}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs
index 04089f23c..1f5baa1be 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs
@@ -22,6 +22,11 @@ internal interface IChangelogEntry
///
string Text { get; }
+ ///
+ /// Gets the author of the changelog.
+ ///
+ string? Author { get; }
+
///
/// Gets the date of the entry.
///
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs
index 90e78b35a..495d59d64 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs
@@ -1,7 +1,7 @@
using System;
+using CheapLoc;
using Dalamud.Plugin.Internal.Types;
-using Dalamud.Utility;
namespace Dalamud.Interface.Internal.Windows.PluginInstaller;
@@ -14,16 +14,15 @@ internal class PluginChangelogEntry : IChangelogEntry
/// Initializes a new instance of the class.
///
/// The plugin manifest.
- public PluginChangelogEntry(LocalPlugin plugin)
+ /// The changelog history entry.
+ public PluginChangelogEntry(LocalPlugin plugin, DalamudChangelogManager.PluginHistory.PluginVersion history)
{
this.Plugin = plugin;
- if (plugin.Manifest.Changelog.IsNullOrEmpty())
- throw new ArgumentException("Manifest has no changelog.");
-
- var version = plugin.Manifest.EffectiveVersion;
-
- this.Version = version!.ToString();
+ this.Version = history.Version;
+ this.Text = history.Changelog ?? Loc.Localize("ChangelogNoText", "No changelog for this version.");
+ this.Author = history.PublishedBy;
+ this.Date = history.PublishedAt;
}
///
@@ -35,11 +34,14 @@ internal class PluginChangelogEntry : IChangelogEntry
public string Title => this.Plugin.Manifest.Name;
///
- public string Version { get; init; }
+ public string Version { get; private set; }
///
- public string Text => this.Plugin.Manifest.Changelog!;
+ public string Text { get; private set; }
///
- public DateTime Date => DateTimeOffset.FromUnixTimeSeconds(this.Plugin.Manifest.LastUpdate).DateTime;
+ public string? Author { get; private set; }
+
+ ///
+ public DateTime Date { get; private set; }
}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 4710dd68b..66f706bfe 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Numerics;
+using System.Threading;
using System.Threading.Tasks;
using CheapLoc;
@@ -40,7 +41,6 @@ internal class PluginInstallerWindow : Window, IDisposable
private readonly PluginImageCache imageCache;
private readonly PluginCategoryManager categoryManager = new();
- private readonly DalamudChangelogManager dalamudChangelogManager = new();
private readonly List openPluginCollapsibles = new();
@@ -48,6 +48,10 @@ internal class PluginInstallerWindow : Window, IDisposable
private readonly object listLock = new();
+ private DalamudChangelogManager? dalamudChangelogManager;
+ private Task? dalamudChangelogRefreshTask;
+ private CancellationTokenSource? dalamudChangelogRefreshTaskCts;
+
#region Image Tester State
private string[] testerImagePaths = new string[5];
@@ -132,6 +136,8 @@ internal class PluginInstallerWindow : Window, IDisposable
if (pluginManager.PluginsReady)
this.OnInstalledPluginsChanged();
+ this.dalamudChangelogManager = new(pluginManager);
+
pluginManager.OnAvailablePluginsChanged += this.OnAvailablePluginsChanged;
pluginManager.OnInstalledPluginsChanged += this.OnInstalledPluginsChanged;
@@ -179,6 +185,8 @@ internal class PluginInstallerWindow : Window, IDisposable
///
public void Dispose()
{
+ this.dalamudChangelogRefreshTaskCts?.Cancel();
+
var pluginManager = Service.GetNullable();
if (pluginManager != null)
{
@@ -193,7 +201,6 @@ internal class PluginInstallerWindow : Window, IDisposable
var pluginManager = Service.Get();
_ = pluginManager.ReloadPluginMastersAsync();
- _ = this.dalamudChangelogManager.ReloadChangelogAsync();
this.searchText = string.Empty;
this.sortKind = PluginSortKind.Alphabetical;
@@ -837,30 +844,40 @@ internal class PluginInstallerWindow : Window, IDisposable
return;
}
- var pluginChangelogs = this.pluginListInstalled
- .Where(plugin => !this.IsManifestFiltered(plugin.Manifest)
- && !plugin.Manifest.Changelog.IsNullOrEmpty())
- .Select(x =>
- {
- var changelog = new PluginChangelogEntry(x);
- return (IChangelogEntry)changelog;
- });
+ if (this.dalamudChangelogRefreshTask?.IsFaulted == true ||
+ this.dalamudChangelogRefreshTask?.IsCanceled == true)
+ {
+ ImGui.TextColored(ImGuiColors.DalamudGrey, Locs.TabBody_ChangelogError);
+ return;
+ }
+
+ if (this.dalamudChangelogManager?.Changelogs == null)
+ {
+ ImGui.TextColored(ImGuiColors.DalamudGrey, Locs.TabBody_LoadingPlugins);
+
+ if (this.dalamudChangelogManager != null &&
+ this.dalamudChangelogRefreshTask == null)
+ {
+ this.dalamudChangelogRefreshTaskCts = new CancellationTokenSource();
+ this.dalamudChangelogRefreshTask =
+ Task.Run(this.dalamudChangelogManager.ReloadChangelogAsync, this.dalamudChangelogRefreshTaskCts.Token);
+ }
+
+ return;
+ }
IEnumerable changelogs = null;
if (displayDalamud && displayPlugins && this.dalamudChangelogManager.Changelogs != null)
{
- changelogs = pluginChangelogs
- .Concat(this.dalamudChangelogManager.Changelogs.Select(
- x => new DalamudChangelogEntry(x)));
+ changelogs = this.dalamudChangelogManager.Changelogs;
}
else if (displayDalamud && this.dalamudChangelogManager.Changelogs != null)
{
- changelogs = this.dalamudChangelogManager.Changelogs.Select(
- x => new DalamudChangelogEntry(x));
+ changelogs = this.dalamudChangelogManager.Changelogs.OfType();
}
else if (displayPlugins)
{
- changelogs = pluginChangelogs;
+ changelogs = this.dalamudChangelogManager.Changelogs.OfType();
}
var sortedChangelogs = changelogs?.OrderByDescending(x => x.Date).ToList();
@@ -2898,6 +2915,8 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string TabBody_ChangelogNone => Loc.Localize("InstallerNoChangelog", "None of your installed plugins have a changelog.");
+ public static string TabBody_ChangelogError => Loc.Localize("InstallerChangelogError", "Could not download changelogs.");
+
#endregion
#region Plugin title text