feat(settings): add About tab with brand, links, credits

This commit is contained in:
2026-05-26 20:20:53 +02:00
parent 262fb3022a
commit 490da3e908
5 changed files with 131 additions and 1 deletions
+3
View File
@@ -10,6 +10,8 @@ internal static class BrandingLinks
public const string HellionForgeGitea = "https://gitea.hellion-forge.cloud/Hellion-Forge"; public const string HellionForgeGitea = "https://gitea.hellion-forge.cloud/Hellion-Forge";
public const string HellionChatRepo = public const string HellionChatRepo =
"https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat"; "https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat";
public const string HellionChatCustomRepoManifest =
"https://gitea.hellion-forge.cloud/JonKazama-Hellion/HellionChat/raw/branch/main/repo.json";
public const string HellionForgeWebsite = "https://hellion-forge.cloud"; public const string HellionForgeWebsite = "https://hellion-forge.cloud";
public const string HellionMediaWebsite = "https://hellion-media.de/de"; public const string HellionMediaWebsite = "https://hellion-media.de/de";
@@ -26,6 +28,7 @@ internal static class BrandingLinks
HellionForgeDiscordInvite, HellionForgeDiscordInvite,
HellionForgeGitea, HellionForgeGitea,
HellionChatRepo, HellionChatRepo,
HellionChatCustomRepoManifest,
HellionForgeWebsite, HellionForgeWebsite,
HellionMediaWebsite HellionMediaWebsite
); );
+1 -1
View File
@@ -35,7 +35,7 @@ public class ConfigKeyBind
[Serializable] [Serializable]
public class Configuration : IPluginConfiguration public class Configuration : IPluginConfiguration
{ {
private const int LatestVersion = 20; internal const int LatestVersion = 20;
public int Version { get; set; } = LatestVersion; public int Version { get; set; } = LatestVersion;
+4
View File
@@ -183,6 +183,10 @@ internal static class PluginHostFactory
services.AddSingleton(sp => new Ui.Components.Settings.Tabs.DataPrivacyTab( services.AddSingleton(sp => new Ui.Components.Settings.Tabs.DataPrivacyTab(
sp.GetRequiredService<Plugin>() sp.GetRequiredService<Plugin>()
)); ));
services.AddSingleton(sp => new Ui.Components.Settings.Tabs.AboutTab(
sp.GetRequiredService<FontManager>(),
sp.GetRequiredService<ILogger<Ui.Components.Settings.Tabs.AboutTab>>()
));
services.AddSingleton(sp => new Ui.Components.StatusBar( services.AddSingleton(sp => new Ui.Components.StatusBar(
sp.GetRequiredService<ThemeRegistry>(), sp.GetRequiredService<ThemeRegistry>(),
sp.GetRequiredService<FontManager>() sp.GetRequiredService<FontManager>()
@@ -0,0 +1,117 @@
using System.Diagnostics;
using System.Reflection;
using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using HellionChat.Branding;
using Microsoft.Extensions.Logging;
namespace HellionChat.Ui.Components.Settings.Tabs;
internal sealed class AboutTab
{
private readonly FontManager _fonts;
private readonly ILogger<AboutTab> _logger;
public AboutTab(FontManager fonts, ILogger<AboutTab> logger)
{
_fonts = fonts;
_logger = logger;
}
public void Draw()
{
DrawPluginInfo();
DrawSectionHeader("Brand");
DrawBrand();
DrawSectionHeader("Links");
DrawLinks();
DrawSectionHeader("Credits");
DrawCredits();
DrawSectionHeader("License");
DrawLicense();
}
// Dalamud.Bindings.ImGui does not expose ImGui.SeparatorText, so we use
// the Separator + TextUnformatted idiom the rest of the codebase uses.
private static void DrawSectionHeader(string title)
{
ImGui.Spacing();
ImGui.Separator();
ImGui.Spacing();
ImGui.TextUnformatted(title);
}
private static void DrawPluginInfo()
{
var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
ImGui.TextUnformatted("HellionChat");
// Schema version pulled from Configuration.LatestVersion (single source of
// truth) so future schema bumps don't have to touch this string.
ImGui.TextDisabled($"Version {version} · Schema v{Configuration.LatestVersion}");
}
private void DrawBrand()
{
using (_fonts.FontAwesome.Push())
{
// ImGui's PushStyleColor uint API is ABGR-native. 0xFF0C41C2u packs
// as A=FF B=0C G=41 R=C2 → RGB #C2410C (Forge-Bronze). No swap needed
// because the literal is already ABGR; theme-sourced uints from
// ThemeColors.* (RGBA) would need ColourUtil.RgbaToAbgr first.
ImGui.PushStyleColor(ImGuiCol.Text, 0xFF0C41C2u);
ImGui.TextUnformatted(FontAwesomeIcon.Hammer.ToIconString());
ImGui.PopStyleColor();
}
ImGui.SameLine();
ImGui.TextUnformatted("by Hellion Online Media");
ImGui.TextDisabled("Hellion Forge — Modding Division");
}
private void DrawLinks()
{
DrawLinkButton("Discord (Hellion Forge)", BrandingLinks.HellionForgeDiscordInvite);
DrawLinkButton("Gitea repository", BrandingLinks.HellionChatRepo);
DrawLinkButton("Custom repo manifest", BrandingLinks.HellionChatCustomRepoManifest);
}
// URLs in v1.7.0 are exclusively hardcoded BrandingLinks.* constants —
// Process.Start with UseShellExecute=true is safe under that constraint.
// If a future cycle ever feeds user-supplied URLs here, add an https/http
// allow-list filter via Uri.TryCreate before Process.Start; without it
// UseShellExecute would happily launch file:// or shell-protocol handlers.
private void DrawLinkButton(string label, string url)
{
if (ImGui.Button(label))
{
try
{
Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Could not open {Url}, copying to clipboard instead", url);
ImGui.SetClipboardText(url);
}
}
ImGui.SameLine();
if (ImGui.SmallButton($"Copy##{url}"))
{
ImGui.SetClipboardText(url);
}
}
private static void DrawCredits()
{
ImGui.BulletText("ChatTwo — original maintainer Anna Clemens, GPL-3.0");
ImGui.BulletText("Dalamud — goatcorp, AGPL-3.0");
ImGui.BulletText("ImGui — Omar Cornut, MIT");
ImGui.BulletText("FontAwesome — Fonticons, OFL-1.1");
ImGui.BulletText("Inter — rsms, OFL-1.1");
ImGui.BulletText("NotoSansCJK — Google, OFL-1.1");
}
private static void DrawLicense()
{
ImGui.TextUnformatted("GPL-3.0-or-later");
}
}
+6
View File
@@ -25,6 +25,7 @@ internal sealed class SettingsWindow : Window
private readonly WindowTab _window; private readonly WindowTab _window;
private readonly ChannelsTab _channels; private readonly ChannelsTab _channels;
private readonly DataPrivacyTab _dataPrivacy; private readonly DataPrivacyTab _dataPrivacy;
private readonly AboutTab _about;
public SettingsWindow( public SettingsWindow(
Plugin plugin, Plugin plugin,
@@ -39,6 +40,7 @@ internal sealed class SettingsWindow : Window
WindowTab window, WindowTab window,
ChannelsTab channels, ChannelsTab channels,
DataPrivacyTab dataPrivacy, DataPrivacyTab dataPrivacy,
AboutTab about,
ILoggerFactory loggerFactory ILoggerFactory loggerFactory
) )
: base($"{Language.Settings_Title.Format(Plugin.PluginName)}###chat2-settings") : base($"{Language.Settings_Title.Format(Plugin.PluginName)}###chat2-settings")
@@ -55,6 +57,7 @@ internal sealed class SettingsWindow : Window
_window = window; _window = window;
_channels = channels; _channels = channels;
_dataPrivacy = dataPrivacy; _dataPrivacy = dataPrivacy;
_about = about;
_ = loggerFactory; _ = loggerFactory;
Size = new Vector2(720, 540); Size = new Vector2(720, 540);
@@ -98,6 +101,9 @@ internal sealed class SettingsWindow : Window
case "data-privacy": case "data-privacy":
_dataPrivacy.Draw(); _dataPrivacy.Draw();
break; break;
case "about":
_about.Draw();
break;
case "appearance": case "appearance":
_appearance.Draw(); _appearance.Draw();
break; break;