fix(tell): strip stale tell state on tab activation
OnTabActivated clears the runtime tell state the game-side detour leaves on a tab (CurrentChannel tell target + partner label) when a DIFFERENT tab becomes the input surface, so a normal typed line can no longer route as a silent /tell to the old partner. Re-clicking the active tab and tabs carrying their own Tab.TellTarget binding (leg1) are preserved. All four activation paths route through it: Sidebar, TopTabBar, ChannelPopoutPool.TryOpen, and the MainWindow draw-seed. EnsureCurrentChannel becomes a pure derive-helper reached only via OnTabActivated. Adds the TellResetOnActivateStep self-test (step count 29 -> 30).
This commit is contained in:
@@ -247,8 +247,9 @@ internal sealed class Sidebar
|
||||
var rowHovered = ImGui.IsItemHovered();
|
||||
if (ImGui.IsItemClicked())
|
||||
{
|
||||
var previous = activeTab;
|
||||
activeTab = tab;
|
||||
TabLifecycleHelpers.EnsureCurrentChannel(tab);
|
||||
TabLifecycleHelpers.OnTabActivated(tab, previous);
|
||||
}
|
||||
|
||||
dl.DrawHoverSheen(
|
||||
|
||||
@@ -34,8 +34,9 @@ internal sealed class TopTabBar
|
||||
)
|
||||
)
|
||||
{
|
||||
var previous = activeTab;
|
||||
activeTab = tab;
|
||||
TabLifecycleHelpers.EnsureCurrentChannel(tab);
|
||||
TabLifecycleHelpers.OnTabActivated(tab, previous);
|
||||
}
|
||||
|
||||
TabContextMenu.Draw(tab, $"toptab_ctx_{i}", _pool);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using HellionChat.Util;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HellionChat.Ui.Windows;
|
||||
@@ -40,6 +41,12 @@ internal sealed class ChannelPopoutPool
|
||||
|
||||
public bool TryOpen(Tab tab)
|
||||
{
|
||||
// A popped tab gets its own input bar, so strip stale tell state first —
|
||||
// otherwise a popped-out stale-tell tab would be a send surface that
|
||||
// bypasses the click-path activation strip. Previous = the main window's
|
||||
// active tab; popping the active tab itself must not strip (TR-4 guard).
|
||||
TabLifecycleHelpers.OnTabActivated(tab, Plugin.Instance.MainWindow?.ActiveTab);
|
||||
|
||||
var slot = _slots.TryReserve(tab.Identifier);
|
||||
if (slot < 0)
|
||||
{
|
||||
|
||||
@@ -156,7 +156,13 @@ internal sealed class MainWindow : Window
|
||||
// First-frame seed: the active tab defaults to the first persisted
|
||||
// tab so the message list isn't empty on a clean session.
|
||||
if (_activeTab is null && Plugin.Config.Tabs.Count > 0)
|
||||
_activeTab = Plugin.Config.Tabs[0];
|
||||
{
|
||||
var seeded = Plugin.Config.Tabs[0];
|
||||
_activeTab = seeded;
|
||||
// The seeded Tabs[0] is the likeliest legacy stale-tell carrier
|
||||
// (pre-coupling the detour wrote here); strip it like any activation.
|
||||
TabLifecycleHelpers.OnTabActivated(seeded, null);
|
||||
}
|
||||
|
||||
var statusHeight = Components.StatusBar.Height;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user