From a2db8cb6397cf779806023b4515e88438451593d Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Tue, 5 May 2026 18:52:47 +0200 Subject: [PATCH] feat(tabs): TabIconMapping with default-pool plus override resolver --- HellionChat/Ui/TabIconMapping.cs | 145 +++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 HellionChat/Ui/TabIconMapping.cs diff --git a/HellionChat/Ui/TabIconMapping.cs b/HellionChat/Ui/TabIconMapping.cs new file mode 100644 index 0000000..259dcb4 --- /dev/null +++ b/HellionChat/Ui/TabIconMapping.cs @@ -0,0 +1,145 @@ +using Dalamud.Interface; + +namespace HellionChat.Ui; + +/// +/// Default-Icon-Mapping für Tabs. v1.2.0 Layout-Refresh nutzt das +/// in Top-Tabs (Icon-Prefix) und Sidebar (Icon-only mit Tooltip). +/// User können in Settings → Tabs per Tab.Icon-Override eigene +/// FontAwesome-Glyphen setzen. +/// +/// Aufteilung: +/// - + +/// sind reine String-Logik und stehen aus Test-Sicht ohne +/// Dalamud-Dependency zur Verfügung (siehe Hilfsklasse +/// in derselben Datei, die ohne +/// Dalamud-Imports auskommt). +/// - liefert den FontAwesomeIcon-Enum-Wert +/// für Render-Code (T3/T5/T7) und ist daher Dalamud-abhängig. +/// +internal static class TabIconMapping +{ + /// + /// FontAwesome-Glyph-Name → Icon-Enum-Lookup. Wird für die + /// Production-Resolve-API benötigt. Enthält nur Glyphen aus + /// . + /// + private static readonly Dictionary GlyphLookup = new(StringComparer.OrdinalIgnoreCase) + { + ["comment"] = FontAwesomeIcon.Comment, + ["comments"] = FontAwesomeIcon.Comments, + ["cog"] = FontAwesomeIcon.Cog, + ["users"] = FontAwesomeIcon.Users, + ["user-friends"] = FontAwesomeIcon.UserFriends, + ["link"] = FontAwesomeIcon.Link, + ["envelope"] = FontAwesomeIcon.Envelope, + ["clock"] = FontAwesomeIcon.Clock, + ["hashtag"] = FontAwesomeIcon.Hashtag, + ["star"] = FontAwesomeIcon.Star, + ["heart"] = FontAwesomeIcon.Heart, + ["bell"] = FontAwesomeIcon.Bell, + ["bookmark"] = FontAwesomeIcon.Bookmark, + ["flag"] = FontAwesomeIcon.Flag, + ["fire"] = FontAwesomeIcon.Fire, + }; + + /// + /// Picker-Options-Pool — Pass-through zu . + /// + public static IReadOnlyList PickerOptions => TabIconGlyphResolver.PickerOptions; + + /// + /// Pass-through zu . + /// Liegt hier nochmal als Convenience-Alias, damit Aufrufer nur + /// kennen müssen. + /// + public static string ResolveGlyphName(Tab tab) => TabIconGlyphResolver.ResolveGlyphName(tab); + + /// + /// Production-Surface: liefert das Icon für einen Tab. Wrapper um + /// plus + /// Enum-Lookup. Wird von Render-Code (T3, T5, T7) verwendet. + /// + public static FontAwesomeIcon Resolve(Tab tab) + { + var glyph = TabIconGlyphResolver.ResolveGlyphName(tab); + return GlyphLookup.TryGetValue(glyph, out var icon) + ? icon + : FontAwesomeIcon.Hashtag; + } +} + +/// +/// Reine String-Resolver-Logik ohne Dalamud-Dependency. Bewusst +/// separat, damit Tests (HellionChat.Tests, Microsoft.NET.Sdk ohne +/// Dalamud-Reference) sie aufrufen können, ohne dass die JIT beim +/// Methodenaufruf die Dalamud-Assembly laden muss. +/// +internal static class TabIconGlyphResolver +{ + /// + /// Glyph-Set, das überhaupt als Override akzeptiert wird. Spiegelt + /// die Keys aus . + /// + private static readonly HashSet KnownGlyphs = new(StringComparer.OrdinalIgnoreCase) + { + "comment", "comments", "cog", "users", "user-friends", "link", + "envelope", "clock", "hashtag", "star", "heart", "bell", + "bookmark", "flag", "fire", + }; + + /// + /// Picker-Options-Pool. Wird im Settings-Tab Icon-Combobox angezeigt. + /// Reihenfolge ist die UI-Reihenfolge. + /// + public static readonly IReadOnlyList PickerOptions = + ["comment", "comments", "cog", "users", "user-friends", "link", + "envelope", "clock", "hashtag", "star", "heart", "bell", + "bookmark", "flag", "fire"]; + + /// + /// Tab-Name → Default-Glyph-Name. Tab.Name wird per Lokalisierung + /// gesetzt; wir matchen daher gegen einen Pool aus DE/EN-Synonymen. + /// + private static readonly Dictionary NameDefaults = new(StringComparer.OrdinalIgnoreCase) + { + ["allgemein"] = "comment", + ["general"] = "comment", + ["system"] = "cog", + ["free company"] = "users", + ["fc"] = "users", + ["gruppe"] = "user-friends", + ["group"] = "user-friends", + ["party"] = "user-friends", + ["linkshell"] = "link", + ["ls"] = "link", + ["cwls"] = "link", + ["tells"] = "envelope", + ["tell"] = "envelope", + }; + + /// + /// Test-Surface: Glyph-Name-Resolver ohne Dalamud-Dependency. + /// Reihenfolge: + /// 1. Tab.Icon-Override (falls gesetzt): + /// a) bekannter Glyph → diesen Glyph + /// b) unbekannter Glyph → harter Fallback "hashtag" (User hat + /// bewusst etwas gesetzt, also überstimmt das die Defaults) + /// 2. Auto-Tell-Tab → "clock" + /// 3. Tab-Name-Default (-Lookup) + /// 4. Fallback "hashtag" + /// + public static string ResolveGlyphName(Tab tab) + { + if (!string.IsNullOrEmpty(tab.Icon)) + return KnownGlyphs.Contains(tab.Icon) ? tab.Icon : "hashtag"; + + if (tab.IsTempTab) + return "clock"; + + if (NameDefaults.TryGetValue(tab.Name, out var byName)) + return byName; + + return "hashtag"; + } +}