diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index a194f610c..234f583a3 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -14,6 +14,7 @@ using Dalamud.Game.Gui;
using Dalamud.Game.Internal;
using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Windows;
+using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Internal.Windows.SelfTest;
using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Style;
diff --git a/Dalamud/Interface/Internal/Windows/PluginImageCache.cs b/Dalamud/Interface/Internal/Windows/PluginImageCache.cs
index 834c60cf4..cf0942362 100644
--- a/Dalamud/Interface/Internal/Windows/PluginImageCache.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginImageCache.cs
@@ -64,9 +64,10 @@ namespace Dalamud.Interface.Internal.Windows
this.InstalledIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "installedIcon.png"))!;
this.ThirdIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "thirdIcon.png"))!;
this.ThirdInstalledIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "thirdInstalledIcon.png"))!;
+ this.CorePluginIcon = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "tsmLogo.png"))!;
if (this.DefaultIcon == null || this.TroubleIcon == null || this.UpdateIcon == null || this.InstalledIcon == null ||
- this.ThirdIcon == null || this.ThirdInstalledIcon == null)
+ this.ThirdIcon == null || this.ThirdInstalledIcon == null || this.CorePluginIcon == null)
{
throw new Exception("Plugin overlay images could not be loaded.");
}
@@ -105,6 +106,11 @@ namespace Dalamud.Interface.Internal.Windows
///
public TextureWrap ThirdInstalledIcon { get; }
+ ///
+ /// Gets the core plugin icon.
+ ///
+ public TextureWrap CorePluginIcon { get; }
+
///
public void Dispose()
{
@@ -114,6 +120,7 @@ namespace Dalamud.Interface.Internal.Windows
this.InstalledIcon?.Dispose();
this.ThirdIcon?.Dispose();
this.ThirdInstalledIcon?.Dispose();
+ this.CorePluginIcon?.Dispose();
this.downloadToken?.Cancel();
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelog.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelog.cs
new file mode 100644
index 000000000..dd928898f
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelog.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+
+namespace Dalamud.Interface.Internal.Windows.PluginInstaller
+{
+ ///
+ /// Class representing a Dalamud changelog.
+ ///
+ internal class DalamudChangelog
+ {
+ ///
+ /// Gets the date of the version.
+ ///
+ public DateTime Date { get; init; }
+
+ ///
+ /// Gets the relevant version number.
+ ///
+ public string Version { get; init; }
+
+ ///
+ /// Gets the list of changes.
+ ///
+ public List Changes { get; init; }
+
+ ///
+ /// Class representing the relevant changes.
+ ///
+ public class DalamudChangelogChange
+ {
+ ///
+ /// Gets the commit message.
+ ///
+ public string Message { get; init; }
+
+ ///
+ /// Gets the commit author.
+ ///
+ public string Author { get; init; }
+
+ ///
+ /// Gets the commit reference SHA.
+ ///
+ public string Sha { get; init; }
+
+ ///
+ /// Gets the commit datetime.
+ ///
+ public DateTime Date { get; init; }
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs
new file mode 100644
index 000000000..1b8b2af6c
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogEntry.cs
@@ -0,0 +1,54 @@
+using System;
+
+using ImGuiScene;
+
+namespace Dalamud.Interface.Internal.Windows.PluginInstaller
+{
+ ///
+ /// Class representing a Dalamud changelog.
+ ///
+ internal class DalamudChangelogEntry : IChangelogEntry
+ {
+ private readonly DalamudChangelog changelog;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The changelog.
+ /// The icon.
+ public DalamudChangelogEntry(DalamudChangelog changelog, TextureWrap icon)
+ {
+ this.changelog = changelog;
+ this.Icon = icon;
+
+ var changelogText = string.Empty;
+ for (var i = 0; i < changelog.Changes.Count; i++)
+ {
+ var change = changelog.Changes[i];
+ changelogText += $"{change.Message} (by {change.Author})";
+
+ if (i < changelog.Changes.Count - 1)
+ {
+ changelogText += Environment.NewLine;
+ }
+ }
+
+ this.Text = changelogText;
+ }
+
+ ///
+ public string Title => "Dalamud Core";
+
+ ///
+ public string Version => this.changelog.Version;
+
+ ///
+ public string Text { get; init; }
+
+ ///
+ public TextureWrap Icon { get; init; }
+
+ ///
+ public DateTime Date => this.changelog.Date;
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs
new file mode 100644
index 000000000..f0fef8163
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/DalamudChangelogManager.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Net.Http.Json;
+using System.Threading.Tasks;
+
+namespace Dalamud.Interface.Internal.Windows.PluginInstaller
+{
+ ///
+ /// Class responsible for managing Dalamud changelogs.
+ ///
+ internal class DalamudChangelogManager : IDisposable
+ {
+ private const string ChangelogUrl = "https://kamori.goats.dev/Plugin/CoreChangelog";
+
+ private readonly HttpClient client = new();
+
+ ///
+ /// Gets a list of all available changelogs.
+ ///
+ public IReadOnlyList? Changelogs { get; private set; }
+
+ ///
+ /// Reload the changelog list.
+ ///
+ /// A representing the asynchronous operation.
+ public async Task ReloadChangelogAsync()
+ {
+ this.Changelogs = await this.client.GetFromJsonAsync>(ChangelogUrl);
+ }
+
+ ///
+ public void Dispose()
+ {
+ this.client.Dispose();
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs
new file mode 100644
index 000000000..012b870b8
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/IChangelogEntry.cs
@@ -0,0 +1,37 @@
+using System;
+
+using ImGuiScene;
+
+namespace Dalamud.Interface.Internal.Windows.PluginInstaller
+{
+ ///
+ /// Class representing a changelog entry.
+ ///
+ internal interface IChangelogEntry
+ {
+ ///
+ /// Gets the title of the entry.
+ ///
+ string Title { get; }
+
+ ///
+ /// Gets the version this entry applies to.
+ ///
+ string Version { get; }
+
+ ///
+ /// Gets the text of the entry.
+ ///
+ string Text { get; }
+
+ ///
+ /// Gets the icon of the entry.
+ ///
+ TextureWrap Icon { get; }
+
+ ///
+ /// Gets the date of the entry.
+ ///
+ DateTime Date { get; }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs
new file mode 100644
index 000000000..fc57bfe62
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginChangelogEntry.cs
@@ -0,0 +1,52 @@
+using System;
+
+using Dalamud.Plugin.Internal;
+using Dalamud.Utility;
+using ImGuiScene;
+
+namespace Dalamud.Interface.Internal.Windows.PluginInstaller
+{
+ ///
+ /// Class representing a plugin changelog.
+ ///
+ internal class PluginChangelogEntry : IChangelogEntry
+ {
+ private readonly LocalPlugin plugin;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The plugin manifest.
+ /// The icon.
+ public PluginChangelogEntry(LocalPlugin plugin, TextureWrap icon)
+ {
+ this.plugin = plugin;
+ this.Icon = icon;
+
+ if (plugin.Manifest.Changelog.IsNullOrEmpty())
+ throw new ArgumentException("Manifest has no changelog.");
+
+ var version = plugin.AssemblyName?.Version;
+ version ??= plugin.Manifest.Testing
+ ? plugin.Manifest.TestingAssemblyVersion
+ : plugin.Manifest.AssemblyVersion;
+
+ this.Version = version!.ToString();
+ }
+
+ ///
+ public string Title => this.plugin.Manifest.Name;
+
+ ///
+ public string Version { get; init; }
+
+ ///
+ public string Text => this.plugin.Manifest.Changelog!;
+
+ ///
+ public TextureWrap Icon { get; init; }
+
+ ///
+ public DateTime Date => DateTimeOffset.FromUnixTimeSeconds(this.plugin.Manifest.LastUpdate).DateTime;
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
similarity index 98%
rename from Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs
rename to Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
index 57f984016..30e76fff2 100644
--- a/Dalamud/Interface/Internal/Windows/PluginInstallerWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
+using System.Net.Http;
using System.Numerics;
using System.Threading.Tasks;
@@ -25,7 +26,7 @@ using Dalamud.Utility;
using ImGuiNET;
using ImGuiScene;
-namespace Dalamud.Interface.Internal.Windows
+namespace Dalamud.Interface.Internal.Windows.PluginInstaller
{
///
/// Class responsible for drawing the plugin installer.
@@ -39,6 +40,9 @@ namespace Dalamud.Interface.Internal.Windows
private readonly PluginCategoryManager categoryManager = new();
private readonly PluginImageCache imageCache = new();
+ private readonly DalamudChangelogManager dalamudChangelogManager = new();
+
+ private readonly List openPluginCollapsibles = new();
#region Image Tester State
@@ -81,8 +85,6 @@ namespace Dalamud.Interface.Internal.Windows
private OperationStatus installStatus = OperationStatus.Idle;
private OperationStatus updateStatus = OperationStatus.Idle;
- private List openPluginCollapsibles = new();
-
///
/// Initializes a new instance of the class.
///
@@ -150,6 +152,7 @@ namespace Dalamud.Interface.Internal.Windows
var pluginManager = Service.Get();
_ = pluginManager.ReloadPluginMastersAsync();
+ _ = this.dalamudChangelogManager.ReloadChangelogAsync();
this.searchText = string.Empty;
this.sortKind = PluginSortKind.Alphabetical;
@@ -518,13 +521,28 @@ namespace Dalamud.Interface.Internal.Windows
return;
}
- var filteredList = this.pluginListInstalled
+ var pluginChangelogs = this.pluginListInstalled
.Where(plugin => !this.IsManifestFiltered(plugin.Manifest)
&& !plugin.Manifest.Changelog.IsNullOrEmpty())
- .OrderByDescending(plugin => plugin.Manifest.LastUpdate)
- .ToList();
+ .Select(x =>
+ {
+ var iconTex = this.imageCache.DefaultIcon;
+ var hasIcon = this.imageCache.TryGetIcon(x, x.Manifest, x.Manifest.IsThirdParty, out var cachedIconTex);
+ if (hasIcon && cachedIconTex != null)
+ {
+ iconTex = cachedIconTex;
+ }
- if (!filteredList.Any())
+ var changelog = new PluginChangelogEntry(x, iconTex);
+ return (IChangelogEntry)changelog;
+ });
+
+ var changelogs = (this.dalamudChangelogManager.Changelogs != null
+ ? pluginChangelogs
+ .Concat(this.dalamudChangelogManager.Changelogs.Select(x => new DalamudChangelogEntry(x, this.imageCache.CorePluginIcon)))
+ : pluginChangelogs).OrderByDescending(x => x.Date).ToList();
+
+ if (!changelogs.Any())
{
ImGui.TextColored(
ImGuiColors.DalamudGrey2,
@@ -535,9 +553,9 @@ namespace Dalamud.Interface.Internal.Windows
return;
}
- foreach (var plugin in filteredList)
+ foreach (var logEntry in changelogs)
{
- this.DrawChangelog(plugin);
+ this.DrawChangelog(logEntry);
}
}
@@ -1202,41 +1220,30 @@ namespace Dalamud.Interface.Internal.Windows
return isOpen;
}
- private void DrawChangelog(LocalPlugin plugin)
+ private void DrawChangelog(IChangelogEntry log)
{
ImGui.Separator();
var startCursor = ImGui.GetCursorPos();
- var iconTex = this.imageCache.DefaultIcon;
- var hasIcon = this.imageCache.TryGetIcon(plugin, plugin.Manifest, plugin.Manifest.IsThirdParty, out var cachedIconTex);
- if (hasIcon && cachedIconTex != null)
- {
- iconTex = cachedIconTex;
- }
-
var iconSize = ImGuiHelpers.ScaledVector2(64, 64);
- ImGui.Image(iconTex.ImGuiHandle, iconSize);
+ ImGui.Image(log.Icon.ImGuiHandle, iconSize);
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
var cursor = ImGui.GetCursorPos();
- ImGui.Text(plugin.Name);
+ ImGui.Text(log.Title);
ImGui.SameLine();
- var version = plugin.AssemblyName?.Version;
- version ??= plugin.Manifest.Testing
- ? plugin.Manifest.TestingAssemblyVersion
- : plugin.Manifest.AssemblyVersion;
- ImGui.TextColored(ImGuiColors.DalamudGrey3, $" v{version}");
+ ImGui.TextColored(ImGuiColors.DalamudGrey3, $" v{log.Version}");
cursor.Y += ImGui.GetTextLineHeightWithSpacing();
ImGui.SetCursorPos(cursor);
- ImGui.TextWrapped(plugin.Manifest.Changelog);
+ ImGui.TextWrapped(log.Text);
var endCursor = ImGui.GetCursorPos();
diff --git a/Dalamud/Plugin/Internal/PluginRepository.cs b/Dalamud/Plugin/Internal/PluginRepository.cs
index a3e7fbaba..55b77ce49 100644
--- a/Dalamud/Plugin/Internal/PluginRepository.cs
+++ b/Dalamud/Plugin/Internal/PluginRepository.cs
@@ -15,7 +15,7 @@ namespace Dalamud.Plugin.Internal
///
internal class PluginRepository
{
- private const string DalamudPluginsMasterUrl = "https://kamori.goats.dev/Plugin/GetPluginMaster";
+ private const string DalamudPluginsMasterUrl = "https://kamori.goats.dev/Plugin/PluginMaster";
private static readonly ModuleLog Log = new("PLUGINR");