diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index acd0218..95f20ec 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -5,7 +5,7 @@ namespace ChatTwo; [Serializable] internal class Configuration : IPluginConfiguration { - public int Version { get; set; } = 1; + public int Version { get; set; } = 2; public bool HideChat = true; public bool HideDuringCutscenes = true; @@ -36,13 +36,45 @@ internal class Configuration : IPluginConfiguration { this.ChatColours = other.ChatColours.ToDictionary(entry => entry.Key, entry => entry.Value); this.Tabs = other.Tabs.Select(t => t.Clone()).ToList(); } + + public void Migrate() { + if (this.Version == 1) { + this.Version = 2; + + foreach (var tab in this.Tabs) { + #pragma warning disable CS0618 + tab.UnreadMode = tab.DisplayUnread ? UnreadMode.Unseen : UnreadMode.None; + #pragma warning restore CS0618 + } + } + } +} + +[Serializable] +internal enum UnreadMode { + All, + Unseen, + None, +} + +internal static class UnreadModeExt { + internal static string? Tooltip(this UnreadMode mode) => mode switch { + UnreadMode.All => "Always show unread indicators.", + UnreadMode.Unseen => "Only show unread indicators for messages you haven't seen.", + UnreadMode.None => "Never show unread indicators.", + _ => null, + }; } [Serializable] internal class Tab { public string Name = "New tab"; public Dictionary ChatCodes = new(); + + [Obsolete("Use UnreadMode instead")] public bool DisplayUnread = true; + + public UnreadMode UnreadMode = UnreadMode.Unseen; public bool DisplayTimestamp = true; public InputChannel? Channel; @@ -87,7 +119,10 @@ internal class Tab { return new Tab { Name = this.Name, ChatCodes = this.ChatCodes.ToDictionary(entry => entry.Key, entry => entry.Value), + #pragma warning disable CS0618 DisplayUnread = this.DisplayUnread, + #pragma warning restore CS0618 + UnreadMode = this.UnreadMode, DisplayTimestamp = this.DisplayTimestamp, Channel = this.Channel, }; diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index 65ccce4..b096d4b 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -66,6 +66,7 @@ public sealed class Plugin : IDalamudPlugin { #pragma warning disable CS8618 public Plugin() { this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration(); + this.Config.Migrate(); this.Common = new XivCommonBase(); this.TextureCache = new TextureCache(this.DataManager!); this.Functions = new GameFunctions.GameFunctions(this); diff --git a/ChatTwo/PluginUi.cs b/ChatTwo/PluginUi.cs index 35d0562..5e29df5 100755 --- a/ChatTwo/PluginUi.cs +++ b/ChatTwo/PluginUi.cs @@ -18,6 +18,17 @@ internal sealed class PluginUi : IDisposable { internal ImFontPtr? ItalicFont { get; private set; } internal Vector4 DefaultText { get; private set; } + internal Tab? CurrentTab { + get { + var i = this._chatLog.LastTab; + if (i > -1 && i < this.Plugin.Config.Tabs.Count) { + return this.Plugin.Config.Tabs[i]; + } + + return null; + } + } + private List Components { get; } private ImFontConfigPtr _fontCfg; private ImFontConfigPtr _fontCfgMerge; @@ -42,12 +53,16 @@ internal sealed class PluginUi : IDisposable { GCHandleType.Pinned ); + private readonly ChatLog _chatLog; + internal unsafe PluginUi(Plugin plugin) { this.Plugin = plugin; this.Salt = new Random().Next().ToString(); + + this._chatLog = new ChatLog(this); this.Components = new List { new Settings(this), - new ChatLog(this), + this._chatLog, }; this._fontCfg = new ImFontConfigPtr(ImGuiNative.ImFontConfig_ImFontConfig()) { diff --git a/ChatTwo/Store.cs b/ChatTwo/Store.cs index 0d74d6b..b924ab4 100755 --- a/ChatTwo/Store.cs +++ b/ChatTwo/Store.cs @@ -62,7 +62,7 @@ internal class Store : IDisposable { return new MessagesLock(this.Messages, this.MessagesMutex); } - internal void AddMessage(Message message) { + internal void AddMessage(Message message, Tab? currentTab) { using var messages = this.GetMessages(); messages.Messages.Add(message); @@ -70,9 +70,13 @@ internal class Store : IDisposable { messages.Messages.RemoveAt(0); } + var currentMatches = currentTab?.Matches(message) ?? false; + foreach (var tab in this.Plugin.Config.Tabs) { + var unread = !(tab.UnreadMode == UnreadMode.Unseen && currentTab != tab && currentMatches); + if (tab.Matches(message)) { - tab.AddMessage(message); + tab.AddMessage(message, unread); } } } @@ -114,7 +118,7 @@ internal class Store : IDisposable { var messageChunks = ChunkUtil.ToChunks(message, chatCode.Type).ToList(); var msg = new Message(chatCode, senderChunks, messageChunks); - this.AddMessage(msg); + this.AddMessage(msg, this.Plugin.Ui.CurrentTab); var idx = this.Plugin.Functions.GetCurrentChatLogEntryIndex(); if (idx != null) { diff --git a/ChatTwo/Ui/ChatLog.cs b/ChatTwo/Ui/ChatLog.cs index ce44530..1b40425 100755 --- a/ChatTwo/Ui/ChatLog.cs +++ b/ChatTwo/Ui/ChatLog.cs @@ -26,7 +26,7 @@ internal sealed class ChatLog : IUiComponent { private readonly TextureWrap? _fontIcon; private readonly List _inputBacklog = new(); private int _inputBacklogIdx = -1; - private int _lastTab; + internal int LastTab { get; private set; } private InputChannel? _tempChannel; private TellTarget? _tellTarget; private Vector2 _lastWindowSize = Vector2.Zero; @@ -137,8 +137,8 @@ internal sealed class ChatLog : IUiComponent { break; default: - if (this._lastTab > -1 && this._lastTab < this.Ui.Plugin.Config.Tabs.Count) { - this.Ui.Plugin.Config.Tabs[this._lastTab].Clear(); + if (this.LastTab > -1 && this.LastTab < this.Ui.Plugin.Config.Tabs.Count) { + this.Ui.Plugin.Config.Tabs[this.LastTab].Clear(); } break; @@ -645,7 +645,7 @@ internal sealed class ChatLog : IUiComponent { for (var tabI = 0; tabI < this.Ui.Plugin.Config.Tabs.Count; tabI++) { var tab = this.Ui.Plugin.Config.Tabs[tabI]; - var unread = tabI == this._lastTab || !tab.DisplayUnread || tab.Unread == 0 ? "" : $" ({tab.Unread})"; + var unread = tabI == this.LastTab || tab.UnreadMode == UnreadMode.None || tab.Unread == 0 ? "" : $" ({tab.Unread})"; var draw = ImGui.BeginTabItem($"{tab.Name}{unread}###log-tab-{tabI}"); this.DrawTabContextMenu(tab, tabI); @@ -654,8 +654,8 @@ internal sealed class ChatLog : IUiComponent { } currentTab = tabI; - var switchedTab = this._lastTab != tabI; - this._lastTab = tabI; + var switchedTab = this.LastTab != tabI; + this.LastTab = tabI; tab.Unread = 0; this.DrawMessageLog(tab, GetRemainingHeightForMessageLog(), switchedTab); @@ -686,8 +686,8 @@ internal sealed class ChatLog : IUiComponent { for (var tabI = 0; tabI < this.Ui.Plugin.Config.Tabs.Count; tabI++) { var tab = this.Ui.Plugin.Config.Tabs[tabI]; - var unread = tabI == this._lastTab || !tab.DisplayUnread || tab.Unread == 0 ? "" : $" ({tab.Unread})"; - var clicked = ImGui.Selectable($"{tab.Name}{unread}###log-tab-{tabI}", this._lastTab == tabI); + var unread = tabI == this.LastTab || tab.UnreadMode == UnreadMode.None || tab.Unread == 0 ? "" : $" ({tab.Unread})"; + var clicked = ImGui.Selectable($"{tab.Name}{unread}###log-tab-{tabI}", this.LastTab == tabI); this.DrawTabContextMenu(tab, tabI); if (!clicked) { @@ -695,8 +695,8 @@ internal sealed class ChatLog : IUiComponent { } currentTab = tabI; - switchedTab = this._lastTab != tabI; - this._lastTab = tabI; + switchedTab = this.LastTab != tabI; + this.LastTab = tabI; } } @@ -704,8 +704,8 @@ internal sealed class ChatLog : IUiComponent { ImGui.TableNextColumn(); - if (currentTab == -1 && this._lastTab < this.Ui.Plugin.Config.Tabs.Count) { - currentTab = this._lastTab; + if (currentTab == -1 && this.LastTab < this.Ui.Plugin.Config.Tabs.Count) { + currentTab = this.LastTab; this.Ui.Plugin.Config.Tabs[currentTab].Unread = 0; } diff --git a/ChatTwo/Ui/SettingsTabs/Tabs.cs b/ChatTwo/Ui/SettingsTabs/Tabs.cs index 20cd44f..250fb1f 100755 --- a/ChatTwo/Ui/SettingsTabs/Tabs.cs +++ b/ChatTwo/Ui/SettingsTabs/Tabs.cs @@ -43,9 +43,24 @@ internal sealed class Tabs : ISettingsTab { } ImGui.InputText("Name", ref tab.Name, 512, ImGuiInputTextFlags.EnterReturnsTrue); - ImGui.Checkbox("Show unread count", ref tab.DisplayUnread); ImGui.Checkbox("Show timestamps", ref tab.DisplayTimestamp); + if (ImGui.BeginCombo("Unread mode", tab.UnreadMode.ToString())) { + foreach (var mode in Enum.GetValues()) { + if (ImGui.Selectable(mode.ToString(), tab.UnreadMode == mode)) { + tab.UnreadMode = mode; + } + + if (mode.Tooltip() is { } tooltip && ImGui.IsItemHovered()) { + ImGui.BeginTooltip(); + ImGui.TextUnformatted(tooltip); + ImGui.EndTooltip(); + } + } + + ImGui.EndCombo(); + } + var input = tab.Channel?.ToChatType().Name() ?? ""; if (ImGui.BeginCombo("Input channel", input)) { if (ImGui.Selectable("", tab.Channel == null)) {