fix(tabs): pin indicator, history preload, drop Promote from temp menu
Smoke-test round 2 feedback from Jin: - Promote-to-permanent label "Dauerhaft behalten" was indistinguishable from Pin in German, leading to misclicks that dropped the tell-target. Removed the menu entry from TempTabs entirely — Promote stays as a service method for future use, but the user-facing path is gone. Anyone who wants a regular tab can still create one via the existing "neuen Tab anlegen" flow. - No visual confirmation that pin took effect. Added a FontAwesome thumbtack overlay top-left of the sidebar icon, accent-coloured, and appended a "Pinned — survives relog" line to the hover tooltip. - Pinned tabs came back empty after a full disable/enable cycle because Tab.Messages is NonSerialized. RehydratePinnedTabs now also runs the same MessageStore-backed PreloadHistory the spawn path uses, so the recent conversation window reappears alongside the rehydrated TellTarget. Diagnose-logging on TryPin/Unpin/Promote/Rehydrate stays in so the next smoke can confirm at a glance which path fired from the Dalamud console.
This commit is contained in:
@@ -64,18 +64,38 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
private static void RehydratePinnedTabs()
|
||||
private void RehydratePinnedTabs()
|
||||
{
|
||||
var pinned = Plugin.Config.Tabs.Count(TabLifecycleHelpers.IsInPinnedPool);
|
||||
Plugin.LogProxy.Info($"[Pin] Rehydrate scan: {pinned} pinned tab(s) found");
|
||||
|
||||
foreach (var tab in Plugin.Config.Tabs)
|
||||
{
|
||||
if (!TabLifecycleHelpers.IsInPinnedPool(tab))
|
||||
continue;
|
||||
|
||||
if (tab.TellTarget is null || !tab.TellTarget.IsSet())
|
||||
{
|
||||
Plugin.LogProxy.Warning(
|
||||
$"[Pin] Pinned tab '{tab.Name}' has no usable TellTarget "
|
||||
+ $"(Name={tab.TellTarget?.Name ?? "<null>"} World={tab.TellTarget?.World ?? 0}). "
|
||||
+ "Chat input on this tab will be empty until the partner sends a tell or you /tell manually."
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
tab.Channel ??= InputChannel.Tell;
|
||||
tab.CurrentChannel.Channel = InputChannel.Tell;
|
||||
tab.CurrentChannel.TellTarget = tab.TellTarget.Clone();
|
||||
|
||||
// MessageList is NonSerialized so pinned tabs come back empty.
|
||||
// Preload the same history window the spawn path uses so the user
|
||||
// sees the recent conversation, not a blank tab.
|
||||
PreloadHistory(tab, tab.TellTarget.Name, tab.TellTarget.World, Guid.Empty);
|
||||
|
||||
Plugin.LogProxy.Info(
|
||||
$"[Pin] Rehydrated '{tab.Name}' -> Tell target {tab.TellTarget.Name}@{tab.TellTarget.World}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,6 +456,9 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
{
|
||||
if (!tab.IsTempTab || tab.IsPinned)
|
||||
{
|
||||
Plugin.LogProxy.Info(
|
||||
$"[Pin] TryPin skipped: IsTempTab={tab.IsTempTab} IsPinned={tab.IsPinned}"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -449,6 +472,9 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
}
|
||||
|
||||
tab.IsPinned = true;
|
||||
Plugin.LogProxy.Info(
|
||||
$"[Pin] Pinned tab '{tab.Name}' target={tab.TellTarget?.Name}@{tab.TellTarget?.World}"
|
||||
);
|
||||
_plugin.SaveConfig();
|
||||
return true;
|
||||
}
|
||||
@@ -469,6 +495,7 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
}
|
||||
|
||||
tab.IsPinned = false;
|
||||
Plugin.LogProxy.Info($"[Pin] Unpinned tab '{tab.Name}'");
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
|
||||
@@ -482,6 +509,9 @@ internal sealed class AutoTellTabsService : IDisposable
|
||||
tab.IsTempTab = false;
|
||||
tab.IsPinned = false;
|
||||
tab.TellTarget = TellTarget.Empty();
|
||||
Plugin.LogProxy.Info(
|
||||
$"[Pin] Promoted tab '{tab.Name}' to permanent (tell-binding dropped)"
|
||||
);
|
||||
_plugin.SaveConfig();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user