feat(chat): CT-C1 — the unseen-text indicator
Campaign CT slice C1, completing Group C. The authored element was already in the layout and simply never bound: 0x1000048C, a 16x16 button at the transcript's bottom-left. It now lights when a line arrives while the transcript is scrolled up, and clicking it jumps to the newest text. Half of this slice turned out to be done already, and checking rather than assuming is what kept it that way. The plan called for porting retail's rule that IsAtVerticalEnd is sampled BEFORE the new line lands, so a player reading back is not yanked to the bottom. UiScrollable.SetExtents already does exactly that via preserveEnd, and chat gets it by default — so the scroll behaviour was untouched and only the indicator was missing. Rewriting it would have been churn on correct code. The flag clears on reaching the bottom by ANY means, not only by clicking the indicator. Clearing only on the click would leave it lit over text the player had already scrolled down and read, which is worse than not having it. Detection samples the scroll position before the rebuild, at the one moment we know new content arrived (the revision advancing). The first build after bind is deliberately excluded — a fresh window has not "missed" anything. Solution builds clean; full hermetic gate green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
9f6d79b7e0
commit
550621efb2
3 changed files with 103 additions and 0 deletions
|
|
@ -158,6 +158,48 @@ public class ChatWindowControllerTests
|
|||
Assert.NotNull(ctrl);
|
||||
}
|
||||
|
||||
// ── CT-C1: the unseen-text indicator ────────────────────────────────
|
||||
|
||||
private static ChatWindowController BindController()
|
||||
{
|
||||
var (rootInfo, layout, vm) = BuildTestTree();
|
||||
var bus = new CaptureBus();
|
||||
ChatWindowController? ctrl = ChatWindowController.Bind(
|
||||
rootInfo, layout, vm, () => bus, new ChatWindowState(), null, null, NoTex);
|
||||
Assert.NotNull(ctrl);
|
||||
return ctrl!;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReachingTheBottomClearsTheUnseenFlagHoweverYouGotThere()
|
||||
{
|
||||
// Retail clears on arrival at the bottom, not only on clicking the
|
||||
// indicator — otherwise scrolling down with the wheel would leave it
|
||||
// lit over text the player has just read.
|
||||
ChatWindowController ctrl = BindController();
|
||||
ctrl.Transcript.Scroll.SetExtents(contentHeight: 500, viewHeight: 100);
|
||||
ctrl.Transcript.Scroll.SetScrollY(0); // scrolled up
|
||||
Assert.False(ctrl.Transcript.Scroll.AtEnd);
|
||||
|
||||
ctrl.Transcript.Scroll.ScrollToEnd();
|
||||
ctrl.UpdateUnreadIndicator();
|
||||
|
||||
Assert.True(ctrl.Transcript.Scroll.AtEnd);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ClickingTheIndicatorJumpsToTheNewestText()
|
||||
{
|
||||
ChatWindowController ctrl = BindController();
|
||||
ctrl.Transcript.Scroll.SetExtents(contentHeight: 500, viewHeight: 100);
|
||||
ctrl.Transcript.Scroll.SetScrollY(0);
|
||||
Assert.False(ctrl.Transcript.Scroll.AtEnd);
|
||||
|
||||
ctrl.ScrollToNewestAndClearUnread();
|
||||
|
||||
Assert.True(ctrl.Transcript.Scroll.AtEnd);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void StartTell_PrefillsTheEntryAndPutsTheCaretAtTheEnd()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue