Files
HellionChat/HellionChat/SelfTests/SidebarUnreadDotStep.cs
T
JonKazama-Hellion 5dfe8e3b49 fix(unread): restore the tab unread badge and fix the post-F2 unread decision
The v1.8.x sidebar/top-bar rebuild never re-rendered the unread dot, so inactive tabs showed no badge even though the counter was tracked. Draw it again top-right of the tab icon in both Sidebar and TopTabBar, gated on !active && UnreadMode != None && Unread > 0, and zero the active tab's counter every frame (1.5.6 convention) so the dot only ever shows on tabs you are not looking at.

The unread decision moves to MessageManager.ShouldCountUnread and snapshots the active tab + whether it shows the message once before the loop: Unseen suppresses unread on an inactive tab only when the active (real, post-F2) tab also shows that message. Adds SidebarUnreadDotStep (render) and UnreadDecisionStep (decision) self-tests (step count 32 -> 34).
2026-06-13 18:49:27 +02:00

78 lines
2.7 KiB
C#

using Dalamud.Bindings.ImGui;
using Dalamud.Plugin.SelfTest;
using HellionChat.Code;
namespace HellionChat.SelfTests;
// F3: the unread dot the v1.8.x sidebar rebuild dropped. Drives the REAL
// Sidebar.Draw (render precedent: SidebarGreetedGlyphStep) with a probe tab that
// is inactive and carries Unread>0, then reads the render-observability counter
// so a regressed/absent dot fails. Asserts: dot drawn for an inactive Unseen tab;
// NOT drawn for UnreadMode.None. Uses a local one-tab list so the count is
// unambiguous; restores SidebarWidth in finally.
internal sealed class SidebarUnreadDotStep : ISelfTestStep
{
private readonly Plugin _plugin;
public SidebarUnreadDotStep(Plugin plugin) => _plugin = plugin;
public string Name => "Hellion Chat - Sidebar unread dot";
public SelfTestStepResult RunStep()
{
var sidebar = _plugin.MainWindow.GetSidebarForSelfTest();
if (sidebar is null)
{
ImGui.Text("Sidebar null");
return SelfTestStepResult.Fail;
}
var probe = new Tab
{
Name = "Unread Probe@SelfTest",
UnreadMode = UnreadMode.Unseen,
Unread = 3,
SelectedChannels = new Dictionary<ChatType, (ChatSource, ChatSource)>
{
[ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All),
},
};
var list = new List<Tab> { probe };
Tab? active = null; // probe is NOT the active tab
var width = (float)Plugin.Config.SidebarAutoSwitchThresholdPx + 100f; // expanded
var savedWidth = Plugin.Config.SidebarWidth;
try
{
Plugin.Config.SidebarWidth = 220;
// (a) an inactive Unseen tab with Unread>0 draws exactly one dot
// (the one-tab list makes the expected count unambiguous).
sidebar.Draw(width, list, ref active);
if (sidebar.LastRenderedUnreadDotCount != 1)
{
ImGui.Text(
$"Expected exactly 1 unread dot, got {sidebar.LastRenderedUnreadDotCount}"
);
return SelfTestStepResult.Fail;
}
// (b) UnreadMode.None opts the tab out — no dot.
probe.UnreadMode = UnreadMode.None;
sidebar.Draw(width, list, ref active);
if (sidebar.LastRenderedUnreadDotCount != 0)
{
ImGui.Text("Unread dot drawn for an UnreadMode.None tab");
return SelfTestStepResult.Fail;
}
}
finally
{
Plugin.Config.SidebarWidth = savedWidth;
}
return SelfTestStepResult.Pass;
}
public void CleanUp() { }
}