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