From 56a9f3f4742eb84d2e8fee401819be82e166908a Mon Sep 17 00:00:00 2001 From: Jon Kazama Date: Wed, 19 Aug 2026 11:42:13 +0200 Subject: [PATCH] fix(privacy): the header gave away what the log was hiding Screenshot mode anonymises sender names in the message list. The channel header I added yesterday sat above that list and showed two things it should not. The home world, on the right. It narrows a player down almost as far as the character name does, and the mode exists so a picture can be shared. Worse, the tab name on the left. AutoTellTabsService builds a tell tab's name as "Player@World", so a tell conversation had the partner's name and world set in tracked caps directly above a log where every message had been anonymised. The one place a reader looks first was the one place still naming them. The name is suppressed only where it actually names someone -- a tab with a tell target set. General or Trade stay readable, because they identify nobody, and a self-named tab is the user's own text. Found by asking what the new surface shows rather than by a test failing. Nothing here was failing. --- .../Ui/StyleEngine/Widgets/ChannelHeader.cs | 20 +++++++++++++++---- .../Widgets/ChannelHeaderDetail.cs | 11 ++++++++-- HellionChat/Ui/Windows/WidgetGalleryWindow.cs | 3 ++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/HellionChat/Ui/StyleEngine/Widgets/ChannelHeader.cs b/HellionChat/Ui/StyleEngine/Widgets/ChannelHeader.cs index c773066..9a82176 100644 --- a/HellionChat/Ui/StyleEngine/Widgets/ChannelHeader.cs +++ b/HellionChat/Ui/StyleEngine/Widgets/ChannelHeader.cs @@ -68,7 +68,13 @@ internal static class ChannelHeader var icon = Components.Sidebar.ResolveTabIcon(tab); var track = TrackRaw * scale; var detailTrack = DetailTrackRaw * scale; - var showName = mode is ChannelHeaderMode.Full; + // Screenshot mode hides the name of a tell tab, because that name IS the + // conversation partner: AutoTellTabsService builds it as "Player@World". + // Drawing it in tracked caps above a log whose messages are anonymised + // would give away in the header exactly what the log is hiding. + var namesAPartner = tab.TellTarget?.IsSet() == true; + var showName = + mode is ChannelHeaderMode.Full && !(Plugin.Config.ScreenshotMode && namesAPartner); // ToUpperInvariant allocates, so only where the name is actually drawn. var name = showName ? tab.Name.ToUpperInvariant() : string.Empty; @@ -92,7 +98,12 @@ internal static class ChannelHeader using ((detail.WhereIsTranslated ? body : meta).Push()) whereRun = DrawListExtensions.MeasureTrackedText(detail.Where, detailTrack); - var rest = ChannelHeaderDetailParts.Separator + detail.Clock; + // No separator with nothing in front of it -- screenshot mode leaves the + // clock standing alone. + var rest = + detail.Where.Length == 0 + ? detail.Clock + : ChannelHeaderDetailParts.Separator + detail.Clock; float restRun; using (meta.Push()) @@ -102,7 +113,7 @@ internal static class ChannelHeader var inset = InsetRaw * scale; var plan = ChannelHeaderLayout.Plan( - mode, + showName ? ChannelHeaderMode.Full : ChannelHeaderMode.DetailOnly, width - inset * 2f, ImGui.GetContentRegionAvail().Y - height - reservedBelow, nameRun, @@ -196,7 +207,8 @@ internal static class ChannelHeader world, DateTimeOffset.Now, Plugin.Config.Use24HourClock, - Resources.HellionStrings.ChannelHeader_NotLoggedIn + Resources.HellionStrings.ChannelHeader_NotLoggedIn, + Plugin.Config.ScreenshotMode ); } diff --git a/HellionChat/Ui/StyleEngine/Widgets/ChannelHeaderDetail.cs b/HellionChat/Ui/StyleEngine/Widgets/ChannelHeaderDetail.cs index e2b6c3c..d9b41d0 100644 --- a/HellionChat/Ui/StyleEngine/Widgets/ChannelHeaderDetail.cs +++ b/HellionChat/Ui/StyleEngine/Widgets/ChannelHeaderDetail.cs @@ -31,14 +31,21 @@ internal static class ChannelHeaderDetail string? world, DateTimeOffset now, bool use24Hour, - string fallback + string fallback, + bool hideWhere ) { - var missing = string.IsNullOrWhiteSpace(world); var clock = use24Hour ? now.ToString("HH:mm", CultureInfo.InvariantCulture) : now.ToString("h:mm tt", CultureInfo.InvariantCulture); + // Screenshot mode. A home world names the player almost as precisely as + // the character name does, and the whole point of that mode is that a + // picture can be shared. The clock stays -- it identifies nobody. + if (hideWhere) + return new ChannelHeaderDetailParts(string.Empty, clock, false); + + var missing = string.IsNullOrWhiteSpace(world); return new ChannelHeaderDetailParts(missing ? fallback : world!, clock, missing); } } diff --git a/HellionChat/Ui/Windows/WidgetGalleryWindow.cs b/HellionChat/Ui/Windows/WidgetGalleryWindow.cs index 7704d31..6dff68f 100644 --- a/HellionChat/Ui/Windows/WidgetGalleryWindow.cs +++ b/HellionChat/Ui/Windows/WidgetGalleryWindow.cs @@ -96,7 +96,8 @@ internal sealed class WidgetGalleryWindow : Window _headerLoggedOut ? null : "Ravana", DateTimeOffset.Now, Plugin.Config.Use24HourClock, - Resources.HellionStrings.ChannelHeader_NotLoggedIn + Resources.HellionStrings.ChannelHeader_NotLoggedIn, + Plugin.Config.ScreenshotMode ); ChannelHeader.Draw(_headerSample, mode, fonts, detail, 0f);