The settings window was rebuilt in v1.10.0 and v1.11.0 with its labels written straight into the C#. Every section heading and most row labels across five tabs read English in all 25 languages, which the memory notes had accepted as a known backlog. Forty-nine keys close it: seventeen section headings, the rows under them, and the two layout choices. All 25 languages, 437 keys each, no gaps and no placeholder drift in either direction. The layout labels are a property rather than a static array now. A static one would hold whichever language the plugin started in, and this plugin switches language at runtime. What stays English, deliberately: log lines and thread names, which no user reads; the two developer tools behind Shift plus Ctrl+Shift, per the decision that developer surfaces stay English; and the About tab's brand lines, attributions and licence identifiers, which are names.
263 lines
9.7 KiB
C#
263 lines
9.7 KiB
C#
using System.Reflection;
|
|
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface;
|
|
using HellionChat.Branding;
|
|
using HellionChat.Integrations;
|
|
using HellionChat.Resources;
|
|
using HellionChat.Themes;
|
|
using HellionChat.Util;
|
|
|
|
namespace HellionChat.Ui.Components.Settings.Tabs;
|
|
|
|
internal sealed class AboutTab
|
|
{
|
|
private readonly FontManager _fonts;
|
|
private readonly Plugin _plugin;
|
|
private readonly SettingsWidgets _w;
|
|
private readonly HonorificService _honorific;
|
|
private readonly ThemeRegistry _themes;
|
|
private readonly IPlatformUtil _platformUtil;
|
|
|
|
// SelfTest observable — the status key the real render path resolved.
|
|
internal string? LastHonorificStatusKey { get; private set; }
|
|
|
|
public AboutTab(
|
|
FontManager fonts,
|
|
Plugin plugin,
|
|
HonorificService honorific,
|
|
ThemeRegistry themes,
|
|
IPlatformUtil platformUtil
|
|
)
|
|
{
|
|
_fonts = fonts;
|
|
_plugin = plugin;
|
|
_w = new SettingsWidgets(plugin);
|
|
_honorific = honorific;
|
|
_themes = themes;
|
|
_platformUtil = platformUtil;
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
// Reset the SelfTest observable each frame so a stale value from a prior
|
|
// real render can never let the integrations-status SelfTest pass falsely.
|
|
LastHonorificStatusKey = null;
|
|
DrawPluginInfo();
|
|
DrawSectionHeader(HellionStrings.Settings_Section_Brand);
|
|
DrawBrand();
|
|
DrawSectionHeader(HellionStrings.Settings_Section_Links);
|
|
DrawLinks();
|
|
DrawSectionHeader(HellionStrings.Settings_Section_Integrations);
|
|
DrawIntegrations();
|
|
DrawSectionHeader(HellionStrings.Settings_Section_Credits);
|
|
DrawCredits();
|
|
DrawSectionHeader(HellionStrings.Settings_Section_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(HellionStrings.Settings_About_GiteaRepo, BrandingLinks.HellionChatRepo);
|
|
DrawLinkButton(
|
|
HellionStrings.Settings_About_CustomRepo,
|
|
BrandingLinks.HellionChatCustomRepoManifest
|
|
);
|
|
}
|
|
|
|
private void DrawIntegrations()
|
|
{
|
|
ImGui.TextWrapped(HellionStrings.Settings_Integrations_Intro);
|
|
ImGui.Spacing();
|
|
|
|
ImGui.TextUnformatted(HellionStrings.Settings_Integrations_Honorific_SectionHeader);
|
|
DrawHonorificStatus();
|
|
_w.Toggle(
|
|
HellionStrings.Settings_Integrations_Honorific_Toggle,
|
|
() => Plugin.Config.ShowHonorificTitleInHeader,
|
|
v => Plugin.Config.ShowHonorificTitleInHeader = v
|
|
);
|
|
ImGui.TextDisabled(HellionStrings.Settings_Integrations_Honorific_ToggleHint);
|
|
DrawLinkButton(
|
|
HellionStrings.Settings_Integrations_Honorific_LinkRepo,
|
|
IntegrationLinks.HonorificRepo
|
|
);
|
|
DrawLinkButton(
|
|
HellionStrings.Settings_Integrations_Honorific_LinkAuthor,
|
|
IntegrationLinks.HonorificAuthor
|
|
);
|
|
|
|
DrawComingSoon();
|
|
DrawGotAnIdea();
|
|
}
|
|
|
|
private void DrawHonorificStatus()
|
|
{
|
|
var kind = HonorificStatus.Resolve(_honorific.IsAvailable, _honorific.DetectedApiVersion);
|
|
LastHonorificStatusKey = kind.ToString();
|
|
var colors = _themes.Active.Colors;
|
|
|
|
// Null-safety via the `is { } v` pattern, never `.Value` raw (spec SEC-2):
|
|
// the version is bound only on the arms that have it; the impossible
|
|
// Detected/Incompatible-without-version state falls through to default.
|
|
switch (kind)
|
|
{
|
|
case HonorificStatusKind.Detected when _honorific.DetectedApiVersion is { } v:
|
|
DrawStatusGlyph('●', colors.StatusSuccess);
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(
|
|
string.Format(
|
|
HellionStrings.Settings_Integrations_Honorific_Status_Detected,
|
|
v.Major,
|
|
v.Minor
|
|
)
|
|
);
|
|
break;
|
|
case HonorificStatusKind.Incompatible when _honorific.DetectedApiVersion is { } iv:
|
|
DrawStatusGlyph('⚠', colors.StatusWarning);
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(
|
|
string.Format(
|
|
HellionStrings.Settings_Integrations_Honorific_Status_Incompatible,
|
|
HonorificService.ExpectedApiMajor,
|
|
iv.Major,
|
|
iv.Minor
|
|
)
|
|
);
|
|
break;
|
|
default:
|
|
DrawStatusGlyph('○', colors.TextMuted);
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(
|
|
HellionStrings.Settings_Integrations_Honorific_Status_NotInstalled
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void DrawStatusGlyph(char glyph, uint rgba)
|
|
{
|
|
ImGui.PushStyleColor(ImGuiCol.Text, ColourUtil.RgbaToAbgr(rgba));
|
|
ImGui.TextUnformatted(glyph.ToString());
|
|
ImGui.PopStyleColor();
|
|
}
|
|
|
|
private void DrawComingSoon()
|
|
{
|
|
ImGui.Spacing();
|
|
ImGui.TextUnformatted(HellionStrings.Settings_Integrations_ComingSoon_SectionHeader);
|
|
ImGui.TextDisabled(HellionStrings.Settings_Integrations_ComingSoon_Intro);
|
|
DrawComingSoonItem(
|
|
HellionStrings.Settings_Integrations_ComingSoon_ContextMenu_Title,
|
|
HellionStrings.Settings_Integrations_ComingSoon_ContextMenu_Description
|
|
);
|
|
DrawComingSoonItem(
|
|
HellionStrings.Settings_Integrations_ComingSoon_Notifications_Title,
|
|
HellionStrings.Settings_Integrations_ComingSoon_Notifications_Description
|
|
);
|
|
DrawComingSoonItem(
|
|
HellionStrings.Settings_Integrations_ComingSoon_RPStatus_Title,
|
|
HellionStrings.Settings_Integrations_ComingSoon_RPStatus_Description
|
|
);
|
|
DrawComingSoonItem(
|
|
HellionStrings.Settings_Integrations_ComingSoon_ExtraChat_Title,
|
|
HellionStrings.Settings_Integrations_ComingSoon_ExtraChat_Description
|
|
);
|
|
DrawComingSoonItem(
|
|
HellionStrings.Settings_Integrations_ComingSoon_QuickDM_Title,
|
|
HellionStrings.Settings_Integrations_ComingSoon_QuickDM_Description
|
|
);
|
|
}
|
|
|
|
private void DrawComingSoonItem(string title, string description)
|
|
{
|
|
using (_fonts.FontAwesome.Push())
|
|
{
|
|
ImGui.TextDisabled(FontAwesomeIcon.Hourglass.ToIconString());
|
|
}
|
|
ImGui.SameLine();
|
|
ImGui.TextUnformatted(title);
|
|
ImGui.TextDisabled(description);
|
|
}
|
|
|
|
private void DrawGotAnIdea()
|
|
{
|
|
ImGui.Spacing();
|
|
ImGui.TextUnformatted(HellionStrings.Settings_Integrations_GotAnIdea_SectionHeader);
|
|
ImGui.TextWrapped(HellionStrings.Settings_Integrations_GotAnIdea_Body);
|
|
if (ImGui.Button(HellionStrings.Settings_Integrations_GotAnIdea_LinkLabel))
|
|
{
|
|
_platformUtil.OpenLink(BrandingLinks.HellionForgeDiscordInvite);
|
|
}
|
|
}
|
|
|
|
// URLs are exclusively hardcoded BrandingLinks/IntegrationLinks constants,
|
|
// validated to http/https at module-init. OpenLink centralises the browser
|
|
// open on an off-draw thread (it internally uses the same ShellExecute, so
|
|
// this is a consistency cleanup, not a security change). The standalone Copy
|
|
// button stays as the clipboard path.
|
|
private void DrawLinkButton(string label, string url)
|
|
{
|
|
if (ImGui.Button(label))
|
|
{
|
|
_platformUtil.OpenLink(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");
|
|
}
|
|
}
|