From 014e176e0a7cf457a03278dbdf8495400981b8b2 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Wed, 28 Jul 2021 03:34:36 -0400 Subject: handle THREAD_CREATE also fix compilation also change channel_create signal to emit ChannelData --- discord/objects.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'discord/objects.hpp') diff --git a/discord/objects.hpp b/discord/objects.hpp index 11c8df4..7c249cd 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -71,6 +71,12 @@ enum class GatewayEvent : int { GUILD_JOIN_REQUEST_DELETE, RELATIONSHIP_REMOVE, RELATIONSHIP_ADD, + THREAD_CREATE, + THREAD_UPDATE, + THREAD_DELETE, + THREAD_LIST_SYNC, + THREAD_MEMBER_UPDATE, + THREAD_MEMBERS_UPDATE, }; enum class GatewayCloseCode : uint16_t { @@ -659,3 +665,9 @@ struct PutRelationshipObject { friend void to_json(nlohmann::json &j, const PutRelationshipObject &m); }; + +struct ThreadCreateData { + ChannelData Channel; + + friend void from_json(const nlohmann::json &j, ThreadCreateData &m); +}; -- cgit v1.2.3 From 22376ba54af0cfe85f006679467850de04b3feae Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Fri, 30 Jul 2021 01:32:43 -0400 Subject: handle THREAD_DELETE --- components/channels.cpp | 7 +++++++ components/channels.hpp | 1 + discord/discord.cpp | 19 ++++++++++++++++--- discord/discord.hpp | 4 ++++ discord/objects.cpp | 8 ++++++++ discord/objects.hpp | 10 ++++++++++ 6 files changed, 46 insertions(+), 3 deletions(-) (limited to 'discord/objects.hpp') diff --git a/components/channels.cpp b/components/channels.cpp index a80cfd8..e175e8c 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -129,6 +129,7 @@ ChannelList::ChannelList() discord.signal_channel_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateChannel)); discord.signal_channel_create().connect(sigc::mem_fun(*this, &ChannelList::UpdateCreateChannel)); discord.signal_thread_create().connect(sigc::mem_fun(*this, &ChannelList::UpdateCreateThread)); + discord.signal_thread_delete().connect(sigc::mem_fun(*this, &ChannelList::UpdateDeleteThread)); discord.signal_guild_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateGuild)); } @@ -271,6 +272,12 @@ void ChannelList::UpdateCreateThread(const ChannelData &channel) { CreateThreadRow(parent_row->children(), channel); } +void ChannelList::UpdateDeleteThread(const ThreadDeleteData &data) { + auto iter = GetIteratorForChannelFromID(data.ID); + if (iter) + m_model->erase(iter); +} + void ChannelList::SetActiveChannel(Snowflake id) { const auto channel_iter = GetIteratorForChannelFromID(id); if (channel_iter) { diff --git a/components/channels.hpp b/components/channels.hpp index bdc3e84..ed87b57 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -141,6 +141,7 @@ protected: void UpdateChannel(Snowflake id); void UpdateCreateChannel(const ChannelData &channel); void UpdateCreateThread(const ChannelData &channel); + void UpdateDeleteThread(const ThreadDeleteData &data); void UpdateGuild(Snowflake id); Gtk::TreeView m_view; diff --git a/discord/discord.cpp b/discord/discord.cpp index 61c224a..99ffb0b 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -429,6 +429,7 @@ void DiscordClient::SendLazyLoad(Snowflake id) { msg.GuildID = *GetChannel(id)->GuildID; msg.ShouldGetActivities = true; msg.ShouldGetTyping = true; + msg.ShouldGetThreads = true; m_websocket.Send(msg); } @@ -1158,6 +1159,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::THREAD_CREATE: { HandleGatewayThreadCreate(m); } break; + case GatewayEvent::THREAD_DELETE: { + HandleGatewayThreadDelete(m); + } break; } } break; default: @@ -1224,7 +1228,7 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) { } if (guild.Threads.has_value()) { - for (auto& c : *guild.Threads) { + for (auto &c : *guild.Threads) { c.GuildID = guild.ID; m_store.SetChannel(c.ID, c); } @@ -1640,12 +1644,16 @@ void DiscordClient::HandleGatewayRelationshipAdd(const GatewayMessage &msg) { void DiscordClient::HandleGatewayThreadCreate(const GatewayMessage &msg) { ThreadCreateData data = msg.Data; - m_store.SetChannel(data.Channel.ID, data.Channel); - m_signal_thread_create.emit(data.Channel); } +void DiscordClient::HandleGatewayThreadDelete(const GatewayMessage &msg) { + ThreadDeleteData data = msg.Data; + // m_store.ClearChannel? + m_signal_thread_delete.emit(data); +} + void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -2009,6 +2017,7 @@ void DiscordClient::LoadEventMap() { m_event_map["RELATIONSHIP_REMOVE"] = GatewayEvent::RELATIONSHIP_REMOVE; m_event_map["RELATIONSHIP_ADD"] = GatewayEvent::RELATIONSHIP_ADD; m_event_map["THREAD_CREATE"] = GatewayEvent::THREAD_CREATE; + m_event_map["THREAD_DELETE"] = GatewayEvent::THREAD_DELETE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -2151,6 +2160,10 @@ DiscordClient::type_signal_thread_create DiscordClient::signal_thread_create() { return m_signal_thread_create; } +DiscordClient::type_signal_thread_delete DiscordClient::signal_thread_delete() { + return m_signal_thread_delete; +} + DiscordClient::type_signal_message_sent DiscordClient::signal_message_sent() { return m_signal_message_sent; } diff --git a/discord/discord.hpp b/discord/discord.hpp index 93825af..28c719c 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -237,6 +237,7 @@ private: void HandleGatewayRelationshipRemove(const GatewayMessage &msg); void HandleGatewayRelationshipAdd(const GatewayMessage &msg); void HandleGatewayThreadCreate(const GatewayMessage &msg); + void HandleGatewayThreadDelete(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); @@ -331,6 +332,7 @@ public: typedef sigc::signal type_signal_relationship_remove; typedef sigc::signal type_signal_relationship_add; typedef sigc::signal type_signal_thread_create; + typedef sigc::signal type_signal_thread_delete; typedef sigc::signal type_signal_message_unpinned; // not a real event typedef sigc::signal type_signal_message_pinned; // not a real event either typedef sigc::signal type_signal_message_sent; @@ -371,6 +373,7 @@ public: type_signal_message_unpinned signal_message_unpinned(); type_signal_message_pinned signal_message_pinned(); type_signal_thread_create signal_thread_create(); + type_signal_thread_delete signal_thread_delete(); type_signal_message_sent signal_message_sent(); type_signal_message_send_fail signal_message_send_fail(); type_signal_disconnected signal_disconnected(); @@ -410,6 +413,7 @@ protected: type_signal_message_unpinned m_signal_message_unpinned; type_signal_message_pinned m_signal_message_pinned; type_signal_thread_create m_signal_thread_create; + type_signal_thread_delete m_signal_thread_delete; type_signal_message_sent m_signal_message_sent; type_signal_message_send_fail m_signal_message_send_fail; type_signal_disconnected m_signal_disconnected; diff --git a/discord/objects.cpp b/discord/objects.cpp index c4b1517..e98ac61 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -87,6 +87,7 @@ void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m) { } j["d"]["typing"] = m.ShouldGetTyping; j["d"]["activities"] = m.ShouldGetActivities; + j["d"]["threads"] = m.ShouldGetThreads; if (m.Members.has_value()) j["d"]["members"] = *m.Members; } @@ -476,3 +477,10 @@ void to_json(nlohmann::json &j, const PutRelationshipObject &m) { void from_json(const nlohmann::json &j, ThreadCreateData &m) { j.get_to(m.Channel); } + +void from_json(const nlohmann::json &j, ThreadDeleteData &m) { + JS_D("id", m.ID); + JS_D("guild_id", m.GuildID); + JS_D("parent_id", m.ParentID); + JS_D("type", m.Type); +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 7c249cd..956e2d0 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -206,6 +206,7 @@ struct LazyLoadRequestMessage { Snowflake GuildID; bool ShouldGetTyping = false; bool ShouldGetActivities = false; + bool ShouldGetThreads = false; std::optional> Members; // snowflake? std::optional>>> Channels; // channel ID -> range of sidebar @@ -671,3 +672,12 @@ struct ThreadCreateData { friend void from_json(const nlohmann::json &j, ThreadCreateData &m); }; + +struct ThreadDeleteData { + Snowflake ID; + Snowflake GuildID; + Snowflake ParentID; + ChannelType Type; + + friend void from_json(const nlohmann::json &j, ThreadDeleteData &m); +}; -- cgit v1.2.3 From 06f85c3a2de5af9e0d63ff86a8e411030d1ee45d Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 2 Aug 2021 00:53:08 -0400 Subject: THREAD_LIST_SYNC --- discord/discord.cpp | 20 ++++++++++++++++++++ discord/discord.hpp | 4 ++++ discord/objects.cpp | 5 +++++ discord/objects.hpp | 9 +++++++++ 4 files changed, 38 insertions(+) (limited to 'discord/objects.hpp') diff --git a/discord/discord.cpp b/discord/discord.cpp index 6ac2223..dcab6be 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -1173,6 +1173,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::THREAD_DELETE: { HandleGatewayThreadDelete(m); } break; + case GatewayEvent::THREAD_LIST_SYNC: { + HandleGatewayThreadListSync(m); + } break; } } break; default: @@ -1653,6 +1656,8 @@ void DiscordClient::HandleGatewayRelationshipAdd(const GatewayMessage &msg) { m_signal_relationship_add.emit(std::move(data)); } +// remarkably this doesnt actually mean a thread was created +// it can also mean you gained access to a thread. yay ... void DiscordClient::HandleGatewayThreadCreate(const GatewayMessage &msg) { ThreadCreateData data = msg.Data; m_store.SetChannel(data.Channel.ID, data.Channel); @@ -1665,6 +1670,16 @@ void DiscordClient::HandleGatewayThreadDelete(const GatewayMessage &msg) { m_signal_thread_delete.emit(data); } +// this message is received when you load a channel as part of the lazy load request +// so the ui will only update thread when you load a channel in some guild +// which is rather annoying but oh well +void DiscordClient::HandleGatewayThreadListSync(const GatewayMessage &msg) { + ThreadListSyncData data = msg.Data; + for (const auto &thread : data.Threads) + m_store.SetChannel(thread.ID, thread); + m_signal_thread_list_sync.emit(data); +} + void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -2029,6 +2044,7 @@ void DiscordClient::LoadEventMap() { m_event_map["RELATIONSHIP_ADD"] = GatewayEvent::RELATIONSHIP_ADD; m_event_map["THREAD_CREATE"] = GatewayEvent::THREAD_CREATE; m_event_map["THREAD_DELETE"] = GatewayEvent::THREAD_DELETE; + m_event_map["THREAD_LIST_SYNC"] = GatewayEvent::THREAD_LIST_SYNC; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -2175,6 +2191,10 @@ DiscordClient::type_signal_thread_delete DiscordClient::signal_thread_delete() { return m_signal_thread_delete; } +DiscordClient::type_signal_thread_list_sync DiscordClient::signal_thread_list_sync() { + return m_signal_thread_list_sync; +} + DiscordClient::type_signal_message_sent DiscordClient::signal_message_sent() { return m_signal_message_sent; } diff --git a/discord/discord.hpp b/discord/discord.hpp index 156ab45..616941b 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -239,6 +239,7 @@ private: void HandleGatewayRelationshipAdd(const GatewayMessage &msg); void HandleGatewayThreadCreate(const GatewayMessage &msg); void HandleGatewayThreadDelete(const GatewayMessage &msg); + void HandleGatewayThreadListSync(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); @@ -334,6 +335,7 @@ public: typedef sigc::signal type_signal_relationship_add; typedef sigc::signal type_signal_thread_create; typedef sigc::signal type_signal_thread_delete; + typedef sigc::signal type_signal_thread_list_sync; typedef sigc::signal type_signal_message_unpinned; // not a real event typedef sigc::signal type_signal_message_pinned; // not a real event either typedef sigc::signal type_signal_message_sent; @@ -375,6 +377,7 @@ public: type_signal_message_pinned signal_message_pinned(); type_signal_thread_create signal_thread_create(); type_signal_thread_delete signal_thread_delete(); + type_signal_thread_list_sync signal_thread_list_sync(); type_signal_message_sent signal_message_sent(); type_signal_message_send_fail signal_message_send_fail(); type_signal_disconnected signal_disconnected(); @@ -415,6 +418,7 @@ protected: type_signal_message_pinned m_signal_message_pinned; type_signal_thread_create m_signal_thread_create; type_signal_thread_delete m_signal_thread_delete; + type_signal_thread_list_sync m_signal_thread_list_sync; type_signal_message_sent m_signal_message_sent; type_signal_message_send_fail m_signal_message_send_fail; type_signal_disconnected m_signal_disconnected; diff --git a/discord/objects.cpp b/discord/objects.cpp index e98ac61..e7b421f 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -484,3 +484,8 @@ void from_json(const nlohmann::json &j, ThreadDeleteData &m) { JS_D("parent_id", m.ParentID); JS_D("type", m.Type); } + +void from_json(const nlohmann::json &j, ThreadListSyncData &m) { + JS_D("threads", m.Threads); + JS_D("guild_id", m.GuildID); +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 956e2d0..7493404 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -681,3 +681,12 @@ struct ThreadDeleteData { friend void from_json(const nlohmann::json &j, ThreadDeleteData &m); }; + +// pretty different from docs +struct ThreadListSyncData { + std::vector Threads; + Snowflake GuildID; + // std::optional> MostRecentMessages; + + friend void from_json(const nlohmann::json &j, ThreadListSyncData &m); +}; -- cgit v1.2.3 From a19d21427206bcd5ab5cc0af273a05f3fe827720 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 2 Aug 2021 02:00:03 -0400 Subject: basic THREAD_MEMBERS_UPDATE handling for updating channel list --- components/channels.cpp | 18 +++++++++++++++--- components/channels.hpp | 5 ++++- discord/discord.cpp | 15 ++++++++++++++- discord/discord.hpp | 4 ++++ discord/objects.cpp | 8 ++++++++ discord/objects.hpp | 10 ++++++++++ 6 files changed, 55 insertions(+), 5 deletions(-) (limited to 'discord/objects.hpp') diff --git a/components/channels.cpp b/components/channels.cpp index ed5de62..644e090 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -142,7 +142,8 @@ ChannelList::ChannelList() discord.signal_channel_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateChannel)); discord.signal_channel_create().connect(sigc::mem_fun(*this, &ChannelList::UpdateCreateChannel)); discord.signal_thread_create().connect(sigc::mem_fun(*this, &ChannelList::UpdateCreateThread)); - discord.signal_thread_delete().connect(sigc::mem_fun(*this, &ChannelList::UpdateDeleteThread)); + discord.signal_thread_delete().connect(sigc::mem_fun(*this, &ChannelList::OnThreadDelete)); + discord.signal_thread_members_update().connect(sigc::mem_fun(*this, &ChannelList::OnThreadMembersUpdate)); discord.signal_guild_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateGuild)); } @@ -279,14 +280,25 @@ void ChannelList::UpdateGuild(Snowflake id) { } } +void ChannelList::OnThreadDelete(const ThreadDeleteData &data) { + UpdateDeleteThread(data.ID); +} + +void ChannelList::OnThreadMembersUpdate(const ThreadMembersUpdateData &data) { + auto &r = data.RemovedMemberIDs; + if (r.has_value() && std::find(r->begin(), r->end(), Abaddon::Get().GetDiscordClient().GetUserData().ID) != r->end()) { + UpdateDeleteThread(data.ID); + } +} + void ChannelList::UpdateCreateThread(const ChannelData &channel) { auto parent_row = GetIteratorForChannelFromID(*channel.ParentID); if (parent_row) CreateThreadRow(parent_row->children(), channel); } -void ChannelList::UpdateDeleteThread(const ThreadDeleteData &data) { - auto iter = GetIteratorForChannelFromID(data.ID); +void ChannelList::UpdateDeleteThread(Snowflake id) { + auto iter = GetIteratorForChannelFromID(id); if (iter) m_model->erase(iter); } diff --git a/components/channels.hpp b/components/channels.hpp index c131a07..24c7170 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -141,9 +141,12 @@ protected: void UpdateChannel(Snowflake id); void UpdateCreateChannel(const ChannelData &channel); void UpdateCreateThread(const ChannelData &channel); - void UpdateDeleteThread(const ThreadDeleteData &data); + void UpdateDeleteThread(Snowflake id); void UpdateGuild(Snowflake id); + void OnThreadDelete(const ThreadDeleteData &data); + void OnThreadMembersUpdate(const ThreadMembersUpdateData &data); + Gtk::TreeView m_view; class ModelColumns : public Gtk::TreeModel::ColumnRecord { diff --git a/discord/discord.cpp b/discord/discord.cpp index dcab6be..82d2131 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -764,7 +764,7 @@ void DiscordClient::Unpin(Snowflake channel_id, Snowflake message_id, sigc::slot // i dont know if the location parameter is necessary at all but discord's thread implementation is extremely strange // so its here just in case void DiscordClient::LeaveThread(Snowflake channel_id, const std::string &location, sigc::slot callback) { - m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/thread-members/@me?location=" + location, [this, callback](const http::response_type& response) { + m_http.MakeDELETE("/channels/" + std::to_string(channel_id) + "/thread-members/@me?location=" + location, [this, callback](const http::response_type &response) { if (CheckCode(response, 204)) callback(DiscordError::NONE); else @@ -1176,6 +1176,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::THREAD_LIST_SYNC: { HandleGatewayThreadListSync(m); } break; + case GatewayEvent::THREAD_MEMBERS_UPDATE: { + HandleGatewayThreadMembersUpdate(m); + } break; } } break; default: @@ -1680,6 +1683,11 @@ void DiscordClient::HandleGatewayThreadListSync(const GatewayMessage &msg) { m_signal_thread_list_sync.emit(data); } +void DiscordClient::HandleGatewayThreadMembersUpdate(const GatewayMessage &msg) { + ThreadMembersUpdateData data = msg.Data; + m_signal_thread_members_update.emit(data); +} + void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -2045,6 +2053,7 @@ void DiscordClient::LoadEventMap() { m_event_map["THREAD_CREATE"] = GatewayEvent::THREAD_CREATE; m_event_map["THREAD_DELETE"] = GatewayEvent::THREAD_DELETE; m_event_map["THREAD_LIST_SYNC"] = GatewayEvent::THREAD_LIST_SYNC; + m_event_map["THREAD_MEMBERS_UPDATE"] = GatewayEvent::THREAD_MEMBERS_UPDATE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -2195,6 +2204,10 @@ DiscordClient::type_signal_thread_list_sync DiscordClient::signal_thread_list_sy return m_signal_thread_list_sync; } +DiscordClient::type_signal_thread_members_update DiscordClient::signal_thread_members_update() { + return m_signal_thread_members_update; +} + DiscordClient::type_signal_message_sent DiscordClient::signal_message_sent() { return m_signal_message_sent; } diff --git a/discord/discord.hpp b/discord/discord.hpp index 616941b..619a898 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -240,6 +240,7 @@ private: void HandleGatewayThreadCreate(const GatewayMessage &msg); void HandleGatewayThreadDelete(const GatewayMessage &msg); void HandleGatewayThreadListSync(const GatewayMessage &msg); + void HandleGatewayThreadMembersUpdate(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); @@ -336,6 +337,7 @@ public: typedef sigc::signal type_signal_thread_create; typedef sigc::signal type_signal_thread_delete; typedef sigc::signal type_signal_thread_list_sync; + typedef sigc::signal type_signal_thread_members_update; typedef sigc::signal type_signal_message_unpinned; // not a real event typedef sigc::signal type_signal_message_pinned; // not a real event either typedef sigc::signal type_signal_message_sent; @@ -378,6 +380,7 @@ public: type_signal_thread_create signal_thread_create(); type_signal_thread_delete signal_thread_delete(); type_signal_thread_list_sync signal_thread_list_sync(); + type_signal_thread_members_update signal_thread_members_update(); type_signal_message_sent signal_message_sent(); type_signal_message_send_fail signal_message_send_fail(); type_signal_disconnected signal_disconnected(); @@ -419,6 +422,7 @@ protected: type_signal_thread_create m_signal_thread_create; type_signal_thread_delete m_signal_thread_delete; type_signal_thread_list_sync m_signal_thread_list_sync; + type_signal_thread_members_update m_signal_thread_members_update; type_signal_message_sent m_signal_message_sent; type_signal_message_send_fail m_signal_message_send_fail; type_signal_disconnected m_signal_disconnected; diff --git a/discord/objects.cpp b/discord/objects.cpp index e7b421f..41164a4 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -489,3 +489,11 @@ void from_json(const nlohmann::json &j, ThreadListSyncData &m) { JS_D("threads", m.Threads); JS_D("guild_id", m.GuildID); } + +void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m) { + JS_D("id", m.ID); + JS_D("guild_id", m.GuildID); + JS_D("member_count", m.MemberCount); + JS_O("added_members", m.AddedMembers); + JS_O("removed_member_ids", m.RemovedMemberIDs); +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 7493404..889671f 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -690,3 +690,13 @@ struct ThreadListSyncData { friend void from_json(const nlohmann::json &j, ThreadListSyncData &m); }; + +struct ThreadMembersUpdateData { + Snowflake ID; + Snowflake GuildID; + int MemberCount; + std::optional> AddedMembers; + std::optional> RemovedMemberIDs; + + friend void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m); +}; -- cgit v1.2.3 From 7ffded5b1373444cf3442d759a3bd8ae0940bd7d Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Wed, 11 Aug 2021 03:32:09 -0400 Subject: rest of view threads window --- discord/discord.cpp | 18 +++++++- discord/discord.hpp | 3 +- discord/objects.cpp | 6 +++ discord/objects.hpp | 8 ++++ discord/store.cpp | 27 ++++++++++-- discord/store.hpp | 2 +- windows/threadswindow.cpp | 107 ++++++++++++++++++++++++++++++++++++++++++++++ windows/threadswindow.hpp | 60 ++++++++++++++++++++++++++ 8 files changed, 223 insertions(+), 8 deletions(-) create mode 100644 windows/threadswindow.cpp create mode 100644 windows/threadswindow.hpp (limited to 'discord/objects.hpp') diff --git a/discord/discord.cpp b/discord/discord.cpp index aa363f5..7dfacc0 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -249,8 +249,22 @@ std::set DiscordClient::GetChannelsInGuild(Snowflake id) const { return {}; } -std::vector DiscordClient::GetPublicThreads(Snowflake channel_id) const { - return m_store.GetThreads(channel_id); +// there is an endpoint for this but it should be synced before this is called anyways +std::vector DiscordClient::GetActiveThreads(Snowflake channel_id) const { + return m_store.GetActiveThreads(channel_id); +} + +void DiscordClient::GetArchivedPublicThreads(Snowflake channel_id, sigc::slot callback) { + m_http.MakeGET("/channels/" + std::to_string(channel_id) + "/threads/archived/public", [this, callback](const http::response_type &r) { + if (CheckCode(r)) { + const auto data = nlohmann::json::parse(r.text).get(); + for (const auto &thread : data.Threads) + m_store.SetChannel(thread.ID, thread); + callback(DiscordError::NONE, data); + } else { + callback(GetCodeFromResponse(r), {}); + } + }); } bool DiscordClient::IsThreadJoined(Snowflake thread_id) const { diff --git a/discord/discord.hpp b/discord/discord.hpp index 11b8cbd..f001461 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -86,7 +86,8 @@ public: std::optional GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const; std::set GetUsersInGuild(Snowflake id) const; std::set GetChannelsInGuild(Snowflake id) const; - std::vector GetPublicThreads(Snowflake channel_id) const; + std::vector GetActiveThreads(Snowflake channel_id) const; + void GetArchivedPublicThreads(Snowflake channel_id, sigc::slot callback); bool IsThreadJoined(Snowflake thread_id) const; bool HasGuildPermission(Snowflake user_id, Snowflake guild_id, Permission perm) const; diff --git a/discord/objects.cpp b/discord/objects.cpp index 41164a4..723ca09 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -497,3 +497,9 @@ void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m) { JS_O("added_members", m.AddedMembers); JS_O("removed_member_ids", m.RemovedMemberIDs); } + +void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m) { + JS_D("threads", m.Threads); + JS_D("members", m.Members); + JS_D("has_more", m.HasMore); +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 889671f..9046162 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -700,3 +700,11 @@ struct ThreadMembersUpdateData { friend void from_json(const nlohmann::json &j, ThreadMembersUpdateData &m); }; + +struct ArchivedThreadsResponseData { + std::vector Threads; + std::vector Members; + bool HasMore; + + friend void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m); +}; diff --git a/discord/store.cpp b/discord/store.cpp index ba8e59a..3b00949 100644 --- a/discord/store.cpp +++ b/discord/store.cpp @@ -105,6 +105,16 @@ void Store::SetChannel(Snowflake id, const ChannelData &chan) { Bind(m_set_chan_stmt, 17, chan.ParentID); Bind(m_set_chan_stmt, 18, chan.LastPinTimestamp); + if (chan.ThreadMetadata.has_value()) { + Bind(m_set_chan_stmt, 19, chan.ThreadMetadata->IsArchived); + Bind(m_set_chan_stmt, 20, chan.ThreadMetadata->AutoArchiveDuration); + Bind(m_set_chan_stmt, 21, chan.ThreadMetadata->ArchiveTimestamp); + } else { + Bind(m_set_chan_stmt, 19, nullptr); + Bind(m_set_chan_stmt, 20, nullptr); + Bind(m_set_chan_stmt, 21, nullptr); + } + if (!RunInsert(m_set_chan_stmt)) fprintf(stderr, "channel insert failed: %s\n", sqlite3_errstr(m_db_err)); @@ -499,7 +509,7 @@ std::vector Store::GetPinnedMessages(Snowflake channel_id) const { return ret; } -std::vector Store::GetThreads(Snowflake channel_id) const { +std::vector Store::GetActiveThreads(Snowflake channel_id) const { std::vector ret; Bind(m_get_threads_stmt, 1, channel_id); @@ -552,6 +562,12 @@ std::optional Store::GetChannel(Snowflake id) const { Get(m_get_chan_stmt, 15, ret.ApplicationID); Get(m_get_chan_stmt, 16, ret.ParentID); Get(m_get_chan_stmt, 17, ret.LastPinTimestamp); + if (!IsNull(m_get_chan_stmt, 18)) { + ret.ThreadMetadata.emplace(); + Get(m_get_chan_stmt, 18, ret.ThreadMetadata->IsArchived); + Get(m_get_chan_stmt, 19, ret.ThreadMetadata->AutoArchiveDuration); + Get(m_get_chan_stmt, 20, ret.ThreadMetadata->ArchiveTimestamp); + } Reset(m_get_chan_stmt); @@ -987,7 +1003,10 @@ bool Store::CreateTables() { owner_id INTEGER, application_id INTEGER, parent_id INTEGER, - last_pin_timestamp TEXT + last_pin_timestamp TEXT, + archived BOOL, /* threads */ + auto_archive INTEGER, /* threads */ + archived_ts TEXT /* threads */ ) )"; @@ -1156,7 +1175,7 @@ bool Store::CreateStatements() { const char *set_chan = R"( REPLACE INTO channels VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) )"; @@ -1206,7 +1225,7 @@ bool Store::CreateStatements() { )"; const char *get_threads = R"( - SELECT id FROM channels WHERE parent_id = ? AND type = 11 + SELECT id FROM channels WHERE parent_id = ? AND (type = 10 OR type = 11 OR type = 12) AND archived = FALSE )"; m_db_err = sqlite3_prepare_v2(m_db, set_user, -1, &m_set_user_stmt, nullptr); diff --git a/discord/store.hpp b/discord/store.hpp index 76c8a8e..8e19e20 100644 --- a/discord/store.hpp +++ b/discord/store.hpp @@ -44,7 +44,7 @@ public: std::vector GetLastMessages(Snowflake id, size_t num) const; std::vector GetChannelMessageIDs(Snowflake id) const; std::vector GetPinnedMessages(Snowflake channel_id) const; - std::vector GetThreads(Snowflake channel_id) const; // public + std::vector GetActiveThreads(Snowflake channel_id) const; // public void ClearGuild(Snowflake id); void ClearChannel(Snowflake id); diff --git a/windows/threadswindow.cpp b/windows/threadswindow.cpp new file mode 100644 index 0000000..a772eeb --- /dev/null +++ b/windows/threadswindow.cpp @@ -0,0 +1,107 @@ +#include "threadswindow.hpp" +#include "../abaddon.hpp" + +ThreadsWindow::ThreadsWindow(const ChannelData &channel) + : m_channel_id(channel.ID) + , m_box(Gtk::ORIENTATION_VERTICAL) + , m_active(channel) + , m_archived(channel) { + set_name("threads-window"); + set_default_size(450, 375); + set_title("#" + *channel.Name + " - Threads"); + set_position(Gtk::WIN_POS_CENTER); + get_style_context()->add_class("app-window"); + get_style_context()->add_class("app-popup"); + get_style_context()->add_class("threads-window"); + + const auto cb = [this](Snowflake id) { + Abaddon::Get().ActionChannelOpened(id); + hide(); + }; + m_active.signal_thread_open().connect(cb); + m_archived.signal_thread_open().connect(cb); + + m_switcher.set_halign(Gtk::ALIGN_CENTER); + m_switcher.set_stack(m_stack); + + m_stack.add(m_active, "active", "Active Threads"); + m_stack.add(m_archived, "archived", "Archived Threads"); + + m_active.show(); + m_archived.show(); + m_switcher.show(); + m_stack.show(); + m_box.show(); + + m_box.add(m_switcher); + m_box.add(m_stack); + add(m_box); +} + +ThreadListRow::ThreadListRow(const ChannelData &channel) + : ID(channel.ID) + , m_label(*channel.Name, Gtk::ALIGN_START) { + m_label.show(); + add(m_label); +} + +ActiveThreadsList::ActiveThreadsList(const ChannelData &channel) { + set_vexpand(true); + + m_list.set_selection_mode(Gtk::SELECTION_SINGLE); + m_list.set_hexpand(true); + m_list.show(); + + add(m_list); + + m_list.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool { + if (ev->button == GDK_BUTTON_PRIMARY && ev->type == GDK_2BUTTON_PRESS) { + if (auto row = dynamic_cast(m_list.get_selected_row())) + m_signal_thread_open.emit(row->ID); + } + return false; + }); + + const auto threads = Abaddon::Get().GetDiscordClient().GetActiveThreads(channel.ID); + for (const auto &thread : threads) { + auto row = Gtk::manage(new ThreadListRow(thread)); + row->show(); + m_list.add(*row); + } +} + +ActiveThreadsList::type_signal_thread_open ActiveThreadsList::signal_thread_open() { + return m_signal_thread_open; +} + +ArchivedThreadsList::ArchivedThreadsList(const ChannelData &channel) { + set_vexpand(true); + + m_list.set_selection_mode(Gtk::SELECTION_SINGLE); + m_list.set_hexpand(true); + m_list.show(); + + add(m_list); + + m_list.signal_button_press_event().connect([this](GdkEventButton *ev) -> bool { + if (ev->button == GDK_BUTTON_PRIMARY && ev->type == GDK_2BUTTON_PRESS) { + if (auto row = dynamic_cast(m_list.get_selected_row())) + m_signal_thread_open.emit(row->ID); + } + return false; + }); + + Abaddon::Get().GetDiscordClient().GetArchivedPublicThreads(channel.ID, sigc::mem_fun(*this, &ArchivedThreadsList::OnPublicFetched)); +} + +void ArchivedThreadsList::OnPublicFetched(DiscordError code, const ArchivedThreadsResponseData &data) { + for (const auto &thread : data.Threads) { + auto row = Gtk::manage(new ThreadListRow(thread)); + row->show(); + m_list.add(*row); + } +} + +ArchivedThreadsList::type_signal_thread_open ArchivedThreadsList::signal_thread_open() { + return m_signal_thread_open; +} diff --git a/windows/threadswindow.hpp b/windows/threadswindow.hpp new file mode 100644 index 0000000..a0c77e8 --- /dev/null +++ b/windows/threadswindow.hpp @@ -0,0 +1,60 @@ +#pragma once +#include +#include "../discord/objects.hpp" + +class ActiveThreadsList : public Gtk::ScrolledWindow { +public: + ActiveThreadsList(const ChannelData &channel); + +private: + Gtk::ListBox m_list; + + using type_signal_thread_open = sigc::signal; + type_signal_thread_open m_signal_thread_open; + +public: + type_signal_thread_open signal_thread_open(); +}; + +class ArchivedThreadsList : public Gtk::ScrolledWindow { +public: + ArchivedThreadsList(const ChannelData &channel); + +private: + Gtk::ListBox m_list; + + void OnPublicFetched(DiscordError code, const ArchivedThreadsResponseData &data); + + using type_signal_thread_open = sigc::signal; + type_signal_thread_open m_signal_thread_open; + +public: + type_signal_thread_open signal_thread_open(); +}; + +// view all threads in a channel +class ThreadsWindow : public Gtk::Window { +public: + ThreadsWindow(const ChannelData &channel); + +private: + Snowflake m_channel_id; + + Gtk::StackSwitcher m_switcher; + Gtk::Stack m_stack; + + Gtk::Box m_box; + + ActiveThreadsList m_active; + ArchivedThreadsList m_archived; +}; + +class ThreadListRow : public Gtk::ListBoxRow { +public: + ThreadListRow(const ChannelData &channel); + + Snowflake ID; + +private: + Gtk::Label m_label; +}; -- cgit v1.2.3 From 613bb2b7c6065035bba5eee606249e413dcc5149 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sun, 15 Aug 2021 00:25:00 -0400 Subject: handle thread create via thread_member_update --- discord/discord.cpp | 13 ++++++++++++- discord/discord.hpp | 1 + discord/objects.cpp | 4 ++++ discord/objects.hpp | 6 ++++++ 4 files changed, 23 insertions(+), 1 deletion(-) (limited to 'discord/objects.hpp') diff --git a/discord/discord.cpp b/discord/discord.cpp index 7dfacc0..2e12d41 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -1201,6 +1201,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::THREAD_MEMBERS_UPDATE: { HandleGatewayThreadMembersUpdate(m); } break; + case GatewayEvent::THREAD_MEMBER_UPDATE: { + HandleGatewayThreadMemberUpdate(m); + } break; } } break; default: @@ -1693,7 +1696,7 @@ void DiscordClient::HandleGatewayThreadCreate(const GatewayMessage &msg) { void DiscordClient::HandleGatewayThreadDelete(const GatewayMessage &msg) { ThreadDeleteData data = msg.Data; - // m_store.ClearChannel? + m_store.ClearChannel(data.ID); m_signal_thread_delete.emit(data); } @@ -1723,6 +1726,13 @@ void DiscordClient::HandleGatewayThreadMembersUpdate(const GatewayMessage &msg) m_signal_thread_members_update.emit(data); } +void DiscordClient::HandleGatewayThreadMemberUpdate(const GatewayMessage &msg) { + ThreadMemberUpdateData data = msg.Data; + m_joined_threads.insert(*data.Member.ThreadID); + if (*data.Member.UserID == GetUserData().ID) + m_signal_added_to_thread.emit(*data.Member.ThreadID); +} + void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -2089,6 +2099,7 @@ void DiscordClient::LoadEventMap() { m_event_map["THREAD_DELETE"] = GatewayEvent::THREAD_DELETE; m_event_map["THREAD_LIST_SYNC"] = GatewayEvent::THREAD_LIST_SYNC; m_event_map["THREAD_MEMBERS_UPDATE"] = GatewayEvent::THREAD_MEMBERS_UPDATE; + m_event_map["THREAD_MEMBER_UPDATE"] = GatewayEvent::THREAD_MEMBER_UPDATE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { diff --git a/discord/discord.hpp b/discord/discord.hpp index f001461..952a5c4 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -244,6 +244,7 @@ private: void HandleGatewayThreadDelete(const GatewayMessage &msg); void HandleGatewayThreadListSync(const GatewayMessage &msg); void HandleGatewayThreadMembersUpdate(const GatewayMessage &msg); + void HandleGatewayThreadMemberUpdate(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); diff --git a/discord/objects.cpp b/discord/objects.cpp index 723ca09..77d5286 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -503,3 +503,7 @@ void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m) { JS_D("members", m.Members); JS_D("has_more", m.HasMore); } + +void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m) { + m.Member = j; +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 9046162..4e7de81 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -708,3 +708,9 @@ struct ArchivedThreadsResponseData { friend void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m); }; + +struct ThreadMemberUpdateData { + ThreadMemberObject Member; + + friend void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m); +}; -- cgit v1.2.3 From d2f6bd08fc27c2e499ab1573604932448feef269 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Mon, 16 Aug 2021 02:47:08 -0400 Subject: handle archiving via THREAD_UPDATE (sorta) --- components/channels.cpp | 14 ++++++++++---- components/channels.hpp | 1 + discord/discord.cpp | 14 ++++++++++++++ discord/discord.hpp | 4 ++++ discord/objects.cpp | 4 ++++ discord/objects.hpp | 6 ++++++ 6 files changed, 39 insertions(+), 4 deletions(-) (limited to 'discord/objects.hpp') diff --git a/components/channels.cpp b/components/channels.cpp index f8d0fb6..117e5a6 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -142,6 +142,7 @@ ChannelList::ChannelList() discord.signal_channel_update().connect(sigc::mem_fun(*this, &ChannelList::UpdateChannel)); discord.signal_channel_create().connect(sigc::mem_fun(*this, &ChannelList::UpdateCreateChannel)); discord.signal_thread_delete().connect(sigc::mem_fun(*this, &ChannelList::OnThreadDelete)); + discord.signal_thread_update().connect(sigc::mem_fun(*this, &ChannelList::OnThreadUpdate)); discord.signal_thread_list_sync().connect(sigc::mem_fun(*this, &ChannelList::OnThreadListSync)); discord.signal_added_to_thread().connect(sigc::mem_fun(*this, &ChannelList::OnThreadJoined)); discord.signal_removed_from_thread().connect(sigc::mem_fun(*this, &ChannelList::OnThreadRemoved)); @@ -291,14 +292,19 @@ void ChannelList::OnThreadJoined(Snowflake id) { } void ChannelList::OnThreadRemoved(Snowflake id) { - if (GetIteratorForChannelFromID(id)) - DeleteThreadRow(id); + DeleteThreadRow(id); } void ChannelList::OnThreadDelete(const ThreadDeleteData &data) { DeleteThreadRow(data.ID); } +// todo probably make the row stick around if its selected until the selection changes +void ChannelList::OnThreadUpdate(const ThreadUpdateData &data) { + if (data.Thread.ThreadMetadata->IsArchived) + DeleteThreadRow(data.Thread.ID); +} + void ChannelList::OnThreadListSync(const ThreadListSyncData &data) { // get the threads in the guild std::vector threads; @@ -317,7 +323,7 @@ void ChannelList::OnThreadListSync(const ThreadListSyncData &data) { // delete all threads not present in the synced data for (auto thread_id : threads) { - if (std::find_if(data.Threads.begin(), data.Threads.end(), [thread_id](const auto& x) { return x.ID == thread_id; }) == data.Threads.end()) { + if (std::find_if(data.Threads.begin(), data.Threads.end(), [thread_id](const auto &x) { return x.ID == thread_id; }) == data.Threads.end()) { auto iter = GetIteratorForChannelFromID(thread_id); m_model->erase(iter); } @@ -336,7 +342,7 @@ void ChannelList::SetActiveChannel(Snowflake id) { if (m_temporary_thread_row) { const auto thread_id = static_cast((*m_temporary_thread_row)[m_columns.m_id]); const auto thread = Abaddon::Get().GetDiscordClient().GetChannel(thread_id); - if (thread.has_value() && !thread->IsJoinedThread()) + if (thread.has_value() && (!thread->IsJoinedThread() || thread->ThreadMetadata->IsArchived)) m_model->erase(m_temporary_thread_row); m_temporary_thread_row = {}; } diff --git a/components/channels.hpp b/components/channels.hpp index 31857ec..506ad93 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -146,6 +146,7 @@ protected: void OnThreadJoined(Snowflake id); void OnThreadRemoved(Snowflake id); void OnThreadDelete(const ThreadDeleteData &data); + void OnThreadUpdate(const ThreadUpdateData &data); void OnThreadListSync(const ThreadListSyncData &data); Gtk::TreeView m_view; diff --git a/discord/discord.cpp b/discord/discord.cpp index 0ef1202..c4276dc 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -1220,6 +1220,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::THREAD_MEMBER_UPDATE: { HandleGatewayThreadMemberUpdate(m); } break; + case GatewayEvent::THREAD_UPDATE: { + HandleGatewayThreadUpdate(m); + } break; } } break; default: @@ -1749,6 +1752,12 @@ void DiscordClient::HandleGatewayThreadMemberUpdate(const GatewayMessage &msg) { m_signal_added_to_thread.emit(*data.Member.ThreadID); } +void DiscordClient::HandleGatewayThreadUpdate(const GatewayMessage &msg) { + ThreadUpdateData data = msg.Data; + m_store.SetChannel(data.Thread.ID, data.Thread); + m_signal_thread_update.emit(data); +} + void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -2116,6 +2125,7 @@ void DiscordClient::LoadEventMap() { m_event_map["THREAD_LIST_SYNC"] = GatewayEvent::THREAD_LIST_SYNC; m_event_map["THREAD_MEMBERS_UPDATE"] = GatewayEvent::THREAD_MEMBERS_UPDATE; m_event_map["THREAD_MEMBER_UPDATE"] = GatewayEvent::THREAD_MEMBER_UPDATE; + m_event_map["THREAD_UPDATE"] = GatewayEvent::THREAD_UPDATE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -2270,6 +2280,10 @@ DiscordClient::type_signal_thread_members_update DiscordClient::signal_thread_me return m_signal_thread_members_update; } +DiscordClient::type_signal_thread_update DiscordClient::signal_thread_update() { + return m_signal_thread_update; +} + DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() { return m_signal_added_to_thread; } diff --git a/discord/discord.hpp b/discord/discord.hpp index 952a5c4..a9dc62e 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -245,6 +245,7 @@ private: void HandleGatewayThreadListSync(const GatewayMessage &msg); void HandleGatewayThreadMembersUpdate(const GatewayMessage &msg); void HandleGatewayThreadMemberUpdate(const GatewayMessage &msg); + void HandleGatewayThreadUpdate(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); @@ -340,6 +341,7 @@ public: typedef sigc::signal type_signal_thread_delete; typedef sigc::signal type_signal_thread_list_sync; typedef sigc::signal type_signal_thread_members_update; + typedef sigc::signal type_signal_thread_update; // not discord dispatch events typedef sigc::signal type_signal_added_to_thread; @@ -388,6 +390,7 @@ public: type_signal_thread_delete signal_thread_delete(); type_signal_thread_list_sync signal_thread_list_sync(); type_signal_thread_members_update signal_thread_members_update(); + type_signal_thread_update signal_thread_update(); type_signal_added_to_thread signal_added_to_thread(); type_signal_removed_from_thread signal_removed_from_thread(); type_signal_message_sent signal_message_sent(); @@ -432,6 +435,7 @@ protected: type_signal_thread_delete m_signal_thread_delete; type_signal_thread_list_sync m_signal_thread_list_sync; type_signal_thread_members_update m_signal_thread_members_update; + type_signal_thread_update m_signal_thread_update; type_signal_removed_from_thread m_signal_removed_from_thread; type_signal_added_to_thread m_signal_added_to_thread; type_signal_message_sent m_signal_message_sent; diff --git a/discord/objects.cpp b/discord/objects.cpp index 77d5286..fb713f4 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -507,3 +507,7 @@ void from_json(const nlohmann::json &j, ArchivedThreadsResponseData &m) { void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m) { m.Member = j; } + +void from_json(const nlohmann::json &j, ThreadUpdateData &m) { + m.Thread = j; +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 4e7de81..daaa9b2 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -714,3 +714,9 @@ struct ThreadMemberUpdateData { friend void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m); }; + +struct ThreadUpdateData { + ChannelData Thread; + + friend void from_json(const nlohmann::json &j, ThreadUpdateData &m); +}; -- cgit v1.2.3 From 2a45d7173ab58e60b63ce1e1183d719442988a32 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Fri, 20 Aug 2021 01:13:51 -0400 Subject: proper member list in threads --- abaddon.cpp | 5 ++++- components/memberlist.cpp | 7 ++++++- discord/discord.cpp | 35 +++++++++++++++++++++++++++++++++++ discord/discord.hpp | 9 +++++++++ discord/objects.cpp | 22 +++++++++++++++++++--- discord/objects.hpp | 28 +++++++++++++++++++++++----- 6 files changed, 96 insertions(+), 10 deletions(-) (limited to 'discord/objects.hpp') diff --git a/abaddon.cpp b/abaddon.cpp index 22ca576..6e7a9a5 100644 --- a/abaddon.cpp +++ b/abaddon.cpp @@ -36,6 +36,7 @@ Abaddon::Abaddon() m_discord.signal_message_delete().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnMessageDelete)); m_discord.signal_message_update().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnMessageUpdate)); m_discord.signal_guild_member_list_update().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnGuildMemberListUpdate)); + m_discord.signal_thread_member_list_update().connect([this](...) { m_main_window->UpdateMembers(); }); m_discord.signal_reaction_add().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnReactionAdd)); m_discord.signal_reaction_remove().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnReactionRemove)); m_discord.signal_guild_join_request_create().connect(sigc::mem_fun(*this, &Abaddon::DiscordOnGuildJoinRequestCreate)); @@ -472,7 +473,9 @@ void Abaddon::ActionChannelOpened(Snowflake id) { m_main_window->UpdateChatWindowContents(); } - if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM && channel->GuildID.has_value()) { + if (channel->IsThread()) { + m_discord.SendThreadLazyLoad(id); + } else if (channel->Type != ChannelType::DM && channel->Type != ChannelType::GROUP_DM && channel->GuildID.has_value()) { m_discord.SendLazyLoad(id); if (m_discord.IsVerificationRequired(*channel->GuildID)) diff --git a/components/memberlist.cpp b/components/memberlist.cpp index e91ce88..804f443 100644 --- a/components/memberlist.cpp +++ b/components/memberlist.cpp @@ -127,7 +127,12 @@ void MemberList::UpdateMemberList() { return; } - auto ids = discord.GetUsersInGuild(m_guild_id); + std::set ids; + if (chan->IsThread()) { + const auto x = discord.GetUsersInThread(m_chan_id); + ids = { x.begin(), x.end() }; + } else + ids = discord.GetUsersInGuild(m_guild_id); // process all the shit first so its in proper order std::map pos_to_role; diff --git a/discord/discord.cpp b/discord/discord.cpp index c4276dc..d30e57d 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -265,6 +265,12 @@ std::set DiscordClient::GetChannelsInGuild(Snowflake id) const { return {}; } +std::vector DiscordClient::GetUsersInThread(Snowflake id) const { + if (auto it = m_thread_members.find(id); it != m_thread_members.end()) + return it->second; + return {}; +} + // there is an endpoint for this but it should be synced before this is called anyways std::vector DiscordClient::GetActiveThreads(Snowflake channel_id) const { return m_store.GetActiveThreads(channel_id); @@ -472,6 +478,14 @@ void DiscordClient::SendLazyLoad(Snowflake id) { m_websocket.Send(msg); } +void DiscordClient::SendThreadLazyLoad(Snowflake id) { + LazyLoadRequestMessage msg; + msg.GuildID = *GetChannel(id)->GuildID; + msg.ThreadIDs.emplace().push_back(id); + + m_websocket.Send(msg); +} + void DiscordClient::JoinGuild(std::string code) { m_http.MakePOST("/invites/" + code, "", [](auto) {}); } @@ -1223,6 +1237,9 @@ void DiscordClient::HandleGatewayMessage(std::string str) { case GatewayEvent::THREAD_UPDATE: { HandleGatewayThreadUpdate(m); } break; + case GatewayEvent::THREAD_MEMBER_LIST_UPDATE: { + HandleGatewayThreadMemberListUpdate(m); + } break; } } break; default: @@ -1758,6 +1775,19 @@ void DiscordClient::HandleGatewayThreadUpdate(const GatewayMessage &msg) { m_signal_thread_update.emit(data); } +void DiscordClient::HandleGatewayThreadMemberListUpdate(const GatewayMessage &msg) { + ThreadMemberListUpdateData data = msg.Data; + m_store.BeginTransaction(); + for (const auto &entry : data.Members) { + m_thread_members[data.ThreadID].push_back(entry.UserID); + if (entry.Member.User.has_value()) + m_store.SetUser(entry.Member.User->ID, *entry.Member.User); + m_store.SetGuildMember(data.GuildID, entry.Member.User->ID, entry.Member); + } + m_store.EndTransaction(); + m_signal_thread_member_list_update.emit(data); +} + void DiscordClient::HandleGatewayReadySupplemental(const GatewayMessage &msg) { ReadySupplementalData data = msg.Data; for (const auto &p : data.MergedPresences.Friends) { @@ -2126,6 +2156,7 @@ void DiscordClient::LoadEventMap() { m_event_map["THREAD_MEMBERS_UPDATE"] = GatewayEvent::THREAD_MEMBERS_UPDATE; m_event_map["THREAD_MEMBER_UPDATE"] = GatewayEvent::THREAD_MEMBER_UPDATE; m_event_map["THREAD_UPDATE"] = GatewayEvent::THREAD_UPDATE; + m_event_map["THREAD_MEMBER_LIST_UPDATE"] = GatewayEvent::THREAD_MEMBER_LIST_UPDATE; } DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() { @@ -2284,6 +2315,10 @@ DiscordClient::type_signal_thread_update DiscordClient::signal_thread_update() { return m_signal_thread_update; } +DiscordClient::type_signal_thread_member_list_update DiscordClient::signal_thread_member_list_update() { + return m_signal_thread_member_list_update; +} + DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() { return m_signal_added_to_thread; } diff --git a/discord/discord.hpp b/discord/discord.hpp index a9dc62e..f80d264 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -86,6 +86,7 @@ public: std::optional GetMemberHighestRole(Snowflake guild_id, Snowflake user_id) const; std::set GetUsersInGuild(Snowflake id) const; std::set GetChannelsInGuild(Snowflake id) const; + std::vector GetUsersInThread(Snowflake id) const; std::vector GetActiveThreads(Snowflake channel_id) const; void GetArchivedPublicThreads(Snowflake channel_id, sigc::slot callback); @@ -105,6 +106,7 @@ public: void DeleteMessage(Snowflake channel_id, Snowflake id); void EditMessage(Snowflake channel_id, Snowflake id, std::string content); void SendLazyLoad(Snowflake id); + void SendThreadLazyLoad(Snowflake id); void JoinGuild(std::string code); void LeaveGuild(Snowflake id); void KickUser(Snowflake user_id, Snowflake guild_id); @@ -246,6 +248,7 @@ private: void HandleGatewayThreadMembersUpdate(const GatewayMessage &msg); void HandleGatewayThreadMemberUpdate(const GatewayMessage &msg); void HandleGatewayThreadUpdate(const GatewayMessage &msg); + void HandleGatewayThreadMemberListUpdate(const GatewayMessage &msg); void HandleGatewayReadySupplemental(const GatewayMessage &msg); void HandleGatewayReconnect(const GatewayMessage &msg); void HandleGatewayInvalidSession(const GatewayMessage &msg); @@ -270,6 +273,7 @@ private: std::map m_user_to_status; std::map m_user_relationships; std::set m_joined_threads; + std::map> m_thread_members; UserData m_user_data; UserSettings m_user_settings; @@ -342,6 +346,7 @@ public: typedef sigc::signal type_signal_thread_list_sync; typedef sigc::signal type_signal_thread_members_update; typedef sigc::signal type_signal_thread_update; + typedef sigc::signal type_signal_thread_member_list_update; // not discord dispatch events typedef sigc::signal type_signal_added_to_thread; @@ -391,6 +396,8 @@ public: type_signal_thread_list_sync signal_thread_list_sync(); type_signal_thread_members_update signal_thread_members_update(); type_signal_thread_update signal_thread_update(); + type_signal_thread_member_list_update signal_thread_member_list_update(); + type_signal_added_to_thread signal_added_to_thread(); type_signal_removed_from_thread signal_removed_from_thread(); type_signal_message_sent signal_message_sent(); @@ -436,6 +443,8 @@ protected: type_signal_thread_list_sync m_signal_thread_list_sync; type_signal_thread_members_update m_signal_thread_members_update; type_signal_thread_update m_signal_thread_update; + type_signal_thread_member_list_update m_signal_thread_member_list_update; + type_signal_removed_from_thread m_signal_removed_from_thread; type_signal_added_to_thread m_signal_added_to_thread; type_signal_message_sent m_signal_message_sent; diff --git a/discord/objects.cpp b/discord/objects.cpp index fb713f4..725cba5 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -85,11 +85,16 @@ void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m) { for (const auto &[key, chans] : *m.Channels) j["d"]["channels"][std::to_string(key)] = chans; } - j["d"]["typing"] = m.ShouldGetTyping; - j["d"]["activities"] = m.ShouldGetActivities; - j["d"]["threads"] = m.ShouldGetThreads; + if (m.ShouldGetTyping) + j["d"]["typing"] = *m.ShouldGetTyping; + if (m.ShouldGetActivities) + j["d"]["activities"] = *m.ShouldGetActivities; + if (m.ShouldGetThreads) + j["d"]["threads"] = *m.ShouldGetThreads; if (m.Members.has_value()) j["d"]["members"] = *m.Members; + if (m.ThreadIDs.has_value()) + j["d"]["thread_member_lists"] = *m.ThreadIDs; } void to_json(nlohmann::json &j, const UpdateStatusMessage &m) { @@ -511,3 +516,14 @@ void from_json(const nlohmann::json &j, ThreadMemberUpdateData &m) { void from_json(const nlohmann::json &j, ThreadUpdateData &m) { m.Thread = j; } + +void from_json(const nlohmann::json &j, ThreadMemberListUpdateData::UserEntry &m) { + JS_D("user_id", m.UserID); + JS_D("member", m.Member); +} + +void from_json(const nlohmann::json &j, ThreadMemberListUpdateData &m) { + JS_D("thread_id", m.ThreadID); + JS_D("guild_id", m.GuildID); + JS_D("members", m.Members); +} diff --git a/discord/objects.hpp b/discord/objects.hpp index daaa9b2..4613a85 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -77,6 +77,7 @@ enum class GatewayEvent : int { THREAD_LIST_SYNC, THREAD_MEMBER_UPDATE, THREAD_MEMBERS_UPDATE, + THREAD_MEMBER_LIST_UPDATE, }; enum class GatewayCloseCode : uint16_t { @@ -204,11 +205,12 @@ struct GuildMemberListUpdateMessage { struct LazyLoadRequestMessage { Snowflake GuildID; - bool ShouldGetTyping = false; - bool ShouldGetActivities = false; - bool ShouldGetThreads = false; - std::optional> Members; // snowflake? - std::optional>>> Channels; // channel ID -> range of sidebar + std::optional ShouldGetTyping; + std::optional ShouldGetActivities; + std::optional ShouldGetThreads; + std::optional> Members; // snowflake? + std::optional>>> Channels; // channel ID -> range of sidebar + std::optional> ThreadIDs; friend void to_json(nlohmann::json &j, const LazyLoadRequestMessage &m); }; @@ -720,3 +722,19 @@ struct ThreadUpdateData { friend void from_json(const nlohmann::json &j, ThreadUpdateData &m); }; + +struct ThreadMemberListUpdateData { + struct UserEntry { + Snowflake UserID; + // PresenceData Presence; + GuildMember Member; + + friend void from_json(const nlohmann::json &j, UserEntry &m); + }; + + Snowflake ThreadID; + Snowflake GuildID; + std::vector Members; + + friend void from_json(const nlohmann::json &j, ThreadMemberListUpdateData &m); +}; -- cgit v1.2.3 From 8ed2cd65b6b49ad6bd4d91c0de71b4be863456b2 Mon Sep 17 00:00:00 2001 From: ouwou <26526779+ouwou@users.noreply.github.com> Date: Sat, 28 Aug 2021 02:28:41 -0400 Subject: archive/unarchive from channel list --- components/channels.cpp | 27 ++++++++++++++++++++++++++- components/channels.hpp | 4 ++++ discord/discord.cpp | 24 ++++++++++++++++++++++++ discord/discord.hpp | 2 ++ discord/objects.cpp | 5 +++++ discord/objects.hpp | 7 +++++++ 6 files changed, 68 insertions(+), 1 deletion(-) (limited to 'discord/objects.hpp') diff --git a/components/channels.cpp b/components/channels.cpp index 41935b9..0a60fd6 100644 --- a/components/channels.cpp +++ b/components/channels.cpp @@ -19,7 +19,9 @@ ChannelList::ChannelList() , m_menu_dm_close("") // changes depending on if group or not , m_menu_dm_copy_id("_Copy ID", true) , m_menu_thread_copy_id("_Copy ID", true) - , m_menu_thread_leave("_Leave", true) { + , m_menu_thread_leave("_Leave", true) + , m_menu_thread_archive("_Archive", true) + , m_menu_thread_unarchive("_Unarchive", true) { get_style_context()->add_class("channel-list"); const auto cb = [this](const Gtk::TreeModel::Path &path, Gtk::TreeViewColumn *column) { @@ -130,10 +132,20 @@ ChannelList::ChannelList() if (Abaddon::Get().ShowConfirm("Are you sure you want to leave this thread?")) Abaddon::Get().GetDiscordClient().LeaveThread(static_cast((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]), "Context%20Menu", [](...) {}); }); + m_menu_thread_archive.signal_activate().connect([this] { + Abaddon::Get().GetDiscordClient().ArchiveThread(static_cast((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]), [](...) {}); + }); + m_menu_thread_unarchive.signal_activate().connect([this] { + Abaddon::Get().GetDiscordClient().UnArchiveThread(static_cast((*m_model->get_iter(m_path_for_menu))[m_columns.m_id]), [](...) {}); + }); m_menu_thread.append(m_menu_thread_copy_id); m_menu_thread.append(m_menu_thread_leave); + m_menu_thread.append(m_menu_thread_archive); + m_menu_thread.append(m_menu_thread_unarchive); m_menu_thread.show_all(); + m_menu_thread.signal_popped_up().connect(sigc::mem_fun(*this, &ChannelList::OnThreadSubmenuPopup)); + auto &discord = Abaddon::Get().GetDiscordClient(); discord.signal_message_create().connect(sigc::mem_fun(*this, &ChannelList::OnMessageCreate)); discord.signal_guild_create().connect(sigc::mem_fun(*this, &ChannelList::UpdateNewGuild)); @@ -692,6 +704,19 @@ void ChannelList::MoveRow(const Gtk::TreeModel::iterator &iter, const Gtk::TreeM m_model->erase(iter); } +void ChannelList::OnThreadSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y) { + m_menu_thread_archive.set_visible(false); + m_menu_thread_unarchive.set_visible(false); + + auto iter = m_model->get_iter(m_path_for_menu); + if (!iter) return; + auto channel = Abaddon::Get().GetDiscordClient().GetChannel(static_cast((*iter)[m_columns.m_id])); + if (!channel.has_value() || !channel->ThreadMetadata.has_value()) return; + + m_menu_thread_archive.set_visible(!channel->ThreadMetadata->IsArchived); + m_menu_thread_unarchive.set_visible(channel->ThreadMetadata->IsArchived); +} + ChannelList::type_signal_action_channel_item_select ChannelList::signal_action_channel_item_select() { return m_signal_action_channel_item_select; } diff --git a/components/channels.hpp b/components/channels.hpp index 37a3254..5cfa9c3 100644 --- a/components/channels.hpp +++ b/components/channels.hpp @@ -222,6 +222,10 @@ protected: Gtk::Menu m_menu_thread; Gtk::MenuItem m_menu_thread_copy_id; Gtk::MenuItem m_menu_thread_leave; + Gtk::MenuItem m_menu_thread_archive; + Gtk::MenuItem m_menu_thread_unarchive; + + void OnThreadSubmenuPopup(const Gdk::Rectangle *flipped_rect, const Gdk::Rectangle *final_rect, bool flipped_x, bool flipped_y); bool m_updating_listing = false; diff --git a/discord/discord.cpp b/discord/discord.cpp index d30e57d..445cb65 100644 --- a/discord/discord.cpp +++ b/discord/discord.cpp @@ -824,6 +824,30 @@ void DiscordClient::LeaveThread(Snowflake channel_id, const std::string &locatio }); } +void DiscordClient::ArchiveThread(Snowflake channel_id, sigc::slot callback) { + ModifyChannelObject obj; + obj.Archived = true; + obj.Locked = true; + m_http.MakePATCH("/channels/" + std::to_string(channel_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) { + if (CheckCode(response)) + callback(DiscordError::NONE); + else + callback(GetCodeFromResponse(response)); + }); +} + +void DiscordClient::UnArchiveThread(Snowflake channel_id, sigc::slot callback) { + ModifyChannelObject obj; + obj.Archived = false; + obj.Locked = false; + m_http.MakePATCH("/channels/" + std::to_string(channel_id), nlohmann::json(obj).dump(), [this, callback](const http::response_type &response) { + if (CheckCode(response)) + callback(DiscordError::NONE); + else + callback(GetCodeFromResponse(response)); + }); +} + void DiscordClient::FetchPinned(Snowflake id, sigc::slot, DiscordError code)> callback) { // return from db if we know the pins have already been requested if (m_channels_pinned_requested.find(id) != m_channels_pinned_requested.end()) { diff --git a/discord/discord.hpp b/discord/discord.hpp index f80d264..4c3b365 100644 --- a/discord/discord.hpp +++ b/discord/discord.hpp @@ -143,6 +143,8 @@ public: void Pin(Snowflake channel_id, Snowflake message_id, sigc::slot callback); void Unpin(Snowflake channel_id, Snowflake message_id, sigc::slot callback); void LeaveThread(Snowflake channel_id, const std::string &location, sigc::slot callback); + void ArchiveThread(Snowflake channel_id, sigc::slot callback); + void UnArchiveThread(Snowflake channel_id, sigc::slot callback); bool CanModifyRole(Snowflake guild_id, Snowflake role_id) const; bool CanModifyRole(Snowflake guild_id, Snowflake role_id, Snowflake user_id) const; diff --git a/discord/objects.cpp b/discord/objects.cpp index 725cba5..c6de2ce 100644 --- a/discord/objects.cpp +++ b/discord/objects.cpp @@ -527,3 +527,8 @@ void from_json(const nlohmann::json &j, ThreadMemberListUpdateData &m) { JS_D("guild_id", m.GuildID); JS_D("members", m.Members); } + +void to_json(nlohmann::json &j, const ModifyChannelObject &m) { + JS_IF("archived", m.Archived); + JS_IF("locked", m.Locked); +} diff --git a/discord/objects.hpp b/discord/objects.hpp index 4613a85..7084efb 100644 --- a/discord/objects.hpp +++ b/discord/objects.hpp @@ -738,3 +738,10 @@ struct ThreadMemberListUpdateData { friend void from_json(const nlohmann::json &j, ThreadMemberListUpdateData &m); }; + +struct ModifyChannelObject { + std::optional Archived; + std::optional Locked; + + friend void to_json(nlohmann::json &j, const ModifyChannelObject &m); +}; -- cgit v1.2.3