diff --git a/.github/forge-posts/v1.2.0.md b/.github/forge-posts/v1.2.0.md
index 0d3a52a..eded536 100644
--- a/.github/forge-posts/v1.2.0.md
+++ b/.github/forge-posts/v1.2.0.md
@@ -11,7 +11,7 @@ versionsnatur: "Major-UI-Cycle"
- Auto-Tell-Tabs unterscheiden sich jetzt visuell: jeder Tell-Partner bekommt ein eigenes Icon (envelope/star/heart/bell/bookmark/flag/fire) plus eigene Farbe aus 12-Farb-Palette — 84 Icon-Farb-Kombinationen, gleicher Partner ergibt konsistent dieselbe Kombination
- Pulsierender roter Dot oben rechts am Sidebar-Icon wenn ein Tab ungelesene Nachrichten hat. Sanft, 2-Sekunden-Cycle, lässt sich über `Configuration.ReduceMotion` deaktivieren (UI-Toggle kommt in v1.3.0)
- Migration v14 → v15: alte `HellionThemeEnabled` und `HellionThemeWindowOpacity` Konfigurationsfelder entfernt, alle anderen Settings bleiben erhalten
-- Bug-Fix: Settings speichern zerstört nicht mehr den Chat-Verlauf — weder bei den dauerhaften Tabs noch bei den Auto-Tell-Tabs
+- Bug-Fix: Settings speichern zerstört nicht mehr den Chat-Verlauf. Der schwere Refilter-Cycle läuft jetzt nur noch wenn sich Filter-relevante Settings tatsächlich geändert haben (Privacy-Filter, gemerkte Channels, Tab-Channel-Auswahl) — Cosmetic-Änderungen wie Theme oder Tab-Icons lassen den Chat unverändert. Persistente Tabs und Auto-Tell-Tabs überleben beide
- Bug-Fix: Sidebar-Buttons sitzen jetzt vertikal in einer Linie mit der ersten Message-Zeile, Status-Bar-Versionsname wird vollständig angezeigt
Animation-Polish (Lerps, Theme-Crossfade, Header-Quick-Picker) folgt in v1.3.0. v1.2.0 ist bewusst Hard-Switch — sauberes Layout zuerst, Bewegung später.
diff --git a/HellionChat/HellionChat.yaml b/HellionChat/HellionChat.yaml
index 1959b4d..ff4bd30 100755
--- a/HellionChat/HellionChat.yaml
+++ b/HellionChat/HellionChat.yaml
@@ -114,13 +114,15 @@ changelog: |-
Bug fixes from in-game testing:
- - Settings save no longer wipes the in-session chat history of
- persistent tabs (Tab.Clone preserved Identifier but not
- Messages — Identifier-based mapping now restores the live
- MessageList onto cloned tabs).
- - Settings save no longer clears Auto-Tell tabs either
- (ClearAllTabs/FilterAllTabs now skip TempTabs since their
- messages have no DB persistence to refilter from).
+ - Settings save no longer wipes chat history by default. The
+ heavy ClearAllTabs + FilterAllTabsAsync refilter cycle now
+ only runs when a filter-relevant setting actually changed
+ (Privacy filter, persisted channels, per-tab channel
+ selection). Cosmetic changes — theme, tab icons, layout
+ flags — keep the in-session chat intact. Combined with an
+ Identifier-based MessageList restore in Configuration.
+ UpdateFrom and a TempTab skip in ClearAllTabs/FilterAllTabs,
+ persistent tabs and Auto-Tell tabs both survive the save.
- Sidebar buttons now align vertically with the first message
row (top padding mirrors the chat header toolbar height).
- Sidebar child window no longer paints the top padding with
diff --git a/HellionChat/Ui/Settings.cs b/HellionChat/Ui/Settings.cs
index 2a61094..8bafce8 100755
--- a/HellionChat/Ui/Settings.cs
+++ b/HellionChat/Ui/Settings.cs
@@ -210,14 +210,24 @@ public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window
var fontSizeChanged = Math.Abs(Mutable.SymbolsFontSizeV2 - Plugin.Config.SymbolsFontSizeV2) > 0.001
|| Math.Abs(Mutable.FontSizeV2 - Plugin.Config.FontSizeV2) > 0.001;
var italicStateChanged = Mutable.ItalicEnabled != Plugin.Config.ItalicEnabled;
+ // v1.2.0 — Refilter only if a filter-relevant setting actually
+ // changed. The Clear+Refilter cycle reloads messages from the DB,
+ // which silently wipes any in-session message that wasn't
+ // persisted (Privacy-First config blocks most channels from DB).
+ // Cosmetic changes (theme, tab icons, layout flags) trigger no
+ // refilter — chat history stays intact.
+ var filtersChanged = HasFilterRelevantChanges();
Plugin.Config.UpdateFrom(Mutable, true);
// save after 60 frames have passed, which should hopefully not
// commit any changes that cause a crash
Plugin.DeferredSaveFrames = 60;
- Plugin.MessageManager.ClearAllTabs();
- Plugin.MessageManager.FilterAllTabsAsync();
+ if (filtersChanged)
+ {
+ Plugin.MessageManager.ClearAllTabs();
+ Plugin.MessageManager.FilterAllTabsAsync();
+ }
if (fontChanged || fontSizeChanged || italicStateChanged)
Plugin.FontManager.BuildFonts();
@@ -233,4 +243,59 @@ public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window
Initialise();
}
+
+ ///
+ /// v1.2.0 — Detects whether any setting that influences message
+ /// filtering changed between Plugin.Config and the Mutable working
+ /// copy. Used to gate the heavy ClearAllTabs+FilterAllTabsAsync cycle
+ /// in Save: cosmetic changes (theme, tab icons, layout flags) do not
+ /// touch the chat log, only filter-relevant changes do. Without this
+ /// gate, every settings save wipes the chat history of any channel
+ /// the Privacy filter blocks from being persisted to the DB —
+ /// reported by Flo from in-game testing 2026-05-05/06.
+ ///
+ private bool HasFilterRelevantChanges()
+ {
+ // Top-level privacy controls.
+ if (Mutable.PrivacyFilterEnabled != Plugin.Config.PrivacyFilterEnabled) return true;
+ if (Mutable.PrivacyPersistUnknownChannels != Plugin.Config.PrivacyPersistUnknownChannels) return true;
+ if (!Mutable.PrivacyPersistChannels.SetEquals(Plugin.Config.PrivacyPersistChannels)) return true;
+
+ // FilterIncludePreviousSessions changes the GetMostRecentMessages
+ // window in MessageManager.FilterAllTabs and is therefore filter-
+ // relevant even though it lives outside the Privacy block.
+ if (Mutable.FilterIncludePreviousSessions != Plugin.Config.FilterIncludePreviousSessions) return true;
+
+ // Per-tab channel selection. Compare persistent tabs only —
+ // TempTabs are session-only and never refiltered anyway.
+ var origPersistent = Plugin.Config.Tabs.Where(t => !t.IsTempTab).ToList();
+ var newPersistent = Mutable.Tabs.Where(t => !t.IsTempTab).ToList();
+
+ if (origPersistent.Count != newPersistent.Count) return true; // add or delete
+
+ for (var i = 0; i < origPersistent.Count; i++)
+ {
+ var orig = origPersistent[i];
+ var neu = newPersistent[i];
+
+ // Identifier mismatch at the same index means reorder or
+ // a slot got swapped — treat as filter-relevant so the new
+ // channel-selection layout actually applies.
+ if (orig.Identifier != neu.Identifier) return true;
+
+ if (orig.ExtraChatAll != neu.ExtraChatAll) return true;
+ if (!orig.ExtraChatChannels.SetEquals(neu.ExtraChatChannels)) return true;
+
+ // SelectedChannels is a Dictionary
+ // — value-tuple equality already does the right thing per-pair.
+ if (orig.SelectedChannels.Count != neu.SelectedChannels.Count) return true;
+ foreach (var pair in orig.SelectedChannels)
+ {
+ if (!neu.SelectedChannels.TryGetValue(pair.Key, out var nv)) return true;
+ if (!pair.Value.Equals(nv)) return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md
index bb8f605..c00a694 100644
--- a/docs/CHANGELOG.md
+++ b/docs/CHANGELOG.md
@@ -29,8 +29,8 @@ und verlinkt für Details auf die Release-Pages.
- Appearance settings cleaned: legacy theme-engine bindings replaced by Themes tab (introduced in v1.1.0)
### Fixed
-- Settings save no longer wipes the in-session chat history of persistent tabs (`Tab.Clone` preserved `Identifier` but not `Messages` — Identifier-based mapping now restores the live `MessageList` onto cloned tabs)
-- Settings save no longer clears Auto-Tell tab message history (`ClearAllTabs`/`FilterAllTabs` now skip TempTabs since their messages have no DB persistence to refilter from)
+- Settings save no longer wipes chat history by default — the heavy `ClearAllTabs + FilterAllTabsAsync` cycle now only runs when a filter-relevant setting actually changed (Privacy filter, persisted channels, per-tab channel selection). Cosmetic changes keep the in-session chat intact
+- Identifier-based `MessageList` restore in `Configuration.UpdateFrom` plus TempTab skip in `ClearAllTabs`/`FilterAllTabs` ensure persistent tabs and Auto-Tell tabs both survive the save
- Sidebar buttons now align vertically with the first message row (top padding mirrors the chat header toolbar height)
- Sidebar child window no longer paints the top padding area with its frame background
- Status bar version slot (`vX.Y.Z · Hellion`) no longer clips its rightmost character