refactor(integrations): apply review findings (constant, util move, prose cleanup)

This commit is contained in:
2026-05-06 21:08:50 +02:00
parent e58376bf50
commit 2d768e4edb
7 changed files with 52 additions and 41 deletions
+7 -1
View File
@@ -17,6 +17,12 @@ internal sealed class HonorificService : IDisposable
{ {
private const string IpcNamespace = "Honorific"; private const string IpcNamespace = "Honorific";
// Major version of the Honorific IPC contract HellionChat is built against.
// Used both by the runtime compatibility check and by the settings tab when
// it tells the user which major version we expected, so the literal lives
// in exactly one place.
internal const uint ExpectedApiMajor = 3;
// IPC gates we subscribe to. Keep them as fields so Dispose can // IPC gates we subscribe to. Keep them as fields so Dispose can
// unsubscribe the same instances we subscribed in the constructor. // unsubscribe the same instances we subscribed in the constructor.
private readonly ICallGateSubscriber<(uint, uint)> _apiVersion; private readonly ICallGateSubscriber<(uint, uint)> _apiVersion;
@@ -221,7 +227,7 @@ internal sealed class HonorificService : IDisposable
internal static bool IsApiVersionCompatible((uint Major, uint Minor) apiVersion) internal static bool IsApiVersionCompatible((uint Major, uint Minor) apiVersion)
{ {
return apiVersion.Major == 3; return apiVersion.Major == ExpectedApiMajor;
} }
internal static bool ShouldRenderSlot( internal static bool ShouldRenderSlot(
+2 -2
View File
@@ -7,6 +7,6 @@ namespace HellionChat.Integrations;
// brand-links class. // brand-links class.
internal static class IntegrationLinks internal static class IntegrationLinks
{ {
public const string Honorific_Repo = "https://github.com/Caraxi/Honorific"; public const string HonorificRepo = "https://github.com/Caraxi/Honorific";
public const string Honorific_Author = "https://github.com/Caraxi"; public const string HonorificAuthor = "https://github.com/Caraxi";
} }
+2 -2
View File
@@ -750,7 +750,7 @@
<value>Integrationen</value> <value>Integrationen</value>
</data> </data>
<data name="Settings_Card_Integrations_Subtext" xml:space="preserve"> <data name="Settings_Card_Integrations_Subtext" xml:space="preserve">
<value>Andere Dalamud-Plugins, mit denen HellionChat zusammenarbeitet — auto-detected, mit Vorschau auf kommende Integrationen.</value> <value>Andere Dalamud-Plugins, mit denen HellionChat zusammenarbeitet. Auto-detected, mit Vorschau auf kommende Integrationen.</value>
</data> </data>
<data name="Settings_ThemeAndLayout_Theme_Heading" xml:space="preserve"> <data name="Settings_ThemeAndLayout_Theme_Heading" xml:space="preserve">
<value>Theme</value> <value>Theme</value>
@@ -867,7 +867,7 @@
<value>Idee?</value> <value>Idee?</value>
</data> </data>
<data name="Settings_Integrations_GotAnIdea_Body" xml:space="preserve"> <data name="Settings_Integrations_GotAnIdea_Body" xml:space="preserve">
<value>Idee für eine Plugin-Integration, die nicht auf der Liste steht? Komm auf den Hellion-Forge-Discord und schreib mir Community-Input bestimmt die Roadmap.</value> <value>Idee für eine Plugin-Integration, die nicht auf der Liste steht? Komm auf den Hellion-Forge-Discord und schreib mir. Community-Input bestimmt die Roadmap.</value>
</data> </data>
<data name="Settings_Integrations_GotAnIdea_LinkLabel" xml:space="preserve"> <data name="Settings_Integrations_GotAnIdea_LinkLabel" xml:space="preserve">
<value>Hellion Forge öffnen</value> <value>Hellion Forge öffnen</value>
+2 -2
View File
@@ -750,7 +750,7 @@
<value>Integrations</value> <value>Integrations</value>
</data> </data>
<data name="Settings_Card_Integrations_Subtext" xml:space="preserve"> <data name="Settings_Card_Integrations_Subtext" xml:space="preserve">
<value>Other Dalamud plugins HellionChat reacts to — auto-detected, with a "coming soon" preview of upcoming integrations.</value> <value>Other Dalamud plugins HellionChat reacts to. Auto-detected, with a "coming soon" preview of upcoming integrations.</value>
</data> </data>
<data name="Settings_ThemeAndLayout_Theme_Heading" xml:space="preserve"> <data name="Settings_ThemeAndLayout_Theme_Heading" xml:space="preserve">
<value>Theme</value> <value>Theme</value>
@@ -867,7 +867,7 @@
<value>Got an idea?</value> <value>Got an idea?</value>
</data> </data>
<data name="Settings_Integrations_GotAnIdea_Body" xml:space="preserve"> <data name="Settings_Integrations_GotAnIdea_Body" xml:space="preserve">
<value>Got an idea for a plugin integration that's not on this list? Hop on the Hellion Forge Discord and tell me — community input drives the roadmap.</value> <value>Got an idea for a plugin integration that's not on this list? Hop on the Hellion Forge Discord and tell me. Community input drives the roadmap.</value>
</data> </data>
<data name="Settings_Integrations_GotAnIdea_LinkLabel" xml:space="preserve"> <data name="Settings_Integrations_GotAnIdea_LinkLabel" xml:space="preserve">
<value>Open Hellion Forge</value> <value>Open Hellion Forge</value>
+3 -31
View File
@@ -1683,7 +1683,7 @@ public sealed class ChatLogWindow : Window
// Renders only for the active tab in the main ChatLogWindow; pop-out // Renders only for the active tab in the main ChatLogWindow; pop-out
// windows have their own render path and skip this toolbar. // windows have their own render path and skip this toolbar.
// //
// Hellion Chat v1.3.0 also renders the optional Honorific title slot // Hellion Chat v1.3.0 also renders the optional Honorific title slot
// left of the pop-out button, when HonorificService reports an active // left of the pop-out button, when HonorificService reports an active
// custom title and the user has ShowHonorificTitleInHeader enabled. // custom title and the user has ShowHonorificTitleInHeader enabled.
private void DrawChatHeaderToolbar(Tab tab) private void DrawChatHeaderToolbar(Tab tab)
@@ -1708,7 +1708,7 @@ public sealed class ChatLogWindow : Window
// Renders the Honorific custom title to the left of the pop-out button, // Renders the Honorific custom title to the left of the pop-out button,
// wrapped in guillemets to match how the game itself displays titles. // wrapped in guillemets to match how the game itself displays titles.
// We lay out the title first, then DrawPopOutButton uses // We lay out the title first, then DrawPopOutButton uses
// GetContentRegionAvail to anchor itself flush right — that's why the // GetContentRegionAvail to anchor itself flush right, which is why the
// call order in DrawChatHeaderToolbar matters: title first, button second. // call order in DrawChatHeaderToolbar matters: title first, button second.
// //
// The slot stays on the same line as the pop-out button so the chat // The slot stays on the same line as the pop-out button so the chat
@@ -1749,7 +1749,7 @@ public sealed class ChatLogWindow : Window
} }
var rendered = "«" + title!.Title + "»"; var rendered = "«" + title!.Title + "»";
rendered = TruncateToWidth(rendered, maxTitleWidth); rendered = StringUtil.TruncateToFitWidth(rendered, maxTitleWidth);
var titleColor = title.Color is { } c var titleColor = title.Color is { } c
? new Vector4(c.X, c.Y, c.Z, 1f) ? new Vector4(c.X, c.Y, c.Z, 1f)
@@ -1780,34 +1780,6 @@ public sealed class ChatLogWindow : Window
ImGui.SameLine(); ImGui.SameLine();
} }
private static string TruncateToWidth(string text, float maxWidth)
{
if (ImGui.CalcTextSize(text).X <= maxWidth)
{
return text;
}
// Binary-search the longest prefix that fits with an ellipsis.
const string ellipsis = "…";
var lo = 0;
var hi = text.Length;
while (lo < hi)
{
var mid = (lo + hi + 1) / 2;
var candidate = text[..mid] + ellipsis;
if (ImGui.CalcTextSize(candidate).X <= maxWidth)
{
lo = mid;
}
else
{
hi = mid - 1;
}
}
return lo == 0 ? ellipsis : text[..lo] + ellipsis;
}
// Hellion Chat v0.6.1 — One-Time-Hint-Banner introducing the chat header // Hellion Chat v0.6.1 — One-Time-Hint-Banner introducing the chat header
// pop-out toolbar button and the right-click pathway. Reuses the visual // pop-out toolbar button and the right-click pathway. Reuses the visual
// pattern from Popout.cs DrawHintBannerIfNeeded so users see a familiar // pattern from Popout.cs DrawHintBannerIfNeeded so users see a familiar
+3 -3
View File
@@ -76,12 +76,12 @@ internal sealed class Integrations : ISettingsTab
ImGui.Spacing(); ImGui.Spacing();
if (ImGui.Button(HellionStrings.Settings_Integrations_Honorific_LinkRepo)) if (ImGui.Button(HellionStrings.Settings_Integrations_Honorific_LinkRepo))
{ {
Dalamud.Utility.Util.OpenLink(IntegrationLinks.Honorific_Repo); Dalamud.Utility.Util.OpenLink(IntegrationLinks.HonorificRepo);
} }
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.Button(HellionStrings.Settings_Integrations_Honorific_LinkAuthor)) if (ImGui.Button(HellionStrings.Settings_Integrations_Honorific_LinkAuthor))
{ {
Dalamud.Utility.Util.OpenLink(IntegrationLinks.Honorific_Author); Dalamud.Utility.Util.OpenLink(IntegrationLinks.HonorificAuthor);
} }
} }
@@ -104,7 +104,7 @@ internal sealed class Integrations : ISettingsTab
ImGui.SameLine(); ImGui.SameLine();
ImGui.TextUnformatted(string.Format( ImGui.TextUnformatted(string.Format(
HellionStrings.Settings_Integrations_Honorific_Status_Incompatible, HellionStrings.Settings_Integrations_Honorific_Status_Incompatible,
3, incompatibleVersion.Major, incompatibleVersion.Minor)); HonorificService.ExpectedApiMajor, incompatibleVersion.Major, incompatibleVersion.Minor));
} }
else else
{ {
+33
View File
@@ -1,5 +1,6 @@
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using Dalamud.Bindings.ImGui;
namespace HellionChat.Util; namespace HellionChat.Util;
@@ -29,4 +30,36 @@ internal static class StringUtil
// separator to '.' so a German locale doesn't render "1,5GB". // separator to '.' so a German locale doesn't render "1,5GB".
return (Math.Sign(byteCount) * num).ToString("0.#", CultureInfo.InvariantCulture) + suf[place]; return (Math.Sign(byteCount) * num).ToString("0.#", CultureInfo.InvariantCulture) + suf[place];
} }
// Returns the text unchanged when it already fits the width budget,
// otherwise the longest prefix plus a horizontal-ellipsis character that
// still fits. Used by the chat header Honorific title slot and reused by
// the chat-line truncation path in later cycles.
public static string TruncateToFitWidth(string text, float maxWidth)
{
if (ImGui.CalcTextSize(text).X <= maxWidth)
{
return text;
}
// Binary-search the longest prefix that fits with an ellipsis.
const string ellipsis = "…";
var lo = 0;
var hi = text.Length;
while (lo < hi)
{
var mid = (lo + hi + 1) / 2;
var candidate = text[..mid] + ellipsis;
if (ImGui.CalcTextSize(candidate).X <= maxWidth)
{
lo = mid;
}
else
{
hi = mid - 1;
}
}
return lo == 0 ? ellipsis : text[..lo] + ellipsis;
}
} }