feat(tabs): add IsPinned with separate pool and 5-tab cap

Tester-Request from Jin (2026-05-03): TempTabs should be pinnable so a
key conversation partner survives a relog. Right-click a TempTab and
choose Pin Tab / Unpin Tab / Promote to permanent.

Pool semantics:
- AutoTellTabsLimit (15) still gates the auto-managed unpinned pool.
- Pinned TempTabs live in their own pool, hard-capped at 5.
- The 6th pin attempt fails with a notification; users can unpin first
  or promote to permanent.
- Unpinning into a full unpinned pool drops the oldest unpinned (no
  user friction).

Mechanics:
- Tab.IsPinned (default false); Tab.Clone() carries it.
- Migration v16 -> v17 (additive; existing tabs default to unpinned).
- Three strip-sites synchronised through TabLifecycleHelpers:
  Plugin.cs load-time, Plugin.SaveConfig, Configuration.UpdateFrom.
- AutoTellTabsService:
  * MaxPinnedTempTabs constant.
  * F2.1 _activeTempTabCount counter retired — ActiveTempTabCount is
    now Tabs.Count(predicate). Pin/Unpin/Promote transitions are
    cold-path and don't need lock-free reads.
  * DropOldestTempTab filters on IsInUnpinnedPool so pinned tabs are
    never drop candidates.
  * OnLogout strips only the unpinned pool; pinned popouts and the
    active-tab switch behave correspondingly.
  * TryPin / Unpin / PromoteToPermanent service methods.
- ChatLogWindow tab context menu: Pin / Unpin / Promote with disabled-
  state at-cap tooltip + Promote tooltip explaining the channel-filter
  side effect.
- HellionStrings (EN+DE) for menu labels, tooltips, the limit warning.
- AutoTellTabsLimit slider description now flags the separate pinned
  pool so users aren't surprised by 18 tabs when the limit reads 15.
This commit is contained in:
2026-05-13 09:06:14 +02:00
parent fee2459e73
commit fd5f970a8b
8 changed files with 222 additions and 66 deletions
+19 -1
View File
@@ -383,6 +383,24 @@
<data name="AutoTellTabs_UnGreetedTooltip" xml:space="preserve">
<value>Als begrüßt markieren.</value>
</data>
<data name="PinTab_MenuPin" xml:space="preserve">
<value>Tab anpinnen</value>
</data>
<data name="PinTab_MenuUnpin" xml:space="preserve">
<value>Tab lösen</value>
</data>
<data name="PinTab_MenuPromote" xml:space="preserve">
<value>Dauerhaft behalten</value>
</data>
<data name="PinTab_PromoteTooltip" xml:space="preserve">
<value>„Dauerhaft behalten" macht aus dem Tab einen regulären Tab, der zu allen channel-gefilterten Nachrichten passt — bei Bedarf danach umbenennen.</value>
</data>
<data name="PinTab_LimitReached" xml:space="preserve">
<value>Maximal {0} angepinnte Tell-Tabs erreicht. Erst einen lösen oder dauerhaft behalten.</value>
</data>
<data name="PinTab_PinnedTooltip" xml:space="preserve">
<value>Angepinnt — überlebt Relog.</value>
</data>
<!-- Hellion Chat — Auto-Tell-Tabs (Chat-Einstellungstab) -->
<data name="ChatLog_AutoTellTabs_Section_Title" xml:space="preserve">
@@ -398,7 +416,7 @@
<value>Maximale Anzahl der Auto-Tell-Tabs</value>
</data>
<data name="ChatLog_AutoTellTabs_Limit_Description" xml:space="preserve">
<value>Beim Erreichen werden begrüßte Tabs mit der ältesten Aktivität zuerst geschlossen. Änderungen greifen beim nächsten /tell.</value>
<value>Beim Erreichen werden begrüßte Tabs mit der ältesten Aktivität zuerst geschlossen. Änderungen greifen beim nächsten /tell. Diese Grenze gilt nur für den automatisch verwalteten Pool. Angepinnte Tell-Tabs (Rechtsklick → Tab anpinnen) leben in einem separaten Pool von bis zu 5 Tabs und überleben Relog.</value>
</data>
<data name="ChatLog_AutoTellTabs_Compact_Name" xml:space="preserve">
<value>Kompakte Anzeige</value>