diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index e78cf2e..3417780 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -251,6 +251,7 @@ internal class Tab public bool HideWhenInactive; [NonSerialized] public uint Unread; + [NonSerialized] public uint LastSendUnread; [NonSerialized] public long LastActivity; [NonSerialized] public MessageList Messages = new(); @@ -265,8 +266,8 @@ internal class Tab Messages.AddPrune(message, MessageManager.MessageDisplayLimit); if (!unread) return; - Unread += 1; + Unread += 1; if (message.Matches(Plugin.Config.InactivityHideChannels!, Plugin.Config.InactivityHideExtraChatAll, Plugin.Config.InactivityHideExtraChatChannels)) LastActivity = Environment.TickCount64; } diff --git a/ChatTwo/Http/Frontend/src/lib/chat.svelte.ts b/ChatTwo/Http/Frontend/src/lib/chat.svelte.ts index 21dd98d..1eb1ce2 100644 --- a/ChatTwo/Http/Frontend/src/lib/chat.svelte.ts +++ b/ChatTwo/Http/Frontend/src/lib/chat.svelte.ts @@ -45,6 +45,7 @@ interface ChannelList { export interface ChatTab { name: string; index: number; + unreadCount: number; } // ref `DataStructure.ChatTabList` @@ -52,6 +53,12 @@ interface ChatTabList { tabs: ChatTab[]; } +// ref `DataStructure.ChatTabUnreadState` +interface ChatTabUnreadState { + index: number; + unreadCount: number; +} + export class ChatTwoWeb { elements!: ChatElements; maxTimestampWidth: number = 0; @@ -297,7 +304,7 @@ export class ChatTwoWeb { this.connection = source('/sse') this.connection.select('close').subscribe((data: string) => { - console.log(`Data received: ${data}`) + console.log(`close: ${data}`) if (data) { console.log('Closing SSE connection.'); this.connection.close(); @@ -306,7 +313,7 @@ export class ChatTwoWeb { // new messages to be appended to the message list this.connection.select('new-message').subscribe((data: string) => { - console.log(`Data received: ${data}`) + console.log(`new-message: ${data}`) if (data) { try { let message: MessageResponse = JSON.parse(data); @@ -319,7 +326,7 @@ export class ChatTwoWeb { // a bulk of new messages, with a clear of the message list beforehand this.connection.select('bulk-messages').subscribe((data: string) => { - console.log(`Data received: ${data}`) + console.log(`bulk-messages: ${data}`) if (data) { this.clearAllMessages(); try { @@ -334,7 +341,7 @@ export class ChatTwoWeb { }); this.connection.select('channel-switched').subscribe((data: string) => { - console.log(`Data received: ${data}`) + console.log(`channel-switched: ${data}`) if (data) { try { let channel: SwitchChannel = JSON.parse(data); @@ -347,7 +354,7 @@ export class ChatTwoWeb { // list of all channels this.connection.select('channel-list').subscribe((data: string) => { - console.log(`Data received: ${data}`) + console.log(`channel-list: ${data}`) if (data) { try { let channelList: ChannelList = JSON.parse(data); @@ -386,5 +393,17 @@ export class ChatTwoWeb { } } }); + + // the unread state of a specific tab has changed + this.connection.select('tab-unread-state').subscribe((data: string) => { + console.log(`tab-unread-state: ${data}`) + if (data) { + try { + const chatTabUnreadState: ChatTabUnreadState = JSON.parse(data); + } catch (error) { + console.error(error); + } + } + }); } } diff --git a/ChatTwo/Http/MessageProtocol/DataStructure.cs b/ChatTwo/Http/MessageProtocol/DataStructure.cs index d410682..d4a8eb5 100644 --- a/ChatTwo/Http/MessageProtocol/DataStructure.cs +++ b/ChatTwo/Http/MessageProtocol/DataStructure.cs @@ -7,10 +7,11 @@ namespace ChatTwo.Http.MessageProtocol; /// /// Contains a valid tab with its assigned index /// -public struct ChatTab(string name, int index) +public struct ChatTab(string name, int index, uint unreadCount) { [JsonProperty("name")] public string Name = name; [JsonProperty("index")] public int Index = index; + [JsonProperty("unreadCount")] public uint UnreadCount = unreadCount; } /// @@ -21,6 +22,15 @@ public struct ChatTabList(ChatTab[] tabs) [JsonProperty("tabs")] public ChatTab[] Tabs = tabs; } +/// +/// Contains a valid tab index and the current unread state as a number unread of messages +/// +public struct ChatTabUnreadState(int index, uint unreadCount) +{ + [JsonProperty("index")] public int Index = index; + [JsonProperty("unreadCount")] public uint UnreadCount = unreadCount; +} + /// /// Contains the current channel name /// diff --git a/ChatTwo/Http/MessageProtocol/OutgoingMessage.cs b/ChatTwo/Http/MessageProtocol/OutgoingMessage.cs index b64c822..80b2997 100644 --- a/ChatTwo/Http/MessageProtocol/OutgoingMessage.cs +++ b/ChatTwo/Http/MessageProtocol/OutgoingMessage.cs @@ -9,6 +9,7 @@ public class CloseEvent() : BaseEvent("close"); // Tab related public class ChatTabListEvent(ChatTabList list) : BaseEvent("tab-list", JsonConvert.SerializeObject(list)); public class ChatTabSwitchedEvent(ChatTab chatTab) : BaseEvent("tab-switched", JsonConvert.SerializeObject(chatTab)); +public class ChatTabUnreadStateEvent(ChatTabUnreadState unreadState) : BaseEvent("tab-unread-state", JsonConvert.SerializeObject(unreadState)); // Input channel related public class ChannelListEvent(ChannelList channelList) : BaseEvent("channel-list", JsonConvert.SerializeObject(channelList)); diff --git a/ChatTwo/Http/Processing.cs b/ChatTwo/Http/Processing.cs index 8e18c1f..494b1ec 100644 --- a/ChatTwo/Http/Processing.cs +++ b/ChatTwo/Http/Processing.cs @@ -104,12 +104,13 @@ public class Processing public ChatTab GetCurrentTab() { - return new ChatTab(HostContext.Core.Plugin.CurrentTab.Name, HostContext.Core.Plugin.LastTab); + var currentTab = HostContext.Core.Plugin.CurrentTab; + return new ChatTab(currentTab.Name, HostContext.Core.Plugin.LastTab, currentTab.Unread); } public ChatTabList GetAllTabs() { - var tabs = Plugin.Config.Tabs.Select((tab, idx) => new ChatTab(tab.Name, idx)).ToArray(); + var tabs = Plugin.Config.Tabs.Select((tab, idx) => new ChatTab(tab.Name, idx, tab.Unread)).ToArray(); return new ChatTabList(tabs); } } diff --git a/ChatTwo/Http/ServerCore.cs b/ChatTwo/Http/ServerCore.cs index 70770a5..c4b7b9c 100644 --- a/ChatTwo/Http/ServerCore.cs +++ b/ChatTwo/Http/ServerCore.cs @@ -1,4 +1,6 @@ using ChatTwo.Http.MessageProtocol; +using ChatTwo.Util; +using Dalamud.Plugin.Services; namespace ChatTwo.Http; @@ -11,6 +13,27 @@ public class ServerCore : IAsyncDisposable { Plugin = plugin; HostContext = new HostContext(this); + + Plugin.Framework.Update += FrameworkUpdate; + } + + public async ValueTask DisposeAsync() + { + Plugin.Framework.Update -= FrameworkUpdate; + await HostContext.DisposeAsync(); + } + + private void FrameworkUpdate(IFramework _) + { + foreach (var (tab, idx) in Plugin.Config.Tabs.WithIndex()) + { + if (tab.Unread == tab.LastSendUnread) + continue; + + tab.LastSendUnread = tab.Unread; + foreach (var eventServer in HostContext.EventConnections) + eventServer.OutboundQueue.Enqueue(new ChatTabUnreadStateEvent(new ChatTabUnreadState(idx, tab.Unread))); + } } #region SSE Helper @@ -165,9 +188,4 @@ public class ServerCore : IAsyncDisposable { return await HostContext.Stop(); } - - public async ValueTask DisposeAsync() - { - await HostContext.DisposeAsync(); - } } \ No newline at end of file