From 14e585ef63ff9fd295a79f0ec886e41e31cc4d1f Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 15:54:35 +0200 Subject: [PATCH 01/23] feat(settings-refactor): bump configuration version to 10 with wipe migration --- ChatTwo/Configuration.cs | 2 +- ChatTwo/Plugin.cs | 102 ++++++------------- ChatTwo/Resources/HellionStrings.Designer.cs | 4 + ChatTwo/Resources/HellionStrings.de.resx | 8 ++ ChatTwo/Resources/HellionStrings.resx | 8 ++ 5 files changed, 51 insertions(+), 73 deletions(-) diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index 915f5e1..58102e5 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -34,7 +34,7 @@ public class ConfigKeyBind [Serializable] public class Configuration : IPluginConfiguration { - private const int LatestVersion = 9; + private const int LatestVersion = 10; public int Version { get; set; } = LatestVersion; diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index 63b101e..7b41a39 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.IO; using ChatTwo.Ipc; using ChatTwo.Resources; using ChatTwo.Ui; @@ -107,94 +108,51 @@ public sealed class Plugin : IDalamudPlugin // Drop them on load to guarantee the session-only invariant. Config.Tabs.RemoveAll(t => t.IsTempTab); -#pragma warning disable CS0618 // Type or member is obsolete - // TODO Remove after 01.07.2026 - // Migrate old channel values - if (Config.Version <= 5) + // Hellion Chat v9 → v10 — Settings UX Polish wipes the configuration so + // the new 8-tab layout starts from defaults instead of mapping every + // previous setting to its new position. The chat database lives in a + // separate file and is not touched. A backup of the pre-wipe JSON is + // placed next to the live config as a manual restore safety net. + if (Config.Version < 10) { - foreach (var tab in Config.Tabs) + var configDir = Interface.ConfigDirectory.FullName; + var liveConfigPath = Path.Join(configDir, $"{Interface.InternalName}.json"); + var backupPath = Path.Join(configDir, $"{Interface.InternalName}.json.pre-v10-backup"); + + try { - if (tab.ChatCodes.Count > 0) + if (File.Exists(liveConfigPath)) { - tab.SelectedChannels = tab.ChatCodes.ToDictionary(pair => pair.Key, pair => (pair.Value, pair.Value)); - tab.ChatCodes.Clear(); + File.Copy(liveConfigPath, backupPath, overwrite: true); } - - if (Config.InactivityHideChannels.Count > 0) - { - Config.InactivityHideChannelsV2 = Config.InactivityHideChannels.ToDictionary(pair => pair.Key, pair => (pair.Value, pair.Value)); - Config.InactivityHideChannels.Clear(); - } - - Config.Version = 6; - SaveConfig(); } - } -#pragma warning restore CS0618 // Type or member is obsolete + catch (Exception ex) + { + // Backup failure is non-fatal — the wipe still runs, the user + // just loses the safety net for manual restore. + Plugin.Log.Warning(ex, "[SettingsRefactor] Could not write pre-v10 config backup"); + } - // Hellion Chat v6→v7: seed Privacy-First defaults. - if (Config.Version <= 6) - { - Config.PrivacyFilterEnabled = true; - Config.PrivacyPersistChannels = [..Privacy.PrivacyDefaults.PrivacyFirstWhitelist]; - Config.PrivacyPersistUnknownChannels = false; - // Existing ChatTwo users skip the first-run wizard — the - // migration toast already explains what changed and they - // can reopen the wizard from Settings → Privacy if they - // want to pick a different profile. - Config.FirstRunCompleted = true; - Config.Version = 7; + Config = new Configuration + { + Version = 10, + FirstRunCompleted = true, + }; SaveConfig(); Notification.AddNotification(new Dalamud.Interface.ImGuiNotification.Notification { - Title = HellionStrings.Migration_Notification_Title, - Content = HellionStrings.Migration_Notification_Content, + Title = HellionStrings.SettingsRefactor_Migration_Title, + Content = HellionStrings.SettingsRefactor_Migration_Content, Type = Dalamud.Interface.ImGuiNotification.NotificationType.Info, - InitialDuration = TimeSpan.FromSeconds(15), - }); - } - - // Hellion Chat v7→v8: webinterface removed in 0.2.0. Old config - // entries (WebinterfacePassword, AuthStore, etc.) get dropped on - // the next save because their properties no longer exist on the - // Configuration class. The bump is recorded so the notification - // only fires once. - if (Config.Version <= 7) - { - Config.Version = 8; - SaveConfig(); - - Notification.AddNotification(new Dalamud.Interface.ImGuiNotification.Notification - { - Title = HellionStrings.Migration_Webinterface_Removed_Title, - Content = HellionStrings.Migration_Webinterface_Removed_Content, - Type = Dalamud.Interface.ImGuiNotification.NotificationType.Info, - InitialDuration = TimeSpan.FromSeconds(20), - }); - } - - // Hellion Chat v8→v9: Auto-Tell-Tabs feature seeded with - // property-initializer defaults (enabled, limit 15, history 20, - // section header on). No data migration needed — just bump the - // version and notify the user once so the feature does not - // surprise them. - if (Config.Version <= 8) - { - Config.Version = 9; - SaveConfig(); - - Notification.AddNotification(new Dalamud.Interface.ImGuiNotification.Notification - { - Title = HellionStrings.AutoTellTabs_Migration_Title, - Content = HellionStrings.AutoTellTabs_Migration_Content, - Type = Dalamud.Interface.ImGuiNotification.NotificationType.Info, - InitialDuration = TimeSpan.FromSeconds(20), + InitialDuration = TimeSpan.FromSeconds(25), }); } if (Config.Tabs.Count == 0) + { Config.Tabs.Add(TabsUtil.VanillaGeneral); + } LanguageChanged(Interface.UiLanguage); ImGuiUtil.Initialize(this); diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index b2a7c9e..c416026 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -192,4 +192,8 @@ internal class HellionStrings internal static string Privacy_AutoTellTabs_Preload_Name => Get(nameof(Privacy_AutoTellTabs_Preload_Name)); internal static string Privacy_AutoTellTabs_Preload_Description => Get(nameof(Privacy_AutoTellTabs_Preload_Description)); internal static string Privacy_AutoTellTabs_Preload_Hint => Get(nameof(Privacy_AutoTellTabs_Preload_Hint)); + + // Hellion Chat — Settings UX Polish v10 wipe migration + internal static string SettingsRefactor_Migration_Title => Get(nameof(SettingsRefactor_Migration_Title)); + internal static string SettingsRefactor_Migration_Content => Get(nameof(SettingsRefactor_Migration_Content)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index c4d2826..396bf54 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -438,4 +438,12 @@ Greift nur, wenn Auto-Tell-Tabs im Chat-Tab aktiviert sind. + + + + Settings umstrukturiert + + + Hellion Chat 0.5.0 hat die Settings in thematische Tabs umstrukturiert. Deine Chat-Datenbank und dein Nachrichtenverlauf bleiben unverändert. Settings wurden auf Defaults zurückgesetzt. Falls du das Privacy-Profil neu wählen willst, findest du den Reopen-Button im Datenschutz-Tab. Ein Backup der vorherigen Config liegt unter HellionChat.json.pre-v10-backup neben der aktiven Config-Datei. + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 01cb688..918dd1d 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -438,4 +438,12 @@ Only takes effect when auto tell tabs are enabled in the Chat tab. + + + + Settings reorganised + + + Hellion Chat 0.5.0 reorganised the settings into themed tabs. Your chat database and your message history stay untouched. Settings have been reset to defaults; if you want to pick a privacy profile again, the reopen button is in the Privacy tab. A backup of your previous config is at HellionChat.json.pre-v10-backup next to the live config file. + From c33e519bb9a83adb242e0e4853f55e9853bd6ca2 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:03:51 +0200 Subject: [PATCH 02/23] fix(settings-refactor): use pluginConfigs root for backup path --- ChatTwo/Plugin.cs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index 7b41a39..d28b08d 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -108,29 +108,29 @@ public sealed class Plugin : IDalamudPlugin // Drop them on load to guarantee the session-only invariant. Config.Tabs.RemoveAll(t => t.IsTempTab); - // Hellion Chat v9 → v10 — Settings UX Polish wipes the configuration so - // the new 8-tab layout starts from defaults instead of mapping every - // previous setting to its new position. The chat database lives in a - // separate file and is not touched. A backup of the pre-wipe JSON is - // placed next to the live config as a manual restore safety net. + // Hellion Chat v9 → v10 — wipes the configuration so the new 8-tab + // layout starts from defaults instead of mapping every previous setting + // to its new position. Backup-Failure ist non-fatal, der Wipe läuft + // trotzdem; dem User fehlt dann nur das manuelle Restore-Sicherheitsnetz. if (Config.Version < 10) { - var configDir = Interface.ConfigDirectory.FullName; - var liveConfigPath = Path.Join(configDir, $"{Interface.InternalName}.json"); - var backupPath = Path.Join(configDir, $"{Interface.InternalName}.json.pre-v10-backup"); + var pluginConfigsDir = Interface.ConfigDirectory.Parent?.FullName; + if (pluginConfigsDir is not null) + { + var liveConfigPath = Path.Combine(pluginConfigsDir, $"{Interface.InternalName}.json"); + var backupPath = Path.Combine(pluginConfigsDir, $"{Interface.InternalName}.json.pre-v10-backup"); - try - { - if (File.Exists(liveConfigPath)) + try { - File.Copy(liveConfigPath, backupPath, overwrite: true); + if (File.Exists(liveConfigPath)) + { + File.Copy(liveConfigPath, backupPath, overwrite: true); + } + } + catch (Exception ex) + { + Log.Warning(ex, "HellionChat: pre-v10 config backup failed"); } - } - catch (Exception ex) - { - // Backup failure is non-fatal — the wipe still runs, the user - // just loses the safety net for manual restore. - Plugin.Log.Warning(ex, "[SettingsRefactor] Could not write pre-v10 config backup"); } Config = new Configuration From 9a38f7f0943a6b75e554ca93f60a1e499c082af1 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:22:48 +0200 Subject: [PATCH 03/23] chore: rewrite AI disclosure in a more human, less legal-watertight tone --- AI_DISCLOSURE.md | 77 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/AI_DISCLOSURE.md b/AI_DISCLOSURE.md index 8aa662e..c37ba10 100644 --- a/AI_DISCLOSURE.md +++ b/AI_DISCLOSURE.md @@ -1,18 +1,49 @@ # AI assistance disclosure -Per the [Dalamud Plugin AI Usage Policy](https://github.com/goatcorp/DalamudPluginsD17/), -this fork uses AI assistance at the **Pair** level. Pair means the maintainer -plans the architecture, decides what gets built, reviews each change and -tests against the running game; Claude (Anthropic) helps explain Dalamud -APIs, suggests patterns, drafts code on request, and reviews approaches. -Neither side acts autonomously: nothing ships without the maintainer's -review, and Claude can't run the game. +This fork uses AI assistance per the [Dalamud Plugin AI Usage Policy](https://github.com/goatcorp/DalamudPluginsD17/) +at the **Pair** level. -The level varies by area and over time. Some commits are mostly hand-written -with the AI used as a sounding board, others lean more on Claude for an API -walkthrough or a code draft that the maintainer then reads, edits and -integrates. The maintainer's commitment is to be able to explain why every -piece of Hellion code is the way it is — not "I typed every character." +A note up front: Hellion Chat is currently in a rebuild and adjustment +phase, and there are no plans to submit it to the Dalamud team for review +while it stays standalone. If the plugin stays out of the official repo I +technically wouldn't need to disclose any of this, but I'd rather be +upfront about how it's built. + +Hellion Chat is my entry point into game modding and plugin development. I +have never written a plugin for a game before. I work alone, so I get help +where I need it. That's not something I want to hide. + +## How I actually work + +I plan the architecture, decide what gets built, and own every design +decision. For each change I: + +- Read the code Claude drafts before I integrate it +- Test with my own tooling and in the running game +- Read the Dalamud log output to verify behaviour +- Run security and privacy audits on anything that touches user data + +One of the main reasons I use AI is consistency. I want the Hellion code to +match the style of the upstream Chat 2 codebase and stay readable for +anyone who opens the repo, not just for me. Claude helps me catch when I'm +drifting from upstream conventions or writing something that only makes +sense in my own head. + +The balance is shifting toward more hand-written work as I get more +comfortable with Dalamud and plugin development in general. + +## What AI is used for + +- API explanations (Dalamud, ImGui, .NET specifics I haven't worked with before) +- Code drafts that I read, edit, and integrate +- Pattern suggestions and code review +- Keeping the style aligned with the upstream Chat 2 codebase + +## What AI isn't used for + +- **Visual assets.** Logos, icons, banners, and screenshots are human-drawn + or taken from the running game. +- **German translations.** Written by me as a native speaker. ## What's where @@ -22,20 +53,24 @@ produced with AI assistance. Hellion-specific code lives in `Ui/SettingsTabs/Privacy.cs`, `Ui/FirstRunWizard.cs`, `Ui/HellionStyle.cs`, plus the Migrate3 recovery and plugin layout migration in `MessageStore.cs` and `Plugin.cs`. These were developed with Pair-level assistance as -described above; the share of human vs. AI authorship varies file by file -and is expected to keep shifting toward more hand-written work as the -maintainer's plugin-dev experience grows. +described above. -## What AI is not used for +## If AI-assisted development is a dealbreaker for you -- **Visual assets.** Logos, icons, banners, screenshots are human-drawn or - taken from the running game. -- **German translations.** Written by the maintainer (native speaker). +Fair enough. There are solid alternatives that don't rely on AI in their +development: + +- [Chat 2](https://github.com/Infiziert90/ChatTwo), the original upstream + this fork is based on +- [XIV Instant Messenger](https://github.com/NightmareXIV/XIVInstantMessenger), + a different approach to chat in FFXIV + +Both are good projects. Use what fits you best. ## Tooling -- Claude (Anthropic) via Claude Code CLI as the main pair partner. -- Context7 / Microsoft Learn for current Dalamud and .NET documentation. +- Claude (Anthropic) via Claude Code CLI +- Context7 / Microsoft Learn for current Dalamud and .NET documentation ## Contact From 71ae95d79ca28eadcbda2f52d64f1082422c1974 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:26:22 +0200 Subject: [PATCH 04/23] feat(settings-refactor): wire new 8-tab structure with stubs --- ChatTwo/Resources/HellionStrings.Designer.cs | 7 +++++ ChatTwo/Resources/HellionStrings.de.resx | 17 ++++++++++++ ChatTwo/Resources/HellionStrings.resx | 17 ++++++++++++ ChatTwo/Ui/Settings.cs | 18 +++++-------- ChatTwo/Ui/SettingsTabs/Appearance.cs | 27 ++++++++++++++++++++ ChatTwo/Ui/SettingsTabs/Chat.cs | 26 +++++++++++++++++++ ChatTwo/Ui/SettingsTabs/General.cs | 25 ++++++++++++++++++ ChatTwo/Ui/SettingsTabs/Information.cs | 23 +++++++++++++++++ ChatTwo/Ui/SettingsTabs/Window.cs | 26 +++++++++++++++++++ 9 files changed, 175 insertions(+), 11 deletions(-) create mode 100644 ChatTwo/Ui/SettingsTabs/Appearance.cs create mode 100644 ChatTwo/Ui/SettingsTabs/Chat.cs create mode 100644 ChatTwo/Ui/SettingsTabs/General.cs create mode 100644 ChatTwo/Ui/SettingsTabs/Information.cs create mode 100644 ChatTwo/Ui/SettingsTabs/Window.cs diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index c416026..25e8be5 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -196,4 +196,11 @@ internal class HellionStrings // Hellion Chat — Settings UX Polish v10 wipe migration internal static string SettingsRefactor_Migration_Title => Get(nameof(SettingsRefactor_Migration_Title)); internal static string SettingsRefactor_Migration_Content => Get(nameof(SettingsRefactor_Migration_Content)); + + // Hellion Chat — Settings UX Polish 8-tab structure + internal static string Settings_Tab_General => Get(nameof(Settings_Tab_General)); + internal static string Settings_Tab_Appearance => Get(nameof(Settings_Tab_Appearance)); + internal static string Settings_Tab_Window => Get(nameof(Settings_Tab_Window)); + internal static string Settings_Tab_Chat => Get(nameof(Settings_Tab_Chat)); + internal static string Settings_Tab_Information => Get(nameof(Settings_Tab_Information)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 396bf54..848c0d7 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -446,4 +446,21 @@ Hellion Chat 0.5.0 hat die Settings in thematische Tabs umstrukturiert. Deine Chat-Datenbank und dein Nachrichtenverlauf bleiben unverändert. Settings wurden auf Defaults zurückgesetzt. Falls du das Privacy-Profil neu wählen willst, findest du den Reopen-Button im Datenschutz-Tab. Ein Backup der vorherigen Config liegt unter HellionChat.json.pre-v10-backup neben der aktiven Config-Datei. + + + + Allgemein + + + Aussehen + + + Fenster + + + Chat + + + Über + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 918dd1d..dca59cb 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -446,4 +446,21 @@ Hellion Chat 0.5.0 reorganised the settings into themed tabs. Your chat database and your message history stay untouched. Settings have been reset to defaults; if you want to pick a privacy profile again, the reopen button is in the Privacy tab. A backup of your previous config is at HellionChat.json.pre-v10-backup next to the live config file. + + + + General + + + Appearance + + + Window + + + Chat + + + Information + diff --git a/ChatTwo/Ui/Settings.cs b/ChatTwo/Ui/Settings.cs index b35e545..619e958 100755 --- a/ChatTwo/Ui/Settings.cs +++ b/ChatTwo/Ui/Settings.cs @@ -9,7 +9,7 @@ using Dalamud.Bindings.ImGui; namespace ChatTwo.Ui; -public sealed class SettingsWindow : Window +public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window { private readonly Plugin Plugin; @@ -33,18 +33,14 @@ public sealed class SettingsWindow : Window Tabs = [ - new Display(Mutable), - new ChatLog(Plugin, Mutable), - new Emote(Plugin, Mutable), - new Preview(Mutable), - new Fonts(Mutable), - new ChatColours(Plugin, Mutable), - new Tabs(Plugin, Mutable), + new General(Plugin, Mutable), + new Appearance(Plugin, Mutable), + new SettingsTabs.Window(Plugin, Mutable), + new Chat(Plugin, Mutable), + new SettingsTabs.Tabs(Plugin, Mutable), new SettingsTabs.Privacy(Plugin, Mutable), new Database(Plugin, Mutable), - new Miscellaneous(Mutable), - new Changelog(Mutable), - new About() + new Information(Mutable), ]; RespectCloseHotkey = false; diff --git a/ChatTwo/Ui/SettingsTabs/Appearance.cs b/ChatTwo/Ui/SettingsTabs/Appearance.cs new file mode 100644 index 0000000..5e1beda --- /dev/null +++ b/ChatTwo/Ui/SettingsTabs/Appearance.cs @@ -0,0 +1,27 @@ +using ChatTwo.Resources; +using ChatTwo.Util; +using Dalamud.Interface.Style; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Bindings.ImGui; + +namespace ChatTwo.Ui.SettingsTabs; + +internal sealed class Appearance : ISettingsTab +{ + private readonly Plugin Plugin; + private Configuration Mutable { get; } + + public string Name => HellionStrings.Settings_Tab_Appearance + "###tabs-appearance"; + + internal Appearance(Plugin plugin, Configuration mutable) + { + Plugin = plugin; + Mutable = mutable; + } + + public void Draw(bool changed) + { + // Settings ziehen in Plan-Task 4 ein. + } +} diff --git a/ChatTwo/Ui/SettingsTabs/Chat.cs b/ChatTwo/Ui/SettingsTabs/Chat.cs new file mode 100644 index 0000000..775953b --- /dev/null +++ b/ChatTwo/Ui/SettingsTabs/Chat.cs @@ -0,0 +1,26 @@ +using ChatTwo.Resources; +using ChatTwo.Util; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Bindings.ImGui; + +namespace ChatTwo.Ui.SettingsTabs; + +internal sealed class Chat : ISettingsTab +{ + private readonly Plugin Plugin; + private Configuration Mutable { get; } + + public string Name => HellionStrings.Settings_Tab_Chat + "###tabs-chat"; + + internal Chat(Plugin plugin, Configuration mutable) + { + Plugin = plugin; + Mutable = mutable; + } + + public void Draw(bool changed) + { + // Settings ziehen in Plan-Task 6 ein. + } +} diff --git a/ChatTwo/Ui/SettingsTabs/General.cs b/ChatTwo/Ui/SettingsTabs/General.cs new file mode 100644 index 0000000..e1415bb --- /dev/null +++ b/ChatTwo/Ui/SettingsTabs/General.cs @@ -0,0 +1,25 @@ +using ChatTwo.Resources; +using ChatTwo.Util; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Bindings.ImGui; + +namespace ChatTwo.Ui.SettingsTabs; + +internal sealed class General : ISettingsTab +{ + private readonly Plugin Plugin; + private Configuration Mutable { get; } + + public string Name => HellionStrings.Settings_Tab_General + "###tabs-general"; + + internal General(Plugin plugin, Configuration mutable) + { + Plugin = plugin; + Mutable = mutable; + } + + public void Draw(bool changed) + { + // Settings ziehen in Plan-Task 3 ein. + } +} diff --git a/ChatTwo/Ui/SettingsTabs/Information.cs b/ChatTwo/Ui/SettingsTabs/Information.cs new file mode 100644 index 0000000..9d02960 --- /dev/null +++ b/ChatTwo/Ui/SettingsTabs/Information.cs @@ -0,0 +1,23 @@ +using ChatTwo.Resources; +using ChatTwo.Util; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Bindings.ImGui; + +namespace ChatTwo.Ui.SettingsTabs; + +internal sealed class Information : ISettingsTab +{ + private readonly Configuration Mutable; + + public string Name => HellionStrings.Settings_Tab_Information + "###tabs-information"; + + internal Information(Configuration mutable) + { + Mutable = mutable; + } + + public void Draw(bool changed) + { + // About-Inhalt zieht in Plan-Task 10 ein. + } +} diff --git a/ChatTwo/Ui/SettingsTabs/Window.cs b/ChatTwo/Ui/SettingsTabs/Window.cs new file mode 100644 index 0000000..9876fc0 --- /dev/null +++ b/ChatTwo/Ui/SettingsTabs/Window.cs @@ -0,0 +1,26 @@ +using ChatTwo.Resources; +using ChatTwo.Util; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Utility.Raii; +using Dalamud.Bindings.ImGui; + +namespace ChatTwo.Ui.SettingsTabs; + +internal sealed class Window : ISettingsTab +{ + private readonly Plugin Plugin; + private Configuration Mutable { get; } + + public string Name => HellionStrings.Settings_Tab_Window + "###tabs-window"; + + internal Window(Plugin plugin, Configuration mutable) + { + Plugin = plugin; + Mutable = mutable; + } + + public void Draw(bool changed) + { + // Settings ziehen in Plan-Task 5 ein. + } +} From 444d7f8e2e5ac9f1f16d67de7d503d24214a949a Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:31:42 +0200 Subject: [PATCH 05/23] style(settings-refactor): use property-style for Plugin reference in tab stubs --- ChatTwo/Ui/SettingsTabs/Appearance.cs | 2 +- ChatTwo/Ui/SettingsTabs/Chat.cs | 2 +- ChatTwo/Ui/SettingsTabs/General.cs | 2 +- ChatTwo/Ui/SettingsTabs/Window.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ChatTwo/Ui/SettingsTabs/Appearance.cs b/ChatTwo/Ui/SettingsTabs/Appearance.cs index 5e1beda..99db591 100644 --- a/ChatTwo/Ui/SettingsTabs/Appearance.cs +++ b/ChatTwo/Ui/SettingsTabs/Appearance.cs @@ -9,7 +9,7 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Appearance : ISettingsTab { - private readonly Plugin Plugin; + private Plugin Plugin { get; } private Configuration Mutable { get; } public string Name => HellionStrings.Settings_Tab_Appearance + "###tabs-appearance"; diff --git a/ChatTwo/Ui/SettingsTabs/Chat.cs b/ChatTwo/Ui/SettingsTabs/Chat.cs index 775953b..61f8896 100644 --- a/ChatTwo/Ui/SettingsTabs/Chat.cs +++ b/ChatTwo/Ui/SettingsTabs/Chat.cs @@ -8,7 +8,7 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Chat : ISettingsTab { - private readonly Plugin Plugin; + private Plugin Plugin { get; } private Configuration Mutable { get; } public string Name => HellionStrings.Settings_Tab_Chat + "###tabs-chat"; diff --git a/ChatTwo/Ui/SettingsTabs/General.cs b/ChatTwo/Ui/SettingsTabs/General.cs index e1415bb..ce3cab5 100644 --- a/ChatTwo/Ui/SettingsTabs/General.cs +++ b/ChatTwo/Ui/SettingsTabs/General.cs @@ -7,7 +7,7 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class General : ISettingsTab { - private readonly Plugin Plugin; + private Plugin Plugin { get; } private Configuration Mutable { get; } public string Name => HellionStrings.Settings_Tab_General + "###tabs-general"; diff --git a/ChatTwo/Ui/SettingsTabs/Window.cs b/ChatTwo/Ui/SettingsTabs/Window.cs index 9876fc0..480ccf0 100644 --- a/ChatTwo/Ui/SettingsTabs/Window.cs +++ b/ChatTwo/Ui/SettingsTabs/Window.cs @@ -8,7 +8,7 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Window : ISettingsTab { - private readonly Plugin Plugin; + private Plugin Plugin { get; } private Configuration Mutable { get; } public string Name => HellionStrings.Settings_Tab_Window + "###tabs-window"; From cca45714705a44a46a899552a29c56173730adca Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:36:52 +0200 Subject: [PATCH 06/23] feat(settings-refactor): populate General tab with input, audio, performance, language sections --- ChatTwo/Resources/HellionStrings.Designer.cs | 6 + ChatTwo/Resources/HellionStrings.de.resx | 14 ++ ChatTwo/Resources/HellionStrings.resx | 14 ++ ChatTwo/Ui/SettingsTabs/General.cs | 135 ++++++++++++++++++- 4 files changed, 168 insertions(+), 1 deletion(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index 25e8be5..b1cb5ba 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -203,4 +203,10 @@ internal class HellionStrings internal static string Settings_Tab_Window => Get(nameof(Settings_Tab_Window)); internal static string Settings_Tab_Chat => Get(nameof(Settings_Tab_Chat)); internal static string Settings_Tab_Information => Get(nameof(Settings_Tab_Information)); + + // Hellion Chat — General-Tab section headings + internal static string Settings_General_Input_Heading => Get(nameof(Settings_General_Input_Heading)); + internal static string Settings_General_Audio_Heading => Get(nameof(Settings_General_Audio_Heading)); + internal static string Settings_General_Performance_Heading => Get(nameof(Settings_General_Performance_Heading)); + internal static string Settings_General_Language_Heading => Get(nameof(Settings_General_Language_Heading)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 848c0d7..1559d9a 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -463,4 +463,18 @@ Über + + + + Eingabe + + + Audio & Benachrichtigungen + + + Performance + + + Sprache & Eingabe-Hilfen + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index dca59cb..78f1dbd 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -463,4 +463,18 @@ Information + + + + Input + + + Audio & Notifications + + + Performance + + + Language & Input Helpers + diff --git a/ChatTwo/Ui/SettingsTabs/General.cs b/ChatTwo/Ui/SettingsTabs/General.cs index ce3cab5..60ea048 100644 --- a/ChatTwo/Ui/SettingsTabs/General.cs +++ b/ChatTwo/Ui/SettingsTabs/General.cs @@ -20,6 +20,139 @@ internal sealed class General : ISettingsTab public void Draw(bool changed) { - // Settings ziehen in Plan-Task 3 ein. + DrawInputSection(); + ImGui.Spacing(); + DrawAudioSection(); + ImGui.Spacing(); + DrawPerformanceSection(); + ImGui.Spacing(); + DrawLanguageSection(); + } + + private void DrawInputSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_General_Input_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_KeepInputFocus_Name, ref Mutable.KeepInputFocus); + ImGuiUtil.HelpMarker(Language.Options_KeepInputFocus_Description); + + ImGui.Spacing(); + ImGui.TextUnformatted(Language.Options_ChatTabForwardKeybind_Name); + ImGui.SetNextItemWidth(-1); + ImGuiUtil.KeybindInput("ChatTabForwardKeybind", ref Mutable.ChatTabForward); + + ImGui.TextUnformatted(Language.Options_ChatTabBackwardKeybind_Name); + ImGui.SetNextItemWidth(-1); + ImGuiUtil.KeybindInput("ChatTabBackwardKeybind", ref Mutable.ChatTabBackward); + } + } + + private void DrawAudioSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_General_Audio_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_PlaySounds_Name, ref Mutable.PlaySounds); + ImGuiUtil.HelpMarker(Language.Options_PlaySounds_Description); + + ImGui.Checkbox(Language.Options_ShowNoviceNetwork_Name, ref Mutable.ShowNoviceNetwork); + ImGuiUtil.HelpMarker(Language.Options_ShowNoviceNetwork_Description); + } + } + + private void DrawPerformanceSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_General_Performance_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + if (ImGuiUtil.InputIntVertical(Language.Options_MaxLinesToShow_Name, Language.Options_MaxLinesToShow_Description, ref Mutable.MaxLinesToRender)) + { + Mutable.MaxLinesToRender = Math.Clamp(Mutable.MaxLinesToRender, 1, 10_000); + } + } + } + + private void DrawLanguageSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_General_Language_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_Language_Name, Mutable.LanguageOverride.Name())) + { + if (combo.Success) + { + foreach (var language in Enum.GetValues()) + { + if (ImGui.Selectable(language.Name())) + { + Mutable.LanguageOverride = language; + } + } + } + } + ImGuiUtil.HelpMarker(string.Format(Language.Options_Language_Description, Plugin.PluginName)); + ImGui.Spacing(); + + using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_CommandHelpSide_Name, Mutable.CommandHelpSide.Name())) + { + if (combo.Success) + { + foreach (var side in Enum.GetValues()) + { + if (ImGui.Selectable(side.Name(), Mutable.CommandHelpSide == side)) + { + Mutable.CommandHelpSide = side; + } + } + } + } + ImGuiUtil.HelpMarker(string.Format(Language.Options_CommandHelpSide_Description, Plugin.PluginName)); + ImGui.Spacing(); + + using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_KeybindMode_Name, Mutable.KeybindMode.Name())) + { + if (combo.Success) + { + foreach (var mode in Enum.GetValues()) + { + if (ImGui.Selectable(mode.Name(), Mutable.KeybindMode == mode)) + { + Mutable.KeybindMode = mode; + } + + if (ImGui.IsItemHovered()) + { + ImGuiUtil.Tooltip(mode.Tooltip() ?? ""); + } + } + } + } + ImGuiUtil.HelpMarker(string.Format(Language.Options_KeybindMode_Description, Plugin.PluginName)); + ImGui.Spacing(); + + ImGui.Checkbox(Language.Options_SortAutoTranslate_Name, ref Mutable.SortAutoTranslate); + ImGuiUtil.HelpMarker(Language.Options_SortAutoTranslate_Description); + } } } From c97ce7543b605b20eb996b576bd8cdb6ee8fda63 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:44:50 +0200 Subject: [PATCH 07/23] feat(settings-refactor): populate Appearance tab with theme, fonts, colours, timestamps --- ChatTwo/Resources/HellionStrings.Designer.cs | 6 + ChatTwo/Resources/HellionStrings.de.resx | 14 ++ ChatTwo/Resources/HellionStrings.resx | 14 ++ ChatTwo/Ui/SettingsTabs/Appearance.cs | 249 ++++++++++++++++++- 4 files changed, 282 insertions(+), 1 deletion(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index b1cb5ba..3f6d3a7 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -209,4 +209,10 @@ internal class HellionStrings internal static string Settings_General_Audio_Heading => Get(nameof(Settings_General_Audio_Heading)); internal static string Settings_General_Performance_Heading => Get(nameof(Settings_General_Performance_Heading)); internal static string Settings_General_Language_Heading => Get(nameof(Settings_General_Language_Heading)); + + // Hellion Chat — Appearance-Tab section headings + internal static string Settings_Appearance_Theme_Heading => Get(nameof(Settings_Appearance_Theme_Heading)); + internal static string Settings_Appearance_Fonts_Heading => Get(nameof(Settings_Appearance_Fonts_Heading)); + internal static string Settings_Appearance_Colours_Heading => Get(nameof(Settings_Appearance_Colours_Heading)); + internal static string Settings_Appearance_Timestamps_Heading => Get(nameof(Settings_Appearance_Timestamps_Heading)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 1559d9a..0598225 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -477,4 +477,18 @@ Sprache & Eingabe-Hilfen + + + + Theme + + + Schriftarten + + + Chat-Farben + + + Zeitstempel + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 78f1dbd..f58438d 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -477,4 +477,18 @@ Language & Input Helpers + + + + Theme + + + Fonts + + + Chat Colours + + + Timestamps + diff --git a/ChatTwo/Ui/SettingsTabs/Appearance.cs b/ChatTwo/Ui/SettingsTabs/Appearance.cs index 99db591..def4cd4 100644 --- a/ChatTwo/Ui/SettingsTabs/Appearance.cs +++ b/ChatTwo/Ui/SettingsTabs/Appearance.cs @@ -1,5 +1,9 @@ +using ChatTwo.Code; using ChatTwo.Resources; using ChatTwo.Util; +using Dalamud; +using Dalamud.Interface; +using Dalamud.Interface.FontIdentifier; using Dalamud.Interface.Style; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; @@ -22,6 +26,249 @@ internal sealed class Appearance : ISettingsTab public void Draw(bool changed) { - // Settings ziehen in Plan-Task 4 ein. + DrawThemeSection(); + ImGui.Spacing(); + DrawFontsSection(); + ImGui.Spacing(); + DrawColoursSection(); + ImGui.Spacing(); + DrawTimestampsSection(); + } + + private void DrawThemeSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Appearance_Theme_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(HellionStrings.Theme_Enabled_Name, ref Mutable.HellionThemeEnabled); + ImGuiUtil.HelpMarker(HellionStrings.Theme_Enabled_Description); + + // Clamp 0.5–1.0 stays consistent with Privacy.cs which already + // shipped this slider; lower values would let chat windows + // disappear behind game UI. + using (ImRaii.Disabled(!Mutable.HellionThemeEnabled)) + { + ImGui.SetNextItemWidth(200f * ImGuiHelpers.GlobalScale); + var opacity = Mutable.HellionThemeWindowOpacity; + if (ImGui.SliderFloat($"{HellionStrings.Theme_WindowOpacity_Label}##theme-opacity", ref opacity, 0.5f, 1.0f, "%.2f")) + { + Mutable.HellionThemeWindowOpacity = Math.Clamp(opacity, 0.5f, 1.0f); + } + ImGuiUtil.HelpMarker(HellionStrings.Theme_WindowOpacity_Help); + } + + ImGui.Spacing(); + + ImGui.Checkbox(Language.Options_OverrideStyle_Name, ref Mutable.OverrideStyle); + ImGuiUtil.HelpMarker(Language.Options_OverrideStyle_Name_Desc); + + if (Mutable.OverrideStyle) + { + DrawStyleCombo(); + } + + ImGuiUtil.DragFloatVertical(Language.Options_WindowOpacity_Name, ref Mutable.WindowAlpha, .25f, 0f, 100f, $"{Mutable.WindowAlpha:N2}%%", ImGuiSliderFlags.AlwaysClamp); + } + } + + private void DrawStyleCombo() + { + var styles = StyleModel.GetConfiguredStyles(); + if (styles == null) + { + ImGui.TextUnformatted(Language.Options_OverrideStyle_NotAvailable); + return; + } + + var currentStyle = Mutable.ChosenStyle ?? Language.Options_OverrideStyle_NotSelected; + using var combo = ImRaii.Combo(Language.Options_OverrideStyleDropdown_Name, currentStyle); + if (!combo) + { + return; + } + + foreach (var style in styles) + { + if (ImGui.Selectable(style.Name, Mutable.ChosenStyle == style.Name)) + { + Mutable.ChosenStyle = style.Name; + } + } + } + + private void DrawFontsSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Appearance_Fonts_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(HellionStrings.Theme_UseHellionFont_Name, ref Mutable.UseHellionFont); + ImGuiUtil.HelpMarker(HellionStrings.Theme_UseHellionFont_Description); + ImGui.Spacing(); + + // Hellion-Font und der Custom-Font-Stack schließen sich aus: + // wenn Exo 2 erzwungen wird, sind die ChatTwo-Font-Picker + // ohne Wirkung, also UI-seitig ausgrauen statt versteckt + // weiterzuwerken. + using var fontDisabled = ImRaii.Disabled(Mutable.UseHellionFont); + + ImGui.Checkbox(Language.Options_FontsEnabled, ref Mutable.FontsEnabled); + ImGui.Spacing(); + + var unused = false; + if (!Mutable.FontsEnabled) + { + ImGuiUtil.FontSizeCombo(Language.Options_FontSize_Name, ref Mutable.FontSizeV2); + } + else + { + var globalChooser = ImGuiUtil.FontChooser(Language.Options_Font_Name, Mutable.GlobalFontV2, false, ref unused); + globalChooser?.ResultTask.ContinueWith(r => + { + if (r.IsCompletedSuccessfully) + Mutable.GlobalFontV2 = r.Result; + }); + ImGui.SameLine(); + if (ImGui.Button("Reset##global")) + { + Mutable.GlobalFontV2 = new SingleFontSpec { FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkRegular), SizePt = 12.75f }; + } + + ImGuiUtil.HelpMarker(string.Format(Language.Options_Font_Description, Plugin.PluginName)); + ImGuiUtil.WarningText(Language.Options_Font_Warning); + ImGui.Spacing(); + + // LocaleNames being null means it is likely a game font which all support JP symbols. + var japaneseChooser = ImGuiUtil.FontChooser(Language.Options_JapaneseFont_Name, Mutable.JapaneseFontV2, false, ref unused, id => !id.LocaleNames?.ContainsKey("ja-jp") ?? false, "いろはにほへと ちりぬるを"); + japaneseChooser?.ResultTask.ContinueWith(r => + { + if (r.IsCompletedSuccessfully) + Mutable.JapaneseFontV2 = r.Result; + }); + ImGui.SameLine(); + if (ImGui.Button("Reset##japanese")) + { + Mutable.JapaneseFontV2 = new SingleFontSpec { FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkMedium), SizePt = 12.75f }; + } + + ImGuiUtil.HelpMarker(string.Format(Language.Options_JapaneseFont_Description, Plugin.PluginName)); + ImGui.Spacing(); + + var italicChooser = ImGuiUtil.FontChooser(Language.Options_ItalicFont_Name, Mutable.ItalicFontV2, true, ref Mutable.ItalicEnabled); + italicChooser?.ResultTask.ContinueWith(r => + { + if (r.IsCompletedSuccessfully) + Mutable.ItalicFontV2 = r.Result; + }); + ImGui.SameLine(); + if (ImGui.Button("Reset##italic")) + { + Mutable.ItalicEnabled = false; + Mutable.ItalicFontV2 = new SingleFontSpec { FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkRegular), SizePt = 12.75f }; + } + + ImGuiUtil.HelpMarker(string.Format(Language.Options_Italic_Description, Plugin.PluginName)); + ImGui.Spacing(); + + if (ImGui.CollapsingHeader(Language.Options_ExtraGlyphs_Name)) + { + ImGuiUtil.HelpMarker(string.Format(Language.Options_ExtraGlyphs_Description, Plugin.PluginName)); + + var range = (int)Mutable.ExtraGlyphRanges; + foreach (var extra in Enum.GetValues()) + { + ImGui.CheckboxFlags(extra.Name(), ref range, (int)extra); + } + + Mutable.ExtraGlyphRanges = (ExtraGlyphRanges)range; + } + + ImGui.Spacing(); + } + + ImGuiUtil.FontSizeCombo(Language.Options_SymbolsFontSize_Name, ref Mutable.SymbolsFontSizeV2); + ImGuiUtil.HelpMarker(Language.Options_SymbolsFontSize_Description); + + ImGui.Spacing(); + } + } + + private void DrawColoursSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Appearance_Colours_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + foreach (var (_, types) in ChatTypeExt.SortOrder) + { + foreach (var type in types) + { + if (ImGuiUtil.IconButton(FontAwesomeIcon.UndoAlt, $"{type}", Language.Options_ChatColours_Reset)) + { + Mutable.ChatColours.Remove(type); + } + + ImGui.SameLine(); + + if (ImGuiUtil.IconButton(FontAwesomeIcon.LongArrowAltDown, $"{type}", Language.Options_ChatColours_Import)) + { + var gameColour = Plugin.Functions.Chat.GetChannelColor(type); + Mutable.ChatColours[type] = gameColour ?? type.DefaultColor() ?? 0; + } + + ImGui.SameLine(); + + var vec = Mutable.ChatColours.TryGetValue(type, out var colour) + ? ColourUtil.RgbaToVector3(colour) + : ColourUtil.RgbaToVector3(type.DefaultColor() ?? 0); + if (ImGui.ColorEdit3(type.Name(), ref vec, ImGuiColorEditFlags.NoInputs)) + { + Mutable.ChatColours[type] = ColourUtil.Vector3ToRgba(vec); + } + } + } + + ImGui.Spacing(); + } + } + + private void DrawTimestampsSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Appearance_Timestamps_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_PrettierTimestamps_Name, ref Mutable.PrettierTimestamps); + ImGuiUtil.HelpMarker(Language.Options_PrettierTimestamps_Description); + + if (Mutable.PrettierTimestamps) + { + ImGui.Checkbox(Language.Options_MoreCompactPretty_Name, ref Mutable.MoreCompactPretty); + ImGuiUtil.HelpMarker(Language.Options_MoreCompactPretty_Description); + + ImGui.Checkbox(Language.Options_HideSameTimestamps_Name, ref Mutable.HideSameTimestamps); + ImGuiUtil.HelpMarker(Language.Options_HideSameTimestamps_Description); + } + + ImGui.Checkbox(Language.Options_Use24HourClock_Name, ref Mutable.Use24HourClock); + ImGuiUtil.HelpMarker(Language.Options_Use24HourClock_Description); + } } } From e086afe2a816a56c29b1182743251db7a53cf9d4 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 16:54:23 +0200 Subject: [PATCH 08/23] feat(settings-refactor): populate Window tab with hide, inactivity, frame, tooltips --- ChatTwo/Resources/HellionStrings.Designer.cs | 6 + ChatTwo/Resources/HellionStrings.de.resx | 14 ++ ChatTwo/Resources/HellionStrings.resx | 14 ++ ChatTwo/Ui/SettingsTabs/Window.cs | 141 ++++++++++++++++++- 4 files changed, 173 insertions(+), 2 deletions(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index 3f6d3a7..f50e2e8 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -215,4 +215,10 @@ internal class HellionStrings internal static string Settings_Appearance_Fonts_Heading => Get(nameof(Settings_Appearance_Fonts_Heading)); internal static string Settings_Appearance_Colours_Heading => Get(nameof(Settings_Appearance_Colours_Heading)); internal static string Settings_Appearance_Timestamps_Heading => Get(nameof(Settings_Appearance_Timestamps_Heading)); + + // Hellion Chat — Window-Tab section headings + internal static string Settings_Window_Hide_Heading => Get(nameof(Settings_Window_Hide_Heading)); + internal static string Settings_Window_InactivityHide_Heading => Get(nameof(Settings_Window_InactivityHide_Heading)); + internal static string Settings_Window_Frame_Heading => Get(nameof(Settings_Window_Frame_Heading)); + internal static string Settings_Window_Tooltips_Heading => Get(nameof(Settings_Window_Tooltips_Heading)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 0598225..2bf579c 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -491,4 +491,18 @@ Zeitstempel + + + + Verstecken + + + Inaktivitäts-Verstecken + + + Fenster-Rahmen + + + Tooltips + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index f58438d..f14e346 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -491,4 +491,18 @@ Timestamps + + + + Hide + + + Inactivity Hide + + + Window Frame + + + Tooltips + diff --git a/ChatTwo/Ui/SettingsTabs/Window.cs b/ChatTwo/Ui/SettingsTabs/Window.cs index 480ccf0..109bc78 100644 --- a/ChatTwo/Ui/SettingsTabs/Window.cs +++ b/ChatTwo/Ui/SettingsTabs/Window.cs @@ -1,6 +1,5 @@ using ChatTwo.Resources; using ChatTwo.Util; -using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Bindings.ImGui; @@ -21,6 +20,144 @@ internal sealed class Window : ISettingsTab public void Draw(bool changed) { - // Settings ziehen in Plan-Task 5 ein. + DrawHideSection(); + ImGui.Spacing(); + DrawInactivityHideSection(); + ImGui.Spacing(); + DrawFrameSection(); + ImGui.Spacing(); + DrawTooltipsSection(); + } + + private void DrawHideSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Window_Hide_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_HideChat_Name, ref Mutable.HideChat); + ImGuiUtil.HelpMarker(Language.Options_HideChat_Description); + + ImGui.Checkbox(Language.Options_HideDuringCutscenes_Name, ref Mutable.HideDuringCutscenes); + ImGuiUtil.HelpMarker(string.Format(Language.Options_HideDuringCutscenes_Description, Plugin.PluginName)); + + ImGui.Checkbox(Language.Options_HideWhenNotLoggedIn_Name, ref Mutable.HideWhenNotLoggedIn); + ImGuiUtil.HelpMarker(string.Format(Language.Options_HideWhenNotLoggedIn_Description, Plugin.PluginName)); + + ImGui.Checkbox(Language.Options_HideWhenUiHidden_Name, ref Mutable.HideWhenUiHidden); + ImGuiUtil.HelpMarker(string.Format(Language.Options_HideWhenUiHidden_Description, Plugin.PluginName)); + + ImGui.Checkbox(Language.Options_HideInLoadingScreens_Name, ref Mutable.HideInLoadingScreens); + ImGuiUtil.HelpMarker(string.Format(Language.Options_HideInLoadingScreens_Description, Plugin.PluginName)); + + ImGui.Checkbox(Language.Options_HideInBattle_Name, ref Mutable.HideInBattle); + ImGuiUtil.HelpMarker(Language.Options_HideInBattle_Description); + } + } + + private void DrawInactivityHideSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Window_InactivityHide_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_HideWhenInactive_Name, ref Mutable.HideWhenInactive); + ImGuiUtil.HelpMarker(Language.Options_HideWhenInactive_Description); + + if (!Mutable.HideWhenInactive) + { + return; + } + + ImGuiUtil.InputIntVertical(Language.Options_InactivityHideTimeout_Name, Language.Options_InactivityHideTimeout_Description, ref Mutable.InactivityHideTimeout, 1, 10); + // Untergrenze von 2 Sekunden gegen Selbst-Soft-Lock. + Mutable.InactivityHideTimeout = Math.Max(2, Mutable.InactivityHideTimeout); + + using (ImRaii.Disabled(Mutable.HideInBattle)) + { + ImGui.Checkbox(Language.Options_InactivityHideActiveDuringBattle_Name, ref Mutable.InactivityHideActiveDuringBattle); + ImGuiUtil.HelpMarker(Language.Options_InactivityHideActiveDuringBattle_Description); + } + + using var channelTree = ImRaii.TreeNode(Language.Options_InactivityHideChannels_Name); + if (!channelTree.Success) + { + return; + } + + if (ImGuiUtil.CtrlShiftButton(Language.Options_InactivityHideChannels_All_Label, Language.Options_InactivityHideChannels_Button_Tooltip)) + { + Mutable.InactivityHideChannelsV2 = TabsUtil.AllChannels(); + Mutable.InactivityHideExtraChatAll = true; + Mutable.InactivityHideExtraChatChannels = []; + } + + ImGui.SameLine(); + if (ImGuiUtil.CtrlShiftButton(Language.Options_InactivityHideChannels_None_Label, Language.Options_InactivityHideChannels_Button_Tooltip)) + { + Mutable.InactivityHideChannelsV2 = []; + Mutable.InactivityHideExtraChatAll = false; + Mutable.InactivityHideExtraChatChannels = []; + } + + ImGui.Spacing(); + + ImGuiUtil.ChannelSelector(Language.Options_Tabs_Channels, Mutable.InactivityHideChannelsV2); + ImGuiUtil.ExtraChatSelector(Language.Options_Tabs_ExtraChatChannels, ref Mutable.InactivityHideExtraChatAll, Mutable.InactivityHideExtraChatChannels); + } + } + + private void DrawFrameSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Window_Frame_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_CanMove_Name, ref Mutable.CanMove); + + ImGui.Checkbox(Language.Options_CanResize_Name, ref Mutable.CanResize); + + ImGui.Checkbox(Language.Options_ShowTitleBar_Name, ref Mutable.ShowTitleBar); + + ImGui.Checkbox(Language.Options_ShowPopOutTitleBar_Name, ref Mutable.ShowPopOutTitleBar); + + ImGui.Checkbox(Language.Options_ShowHideButton_Name, ref Mutable.ShowHideButton); + ImGuiUtil.HelpMarker(Language.Options_ShowHideButton_Description); + + ImGui.Checkbox(Language.Options_SidebarTabView_Name, ref Mutable.SidebarTabView); + ImGuiUtil.HelpMarker(string.Format(Language.Options_SidebarTabView_Description, Plugin.PluginName)); + } + } + + private void DrawTooltipsSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Window_Tooltips_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_NativeItemTooltips_Name, ref Mutable.NativeItemTooltips); + ImGuiUtil.HelpMarker(string.Format(Language.Options_NativeItemTooltips_Description, Plugin.PluginName)); + + if (Mutable.NativeItemTooltips) + { + ImGuiUtil.DragFloatVertical(Language.Options_TooltipOffset_Name, Language.Options_TooltipOffset_Desc, ref Mutable.TooltipOffset, 1, 0f, 400f, $"{Mutable.TooltipOffset:N0}px", ImGuiSliderFlags.AlwaysClamp); + } + } } } From 52e163a47242bc59ae947ac740dd6e0b89e82632 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:00:25 +0200 Subject: [PATCH 09/23] fix(settings-refactor): show HelpMarker tooltip even when item is disabled --- ChatTwo/Util/ImGuiUtil.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ChatTwo/Util/ImGuiUtil.cs b/ChatTwo/Util/ImGuiUtil.cs index 366dcce..7379001 100755 --- a/ChatTwo/Util/ImGuiUtil.cs +++ b/ChatTwo/Util/ImGuiUtil.cs @@ -225,7 +225,11 @@ internal static class ImGuiUtil using (ImRaii.PushColor(ImGuiCol.Text, ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled])) ImGui.TextUnformatted("(?)"); - if (!ImGui.IsItemHovered()) + // AllowWhenDisabled — ohne das Flag liefert IsItemHovered bei + // ausgegrauten Settings false, der User könnte nicht mehr lesen + // warum eine Option nicht aktiv ist. Genau dann braucht er den + // Hover-Tooltip aber am dringendsten. + if (!ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) return; using var tooltip = ImRaii.Tooltip(); From 0e2a14197cf6958ad90c562d5d438130491b6e8b Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:04:25 +0200 Subject: [PATCH 10/23] feat(settings-refactor): populate Chat tab with auto-tell-tabs, behaviour, preview, emotes --- ChatTwo/Resources/HellionStrings.Designer.cs | 6 + ChatTwo/Resources/HellionStrings.de.resx | 14 ++ ChatTwo/Resources/HellionStrings.resx | 14 ++ ChatTwo/Ui/SettingsTabs/Chat.cs | 206 ++++++++++++++++++- 4 files changed, 239 insertions(+), 1 deletion(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index f50e2e8..3dac2eb 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -221,4 +221,10 @@ internal class HellionStrings internal static string Settings_Window_InactivityHide_Heading => Get(nameof(Settings_Window_InactivityHide_Heading)); internal static string Settings_Window_Frame_Heading => Get(nameof(Settings_Window_Frame_Heading)); internal static string Settings_Window_Tooltips_Heading => Get(nameof(Settings_Window_Tooltips_Heading)); + + // Hellion Chat — Chat-Tab section headings + internal static string Settings_Chat_AutoTellTabs_Heading => Get(nameof(Settings_Chat_AutoTellTabs_Heading)); + internal static string Settings_Chat_Behaviour_Heading => Get(nameof(Settings_Chat_Behaviour_Heading)); + internal static string Settings_Chat_Preview_Heading => Get(nameof(Settings_Chat_Preview_Heading)); + internal static string Settings_Chat_Emotes_Heading => Get(nameof(Settings_Chat_Emotes_Heading)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 2bf579c..48b161e 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -505,4 +505,18 @@ Tooltips + + + + Auto-Tell-Tabs + + + Nachrichten-Verhalten + + + Vorschau + + + Emotes + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index f14e346..9cb8ce4 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -505,4 +505,18 @@ Tooltips + + + + Auto-Tell-Tabs + + + Message Behaviour + + + Preview + + + Emotes + diff --git a/ChatTwo/Ui/SettingsTabs/Chat.cs b/ChatTwo/Ui/SettingsTabs/Chat.cs index 61f8896..49baafc 100644 --- a/ChatTwo/Ui/SettingsTabs/Chat.cs +++ b/ChatTwo/Ui/SettingsTabs/Chat.cs @@ -1,5 +1,8 @@ +using System.Numerics; using ChatTwo.Resources; using ChatTwo.Util; +using Dalamud.Interface; +using Dalamud.Interface.Colors; using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Bindings.ImGui; @@ -13,14 +16,215 @@ internal sealed class Chat : ISettingsTab public string Name => HellionStrings.Settings_Tab_Chat + "###tabs-chat"; + private SearchSelector.SelectorPopupOptions WordPopupOptions; + internal Chat(Plugin plugin, Configuration mutable) { Plugin = plugin; Mutable = mutable; + + WordPopupOptions = RefillSheet(); + } + + private SearchSelector.SelectorPopupOptions RefillSheet() + { + return new SearchSelector.SelectorPopupOptions + { + FilteredSheet = EmoteCache.SortedCodeArray.Where(w => !Mutable.BlockedEmotes.Contains(w)).ToArray() + }; } public void Draw(bool changed) { - // Settings ziehen in Plan-Task 6 ein. + DrawAutoTellTabsSection(); + ImGui.Spacing(); + DrawBehaviourSection(); + ImGui.Spacing(); + DrawPreviewSection(); + ImGui.Spacing(); + DrawEmotesSection(); + } + + private void DrawAutoTellTabsSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Chat_AutoTellTabs_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(HellionStrings.ChatLog_AutoTellTabs_Enable_Name, ref Mutable.EnableAutoTellTabs); + ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_Enable_Description); + + ImGui.SetNextItemWidth(200f * ImGuiHelpers.GlobalScale); + var limit = Mutable.AutoTellTabsLimit; + if (ImGui.SliderInt(HellionStrings.ChatLog_AutoTellTabs_Limit_Name, ref limit, 1, 50)) + { + Mutable.AutoTellTabsLimit = limit; + } + ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_Limit_Description); + + ImGui.Checkbox(HellionStrings.ChatLog_AutoTellTabs_Compact_Name, ref Mutable.AutoTellTabsCompactDisplay); + ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_Compact_Description); + + ImGui.Checkbox(HellionStrings.ChatLog_AutoTellTabs_GreetedToggle_Name, ref Mutable.AutoTellTabsShowGreetedToggle); + ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_GreetedToggle_Description); + + ImGui.Spacing(); + ImGuiUtil.HelpText(HellionStrings.ChatLog_AutoTellTabs_PreloadHint); + + ImGui.Spacing(); + ImGuiUtil.WarningText(HellionStrings.ChatLog_AutoTellTabs_ConflictHint); + } + } + + private void DrawBehaviourSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Chat_Behaviour_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_CollapseDuplicateMessages_Name, ref Mutable.CollapseDuplicateMessages); + ImGuiUtil.HelpMarker(Language.Options_CollapseDuplicateMessages_Description); + + if (Mutable.CollapseDuplicateMessages) + { + ImGui.Checkbox(Language.Options_CollapseDuplicateMsgUniqueLink_Name, ref Mutable.CollapseKeepUniqueLinks); + ImGuiUtil.HelpMarker(Language.Options_CollapseDuplicateMsgUniqueLink_Description); + } + } + } + + private void DrawPreviewSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Chat_Preview_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_Preview_Name, Mutable.PreviewPosition.Name())) + { + if (combo) + { + foreach (var position in Enum.GetValues()) + { + if (ImGui.Selectable(position.Name(), Mutable.PreviewPosition == position)) + { + Mutable.PreviewPosition = position; + } + } + } + } + ImGuiUtil.HelpMarker(Language.Options_Preview_Description); + + if (ImGuiUtil.InputIntVertical(Language.Options_PreviewMinimum_Name, Language.Options_PreviewMinimum_Description, ref Mutable.PreviewMinimum)) + { + Mutable.PreviewMinimum = Math.Clamp(Mutable.PreviewMinimum, 1, 250); + } + + ImGui.Checkbox(Language.Options_PreviewOnlyIf_Name, ref Mutable.OnlyPreviewIf); + ImGuiUtil.HelpMarker(Language.Options_PreviewOnlyIf_Description); + } + } + + private void DrawEmotesSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Chat_Emotes_Heading); + if (!tree.Success) + { + return; + } + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_ShowEmotes_Name, ref Mutable.ShowEmotes); + ImGuiUtil.HelpMarker(Language.Options_ShowEmotes_Desc); + + ImGui.Spacing(); + ImGui.TextUnformatted(Language.Options_Emote_BlockedEmotes); + ImGui.Spacing(); + + if (EmoteCache.State is EmoteCache.LoadingState.Done && WordPopupOptions.FilteredSheet.Length == 0) + { + WordPopupOptions = RefillSheet(); + } + + var buttonWidth = ImGui.GetContentRegionAvail().X / 3; + using (Plugin.FontManager.FontAwesome.Push()) + ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), new Vector2(buttonWidth, 0)); + + if (SearchSelector.SelectorPopup("WordAddPopup", out var newWord, WordPopupOptions)) + { + Mutable.BlockedEmotes.Add(newWord); + } + + using (var table = ImRaii.Table("##BlockedWords", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInner)) + { + if (table) + { + ImGui.TableSetupColumn(Language.Options_Emote_EmoteTable); + ImGui.TableSetupColumn("##Del", ImGuiTableColumnFlags.WidthStretch, 0.07f); + + ImGui.TableHeadersRow(); + + var copiedList = Mutable.BlockedEmotes.ToArray(); + foreach (var word in copiedList) + { + ImGui.TableNextColumn(); + ImGui.TextUnformatted(word); + + ImGui.TableNextColumn(); + if (ImGuiUtil.Button($"##{word}Del", FontAwesomeIcon.Trash, !ImGui.GetIO().KeyCtrl)) + { + Mutable.BlockedEmotes.Remove(word); + } + } + } + } + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + ImGui.TextUnformatted(Language.Options_Emote_EmoteStats); + ImGui.Spacing(); + + if (EmoteCache.State is EmoteCache.LoadingState.Done) + { + ImGui.TextColored(ImGuiColors.HealerGreen, Language.Options_Emote_Ready); + } + else + { + ImGui.TextColored(ImGuiColors.DPSRed, Language.Options_Emote_NotReady); + } + + ImGui.TextUnformatted($"{Language.Options_Emote_Loaded} {EmoteCache.SortedCodeArray.Length}"); + using (var emoteTable = ImRaii.Table("##LoadedEmotes", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInner)) + { + if (emoteTable) + { + ImGui.TableSetupColumn("##word1"); + ImGui.TableSetupColumn("##word2"); + ImGui.TableSetupColumn("##word3"); + ImGui.TableSetupColumn("##word4"); + ImGui.TableSetupColumn("##word5"); + + foreach (var word in EmoteCache.SortedCodeArray) + { + ImGui.TableNextColumn(); + ImGui.TextUnformatted(word); + } + } + } + } } } From 654f24c609bd1de3ada4909651939e35566c7fc0 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:09:50 +0200 Subject: [PATCH 11/23] docs(settings-refactor): add Chat tab header explaining emote block migration --- ChatTwo/Ui/SettingsTabs/Chat.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChatTwo/Ui/SettingsTabs/Chat.cs b/ChatTwo/Ui/SettingsTabs/Chat.cs index 49baafc..fffb17a 100644 --- a/ChatTwo/Ui/SettingsTabs/Chat.cs +++ b/ChatTwo/Ui/SettingsTabs/Chat.cs @@ -9,6 +9,10 @@ using Dalamud.Bindings.ImGui; namespace ChatTwo.Ui.SettingsTabs; +// Chat-Tab — vier eigenständige Sektionen: Auto-Tell-Tabs, Behaviour, +// Preview, Emotes. Der Emotes-Block ist 1:1 aus der Bestand-Datei +// Emote.cs übernommen; die Datei wird in Plan-Task 11 (Settings UX +// Polish v0.5.0) entfernt, sobald alle Tabs migriert sind. internal sealed class Chat : ISettingsTab { private Plugin Plugin { get; } From 0512e4729c88086e934936721e3f36bf799892e5 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:14:40 +0200 Subject: [PATCH 12/23] refactor(settings-refactor): remove theme settings from Privacy tab and tighten tree structure --- ChatTwo/Resources/HellionStrings.Designer.cs | 1 + ChatTwo/Resources/HellionStrings.de.resx | 3 + ChatTwo/Resources/HellionStrings.resx | 3 + ChatTwo/Ui/SettingsTabs/Privacy.cs | 174 +++++++++---------- 4 files changed, 85 insertions(+), 96 deletions(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index 3dac2eb..05d7d68 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -45,6 +45,7 @@ internal class HellionStrings internal static string Privacy_FilterEnabled_Name => Get(nameof(Privacy_FilterEnabled_Name)); internal static string Privacy_FilterEnabled_Description => Get(nameof(Privacy_FilterEnabled_Description)); internal static string Privacy_FilterEnabled_StorageOnly_Help => Get(nameof(Privacy_FilterEnabled_StorageOnly_Help)); + internal static string Privacy_Filter_Tree_Heading => Get(nameof(Privacy_Filter_Tree_Heading)); internal static string Privacy_Whitelist_Help => Get(nameof(Privacy_Whitelist_Help)); internal static string Privacy_Preset_PrivacyFirst => Get(nameof(Privacy_Preset_PrivacyFirst)); internal static string Privacy_Preset_ClearAll => Get(nameof(Privacy_Preset_ClearAll)); diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 48b161e..7228309 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -24,6 +24,9 @@ Der Filter steuert nur, was in die lokale Datenbank geschrieben wird. Im Chat-Log siehst du weiterhin jede Nachricht live, ausgeschlossene Kanäle werden nur nicht mehr gespeichert. Wenn du Kanäle auch aus der sichtbaren Anzeige entfernen willst, nutze die normalen Chat-Tab-Filter im Spiel. + + Privacy-Filter und Whitelist + Wähle aus, welche Kanäle in die lokale Datenbank gespeichert werden. Standard nach Datensparsamkeit: nur deine eigenen Konversationen. Über die Buttons unten kannst du eine Voreinstellung anwenden. diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 9cb8ce4..c70b61f 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -24,6 +24,9 @@ The filter only controls what is written to the local database. The chat log itself keeps showing every message live, disallowed channels just stop being saved. Use the channel hide options in your in-game chat tabs if you want to remove channels from the visible chat. + + Privacy filter and whitelist + Pick which channels are stored in the local database. Privacy-First default: only your own conversations. Use the buttons below to apply a preset. diff --git a/ChatTwo/Ui/SettingsTabs/Privacy.cs b/ChatTwo/Ui/SettingsTabs/Privacy.cs index 46d3ca9..8ec92f2 100644 --- a/ChatTwo/Ui/SettingsTabs/Privacy.cs +++ b/ChatTwo/Ui/SettingsTabs/Privacy.cs @@ -74,101 +74,7 @@ internal sealed class Privacy : ISettingsTab Plugin.FirstRunWizard.IsOpen = true; ImGui.Spacing(); - ImGui.TextUnformatted(HellionStrings.Theme_Heading); - using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) - { - ImGuiUtil.OptionCheckbox( - ref Mutable.HellionThemeEnabled, - HellionStrings.Theme_Enabled_Name, - HellionStrings.Theme_Enabled_Description); - - using (ImRaii.Disabled(!Mutable.HellionThemeEnabled)) - { - ImGui.Spacing(); - var opacity = Mutable.HellionThemeWindowOpacity; - if (ImGui.SliderFloat($"{HellionStrings.Theme_WindowOpacity_Label}##theme-opacity", ref opacity, 0.5f, 1.0f, "%.2f")) - Mutable.HellionThemeWindowOpacity = Math.Clamp(opacity, 0.5f, 1.0f); - ImGuiUtil.HelpText(HellionStrings.Theme_WindowOpacity_Help); - } - - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox( - ref Mutable.UseHellionFont, - HellionStrings.Theme_UseHellionFont_Name, - HellionStrings.Theme_UseHellionFont_Description); - } - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox( - ref Mutable.PrivacyFilterEnabled, - HellionStrings.Privacy_FilterEnabled_Name, - HellionStrings.Privacy_FilterEnabled_Description); - - ImGuiUtil.HelpText(HellionStrings.Privacy_FilterEnabled_StorageOnly_Help); - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - using (ImRaii.Disabled(!Mutable.PrivacyFilterEnabled)) - { - ImGuiUtil.HelpText(HellionStrings.Privacy_Whitelist_Help); - - ImGui.Spacing(); - - if (ImGui.Button(HellionStrings.Privacy_Preset_PrivacyFirst)) - Mutable.PrivacyPersistChannels = [..PrivacyDefaults.PrivacyFirstWhitelist]; - - ImGui.SameLine(); - if (ImGui.Button(HellionStrings.Privacy_Preset_ClearAll)) - Mutable.PrivacyPersistChannels.Clear(); - - ImGui.SameLine(); - if (ImGui.Button(HellionStrings.Privacy_Preset_SelectAll)) - foreach (var group in Groups) - foreach (var t in group.Types) - Mutable.PrivacyPersistChannels.Add(t); - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - foreach (var (heading, types) in Groups) - { - using var tree = ImRaii.TreeNode(heading()); - if (!tree.Success) - continue; - - using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) - { - foreach (var type in types) - { - var enabled = Mutable.PrivacyPersistChannels.Contains(type); - var label = type.ToString(); - if (ImGui.Checkbox($"{label}##privacy-{(int)type}", ref enabled)) - { - if (enabled) - Mutable.PrivacyPersistChannels.Add(type); - else - Mutable.PrivacyPersistChannels.Remove(type); - } - } - } - } - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox( - ref Mutable.PrivacyPersistUnknownChannels, - HellionStrings.Privacy_PersistUnknown_Name, - HellionStrings.Privacy_PersistUnknown_Description); - } + DrawPrivacyFilterSection(); ImGui.Spacing(); ImGui.Separator(); @@ -216,6 +122,82 @@ internal sealed class Privacy : ISettingsTab } } + private void DrawPrivacyFilterSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Privacy_Filter_Tree_Heading); + if (!tree.Success) + return; + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGuiUtil.OptionCheckbox( + ref Mutable.PrivacyFilterEnabled, + HellionStrings.Privacy_FilterEnabled_Name, + HellionStrings.Privacy_FilterEnabled_Description); + ImGuiUtil.HelpMarker(HellionStrings.Privacy_FilterEnabled_StorageOnly_Help); + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + using (ImRaii.Disabled(!Mutable.PrivacyFilterEnabled)) + { + ImGuiUtil.HelpText(HellionStrings.Privacy_Whitelist_Help); + + ImGui.Spacing(); + + if (ImGui.Button(HellionStrings.Privacy_Preset_PrivacyFirst)) + Mutable.PrivacyPersistChannels = [..PrivacyDefaults.PrivacyFirstWhitelist]; + + ImGui.SameLine(); + if (ImGui.Button(HellionStrings.Privacy_Preset_ClearAll)) + Mutable.PrivacyPersistChannels.Clear(); + + ImGui.SameLine(); + if (ImGui.Button(HellionStrings.Privacy_Preset_SelectAll)) + foreach (var group in Groups) + foreach (var t in group.Types) + Mutable.PrivacyPersistChannels.Add(t); + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + foreach (var (heading, types) in Groups) + { + using var groupTree = ImRaii.TreeNode(heading()); + if (!groupTree.Success) + continue; + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + foreach (var type in types) + { + var enabled = Mutable.PrivacyPersistChannels.Contains(type); + var label = type.ToString(); + if (ImGui.Checkbox($"{label}##privacy-{(int)type}", ref enabled)) + { + if (enabled) + Mutable.PrivacyPersistChannels.Add(type); + else + Mutable.PrivacyPersistChannels.Remove(type); + } + } + } + } + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + ImGuiUtil.OptionCheckbox( + ref Mutable.PrivacyPersistUnknownChannels, + HellionStrings.Privacy_PersistUnknown_Name, + HellionStrings.Privacy_PersistUnknown_Description); + } + } + } + private void DrawExportSection() { ImGui.TextUnformatted(HellionStrings.Export_Heading); @@ -363,7 +345,7 @@ internal sealed class Privacy : ISettingsTab var defaultDays = Mutable.RetentionDefaultDays; if (ImGui.InputInt(HellionStrings.Retention_Default_Label, ref defaultDays)) Mutable.RetentionDefaultDays = Math.Max(0, defaultDays); - ImGuiUtil.HelpText(HellionStrings.Retention_Default_Help); + ImGuiUtil.HelpMarker(HellionStrings.Retention_Default_Help); ImGui.Spacing(); From b76bfb3cfcd6fc529c4cb1bda76dc645532a1a44 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:22:26 +0200 Subject: [PATCH 13/23] refactor(settings-refactor): regroup Database tab into storage, viewer, stats tree nodes --- ChatTwo/Resources/HellionStrings.Designer.cs | 5 + ChatTwo/Resources/HellionStrings.de.resx | 11 + ChatTwo/Resources/HellionStrings.resx | 11 + ChatTwo/Ui/SettingsTabs/Database.cs | 229 +++++++++++-------- 4 files changed, 157 insertions(+), 99 deletions(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index 05d7d68..b0cef53 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -228,4 +228,9 @@ internal class HellionStrings internal static string Settings_Chat_Behaviour_Heading => Get(nameof(Settings_Chat_Behaviour_Heading)); internal static string Settings_Chat_Preview_Heading => Get(nameof(Settings_Chat_Preview_Heading)); internal static string Settings_Chat_Emotes_Heading => Get(nameof(Settings_Chat_Emotes_Heading)); + + // Hellion Chat — Database-Tab section headings + internal static string Settings_Database_Storage_Heading => Get(nameof(Settings_Database_Storage_Heading)); + internal static string Settings_Database_Viewer_Heading => Get(nameof(Settings_Database_Viewer_Heading)); + internal static string Settings_Database_Stats_Heading => Get(nameof(Settings_Database_Stats_Heading)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 7228309..c0f0d2b 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -522,4 +522,15 @@ Emotes + + + + Speicherung + + + DB-Viewer + + + Statistiken + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index c70b61f..e83edca 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -522,4 +522,15 @@ Emotes + + + + Storage + + + DB Viewer + + + Statistics + diff --git a/ChatTwo/Ui/SettingsTabs/Database.cs b/ChatTwo/Ui/SettingsTabs/Database.cs index e38445d..acba658 100755 --- a/ChatTwo/Ui/SettingsTabs/Database.cs +++ b/ChatTwo/Ui/SettingsTabs/Database.cs @@ -33,127 +33,158 @@ internal sealed class Database : ISettingsTab public void Draw(bool changed) { + // Shift-on-open keeps the Advanced tools available without a permanent + // toggle in the UI, mirroring upstream Chat 2 behaviour. if (changed) ShowAdvanced = ImGui.GetIO().KeyShift; - ImGuiUtil.OptionCheckbox(ref Mutable.DatabaseBattleMessages, Language.Options_DatabaseBattleMessages_Name, Language.Options_DatabaseBattleMessages_Description); + DrawStorageSection(); ImGui.Spacing(); - - if (ImGuiUtil.OptionCheckbox(ref Mutable.LoadPreviousSession, Language.Options_LoadPreviousSession_Name, Language.Options_LoadPreviousSession_Description)) - if (Mutable.LoadPreviousSession) - Mutable.FilterIncludePreviousSessions = true; - + DrawViewerSection(); ImGui.Spacing(); + DrawStatsSection(); + } - if (ImGuiUtil.OptionCheckbox(ref Mutable.FilterIncludePreviousSessions, Language.Options_FilterIncludePreviousSessions_Name, Language.Options_FilterIncludePreviousSessions_Description)) - if (!Mutable.FilterIncludePreviousSessions) - Mutable.LoadPreviousSession = false; + private void DrawStorageSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Database_Storage_Heading); + if (!tree.Success) + return; - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - var old = new FileInfo(Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat.db")); - var migratedOld = new FileInfo(Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat-litedb.db")); - if (old.Exists || migratedOld.Exists) - { - ImGui.TextUnformatted(Language.Options_Database_Old_Heading); - ImGui.Spacing(); - - if (ImGuiUtil.CtrlShiftButton(Language.Options_Database_Old_Delete, Language.Options_Database_Old_Delete_Tooltip)) - { - try - { - if (old.Exists) - old.Delete(); - else - migratedOld.Delete(); - WrapperUtil.AddNotification(Language.Options_Database_Old_Delete_Success, NotificationType.Success); - } - catch (Exception e) - { - Plugin.Log.Error(e, "Unable to delete old database"); - WrapperUtil.AddNotification(Language.Options_Database_Old_Delete_Error, NotificationType.Error); - } - } - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - } - - ImGui.TextUnformatted(Language.Options_Database_Metadata_Heading); using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) { - // Refresh the database size and message count every 5 seconds to avoid - // constant stat calls and spamming the database. - if (DatabaseLastRefreshTicks + 5 * 1000 < Environment.TickCount64) + ImGui.Checkbox(Language.Options_DatabaseBattleMessages_Name, ref Mutable.DatabaseBattleMessages); + ImGuiUtil.HelpMarker(Language.Options_DatabaseBattleMessages_Description); + + if (ImGui.Checkbox(Language.Options_LoadPreviousSession_Name, ref Mutable.LoadPreviousSession)) + if (Mutable.LoadPreviousSession) + Mutable.FilterIncludePreviousSessions = true; + ImGuiUtil.HelpMarker(Language.Options_LoadPreviousSession_Description); + + if (ImGui.Checkbox(Language.Options_FilterIncludePreviousSessions_Name, ref Mutable.FilterIncludePreviousSessions)) + if (!Mutable.FilterIncludePreviousSessions) + Mutable.LoadPreviousSession = false; + ImGuiUtil.HelpMarker(Language.Options_FilterIncludePreviousSessions_Description); + + var old = new FileInfo(Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat.db")); + var migratedOld = new FileInfo(Path.Join(Plugin.Interface.ConfigDirectory.FullName, "chat-litedb.db")); + if (old.Exists || migratedOld.Exists) { - DatabaseSize = Plugin.MessageManager.Store.DatabaseSize(); - DatabaseLogSize = Plugin.MessageManager.Store.DatabaseLogSize(); - DatabaseMessageCount = Plugin.MessageManager.Store.MessageCount(); - DatabaseLastRefreshTicks = Environment.TickCount64; - } + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); - // Copy the directory path instead of the file path so people can - // paste it into their file explorer. - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Path, MessageManager.DatabasePath())); - if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) - { - var path = Path.GetDirectoryName(MessageManager.DatabasePath()); - ImGui.SetClipboardText(path); - WrapperUtil.AddNotification(Language.Options_Database_Metadata_CopyConfigPathNotification, NotificationType.Info); - } + ImGui.TextUnformatted(Language.Options_Database_Old_Heading); + ImGui.Spacing(); - if (ImGui.IsItemHovered()) - { - ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); - ImGuiUtil.Tooltip(Language.Options_Database_Metadata_CopyConfigPath); - } - - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Size, StringUtil.BytesToString(DatabaseSize))); - if (ImGui.IsItemHovered()) - ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseSize)); - - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_LogSize, StringUtil.BytesToString(DatabaseLogSize))); - if (ImGui.IsItemHovered()) - ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseLogSize)); - - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_MessageCount, DatabaseMessageCount)); - - if (ImGuiUtil.CtrlShiftButton(Language.Options_ClearDatabase_Button, Language.Options_ClearDatabase_Tooltip)) - { - Plugin.Log.Warning("Clearing messages from database"); - Plugin.MessageManager.Store.ClearMessages(); - Plugin.MessageManager.ClearAllTabs(); - - // Refresh on next draw - DatabaseLastRefreshTicks = 0; - WrapperUtil.AddNotification(Language.Options_ClearDatabase_Success, NotificationType.Info); + if (ImGuiUtil.CtrlShiftButton(Language.Options_Database_Old_Delete, Language.Options_Database_Old_Delete_Tooltip)) + { + try + { + if (old.Exists) + old.Delete(); + else + migratedOld.Delete(); + WrapperUtil.AddNotification(Language.Options_Database_Old_Delete_Success, NotificationType.Success); + } + catch (Exception e) + { + Plugin.Log.Error(e, "Unable to delete old database"); + WrapperUtil.AddNotification(Language.Options_Database_Old_Delete_Error, NotificationType.Error); + } + } } } + } - ImGui.Spacing(); + private void DrawViewerSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Database_Viewer_Heading); + if (!tree.Success) + return; + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.TextUnformatted(Language.Options_Database_Metadata_Heading); + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + // Refresh the database size and message count every 5 seconds to avoid + // constant stat calls and spamming the database. + if (DatabaseLastRefreshTicks + 5 * 1000 < Environment.TickCount64) + { + DatabaseSize = Plugin.MessageManager.Store.DatabaseSize(); + DatabaseLogSize = Plugin.MessageManager.Store.DatabaseLogSize(); + DatabaseMessageCount = Plugin.MessageManager.Store.MessageCount(); + DatabaseLastRefreshTicks = Environment.TickCount64; + } + + // Copy the directory path instead of the file path so people can + // paste it into their file explorer. + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Path, MessageManager.DatabasePath())); + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) + { + var path = Path.GetDirectoryName(MessageManager.DatabasePath()); + ImGui.SetClipboardText(path); + WrapperUtil.AddNotification(Language.Options_Database_Metadata_CopyConfigPathNotification, NotificationType.Info); + } + + if (ImGui.IsItemHovered()) + { + ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); + ImGuiUtil.Tooltip(Language.Options_Database_Metadata_CopyConfigPath); + } + + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Size, StringUtil.BytesToString(DatabaseSize))); + if (ImGui.IsItemHovered()) + ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseSize)); + + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_LogSize, StringUtil.BytesToString(DatabaseLogSize))); + if (ImGui.IsItemHovered()) + ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseLogSize)); + + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_MessageCount, DatabaseMessageCount)); + + if (ImGuiUtil.CtrlShiftButton(Language.Options_ClearDatabase_Button, Language.Options_ClearDatabase_Tooltip)) + { + Plugin.Log.Warning("Clearing messages from database"); + Plugin.MessageManager.Store.ClearMessages(); + Plugin.MessageManager.ClearAllTabs(); + + // Refresh on next draw + DatabaseLastRefreshTicks = 0; + WrapperUtil.AddNotification(Language.Options_ClearDatabase_Success, NotificationType.Info); + } + } + } + } + + private void DrawStatsSection() + { if (!ShowAdvanced) return; - using var treeNode = ImRaii.TreeNode(Language.Options_Database_Advanced); - using var wrap = ImRaii.TextWrapPos(0.0f); + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Database_Stats_Heading); + if (!tree.Success) + return; - ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning); - if (ImGuiUtil.CtrlShiftButton("Perform maintenance", "Ctrl+Shift: MessageManager.Store.PerformMaintenance()")) - Plugin.MessageManager.Store.PerformMaintenance(); - - if (ImGuiUtil.CtrlShiftButton("Reload messages from database", "Ctrl+Shift: MessageManager.FilterAllTabs()")) + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) { - Plugin.MessageManager.ClearAllTabs(); - Plugin.MessageManager.FilterAllTabsAsync(); - } + using var treeNode = ImRaii.TreeNode(Language.Options_Database_Advanced); + using var wrap = ImRaii.TextWrapPos(0.0f); - if (ImGuiUtil.CtrlShiftButton("Inject 10,000 messages", "Ctrl+Shift: creates 10,000 unique messages (async)")) - new Thread(() => InsertMessages(10_000)).Start(); - ImGui.Spacing(); + ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning); + if (ImGuiUtil.CtrlShiftButton("Perform maintenance", "Ctrl+Shift: MessageManager.Store.PerformMaintenance()")) + Plugin.MessageManager.Store.PerformMaintenance(); + + if (ImGuiUtil.CtrlShiftButton("Reload messages from database", "Ctrl+Shift: MessageManager.FilterAllTabs()")) + { + Plugin.MessageManager.ClearAllTabs(); + Plugin.MessageManager.FilterAllTabsAsync(); + } + + if (ImGuiUtil.CtrlShiftButton("Inject 10,000 messages", "Ctrl+Shift: creates 10,000 unique messages (async)")) + new Thread(() => InsertMessages(10_000)).Start(); + } } private void InsertMessages(int count) From 395a0d7c989795b0e1f5115aceb354342ab303ac Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:33:51 +0200 Subject: [PATCH 14/23] refactor(settings): polish database tab section structure Drop the redundant inner Advanced TreeNode in the Maintenance section, flatten the duplicated indent in the Overview section, and rename the section headings so they reflect their content (Overview shows metadata, Maintenance hosts the shift-gated tooling). --- ChatTwo/Resources/HellionStrings.de.resx | 4 +- ChatTwo/Resources/HellionStrings.resx | 4 +- ChatTwo/Ui/SettingsTabs/Database.cs | 79 +++++++++++------------- 3 files changed, 41 insertions(+), 46 deletions(-) diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index c0f0d2b..671dd43 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -528,9 +528,9 @@ Speicherung - DB-Viewer + Übersicht - Statistiken + Wartung diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index e83edca..8b19242 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -528,9 +528,9 @@ Storage - DB Viewer + Overview - Statistics + Maintenance diff --git a/ChatTwo/Ui/SettingsTabs/Database.cs b/ChatTwo/Ui/SettingsTabs/Database.cs index acba658..afa75e9 100755 --- a/ChatTwo/Ui/SettingsTabs/Database.cs +++ b/ChatTwo/Ui/SettingsTabs/Database.cs @@ -105,55 +105,51 @@ internal sealed class Database : ISettingsTab using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) { - ImGui.TextUnformatted(Language.Options_Database_Metadata_Heading); - using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + // Refresh the database size and message count every 5 seconds to avoid + // constant stat calls and spamming the database. + if (DatabaseLastRefreshTicks + 5 * 1000 < Environment.TickCount64) { - // Refresh the database size and message count every 5 seconds to avoid - // constant stat calls and spamming the database. - if (DatabaseLastRefreshTicks + 5 * 1000 < Environment.TickCount64) - { - DatabaseSize = Plugin.MessageManager.Store.DatabaseSize(); - DatabaseLogSize = Plugin.MessageManager.Store.DatabaseLogSize(); - DatabaseMessageCount = Plugin.MessageManager.Store.MessageCount(); - DatabaseLastRefreshTicks = Environment.TickCount64; - } + DatabaseSize = Plugin.MessageManager.Store.DatabaseSize(); + DatabaseLogSize = Plugin.MessageManager.Store.DatabaseLogSize(); + DatabaseMessageCount = Plugin.MessageManager.Store.MessageCount(); + DatabaseLastRefreshTicks = Environment.TickCount64; + } - // Copy the directory path instead of the file path so people can - // paste it into their file explorer. - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Path, MessageManager.DatabasePath())); - if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) - { - var path = Path.GetDirectoryName(MessageManager.DatabasePath()); - ImGui.SetClipboardText(path); - WrapperUtil.AddNotification(Language.Options_Database_Metadata_CopyConfigPathNotification, NotificationType.Info); - } + // Copy the directory path instead of the file path so people can + // paste it into their file explorer. + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Path, MessageManager.DatabasePath())); + if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) + { + var path = Path.GetDirectoryName(MessageManager.DatabasePath()); + ImGui.SetClipboardText(path); + WrapperUtil.AddNotification(Language.Options_Database_Metadata_CopyConfigPathNotification, NotificationType.Info); + } - if (ImGui.IsItemHovered()) - { - ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); - ImGuiUtil.Tooltip(Language.Options_Database_Metadata_CopyConfigPath); - } + if (ImGui.IsItemHovered()) + { + ImGui.SetMouseCursor(ImGuiMouseCursor.Hand); + ImGuiUtil.Tooltip(Language.Options_Database_Metadata_CopyConfigPath); + } - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Size, StringUtil.BytesToString(DatabaseSize))); - if (ImGui.IsItemHovered()) - ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseSize)); + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_Size, StringUtil.BytesToString(DatabaseSize))); + if (ImGui.IsItemHovered()) + ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseSize)); - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_LogSize, StringUtil.BytesToString(DatabaseLogSize))); - if (ImGui.IsItemHovered()) - ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseLogSize)); + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_LogSize, StringUtil.BytesToString(DatabaseLogSize))); + if (ImGui.IsItemHovered()) + ImGuiUtil.Tooltip(StringUtil.BytesToString(DatabaseLogSize)); - ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_MessageCount, DatabaseMessageCount)); + ImGuiUtil.HelpText(string.Format(Language.Options_Database_Metadata_MessageCount, DatabaseMessageCount)); - if (ImGuiUtil.CtrlShiftButton(Language.Options_ClearDatabase_Button, Language.Options_ClearDatabase_Tooltip)) - { - Plugin.Log.Warning("Clearing messages from database"); - Plugin.MessageManager.Store.ClearMessages(); - Plugin.MessageManager.ClearAllTabs(); + if (ImGuiUtil.CtrlShiftButton(Language.Options_ClearDatabase_Button, Language.Options_ClearDatabase_Tooltip)) + { + Plugin.Log.Warning("Clearing messages from database"); + Plugin.MessageManager.Store.ClearMessages(); + Plugin.MessageManager.ClearAllTabs(); - // Refresh on next draw - DatabaseLastRefreshTicks = 0; - WrapperUtil.AddNotification(Language.Options_ClearDatabase_Success, NotificationType.Info); - } + // Refresh on next draw + DatabaseLastRefreshTicks = 0; + WrapperUtil.AddNotification(Language.Options_ClearDatabase_Success, NotificationType.Info); } } } @@ -169,7 +165,6 @@ internal sealed class Database : ISettingsTab using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) { - using var treeNode = ImRaii.TreeNode(Language.Options_Database_Advanced); using var wrap = ImRaii.TextWrapPos(0.0f); ImGuiUtil.WarningText(Language.Options_Database_Advanced_Warning); From fa108c227150c6d34a37c3a8efe72611e276124f Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:34:24 +0200 Subject: [PATCH 15/23] refactor(settings): align tabs tab plugin reference to property style Match the property-style reference used across the other settings tabs so the field/property mix is gone. --- ChatTwo/Ui/SettingsTabs/Tabs.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChatTwo/Ui/SettingsTabs/Tabs.cs b/ChatTwo/Ui/SettingsTabs/Tabs.cs index 5682aaf..5c84c8e 100755 --- a/ChatTwo/Ui/SettingsTabs/Tabs.cs +++ b/ChatTwo/Ui/SettingsTabs/Tabs.cs @@ -10,7 +10,7 @@ namespace ChatTwo.Ui.SettingsTabs; internal sealed class Tabs : ISettingsTab { - private readonly Plugin Plugin; + private Plugin Plugin { get; } private Configuration Mutable { get; } public string Name => Language.Options_Tabs_Tab + "###tabs-tabs"; From 6839ccaf345bbd08a382d1b187a13c0974e45321 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:36:07 +0200 Subject: [PATCH 16/23] feat(settings): build information tab from about and changelog Three collapsible sections: version info (author, discord handle, version, issue tracker), about HellionChat (maintainer, mission, build lineage, license, SE notice, localisation, translator list), and the changelog (auto-print toggle plus the manifest changelog renderer). --- ChatTwo/Resources/HellionStrings.Designer.cs | 5 + ChatTwo/Resources/HellionStrings.de.resx | 11 ++ ChatTwo/Resources/HellionStrings.resx | 11 ++ ChatTwo/Ui/SettingsTabs/Information.cs | 169 ++++++++++++++++++- 4 files changed, 194 insertions(+), 2 deletions(-) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index b0cef53..dbcffd1 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -233,4 +233,9 @@ internal class HellionStrings internal static string Settings_Database_Storage_Heading => Get(nameof(Settings_Database_Storage_Heading)); internal static string Settings_Database_Viewer_Heading => Get(nameof(Settings_Database_Viewer_Heading)); internal static string Settings_Database_Stats_Heading => Get(nameof(Settings_Database_Stats_Heading)); + + // Hellion Chat — Information-Tab section headings + internal static string Settings_Information_VersionInfo_Heading => Get(nameof(Settings_Information_VersionInfo_Heading)); + internal static string Settings_Information_About_Heading => Get(nameof(Settings_Information_About_Heading)); + internal static string Settings_Information_Changelog_Heading => Get(nameof(Settings_Information_Changelog_Heading)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 671dd43..e0e25f4 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -533,4 +533,15 @@ Wartung + + + + Versionsinfo + + + Über HellionChat + + + Changelog + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 8b19242..ab77c52 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -533,4 +533,15 @@ Maintenance + + + + Version Info + + + About HellionChat + + + Changelog + diff --git a/ChatTwo/Ui/SettingsTabs/Information.cs b/ChatTwo/Ui/SettingsTabs/Information.cs index 9d02960..38667fb 100644 --- a/ChatTwo/Ui/SettingsTabs/Information.cs +++ b/ChatTwo/Ui/SettingsTabs/Information.cs @@ -1,23 +1,188 @@ using ChatTwo.Resources; using ChatTwo.Util; +using Dalamud.Interface; +using Dalamud.Interface.Colors; +using Dalamud.Interface.Utility; using Dalamud.Interface.Utility.Raii; using Dalamud.Bindings.ImGui; namespace ChatTwo.Ui.SettingsTabs; +// Information-Tab vereint die früheren About- und Changelog-Tabs in +// drei kollabierbaren Sektionen. Der About-Inhalt ist 1:1 aus About.cs +// übernommen, die Changelog-Render-Logik aus Changelog.cs. internal sealed class Information : ISettingsTab { - private readonly Configuration Mutable; + private Configuration Mutable { get; } public string Name => HellionStrings.Settings_Tab_Information + "###tabs-information"; + private readonly List Translators = + [ + "q673135110", "Akizem", "d0tiKs", + "Moonlight_Everlit", "Dark32", "andreycout", + "Button_", "Cali666", "cassandra308", + "lokinmodar", "jtabox", "AkiraYorumoto", + "MKhayle", "elena.space", "imlisa", + "andrei5125", "ShivaMaheshvara", "aislinn87", + "nishinatsu051", "lichuyuan", "Risu64", + "yummypillow", "witchymary", "Yuzumi", + "zomsakura", "Sirayuki" + ]; + internal Information(Configuration mutable) { Mutable = mutable; + Translators.Sort((a, b) => string.Compare(a.ToLowerInvariant(), b.ToLowerInvariant(), StringComparison.Ordinal)); } public void Draw(bool changed) { - // About-Inhalt zieht in Plan-Task 10 ein. + using var wrap = ImRaii.TextWrapPos(0.0f); + + DrawVersionInfoSection(); + ImGui.Spacing(); + DrawAboutSection(); + ImGui.Spacing(); + DrawChangelogSection(); + } + + private void DrawVersionInfoSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Information_VersionInfo_Heading); + if (!tree.Success) + return; + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.TextUnformatted(string.Format(Language.Options_About_Opening, Plugin.PluginName)); + + ImGuiHelpers.ScaledDummy(10.0f); + + ImGui.TextUnformatted(Language.Options_About_Authors); + ImGui.SameLine(); + ImGui.TextColored(ImGuiColors.ParsedGold, Plugin.Interface.Manifest.Author); + + ImGui.TextUnformatted(Language.Options_About_Discord); + ImGui.SameLine(); + ImGui.TextColored(ImGuiColors.ParsedGold, "@j.j_kazama"); + + ImGui.TextUnformatted(Language.Options_About_Version); + ImGui.SameLine(); + ImGui.TextColored(ImGuiColors.ParsedOrange, Plugin.Interface.Manifest.AssemblyVersion.ToString(3)); + + ImGuiHelpers.ScaledDummy(10.0f); + + ImGui.TextUnformatted(Language.Options_About_Github_Issues); + ImGui.SameLine(); + if (ImGuiUtil.IconButton(FontAwesomeIcon.ExternalLinkAlt, "githubIssues")) + Dalamud.Utility.Util.OpenLink("https://github.com/JonKazama-Hellion/HellionChat/issues"); + } + } + + private void DrawAboutSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Information_About_Heading); + if (!tree.Success) + return; + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_Maintainer_Heading); + ImGui.TextUnformatted(HellionStrings.About_Maintainer_Body); + ImGui.TextUnformatted(HellionStrings.About_Maintainer_Website_Label); + ImGui.SameLine(); + if (ImGuiUtil.IconButton(FontAwesomeIcon.ExternalLinkAlt, "hellionMedia")) + Dalamud.Utility.Util.OpenLink("https://hellion-media.de"); + + ImGuiHelpers.ScaledDummy(10.0f); + + ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_Mission_Heading); + ImGui.TextUnformatted(HellionStrings.About_Mission_P1); + ImGui.Spacing(); + ImGui.TextUnformatted(HellionStrings.About_Mission_P2); + ImGui.Spacing(); + ImGui.TextUnformatted(HellionStrings.About_Mission_P3); + + ImGuiHelpers.ScaledDummy(10.0f); + + ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_BuiltOn_Heading); + ImGui.TextUnformatted(HellionStrings.About_BuiltOn_P1); + ImGui.Spacing(); + ImGui.TextUnformatted(HellionStrings.About_BuiltOn_P2); + ImGui.Spacing(); + ImGui.TextUnformatted(HellionStrings.About_BuiltOn_Upstream_Label); + ImGui.SameLine(); + if (ImGuiUtil.IconButton(FontAwesomeIcon.ExternalLinkAlt, "chatTwoUpstream")) + Dalamud.Utility.Util.OpenLink("https://github.com/Infiziert90/ChatTwo"); + + ImGuiHelpers.ScaledDummy(10.0f); + + ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_License_Heading); + ImGui.TextUnformatted(HellionStrings.About_License_P1); + ImGui.TextUnformatted(HellionStrings.About_License_P2); + ImGui.TextUnformatted(HellionStrings.About_License_P3); + + ImGuiHelpers.ScaledDummy(10.0f); + + ImGui.TextColored(ImGuiColors.DalamudOrange, HellionStrings.About_SE_Heading); + ImGui.TextUnformatted(HellionStrings.About_SE_P1); + ImGui.TextUnformatted(HellionStrings.About_SE_P2); + + ImGui.Spacing(); + + ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_Localization_Heading); + ImGui.TextUnformatted(HellionStrings.About_Localization_P1); + ImGui.TextUnformatted(HellionStrings.About_Localization_P2); + + ImGui.Spacing(); + + using (var translatorTree = ImRaii.TreeNode(HellionStrings.About_Translators_TreeNode)) + { + if (translatorTree) + { + using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false); + foreach (var translator in Translators) + ImGui.TextUnformatted(translator); + } + } + } + } + + private void DrawChangelogSection() + { + using var tree = ImRaii.TreeNode(HellionStrings.Settings_Information_Changelog_Heading); + if (!tree.Success) + return; + + using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) + { + ImGui.Checkbox(Language.Options_PrintChangelog_Name, ref Mutable.PrintChangelog); + ImGuiUtil.HelpMarker(Language.Options_PrintChangelog_Description); + + ImGui.Spacing(); + ImGui.Separator(); + ImGui.Spacing(); + + var changelog = Plugin.Interface.Manifest.Changelog; + if (changelog == null) + return; + + ImGui.TextUnformatted(Language.Options_Changelog_Header); + ImGui.TextUnformatted($"Version {Plugin.Interface.Manifest.AssemblyVersion.ToString(3)}"); + ImGui.Spacing(); + foreach (var sentence in changelog.Split("\n")) + { + if (sentence == string.Empty) + { + ImGui.NewLine(); + continue; + } + + var indented = sentence.StartsWith('-') || sentence.StartsWith(" -"); + using var indent = ImRaii.PushIndent(10.0f, true, indented); + ImGui.TextUnformatted(sentence); + } + } } } From c22b169b73ad5dca27ee41dd6a97ae3553e7e3f0 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:36:31 +0200 Subject: [PATCH 17/23] chore(settings): remove legacy settings tab files The nine legacy tab implementations were superseded by the new eight themed tabs. Removing them now that the consolidated structure is in place keeps SettingsTabs/ aligned with what actually ships. --- ChatTwo/Ui/SettingsTabs/About.cs | 128 ------------------ ChatTwo/Ui/SettingsTabs/Changelog.cs | 51 -------- ChatTwo/Ui/SettingsTabs/ChatColours.cs | 69 ---------- ChatTwo/Ui/SettingsTabs/ChatLog.cs | 159 ----------------------- ChatTwo/Ui/SettingsTabs/Display.cs | 116 ----------------- ChatTwo/Ui/SettingsTabs/Emote.cs | 113 ---------------- ChatTwo/Ui/SettingsTabs/Fonts.cs | 97 -------------- ChatTwo/Ui/SettingsTabs/Miscellaneous.cs | 62 --------- ChatTwo/Ui/SettingsTabs/Preview.cs | 42 ------ 9 files changed, 837 deletions(-) delete mode 100755 ChatTwo/Ui/SettingsTabs/About.cs delete mode 100644 ChatTwo/Ui/SettingsTabs/Changelog.cs delete mode 100755 ChatTwo/Ui/SettingsTabs/ChatColours.cs delete mode 100644 ChatTwo/Ui/SettingsTabs/ChatLog.cs delete mode 100755 ChatTwo/Ui/SettingsTabs/Display.cs delete mode 100644 ChatTwo/Ui/SettingsTabs/Emote.cs delete mode 100755 ChatTwo/Ui/SettingsTabs/Fonts.cs delete mode 100755 ChatTwo/Ui/SettingsTabs/Miscellaneous.cs delete mode 100644 ChatTwo/Ui/SettingsTabs/Preview.cs diff --git a/ChatTwo/Ui/SettingsTabs/About.cs b/ChatTwo/Ui/SettingsTabs/About.cs deleted file mode 100755 index fde0a6d..0000000 --- a/ChatTwo/Ui/SettingsTabs/About.cs +++ /dev/null @@ -1,128 +0,0 @@ -using System.Numerics; -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Interface; -using Dalamud.Interface.Colors; -using Dalamud.Interface.Utility; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class About : ISettingsTab -{ - public string Name => string.Format(Language.Options_About_Tab, Plugin.PluginName) + "###tabs-about"; - - private readonly List Translators = - [ - "q673135110", "Akizem", "d0tiKs", - "Moonlight_Everlit", "Dark32", "andreycout", - "Button_", "Cali666", "cassandra308", - "lokinmodar", "jtabox", "AkiraYorumoto", - "MKhayle", "elena.space", "imlisa", - "andrei5125", "ShivaMaheshvara", "aislinn87", - "nishinatsu051", "lichuyuan", "Risu64", - "yummypillow", "witchymary", "Yuzumi", - "zomsakura", "Sirayuki" - ]; - - internal About() - { - Translators.Sort((a, b) => string.Compare(a.ToLowerInvariant(), b.ToLowerInvariant(), StringComparison.Ordinal)); - } - - public void Draw(bool changed) - { - using var wrap = ImRaii.TextWrapPos(0.0f); - - ImGui.TextUnformatted(string.Format(Language.Options_About_Opening, Plugin.PluginName)); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextUnformatted(Language.Options_About_Authors); - ImGui.SameLine(); - ImGui.TextColored(ImGuiColors.ParsedGold, Plugin.Interface.Manifest.Author); - - ImGui.TextUnformatted(Language.Options_About_Discord); - ImGui.SameLine(); - ImGui.TextColored(ImGuiColors.ParsedGold, "@j.j_kazama"); - - ImGui.TextUnformatted(Language.Options_About_Version); - ImGui.SameLine(); - ImGui.TextColored(ImGuiColors.ParsedOrange, Plugin.Interface.Manifest.AssemblyVersion.ToString(3)); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextUnformatted(Language.Options_About_Github_Issues); - ImGui.SameLine(); - if (ImGuiUtil.IconButton(FontAwesomeIcon.ExternalLinkAlt, "githubIssues")) - Dalamud.Utility.Util.OpenLink("https://github.com/JonKazama-Hellion/HellionChat/issues"); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_Maintainer_Heading); - ImGui.TextUnformatted(HellionStrings.About_Maintainer_Body); - ImGui.TextUnformatted(HellionStrings.About_Maintainer_Website_Label); - ImGui.SameLine(); - if (ImGuiUtil.IconButton(FontAwesomeIcon.ExternalLinkAlt, "hellionMedia")) - Dalamud.Utility.Util.OpenLink("https://hellion-media.de"); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_Mission_Heading); - ImGui.TextUnformatted(HellionStrings.About_Mission_P1); - ImGui.Spacing(); - ImGui.TextUnformatted(HellionStrings.About_Mission_P2); - ImGui.Spacing(); - ImGui.TextUnformatted(HellionStrings.About_Mission_P3); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_BuiltOn_Heading); - ImGui.TextUnformatted(HellionStrings.About_BuiltOn_P1); - ImGui.Spacing(); - ImGui.TextUnformatted(HellionStrings.About_BuiltOn_P2); - ImGui.Spacing(); - ImGui.TextUnformatted(HellionStrings.About_BuiltOn_Upstream_Label); - ImGui.SameLine(); - if (ImGuiUtil.IconButton(FontAwesomeIcon.ExternalLinkAlt, "chatTwoUpstream")) - Dalamud.Utility.Util.OpenLink("https://github.com/Infiziert90/ChatTwo"); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_License_Heading); - ImGui.TextUnformatted(HellionStrings.About_License_P1); - ImGui.TextUnformatted(HellionStrings.About_License_P2); - ImGui.TextUnformatted(HellionStrings.About_License_P3); - - ImGuiHelpers.ScaledDummy(10.0f); - - ImGui.TextColored(ImGuiColors.DalamudOrange, HellionStrings.About_SE_Heading); - ImGui.TextUnformatted(HellionStrings.About_SE_P1); - ImGui.TextUnformatted(HellionStrings.About_SE_P2); - - ImGui.Spacing(); - - ImGui.TextColored(ImGuiColors.ParsedGold, HellionStrings.About_Localization_Heading); - ImGui.TextUnformatted(HellionStrings.About_Localization_P1); - ImGui.TextUnformatted(HellionStrings.About_Localization_P2); - - ImGui.Spacing(); - - // The translator list lives at the bottom of the About tab. Render - // it directly inside the parent scroll container instead of a - // fixed-height child — the previous "remaining space" calculation - // shrank to zero (or below) once the About copy grew, which made - // the section unreachable on smaller settings windows. - using (var treeNode = ImRaii.TreeNode(HellionStrings.About_Translators_TreeNode)) - { - if (treeNode) - { - using var indent = ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false); - foreach (var translator in Translators) - ImGui.TextUnformatted(translator); - } - } - ImGui.Spacing(); - } -} diff --git a/ChatTwo/Ui/SettingsTabs/Changelog.cs b/ChatTwo/Ui/SettingsTabs/Changelog.cs deleted file mode 100644 index 8ee43a7..0000000 --- a/ChatTwo/Ui/SettingsTabs/Changelog.cs +++ /dev/null @@ -1,51 +0,0 @@ -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class Changelog : ISettingsTab -{ - private Configuration Mutable { get; } - - public string Name => Language.Options_Changelog_Tab + "###tabs-changelog"; - - internal Changelog(Configuration mutable) - { - Mutable = mutable; - } - - public void Draw(bool changed) - { - using var wrap = ImRaii.TextWrapPos(0.0f); - - ImGui.TextUnformatted(Language.Options_Warning_NotImplemented); - ImGuiUtil.OptionCheckbox(ref Mutable.PrintChangelog, Language.Options_PrintChangelog_Name, Language.Options_PrintChangelog_Description); - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - var changelog = Plugin.Interface.Manifest.Changelog; - if (changelog != null) - { - ImGui.TextUnformatted(Language.Options_Changelog_Header); - ImGui.TextUnformatted($"Version {Plugin.Interface.Manifest.AssemblyVersion.ToString(3)}"); - ImGui.Spacing(); - foreach (var sentence in changelog.Split("\n")) - { - if (sentence == string.Empty) - { - ImGui.NewLine(); - continue; - } - - var condition = sentence.StartsWith('-') || sentence.StartsWith(" -"); - using var indent = ImRaii.PushIndent(10.0f, true, condition); - ImGui.TextUnformatted(sentence); - } - } - ImGui.Spacing(); - } -} diff --git a/ChatTwo/Ui/SettingsTabs/ChatColours.cs b/ChatTwo/Ui/SettingsTabs/ChatColours.cs deleted file mode 100755 index 18f784f..0000000 --- a/ChatTwo/Ui/SettingsTabs/ChatColours.cs +++ /dev/null @@ -1,69 +0,0 @@ -using ChatTwo.Code; -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Interface; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class ChatColours : ISettingsTab -{ - private Plugin Plugin { get; } - private Configuration Mutable { get; } - - public string Name => Language.Options_ChatColours_Tab + "###tabs-chat-colours"; - - internal ChatColours(Plugin plugin, Configuration mutable) - { - Plugin = plugin; - Mutable = mutable; - - #if DEBUG - // Users can set colours for ExtraChat linkshells in the ExtraChat plugin directly. - var sortable = ChatTypeExt.SortOrder - .SelectMany(entry => entry.Item2) - .Where(type => !type.IsGm() && !type.IsExtraChatLinkshell()) - .ToHashSet(); - var total = Enum.GetValues() - .Where(type => !type.IsGm() && !type.IsExtraChatLinkshell()) - .ToHashSet(); - if (sortable.Count != total.Count) - { - Plugin.Log.Warning($"There are {sortable.Count} sortable channels, but there are {total.Count} total channels."); - total.ExceptWith(sortable); - foreach (var missing in total) - Plugin.Log.Information($"Missing {missing}"); - } - #endif - } - - public void Draw(bool changed) - { - foreach (var (_, types) in ChatTypeExt.SortOrder) - { - foreach (var type in types) - { - if (ImGuiUtil.IconButton(FontAwesomeIcon.UndoAlt, $"{type}", Language.Options_ChatColours_Reset)) - Mutable.ChatColours.Remove(type); - - ImGui.SameLine(); - - if (ImGuiUtil.IconButton(FontAwesomeIcon.LongArrowAltDown, $"{type}", Language.Options_ChatColours_Import)) - { - var gameColour = Plugin.Functions.Chat.GetChannelColor(type); - Mutable.ChatColours[type] = gameColour ?? type.DefaultColor() ?? 0; - } - - ImGui.SameLine(); - - var vec = Mutable.ChatColours.TryGetValue(type, out var colour) - ? ColourUtil.RgbaToVector3(colour) - : ColourUtil.RgbaToVector3(type.DefaultColor() ?? 0); - if (ImGui.ColorEdit3(type.Name(), ref vec, ImGuiColorEditFlags.NoInputs)) - Mutable.ChatColours[type] = ColourUtil.Vector3ToRgba(vec); - } - } - - ImGui.Spacing(); - } -} diff --git a/ChatTwo/Ui/SettingsTabs/ChatLog.cs b/ChatTwo/Ui/SettingsTabs/ChatLog.cs deleted file mode 100644 index a88f5be..0000000 --- a/ChatTwo/Ui/SettingsTabs/ChatLog.cs +++ /dev/null @@ -1,159 +0,0 @@ -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Interface.Style; -using Dalamud.Interface.Utility; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class ChatLog : ISettingsTab -{ - private readonly Plugin Plugin; - private Configuration Mutable { get; } - - public string Name => Language.Options_ChatLog_Tab + "###tabs-chatlog"; - - internal ChatLog(Plugin plugin, Configuration mutable) - { - Plugin = plugin; - Mutable = mutable; - } - - public void Draw(bool changed) - { - using (ImRaii.TextWrapPos(0.0f)) - { - ImGuiUtil.OptionCheckbox(ref Mutable.KeepInputFocus, Language.Options_KeepInputFocus_Name, Language.Options_KeepInputFocus_Description); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.PlaySounds, Language.Options_PlaySounds_Name, Language.Options_PlaySounds_Description); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.SidebarTabView, Language.Options_SidebarTabView_Name, string.Format(Language.Options_SidebarTabView_Description, Plugin.PluginName)); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.ShowNoviceNetwork, Language.Options_ShowNoviceNetwork_Name, Language.Options_ShowNoviceNetwork_Description); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.ShowHideButton, Language.Options_ShowHideButton_Name, Language.Options_ShowHideButton_Description); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.NativeItemTooltips, Language.Options_NativeItemTooltips_Name, string.Format(Language.Options_NativeItemTooltips_Description, Plugin.PluginName)); - ImGui.Spacing(); - - if (Mutable.NativeItemTooltips) - { - ImGuiUtil.DragFloatVertical(Language.Options_TooltipOffset_Name, Language.Options_TooltipOffset_Desc, ref Mutable.TooltipOffset, 1, 0f, 400f, $"{Mutable.TooltipOffset:N0}px", ImGuiSliderFlags.AlwaysClamp); - ImGui.Spacing(); - } - - ImGuiUtil.DragFloatVertical(Language.Options_WindowOpacity_Name, ref Mutable.WindowAlpha, .25f, 0f, 100f, $"{Mutable.WindowAlpha:N2}%%", ImGuiSliderFlags.AlwaysClamp); - ImGui.Spacing(); - - if (ImGuiUtil.InputIntVertical(Language.Options_MaxLinesToShow_Name, Language.Options_MaxLinesToShow_Description, ref Mutable.MaxLinesToRender)) - Mutable.MaxLinesToRender = Math.Clamp(Mutable.MaxLinesToRender, 1, 10_000); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.CanMove, Language.Options_CanMove_Name); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.CanResize, Language.Options_CanResize_Name); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.ShowTitleBar, Language.Options_ShowTitleBar_Name); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.ShowPopOutTitleBar, Language.Options_ShowPopOutTitleBar_Name); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.OverrideStyle, Language.Options_OverrideStyle_Name, Language.Options_OverrideStyle_Name_Desc); - ImGui.Spacing(); - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - ImGui.TextUnformatted(Language.Options_ChatTabForwardKeybind_Name); - ImGui.SetNextItemWidth(-1); - ImGuiUtil.KeybindInput("ChatTabForwardKeybind", ref Mutable.ChatTabForward); - - ImGui.TextUnformatted(Language.Options_ChatTabBackwardKeybind_Name); - ImGui.SetNextItemWidth(-1); - ImGuiUtil.KeybindInput("ChatTabBackwardKeybind", ref Mutable.ChatTabBackward); - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - ImGui.TextUnformatted(Language.Options_AdjustPosition_Name); - ImGui.SetNextItemWidth(-1); - var pos = Plugin.ChatLogWindow.LastWindowPos; - if (ImGui.DragFloat2($"##{Language.Options_AdjustPosition_Name}", ref pos, 1, 0, float.MaxValue, "%.0fpx")) - Plugin.ChatLogWindow.Position = pos; - ImGuiUtil.WarningText(Language.Options_AdjustPosition_Warning); - ImGui.Spacing(); - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - DrawAutoTellTabsSection(); - } - - if (!Mutable.OverrideStyle) - return; - - var styles = StyleModel.GetConfiguredStyles(); - if (styles == null) - { - ImGui.TextUnformatted(Language.Options_OverrideStyle_NotAvailable); - ImGui.Spacing(); - return; - } - - var currentStyle = Mutable.ChosenStyle ?? Language.Options_OverrideStyle_NotSelected; - using var combo = ImRaii.Combo(Language.Options_OverrideStyleDropdown_Name, currentStyle); - if (combo) - { - foreach (var style in styles) - if (ImGui.Selectable(style.Name, Mutable.ChosenStyle == style.Name)) - Mutable.ChosenStyle = style.Name; - } - - ImGui.Spacing(); - } - - private void DrawAutoTellTabsSection() - { - using var tree = ImRaii.TreeNode(HellionStrings.ChatLog_AutoTellTabs_Section_Title); - if (!tree.Success) - return; - - using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) - { - ImGui.Checkbox(HellionStrings.ChatLog_AutoTellTabs_Enable_Name, ref Mutable.EnableAutoTellTabs); - ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_Enable_Description); - - ImGui.SetNextItemWidth(200f * ImGuiHelpers.GlobalScale); - var limit = Mutable.AutoTellTabsLimit; - if (ImGui.SliderInt(HellionStrings.ChatLog_AutoTellTabs_Limit_Name, ref limit, 1, 50)) - { - Mutable.AutoTellTabsLimit = limit; - } - ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_Limit_Description); - - ImGui.Checkbox(HellionStrings.ChatLog_AutoTellTabs_Compact_Name, ref Mutable.AutoTellTabsCompactDisplay); - ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_Compact_Description); - - ImGui.Checkbox(HellionStrings.ChatLog_AutoTellTabs_GreetedToggle_Name, ref Mutable.AutoTellTabsShowGreetedToggle); - ImGuiUtil.HelpMarker(HellionStrings.ChatLog_AutoTellTabs_GreetedToggle_Description); - - ImGui.Spacing(); - ImGuiUtil.HelpText(HellionStrings.ChatLog_AutoTellTabs_PreloadHint); - - ImGui.Spacing(); - ImGuiUtil.WarningText(HellionStrings.ChatLog_AutoTellTabs_ConflictHint); - } - } -} diff --git a/ChatTwo/Ui/SettingsTabs/Display.cs b/ChatTwo/Ui/SettingsTabs/Display.cs deleted file mode 100755 index 1f2ec64..0000000 --- a/ChatTwo/Ui/SettingsTabs/Display.cs +++ /dev/null @@ -1,116 +0,0 @@ -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class Display : ISettingsTab -{ - private Configuration Mutable { get; } - - public string Name => Language.Options_Display_Tab + "###tabs-display"; - - internal Display(Configuration mutable) - { - Mutable = mutable; - } - - public void Draw(bool changed) - { - using var wrap = ImRaii.TextWrapPos(0.0f); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideChat, Language.Options_HideChat_Name, Language.Options_HideChat_Description); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideDuringCutscenes, Language.Options_HideDuringCutscenes_Name, string.Format(Language.Options_HideDuringCutscenes_Description, Plugin.PluginName)); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenNotLoggedIn, Language.Options_HideWhenNotLoggedIn_Name, string.Format(Language.Options_HideWhenNotLoggedIn_Description, Plugin.PluginName)); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenUiHidden, Language.Options_HideWhenUiHidden_Name, string.Format(Language.Options_HideWhenUiHidden_Description, Plugin.PluginName)); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideInLoadingScreens, Language.Options_HideInLoadingScreens_Name, string.Format(Language.Options_HideInLoadingScreens_Description, Plugin.PluginName)); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideInBattle, Language.Options_HideInBattle_Name, Language.Options_HideInBattle_Description); - ImGui.Spacing(); - - ImGui.Separator(); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenInactive, Language.Options_HideWhenInactive_Name, Language.Options_HideWhenInactive_Description); - ImGui.Spacing(); - - if (Mutable.HideWhenInactive) - { - using var _ = ImRaii.PushIndent(); - ImGuiUtil.InputIntVertical(Language.Options_InactivityHideTimeout_Name, - Language.Options_InactivityHideTimeout_Description, ref Mutable.InactivityHideTimeout, 1, 10); - // Enforce a minimum of 2 seconds to avoid people soft locking - // themselves. - Mutable.InactivityHideTimeout = Math.Max(2, Mutable.InactivityHideTimeout); - ImGui.Spacing(); - - // This setting conflicts with HideInBattle, so it's disabled. - using (ImRaii.Disabled(Mutable.HideInBattle)) - { - ImGuiUtil.OptionCheckbox(ref Mutable.InactivityHideActiveDuringBattle, - Language.Options_InactivityHideActiveDuringBattle_Name, - Language.Options_InactivityHideActiveDuringBattle_Description); - ImGui.Spacing(); - } - - using var channelTree = ImRaii.TreeNode(Language.Options_InactivityHideChannels_Name); - if (channelTree.Success) - { - if (ImGuiUtil.CtrlShiftButton(Language.Options_InactivityHideChannels_All_Label, Language.Options_InactivityHideChannels_Button_Tooltip)) - { - Mutable.InactivityHideChannelsV2 = TabsUtil.AllChannels(); - Mutable.InactivityHideExtraChatAll = true; - Mutable.InactivityHideExtraChatChannels = []; - } - - ImGui.SameLine(); - if (ImGuiUtil.CtrlShiftButton(Language.Options_InactivityHideChannels_None_Label, Language.Options_InactivityHideChannels_Button_Tooltip)) - { - Mutable.InactivityHideChannelsV2 = []; - Mutable.InactivityHideExtraChatAll = false; - Mutable.InactivityHideExtraChatChannels = []; - } - - ImGui.Spacing(); - - ImGuiUtil.ChannelSelector(Language.Options_Tabs_Channels, Mutable.InactivityHideChannelsV2); - ImGuiUtil.ExtraChatSelector(Language.Options_Tabs_ExtraChatChannels, - ref Mutable.InactivityHideExtraChatAll, Mutable.InactivityHideExtraChatChannels); - } - ImGui.Spacing(); - } - - ImGui.Separator(); - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.Use24HourClock, Language.Options_Use24HourClock_Name, Language.Options_Use24HourClock_Description); - - ImGuiUtil.OptionCheckbox(ref Mutable.PrettierTimestamps, Language.Options_PrettierTimestamps_Name, Language.Options_PrettierTimestamps_Description); - - if (Mutable.PrettierTimestamps) - { - using var _ = ImRaii.PushIndent(); - ImGuiUtil.OptionCheckbox(ref Mutable.MoreCompactPretty, Language.Options_MoreCompactPretty_Name, Language.Options_MoreCompactPretty_Description); - ImGuiUtil.OptionCheckbox(ref Mutable.HideSameTimestamps, Language.Options_HideSameTimestamps_Name, Language.Options_HideSameTimestamps_Description); - } - ImGui.Spacing(); - - ImGuiUtil.OptionCheckbox(ref Mutable.CollapseDuplicateMessages, Language.Options_CollapseDuplicateMessages_Name, Language.Options_CollapseDuplicateMessages_Description); - if (Mutable.CollapseDuplicateMessages) - { - using var _ = ImRaii.PushIndent(); - ImGuiUtil.OptionCheckbox(ref Mutable.CollapseKeepUniqueLinks, Language.Options_CollapseDuplicateMsgUniqueLink_Name, Language.Options_CollapseDuplicateMsgUniqueLink_Description); - } - ImGui.Spacing(); - } -} diff --git a/ChatTwo/Ui/SettingsTabs/Emote.cs b/ChatTwo/Ui/SettingsTabs/Emote.cs deleted file mode 100644 index 64f2411..0000000 --- a/ChatTwo/Ui/SettingsTabs/Emote.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System.Numerics; -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Interface; -using Dalamud.Interface.Colors; -using Dalamud.Interface.Utility.Raii; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class Emote : ISettingsTab -{ - private readonly Plugin Plugin; - private Configuration Mutable { get; } - - public string Name => Language.Options_Emote_Tab + "###tabs-emote"; - - private static SearchSelector.SelectorPopupOptions? WordPopupOptions; - - internal Emote(Plugin plugin, Configuration mutable) - { - Plugin = plugin; - Mutable = mutable; - - WordPopupOptions = new SearchSelector.SelectorPopupOptions - { - FilteredSheet = EmoteCache.SortedCodeArray.Where(w => !Mutable.BlockedEmotes.Contains(w)).ToArray() - }; - } - - private SearchSelector.SelectorPopupOptions RefillSheet() - { - return new SearchSelector.SelectorPopupOptions - { - FilteredSheet = EmoteCache.SortedCodeArray.Where(w => !Mutable.BlockedEmotes.Contains(w)).ToArray() - }; - } - - public void Draw(bool changed) - { - using var wrap = ImRaii.TextWrapPos(0.0f); - - ImGuiUtil.OptionCheckbox(ref Mutable.ShowEmotes, Language.Options_ShowEmotes_Name, Language.Options_ShowEmotes_Desc); - ImGui.Spacing(); - - ImGui.TextUnformatted(Language.Options_Emote_BlockedEmotes); - ImGui.Spacing(); - - WordPopupOptions ??= RefillSheet(); - if (EmoteCache.State is EmoteCache.LoadingState.Done && WordPopupOptions.FilteredSheet.Length == 0) - WordPopupOptions = RefillSheet(); - - var buttonWidth = ImGui.GetContentRegionAvail().X / 3; - using (Plugin.FontManager.FontAwesome.Push()) - ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), new Vector2(buttonWidth, 0)); - - if (SearchSelector.SelectorPopup("WordAddPopup", out var newWord, WordPopupOptions)) - Mutable.BlockedEmotes.Add(newWord); - - using(var table = ImRaii.Table("##BlockedWords", 2, ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInner)) - { - if (table) - { - ImGui.TableSetupColumn(Language.Options_Emote_EmoteTable); - ImGui.TableSetupColumn("##Del", ImGuiTableColumnFlags.WidthStretch, 0.07f); - - ImGui.TableHeadersRow(); - - var copiedList = Mutable.BlockedEmotes.ToArray(); - foreach (var word in copiedList) - { - ImGui.TableNextColumn(); - ImGui.TextUnformatted(word); - - ImGui.TableNextColumn(); - if (ImGuiUtil.Button($"##{word}Del", FontAwesomeIcon.Trash, !ImGui.GetIO().KeyCtrl)) - Mutable.BlockedEmotes.Remove(word); - } - } - } - - ImGui.Spacing(); - ImGui.Separator(); - ImGui.Spacing(); - - ImGui.TextUnformatted(Language.Options_Emote_EmoteStats); - ImGui.Spacing(); - - if (EmoteCache.State is EmoteCache.LoadingState.Done) - ImGui.TextColored(ImGuiColors.HealerGreen, Language.Options_Emote_Ready); - else - ImGui.TextColored(ImGuiColors.DPSRed, Language.Options_Emote_NotReady); - - ImGui.TextUnformatted($"{Language.Options_Emote_Loaded} {EmoteCache.SortedCodeArray.Length}"); - using (var emoteTable = ImRaii.Table("##LoadedEmotes", 5, ImGuiTableFlags.RowBg | ImGuiTableFlags.BordersInner)) - { - if (emoteTable) - { - ImGui.TableSetupColumn("##word1"); - ImGui.TableSetupColumn("##word2"); - ImGui.TableSetupColumn("##word3"); - ImGui.TableSetupColumn("##word4"); - ImGui.TableSetupColumn("##word5"); - - foreach (var word in EmoteCache.SortedCodeArray) - { - ImGui.TableNextColumn(); - ImGui.TextUnformatted(word); - } - } - } - } -} diff --git a/ChatTwo/Ui/SettingsTabs/Fonts.cs b/ChatTwo/Ui/SettingsTabs/Fonts.cs deleted file mode 100755 index a55543a..0000000 --- a/ChatTwo/Ui/SettingsTabs/Fonts.cs +++ /dev/null @@ -1,97 +0,0 @@ -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud; -using Dalamud.Interface.FontIdentifier; -using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility.Raii; - -namespace ChatTwo.Ui.SettingsTabs; - -public class Fonts : ISettingsTab -{ - private Configuration Mutable { get; } - - public string Name => Language.Options_Fonts_Tab + "###tabs-fonts"; - - internal Fonts(Configuration mutable) - { - Mutable = mutable; - } - - public void Draw(bool _) - { - using var wrap = ImRaii.TextWrapPos(0.0f); - - ImGui.Checkbox(Language.Options_FontsEnabled, ref Mutable.FontsEnabled); - ImGui.Spacing(); - - if (!Mutable.FontsEnabled) - { - ImGuiUtil.FontSizeCombo(Language.Options_FontSize_Name, ref Mutable.FontSizeV2); - } - else - { - var globalChooser = ImGuiUtil.FontChooser(Language.Options_Font_Name, Mutable.GlobalFontV2, false, ref _); - globalChooser?.ResultTask.ContinueWith(r => - { - if (r.IsCompletedSuccessfully) - Mutable.GlobalFontV2 = r.Result; - }); - ImGui.SameLine(); - if (ImGui.Button("Reset##global")) - Mutable.GlobalFontV2 = new SingleFontSpec{ FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkRegular), SizePt = 12.75f }; - - ImGuiUtil.HelpText(string.Format(Language.Options_Font_Description, Plugin.PluginName)); - ImGuiUtil.WarningText(Language.Options_Font_Warning); - ImGui.Spacing(); - - // LocaleNames being null means it is likely a game font which all support JP symbols - var japaneseChooser = ImGuiUtil.FontChooser(Language.Options_JapaneseFont_Name, Mutable.JapaneseFontV2, false, ref _, id => !id.LocaleNames?.ContainsKey("ja-jp") ?? false, "いろはにほへと ちりぬるを"); - japaneseChooser?.ResultTask.ContinueWith(r => - { - if (r.IsCompletedSuccessfully) - Mutable.JapaneseFontV2 = r.Result; - }); - ImGui.SameLine(); - if (ImGui.Button("Reset##japanese")) - Mutable.JapaneseFontV2 = new SingleFontSpec{ FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkMedium), SizePt = 12.75f }; - - ImGuiUtil.HelpText(string.Format(Language.Options_JapaneseFont_Description, Plugin.PluginName)); - ImGui.Spacing(); - - var italicChooser = ImGuiUtil.FontChooser(Language.Options_ItalicFont_Name, Mutable.ItalicFontV2, true, ref Mutable.ItalicEnabled); - italicChooser?.ResultTask.ContinueWith(r => - { - if (r.IsCompletedSuccessfully) - Mutable.ItalicFontV2 = r.Result; - }); - ImGui.SameLine(); - if (ImGui.Button("Reset##italic")) - { - Mutable.ItalicEnabled = false; - Mutable.ItalicFontV2 = new SingleFontSpec{ FontId = new DalamudAssetFontAndFamilyId(DalamudAsset.NotoSansCjkRegular), SizePt = 12.75f }; - } - - ImGuiUtil.HelpText(string.Format(Language.Options_Italic_Description, Plugin.PluginName)); - ImGui.Spacing(); - - if (ImGui.CollapsingHeader(Language.Options_ExtraGlyphs_Name)) - { - ImGuiUtil.HelpText(string.Format(Language.Options_ExtraGlyphs_Description, Plugin.PluginName)); - - var range = (int) Mutable.ExtraGlyphRanges; - foreach (var extra in Enum.GetValues()) - ImGui.CheckboxFlags(extra.Name(), ref range, (int) extra); - - Mutable.ExtraGlyphRanges = (ExtraGlyphRanges) range; - } - - ImGui.Spacing(); - } - - ImGuiUtil.FontSizeCombo(Language.Options_SymbolsFontSize_Name, ref Mutable.SymbolsFontSizeV2); - ImGuiUtil.HelpText(Language.Options_SymbolsFontSize_Description); - - ImGui.Spacing(); - } -} diff --git a/ChatTwo/Ui/SettingsTabs/Miscellaneous.cs b/ChatTwo/Ui/SettingsTabs/Miscellaneous.cs deleted file mode 100755 index e802d5e..0000000 --- a/ChatTwo/Ui/SettingsTabs/Miscellaneous.cs +++ /dev/null @@ -1,62 +0,0 @@ -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Bindings.ImGui; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class Miscellaneous(Configuration mutable) : ISettingsTab -{ - private Configuration Mutable { get; } = mutable; - public string Name => Language.Options_Miscellaneous_Tab + "###tabs-miscellaneous"; - - public void Draw(bool changed) - { - using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_Language_Name, Mutable.LanguageOverride.Name())) - { - if (combo.Success) - { - foreach (var language in Enum.GetValues()) - if (ImGui.Selectable(language.Name())) - Mutable.LanguageOverride = language; - } - } - - ImGuiUtil.HelpText(string.Format(Language.Options_Language_Description, Plugin.PluginName)); - ImGui.Spacing(); - - using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_CommandHelpSide_Name, Mutable.CommandHelpSide.Name())) - { - if (combo.Success) - { - foreach (var side in Enum.GetValues()) - if (ImGui.Selectable(side.Name(), Mutable.CommandHelpSide == side)) - Mutable.CommandHelpSide = side; - } - } - - ImGuiUtil.HelpText(string.Format(Language.Options_CommandHelpSide_Description, Plugin.PluginName)); - ImGui.Spacing(); - - using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_KeybindMode_Name, Mutable.KeybindMode.Name())) - { - if (combo.Success) - { - foreach (var mode in Enum.GetValues()) - { - if (ImGui.Selectable(mode.Name(), Mutable.KeybindMode == mode)) - Mutable.KeybindMode = mode; - - if (ImGui.IsItemHovered()) - ImGuiUtil.Tooltip(mode.Tooltip() ?? ""); - } - } - } - - ImGuiUtil.HelpText(string.Format(Language.Options_KeybindMode_Description, Plugin.PluginName)); - ImGui.Spacing(); - - ImGui.Checkbox(Language.Options_SortAutoTranslate_Name, ref Mutable.SortAutoTranslate); - ImGuiUtil.HelpText(Language.Options_SortAutoTranslate_Description); - ImGui.Spacing(); - } -} diff --git a/ChatTwo/Ui/SettingsTabs/Preview.cs b/ChatTwo/Ui/SettingsTabs/Preview.cs deleted file mode 100644 index 8cc0119..0000000 --- a/ChatTwo/Ui/SettingsTabs/Preview.cs +++ /dev/null @@ -1,42 +0,0 @@ -using ChatTwo.Resources; -using ChatTwo.Util; -using Dalamud.Bindings.ImGui; -using Dalamud.Interface.Utility.Raii; - -namespace ChatTwo.Ui.SettingsTabs; - -internal sealed class Preview : ISettingsTab -{ - private Configuration Mutable { get; } - - public string Name => $"{Language.Options_Preview_Tab}###tabs-preview"; - - internal Preview(Configuration mutable) - { - Mutable = mutable; - } - - public void Draw(bool changed) - { - using var wrap = ImRaii.TextWrapPos(0.0f); - - using (var combo = ImGuiUtil.BeginComboVertical(Language.Options_Preview_Name, Mutable.PreviewPosition.Name())) - { - if (combo) - { - foreach (var position in Enum.GetValues()) - if (ImGui.Selectable(position.Name(), Mutable.PreviewPosition == position)) - Mutable.PreviewPosition = position; - } - } - ImGuiUtil.HelpText(Language.Options_Preview_Description); - ImGui.Spacing(); - - if (ImGuiUtil.InputIntVertical(Language.Options_PreviewMinimum_Name, Language.Options_PreviewMinimum_Description, ref Mutable.PreviewMinimum)) - Mutable.PreviewMinimum = Math.Clamp(Mutable.PreviewMinimum, 1, 250); - ImGui.Spacing(); - ImGuiUtil.OptionCheckbox(ref Mutable.OnlyPreviewIf, Language.Options_PreviewOnlyIf_Name, Language.Options_PreviewOnlyIf_Description); - - ImGui.Spacing(); - } -} From fde85e6d692832ab0b907027d0156e6fadb1622f Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 17:37:46 +0200 Subject: [PATCH 18/23] chore(release): bump version to 0.5.0 Settings UX polish release. Twelve organic settings tabs collapsed into eight themed ones, theme/font controls moved to Appearance, About and Changelog merged into Information. Configuration migrates from v9 to v10 as a wipe with a backup file written next to the live config; chat history and tabs survive. --- ChatTwo/ChatTwo.csproj | 2 +- ChatTwo/HellionChat.yaml | 33 +++++++++++++++++++++++++++++++++ repo.json | 12 ++++++------ 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/ChatTwo/ChatTwo.csproj b/ChatTwo/ChatTwo.csproj index d1d9dce..4a6c618 100755 --- a/ChatTwo/ChatTwo.csproj +++ b/ChatTwo/ChatTwo.csproj @@ -4,7 +4,7 @@ 0.1.0 is our bootstrap release; the underlying Chat 2 base is called out in the yaml changelog so users can see what it derives from. --> - 0.4.0 + 0.5.0 enable - - Auto-Tell-Tabs - - - Auto-Tell-Tabs sind ab Version 0.4.0 standardmäßig aktiv. Du kannst sie im Chat-Tab deaktivieren oder anpassen. - Aktive Tells diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index ab77c52..4fc908a 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -78,6 +78,9 @@ Cleanup uses your SAVED whitelist (Plugin.Config), not unsaved edits above. Click Save first if you want to apply your current edits. + + The manual sweep uses your SAVED retention policy, not the slider values above. Click Save first if you want the run to apply your current edits. + Refresh preview @@ -177,18 +180,6 @@ Retention sweep failed, see /xllog - - Hellion Chat - - - Privacy filter activated by default. Settings → Privacy to adjust. - - - Hellion Chat 0.2.0 - - - The webinterface has been removed in this version because it could not be hardened to the privacy guarantees Hellion Chat makes by default. If you used it, please consult the README for context. - Hellion Chat — Welcome @@ -276,9 +267,6 @@ Export failed, see /xllog - - Appearance - Use the Hellion theme across all plugin windows @@ -371,12 +359,6 @@ - - Auto-Tell-Tabs - - - Auto-Tell-Tabs are enabled by default starting with version 0.4.0. You can disable or fine-tune them in the Chat tab. - Active Tells diff --git a/ChatTwo/Ui/Settings.cs b/ChatTwo/Ui/Settings.cs index 619e958..cd7ddc7 100755 --- a/ChatTwo/Ui/Settings.cs +++ b/ChatTwo/Ui/Settings.cs @@ -110,14 +110,16 @@ public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window ImGui.SameLine(); - if (ImGui.Button(Language.Settings_SaveAndClose)) { + if (ImGui.Button(Language.Settings_SaveAndClose)) + { save = true; IsOpen = false; } ImGui.SameLine(); - if (ImGui.Button(Language.Settings_Discard)) { + if (ImGui.Button(Language.Settings_Discard)) + { IsOpen = false; } @@ -131,7 +133,7 @@ public sealed class SettingsWindow : Dalamud.Interface.Windowing.Window { var buttonWidth = ImGui.CalcTextSize(buttonLabel).X + ImGui.GetStyle().FramePadding.X * 2; var buttonWidth2 = ImGui.CalcTextSize(buttonLabel2).X + ImGui.GetStyle().FramePadding.X * 2; - ImGui.SameLine(ImGui.GetContentRegionAvail().X - buttonWidth - buttonWidth2); + ImGui.SameLine(ImGui.GetContentRegionAvail().X - buttonWidth - buttonWidth2 - ImGui.GetStyle().ItemSpacing.X); if (ImGui.Button(buttonLabel2)) Dalamud.Utility.Util.OpenLink("https://ko-fi.com/infiii"); diff --git a/ChatTwo/Ui/SettingsTabs/Privacy.cs b/ChatTwo/Ui/SettingsTabs/Privacy.cs index 8ec92f2..eb3bea3 100644 --- a/ChatTwo/Ui/SettingsTabs/Privacy.cs +++ b/ChatTwo/Ui/SettingsTabs/Privacy.cs @@ -403,6 +403,9 @@ internal sealed class Privacy : ISettingsTab ImGui.Spacing(); + ImGuiUtil.HelpText(HellionStrings.Retention_Help_SavedNote); + ImGui.Spacing(); + using (ImRaii.Disabled(RetentionRunning)) { if (ImGuiUtil.CtrlShiftButton(HellionStrings.Retention_Apply_Label, HellionStrings.Retention_Apply_Tooltip)) From 2201478a54fc6a5c553546f57db4e83b076c8a15 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 18:00:04 +0200 Subject: [PATCH 20/23] fix(v0.5.0): defaults and coupling issues from first walkthrough - Configuration.cs: ShowTitleBar defaults to true so a fresh install shows the window header instead of leaving the user without a drag handle and hide button - Configuration.cs: MaxLinesToRender default drops from 10000 to 5000 to match the slider's intended ceiling and the previous user-tuned baseline - ChatLogWindow.cs: 24h-clock checkbox now actually flips the format. The Bestand path passed null culture which on a German system locale always rendered 24h regardless of the toggle - Appearance.cs + ChatLogWindow.cs + Popout.cs: when Hellion theme is enabled the global theme opacity drives the chat-window BgAlpha and the legacy WindowAlpha slider is disabled, so the two opacity controls no longer fight each other - Appearance.cs: ticking UseHellionFont now flips FontsEnabled off so the two mutually-exclusive font stacks no longer appear active at the same time --- ChatTwo/Configuration.cs | 4 ++-- ChatTwo/Ui/ChatLogWindow.cs | 12 ++++++++++-- ChatTwo/Ui/Popout.cs | 12 ++++++++++-- ChatTwo/Ui/SettingsTabs/Appearance.cs | 24 ++++++++++++++++++------ 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index 58102e5..80aec68 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -147,7 +147,7 @@ public class Configuration : IPluginConfiguration public LanguageOverride LanguageOverride = LanguageOverride.None; public bool CanMove = true; public bool CanResize = true; - public bool ShowTitleBar; + public bool ShowTitleBar = true; public bool ShowPopOutTitleBar = true; public bool DatabaseBattleMessages; public bool LoadPreviousSession; @@ -157,7 +157,7 @@ public class Configuration : IPluginConfiguration public bool CollapseKeepUniqueLinks; public bool PlaySounds = true; public bool KeepInputFocus = true; - public int MaxLinesToRender = 10_000; // 1-10000 + public int MaxLinesToRender = 5_000; // 1-10000 public bool Use24HourClock; public bool ShowEmotes = true; diff --git a/ChatTwo/Ui/ChatLogWindow.cs b/ChatTwo/Ui/ChatLogWindow.cs index 0ba15f6..1e60ba8 100644 --- a/ChatTwo/Ui/ChatLogWindow.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -451,7 +451,9 @@ public sealed class ChatLogWindow : Window Flags |= ImGuiWindowFlags.NoTitleBar; if (LastViewport == ImGuiHelpers.MainViewport.Handle && !WasDocked) - BgAlpha = Plugin.Config.WindowAlpha / 100f; + BgAlpha = Plugin.Config.HellionThemeEnabled + ? Plugin.Config.HellionThemeWindowOpacity + : Plugin.Config.WindowAlpha / 100f; LastViewport = ImGui.GetWindowViewport().Handle; WasDocked = ImGui.IsWindowDocked(); @@ -1188,7 +1190,13 @@ public sealed class ChatLogWindow : Window if (tab.DisplayTimestamp) { var localTime = message.Date.ToLocalTime(); - var timestamp = localTime.ToString("t", !Plugin.Config.Use24HourClock ? null : CultureInfo.CreateSpecificCulture("de-DE")); + // Force the format explicitly per setting. Relying on the + // current culture meant a German system locale always + // produced 24h regardless of the toggle, so the checkbox + // looked dead. + var timestamp = Plugin.Config.Use24HourClock + ? localTime.ToString("HH:mm", CultureInfo.InvariantCulture) + : localTime.ToString("h:mm tt", CultureInfo.InvariantCulture); if (isTable) { if (!Plugin.Config.HideSameTimestamps || timestamp != lastTimestamp) diff --git a/ChatTwo/Ui/Popout.cs b/ChatTwo/Ui/Popout.cs index 8871d54..c3f85ab 100644 --- a/ChatTwo/Ui/Popout.cs +++ b/ChatTwo/Ui/Popout.cs @@ -70,8 +70,16 @@ internal class Popout : Window if (!ChatLogWindow.PopOutDocked[Idx]) { - var alpha = Tab.IndependentOpacity ? Tab.Opacity : Plugin.Config.WindowAlpha; - BgAlpha = alpha / 100f; + if (Tab.IndependentOpacity) + { + BgAlpha = Tab.Opacity / 100f; + } + else + { + BgAlpha = Plugin.Config.HellionThemeEnabled + ? Plugin.Config.HellionThemeWindowOpacity + : Plugin.Config.WindowAlpha / 100f; + } } } diff --git a/ChatTwo/Ui/SettingsTabs/Appearance.cs b/ChatTwo/Ui/SettingsTabs/Appearance.cs index def4cd4..e15e10b 100644 --- a/ChatTwo/Ui/SettingsTabs/Appearance.cs +++ b/ChatTwo/Ui/SettingsTabs/Appearance.cs @@ -72,7 +72,15 @@ internal sealed class Appearance : ISettingsTab DrawStyleCombo(); } - ImGuiUtil.DragFloatVertical(Language.Options_WindowOpacity_Name, ref Mutable.WindowAlpha, .25f, 0f, 100f, $"{Mutable.WindowAlpha:N2}%%", ImGuiSliderFlags.AlwaysClamp); + // The Bestand-Slider WindowAlpha targets the chat log window's + // background only. The Hellion theme opacity above already covers + // every plugin window globally, so the two sliders fight each + // other when the theme is active. Disable the legacy slider in + // that case to make Hellion theme the single source of truth. + using (ImRaii.Disabled(Mutable.HellionThemeEnabled)) + { + ImGuiUtil.DragFloatVertical(Language.Options_WindowOpacity_Name, ref Mutable.WindowAlpha, .25f, 0f, 100f, $"{Mutable.WindowAlpha:N2}%%", ImGuiSliderFlags.AlwaysClamp); + } } } @@ -111,14 +119,18 @@ internal sealed class Appearance : ISettingsTab using (ImRaii.PushIndent(ImGui.GetStyle().IndentSpacing, false)) { - ImGui.Checkbox(HellionStrings.Theme_UseHellionFont_Name, ref Mutable.UseHellionFont); + if (ImGui.Checkbox(HellionStrings.Theme_UseHellionFont_Name, ref Mutable.UseHellionFont)) + { + // Mutex with the Bestand custom-font stack. Leaving FontsEnabled + // checked alongside UseHellionFont made both checkboxes look + // active even though the lower stack was greyed out, which + // confused the user during the v0.5.0 walkthrough. + if (Mutable.UseHellionFont) + Mutable.FontsEnabled = false; + } ImGuiUtil.HelpMarker(HellionStrings.Theme_UseHellionFont_Description); ImGui.Spacing(); - // Hellion-Font und der Custom-Font-Stack schließen sich aus: - // wenn Exo 2 erzwungen wird, sind die ChatTwo-Font-Picker - // ohne Wirkung, also UI-seitig ausgrauen statt versteckt - // weiterzuwerken. using var fontDisabled = ImRaii.Disabled(Mutable.UseHellionFont); ImGui.Checkbox(Language.Options_FontsEnabled, ref Mutable.FontsEnabled); From e1931fc7d22d76813a77f5ff3e7f652d68d63b5d Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 18:13:15 +0200 Subject: [PATCH 21/23] feat(tabs): seed default tab layout on first run and v10 wipe Spawn six themed tabs out of the box instead of one General catch-all: General (everything), Free Company (FC chat plus FC announcements and login/logout), Party (Party, CrossParty, Alliance, PvP team plus loot rolls), Beginner (Novice Network only when ShowNoviceNetwork is on), Linkshell (all eight regular and cross-world linkshells together) and Tell Exclusive (TellIncoming/TellOutgoing as a safety-net catch-all in case Auto-Tell-Tabs misses one). Tab names live in HellionStrings (EN/DE). The Tabs settings tab gains a help-text hint above the list recommending one tab per linkshell when the user is in multiple, since a single combined Linkshell tab gets noisy fast for active users. --- ChatTwo/Plugin.cs | 11 ++++ ChatTwo/Resources/HellionStrings.Designer.cs | 7 ++ ChatTwo/Resources/HellionStrings.de.resx | 17 +++++ ChatTwo/Resources/HellionStrings.resx | 17 +++++ ChatTwo/Ui/SettingsTabs/Tabs.cs | 3 + ChatTwo/Util/TabsUtil.cs | 69 ++++++++++++++++++++ 6 files changed, 124 insertions(+) diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index 2711217..b5adad9 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -152,9 +152,20 @@ public sealed class Plugin : IDalamudPlugin }); } + // Hellion default tab layout for first-run and v10-wipe. + // General-catch-all + FC + Party + Linkshell + Tells matches the + // channel set the average raider uses; the Beginner tab only + // appears when the user has the Novice Network enabled in Audio + // & Notifications, otherwise it would just sit empty. if (Config.Tabs.Count == 0) { Config.Tabs.Add(TabsUtil.VanillaGeneral); + Config.Tabs.Add(TabsUtil.HellionFreeCompany); + Config.Tabs.Add(TabsUtil.HellionParty); + if (Config.ShowNoviceNetwork) + Config.Tabs.Add(TabsUtil.HellionBeginner); + Config.Tabs.Add(TabsUtil.HellionLinkshell); + Config.Tabs.Add(TabsUtil.VanillaTellExclusive); } LanguageChanged(Interface.UiLanguage); diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index 6035db8..538883a 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -231,4 +231,11 @@ internal class HellionStrings internal static string Settings_Information_VersionInfo_Heading => Get(nameof(Settings_Information_VersionInfo_Heading)); internal static string Settings_Information_About_Heading => Get(nameof(Settings_Information_About_Heading)); internal static string Settings_Information_Changelog_Heading => Get(nameof(Settings_Information_Changelog_Heading)); + + // Hellion Chat — Default tab presets (channel-themed) + internal static string Tabs_Presets_FreeCompany => Get(nameof(Tabs_Presets_FreeCompany)); + internal static string Tabs_Presets_Party => Get(nameof(Tabs_Presets_Party)); + internal static string Tabs_Presets_Beginner => Get(nameof(Tabs_Presets_Beginner)); + internal static string Tabs_Presets_Linkshell => Get(nameof(Tabs_Presets_Linkshell)); + internal static string Tabs_Presets_Linkshell_Hint => Get(nameof(Tabs_Presets_Linkshell_Hint)); } diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 0ca1dbf..2aa6ac9 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -526,4 +526,21 @@ Changelog + + + + Free Company + + + Gruppe + + + Neulinge + + + Linkshell + + + Wenn du mehrere Linkshells benutzt, empfiehlt der Maintainer einen Tab pro Shell für eine sauberere Übersicht. Tab duplizieren und je Kopie die Kanalauswahl einschränken. + diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 4fc908a..8fa8abd 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -526,4 +526,21 @@ Changelog + + + + Free Company + + + Party + + + Beginner + + + Linkshell + + + If you use multiple linkshells, the maintainer recommends one tab per shell for cleaner readability. Duplicate this tab and narrow the channel selection per copy. + diff --git a/ChatTwo/Ui/SettingsTabs/Tabs.cs b/ChatTwo/Ui/SettingsTabs/Tabs.cs index 5c84c8e..518644f 100755 --- a/ChatTwo/Ui/SettingsTabs/Tabs.cs +++ b/ChatTwo/Ui/SettingsTabs/Tabs.cs @@ -27,6 +27,9 @@ internal sealed class Tabs : ISettingsTab { const string addTabPopup = "add-tab-popup"; + ImGuiUtil.HelpText(HellionStrings.Tabs_Presets_Linkshell_Hint); + ImGui.Spacing(); + if (ImGuiUtil.IconButton(FontAwesomeIcon.Plus, tooltip: Language.Options_Tabs_Add)) ImGui.OpenPopup(addTabPopup); diff --git a/ChatTwo/Util/TabsUtil.cs b/ChatTwo/Util/TabsUtil.cs index 984d168..47d10ed 100755 --- a/ChatTwo/Util/TabsUtil.cs +++ b/ChatTwo/Util/TabsUtil.cs @@ -98,6 +98,75 @@ public static class TabsUtil AllSenderMessages = true, }; + // Hellion default-tab presets used by the v10 wipe migration. Names are + // kept in HellionStrings (EN+DE) instead of Language.* so the upstream + // resource files stay untouched. Channel selections cover the channels + // a typical Eorzea raider uses without forcing the user to hand-tick + // each box on first start. + public static Tab HellionFreeCompany => new() + { + Name = HellionStrings.Tabs_Presets_FreeCompany, + SelectedChannels = new Dictionary + { + [ChatType.FreeCompany] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), + }, + Channel = InputChannel.FreeCompany, + }; + + public static Tab HellionParty => new() + { + Name = HellionStrings.Tabs_Presets_Party, + SelectedChannels = new Dictionary + { + [ChatType.Party] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossParty] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Alliance] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.PvpTeam] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All), + }, + Channel = InputChannel.Party, + }; + + public static Tab HellionBeginner => new() + { + Name = HellionStrings.Tabs_Presets_Beginner, + SelectedChannels = new Dictionary + { + [ChatType.NoviceNetwork] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All), + }, + Channel = InputChannel.NoviceNetwork, + }; + + public static Tab HellionLinkshell => new() + { + Name = HellionStrings.Tabs_Presets_Linkshell, + SelectedChannels = new Dictionary + { + [ChatType.Linkshell1] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell2] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell3] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell4] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell5] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell1] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell2] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell3] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell4] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell5] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell6] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell7] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.CrossLinkshell8] = (ChatSourceExt.All, ChatSourceExt.All), + }, + }; + public static Dictionary MostlyPlayer => new() { // Special From 45a50354260290ff7453cd33d5650b93fd87fe28 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 18:25:59 +0200 Subject: [PATCH 22/23] refactor(tabs): align General preset with maintainer's live config Drop the channels that already live in dedicated themed tabs (Tells, emotes, Novice Network, FC and PvP announcements, Sign and Glamour notifications) so the General tab is the public-chat catch-all instead of a duplicate of every themed tab. NpcDialogue moves in because the maintainer reads it alongside system messages. --- ChatTwo/Util/TabsUtil.cs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/ChatTwo/Util/TabsUtil.cs b/ChatTwo/Util/TabsUtil.cs index 47d10ed..776d3f0 100755 --- a/ChatTwo/Util/TabsUtil.cs +++ b/ChatTwo/Util/TabsUtil.cs @@ -14,6 +14,12 @@ public static class TabsUtil return channels; } + // Hellion-tuned General preset. Differs from upstream Vanilla: + // Tells (own tab), emotes, novice network and the FC/PvP announcement + // streams move into their dedicated themed tabs so the General tab + // is the public-chat catch-all that the maintainer actually runs in + // production. NpcDialogue stays here because the user reads it + // alongside system messages instead of in a separate Event tab. public static Tab VanillaGeneral => new() { Name = Language.Tabs_Presets_General, @@ -27,8 +33,6 @@ public static class TabsUtil [ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Yell] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Shout] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.TellIncoming] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.TellOutgoing] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Party] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.CrossParty] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Alliance] = (ChatSourceExt.All, ChatSourceExt.All), @@ -50,33 +54,25 @@ public static class TabsUtil [ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.NoviceNetwork] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.StandardEmote] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.CustomEmote] = (ChatSourceExt.All, ChatSourceExt.All), // Announcements [ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.GatheringSystem] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.FreeCompanyAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.PvpTeamAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Crafting] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Gathering] = (ChatSource.LocalPlayer, ChatSource.LocalPlayer), [ChatType.PeriodicRecruitmentNotification] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Sign] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.GlamourNotifications] = (ChatSourceExt.All, ChatSourceExt.All), } }; From 281a1e172f6a7824a0ac9f162c7ff4bc7cb9c281 Mon Sep 17 00:00:00 2001 From: JonKazama-Hellion Date: Sat, 2 May 2026 18:28:29 +0200 Subject: [PATCH 23/23] feat(tabs): add dedicated System tab to default layout Split the technical/notification streams (System, Error, Echo, Debug, NPC announcements, login/logout, retainer sales, gathering system, glamour notifications, sign messages, alarms, orchestrion, message book, random number, progress) out of the General tab into their own System tab. General now shows player conversation plus the active gameplay events (loot rolls, crafting, gathering, NPC dialogue, party finder pings) without burying chat under technical chatter. --- ChatTwo/Plugin.cs | 10 ++-- ChatTwo/Resources/HellionStrings.Designer.cs | 1 + ChatTwo/Resources/HellionStrings.de.resx | 3 + ChatTwo/Resources/HellionStrings.resx | 3 + ChatTwo/Util/TabsUtil.cs | 58 ++++++++++++-------- 5 files changed, 47 insertions(+), 28 deletions(-) diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index b5adad9..fc45fc1 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -153,13 +153,15 @@ public sealed class Plugin : IDalamudPlugin } // Hellion default tab layout for first-run and v10-wipe. - // General-catch-all + FC + Party + Linkshell + Tells matches the - // channel set the average raider uses; the Beginner tab only - // appears when the user has the Novice Network enabled in Audio - // & Notifications, otherwise it would just sit empty. + // General catches player chat plus active gameplay events; the + // System tab takes the technical noise so it does not bury real + // conversation. Beginner tab only appears when the Novice + // Network is enabled in Audio and Notifications, otherwise it + // would just sit empty. if (Config.Tabs.Count == 0) { Config.Tabs.Add(TabsUtil.VanillaGeneral); + Config.Tabs.Add(TabsUtil.HellionSystem); Config.Tabs.Add(TabsUtil.HellionFreeCompany); Config.Tabs.Add(TabsUtil.HellionParty); if (Config.ShowNoviceNetwork) diff --git a/ChatTwo/Resources/HellionStrings.Designer.cs b/ChatTwo/Resources/HellionStrings.Designer.cs index 538883a..c4dd719 100644 --- a/ChatTwo/Resources/HellionStrings.Designer.cs +++ b/ChatTwo/Resources/HellionStrings.Designer.cs @@ -233,6 +233,7 @@ internal class HellionStrings internal static string Settings_Information_Changelog_Heading => Get(nameof(Settings_Information_Changelog_Heading)); // Hellion Chat — Default tab presets (channel-themed) + internal static string Tabs_Presets_System => Get(nameof(Tabs_Presets_System)); internal static string Tabs_Presets_FreeCompany => Get(nameof(Tabs_Presets_FreeCompany)); internal static string Tabs_Presets_Party => Get(nameof(Tabs_Presets_Party)); internal static string Tabs_Presets_Beginner => Get(nameof(Tabs_Presets_Beginner)); diff --git a/ChatTwo/Resources/HellionStrings.de.resx b/ChatTwo/Resources/HellionStrings.de.resx index 2aa6ac9..1f9b7f4 100644 --- a/ChatTwo/Resources/HellionStrings.de.resx +++ b/ChatTwo/Resources/HellionStrings.de.resx @@ -528,6 +528,9 @@ + + System + Free Company diff --git a/ChatTwo/Resources/HellionStrings.resx b/ChatTwo/Resources/HellionStrings.resx index 8fa8abd..519f010 100644 --- a/ChatTwo/Resources/HellionStrings.resx +++ b/ChatTwo/Resources/HellionStrings.resx @@ -528,6 +528,9 @@ + + System + Free Company diff --git a/ChatTwo/Util/TabsUtil.cs b/ChatTwo/Util/TabsUtil.cs index 776d3f0..b143a5c 100755 --- a/ChatTwo/Util/TabsUtil.cs +++ b/ChatTwo/Util/TabsUtil.cs @@ -14,22 +14,17 @@ public static class TabsUtil return channels; } - // Hellion-tuned General preset. Differs from upstream Vanilla: - // Tells (own tab), emotes, novice network and the FC/PvP announcement - // streams move into their dedicated themed tabs so the General tab - // is the public-chat catch-all that the maintainer actually runs in - // production. NpcDialogue stays here because the user reads it - // alongside system messages instead of in a separate Event tab. + // Hellion-tuned General preset. The pure player-talk catch-all plus + // the active-gameplay event streams (loot, crafting, gathering, NPC + // dialogue, party-finder pings). Pure technical noise (System, Error, + // Login/Logout spam, retainer sales, alarms, sign messages) lives in + // the dedicated System tab so it doesn't bury actual conversation. public static Tab VanillaGeneral => new() { Name = Language.Tabs_Presets_General, SelectedChannels = new Dictionary { - // Special - [ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Notice] = (ChatSourceExt.All, ChatSourceExt.All), - // Chat + // Player chat [ChatType.Say] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Yell] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Shout] = (ChatSourceExt.All, ChatSourceExt.All), @@ -54,25 +49,13 @@ public static class TabsUtil [ChatType.Linkshell6] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Linkshell7] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Linkshell8] = (ChatSourceExt.All, ChatSourceExt.All), - // Announcements - [ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), + // Active-gameplay events [ChatType.NpcDialogue] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.LootNotice] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.LootRoll] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Crafting] = (ChatSourceExt.All, ChatSourceExt.All), [ChatType.Gathering] = (ChatSource.LocalPlayer, ChatSource.LocalPlayer), [ChatType.PeriodicRecruitmentNotification] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All), - [ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All), } }; @@ -139,6 +122,33 @@ public static class TabsUtil Channel = InputChannel.NoviceNetwork, }; + public static Tab HellionSystem => new() + { + Name = HellionStrings.Tabs_Presets_System, + SelectedChannels = new Dictionary + { + [ChatType.Debug] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Urgent] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Notice] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.System] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Error] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Echo] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.GatheringSystem] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.NoviceNetworkSystem] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.NpcAnnouncement] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.FreeCompanyLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.PvpTeamLoginLogout] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.RetainerSale] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Progress] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.RandomNumber] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Orchestrion] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.MessageBook] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Alarm] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.Sign] = (ChatSourceExt.All, ChatSourceExt.All), + [ChatType.GlamourNotifications] = (ChatSourceExt.All, ChatSourceExt.All), + }, + }; + public static Tab HellionLinkshell => new() { Name = HellionStrings.Tabs_Presets_Linkshell,